MIDI (musical instrument digital interface) controllers are industry-standard digital devices used to manipulate digital audio workstations. These devices are invaluable to music producers and come in a variety of forms, such as MIDI keyboards, MIDI drums, Launchpads, et cetera. They are usually composed of an array of buttons and potentiometers that are used to send standard MIDI signals to a computer or a synthesizer. The MIDI signal is then mapped to various sounds or sound effects.
In this project, we will be building a touchless MIDI device that can be operated by hovering a hand over a sensor area. This is useful for musicians (especially those doing live performances) who wish to have MIDI controls but are already preoccupied with another instrument.
How Does It Work?
In a previous article, we built a metal detector using a Colpitts oscillator circuit. Unlike a traditional BFO (beat frequency oscillator) metal detector, where a secondary fixed-frequency coil is used to shift the frequency of the primary detector coil into the audible range, our metal detector used an Arduino to digitally process the signal of the primary detector coil, and we thus eliminated the need for a secondary coil.
We will be using this same metal detection mechanism with a few additions to the previous Arduino program to create the touchless MIDI device.
The detector coil will be used as the sensor (discretely tucked into the sound hole of the guitar), and a mitten lined with tin foil induces oscillation frequency changes as it moves closer to or farther from the detector. The oscillation frequency is measured by the Arduino (which is housed in the control unit, which in turn is attached to the back of the guitar) and translated into a MIDI CC (control change) signal that is transmitted out the MIDI port. A 3-button panel is also included to switch between three MIDI controller numbers that can be mapped to different effects.
We will require the following components:
- Arduino Nano (or any equivalent ATmega328p-based Arduino)
- 5-pin MIDI port
- Resistors: 39kΩ, 2.2kΩ, 10kΩ, 470Ω, 220Ω
- Ceramic capacitors: 10nF (quantity 3), 0.1µF (quantity 3)
- BC338 NPN transistor
- Tactile buttons (quantity 3)
- Enameled copper wire (25 AWG, approximately 60 feet long)
The device consists of a detector coil (which senses the proximity of the glove), a 3-button panel (to choose one of three effects), and the main unit containing the circuitry.
To create a spool for the detector coil, cut off and tape together the lips of two plastic cups (you want something with a diameter of 3 inches). Next, wrap the enameled copper wire tightly around the spool approximately 70 times.
For the button panel, you can use materials salvaged from a busted (or otherwise expendable) calculator. Solder three tactile buttons onto a perfboard and make an outer housing. One terminal of each button goes to its own digital pin on the Arduino, and the other pin goes to ground (see schematic below).
Finally, the main unit houses the Arduino Nano, the Colpitts oscillator circuit, the MIDI port, and the ports for the detector coil and button panel. Attach the main unit to the back of the guitar (I used Velcro).
The Colpitts oscillator is the same circuit that we used in the metal detector project. We have an Arduino for signal processing and a MIDI port for sending out the sound-effect data.
MIDI 1.0 specification messages are transmitted with the hardware serial pin (TX) of the Arduino, using the standard baud rate for MIDI communication, 31250bps.
Every MIDI message starts with a status byte (4 bits to specify a MIDI command, followed by 4 bits to select the MIDI channel). When the frequency of oscillation in the detector coil changes, we will issue a “control change” command, 1011 (binary), using the first channel, 0000.
The control change command is followed by 2 bytes: the controller number (0-119) and the controller value (0-127). The controller number we issue will depend on which of the three effects is currently selected (via the button panel), and the controller value will depend on the proximity of the tin foil to the detector coil (0 when the foil is undetectable, and gradually increasing to 127 as it approaches the coil).
For example, with the second effect selected and having the tin foil hovering slightly above the coil, an appropriate MIDI transmission might look like this (in binary): 1011 0000 00010001 01011010. The byte 00010001 corresponds to decimal 17, which is the controller number for “general purpose slider 2” in the MIDI specifications, and the byte 01011010 corresponds to decimal 90, which specifies that the controller is at its 71% position (90/127 ≈ 71%).
Full source code for this project can be found here:
The setup function remains largely unchanged from the metal detector code. The additional "Serial.begin(MIDI_SERIAL_RATE)" sets the hardware serial baud rate to the MIDI standard rate of 31250bps.
The interrupt function measures the time delta between interrupts (which occur after every 2000 Colpitts-oscillator cycles). The change made in this function compared to the original metal detector code is the additional capability to keep a running total of time delta values. Since the Arduino's micros() function has a resolution of 4 microseconds on a 16 MHz board (8 microseconds on 8MHz variants), the time deltas will snap to intervals of 4 microseconds. This limited resolution in measuring the deltas leads to undesirable fluctuations that can be smoothed out by using a running total.
The loop function starts by checking the states of the effect buttons. If any one of the buttons is pressed, the selected controller number is changed accordingly. The controller values for the other controller numbers are then reset to 0.
Next, a difference between the longest interrupt time delta running total (the reference point, i.e., when no metal is present to alter the frequency) and the interrupt time delta running total (of the last 4 samples) is taken to determine the proximity of the tin foil to the detector coil. Dividing this value by 10 normalizes it to a range closer to 0 to 127. It is then clamped to a maximum of 127.
int sumDifference = (longestDeltaSum - rollingDeltaSum) / 10;
Lastly, a helper function, midiControlChange(), is called to build the 3-byte MIDI message (as described above in the “MIDI Messages” section) and then transmit it via hardware serial.
Having a touchless MIDI controller is a practical way to add MIDI support to a musical performance without having to switch between an instrument and a traditional MIDI controller.
The small form factor of the detector coil makes it ideal for being embedded into an existing instrument, without the need for intrusive modifications to the instrument. Post-processing effects can be easily mapped to virtually any parameter in a modern digital audio workstation, adding another dimension to what the instrument itself can achieve.