Welcome to Pete Brown's 10rem.net

First time here? If you are a developer or are interested in Microsoft tools and technology, please consider subscribing to the latest posts.

You may also be interested in my blog archives, the articles section, or some of my lab projects such as the C64 emulator written in Silverlight.

(hide this)

A MIDI clock pulse to analog sync voltage converter

Pete Brown - 31 December 2012

I have a few pieces of analog gear which either don't support MIDI, or simply work better with voltage control. This makes including them in a sequence difficult as timing of arpeggios or sequences will drift away from the rest of the performance. Not to mention that synchronizing them by ear is not a simple task in any case, and impossible to do in real-time if you want to adjust the tempo during the performance.

One such piece is my little Korg Monotribe. This is a combination drum machine and step sequencer built into a very inexpensive package.

The Monotribe doesn't have MIDI support (although you can build a conversion for MIDI), but it does accept a sync pulse. The Aturia Minibrute doesn't send an analog clock pulse, so there was no way to synchronize the two. However, the Minibrute *does* accept MIDI clock pulses from an external source, so I knew I could build on that.

Hybrid Analog/Digital sequencers like the Doepfer Dark Time will handle this synchronization for you, but for a price. I already have one analog sequencer on order, one small one mostly built, and another ready to be built, so I didn't want a third one right now.

The Goal

So the goal is to drive both analog gear as well as more modern MIDI gear from an external MIDI clock. In my case, I decided to use Cubase 7 on my PC as the clock source. The completed setup looks like this:

image

All the straight MIDI communication just works. The rest of this post will focus on the development of the MIDI to analog sync signal part. First, however, a little background on synchronization.

MIDI sync

MIDI master clocks send out 8 bit synchronization messages at the rate of 24 for every quarter note. At a typical BPM of 120, that means that there are 24 * 120 = 2880 clock messages per minute, or 48 clock messages per second.

The standard MIDI protocol itself is a 5v serial protocol running at 31,250 bits per second with 8 data bits, no parity bits, and 1 stop bit. Most messages are two or three bytes in length, but a number of important messages, such as the real-time messages, are only one byte in length. Also note that messages can be interrupted by real-time messages. So, you could get the "note on" message, and then the clock byte, and then the note on message's data. Any code which parses these messages must handle this gracefully.

Analog Sync

Analog sync pre-dates MIDI clock signals, so there are a number of standards. Roland used a DIN sync for drum machines, TB-303, and others. This is a 5 pin cable which looks like MIDI, but is actually carrying completely different analog signals.

Even older than that is the modular approach of clock pulses. This is typically a 5v square pulse which is used to move a sequencer to the next step. This is the way most analog sequencers synchronize with each other, all sharing a common clock/sync source.

The Korg monotribe is a new design, but follows older analog principles. In this case, the sync signal doesn't need to be 5v. In fact, there are phone apps which use audio level signals from the headphone jack to generate sync pulses for the monotribe. Much like the classic analog approach, the monotribe sync approach is used to move the sequencer from one step to the next.

There are many other devices which can synchronize with signals like this. For example, the Nova Drone drone synth includes LFO sync which should work with this type of signal. (I haven't tried it yet, though).

image

(Yes, that's a Cthulhu mug. I know I just floored you with the awesomeness of this photo)

Implementation

I've done a fair bit with MIDI hardware, so I knew generally how to parse messages and otherwise deal with the data. I also have a MIDI module which, although designed for .NET Gadgeteer, includes pins so I can use it with any microcontroller. Real-time processing of MIDI messages like this has proven to be too intense for interpreted code like NETMF, so I turned to my ARM development board. Sure, this is something which could have been easily accomplished on Arduino, but I've been getting into ARM lately, and have had larger plans for the processor.

The development board I used is my Mikroelektronika EasyMX Pro v7 for STM32. the C IDE is a mess compared to Visual Studio, but I can't praise this board enough. It's super easy to develop and debug on it, all over USB.

Because the monotribe runs perfectly fine on low amplitude pulses, the 3.3v signal level from the ARM processor works fine. If you use this approach with other analog gear, you'll likely need to scale the output up to 5v (again, not an issue if you use classic Arduino or AVR which both natively support 5v signals).

Initially, I based the pulses on 64 for some reason. I originally thought MIDI used 64 pulses and not 24. Because of this, the code below is not quite correct (it works, but doesn't correspond to actual beats, so the divisions aren't as useful as they should be).

#define MIDI_TIMING_CLOCK 0xF8
#define ANALOG_CLOCK_PULSE_DURATION_MS 1
#define MAX_TICKS 64;

// USART2 TX is PA2
// USART2 RX is PA3

#define GPIO_BASE GPIOD_BASE
#define ODR GPIOD_ODR

#define SetAllPinsLow() ODR = 0;
#define SetPins(pinMask) ODR = pinMask

char _uartReadByte;

void main() {
unsigned short currentTick = 0;
unsigned short pinsHigh = 0;

GPIO_Digital_Output(&GPIO_BASE, _GPIO_PINMASK_LOW); // Set pins as digital output

UART2_Init_Advanced(31250, _UART_8_BIT_DATA, _UART_NOPARITY, _UART_ONE_STOPBIT, &_GPIO_MODULE_USART2_PA23);

Delay_ms(100); // Wait for UART module to stabilize

while (1) {
if (UART2_Data_Ready()) {
_uartReadByte = UART2_Read(); // read the received byte

if (_uartReadByte == MIDI_TIMING_CLOCK) { // if MIDI clock message

pinsHigh=1; // always output full clock on first pin

if (currentTick % 2 == 0) {
pinsHigh |= (1 << 1);

if (currentTick % 4 == 0) {
pinsHigh |= (1 << 2);

if (currentTick % 8 == 0) {
pinsHigh |= (1 << 3);

if (currentTick % 16 == 0) {
pinsHigh |= (1 << 4);

if (currentTick % 32 == 0) {
pinsHigh |= (1 << 5);

if (currentTick % 64 == 0) {
pinsHigh |= (1 << 6);
}
}
}
}
}
}

if (pinsHigh) {
SetPins(pinsHigh);

Delay_ms(ANALOG_CLOCK_PULSE_DURATION_MS);

SetAllPinsLow();

pinsHigh = 0;
}

currentTick = (currentTick + 1) % MAX_TICKS;
}

}
}
}

I hate that K&R style of brace indentation, but like I said, the IDE is a mess. If you deviate from that style of indentation, the tabs and whatnot get really screwed up. In fact, they get a little screwed up anyway. IDEs in the microcontroller world are a long way from what we're used to for more mainstream development.

image

Essentially, the code gets each incoming byte and checks to see if it is a clock message. If so, it checks the current tick to see where we are in the timing and then sets a bitmask to set the pins on a port to high based on that step. It then sets the pins high, sleeps for 1ms, then sets them low again.

When I ran the code, I looked at the pulses using my Saleae Logic 8 channel USB logic analyzer (something which is absolutely indispensible for work like this) and, after some debugging, got the right results:

image

When you code this low to the metal, timing can be really spot on. I love that!

Here's the full device setup on my mess of a desk:

image

And here's a full set of timing pulses, without the MIDI clock signal visible:

image

You can see that each row has a period twice that of the row above it. By connecting to different signal divisions, you can speed up or slow down the slave sequencer, but still keep it in time with the rest of the performance. (Remember, I need to change it to be based on 24, not 64 clocks per quarter note)

What's Next?

I'm going to correct the timing and then develop an inexpensive board around this, possibly including support for TB-303/x0xb0x style DIN sync (including stop/start) in addition to the analog sync. I'll keep a couple around for my studio, but have others for sale. If you're interested, drop me a line via the contact link here and let me know.

I'll also post a recording of the sync working on my Soundcloud page.

Update: Recording is here: https://soundcloud.com/psychlist1972/monotribe-and-modular-sync-test

     
posted by Pete Brown on Monday, December 31, 2012
filed under:      

Comment on this Post

Remember me