I2c2midi
i2c2midi is a DIY open source 2 HP Teletype Expander that speaks I2C and MIDI.
Install / Use
/learn @attowatt/I2c2midiREADME
i2c2midi
i2c2midi is a DIY open source 2 HP Teletype Expander that speaks I2C and MIDI.
i2c2midi bridges the gap between monome Teletype and external MIDI-enabled devices. Using dedicated Teletype OPs, i2c2midi adds MIDI in and out to Teletype.
→ MIDI out:
Sends MIDI notes, MIDI CC messages and other MIDI messages from Teletype to external devices like synths and effects.
← MIDI in:
Receives MIDI messages from external MIDI controllers and stores the values internally, which can be requested and used within Teletype.
- Dedicated Teletype OPs:
I2M.x - MIDI out via TRS
- MIDI out and in via USB Host
- Automatic MIDI Note Off messages (settable note duration per note)
- Chords and Chord Transformations
- Looping MIDI buffer / MIDI recorder
- Works with monome crow, too, thanks to mreid
- 8 voice polyphony per MIDI channel, 16 channels simultaneously
- 2 HP, 42 mm depth
i2c2midi lines community thread:
https://llllllll.co/t/i2c2midi-a-diy-module-that-translates-i2c-to-midi/

<br/><br/>
Table of contents
Connections
Example Scripts
Teletype OPs
Further Reading
Build the module
Firmware
crow Library
Thanks
Sources
<br/><br/>
Connections
TRS
Use a TRS MIDI adapter (Type A) to connect a standard MIDI DIN cable to the TRS output of i2c2midi.
i2c2midi can be used with up to 16 different external MIDI-enabled devices simultaneously, with each device receiving MIDI messages on one of the 16 available MIDI channels. Just make sure each device is set to a different MIDI channel. Use a MIDI through splitter to connect all devices. Set the MIDI channel to 1..16 for the TRS output, using I2M.CH.
Please note: The TRS connection is MIDI out only!
USB
The USB connection can be used for either MIDI out to connect an additional device (e.g. Teenage Engineering OP-1), or MIDI in to receive MIDI Note or CC messages from an external MIDI controller.
Several MIDI controllers can be connected using a USB hub for MIDI in.
i2c2midi acts as a USB host, which makes it possible to connect external USB devices without the need of a computer. However, this also means that a computer (which acts as a host itself) can not be connected via the USB A jack on the front panel. However, it is possible to connect a USB host via the Micro USB jack of the Teensy. More info about that here.
USB MIDI out (Host)
The USB MIDI out connection works like the TRS output, but the 16 available MIDI channels can be addressed separately from TRS. Set the MIDI channel with I2M.CH to 17..32 for MIDI channels 1..16 on the USB connection. Please note: Only one USB device can be connected at a time.
USB MIDI in (Host)
If an external MIDI controller is connected via USB, incoming MIDI messages are stored internally in i2c2midi, and can be requested by Teletype at any time:
- MIDI Note messages: The last eight notes and their velocities are stored in a rotating "note history". Each new received note gets added to the history and pushes the oldest note out. The notes and velocities can be requested with
I2M.Q.NandI2M.Q.V. - MIDI CC messages: All values (127 controllers * 16 channels = 2032 values total) are stored and can be requested with
I2M.Q.CC.
Please note: Use external power or a powered USB hub!
If you connect a MIDI device without its own power supply, use a powered USB hub with power supply in between i2c2midi and the MIDI device. This prevents too much current from being drawn from the Teensy and the voltage regulator on the PCB. I would advise to always use a powered USB hub in between – to be on the safe side.
In case of OP-1, please turn off USB charging by pressing shift + COM, then OPT (T4), then turn the blue encoder to toggle USB charging off.
USB MIDI out (Device to Host)
i2c2midi can act as a USB device, too, if you want to connect a device that acts as a USB host (e.g. a computer). For this, you can use the Micro USB jack of the Teensy, which is accessible on the back of the module. Enable the USB_DEVICE feature flag in the firmware (look for //#define USB_DEVICE and remove the //).
Most importantly: Cut the 5V pads on the Teensy! Otherwise you will damage your Teensy once you connect power from the modular and the host device on the USB port. For more info on why and how to cut the 5V pads, please follow this link.
Please note: Don't connect power and USB at the same time!
Caution: Do not connect power from the modular and the default USB port of the Teensy at the same time, unless you have cut the 5V pads on the Teensy!! Otherwise you will damage your Teensy.
LEDs
- The top LED lights up when MIDI messages are coming in.
- The bottom LED lights up when MIDI messages are going out.

<br/><br/>
Example Scripts
Play a random note
#1
I2M.CH 1 // set channel to 1
I2M.N + 60 RND 24 127 // play note between 60 and 84
Play a V/Oct note using VN
#1
J N.B RRND 1 15 // random note from a scale in V/Oct
K VN J // convert the V/Oct value to MIDI note number
I2M.N + 60 K 127 // play note
Define and play a chord
#1
I2M.C.CLR 1 // clear chord 1
I2M.C.ADD 1 0 // add relative note 0
I2M.C.ADD 1 3 // add relative note 3
I2M.C.ADD 1 7 // add relative note 7
#2
I2M.C.STR 1 100 // set strumming to 100
I2M.C.DIR 1 7 // set play direction to 7: Pingpong
I2M.C 1 60 127 // play chord 1 with rootnote 60 and velocity 127 (= 60,63,67)
Define a chord using reverse binary
#1
I2M.C.B 1 R10010001 // define chord: 1 means add, 0 means don't add = 0,3,7
I2M.C 1 60 127 // play chord 1 with rootnote 60 and velocity 127 (= 60,63,67)
Play chords stored in pattern 0
#1
I2M.C.B 1 PN.NEXT 0 // define chord with next value in pattern 0
I2M.C 1 60 127 // play chord 1 with rootnote 60 and velocity 127
#Pattern 0
137 // = R10010001 = 0,3,7
265 // = R100100001 = 0,3,8
1064 // = R00010100001 = 3,5,10
1060 // = R00100100001 = 2,5,10
Use chord 2 as scale for a chord 1
#1
I2M.C.B 1 R100100011 // define chord 1 = 0,3,7,8 (alternatively use "393")
I2M.C.B 2 R10110101101 // define chord 2 = 0,2,3,5,7,8,10 (minor scale) (or "1453")
I2M.C.SC 1 2 // set chord 2 as scale for chord 1
#2
J WRP + J 1 0 7 // increment J and wrap around 0 and 7
I2M.C.STR 1 200 // set strumming for chord 1 to 200 ms
I2M.C.TRP 1 J // transpose chord 1 by J
I2M.C 1 60 127 // play chord 1 with rootnote 60 and velocity 127
Send transformed chord notes to Just Friends or ER-301
To Just Friends:
#I
JF.MODE 1
JF.SHIFT N 0
#1
I2M.C.B 1 R100100011 // define chord 1 = 0,3,7,8
I2M.C.B 2 R10110101101 // define chord 2 = 0,2,3,5,7,8,10 (minor scale)
I2M.C.SC 1 2 // set chord 2 as scale for chord 1
#2
J WRP + J 1 0 4 // increment J and wrap around 4
I2M.C.DIS 1 J 2 // distort chord 1 by J at anchor point 2
I2M.C.VCUR 1 1 40 100 // set a linear (type 1) velocity curve from 40% to 100%
#3
EV 4: $ 2
J WRP + J 1 0 3 // increment J and wrap around chord length
X I2M.C.QN 1 0 J // get chord note and store in X
Y I2M.C.QV 1 127 J // get chord note velocity and store in Y
Z SCL 0 127 0 800 Y // scale velocity from 0..127 to 0..800
JF.NOTE N X VV Z // play on Just Friends
To ER-301:
#3
J WRP + J 1 0 3 // increment J and wrap around chord length
SC.CV 1 N I2M.C.QN 1 0 J // send V/Oct to ER-301
SC.CV 2 VV I2M.C.QV 1 127 J // send velocity to ER-301 (set Gain to 7.88)
SC.TR.P 1 // send a trigger to ER-301 envelope
Query CC 1-4 and store values in Pattern 0
#1
L 0 3: PN 0 I I2M.Q.CC + I 1
Query MIDI notes from controller
Arpeggiator that plays MIDI notes currently held down on a connected MIDI controller.
CV 1 sends out the V/OCT and CV 2 sends out the velocity.
#I
I2M.Q.LATCH 0 // setting to only store currently played MIDI notes
#M
$ 1
#1
J WRP + J 1 0 7 // counter from 0..7
CV 1 N - I2M.Q.N J 48 // query MIDI note number and subtract 4 octaves
CV 2 VV * 4 I2M.Q.V J // query MIDI note velocity and scale to VV 0..508
Teletype OPs
Overview
| Type | OP | Alias | Channel-specific variant (?) | Function | | ---- | ---------------------------------------------- | ------- | ----------------------------------------------------- | ----------------------------------- | | get | I2M.CH | I2M.# | | Get current Channel | | | I2M.CH channel | I2M.# | | Set current Channel | | get | I2M.TIME | I2M.T | I2M.T# channel | Get note duration | | | I2M.TIME duration | I2M.T | I2M.T# channel duration | Set note duration | | get | I2M.SHIFT
