sinneb36 prototype 8: 3 voices polyphony controlled by Arduino!
Yes, it’s working!
Check out this demo, midi file loaded in Logic > midi out > breadboard > Arduino
Schematics:
Only thing missing in the schematics is the resistor based audio mixer. Connect all out pins from the 42100’s to 1k resistors and join the resulting output.
Code:
// -- sinneb36 -- // proto 8 // common data & clocklines for all ic's // dev start 5 july 2010 // 3 voices poly - voice 0, 1 and 2 // inc midi control // july 2010 #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}; // contains note value for the 3 voices int voices_note[3]; // contains key down (1) of inactive (0) value for each voice int voices_active[3]; // velocity per note int voices_velocity[3] = {0,0,0}; boolean done = false; boolean placed = false; // common pins for all ic's int dataPin = 2; int clockPin = 3; int ic595Pin = 4; int ic42100Pin = 5; int ledPin = 13; class MyMidi : public Midi { public: MyMidi(HardwareSerial &s) : Midi(s) {} void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity) { digitalWrite(13, HIGH); done = false; for(int i = 0; i < 3; i++) { // if voice inactive, replace with this played note // if no voice available, skip this note if(voices_active[i] == 0 && !done) { voices_note[i] = note; voices_active[i] = 1; // play note data_transfer_82c54(midi_divides_lsb[note],midi_divides_msb[note], i); // set velocity and update 42100 voices_velocity[i] = 250; update_42100(); // exit loop done = true; } } } void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity) { digitalWrite(13, LOW); for(int i = 0; i < 3; i++) { // find note and set inactive if(voices_note[i] == note) { voices_active[i] = 0; // set velocity and update 42100 voices_velocity[i] = 0; update_42100(); } } } }; MyMidi midi(Serial); void setup() { pinMode(dataPin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(ic595Pin, OUTPUT); pinMode(ic42100Pin, OUTPUT); pinMode(ledPin, OUTPUT); // set ic write off digitalWrite(ic595Pin, HIGH); digitalWrite(ic42100Pin, HIGH); // midi + serial midi.begin(0); initAllCounters(); // just once, set freqs for test data_transfer_82c54( 124, 425, 0); data_transfer_82c54( 163, 79, 1); data_transfer_82c54( 218, 28, 2); // set velocity to 0 for each voice voices_velocity[0] = 0; voices_velocity[1] = 0; voices_velocity[2] = 0; update_42100(); // init done digitalWrite(ledPin, HIGH); } void loop() { midi.poll(); } void set82c54(byte controlbyte, byte valuebyte, boolean lsbdefault = true) { digitalWrite(ic595Pin, LOW); // send controlbyte to 82c54 with A0,A1,WR shiftOut(dataPin, clockPin, LSBFIRST, controlbyte); // send valuebyte to 82c54, lsbfirst is default if(lsbdefault) { shiftOut(dataPin, clockPin, LSBFIRST, valuebyte); } else { shiftOut(dataPin, clockPin, MSBFIRST, valuebyte); } digitalWrite(ic595Pin, HIGH); } void initAllCounters() { //Serial.println("A0A1 -> 1, WR HIGH"); set82c54(B11100000,B00000000); //Serial.println("WR low"); set82c54(B01100000, B00000000); //Serial.println("control word counter 0"); set82c54(B01100000, B01101100); //Serial.println("WR high"); set82c54(B11100000, B01101100); //Serial.println("WR low"); set82c54(B01100000, B00000000); //Serial.println("control word counter 1"); set82c54(B01100000, B01101110); //Serial.println("WR high"); set82c54(B11100000, B01101100); //Serial.println("WR low"); set82c54(B01100000, B00000000); //Serial.println("control word counter 2"); set82c54(B01100000, B01101101); //Serial.println("WR high"); set82c54(B11100000, B01101100); } void data_transfer_82c54(int LSB, int MSB, int voice) { // counter 0 = B00000000 = 0 // counter 1 = B01000000 = 64 // counter 2 = B00100000 = 32 int voice2bin[3] = {0,64,32}; //Serial.println("A0A1 -> 0, WR high"); set82c54(B10000000 + voice2bin[voice], B00000000); //Serial.println("WR low"); set82c54(B00000000 + voice2bin[voice], B00000000); //Serial.println("82c54 waarde"); set82c54(B00000000 + voice2bin[voice], LSB, false); //Serial.println("WR high"); set82c54(B10000000 + voice2bin[voice], B00000000); //Serial.println("WR low"); set82c54(B00000000 + voice2bin[voice], B00000000); //Serial.println("82c54 waarde 2"); set82c54(B00000000 + voice2bin[voice], MSB, false); //Serial.println("WR high"); set82c54(B10000000 + voice2bin[voice], B00000000); } void update_42100() { byte ic42100pot0 = B00010001; // write to pot 0 byte ic42100pot1 = B00010010; // write to pot 1 digitalWrite (ic42100Pin, LOW); // update chip 2, voice 2 shiftOut(dataPin, clockPin, MSBFIRST, ic42100pot0); shiftOut(dataPin, clockPin, MSBFIRST, voices_velocity[2]); // update chip 1, voice 0 shiftOut(dataPin, clockPin, MSBFIRST, ic42100pot0); shiftOut(dataPin, clockPin, MSBFIRST, voices_velocity[0]); digitalWrite(ic42100Pin, HIGH); digitalWrite (ic42100Pin, LOW); // update chip 2, voice 3 //shiftOut(dataPin, clockPin, MSBFIRST, ic42100pot1); //shiftOut(dataPin, clockPin, MSBFIRST, voices_velocity[3]); // update chip 1, voice 1 shiftOut(dataPin, clockPin, MSBFIRST, ic42100pot1); shiftOut(dataPin, clockPin, MSBFIRST, voices_velocity[1]); digitalWrite(ic42100Pin, HIGH); }