// Sketch written by Jeroen Janmaat
// This version 2013/06/01
// For 1 MHz clock
#define myOutputPin 9
// For switches
int dataWidth = 8;
//int dataSwitches[8] = {2,3,4,5,6,7,8,10};
int dataSwitches[8] = {10,8,7,6,5,4,3,2};
int data[8] = {0,0,0,0,0,0,0,0};
int addressWidth = 5;
int addressSwitches[5] = {A0,A1,A2,A3,A4};
int address[5] = {0,0,0,0,0};
int ii = 0; // just a counter
// For serial comms
char inByte = 0; // incoming serial byte
int addressAvailable = 0;
int dataAvailable = 0;
// Interpretation of midi
double f[96];
int data_Fhi[8] = {0,0,0,0,0,0,0,0};
int data_Flo[8] = {0,0,0,0,0,0,0,0};
byte Byte1 = 0;
byte Byte2 = 0;
byte Byte3 = 0;
byte voice1on = 0;
byte voice1last = 0;
void setup ()
{
pinMode (myOutputPin, OUTPUT);
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 7; // toggle after counting to 8
TCCR1A |= (1 << COM1A0); // Toggle OC1A on Compare Match.
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= (1 << CS10); // clock on, no pre-scaler
// Check for MIDI or USB comms
/* pinMode(A4, INPUT);
if(digitalRead(A4))
Serial.begin(31250);
else
Serial.begin(38400);
*/
// configure I/O to write address and write data
for(ii=0; ii<addressWidth; ii++) {
pinMode(addressSwitches[ii], OUTPUT);
digitalWrite(addressSwitches[ii], address[ii]);
}
for(ii=0; ii<dataWidth; ii++) {
pinMode(dataSwitches[ii], OUTPUT);
digitalWrite(dataSwitches[ii], data[ii]);
}
pinMode(12, OUTPUT); // execute on SID
digitalWrite(12, HIGH); // and set to high
pinMode(A5, INPUT_PULLUP); // read 'enter' here
pinMode(13, OUTPUT); // enable/disable switches
digitalWrite(13, HIGH); // deactivate switches
pinMode(11, OUTPUT); // R/W select line
digitalWrite(11, LOW); // Set R/W select to 0 for Write mode
// Calculate frequencies
for (ii=0; ii<=95; ii++)
f[ii] = 440.0*pow(2.0,(ii-57)/12.0);
//Serial.begin(38400);
Serial.begin(31250);
// Set volume and ADSR.
initialSettings();
}
void loop ()
{
////////////////////////////////
// Front panel mode
////////////////////////////////
if(digitalRead(A5)) { // 'enter' has been detected
digitalWrite(13, LOW); // activate switches
// configure I/O to read switches and read switches
for(ii=0; ii<addressWidth; ii++) {
pinMode(addressSwitches[ii], INPUT_PULLUP);
}
for(ii=0; ii<dataWidth; ii++) {
pinMode(dataSwitches[ii], INPUT_PULLUP);
}
// configure I/O to read switches and read switches
for(ii=0; ii<addressWidth; ii++) {
address[ii] = digitalRead(addressSwitches[ii]);
}
for(ii=0; ii<dataWidth; ii++) {
data[ii] = digitalRead(dataSwitches[ii]);
}
digitalWrite(13, HIGH); // deactivate switches
// configure I/O to write address and write data
for(ii=0; ii<addressWidth; ii++) {
pinMode(addressSwitches[ii], OUTPUT);
digitalWrite(addressSwitches[ii], address[ii]);
}
for(ii=0; ii<dataWidth; ii++) {
pinMode(dataSwitches[ii], OUTPUT);
digitalWrite(dataSwitches[ii], data[ii]);
}
digitalWrite(12, LOW);
delayMicroseconds(2000);;
digitalWrite(12, HIGH);
delay(200); // simple debounce
}
////////////////////////////////
// Remote mode
////////////////////////////////
if (Serial.available() > 0) {
Byte1 = Serial.read();
if ((Byte1 == 144) || (Byte1 == 128)) {
while(!Serial.available()) ;
Byte2 = Serial.read();
while(!Serial.available()) ;
Byte3 = Serial.read();
// Write note 'on'
if ((Byte3 > 0) && (Byte1 != 128)) {
if (voice1on)
voice1on = noteOff();
programNote(Byte2);
voice1on = noteOn();
voice1last = Byte2;
}
// Write note 'off'
if ((Byte3 == 0) || (Byte1 == 128))
if (voice1last == Byte2)
voice1on = noteOff();
}
}
}
void programNote(int midinote) {
calcFreq(f[midinote-12]);
address[0] = 0; address[1] = 0; address[2] = 0; address[3] = 0; address[4] = 0;
for(ii=0; ii<addressWidth; ii++) {
pinMode(addressSwitches[ii], OUTPUT);
digitalWrite(addressSwitches[ii],address[ii]);
}
for(ii=0; ii<dataWidth; ii++) {
pinMode(dataSwitches[ii], OUTPUT);
digitalWrite(dataSwitches[ii], data_Flo[ii]);
}
clockIn();
address[0] = 1;
for(ii=0; ii<addressWidth; ii++)
digitalWrite(addressSwitches[ii],address[ii]);
for(ii=0; ii<dataWidth; ii++)
digitalWrite(dataSwitches[ii], data_Fhi[ii]);
clockIn();
}
int noteOn(void) {
address[0] = 0; address[2] = 1;
data[0] = 1; data[1] = 0; data[2] = 0; data[3] = 0; data[4] = 1; data[5] = 0; data[6] = 0; data[7] = 0;
for(ii=0; ii<addressWidth; ii++)
digitalWrite(addressSwitches[ii],address[ii]);
for(ii=0; ii<dataWidth; ii++)
digitalWrite(dataSwitches[ii], data[ii]);
clockIn();
return 1;
}
int noteOff(void) {
address[0] = 0; address[2] = 1;
data[0] = 0; data[1] = 0; data[2] = 0; data[3] = 0; data[4] = 1; data[5] = 0; data[6] = 0; data[7] = 0;
for(ii=0; ii<addressWidth; ii++)
digitalWrite(addressSwitches[ii],address[ii]);
for(ii=0; ii<dataWidth; ii++)
digitalWrite(dataSwitches[ii], data[ii]);
clockIn();
return 0;
}
void initialSettings() {
// Set Attack and Decay
address[0]=1;address[1]=0;address[2]=1;address[3]=0;address[4]=0;
data[0]=1;data[1]=1;data[2]=0;data[3]=1;data[4]=0;data[5]=0;data[6]=0;data[7]=0;
for(ii=0; ii<addressWidth; ii++)
digitalWrite(addressSwitches[ii],address[ii]);
for(ii=0; ii<dataWidth; ii++)
digitalWrite(dataSwitches[ii], data[ii]);
clockIn();
// Set Sustain and Release
address[0]=0;address[1]=1;address[2]=1;address[3]=0;address[4]=0;
data[0]=0;data[1]=0;data[2]=0;data[3]=1;data[4]=0;data[5]=0;data[6]=1;data[7]=0;
for(ii=0; ii<addressWidth; ii++)
digitalWrite(addressSwitches[ii],address[ii]);
for(ii=0; ii<dataWidth; ii++)
digitalWrite(dataSwitches[ii], data[ii]);
clockIn();
// Set Volume
address[0]=0;address[1]=0;address[2]=0;address[3]=1;address[4]=1;
data[0]=1;data[1]=1;data[2]=1;data[3]=1;data[4]=0;data[5]=0;data[6]=0;data[7]=0;
for(ii=0; ii<addressWidth; ii++)
digitalWrite(addressSwitches[ii],address[ii]);
for(ii=0; ii<dataWidth; ii++)
digitalWrite(dataSwitches[ii], data[ii]);
clockIn();
}
void clockIn(void) {
digitalWrite(12, LOW);
delayMicroseconds(2000);;
digitalWrite(12, HIGH);
}
void calcFreq(double frequency) {
byte Fhi, Flo;
// Commodore magic to calculate high and low frequency data
double F = frequency/0.059605;
Fhi = F/256;
Flo = (F+.5)-Fhi*256;
// Convert data to sequence of ones and zeroes
for (ii=0;ii<dataWidth;ii++) {
data_Fhi[ii] = (Fhi>>ii)&1;
data_Flo[ii] = (Flo>>ii)&1;
}
}