diff --git a/Xmas/Xmas.ino b/Xmas/Xmas.ino index de1bd0b..10a54a6 100644 --- a/Xmas/Xmas.ino +++ b/Xmas/Xmas.ino @@ -8,12 +8,42 @@ 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 d1[] = { 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 4, 2, 2, 2, 2, 4, 2, 2, 2, 2, 4, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 4 }; -int m2[] = { -1, 8, 1, 2, 3, 4, 5, 0, 1, 3, 8, 8, 3, 5, 7, 8, 7, 0, 1, 3, 8 }; -int d2[] = { 2, 6, 6, 6, 6, 6, 4, 2, 4, 2, 6, 6, 6, 6, 6, 6, 4, 2, 4, 2, 4 }; +/* + +For each note: pitch, absolute start time (in beats) and duration - either preset these or compute it + +For a sequencer: is time-elapsed > start time of next note? + +if yes - set the play time to now, increment the note + - if a note happens to be playing now, doesn't matter, just change the pitch and reset the timer + +if no - is there still a note playing? + +if still playing, is now - play start > the note's duration? if so, stop playing + +the absolute start time should include a count-in + +*/ + +// 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[] = { 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, 96 }; +// int d1[] = { 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 4, 2, 2, 2, 2, 4, 2, 2, 2, 2, 4, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 4 }; + +//int m2[] = { -1, 8, 1, 2, 3, 4, 5, 0, 1, 3, 8, 8, 3, 5, 7, 8, 7, 0, 1, 3, 8 }; +//int d2[] = { 2, 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[] = { 3, 5, 7, 9, 11, 13, 15, 17 }; +float d1[] = { 1.0, 0.5, 1.0, 0.5, 1.0, 0.5, 1.0, 0.5 }; +int m2[] = { 0, 3, 6, 9, 1, 4, 7, 11, 2, 5, 8, 13, 1, 4, 7, 11 }; +int s2[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; +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 = 240; +int bpm = 180; float beat_s = 60.0 / (float)bpm; int beat_m = round(1000.0 * beat_s); float voltrange = 5.0; @@ -21,21 +51,23 @@ float octave = 4096.0 / voltrange; // number of DAC steps in an octave float mod_b = 3.141592653589793 / 4.0; typedef struct { - int s = 0; - bool noteOn = false; + int s = -1; + int playing = 0; long play = 0; long rel = 0; long last = 0; long init = 0; int *melody; - int *duration; + int *start; + float *duration; int len = 0; MCP4728_channel_t pitch; MCP4728_channel_t gate; } sequencer; sequencer seq1, seq2; - +long start_time; +int repeat = 8; void setup(void) { Serial.begin(115200); @@ -50,17 +82,18 @@ void setup(void) { Serial.println("MCP4728 initialised"); } - mcp.setChannelValue(MCP4728_CHANNEL_B, 0); 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]); @@ -69,6 +102,7 @@ void setup(void) { seq2.gate = MCP4728_CHANNEL_D; seq2.melody = m2; seq2.duration = d2; + seq2.start = s2; seq2.len = sizeof(m2) / sizeof(m2[0]); } @@ -76,41 +110,44 @@ void setup(void) { void loop() { long now = millis(); - runSequencer(seq1, now); - runSequencer(seq2, now); + float beat = (float)(now - start_time) / (float)beat_m; + runSequencer(seq1, now, beat); + runSequencer(seq2, now, beat); } -void runSequencer(sequencer& seq, long now) { - if( seq.noteOn ) { - if( now - seq.last > seq.rel ) { - noteOff(seq); - seq.last = now; - seq.play = 0; // no gate for now - seq.noteOn = false; +void runSequencer(sequencer& seq, long now, float beat) { + if( seq.s < seq.len - 1 ) { + if( beat > (float)seq.start[seq.s + 1] ) { seq.s += 1; - if( seq.s > seq.len ) { - seq.s = 0; + Serial.print("seq / note "); + Serial.print(seq.s); + Serial.print(" / "); + Serial.println(seq.melody[seq.s]); + seq.rel = now + round((float)beat_m * seq.duration[seq.s]); + if( seq.melody[seq.s] > -1 ) { + mcp.setChannelValue(seq.pitch, tuning[seq.melody[seq.s]]); + mcp.setChannelValue(seq.gate, 4095); } - } - } else { - if( now - seq.last > seq.play ) { - noteOn(seq, seq.melody[seq.s]); - seq.last = now; - seq.rel = beat_m * seq.duration[seq.s]; - seq.noteOn = true; + seq.playing = 1; } } - -} - - -void noteOn(sequencer seq, int note) { - if( note > -1 ) { - mcp.setChannelValue(seq.pitch, tuning[note]); - mcp.setChannelValue(seq.gate, 4095); + if( seq.playing ) { + if( now > seq.rel ) { + Serial.println("release"); + mcp.setChannelValue(seq.gate, 0); + seq.playing = 0; + } } } -void noteOff(sequencer seq) { - mcp.setChannelValue(seq.gate, 0); -} + +// void noteOn(sequencer& seq, int note) { +// if( note > -1 ) { +// mcp.setChannelValue(seq.pitch, tuning[note]); +// mcp.setChannelValue(seq.gate, 4095); +// } +// } + +// void noteOff(sequencer& seq) { +// mcp.setChannelValue(seq.gate, 0); +// }