Sequencer in sync is starting to come together

main
Mike Lynch 2023-12-27 11:18:10 +11:00
parent 0468c427d8
commit bd9940b96b
1 changed files with 76 additions and 39 deletions

View File

@ -8,12 +8,42 @@ Adafruit_MCP4728 mcp;
float tuning[16]; float tuning[16];
// 0 = A, 8 = F (tonic) // 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 }; For each note: pitch, absolute start time (in beats) and duration - either preset these or compute it
int d2[] = { 2, 6, 6, 6, 6, 6, 4, 2, 4, 2, 6, 6, 6, 6, 6, 6, 4, 2, 4, 2, 4 };
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; float gate = 0.5;
int bpm = 240; int bpm = 180;
float beat_s = 60.0 / (float)bpm; float beat_s = 60.0 / (float)bpm;
int beat_m = round(1000.0 * beat_s); int beat_m = round(1000.0 * beat_s);
float voltrange = 5.0; 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; float mod_b = 3.141592653589793 / 4.0;
typedef struct { typedef struct {
int s = 0; int s = -1;
bool noteOn = false; int playing = 0;
long play = 0; long play = 0;
long rel = 0; long rel = 0;
long last = 0; long last = 0;
long init = 0; long init = 0;
int *melody; int *melody;
int *duration; int *start;
float *duration;
int len = 0; int len = 0;
MCP4728_channel_t pitch; MCP4728_channel_t pitch;
MCP4728_channel_t gate; MCP4728_channel_t gate;
} sequencer; } sequencer;
sequencer seq1, seq2; sequencer seq1, seq2;
long start_time;
int repeat = 8;
void setup(void) { void setup(void) {
Serial.begin(115200); Serial.begin(115200);
@ -50,17 +82,18 @@ void setup(void) {
Serial.println("MCP4728 initialised"); Serial.println("MCP4728 initialised");
} }
mcp.setChannelValue(MCP4728_CHANNEL_B, 0);
float n0 = 0; float n0 = 0;
for( int i = 0; i < 16; i++ ) { for( int i = 0; i < 16; i++ ) {
tuning[i] = round(n0 + octave * (float)i / 12.0); tuning[i] = round(n0 + octave * (float)i / 12.0);
} }
long now = millis(); long now = millis();
start_time = now;
seq1.last = now; seq1.last = now;
seq1.pitch = MCP4728_CHANNEL_A; seq1.pitch = MCP4728_CHANNEL_A;
seq1.gate = MCP4728_CHANNEL_B; seq1.gate = MCP4728_CHANNEL_B;
seq1.melody = m1; seq1.melody = m1;
seq1.start = s1;
seq1.duration = d1; seq1.duration = d1;
seq1.len = sizeof(m1) / sizeof(m1[0]); seq1.len = sizeof(m1) / sizeof(m1[0]);
@ -69,6 +102,7 @@ void setup(void) {
seq2.gate = MCP4728_CHANNEL_D; seq2.gate = MCP4728_CHANNEL_D;
seq2.melody = m2; seq2.melody = m2;
seq2.duration = d2; seq2.duration = d2;
seq2.start = s2;
seq2.len = sizeof(m2) / sizeof(m2[0]); seq2.len = sizeof(m2) / sizeof(m2[0]);
} }
@ -76,41 +110,44 @@ void setup(void) {
void loop() { void loop() {
long now = millis(); long now = millis();
runSequencer(seq1, now); float beat = (float)(now - start_time) / (float)beat_m;
runSequencer(seq2, now); runSequencer(seq1, now, beat);
runSequencer(seq2, now, beat);
} }
void runSequencer(sequencer& seq, long now) { void runSequencer(sequencer& seq, long now, float beat) {
if( seq.noteOn ) { if( seq.s < seq.len - 1 ) {
if( now - seq.last > seq.rel ) { if( beat > (float)seq.start[seq.s + 1] ) {
noteOff(seq);
seq.last = now;
seq.play = 0; // no gate for now
seq.noteOn = false;
seq.s += 1; seq.s += 1;
if( seq.s > seq.len ) { Serial.print("seq / note ");
seq.s = 0; 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);
} }
} seq.playing = 1;
} 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;
} }
} }
if( seq.playing ) {
} if( now > seq.rel ) {
Serial.println("release");
mcp.setChannelValue(seq.gate, 0);
void noteOn(sequencer seq, int note) { seq.playing = 0;
if( note > -1 ) { }
mcp.setChannelValue(seq.pitch, tuning[note]);
mcp.setChannelValue(seq.gate, 4095);
} }
} }
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);
// }