Click to MIDI/Click to Tap - Multiformat Tempo Box

by -RML- in Circuits > Electronics

20 Views, 0 Favorites, 0 Comments

Click to MIDI/Click to Tap - Multiformat Tempo Box

IMG_20260505_190415616_HDR.jpg

This is a converter box capable of transforming an audio pulse such as a click track, a metronome or analog sync to MIDI clock and Tap Tempo signals. I've made it to clock guitar pedals and outboard effects from a click track signal.

Supplies

Active Components

  1. 1x Arduino Nano
  2. 1x LM393 Operational Comparator
  3. 2x PC817 Optocouplers
  4. 1x Green 4mm LED

Passive Components

  1. 1x 100nF capacitor
  2. 1x 10kΩ 1/4W Resistor
  3. 1x 1MΩ 1/4W Resistor
  4. 2x 200Ω 1/4W Resistor
  5. 3x 220Ω 1/4W Resistor
  6. 1x 100kΩ Linear Potentiometer

Connectors & Various

  1. 3x TRS 6,3mm Jack
  2. 1x DIN5 MIDI Jack
  3. 1x 5,5mm DC Jack
  4. Stripboard or Veroboard
  5. 2,54mm pitch sockets for Arduino and the ICs
  6. Box

Concept

Immagine.png

The idea for this box was born at my job as a sound engineer, one of the bands that i work with regularly use click tracks to play, the track gets played from a laptop onstage and gets sent to my desk where it can be routed to their IEM (In-Ear Monitors).

The band (https://www.instagram.com/flowersindarkofficial/ - go check them out, they're amazing!) often features opera-like vocals that sounds awesome when drowned in reverb and delay, this is easily done with the help of any digital mixing console (or even some analog ones) nowadays, but having the delay constantly on sync requires setting it for every song at least, this usually is done via a "tap tempo" button, where the engineer can tap along with the song for a couple beats, the device will recognise the tempo and set it to the delay.

But sometimes songs features tempo changes (or sometimes a lot of tempo changes) so I found hard to always reach out to the tap to re-align the delay and ending up missing the correct moment for a delay swell or something else.

So, why do it when you can automate it?

Having a click track is the main prerequisite for the whole setup to work, the core concept could probably work with a regular instrument like a Hi-Hat or Kick Drum but their signal will need to be processed to avoid double background noise from microphones and have a sharp transient attack to make the detector circuit work, and this without even considering the musical nuances of multiple hits, flams and other finesses of the instrument.

Another idea that i had was to have a Linear TimeCode (LTC) track sent alongside the Click in another channel, this is usually done to having light shows or video cue played in sync with the track. LTC naturally embed a digital tempo signal inside a standard audio signal to simplify transportation around the stage; this would have totally avoided the analog circuitry (and the error chances intrinsically introduced by it) but it would have limited the ease of use, implying the need to add something to the band's backing tracks rig (not at all easy, especially in the short time of a soundcheck) so I resorted to the click track.

A click track is an audio cue featuring a metronome or similar sound to help musician keeping track of the tempo along the song (and also keeping them in sync with any backing tracks). Coming from a laptop or similar device the click track is immune to ambient noise from microphones onstage, the sounds used are almost always sharp and clear, having a great dynamic range helps with the detection by any kind of circuit.

Signal Analysis and Circuit Design

393datasheet.png
osc traces.png

I wanted the system to have an adjustable threshold, to be able to filter out any unwanted background signal or noise, and said threshold to be easily adjustable by a potentiometer. This called for a analysis between the input signal and the threshold to be carried out, initially i thought this could be done totally by software inside the Arduino, feeding the audio straight into an analog input pin.

But i the first trial that i made I quickly discovered that the amplitude of the audio Line Level signal would peak at roughly 1,7Vpp, although this can be clearly detected by arduino, it would give us a scarce resolution, being arduino ADC referenced at +5V.

So I've designed a simple external comparator using a LM393 chip and referencing the datasheet's application circuit.

After some trial and error I've managed to sketch out the final schematic, slightly different than the datasheet's one.

The threshold is set by the potentiometer directly connected to the inverting pin of the comparator.

The Audio signal is feed through a decoupling capacitor and referenced to ground via a 100kΩ resistor before arriving at the non-inverting pin of the comparator.

The output is the pulled-up to +5V via a 10kΩ resistor and then connected to the A0 pin on Arduino.

This gives us a clear +5V on the output whenever the signal goes over the threshold, some hysteresis is even present thanks to the 1MΩ resistor between output and the non-inverting input, as seen in the oscilloscope picture (Green trace is audio signal, blue trace is comparator output).

Of course we have multiple bumps due to the waveform nature of audio, I've experimented by low-pass filtering incoming audio with a simple RC to clear the waveform but the resulting output was much lower so I decided to avoid it and to integrate a way for arduino to only acquire the first pulse of a series.

Final Schematic and Addons

Click-To-MIDI.jpg

During the prototyping phase I've added a LED to help me figure out when the signal was getting received by arduino, I've decided to keep it as a visual marker, triggered every quarter note.

This made me realize that the same output could be used to trigger a tap tempo footswitch on a pedal or similar unit (Like this one). Tap tempo footswitches are usually simple momentary, normally open switches that are tapped by a musician along the song to give the correct tempo to the delay. My first idea was to use some 5V relay that i had around to emulate it but they would've been working almost constantly and that could lead them to premature failure, so i resorted to two optocouplers, when arduino outputs go high they short and emulate a "tap".

MIDI Output was simply done by two resistors conforming to MIDI Association specification

Downloads

MIDI Implementation

A quick look at the MIDI specification states that MIDI uses a bunch of different messages to include transport (play/pause/stop) and other features in the same category of messages, although implementing a start/stop message at the beginning and some time after the pulse end could be helpful i finally decided against it to avoid complication.

MIDI Timing Clock is composed by a "Timing Clock" messages, often identified as "System Realtime", that needs to be sent 24 times for each quarter note (24 Pulses Per Quarter Note or 24PPQN), this means that once calculated the time between two pulses we need to divide this time into 24 parts and send 24 messages at regular intervals.

During testing I've programmed a Click Track with multiple tempo changes and noticed that on sharp rises in tempo the MIDI clock temporarily jumped to half the target tempo before stabilizing to the correct tempo. This was caused by the tempo change occurrign before a sequence of 24 messages ended.

To fix this I've added a rescheduling function that reschedule the interval between messages even between quarter notes. This results in the current tempo moving towards the target tempo in a couple beats instead of jumping randomly before stabilization.


Here is a short GIF showing MIDI-OX Beat Clock detecting tempo from Click track played by Ableton Live with Tempo automations

Software

I've started drafting the software using the MIDI library but since I only need to transmit a single byte I've just resorted to a standard serial communication.


// -RML- Click to MIDI/Click to Tap

const int PULSE_PIN = A0; // Input pulse pin
const int LED_PIN = 3; // LED pin
const int TAP_PIN1 = 5; // Tap1 pin
const int TAP_PIN2 = 7; // Tap2 pin
const byte MIDI_CLOCK = 0xF8; // MIDI Timing Clock

// Timing variables
unsigned long lastPulseTime = 0;
unsigned long nextMIDIClockTime = 0;
unsigned long currentInterval = 20833; // Current interval in microseconds

// State machine
bool sendingClocks = false;
int clocksSent = 0;
int totalClocksInSequence = 24; // Will be reduced if rescheduled

// Pulse detection
bool lastPulseState = LOW;
bool firstPulse = true;

void setup()
{
pinMode(PULSE_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
pinMode(TAP_PIN1, OUTPUT);
pinMode(TAP_PIN2, OUTPUT);

digitalWrite(LED_PIN, LOW);

Serial.begin(31250); // MIDI baud rate
lastPulseTime = micros();
}

void loop()
{
checkForPulse();
sendMIDIClockIfDue();
}

void checkForPulse()
{
bool currentPulse = (analogRead(PULSE_PIN) > 512) ? HIGH : LOW;
unsigned long currentTime = micros();

// Rising edge = new beat detected
if (currentPulse == HIGH && lastPulseState == LOW)
{

// LED: Blink to show beat
digitalWrite(LED_PIN, HIGH);
digitalWrite(TAP_PIN1, HIGH);
digitalWrite(TAP_PIN2, HIGH);
delay(20); // Delay timed perfected for tap tempo efficency
digitalWrite(LED_PIN, LOW);
digitalWrite(TAP_PIN1, LOW);
digitalWrite(TAP_PIN2, LOW);

if (firstPulse)
{
lastPulseTime = currentTime;
firstPulse = false;
return;
}

// Calculate new period
unsigned long newPeriod = currentTime - lastPulseTime;
unsigned long newInterval = newPeriod / 24; // 24 PPQ
lastPulseTime = currentTime;

// INSTANT TEMPO CHANGE: Reschedule remaining clocks
if (sendingClocks)
{
// We're in the middle of a sequence - reschedule remaining clocks
int clocksRemaining = 24 - clocksSent;

// Reduce total so we don't send too many
totalClocksInSequence = clocksSent + min(clocksRemaining, 24);

// Update interval for remaining clocks
currentInterval = newInterval;

// Continue from now with new spacing
nextMIDIClockTime = currentTime;

}
else
{
// Normal case: start new sequence
sendingClocks = true;
clocksSent = 0;
totalClocksInSequence = 24;
currentInterval = newInterval;
nextMIDIClockTime = currentTime;
}
}

lastPulseState = currentPulse;
}

void sendMIDIClockIfDue()
{
if (!sendingClocks) return;

unsigned long now = micros();

if (now >= nextMIDIClockTime)
{
Serial.write(MIDI_CLOCK);
clocksSent++;

// Stop when we've sent our allocated number
if (clocksSent >= totalClocksInSequence)
{
sendingClocks = false;
return;
}

// Schedule next clock with current interval
nextMIDIClockTime += currentInterval;
}
}

// This code has been composed with the help of a LLM/AI system

Downloads

Hardware and Box

IMG_20260505_190415616_HDR.jpg
IMG_20260505_190121701_HDR.jpg
IMG_20260505_190140920_HDR.jpg
IMG_20260505_190154607_HDR.jpg
photo_2026-05-06_19-07-01.jpg

Sadly I don't have photos of the building process.

Both the comparator circuit and the optocouplers are soldered on a piece of stripboard, arduino is mounted on it with some 2,54mm sockets.

I've not yet provided the box with a USB-C hole to easily reprogram arduino since i don't have the correct equipment for rectangular hole drilling :D

Labels were printed on my Niimbot B18 Label printer.

Power to the system is provided by a 5V wall adapter that i already had but a 7805 regulator or better PSU can be added easily.

Final Consideration

This is a project born out of the sheer need for a pretty custom way to do a thing. There are probably 1000 better and more efficent ways to do it but I wanted to build it with technologies known to me.

At the same time this could be probably be automated by a software script in thousands of different ways (Max MSP, PureData, Chataigne just to name a few) but I'm a fan of custom hardware solutions, I'd rather carry 10 machines or small boxes that serve a single purpose each than trust a laptop with all of those tasks at the same time.

The bottom line is that I needed a small box to carry with me and to throw behind the mixing desk as a set-and-forget way to quickly get tempo to my effects

Some ideas that i had during development:

  1. This is not restricted to click tracks, it can work with other kind of signals, analog sync, eurorack trig and probably even with some heavily processed hi-hat or kick signal
  2. At the same time this can be used in Modular Synthesizers (Eurorack is 5v compliant) to convert triggers to MIDI or something similar
  3. A Tap Tempo button can be added to manually tap tempo to multiple destinations
  4. MIDI In can be easily added to receive external sync to produce "Tap Tempo" for pedals
  5. Multiple time signatures can be implemented on the "Tap Tempo" outputs
  6. Using a more powerful arduino and a OLED or LCD display audio can be directly processed into Arduino itself

Stuff I missed:

  1. Arduino Nano has an internal comparator that can be used instead of the external LM393
  2. Using an Audio Shield or external amplifier the comparator can be totally avoided and the whole process can be moved into Arduino itself


Acknowledgments and further readings:

I've gathered inspiration from multiple sources scattered all across the internet and probably forgot most of them but here are some of the most significative:

  1. The work by rydan on GitHub on a very similar project
  2. Although I ended up not using it, I've gathered inspiration from this Library on GitHub by dxinteractive