// We Wish You a Merry Christmas #include #include Adafruit_MCP4728 mcp; float tuning[16]; // 0 = A, 8 = F (tonic) int m1[] = { 3, 8, 8, 10, 8, 7, 5, 5, 5, 10, 10, 12, 10, 8, 7, 3, 7, 12, 12, 13, 12, 10, 8, 5, 3, 3, 5, 10, 7, 8, 3, 8, 8, 8, 7, 7, 8, 7, 5, 3, 10, 12, 10, 10, 8, 8, 15, 3, 3, 3, 5, 10, 7, 8 }; int s1[] = { 0, 2, 4, 5, 6, 7, 8, 10, 12, 14, 16, 17, 18, 19, 20, 22, 24, 26, 28, 29, 30, 31, 32, 34, 36, 37, 38, 40, 42, 44, 48, 50, 52, 54, 56, 60, 62, 64, 66, 68, 72, 74, 76, 77, 78, 79, 80, 82, 84, 85, 86, 88, 90, 92 }; float d1[] = { 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 4 }; int m2[] = { 8, 1, 2, 3, 4, 5, 0, 1, 3, 8, 8, 3, 5, 7, 8, 7, 0, 1, 3, 8 }; int s2[] = { 2, 8, 14, 20, 26, 32, 36, 38, 42, 44, 50, 56, 62, 68, 74, 80, 84, 86, 90, 92 }; float d2[] = { 6, 6, 6, 6, 6, 4, 2, 4, 2, 6, 6, 6, 6, 6, 6, 4, 2, 4, 2, 4 }; // int m1[] = { 0, 2, 4, 5, 7, 9, 11, 12 }; // int s1[] = { 0, 2, 4, 6, 8, 10, 12, 14 }; // float d1[] = { 1.0, 0.5, 1.0, 0.5, 1.0, 0.5, 1.0, 0.5 }; // int m2[] = { 0, 4, 7, 12, 0, 4, 7, 12, 0, 4, 7, 12, 0, 4, 7, 12 }; // int s2[] = { 0, 1 , 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; // float d2[] = { 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 }; float gate = 0.5; int bpm = 320; float beat_s = 60.0 / (float)bpm; int beat = round(1000.0 * beat_s); // count_in = number of beats since t0 to wait before we startt playing // repeat = number of beats to repeat - could be computed from the sequence data // From here on, all times are in milliseconds to head off floating point errors long count_in = 4 * beat; int repeat = 96; float voltrange = 5.0; float octave = 4096.0 / voltrange; // number of DAC steps in an octave float mod_b = 3.141592653589793 / 4.0; typedef struct { int s = -1; bool playing = false; bool looped = false; long play = 0; long rel = 0; long last = 0; long init = 0; int *melody; int *start; float *duration; int len = 0; MCP4728_channel_t pitch; MCP4728_channel_t gate; } sequencer; sequencer seq1, seq2; long start_time; void setup(void) { Serial.begin(115200); while (!Serial) delay(10); // will pause Zero, Leonardo, etc until serial console opens if (!mcp.begin(0x64)) { Serial.println("Failed to find MCP4728 chip"); while (1) { delay(10); } Serial.println("MCP4728 initialised"); } float n0 = 0; for( int i = 0; i < 16; i++ ) { tuning[i] = round(n0 + octave * (float)i / 12.0); } long now = millis(); start_time = now; seq1.last = now; seq1.pitch = MCP4728_CHANNEL_A; seq1.gate = MCP4728_CHANNEL_B; seq1.melody = m1; seq1.start = s1; seq1.duration = d1; seq1.len = sizeof(m1) / sizeof(m1[0]); times_to_ms(seq1); seq2.last = now; seq2.pitch = MCP4728_CHANNEL_C; seq2.gate = MCP4728_CHANNEL_D; seq2.melody = m2; seq2.duration = d2; seq2.start = s2; seq2.len = sizeof(m2) / sizeof(m2[0]); times_to_ms(seq2); } void times_to_ms(sequencer& seq) { for( int i = 0; i < seq.len; i++ ) { seq.start[i] *= beat; seq.duration[i] = (float)beat * seq.duration[i] * 0.8; } } void loop() { long now = millis(); long t = now - start_time; long beats = -1; if( t >= count_in ) { beats = (t - count_in) % (beat * repeat); runSequencer(seq1, t, beats); runSequencer(seq2, t, beats); } } void runSequencer(sequencer& seq, long now, long beats) { int next = seq.s + 1; int start; if( seq.playing ) { if( now > seq.rel ) { mcp.setChannelValue(seq.gate, 0); seq.playing = false; } } if( next > seq.len - 1 ) { seq.s = -1; seq.looped = true; return; // don't start the loop yet } else { start = seq.start[next]; } if( seq.looped ) { // reached the end and waiting for the start of the bar if( beats < seq.last ) { seq.looped = false; // bar has restarted, start waiting seq.s = -1; next = 0; } else { return; } } seq.last = beats; if( beats >= start ) { seq.s = next; seq.rel = now + seq.duration[seq.s]; if( seq.melody[seq.s] > -1 ) { mcp.setChannelValue(seq.pitch, tuning[seq.melody[seq.s]]); mcp.setChannelValue(seq.gate, 4095); } seq.playing = true; } }