i2c2midi bridges the gap between monome Teletype and external MIDI-enabled devices, using I2C:
→ It receives I2C messages from Teletype and converts them to MIDI notes, MIDI CC messages and other MIDI messages to control external devices like synths and effects.
← It receives MIDI messages from external MIDI controllers and stores the values internally, which can be requested at any time by Teletype via I2C.
- 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/
Connections
Example Scripts
Teletype OPs
Further Reading
Build the module
Firmware
crow Library
Thanks
Sources
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!
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.
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.
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.N
andI2M.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.
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.
- The top LED lights up when MIDI messages are coming in.
- The bottom LED lights up when MIDI messages are going out.
#1
I2M.CH 1 // set channel to 1
I2M.N 60 RND 24 127 // play note between 60 and 84
#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
#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)
#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)
#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
#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
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
#1
L 0 3: PN 0 I I2M.Q.CC I 1
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
OP
OP (set)
Alias
Description
Settings for outoing MIDI messages
I2M.CH
I2M.CH x
I2M.#
Get currently set MIDI channel / Set MIDI channel x
(1..16 for TRS, 17..32 for USB) for MIDI out. Use MIDI channels 1-16 for TRS output, 17-32 for USB output. Default is x = 1
.
I2M.TIME
I2M.TIME x
I2M.T
Get current note duration / Set note duration of MIDI notes to x
ms (0..32767) for current channel. Based on note duration, i2c2midi will send a MIDI Note Off message automatically. Set x = 0
to deactivate automatic Note Off messages. Default is x = 100
.
I2M.T# ch
I2M.T# ch x
Get current note duration / Set note duration of MIDI notes to x
ms (0..32767) for channel ch
(0..32). Based on note duration, i2c2midi will send a MIDI Note Off message automatically. Set x = 0
to deactivate automatic Note Off messages. Default is x = 100
. Use ch = 0
to set for all channels.
I2M.SHIFT
I2M.SHIFT x
I2M.S
Get current transposition / Set transposition of MIDI notes to x
semitones (-127..127) for current channel. Default is x = 0
.
I2M.S# ch
I2M.S# ch x
Get current transposition / Set transposition of MIDI notes to x
semitones (-127..127) for channel ch
(0..32). Default is x = 0
. Use ch = 0
to set for all channels.
I2M.MIN x y
Set minimum note number of MIDI notes to x
(0..127), using mode y
(0..3), for current channel. Default is x = 0
and y = 0
. The following modes are available for notes lower than the minimum: 0) Ignore notes 1) Clamp notes 2) Fold back notes by one octave 3) Fold back notes by multiple octaves.
I2M.MIN# ch x y
Set minimum note number of MIDI notes to x
(0..127), using mode y
(0..3), for channel ch
(0..32). Default is x = 0
and y = 0
. The following modes are available for notes lower than the minimum: 0) Ignore notes 1) Clamp notes 2) Fold back notes by one octave 3) Fold back notes by multiple octaves. Use ch = 0
to set for all channels.
I2M.MAX x y
Set maximum note number of MIDI notes to x
(0..127), using mode y
(0..3), for current channel. Default is x = 0
and y = 0
. The following modes are available for notes higher than the maximum: 0) Ignore notes 1) Clamp notes 2) Fold back notes by one octave 3) Fold back notes by multiple octaves.
I2M.MAX# ch x y
Set maximum note number of MIDI notes to x
(0..127), using mode y
(0..3), for channel ch
(0..32). Default is x = 0
and y = 0
. The following modes are available for notes higher than the maximum: 0) Ignore notes 1) Clamp notes 2) Fold back notes by one octave 3) Fold back notes by multiple octaves. Use ch = 0
to set for all channels.
I2M.REP
I2M.REP x
Get current repetition / Set repetition of MIDI notes to x
repetitions (1..127) for current channel. Set x = 1
for no repetitions. Default is x = 1
.
I2M.REP# ch
I2M.REP# ch x
Get current repetition / Set repetition of MIDI notes to x
repetitions (1..127) for channel ch
(0..32). Set x = 1
for no repetitions. Default is x = 1
. Use ch = 0
to set for all channels.
I2M.RAT
I2M.RAT x
Get current ratcheting / Set ratcheting of MIDI notes to x
ratchets (1..127) for current channel. Set x = 1
for no ratcheting. Default is x = 1
.
I2M.RAT# ch
I2M.RAT# ch x
Get current ratcheting / Set ratcheting of MIDI notes to x
ratchets (1..127) for channel ch
(0..32). Set x = 1
for no ratcheting. Default is x = 1
. Use ch = 0
to set for all channels.
I2M.MUTE x
Set mute state of current MIDI channel to x
. If x = 1
all outoing MIDI messages on that channel are muted. Default is x = 0
.
I2M.MUTE# ch x
Set mute state of MIDI channel ch
to x
. If x = 1
all outoing MIDI messages on that channel are muted. Default is x = 0
. Use ch = 0
to set for all channels.
I2M.SOLO x
Set solo state of current MIDI channel to x
. If x = 1
all outoing MIDI messages on that channel are solod. Default is x = 0
.
I2M.SOLO x
Set solo state of MIDI channel ch
to x
. If x = 1
all outoing MIDI messages on that channel are solod. Default is x = 0
. Use ch = 0
to set for all channels.
Send an individual MIDI note. Each note consists of a note number (pitch), velocity and duration. i2c2midi will take care of Note Off messages send an automatic Note Off message based on the set note duration. The note duration can be set globally via I2M.TIME
or individually via I2M.NT
.
I2M.NOTE x y
I2M.N
Send MIDI Note On message for note number x
(0..127) with velocity y
(1..127) on current channel. A velocity of 0
will be treated as a MIDI Note Off message.
I2M.N# ch x y
Send MIDI Note On message for note number x
(0..127) with velocity y
(1..127) on channel ch
(1..32). A velocity of 0
will be treated as a MIDI Note Off message.
I2M.NOTE.O x
I2M.NO
Send a manual MIDI Note Off message for note number x
(0..127) on current channel. This can be used either before i2c2midi sends the automatic Note Off message (to stop the note from playing before its originally planned ending), or in combination with I2M.TIME
set to 0
(in which case i2c2midi does not send automatic Note Off messages).
I2M.NO# ch x
Send a manual MIDI Note Off message for note number x
(0..127) on channel ch
(1..32). This can be used either before i2c2midi sends the automatic Note Off message (to stop the note from playing before its originally planned ending), or in combination with I2M.TIME
set to 0
(in which case i2c2midi does not send automatic Note Off messages).
I2M.NT x y z
Send MIDI Note On message for note number x
(0..127) with velocity y
(1..127) and note duration z
ms (0..32767) on current channel.
I2M.NT# ch x y z
Send MIDI Note On message for note number x
(0..127) with velocity y
(1..127) and note duration z
ms (0..32767) on channel ch
(1..32).
Play a chord, consisting of multiple MIDI notes. Chords are basically groups of relative note numbers or pitches. One chord consists of up to eight notes defined via I2M.C.ADD
, I2M.C.RM
, I2M.C.INS
, I2M.C.DEL
or I2M.C.SET
. The notes are defined relative to the root note which is specified when playing a chord via I2M.C
. When a chord is played, the notes are sent out as individual MIDI notes in the order they are defined in the chord. If no note has been defined in the chord yet, no note will be played. 8 chords can be defined using their respective index 1..8.
I2M.CHORD x y z
I2M.C
Play chord x
(1..8) with root note y
(0..127) and velocity z
(1..127) on current channel.
I2M.C# ch x y z
Play chord x
(1..8) with root note y
(0..127) and velocity z
(1..127) on channel ch
(1..32).
I2M.C.ADD x y
I2M.C
Add note y
(-127..127) to chord x
(0..8), with y
relative to the root note specified when playing a chord. E.g. add 0
, 4
and 7
to define a major triad. Or go more experimental, e.g. -2
, 13
, 2
, 13
. Up to eight chords can be defined, with eight notes each. Use x = 0
to add the note to all chords.
I2M.C.RM x y
I2M.C-
Remove note y
(-127..127) from chord x
(0..8). If the chord contains note y
multiple times, the latest instance is removed. If the chord does not contain the note the message is simply ignored. Use x = 0
to remove the note from all chords.
I2M.C.INS x y z
Add note z
(-127..127) to chord x
(0..8) at index y
(0..7), with z
relative to the root note. Already defined notes at index y
and higher are pushed to the right. Use x = 0
to insert the note to all chords.
I2M.C.DEL x y
Delete note at index y
(0..7) from chord x
(0..8). Notes at index y 1
and higher are pushed to the left. If y
is higher than the length of the chord, the message is ignored. Use x = 0
to delete the note from all chords.
I2M.C.SET x y z
Set note at index y
(0..7) in chord x
(0..8) to note z
(-127..127), replacing what was defined earlier at this index. If y
is higher than the length of the chord, the message is ignored. Use x = 0
to set the note in all chords.
I2M.C.B x y
Clear and define chord x
(0..8) using reverse binary notation (R...
). Use 1
or 0
in order to include or exclude notes from the chord. E.g. use x = R10001001
for 0,4,7
(major triad) or x = R1000000100000001
for 0,7,15
. y
can be a maximum of 16 digit long. Use x = 0
to clear and define all chords.
I2M.C.CLR x
Clear chord x
(0..8). Use x = 0
to clear all chords.
I2M.C.L x
I2M.C.L x y
Get current length / Set length of chord x
(0..8) to y
(1..8). The length of a chord changes automatically each time a note is added or removed. Values of x
higher than number of actual defined notes are ignored. Already defined notes are not affected by setting the chord length, but won't be played if their index is outside of the set chord length. Use x = 0
to set the length of all chords.
I2M.C.SC x y
Set scale for chord x
(0..8) based on chord y
(0..8). Setting a scale for a chord comes in handy when using chord transformations that introduce new notes, like I2M.C.TRP
, I2M.C.DIS
or I2M.C.REF
. Use y = 0
to remove the scale. Use x = 0
to set scale for all chords.
→ More info on how scales work on i2c2midi
I2M.C.REV x y
Set reversal of notes in chord x
(0..8) to y
. y = 0
or an even number means not reversed, y = 1
or an uneven number means reversed. E.g. y = 1
for chord 0,3,7
will lead to 7,3,0
. Default is y = 0
. Use x = 0
to set reversal all chords.
i2c2midi-chord-reversal.mp4
I2M.C.ROT x y
Set rotation of notes in chord x
(0..8) to y
steps (-127..127). E.g. y = 1
of chord 0,3,7
will lead to 3,7,0
, y = 2
will lead to 7,0,3
, y = -1
will lead to 7,0,3
. Default is y = 0
. Use x = 0
to set rotation for all chords.
i2c2midi-chord-rotation.mp4
I2M.C.TRP x y
Set transposition of chord x
(0..8) to y
(-127..127). Transposition adds y
to the note number of each note in the chord. Default is y = 0
. Use x = 0
to set transposition for all chords. This transformation introduces new notes to the chord – try it in combination with setting a scale.
i2c2midi-chord-transposition.mp4
I2M.C.DIS x y z
Set distortion of chord x
(0..8) to width y
(-127..127) with anchor point z
(0..16). Distortion adds y n
to the note number of each note in the chord. The anchor point influences the direction and amount (n
) of the transformation. Default is y = 0
. Use x = 0
to set distortion for all chords. This transformation introduces new notes to the chord – try it in combination with setting a scale.
i2c2midi-chord-distortion.mp4
I2M.C.REF x y z
Set reflection of chord x
(0..8) to y
(-127..127) with anchor point z
(0..16). The anchor point defines at which axis the chord gets reflected. Default is y = 0
. Use x = 0
to set distortion for all chords. This transformation introduces new notes to the chord – try it in combination with setting a scale.
i2c2midi-chord-reflection.mp4
I2M.C.INV x y
Set inversion of chord x
(0..8) to y
(-32..32). Default is y = 0
. Use x = 0
to set inversion for all chords.
i2c2midi-chord-inversion.mp4
I2M.C.STR x y
Set strumming of chord x
(0..8) to y
ms (0..32767). Strumming plays the notes of a chord arpeggiated, with an interval of y
ms in between notes. Default is y = 0
. Use x = 0
to set strumming for all chords.
I2M.C.VCUR w x y z
I2M.C.V~
Set velocity curve for chord w
(0..8) with curve type x
(0..5), start value y
% (0..32767) and end value z
% (0..32767). This will affect the velocity of the notes in the order they are defined in the chord. Start and end percentages refer to the velocity with which the chord is played via I2M.C
. Use x = 0
to turn velocity curve off. The following curves are available: 0) Off 1) Linear 2) Exponential 3) Triangle 4) Square 5) Random. Use w = 0
to set velocity curve for all chords. Try a random curve with subtle values for a humanizing effect.
I2M.C.TCUR w x y z
I2M.C.T~
Set time curve for chord w
(0..8) with curve type x
(0..5), start value y
% (0..32767) and end value z
% (0..32767). This will affect the time interval between the notes in the order they are defined in the chord. Start and end percentages refer to the current strumming setting of the chord, set via I2M.C.STR
. Use x = 0
to turn time curve off. The following curves are available: 0) Off 1) Linear 2) Exponential 3) Triangle 4) Square 5) Random. Use w = 0
to set time curve for all chords. Try a square curve with similar values to create swing. Try a random curve with subtle values for a humanizing effect.
I2M.C.DIR x y
Set play direction for chord x
(0..8) to direction y
(0..8). This will affect the order in which chord notes are played. Make sure to set strumming via I2M.C.STR
. The following directions are available: 0) Forward (0,1,2,3,4) 1) Backward (4,3,2,1,0) 2) Inside out (2,1,3,0,4) 3) Outside in (0,4,1,3,2) 4) Random (2,3,1,0,4) 5) Bottom repeat (0,1,0,2,0,3,0,4) 6) Top repeat (0,4,1,4,2,4,3,4) 7) Pingpong (0,1,2,3,4,3,2,1,0) 8) Ping & pong (0,1,2,3,4,4,3,2,1,0). Default is y = 0
.
I2M.C.QN x y z
Get the transformed note number of a chord note for chord x
(1..8) with root note y
(0..127) at index z
(0..7). The reponse is the absolute note number (0..127). Use this OP to send the transformed note number to other devices within eurorack, e.g. via V/OCT to any oscillator or via I2C to I2C-enabled devices like Just Friends or disting EX.
I2M.C.QV x y z
Get the transformed note velocity of a chord note for chord x
(1..8) with root velocity y
(1..127) at index z
(0..7). The response is the absolute note velocity (0..127). Use this OP to send the transformed note velocity to other devices within eurorack, e.g. via CV to a VCA or via I2C to I2C-enabled devices like Just Friends or disting EX.
Record MIDI notes into a looping buffer. i2c2midi's MIDI buffer behaves much like a looping tape recorder, recording every MIDI note that leaves i2c2midi into the buffer. When the buffer reaches its end, it starts over and plays back the recorded notes, while new notes are recorded (overdubbed). Notes in the buffer can be modified with each buffer iteration. Change the note pitch via I2M.B.NSHIFT
and I2M.B.VSHIFT
, change note velocity via I2M.B.FB
, I2M.B.VSHIFT
and I2M.B.VOFF
, change note duration via I2M.B.TSHIFT
and I2M.B.TOFF
. When notes reach a velocity of zero they get deleted from the buffer. However, notes can be held in the buffer indefinitely by setting I2M.B.FB
to 0. Furthermore, the speed and playback direction of the buffer can be set, as well as the length and a start and end offset. The buffer can work in two modes, set via I2M.B.MODE
.
Depending on the settings, the buffer can act more like a MIDI looper or more like a pitch-shifting delay for MIDI notes.
I2M.B.R x
Turn recording of notes into the buffer on or off. x = 1
is on, x = 0
is off. If recording is turned on, all outgoing MIDI notes are recorded into the buffer, storing note number, note velocity, note duration and MIDI channel.
I2M.B.L x
Set the length of the buffer to x
ms (0..32767). Default is x = 1000
.
I2M.B.START x
Add an offset of x
ms (0..32767) to the start of the buffer. The offset time is non-distructively added to the start of the looping buffer. E.g. if the buffer length is set to 1000
ms and start offset is set to 200
ms, the buffer will loop the section 200
- 1000
ms, resulting in a looping buffer length of 800
ms. Default is x = 0
.
I2M.B.END x
Add a negative offset of x
ms (0..32767) to the end of the buffer. The offset time is non-distructively substracted from the end of the looping buffer. E.g. if the buffer length is set to 1000
ms, start offset is set to 200
ms, and end offset is set to 300
ms, the buffer will loop the section 200
- 700
ms, resulting in a looping buffer length of 500
ms. Default is x = 0
.
I2M.B.DIR x
Set the play direction x
(0..2) of the buffer. The following directions are available: 0) Forward 1) Backward 2) Pingpong. Keep in mind that changing the direction only affects notes that have been already recorded to the buffer before the change in direction; all notes recorded afterwards are recorded relative to the new direction. Default is x = 0
.
I2M.B.SPE x
Set the playing speed x
(1..32767) of the buffer. x = 100
is equivalent to "normal speed", x = 50
means double the speed, x = 200
means half the speed, etc. Of course, all values in between can be chosen. Keep in mind that changing the speed only affects notes that have been already recorded to the buffer before the change in speed; all notes recorded afterwards are recorded relative to the new speed. Default is x = 100
.
I2M.B.FB x
Set the feedback length x
(0..255) of the buffer. By default, each recorded note is getting decreased in velocity with each buffer iteration. The feedback value determines, how many buffer iterations a recorded note will "survive" in the buffer, before the decreasing velocity will reach zero (meaning the note is remove from the buffer). Set x = 0
to turn off the automatic decrease in velocity, keeping notes in the buffer indefinitely. Use this setting in combination with I2M.B.VSHIFT
or I2M.B.CLR
. Default is x = 8
.
I2M.B.NSHIFT x
Set the note shift of recorded notes to x
semitones (-127..127). With each buffer iteration, this value gets added accumulatively to the original note number. E.g. with a note shift setting of x = 12
, a recorded note 60
will be played as note 72
during the first buffer iteration, as note 84
during the second iteration, etc. Default is x = 0
.
I2M.B.VSHIFT x
Set the velocity shift of recorded notes to x
(-127..127). With each buffer iteration, this value gets added accumulatively to the original note velocity. E.g. with a velocity shift setting of x = -10
, a recorded note with velocity 110
will be played with velocity 100
during the first buffer iteration, with velocity 90
during the second iteration, etc. Default is x = 0
. Please note: This setting is the twin sibling of I2M.B.FB
: While I2M.B.FB
defines the number of iterations determining the amount of change in velocity per iteration, I2M.B.VSHIFT
defines the amount of change in velocity per iteration determining the number of iterations.
I2M.B.TSHIFT x
Set the note duration shift ("time shift") of recorded notes to x
ms (-16384..16383). With each buffer iteration, this value gets added accumulatively to the original note duration. E.g. with a duration shift setting of x = 100
, a recorded note with duration 200
will be played with duration 300
during the first buffer iteration, with duration 400
during the second iteration, etc. Default is x = 0
.
I2M.B.NOFF x
Set the note offset of recorded notes to x
semitones (-127..127). This value gets added once to the original note number and is then kept for all buffer iterations. E.g. with a note offset setting of x = 7
, a recorded note 60
will be played as note 67
for all buffer iterations. Default is x = 0
.
I2M.B.VOFF x
Set the velocity offset of recorded notes to x
(-127..127). This value gets added once to the original note velocity and is then kept for all buffer iterations. E.g. with a velocity offset setting of x = -50
, a recorded note with velocity 120
will be played with velocity 70
for all buffer iterations. Default is x = 0
.
I2M.B.TOFF x
Set the note duration offset ("time offset") of recorded notes to x
ms (-16384..16383). This value gets added once to the original note duration and is then kept for all buffer iterations. E.g. with a duration offset setting of x = -50
, a recorded note with duration 200
will be played with duration 150
for all buffer iterations. Default is x = 0
.
I2M.B.CLR
Clear the buffer, erasing all recorded notes in the buffer.
I2M.B.MODE x
Set the buffer mode to x
(0..1). The buffer can work in two different modes: 1) Digital 2) Tape. In Digital mode, the buffer speed ( set via I2M.B.SPE
) works independent of note number and note duration: If the buffer speed changes, the note number and note duration of a recorded note stays unaffected. In Tape mode on the other hand, the buffer speed affects the note number and note duration of recorded notes in the buffer, mimicking the behaviour of real tape. If the buffer speed gets doubled, the note number is pitched up by one octave and the note duration gets divided in half. Similarly, if the buffer speed gets divided in half, the note number is pitched down an octave and the note duration gets doubled, etc. Default is x = 0
.
Send MIDI CCs
I2M.CC x y
Send MIDI CC message for controller x
(0..127) with value y
(0..127) on current channel.
I2M.CC# ch x y
Send MIDI CC message for controller x
(0..127) with value y
(0..127) on channel ch
(1..32).
I2M.CCV x y
Send MIDI CC message for controller x
(0..127) with volt value y
(0..16383, 0.. 10V) on current channel.
I2M.CCV# ch x y
Send MIDI CC message for controller x
(0..127) with volt value y
(0..16383, 0.. 10V) on channel ch
(1..32).
I2M.CC.OFF x
I2M.CC.OFF x y
Get current offset / Set offset of values of controller x
(0..127) to y
(-127..127) for current channel. Default is y = 0
.
I2M.CC.OFF# ch x
I2M.CC.OFF# ch x y
Get current offset / Set offset of values of controller x
(0..127) to y
(-127..127) for channel ch
(1..32). Default is y = 0
.
I2M.CC.SLEW x
I2M.CC.SLEW x y
Get current slew time / Set slew time for controller x
(0..127) to y
ms (0..32767) for current channel. i2c2midi will ramp from the controller's last value to a new value within the given time x
, sending MIDI CCs at a maximum rate of 30 ms. If the slewing is still ongoing when a new value is set, the slewing uses its current position as the last value. Is 8 CC controller values can be slewed simoultaneously before the oldest currently slewing value is overwritten by the newest. Default is y = 0
.
I2M.CC.SLEW# ch x
I2M.CC.SLEW# ch x y
Get current slew time / Set slew time for controller x
(0..127) to y
ms (0..32767) for channel ch
(1..32). i2c2midi will ramp from the controller's last value to a new value within the given time x
, sending MIDI CCs at a maximum rate of 30 ms. If the slewing is still ongoing when a new value is set, the slewing uses its current position as the last value. Is 8 CC controller values can be slewed simoultaneously before the oldest currently slewing value is overwritten by the newest. Default is y = 0
.
I2M.CC.SET x y
Send MIDI CC message for controller x
(0..127) with value y
(0..127) on current channel, bypassing any slew settings.
I2M.CC.SET# ch x y
Send MIDI CC message for controller x
(0..127) with value y
(0..127) on channel ch
(1..32), bypassing any slew settings.
Send MIDI NRPN messages
I2M.NRPN x y z
Send MIDI NRPN message (high-res CC) for parameter MSB x
and LSB y
with value y
(0..16383) on current channel.
I2M.NRPN# ch x y z
Send MIDI NRPN message (high-res CC) for parameter MSB x
and LSB y
with value y
(0..16383) on channel ch
(1..32).
I2M.NRPN.OFF x y
I2M.NRPN.OFF x y z
Get current offset / Set offset of values of NRPN messages to z
(-16384..16383) for current channel. Default is z = 0
.
I2M.NRPN.OFF# ch x y
I2M.NRPN.OFF# ch x y z
Get current offset / Set offset of values of NRPN messages to z
(-16384..16383) for channel ch
(1..32). Default is z = 0
.
I2M.NRPN.SLEW x y
I2M.NRPN.SLEW x y z
Get current slew time / Set slew time for NRPN messages to z
ms (0..32767) for current channel. Default is z = 0
.
I2M.NRPN.SLEW# ch x y
I2M.NRPN.SLEW# ch x y z
Get current slew time / Set slew time for NRPN messages to z
ms (0..32767) for channel ch
(1..32). Default is z = 0
.
I2M.NRPN.SET x y z
Send MIDI NRPN message for parameter MSB x
and LSB y
with value y
(0..16383) on current channel, bypassing any slew settings.
I2M.NRPN.SET# ch x y z
Send MIDI NRPN message for parameter MSB x
and LSB y
with value y
(0..16383) on channel ch
(1..32), bypassing any slew settings.
Send other MIDI messages like Program Change, Pitch Bend and Clock
I2M.PRG x
Send MIDI Program Change message for program x
(0..127)
I2M.PB x
Send MIDI Pitch Bend message with value x
(-8192..8191)
I2M.AT x
Send MIDI After Touch message with value x
(0..127)
I2M.CLK
Send MIDI Clock message, for now: interpreted as quarter note
I2M.START
Send MIDI Clock Start message
I2M.STOP
Send MIDI Clock Stop message
I2M.CONT
Send MIDI Clock Continue message
I2M.PANIC
Send MIDI Note Off messages for all notes on all channels, and reset note duration, shift, repetition, ratcheting, min/max
Settings for incoming MIDI messages
I2M.Q.CH
I2M.Q.CH x
I2M.Q.# x
Get currently set MIDI channel / Set MIDI channel x
(1..16) for MIDI in. Default is x = 1
.
I2M.Q.LATCH x
Turn on or off latching for MIDI notes received via MIDI in. x = 0
means Note Off messages are recorded in the note history, so only notes with keys currently held down on the MIDI controller are stored. x = 1
means Note Off messages are not recorded in the note history, so notes are still stored after releasing the respective key on the MIDI controller. Default is x = 1
.
Access the note history – the eight last received note numbers and velocities
I2M.Q.NOTE x
I2M.Q.N
Get x
(0..7) last note number (0..127) received via MIDI in
I2M.Q.VEL x
I2M.Q.V
Get x
(0..7) last note velocity (1..127) received via MIDI in
Access the stored data of CC values received via MIDI in
I2M.Q.CC x
Get current value (0..127) of controller x
(0..127) received via MIDI in
Get the respective latest value reveived via MIDI in
I2M.Q.LCH
Get the latest channel (1..16) received via MIDI in
I2M.Q.LN
Get the note number (0..127) of the latest Note On received via MIDI in
I2M.Q.LV
Get the velocity (1..127) of the latest Note On received via MIDI in
I2M.Q.LO
Get the note number (0..127) of the latest Note Off received via MIDI in
I2M.Q.LC
Get the latest controller number (0..127) received via MIDI in
I2M.Q.LCC
Get the latest controller value (0..127) received via MIDI in
Use the same OP but specify the channel within the OP itself. Simply add #
to the OP name and the desired channel number as the first argument.
This way you can easily send information to different channels, without the need to use I2M.CH
. E.g. send three different CC messages to controller 1 on channels 1, 2 and 3:
I2M.CC# 1 1 10
I2M.CC# 2 1 RND 99
I2M.CC# 3 1 RND 60 120
The following channel-specific OP variants are available:
I2M.T#
I2M.S#
I2M.MIN#
I2M.MAX#
I2M.REP#
I2M.RAT#
I2M.N#
I2M.NO#
I2M.NT#
I2M.C#
I2M.CC#
I2M.CCV#
I2M.CC.OFF#
I2M.CC.SLEW#
I2M.CC.SET#
I2M.NRPN#
I2M.NRPN.OFF#
I2M.NRPN.SLEW#
I2M.NRPN.SET#
Scales in i2c2midi do not work like a quantizer where notes "outside" of the scale are forced in place. Instead, i2c2midi will respect "outside" notes and keep their position in respect to the defined scale. This means, you can use a scale for chord transformations and still intentionally define notes in your chord that are not part of that scale.
Let's say, you define chord 1 with notes 0,4,7,8
and set a major scale 0,2,4,5,7,9,11
via chord 2, note 8
of chord 1 will be "outside" the scale – instead of removing this note or forcing it into another note, i2c2midi will store the nearest note in the scale (7
) and the respective delta ( 1
). In other words, this note will be treated by i2c2midi as the "5th note in the scale raised by 1 semitone".
Let's break this down step by step:
-
The following three lines of Teletype code will define two chords, and set chord 2 as the scale for chord 1:
I2M.C.B 1 R100010011 // define chord 1: 0,4,7,8 I2M.C.B 2 R101011010101 // define chord 2: 0,2,4,5,7,9,11 (major scale) I2M.C.SC 1 2 // set chord 2 as scale for chord 1
-
Chord 1 has a note that is not part of the scale defined by Chord 2:
Notes0
✅,4
✅ and7
✅ are part of the scale, Note8
❗️ is not:Note Name C C# D D# E F F# G G# A A# B Chromatic Scale 0 1 2 3 4 5 6 7 8 9 10 11 Def. Scale (e.g. Chord 2) 0 2 4 5 7 9 11 Def. Chord (e.g. Chord 1) 0 ✅ 4 ✅ 7 ✅ 8❗️ How i2c2midi stores the Chord 0 4 7 7 1 -
If notes in a chord are not part of the defined scale, i2c2midi looks for the nearest scale note and stores this note together with the respective delta.
In this example the note not beeing part of the scale is8
. The nearest note in the scale would be7
, and the delta would be1
. So, i2c2midi will store0,4,7,7 1
. -
Without any Chord Transformations, Chord 1 will be playing exactly as defined:
0,4,7,8
– the defined scale has no effect yet. But as soon as we use Chord Transformations, each transformation will happen within the defined scale, and the "outside" note8
will also be transformed within the scale as note7 1
:Transformation → Note 1 Note 2 Note 3 Note 4 → Resulting Chord Transpose = 0 0 4 7 7 1 0, 4, 7, 8 Transpose = 1 2 5 9 9 1 2, 5, 9, 10 Transpose = 2 4 7 11 11 1 4, 7, 11, 12 Transpose = 3 5 9 0 12 0 12 1 5, 9, 12, 13 Transpose = 4 7 11 2 12 2 12 1 7, 11, 14, 15 Transpose = 5 9 0 12 4 12 4 12 1 9, 12, 16, 17 Transpose = 6 11 2 12 5 12 5 12 1 11, 14, 17, 18 Transpose = 7 0 12 4 12 7 12 7 12 1 12, 16, 19, 20 Transpose = 8 2 12 5 12 9 12 9 12 1 14, 17, 21, 22
Curve transformations allow you to manipulate the notes of a chord in different ways. Like chord transformations, curve transformations are intentionally designed to encourage experimentation, inviting unexpected and surprising results.
There are two types of curves:
-
Velocity Curve: Manipulates the velocity of each note in a chord
-
Time Curve: Manipulates the strumming of notes in a chord
Curves are defined by three parameters: A start value (%), an end value (%), and a curve type. Start and end values are percentage values, referring to the respective originally set value (velocity for velocity curve, strumming for time curve). The curve type defines the inpolation of values between the defined start and end values. There are different types available:
-
- Linear: Linear from start to end
-
- Exponential: Exponential from start to end
-
- Triangle: Linear from start to end to start
-
- Square: Alternating between start and end
-
- Random: Random values between start and end
Here are some examples :
Example: Chord with 3 notes Note duration: 1000 ms; Start: 1%; End: 100%
Curve Type | Value 1 | Value 2 | Value 3 |
---|---|---|---|
0) Off | 1000 | 1000 | 1000 |
1) Linear | 10 | 505 | 1000 |
2) Exponential | 10 | 133 | 1000 |
3) Triangle | 10 | 1000 | 10 |
4) Square | 10 | 1000 | 10 |
5) Random | 907 | 393 | 729 |
Example: Chord with 4 notes Note duration: 1000 ms; Start: 1%; End: 100%
Curve Type | Value 1 | Value 2 | Value 3 | Value 4 |
---|---|---|---|---|
0) Off | 1000 | 1000 | 1000 | 1000 |
1) Linear | 10 | 340 | 670 | 1000 |
2) Exponential | 10 | 46 | 303 | 1000 |
3) Triangle | 10 | 505 | 1000 | 505 |
4) Alternating | 10 | 1000 | 10 | 1000 |
5) Random | 863 | 47 | 677 | 841 |
Example: Chord with 8 notes Note duration: 1000 ms; Start: 1%; End: 100%
Curve Type | Value 1 | Value 2 | Value 3 | Value 4 | Value 5 | Value 6 | Value 7 | Value 8 |
---|---|---|---|---|---|---|---|---|
0) Off | 1000 | 1000 | 1000 | 1000 | 1000 | 1000 | 1000 | 1000 |
1) Linear | 10 | 151 | 292 | 434 | 575 | 717 | 858 | 1000 |
2) Exponential | 10 | 12 | 33 | 87 | 194 | 370 | 633 | 1000 |
3) Triangle | 10 | 257 | 505 | 752 | 1000 | 752 | 505 | 257 |
4) Alternating | 10 | 1000 | 10 | 1000 | 10 | 1000 | 10 | 1000 |
5) Random | 468 | 781 | 472 | 34 | 546 | 164 | 301 | 189 |
i2c2midi comes in two hardware versions:
- MKI
- First iteration
- 4 HP
- TRS, no USB
- Works with current firmware
- MKII
- Second and current iteration
- 2 HP
- TRS and USB Host
- Works with current firmware
- Here's the build guide for i2c2midi MKII
- Looking for i2c2midi MKI? Here's all info about MKI
Number | Part | Value |
---|---|---|
1 | T36 | Teensy 3.6 (with pins or without pins), or Teensy 4.1 |
2 | C1 | 10 uF capacitor |
3 | C2 | 10 uF capacitor |
4 | D1 | LED 3 mm |
5 | D2 | LED 3 mm |
6 | IC1 | LM1117 5V regulator |
7 | R1 | 47 Ω resistor |
8 | R2 | 47 Ω resistor |
9 | R3 | 2.2k Ω resistor |
10 | R4 | 2.2k Ω resistor |
11 | R5 | 220 Ω resistor |
12 | R6 | 220 Ω resistor |
13 | TRS | Green Thonkiconn Stereo 3.5mm Audio Jack (PJ366ST) |
14 | USB | USB Jack Type A vertical |
15 | POW | 2x5 male pin header angled |
16 | I2C | 2x3 male pin header angled |
17 | 1x10 male pin header angled | |
18 | 10 mm M3 Hex standoff | |
19 | 10 mm M3 screw | |
20 | 10 mm M3 screw | |
21 | Nut for Thonkiconn | |
22 | 1x5 male pin header (for USB host) | |
23 | 1x24 male pin header (if Teensy has no pins) | |
24 | 1x24 male pin header (if Teensy has no pins) |
- Here are the gerber files
- Here are some more details about ordering the PCB and Panel from a manufacturer
Teensy | TRS | MIDI |
---|---|---|
Teensy Pin 1 | → Tip | → MIDI Pin 5 |
Teensy 3V3 | → Ring | → MIDI Pin 4 |
Ground | → Sleeve | → MIDI Pin 2 |
- Backup your scenes from Teletype! Your scenes will be gone after the firmware update.
- Then follow the instructions detailed over at monome.
- When the firmware has been flashed successfully, a message appears on Teletype's screen:
Scenes will be overwritten! Press to confirm; Do not press otherwise!
Please make sure to press the button, before the message disappears (ca. 2-3 seconds). Otherwise the update might not work. This is a special quirk of installing a BETA firmware on Teletype.
- Caution: Don't connect the module to Euro power and USB at the same time!
- Download the latest release here.
- Unzip the files and open
firmware/i2c2midi_firmware/i2c2midi_firmware.ino
with Teensyduino. - Depending on your hardware, change the following settings:
- For MKI / Teensy 3.2:
- Set line 37 to
//#define MK2
- Set line 40 to
#define TEENSY3X
- Set line 41 to
//#define TEENSY41
- Set line 37 to
- For MKII / Teensy 3.6:
- Set line 37 to
#define MK2
- Set line 40 to
#define TEENSY3X
- Set line 41 to
//#define TEENSY41
- Set line 37 to
- For MKII / Teensy 4.1:
- Set line 37 to
#define MK2
- Set line 40 to
//#define TEENSY3X
- Set line 41 to
#define TEENSY41
- Set line 37 to
- For MKI / Teensy 3.2:
- Make sure to install all necessary libraries (see list of libraries below). More info on how to install libraries.
- Connect the Teensy to your computer with a USB cable. Caution: Don't connect the module to Euro power and USB at the same time! (Unless you have cut the "5V pad" during your build)
- Under
Tools
:- set
Board
toTeensy 3.2
,Teensy 3.6
orTeensy 4.1
- set
USB Type
toSerial
- set
CPU Speed
to96 MHz
for Teensy 3.6 and150 MHz
for Teensy 4.1 - select the Port that shows the Teensy
- set
- Upload the firmware to your Teensy via
Sketch
→Upload
. - If the upload was successfull, Teensyduino says
Done uploading
and i2c2midi lights up with both LEDs turning on and off four times.
- Version 5.0.1
- Bugfix for Teensyduino 1.58
- Version 5.0.0 (works with Teletype Firmware
5.0.0 BETA 1
Link)- New OP
I2M.MUTE
/I2M.MUTE#
: Get/Set mute state of MIDI channel - New OP
I2M.SOLO
/I2M.SOLO#
: Get/Set solo state of MIDI channel
- New OP
- Version 4.4.1 ( Teletype Firmware
I2M BETA 3.1
)- Bugfix: Chord 1 could not be set as a scale
- Version 4.4.0 ( Teletype Firmware
I2M BETA 3.1
)- New OP
I2M.C.QN
: Get the transformed chord note at index - New OP
I2M.C.QV
: Get the transformed chord note velocity at index
- New OP
- Version 4.3.0 ( Teletype Firmware
I2M BETA 3
)- New looping MIDI buffer / MIDI recorder feature, with new OPs:
I2M.B.R
,I2M.B.L
,I2M.B.START
,I2M.B.END
,I2M.B.DIR
,I2M.B.SPE
,I2M.B.FB
,I2M.B.NSHIFT
,I2M.B.VSHIFT
,I2M.B.TSHIFT
,I2M.B.NOFF
,I2M.B.VOFF
,I2M.B.TOFF
,I2M.B.CLR
,I2M.B.MODE
- New OP
I2M.C.DIR
: Set a play direction for a chord
- New looping MIDI buffer / MIDI recorder feature, with new OPs:
- Version 4.2.0 ( Teletype Firmware
I2M BETA 2
)- New channel-specific OP variants for most of the existing OPs
- New OP
I2M.NT
: Send a note with specific duration - New OP
I2M.C.B
: Define chord using reverse binary notation (R...
) - New OP
I2M.C.SC
: Set scale for chord based on another chord - New chord transformations:
I2M.C.TRP
: Transpose chordI2M.C.DIS
: Distort chord based on an anchor pointI2M.C.REF
: Reflect chord based on an anchor pointI2M.C.VCUR
: Apply velocity curve to chord notesI2M.C.TCUR
: Apply time curve to chord notes
- New alias for
I2M.CH
:I2M.#
- New alias for
I2M.Q.CH
:I2M.Q.#
- BREAKING: New modes for
I2M.MIN
andI2M.MAX
: Ignore notes, clamp notes, fold back notes by one octave, fold back notes by multiple octaves - BREAKING: Removed getter OPs for
I2M.MIN
,I2M.MAX
,I2M.C.ROT
,I2M.C.INV
,I2M.C.STR
because OPs have multiple parameters - BREAKING: Removed
I2M.NC
,I2M.NOC
,I2M.CCC
,I2M.CCVC
; replaced by channel-specific OP variants
- Version 4.1.0
- Experimental support for Teensy 4.1
- Version 4.0.0 ( Teletype Firmware
I2M BETA 1
) (more info)- Completely rewritten firmware with support for i2c2midi's dedicated Teletype OPs (
I2M
). - Updated README.
- Completely rewritten firmware with support for i2c2midi's dedicated Teletype OPs (
- Version 3.1.0
- Added feature flag to use i2c2midi as USB device, using the Teensy Micro USB jack.
- Fixed a bug where unknown I2C request messages would freeze the I2C bus.
- Version 3.0.0 (MKII)
- Firmware for i2c2midi hardware MKII, adding USB Host functionality.
- Arduino MIDI Library
MIT License – Copyright (c) 2016 Francois Best
https://github.com/FortySevenEffects/arduino_midi_library - I2C_t3
MIT License – Copyright (c) 2013-2018, Brian (nox771 at gmail.com)
https://github.com/nox771/i2c_t3 - USBHost_t36
MIT License – Copyright 2017 Paul Stoffregen ([email protected])
https://github.com/PaulStoffregen/USBHost_t36 - teensy4_i2c
MIT License – Copyright © 2019-2020 Richard Gemmell
https://github.com/Richard-Gemmell/teensy4_i2c - Ramp
GPL-3.0 License – Sylvain GARNAVAULT - 2016/08/07
https://github.com/siteswapjuggler/RAMP
@mreid created a great library that connects i2c2midi to monome crow:
https://github.com/mreid/crow-i2c2midi
A huge Thank You to the legendary scanner-darkly who not only implemented i2c2midi's Teletype OPs, but also joined forces with me in designing the feature set and OP concept for MKII.
Also, many thanks to everyone who contributed and helped making this module a reality (in no particular order): Ansome, Tom Whitwell, Konstantine, mxmxmx, littlescale, non.verbal.poetry, free_art_ideas.
- https://www.pjrc.com/teensy/external_power.html
- https://www.pjrc.com/teensy/td_libs_MIDI.html
- https://github.com/PaulStoffregen/USBHost_t36
- https://github.com/nox771/i2c_t3
- https://github.com/TomWhitwell/MTM-Parts-Library
- https://github.com/monome/teletype/blob/main/docs/ops/i2c.toml
- https://doepfer.de/DIY/a100_diy.htm