About MIDI

A project log for Teensymoog

A re-creation of the minimoog using Teensy 4.0

Pierre-Loup M.Pierre-Loup M. 04/13/2020 at 18:524 Comments

Although not present on the original minimoog, midi is something so omnipresent and usefull I couldn't not implement it.
It happens it is quite easy to do with the Arduino environment, thanks to this library from FortySevenEffects. It's even easier with Teensy, has the library is automatically implemented when you choose MIDI as the kind of USB output.

There are two "kinds" of midi on the synth. One is what is expected from a modern music instrument, i.e. the ability to interact with other instruments.

---------- more ----------

This part is pretty straightforward for now : the synth appears as a MIDI USB device when connected on a computer (or anything where you can plug a MIDI device via USB). Key press, pitchbend and modulation are transmitted whenever they change, and can be received and processed by the synth as well.

The second MIDI kind is the one used for communication between the Teensy that handles the audio processing, and the two Arduino Mega that read keyboard switches and potentiometers.

The keyboard is easy : the Arduino simply sends note on when a key is pressed, and note off when released. As the keybed used is not velocity sensitive, a default velocity of 64 has been chosen. The only thing to note is that the keys start at 0 (midi note 0, C-1), and they are offset in the Teensy part. It makes things easier to apply octave offset, among other things.
For controls, I tried to stick as much as possible to the midi specification. For some it's easy. For example MIDI defines CC1 as modulation wheel. CC5 is portamento time. Whenever it was possible, the official CC number was used to map functions sent from Arduinos to teensy. Most MIDI messages use a 7-bits value to send information. for some controls it's ok, but I had fear that for others it would not be a fine enough resolution. It happens that (probably) for this reason, the first 32 control change are 14 bits wide, with the 7 MSB sent on CC0-CC31, and the associate 7LSB sent on CC32-63. So some controls have been mapped to undefined CC in the 0-31 + 32-63 range. It's the case for both general and filter envelopes, filter cutoff frequency and resonance, the five mix knobs, to name a few. Attack and release often use CC73 & 72, filter cuttoff CC74. They have been assigned to CC59, 60 & 52, respectively.

This poses a problem. Using the "official" control change numbers would have enable to simply map internal controls to external MIDI. Here is how it's done on Teensy :

There is room for improvement here. As much as possible of the controls should be accessed through MIDI when connecting the synth to a computer or anything else, but having those numbers would mean having to handlers, and probably using setting functions for every control, capable of handling 14 and 7-bits wide ranges, instead of this unique handler with this looong switch/case statement.

It would also open the door to something usefull : the ability to save and recall presets.

Two websites have been used for checking which CC numbers to use :


J. M. Hopkins wrote 04/14/2020 at 12:31 point

On my Teensy synth I have 100+ CC channels being mapped to various things, all being controlled via an OSC interface. I disregard all 'standard' CC channel mapping except for a few.

I take all CC channels and just handle them in a processMIDI

 if ( {

  byte type, data1, data2;
  type = usbMIDI.getType();       // which MIDI message, 128-255
  data1 = usbMIDI.getData1();     // first data byte of message, 0-127
  data2 = usbMIDI.getData2();     // second data byte of message, 0-127
  float data2f = data2/127.0;       //float value for teensy audio objects

case usbMIDI.ControlChange: // 0xB0
      switch(data1) {
          modulation.amplitude(data2f, modulation_ramp_rate);


I'll keep going down the case statement for each CC message. It works out quite well for modifying teensy objects.

Full source here:

I even have SD card based patch save/recall

  Are you sure? yes | no

Pierre-Loup M. wrote 04/14/2020 at 16:03 point

Hi Jeff,

Thank you for your explanation ! It's quite close to what I've implemented in my code, except I've used the handy handler function from the MIDI library.

I've thought about OSC as another protocol for communication. I know it's used by a lot of devices, and I've used it myslef to make a monome-like pad comuunicate with puredata.
As the synth is much more common layout than you project (which sounds really great, I'm impressed by how the sounds it creates seems natural ! ), sticking as much as possible to what already exists seemed important to me.

In fact at first I was going to simply use (internal) MIDI, simply as a way to avoid writing a reliable communication protocol between the three boards involved, which can be be harder than expected.

  Are you sure? yes | no

J. M. Hopkins wrote 04/14/2020 at 18:31 point

TouchOSC has just been so handy that I can just make a slider and assign a CC channel, it’s a no brainer for “unlocking” synths to the multitude of controls you can add without a physical interface. 

I really enjoy the tactile physical synth knobs, but particularly when defining work flows etc, being able to drag and drop slider and knobs anywhere and assign them to any of my midi devices is undeniably awesome. 

Loading and saving patches as structs to the SD card is also super useful because I can pull the as card and share patches now too

  Are you sure? yes | no

Pierre-Loup M. wrote 04/14/2020 at 22:55 point

Yes, using a software interface is very convenient. I didn't know touchOSC, i'm going to have a deep look at it.
For this synth I used a puredata patch, that was very handy to have the code running and debugged before to build the whole thing. And it helped to make choices as well, some functions were added, others removed. ;)

  Are you sure? yes | no