🛠 Un instrument MIDI USB en 10 minutes : Bounce, boutons et règle d'or du drain
Objectives
Turn the Teensy 3.2 into a USB musical instrument: its 12 Mbit/s USB device port is reconfigurable at will (Serial, MIDI, MIDIx4/MIDIx16, Audio, Keyboard, Mouse, Joystick, Flightsim, RawHID…) via Tools > USB Type. This tutorial builds a mini-keyboard with 3 buttons using the Bounce library, applying the golden rule of MIDI controllers stated by PJRC: always drain incoming messages, otherwise USB buffers fill up and everything freezes.
Hardware
- 1 Teensy 3.2
- 3 push buttons connected to pins 1, 2, 3 (the other side of each button goes to GND; internal pull-ups are enabled by the code)
- USB cable to a PC with a sequencer (DAW), MIDI-OX (Windows) or any MIDI monitor
- No additional components: mechanical buttons are debounced in software by Bounce
Complete Code
Official example from PJRC's USB MIDI tutorial (original comments):
#include <Bounce.h> // Bounce library makes button change detection easy
const int channel = 1;
Bounce button1 = Bounce(1, 5); // 5 = 5 ms debounce time
Bounce button2 = Bounce(2, 5); // appropriate for good quality
Bounce button3 = Bounce(3, 5); // mechanical pushbuttons
void setup {
pinMode(1, INPUT_PULLUP);
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
}
void loop {
button1.update;
button2.update;
button3.update;
// Note On when each button is pressed
if (button1.fallingEdge) usbMIDI.sendNoteOn(60, 99, channel); // 60 = C4
if (button2.fallingEdge) usbMIDI.sendNoteOn(61, 99, channel); // 61 = C#4
if (button3.fallingEdge) usbMIDI.sendNoteOn(62, 99, channel); // 62 = D4
// Note Off on release
if (button1.risingEdge) usbMIDI.sendNoteOff(60, 0, channel);
if (button2.risingEdge) usbMIDI.sendNoteOff(61, 0, channel);
if (button3.risingEdge) usbMIDI.sendNoteOff(62, 0, channel);
// MIDI controllers should discard incoming MIDI messages,
// otherwise USB buffers fill up
while (usbMIDI.read) { }
}
Uploading
Set Tools > USB Type : MIDI BEFORE compiling, then upload normally (Teensy Loader). The board is then recognized as a USB MIDI class-compliant device — no driver installation required on Windows, macOS, or Linux. This is the reason for the Teensy's success in DIY MIDI controllers.
Expected Verification
Open your DAW or MIDI-OX: the Teensy appears as a MIDI input. Each press triggers C4/C#4/D4 (notes 60/61/62, velocity 99) and the release sends the corresponding Note Off. Now test the drain rule: if your sequencer sends messages back (aftertouch, MIDI clock, MTC synchronization…), the absence of the while (usbMIDI.read) { } loop fills the USB buffers and freezes the controller after a few minutes — this is the most reported bug.
Common Errors
- Forgetting Tools > USB Type: MIDI: the sketch compiles in Serial mode and usbMIDI does nothing at runtime — change the USB type, recompile, and re-upload.
- Breaking the drain rule: even a "transmitter-only" controller must still consume usbMIDI.read in a loop.
- Teensyduino 1.41 compatibility break: the pitch bend range changed from 0…16383 to +8191…−8192 and the values returned by getType have changed — adapt old sketches (see the "Teensyduino 1.40 & Earlier" section on the PJRC page).
- MIDI-OX on Windows: requires specific "input only" configuration to avoid blocking — follow the USB MIDI page.
- Confusing virtual cables: MIDIx4/MIDIx16 expose 4 or 16 MIDI cables with up to 16 messages per USB packet — powerful for large controllers, but confusing at first (select cable 1 in the DAW).
- Buttons without pull-ups: without INPUT_PULLUP or an external resistor, the pin floats and notes trigger randomly.
Other tutorials for this board
- Premiers pas sur la Teensy 3.2 : Teensyduino, HalfKay et premier Blink
- Broches, ADC 13 bits, DAC 12 bits et PWM : dompter les E/S de la Teensy 3.2
- Audio Shield SGTL5000 : boucle stéréo 44,1 kHz et outil de conception graphique
- OctoWS2811 : piloter 8 rubans WS2812 en parallèle par DMA (presque zéro CPU)
- Timers matériels, interruptions imbriquées et FASTRUN : la vitesse Cortex-M4
- Intégration produit : alimentation VIN/VUSB, régulateur 250 mA, RTC à quartz et EEPROM
Code examples for this board
clignotante.inoArduinotouche-capacitive.inoArduinoanalogique-12-bits.inoArduinomidi-piano.inoArduinopwm-respiration.inoArduinoservo-angle.inoArduino