commit ddad5492e1f04d05af89c98a67109b9814ee38e1 Author: Mike Lynch Date: Sun Sep 29 08:50:28 2024 +1000 Initial commit diff --git a/LogisticAR/LogisticAR.ino b/LogisticAR/LogisticAR.ino new file mode 100644 index 0000000..f764b67 --- /dev/null +++ b/LogisticAR/LogisticAR.ino @@ -0,0 +1,41 @@ +// Basic demo for configuring the MCP4728 4-Channel 12-bit I2C DAC +#include +#include + +Adafruit_MCP4728 mcp; + +float xlog = 0.5; +float r = 3.783423; + +void setup(void) { + Serial.begin(115200); + while (!Serial) + delay(10); // will pause Zero, Leonardo, etc until serial console opens + + Serial.println("Adafruit MCP4728 test!"); + + // Try to initialize! + if (!mcp.begin(0x64)) { + Serial.println("Failed to find MCP4728 chip"); + while (1) { + delay(10); + } + } + + mcp.setChannelValue(MCP4728_CHANNEL_A, 4095); + mcp.setChannelValue(MCP4728_CHANNEL_B, 2048); + mcp.setChannelValue(MCP4728_CHANNEL_C, 1024); + mcp.setChannelValue(MCP4728_CHANNEL_D, 0); + + +} + + +void loop() { + int pot = analogRead(A0); + r = (float)pot / 1024.0 + 3.0; + xlog = r * xlog * (1 - xlog); + int cv = round(xlog * 4095.0); + mcp.setChannelValue(MCP4728_CHANNEL_A, cv); +// delay(100); +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..8c889f2 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +Looptober 2024 +============== + +Arduino code for my Looptober 24 stuff + +Music to be found at [my Funkwhale server](https://music.mikelynch.org/) \ No newline at end of file diff --git a/Sequencer/Sequencer.ino b/Sequencer/Sequencer.ino new file mode 100644 index 0000000..63b151f --- /dev/null +++ b/Sequencer/Sequencer.ino @@ -0,0 +1,168 @@ +// 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; + } +} +