MIDI Interface & Sequencer

A device to play and sequence a simple analogue synthesizer (fairly retro!) from a MIDI keyboard

Overview

In this project, I created a MIDI interface for a simple hand-held analogue synthesizer (a Gakken SX-150 Mark II), so that it can be played from a keyboard (a Yamaha digital piano). The interface and sequencer plays just one note at a time as the synth is monophonic. The project could be easily adapted for another keyboard or for another synthesizer lacking a MIDI interface, so long as it has an accessible VCO input - a Korg Monotron perhaps, or maybe a home-made synthesizer. Be careful to ensure that the voltage generated is compatible with the synth you use! (In my case, the synth runs at 6v, while the signal it receives is a maximum of 5v).

The project dates from 2016/2017. I worked on it quite intensively for many months, then put it to one side, while it was still a work in progress and gradually forgot about it as other things took up my time! Now some years later, I've decided to review, update and document it here.

It started out as a means of playing a DIY 'synth'  (actually an Atari Punk Console) from a company called TWSU (Technology Will Save Us), now sadly gone, in spite of its name. MIDI notes were generated by playing a virtual keyboard on a computer connected to an Arduino, which used Pulse-Width Modulation (PWM) to generate a Control Voltage (CV) to the 'synth' to which it was connected in turn. Instructions and code were provided online, as a free extension to the kit. Unfortunately, it never really worked, the 'synth' not being playable in any meaningful sense, but it got me thinking and I adapted the code with success to play my Gakken instead.

A little later, I came across a project on the Mr. Book website (now also sadly gone, was http://mrbook.org/) to play notes from a MIDI keyboard, again on a Gakken synth. This project also used an Arduino, but this time with a Digital to Analogue Converter (DAC), an MCP4921, to generate CV. I tried that method and it worked fine and having already made a Baby-8 sequencer for use with the Gakken synth, I realized it was would be relatively simple matter to adapt the code to (temporarily) store sequences of notes as well, so added that capability. 

After much experimentation, I went back to using PWM, as it sounded quite acceptable to my ear. As I added increased ability to manipulate sequences interactively (in which I may have been been influenced by the sequencer project described here), I decided to use two Arduinos connected by a serial link, as shown below.

Most recently, I have allowed recorded sequences to be stored permanently in the on-board EEPROM, which I hadn't known about earlier.

Main breadboard with two Arduinos Nano clones: the one at left is the pre-processor, the one at right is responsible for tuning, sequencing and playing notes. Controls for the second Arduino are on the breadboad below. MIDI in is through the socket at left, CV out is through the socket top right. A 9v power supply (not shown) needs to be connected to the top power rails, while the bottom rails are used for 5v generated by one of the Arduinos.

The first Arduino receives MIDI input via a 4N28 optocoupler (to electrically isolate the keyboard from the interface) and runs a program (midi_seq_pre.ino) that acts as a filter for my Yamaha piano's quirks (such as ignoring the 252 & 254 messages it sends continuously!). The wiring used to connect the 4N28 is straight from Mr. Book.  (It's very close to the circuit shown here, which uses a much larger resistor on pin 5. The latter circuit also takes the output, incorrectly I think, from after the resistor, at the 5V supply).

Components used with 4N28

Wiring the 4N28

The first Arduino filters MIDI notes received by the optocoupler at the left. 

MIDI socket back. Pins at top, l-r:  3, 5, 2, 4, 1. Grey lead - pin 5, white - pin 4.

The second Arduino runs another program (midi_seq_gakken.ino), which receives this filtered output and, as appropriate, generates a square waveform signal using PWM. It also plays pre-defined sequences that are stored as MIDI notes.

The signal is output through pin D9, which is connected to ground via a 10k ohm resistor and a 100k pF capacitor, forming a low pass filter (presumably) to transform the square wave to usable CV, which is taken from between the resistor and capacitor. As far as I can tell, this is as per the instructions from TWSU.

In an attempt to simplify matters, the first Arduino adds 100 to the MIDI note number for 'note off' messages and the second takes it off again if the MIDI note number exceeds a certain limit. In practice, this means that MIDI notes are restricted to between 21 (the lowest on my Yamaha piano) and 120, a span over 8 octaves, which is way more than are needed, the keyboard spanning just over 7 octaves and the Gakken synth just over 3 here.

The second Arduino is  responsible for the CV out to the synth

Converting MIDI to PWM

The TimerOne library used provides PWM duty from 0 to 1023, corresponding to duty cycles of 0% and 100% respectively. (Do these correspond to 0 Volts and 5 Volts respectively?). The timer's period is set to 32 microseconds, i.e. ~ 30 kHz, which I copied from the original sketch from TWSU for use with their diy 'synth'. It would be interesting to experiment with this setting.

Keyboard note C3 note MIDI 48 is the reference point for tuning and generating CVs for notes. (Not sure why I didn't use middle C or C4, MIDI 60). 

There is a linear relationship, derived empirically, between MIDI note and PMW duty setting. The following variables are used here:

The PWM duty for the note to be played (from the MIDI input note, note_in) is, therefore:

C3_value-((48-note_in)*note_mult)/note_mult_factor

Using the default values, this is:

475-(48-note_in)*950/100

So, for MIDI 36, C2, the PWM duty is:

 475-(12*9.5)=361

Converting PWM to CV

To convert PWM duty to the PWM voltage output at pin D9, we need to multiply by 5 (volts) and divide by 1023. With a difference of 114 PMW duty per octave (see above), this means about 0.56 volts per octave.

I'd have thought that this signal would need to be smoothed out to (ideally) a constant voltage for the synth. There's a lot of information here, but it seems that the low pass filter referred to earlier transforms the square wave to a saw wave (at best?). I need to do some more research to understand this better.

What if the synth were to run at less than 5v? The maximum PWM duty setting could be limited accordingly, e.g. if rated at 3v, limit the setting to 3/5 of 1023, i.e. 613.

Note lengths and intervals during playback of sequences

The length of a single note is determined by means of an adjustable voltage, varying from 0 to 5v, read by Arduino 2 and converted to a value between 0 and 1023 (ms). Notes in sequences can be set to this value, or twice as long or four times as long, to effectively give crotchets, quavers and minims.

The interval between notes has been fixed, arbitrarily, to one fifth of this value but is easily changed via the variable note_int_ratio, currently set to 5.

As a  consequence, the duration of a double note say plus interval would be less than that of two single notes and intervals. It didn't seem to be a problem during playback, but even so, I extended the duration of a double note by an interval and that of a quad note by 3 intervals. 

If you want a pause with no note played, one of the lower MIDI notes will work so long as it has not been designated for special use (see Keyboard controls below).

Tuning

Control panel

Control Panel. Top, l-r: Record, Playback, + Major 4th, + Major 5th, experimentation; Bottom, l-r: Fine Tune C3_value, + Tuning, - Tuning, Fine Tune note_mult. Middle, right: Playback Speed Control

Keyboard controls

These use 'special' MIDI keys rather than dedicated buttons:

(Note: the lowest playable note on the Gakken is ~ MIDI 43).

EEPROM

As with arrays, the first location in EEPROM is number 0. 

The amount of EEPROM depends on the Arduino. I understand my model of Arduino Nano has 1024 bytes, but I've not used anything like this amount, so cannot confirm.

In the code for Arduino 2, the value of the next free storage location (eeprom_next_free) is stored in location 0 of EEPROM. It is initialized to '1' and is updated automatically as sequences are added.

Each stored sequence consists of:  the number of notes in the sequence, followed by, note and note length pairs. An 8-step sequence will therefore need to use 17 locations in storage.

Note: an artificial limit has been placed to allow up to 9 8-step sequences to be stored in EEPROM.  This is achieved with variable eeprom_lim, currently set to 153. For each additional 8-step sequence to be stored, this number will need to be increased by 17. It should be possible to store up to 60 8-bit sequences on my Arduino Nano, but it would be arduous to have to step through so many.

In use

Possible enhancements

Downloads

Arduino 1: midi_seq_pre.ino

Arduino 2: midi_seq_gakken.ino