Third prototype: one voice!

Check this video on vimeo: http://vimeo.com/12988327 :)

This is the third prototype of my DIY synthesizer. I’m using a 82c54 16-bit timer chip for the voice (one chip has three timers, so three voices should be possible). This chip divides a master clock signal (usually in the Mhz range) through a programmable 16-bit value to create a audible frequency.

An Arduino Duemilanove interprets the midi (CNY17) and feeds a divider value via a shift register (74hc595) to the 82c54 voice. The crystal oscillator clock ticks at 8Mhz so for a 440Hz pulse waveform (central A) the division value is 18182. This prototype cannot produce notes below midinote 47 (B) because of it’s maximum divider value (16-bit = 65.536). Future prototypes will use a clock divider (arduino itself?)

Oh, my synth-playing-skills are well below par ;)

Very much inspired by the Roland Jupiter / Juno series.

This is the prototype from the previous post, with the midi in hardware solution from tetracon (arduino forum).

[][1]

Timothy Twillman has developed a great Arduino midi library. Very easy to implement, exactly what I needed. Check it out.

For each midi note, I pre-calculated the least and the most significant byte. The prototype code (very ugly):

#include "Midi.h"

int midi_divides_lsb[] = {66, 182, 65, 33, 183, 116, 192, 11, 222, 186, 44, 195, 33, 222, 160, 16,
                          221, 186, 94, 135, 240, 93, 150, 99, 144, 239, 80, 136, 111, 221, 176, 195,
                          248, 47, 75, 49, 200, 247, 168, 196, 55, 239, 216, 226, 252, 23, 37, 25, 228,
                          124, 212, 226, 156, 247, 236, 113, 126, 12, 19, 140, 114, 190, 106, 113, 206,
                          124, 118, 184, 63, 6, 9, 70, 185, 95, 53, 56, 103, 190, 59, 220, 159, 131, 133,
                          163, 221, 47, 154, 28, 179, 95, 29, 238, 208, 193, 194, 210, 238, 24, 77, 142,
                          218, 47, 143, 247, 104, 225, 97, 233, 119, 12, 167, 71, 237, 152, 71, 252, 180, 112,
                          49, 244, 188, 134, 83, 36, 246, 204, 164, 126};
int midi_divides_msb[] = {3822, 3607, 3405, 3214, 3033, 2863, 2702, 2551, 2407, 2272, 2145, 2024,
                          1911, 1803, 1702, 1607, 1516, 1431, 1351, 1275, 1203, 1136, 1072, 1012,
                          955, 901, 851, 803, 758, 715, 675, 637, 601, 568, 536, 506, 477, 450,
                          425, 401, 379, 357, 337, 318, 300, 284, 268, 253, 238, 225, 212, 200,
                          189, 178, 168, 159, 150, 142, 134, 126, 119, 112, 106, 100, 94, 89, 84,
                          79, 75, 71, 67, 63, 59, 56, 53, 50, 47, 44, 42, 39, 37, 35, 33, 31, 29,
                          28, 26, 25, 23, 22, 21, 19, 18, 17, 16, 15, 14, 14, 13, 12, 11, 11, 10,
                          9, 9, 8, 8, 7, 7, 7, 6, 6, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 2};

class MyMidi : public Midi {
  public:

  // Need this to compile; it just hands things off to the Midi class.
  MyMidi(HardwareSerial &s) : Midi(s) {}

  void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity)
  {
    digitalWrite(13, HIGH);
    data_transfer(midi_divides_lsb[note],midi_divides_msb[note]);
//    Serial.println(note);
//    Serial.print(midi_divides_lsb[note]);
//    Serial.print(" - ");
//    Serial.println(midi_divides_msb[note]);

  }

  void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity)
  {
    digitalWrite(13, LOW);
  }

  /* You can define any of these functions and they will be called when the
     matching message type is received.  Otherwise those types of Midi messages
     are just ignored.

    For C++ folks: these are all declared virtual in the base class

    void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity);
    void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity);
    void handleVelocityChange(unsigned int channel, unsigned int note, unsigned int velocity);
    void handleControlChange(unsigned int channel, unsigned int controller, unsigned int value);
    void handleProgramChange(unsigned int channel, unsigned int program);
    void handleAfterTouch(unsigned int channel, unsigned int velocity);
    void handlePitchChange(unsigned int pitch);
    void handleSongPosition(unsigned int position);
    void handleSongSelect(unsigned int song);
    void handleTuneRequest(void);
    void handleSync(void);
    void handleStart(void);
    void handleContinue(void);
    void handleStop(void);
    void handleActiveSense(void);
    void handleReset(void);
*/
};

//Pin connected to ST_CP of 74HC595
int latchPin = 8;
//Pin connected to SH_CP of 74HC595
int clockPin = 12;
////Pin connected to DS of 74HC595
int dataPin = 11;

int statusled = 13;

int incomingByte = 0;   // for incoming serial data

MyMidi midi(Serial);

void setup() {
  //set pins to output so you can control the shift register
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(statusled, OUTPUT);
  digitalWrite(statusled,HIGH);

  // init 8254 control ports 2,3,4
  pinMode(2, OUTPUT); // WR
  digitalWrite(2, HIGH); // disabled
  pinMode(3, OUTPUT); // A0
  pinMode(4, OUTPUT); // A1
  digitalWrite(3, LOW);
  digitalWrite(4, LOW);

  midi.begin(0);

  firstrun();
  //settozero();
}

void loop() {

//  if(Serial.available() > 0)
//      {
//        incomingByte = Serial.read();
//        if (incomingByte == 49) { // 1
//          firstrun();
//        }
//      }

       midi.poll();

}

void firstrun() {

    // control word sequence
    Serial.println("A0A1 -> 1");
    digitalWrite(3, HIGH);
    digitalWrite(4, HIGH);

    Serial.println("2 low");
    digitalWrite(2, LOW);

    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, LSBFIRST, B01101100);
    digitalWrite(latchPin, HIGH);
    Serial.println("595 loaded");

    Serial.println("2 high");
    digitalWrite(2, HIGH);
    // end control word sequence

    // start data transfer, LSB MSB
    // 18181 for 400hz
    data_transfer( 5, 71);
}

void data_transfer(int LSB, int MSB) {

    Serial.println("A0A1 -> 0");
    digitalWrite(3, LOW);
    digitalWrite(4, LOW);

    Serial.println("2 low");
    digitalWrite(2, LOW);

    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, LSB);
    digitalWrite(latchPin, HIGH);
    Serial.println("595 LSB");

    Serial.println("2 high");
    digitalWrite(2, HIGH);

    Serial.println("2 low");
    digitalWrite(2, LOW);

    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, MSB);
    digitalWrite(latchPin, HIGH);
    Serial.println("595 MSB");

    Serial.println("2 high");
    digitalWrite(2, HIGH);
}