proto 6 and new ideas

At the bottom of this post you’ll find the newest code for the prototype. This code has some nice enhancements over the previous:

Sketch for proto 7:

Here I’m going to use 1 dataline and 1 clockline for all components. This saves on the digital out pins from the Arduino. There’s going to be a lot of data shifting through the 4 74hc595’s and the 3 mcp42100’s… A challenge ;)

// sinneb.com
// arduino interface code for the Sinneb Aurora 6

// Midi library from http://timothytwillman.com
// MCP42100 code from http://little-scale.blogspot.com/
// 82c54 code from sinneb.com

#include "Midi.h"

// Midi note 0 - 127 LSB & MSB values
// http://www.decisioncards.com/io/tutorials/8254_tut2.html
// Divide value by 256. i.e. 10000 / 256 gives 39.0625
// Use the whole value to load your MSB i.e. MSB=39
// Subtract the whole number i.e. 39.0625 - 39=0.0625
// Multiply by 256 to obtain remainder i.e. 0.0625 x 256=16
// Use the value diplayed as your LSB i.e. LSB=16

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};

int activenotes[10];
int temp_activenotes[10];
int temp_counter;

// for potentiometer antilog
// http://tp01.com/etutorials/images/resistors/Potentiometer%20Tapers.gif
int lin2log[] = { 0,  15,  30,  61,  70,  85,  91, 101, 105, 112,
                116, 119, 121, 127, 131, 137, 139, 141, 143, 146,
                147, 149, 150, 156, 157, 159, 160, 162, 163, 165,
                166, 167, 170, 171, 172, 174, 175, 175, 176, 178,
                179, 181, 182, 183, 183, 185, 185, 186, 188, 188,
                190, 191, 191, 192, 192, 194, 195, 195, 196, 197,
                198, 199, 200, 201, 203, 203, 204, 205, 206, 207,
                207, 209, 210, 210, 211, 212, 212, 214, 214, 215,
                216, 217, 217, 218, 219, 219, 220, 221, 222, 223,
                223, 224, 224, 224, 225, 226, 227, 227, 227, 228,
                229, 229, 230, 230, 231, 231, 232, 232, 232, 233,
                233, 234, 234, 235, 235, 235, 236, 236, 237, 237,
                237, 238, 238, 239, 239, 239, 240, 240, 240}; // about 128 ;)

// 74HC595 pins
int latchPin = 8;
int dataPin = 11;
int clockPin = 12;

// 42100 pins
int select42100 = 5;
int clock42100 = 6;
int data42100 = 7;
byte pot0 = B00010001; // write to pot 0
byte pot1 = B00010010; // write to pot 1
boolean placed = false;

// various vars
int statusled = 13;
int incomingByte = 0;
int startnote = 47;
int potinit = 1;
float counter = 0;
// ADSR vars
float potcurrent = 0;
int pottarget = 0;

class MyMidi : public Midi {
  public:
  MyMidi(HardwareSerial &s) : Midi(s) {}

  void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity)
  {
    digitalWrite(13, HIGH);
    // place noteon note in activenotes array
    placed = false;
    for(int i = 0; i < 10; i++) {
      if(activenotes[i]==0 && placed == false) {
        activenotes[i]=note;
        placed=true;
      }
    }
    data_transfer(midi_divides_lsb[note],midi_divides_msb[note]);
    pottarget=127;
    //spi_out(select42100, pot0, 240);
  }

  void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity)
  {
    digitalWrite(13, LOW);
    //pottarget=0;
    temp_counter=0;
    // empty temp_activenotes
    memset(temp_activenotes, 0, sizeof(temp_activenotes));
    // remove note from activenotes array
    for(int i = 0; i < 10; i++) {
      if(activenotes[i]==note) {
        activenotes[i]=0;
      }
      // place still active notes in temp_array
      else if (activenotes[i]!=0) {
        temp_activenotes[temp_counter]=activenotes[i];
        temp_counter++;
      }
    }
    // copy temp to activenotes
    for(int i=0; i < 10; i++) {
      activenotes[i] = temp_activenotes[i];
    }
    // if firstnote <> 0, retrigger last note in array
    placed = false;
    // check if notes in array
    if(activenotes[0]!=0) {
      // find first zero, play index - 1 (last value in array)
      for(int i=1; i < 10; i++) {
        if(activenotes[i]==0 && placed == false) {
          data_transfer(midi_divides_lsb[activenotes[i-1]],midi_divides_msb[activenotes[i-1]]);
          placed = true;
        }
      }
    }
    else {
      // start release
      //spi_out(select42100, pot0, 0);
      pottarget=0;
    }
  }

  /* 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 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);
*/
};

MyMidi midi(Serial);

void setup() {
  // init all pin
  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);

  // init 42100

  pinMode(select42100, OUTPUT);
  pinMode(clock42100, OUTPUT);
  pinMode(data42100, OUTPUT);
  digitalWrite(select42100, HIGH);

  midi.begin(0);

  firstrun();

  spi_out(select42100, pot0, 240);

}

void loop() {

       midi.poll();

       // ADSR
       if (potcurrent != pottarget) {
         if (potcurrent > pottarget) {
           // release
           potcurrent = potcurrent - (127 / 300);
         } else {
           // attack
           potcurrent = 127;
         }
       }
       spi_out(select42100, pot0, lin2log[int(potcurrent)]);
}

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);
}

/* FUNCTIONS */
void spi_transfer(byte working) {
  for(int i = 1; i <= 8; i++) {
    if (working > 127) {
      digitalWrite (data42100,HIGH);
    }
    else {
      digitalWrite (data42100, LOW);
    }
    digitalWrite (clock42100,HIGH);
    working = working << 1;
    digitalWrite(clock42100,LOW);
  }
}

void spi_out(int ss, byte cmd_byte, byte data_byte) {
  digitalWrite (select42100, LOW);
  spi_transfer(cmd_byte);
  spi_transfer(data_byte);
  digitalWrite(select42100, HIGH);
}