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