🛠 Contrôleur MIDI complet : encodeurs, multiplexage 74HC4051 et MIDIx16
Objectives
Move from the 3 buttons in the beginner tutorial to a real DIY MIDI controller — the historical specialty of the Teensy 3.2: buttons, rotary encoders, and rows of potentiometers, multiplexed to save pins, published over 16 virtual MIDI cables (MIDIx16). You will use the MIDIcontroller library (Josh Nishikawa), published for this use case, and you will address the two documented pitfalls: crosstalk in multiplexed potentiometers and USB buffer overflow.
Hardware
- 1 Teensy 3.2
- 8 rotary encoders with push button (quadrature + switch)
- 16 10 kΩ potentiometers multiplexed by 2 74HC4051 chips (8 analog inputs each → 3 address pins per chip)
- 16 push buttons (matrix or direct depending on remaining pins)
- USB cable; DAW or MIDI monitor for validation
Architecture
- USB Type: MIDIx16 (Tools > USB Type): 16 virtual MIDI cables, up to 16 messages per USB packet — each section of the controller can live on its own cable.
- MIDIcontroller library (<https://github.com/joshnishikawa/MIDIcontroller>): handles buttons, encoders, aftertouch, and channel/cable routing; Yann Seznec published his open-source MIDI controller code on the PJRC forum — a reference for structure (button scanning, encoder reading, CC sending).
- Drain rule: even in pure transmission mode, call
while (usbMIDI.read) { }at each loop iteration — otherwise USB buffers fill up and the controller freezes (Issue #10 on the USB MIDI page).
The 74HC4051 pitfall: letting the signal stabilize
When changing the selected channel of a 74HC4051 multiplexer, the analog input needs a settling time of at least 50 µs — more if capacitors are present — otherwise the previous channel continues to influence the reading: potentiometers "read into each other" (PJRC forum thread "Potentiometers affecting each others when connected to 74HC4051").
// Squelette de lecture multiplexee avec settling time.
const int ADDR[] = {A0, A1, A2}; // adresses du 4051
void selectCanal(uint8_t n) {
for (int i = 0; i < 3; i++) digitalWrite(ADDR[i], (n >> i) & 1);
delayMicroseconds(60); // >= 50 us de stabilisation (forum PJRC)
}
uint16_t lirePot(uint8_t canal) {
selectCanal(canal);
return analogRead(A3); // sortie commune du 4051 -> A3
}
Sending messages
#include <MIDIcontroller.h>
// Exemple de declaration (voir README de la biblio pour la signature exacte) :
// MIDIcontroller ctl = MIDIcontroller(NUM_BUTTONS, NUM_SLIDERS, ...);
// A chaque tour de loop :
// ctl.encode(encodeurPin, canal, numeroCC);
// ctl.button(boutonPin, canal, numeroNote);
// ctl.slider(canalMux, canal, numeroCC);
// puis TOUJOURS :
void loop {
// ... scan des entrees, envois CC/Note ...
while (usbMIDI.read) { } // draine les messages entrants
}
Compatibility breaks to know (Teensyduino ≥ 1.41)
- The pitch bend range changed from 0…16383 to +8191…−8192; the values of
getTypehave changed — old controller sketches must be adapted. - MIDI-OX on Windows: specific "input only" configuration required (section "Teensyduino 1.40 & Earlier" on the PJRC page).
Expected verification
In the DAW: the Teensy appears with 16 MIDI cables; turn encoder 1 → the corresponding CC moves on the chosen cable; move a multiplexed potentiometer → its value follows cleanly, without neighbors jumping (proof that the 60 µs settling time is doing its job). Let the DAW send MIDI clock for 10 minutes: without the usbMIDI.read drain, the controller freezes — with it, it holds.
Common errors
- Skipping the
delayMicrosecondsafter changing the 4051 channel: channels read into each other — the symptom is exactly "my potentiometers influence each other". - Adding anti-noise capacitors on each pot without increasing the settling time: more capacitance = more delay needed.
- Forgetting the
usbMIDI.readdrain: crash after a few minutes, often wrongly attributed to USB power supply. - Selecting simple MIDI instead of MIDIx16: the DAW only sees one cable and sections interfere with each other.
- Copying an old pre-1.41 tutorial: inverted pitch bend and
getTyperesult in "crazy" controllers on modern versions. - Pin overflow: the 34 I/Os of the 3.2 run out quickly with 8 quadrature encoders — hence the multiplexing (or a shift register like 74HC165 for buttons).
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
- Un instrument MIDI USB en 10 minutes : Bounce, boutons et règle d'or du drain
- 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
Code examples for this board
clignotante.inoArduinotouche-capacitive.inoArduinoanalogique-12-bits.inoArduinomidi-piano.inoArduinopwm-respiration.inoArduinoservo-angle.inoArduino