MIDI for your serial devices

In a nutshell

ttymidi is a GPL-licensed program that allows external serial devices to interface with ALSA MIDI applications. The main motivation behind ttymidi was to make Arduino boards talk to MIDI applications without the need to use (or build) any extra hardware.


If you are using an Arduino board, simplest will be to use Arduino MIDI library, as described in the following sections. You may also use less sophisticated ardumidi library that is provided with ttymidi download package. If you are using another device, you should read the rest of this page to see how your device should communicate. Once your device is programmed and connected to your PC, ttymidi is executed in the following manner:

ttymidi -s /dev/ttyS0 -b 9600

Where /dev/ttyS0 is the serial port you want to read from, and 9600 is the bitrate. For Arduino with serial connection runnning at 115200bps (the default rate for ttymidi) the command would be:

Arduino Diecimila:

ttymidi -s /dev/ttyUSB0 -v

Arduino UNO:

ttymidi -s /dev/ttyACM0 -v

Where the -v gives me verbose output, which helps me when I'm debugging.

ttymidi creates an ALSA MIDI input and output ports that can be interfaced to any compatible program. This is done in the following manner:

# start ttymidi
ttymidi -s /dev/ttyUSB0 &

# start some ALSA compatible MIDI 
# program (timidity, in this case)
timidity -iA &                    

# list available MIDI input clients
aconnect -i                       

# list available MIDI output clients
aconnect -o                       

# connect
aconnect 128:0 129:0

# ...where 128 and 129 are the client 
# numbers for ttymidi and timidity,
# found with the commands above

If you would like to use a graphical interface to connect your MIDI clients, you can use something like qjackctl. As for the program that will consume the MIDI data, there are many out there (other than timidity, which was used in the previous example). Some crowd pleasers are fluidsynth, puredata, sooperlooper and ardour, to cite a few.

If you are using automated patchbay connecting application, such as the patchbay feature of qjackctl or aj-snapshot you might want to rename the name of ttymidi client created by using -n flag.

ttymidi -s /dev/ttyUSB0 -v -n my_weird_controller

Programming your serial device

Arduino MIDI library

ttymidi is nowadays compatible with Arduino MIDI library and we strongly recommend using it when communicating from Arduino to ttymidi. You only need to remember to call Serial.begin(int baud_rate) immediately after MIDI.begin(int channel) on your patch as the serial port of your computer is not able to operate at MIDI baud rate that MIDI library is using. For example:

void setup() {
  MIDI.begin(4);        // will listen incoming MIDI at channel 4
  Serial.begin(115200); // will change baud rate of MIDI traffic from 31250 to 115200

You'll find MIDI library examples with these changes made in ttymidi download package.

Arduino interface

This chapter explains how to use deprecated (but still functional) ardumidi library instead of Arduino MIDI library. To interface to ttymidi, the serial-attached device must send data in MIDI-format. In the case of Arduino boards, a library is provided that abstracts all the nitty-gritty details away. Below is a list of the available functions:

// Start/stop playing a certain note:
midi_note_on(byte channel, byte key, byte velocity);
midi_note_off(byte channel, byte key, byte velocity);

// Change pressure of specific keys:
midi_key_pressure(byte channel, byte key, byte value);

// Change controller value (used for knobs, etc):
midi_controller_change(byte channel, byte controller, byte value);

// Change "program" (change the instrument):
midi_program_change(byte channel, byte program);

// Change key pressure of entire channels:
midi_channel_pressure(byte channel, byte value);

// Change pitch-bend wheel:
midi_pitch_bend(byte channel, int value);

// Check if a MIDI message has arrived from the PC
int midi_message_available();

// Get a MIDI message from the PC
MidiMessage read_midi_message();

// Get the pitch bend value from a MIDI message
int get_pitch_bend(MidiMessage msg);

// Send a comment:
midi_comment(char* str);

// Send a series of bytes (to be interpreted by another program):
midi_printbytes(char* bytes, int len);

Where the parameters are in the range: channel (0–15), pitch-bend value (0–16383), all other values (0–127). The center position of the pitch-bend wheel is 8192.

Since MIDI uses numbers to represent notes, a few useful constants are defined in this library. With them, it is much easier to deal with MIDI nodes. For example:

midi_note_on(0, MIDI_C + MIDI_SHARP - 2*MIDI_OCTAVE, 127)

All notes refer to the 4th octave by default. So the line above plays a C#2. As a shortcut to the 1st octave, constants such as MIDI_C0 can be used.

Similarly, when receiving MIDI messages from the PC, you can use constants to figure out type of the incoming message:

if (midi_message_available() > 0) {
	MidiMessage msg = read_midi_message();
	if (msg.command == MIDI_NOTE_ON && == 0) {
		Since this is a "Note On" command, we know that 
		- msg.param1 is the MIDI note 
		- msg.param2 is the "velocity" of the note 

		How do we know this? See the table below.

There are a couple of things to keep in mind when using MIDI in features of ardumidi. Firstly midi_message_available() will always flush the incoming Serial buffer of all non-MIDI data. In practice this means that you can't mix using the Serial library and ardumidi (unless you know what you are doing). Secondly the incoming Serial buffer of arduino can store at most 42 MIDI commands so you have to take care that buffer does not overflow. However this does not cause your patch to crash, only couple MIDI messages are lost.

To install the ardumidi library, just copy its folder into Arduino's sketchbook/libraries directory. Also note that an example Arduino sketches are included in the ttymidi package. They should appear under Examples in Arduino IDE after you have succesfully installed the library. For instance, ardumidi_test, will play one C-minor chord every second.

General interface

If you are using another serial device in place of the Arduino, you'll need to program it to follow the MIDI specification. To sum this up, most of the commands sent to ttymidi are comprised of 3 bytes:

byte 1       byte 2           byte 3
status       parameter #1     parameter #2

Where status is a combination of a command and a channel. Why is it called status? I haven't a clue, but that's the name in the MIDI spec. The table below describes the codes for each command as well as their associated parameters.

code parameter #1 parameter #2
note off 0x80-0x8F key velocity
note on 0x90-0x9F key velocity
pressure 0xA0-0xAF key pressure
controller change 0xB0-0xBF controller value
program change 0xC0-0xCF program -
channel pressure 0xD0-0xDF value -
pitch bend 0xE0-0xEF range LSB range MSB
bytes 0xFF 0 0

Most of these commands and parameters are self-explanatory. All parameters are given as a number in the range 0–127. That is, they're all 7-bit numbers with a 0 padded to their left (i.e. 0xxxxxxx) in order to make up 1 full byte (8 bits). For channel pressure and program change you should send only one data byte.

One odd MIDI command is the pitch bend, whose parameter is a 14-bit number. For this reason, it is split into two parts: a least significant byte (LSB) and a most significant byte (MSB). These can be easily computed by quick logical and and shift operations:

int range = 12345;
byte range_lsb = range & 0x7F;
byte range_msb = range >> 7;

The bytes command provides a way to send non-MIDI data through the serial port without messing up with ttymidi. All you need to do is send 0xFF 0x00 0x00 len data[0] data[1] ..., where len is the number of data[•] in the message. When seeing such messages, ttymidi will just print them to the screen (but not parse them), so you can use this to print comments from your serial device. You can also use it with sprintf for debugging.

You may have noticed that, for all commands, the 1st byte always has a 1 as the most-significant bit, while the other 2 (or 1) bytes always have a 0. This comes from the MIDI spec, and is used by ttymidi for data alignment purposes. Do not try to change that in your serial device's program, or it will royally mess things up.


Get ttymidi here

The archive includes the ttymidi program, examples for Arduino MIDI library as well as the ardumidi libraries for Arduino. Also, don't forget to read the README file in that is included in the archive. It has important information about compiling ttymidi.

It is possible that a more recent version is available at the project's trunk series.

Found a Bug?

If you find a bug, please report it! I especially like when the report comes with a patch :) but that's not a requirement.



Thiago Teixeira
  • Original developer and maintainer.
  • Jari Suominen
  • New co-maintainer of ttymidi. Originally contributed the MIDI-out code :)
  • Changelog

  • Bugfix release.
  • 0.50
  • Now with MIDI output capability!
  • 0.30
  • Added "super debug mode". Activate it by pass "-p" (which stands for "print only").
  • 0.21
  • Apparently WConstants.h is no longer distributed with the Arduino software. So I had to replace that with WProgram.h .
  • 0.20
  • Added ability to print comments and random bytes to serial port. Fixed the alignment code.
  • 0.11
  • Changed some function names in the Arduino sketch
  • 0.10
  • Initial release
  • Return to Thiago Teixeira's main website