Yet another MIDI-to-Gakken interface!

Gakken SX-150 schematics

A couple of months ago, during Homework Festival I met a guy from Sofia who had a strange machine in his setup... he told me how cheap and funny it was, so I decided to order one on ebay. Last week I received my Gakken SX-150 and started searching around the net for hacks and mods, and I found several projects and articles describing possible ways of interfacing it with MIDI and various external sensors, but, since I was already doing some experiments with a DAC board, I decided to try it with my freshly received Gakken.

I'm using a 16bit serial DAC from Analog Devices, the AD420 (you'll find the board details in my previous article), and, as you can see from the schematics below, the connections are really simple: you just need to solder four wires on the Gakken board, two for the audio output and two for the DAC input. I've also used the MIDI I/O board described in one of my previous articles, and the code below enables Arduino to receive note on/off events and forward them to the Gakken.
You can try some tuning by tweaking "GAKKEN_OFFSET" and "GAKKEN_NOTE_STEP"... enjoy :)

/*---------------------------------------------------------*/
/*   MIDI-to-Gakken Interface                              */
/*   Vincenzo Pacella - www.shaduzlabs.com                 */
/*---------------------------------------------------------*/

//arduino output pins
#define LATCH 7
#define CLOCK 8
#define DATA  9
#define OPTOCOUPLER_ENABLE 10 //to MIDI I/O Board Vcc

//2 uS of clock period (sample rate = 30.3 KHz)
#define HALF_CLOCK_PERIOD 1 //uS

//MIDI Input state machine definitions
#define STATUS_IDLE 0
#define STATUS_MIDI_NOTE_ON 1
#define STATUS_MIDI_NOTE_OFF 2
#define STATUS_MIDI_NOTE_VELOCITY 3
int status = STATUS_IDLE;

//MIDI Input buffer
byte midiByte;

//MIDI Channel (1-16)
#define MIDI_CHANNEL 1

//MIDI Events
#define NOTE_ON (0x90|(MIDI_CHANNEL-1))
#define NOTE_OFF (0x80|(MIDI_CHANNEL-1))

//Tuning 8)
#define GAKKEN_OFFSET 12000
#define GAKKEN_NOTE_STEP 374

void setup()
{
pinMode(DATA, OUTPUT);
pinMode(CLOCK,OUTPUT);
pinMode(LATCH,OUTPUT);
pinMode(OPTOCOUPLER_ENABLE,OUTPUT);

digitalWrite(DATA,LOW);
digitalWrite(CLOCK,LOW);
digitalWrite(LATCH,LOW);
digitalWrite(OPTOCOUPLER_ENABLE,HIGH);
Serial.begin(31250);
}

void writeValue(uint16_t value){

//start of sequence
digitalWrite(LATCH,LOW);
digitalWrite(CLOCK,LOW);

//send the 16 bit sample data
for(int i=15;i>=0;i--){
digitalWrite(DATA,((value&(1<<i)))>>i);
delayMicroseconds(HALF_CLOCK_PERIOD);
digitalWrite(CLOCK,HIGH);
delayMicroseconds(HALF_CLOCK_PERIOD);
digitalWrite(CLOCK,LOW);
}

//latch enable, DAC output is set
digitalWrite(DATA,LOW);
digitalWrite(CLOCK,LOW);
digitalWrite(LATCH,HIGH);
delayMicroseconds(HALF_CLOCK_PERIOD);
digitalWrite(LATCH,LOW);

}

void loop()
{
if (Serial.available() > 0) {
midiByte = Serial.read(); 
switch(status){
case STATUS_IDLE:
if (midiByte== NOTE_ON){
status=STATUS_MIDI_NOTE_ON;
}
else if (midiByte== NOTE_OFF){
status=STATUS_MIDI_NOTE_OFF;
}
break; 

case STATUS_MIDI_NOTE_ON:
writeValue(GAKKEN_OFFSET+(midiByte*GAKKEN_NOTE_STEP));
status=STATUS_MIDI_NOTE_VELOCITY;
break;

case STATUS_MIDI_NOTE_OFF:
writeValue(0);
status=STATUS_MIDI_NOTE_VELOCITY;
break;

case STATUS_MIDI_NOTE_VELOCITY:
//velocity data is not used!
status=STATUS_IDLE;
break;

default:
break; 

}
}

comments powered by Disqus