From 534a6602a44a62dc50bfb7866848614c1e2d0d0d Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sat, 26 Oct 2024 18:16:45 +1100 Subject: [PATCH] Remaining tracks and complete notes --- 01LogisticChaos/01LogisticChaos.ino | 1 - 27CloudII/27CloudII.ino | 145 +++++++++++++++++++ 29SequencerChaos/29SequencerChaos.ino | 160 +++++++++++++++++++++ 30LogisticMod/30LogisticMod.ino | 163 +++++++++++++++++++++ 31FibomodAgain/31FibomodAgain.ino | 195 ++++++++++++++++++++++++++ README.md | 34 ++++- 6 files changed, 695 insertions(+), 3 deletions(-) create mode 100644 27CloudII/27CloudII.ino create mode 100644 29SequencerChaos/29SequencerChaos.ino create mode 100644 30LogisticMod/30LogisticMod.ino create mode 100644 31FibomodAgain/31FibomodAgain.ino diff --git a/01LogisticChaos/01LogisticChaos.ino b/01LogisticChaos/01LogisticChaos.ino index 7f6f8ef..15661f5 100644 --- a/01LogisticChaos/01LogisticChaos.ino +++ b/01LogisticChaos/01LogisticChaos.ino @@ -37,5 +37,4 @@ void loop() { xlog = r * xlog * (1 - xlog); int cv = round(xlog * 4095.0); mcp.setChannelValue(MCP4728_CHANNEL_A, cv); - delay(100); } diff --git a/27CloudII/27CloudII.ino b/27CloudII/27CloudII.ino new file mode 100644 index 0000000..cebe28a --- /dev/null +++ b/27CloudII/27CloudII.ino @@ -0,0 +1,145 @@ +// Better sequencer which uses interrupts + +#include +#include + +Adafruit_MCP4728 mcp; + + +float tuning[37]; +float voltrange = 4.85; // measured this, probably not accurate +float octave = 4096.0 / voltrange; // number of DAC steps in an octave + + +// melody + +// int pitch[] = { 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +// -1, -1, -1, -1, -1, -1, -1, -1,-1, -1, -1, -1,2, -1, -1, -1, }; +// int dur[] = { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, }; + +// hi hat + +int pitch[] = { 1, -1, 3, -1, 4, -1, 5, -1, }; + + +int note = 0; +int phrase = 8; +int grains_n = 12; +int grainc = 0; +int grainsize = 20; + +int s; +int bpm = 9000; +float beat_s = 60.0 / (float)bpm; +float note_s = beat_s * grains_n; +float beat_m = 1000.0 * beat_s; +bool noteon = false; +int beat = false; +long notestart, notedur, barstart; +int target, slew; +float decay = 0.1; + + +void setup() { + Serial.begin(115200); + + float freq = (float)bpm / 60.0; + + int ocr = round(16000000.0 / (1024.0 * freq )) - 1; + Serial.println(ocr); + if( ocr < 65536 ) { + + cli(); + + TCCR1A = 0;// set entire TCCR1A register to 0 + TCCR1B = 0;// same for TCCR1B + TCNT1 = 0;//initialize counter value to 0 + OCR1A = ocr; //ocr; + // turn on CTC mode + TCCR1B |= (1 << WGM12); + // Set CS10 and CS12 bits for 1024 escaler + TCCR1B |= (1 << CS12) | (1 << CS10); + // enable timer compare interrupt + TIMSK1 |= (1 << OCIE1A); + + sei(); + + } else { + Serial.println("BPM out of range"); + } + + if (!mcp.begin(0x64)) { + while (1) { + delay(100); + } + } + + // randomSeed(analogRead(A0)); + mcp.setSpeed(800000L); + make_tuning(12); + note=0; + notestart=millis(); +} + +void make_tuning(int edo) { + float n0 = 0; + float edof = (float)edo; + for( int i = 0; i < 37; i++ ) { + tuning[i] = round(n0 + octave * (float)i / edof); + } + +} + + +ISR(TIMER1_COMPA_vect){ // called once every beat + beat = true; +} + + +bool play_grain(int dur) { + return true; +// return random(0, 1000) > (float)dur * decay; +} + + +void loop() { + int now = millis(); + if( beat ) { + beat = false; + noteOn(pitch[s], now - notestart); + grainc++; + if( grainc > grains_n ) { + grainc = 0; + s += 1; + if( s == phrase ) { + s = 0; + notestart = now; + } + grainc = 0; + Serial.println(s); + } + } else { + if( noteon && now - notestart > grainsize ) { + noteOff(); + } + } +} + + +void noteOn(int note, int dur) { + Serial.println("noteOn"); + if( note > -1 && play_grain(dur) ) { + mcp.setChannelValue(MCP4728_CHANNEL_A, tuning[note]); + mcp.setChannelValue(MCP4728_CHANNEL_B, 4095); + noteon = true; + } +} + +void noteOff() { + mcp.setChannelValue(MCP4728_CHANNEL_B, 0); + noteon = false; + Serial.println("noteOff"); +} + + diff --git a/29SequencerChaos/29SequencerChaos.ino b/29SequencerChaos/29SequencerChaos.ino new file mode 100644 index 0000000..64a7293 --- /dev/null +++ b/29SequencerChaos/29SequencerChaos.ino @@ -0,0 +1,160 @@ +// Better sequencer which uses interrupts + +#include +#include + +Adafruit_MCP4728 mcp; + + +float tuning[37]; +float voltrange = 4.85; // measured this, probably not accurate +float octave = 4096.0 / voltrange; // number of DAC steps in an octave + + +// melody +// int pitch[] = { 1,3,7,2,3,4,3,4,3,4,6,7,3,4,3,1,3, 5, 9, 4, 5, 6, 5, 6, 5, 6, 8, 9, 5, 6, 5, 3}; +// float dur[] = { 0.1,0.00, 0.1, 0.05, 0.1,0.05, 0.05, 0.05, +// 0.1,0.05, 0.1, 0.05, 0.1,0.05, 0.05, 0.05, +// 0.1,0.05, 0.1, 0.05, 0.1,0.05, 0.05, 0.05, +// 0.1,0.05, 0.1, 0.05, 0.1,0.05, 0.05, 0.05,}; + + +int pitch[] = { 4, 1, 2, 3, 4, 5, 6, 4, 3, }; +int dur[] = { 0.6, 0.6,0.6,0.6,0.6,0.6,0.6,0.6, }; + +//float rseq[] = { 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, }; +float rseq[] = { 4.0, 3.6, -1, 3.232, 3.99, -1, -1, -1, }; + +int note = 0; +int phrase = 8; + +int s; +int bpm = 121; +float beat_s = 60.0 / (float)bpm; +float beat_m = 1000.0 * beat_s; +bool noteon = false; +int beat = false; +long notestart, notedur, barstart; +float xlog = 0.75; +float r = 3.7; + +void setup() { + Serial.begin(115200); + + float freqint = 60.0 / (float)bpm; + + int ocr = round(16000000.0 / (1024.0 * freqint * 16)) - 1; + Serial.println(ocr); + if( ocr < 65536 ) { + + cli(); + + TCCR1A = 0;// set entire TCCR1A register to 0 + TCCR1B = 0;// same for TCCR1B + TCNT1 = 0;//initialize counter value to 0 + OCR1A = ocr; + // turn on CTC mode + TCCR1B |= (1 << WGM12); + // Set CS10 and CS12 bits for 1024 escaler + TCCR1B |= (1 << CS12) | (1 << CS10); + // enable timer compare interrupt + TIMSK1 |= (1 << OCIE1A); + + sei(); + + } else { + Serial.println("BPM out of range"); + } + + if (!mcp.begin(0x64)) { + while (1) { + delay(100); + } + } + + // randomSeed(analogRead(A0)); + mcp.setSpeed(800000L); + make_tuning(7); + note=0; + barstart=millis(); +} + +void make_tuning(int edo) { + float n0 = 0; + float edof = (float)edo; + for( int i = 0; i < 37; i++ ) { + tuning[i] = round(n0 + octave * (float)i / edof); + } + +} + + +// mod_note argument is milliseconds from the start of last note +float mod_note(int x) { + return 1 - sq((float)x / 1000.0); +} + +// mod_note argument is milliseconds from the start of this bar +float mod_bar(int x) { + return 0.5 + 0.5 * sin((float)x / (beat_m * 2)); +} + +void set_mod(MCP4728_channel_t channel, float v) { + int o; + o = round(v * 4095.0); + if( o > 4095 ) { + o = 4095; + } + if( o < 0 ) { + o = 0; + } + mcp.setChannelValue(channel, o); +} + +ISR(TIMER1_COMPA_vect){ // called once every beat + beat = true; +} + + +void loop() { + float mod; + int o; + long now = millis(); + if( beat ) { + r = rseq[s]; + beat = false; + if( rseq[s] > -1 ) { + notestart = millis(); + notedur = round(beat_m * dur[s]); + noteOn(pitch[s]); + noteon = true; + } + s += 1; + if( s == phrase ) { + s = 0; + barstart = notestart; + } + } else { + if( noteon ) { + if( now - notestart > notedur ) { + noteOff(); + noteon = false; + } + } + } + xlog = r * xlog * (1 - xlog); + mcp.setChannelValue(MCP4728_CHANNEL_A, round(xlog * 4095.0)); +} + + +void noteOn(int note) { +// mcp.setChannelValue(MCP4728_CHANNEL_A, tuning[note]); + mcp.setChannelValue(MCP4728_CHANNEL_B, 4095); +} + +void noteOff() { + Serial.println("off"); + mcp.setChannelValue(MCP4728_CHANNEL_B, 0); +} + + diff --git a/30LogisticMod/30LogisticMod.ino b/30LogisticMod/30LogisticMod.ino new file mode 100644 index 0000000..0e34758 --- /dev/null +++ b/30LogisticMod/30LogisticMod.ino @@ -0,0 +1,163 @@ +// Better sequencer which uses interrupts + +#include +#include + +Adafruit_MCP4728 mcp; + + +float tuning[37]; +float voltrange = 4.85; // measured this, probably not accurate +float octave = 4096.0 / voltrange; // number of DAC steps in an octave + + +// melody + +// int pitch[] = { 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +// -1, -1, -1, -1, -1, -1, -1, -1,-1, -1, -1, -1,2, -1, -1, -1, }; +// int dur[] = { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, }; + +// hi hat + +int pitch[] = { 1, -1, -1-1, 4, -1,-1, -1,1, -1, -1,-1, 4, -1,-1, -1,1, -1, -1,-1, 4, -1,-1, -1,1, -1, -1,-1, 4, -1,-1, -1, }; +int dur[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; + + +int note = 0; +int phrase = 32; + +int s; +int bpm = 80; +float beat_s = 60.0 / (float)bpm; +float beat_m = 1000.0 * beat_s; +bool noteon = false; +int beat = false; +long notestart, notedur, barstart; +float xlog = 0.75; +float r = 0; + +void setup() { + Serial.begin(115200); + + float freqint = 60.0 / (float)bpm; + + int ocr = round(16000000.0 / (1024.0 * freqint * 16)) - 1; + Serial.println(ocr); + if( ocr < 65536 ) { + + cli(); + + TCCR1A = 0;// set entire TCCR1A register to 0 + TCCR1B = 0;// same for TCCR1B + TCNT1 = 0;//initialize counter value to 0 + OCR1A = ocr; + // turn on CTC mode + TCCR1B |= (1 << WGM12); + // Set CS10 and CS12 bits for 1024 escaler + TCCR1B |= (1 << CS12) | (1 << CS10); + // enable timer compare interrupt + TIMSK1 |= (1 << OCIE1A); + + sei(); + + } else { + Serial.println("BPM out of range"); + } + + if (!mcp.begin(0x64)) { + while (1) { + delay(100); + } + } + + // randomSeed(analogRead(A0)); + mcp.setSpeed(800000L); + make_tuning(12); + note=0; + barstart=millis(); +} + +void make_tuning(int edo) { + float n0 = 0; + float edof = (float)edo; + for( int i = 0; i < 37; i++ ) { + tuning[i] = round(n0 + octave * (float)i / edof); + } + +} + + +// mod_note argument is milliseconds from the start of last note +float mod_note(int x) { + float xb = x / (0.2 * beat_m); + return 0.5 + 0.5 * xb * (xb - 1) * ( xb - 2); +} + +// mod_note argument is milliseconds from the start of this bar +float mod_bar(int x) { + return 0.5 + 0.5 * sin((float)x / (beat_m)); +} + +void set_mod(MCP4728_channel_t channel, float v) { + int o; + o = round(v * 4095.0); + if( o > 4095 ) { + o = 4095; + } + if( o < 0 ) { + o = 0; + } + mcp.setChannelValue(channel, o); +} + +ISR(TIMER1_COMPA_vect){ // called once every beat + beat = true; +} + + +void loop() { + float mod; + int o; + long now = millis(); + if( beat ) { + beat = false; + if( pitch[s] > -1 ) { + notestart = millis(); + notedur = round(beat_m * dur[s]); + noteOn(pitch[s]); + noteon = true; + } + s += 1; + if( s == phrase ) { + s = 0; + barstart = notestart; + } + } else { + if( noteon ) { + set_mod(MCP4728_CHANNEL_C, mod_note(now - notestart)); + if( now - notestart > notedur ) { + noteOff(); + noteon = false; + } + } + mod = mod_bar(now - barstart); + set_mod(MCP4728_CHANNEL_D, mod); + r = 3.0 + mod; + xlog = r * xlog * (1 - xlog); + mcp.setChannelValue(MCP4728_CHANNEL_A, round(xlog * 4095.0)); + } +} + + +void noteOn(int note) { + if( note > -1 ) { + mcp.setChannelValue(MCP4728_CHANNEL_B, 4095); + } +} + +void noteOff() { + mcp.setChannelValue(MCP4728_CHANNEL_B, 0); +} + + diff --git a/31FibomodAgain/31FibomodAgain.ino b/31FibomodAgain/31FibomodAgain.ino new file mode 100644 index 0000000..6bbe492 --- /dev/null +++ b/31FibomodAgain/31FibomodAgain.ino @@ -0,0 +1,195 @@ +// Better sequencer which uses interrupts + +#include +#include + +Adafruit_MCP4728 mcp; +#define nsamp 1500 +#define dacmax 256 + + +float tuning[37]; +float voltrange = 4.85; // measured this, probably not accurate +float octave = 4096.0 / voltrange; // number of DAC steps in an octave + +byte waveform[nsamp]; + +// melody + +// int pitch[] = { 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +// -1, -1, -1, -1, -1, -1, -1, -1,-1, -1, -1, -1,2, -1, -1, -1, }; +// int dur[] = { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, }; + +// melody + +int pitch[] = { 1, -1, -1, -1, -1, -1, -1, -1, }; +int sequence[] = { 97, 98, 99, 100, 101, 102, 103, 104,105,}; +float dur[] = { 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, }; + + +// bass + + +unsigned int phase = 0; +unsigned int fibo = 3; +unsigned int scale = 0; +unsigned int fibi = 0; +unsigned int gate = 4095; +unsigned int pmax = nsamp; +unsigned int beat = 0; + + +int note = 0; +int phrase = 16; + +int s; +int bpm = 220; +float beat_s = 60.0 / (float)bpm; +float beat_m = 1000.0 * beat_s; +bool noteon = false; +long notestart, notedur, barstart; +float xlog = 0.75; +float r = 0; + +void setup() { + Serial.begin(115200); + + float freqint = (float)bpm/ 60.0; + + int ocr = round(16000000.0 / (1024.0 * freqint)) - 1; + Serial.println(ocr); + if( ocr < 65536 ) { + + cli(); + + TCCR1A = 0;// set entire TCCR1A register to 0 + TCCR1B = 0;// same for TCCR1B + TCNT1 = 0;//initialize counter value to 0 + OCR1A = ocr; + // turn on CTC mode + TCCR1B |= (1 << WGM12); + // Set CS10 and CS12 bits for 1024 escaler + TCCR1B |= (1 << CS12) | (1 << CS10); + // enable timer compare interrupt + TIMSK1 |= (1 << OCIE1A); + + sei(); + + } else { + Serial.println("BPM out of range"); + } + + if (!mcp.begin(0x64)) { + while (1) { + delay(100); + } + } + for( int i = 0; i < nsamp; i++ ) { + waveform[i] = 1; + } + fibi = 3; + fibo = 3; //fibosort[fibi]; + setwave(); + + // randomSeed(analogRead(A0)); + mcp.setSpeed(800000L); + note=0; + barstart=millis(); + + +} + +void setwave(){ + waveform[0] = 0; + waveform[1] = 1; + fibo = fibi; // fibosort[fibi];// + 3; + pmax = nsamp; + for (int i=2; i 4095 ) { + o = 4095; + } + if( o < 0 ) { + o = 0; + } + mcp.setChannelValue(channel, o); +} + +ISR(TIMER1_COMPA_vect){ // called once every beat + note++; + if( note == phrase ) { + note = 0; + } + fibi = sequence[note]; + beat = true; + setwave(); + phase = 0; +} + + +void loop() { + float mod; + int o; + long now = millis(); + if( beat ) { + beat = false; + if( pitch[note] > -1 ) { + notestart = millis(); + notedur = round(beat_m * dur[s]); + Serial.println(notedur); + gate = 4095; + } + } else { + if( gate ) { + if( now - notestart > notedur ) { + gate = 0; + } + } + mcp.fastWrite(waveform[phase] << 4, gate, 0, 0); + phase += 1; + if( phase == pmax ) { + phase = 0; + } + } +} + + +void noteOn(int note) { + if( note > -1 ) { + mcp.setChannelValue(MCP4728_CHANNEL_B, 4095); + } +} + +void noteOff() { + mcp.setChannelValue(MCP4728_CHANNEL_B, 0); +} + + diff --git a/README.md b/README.md index 4ebc8d1..d28c0a9 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,36 @@ Another 7TET piece using the sequencer Using the sequencer to trigger envelopes and LFOs at two scales - notes and bars -### 26 +### 26 Slew -Basic slew / portamento \ No newline at end of file +Basic slew / portamento + +### 27 Stasis Field + +A single track I recorded when trying to make Ribosome and left for later +because I liked it + +### 28 Spores + +One thing I wanted to get working this year was triggering clouds of small +events which I could layer up into richer textures. I didn't really succeed, +this is as close as I got. + +### 29 Nickel Itch + +Controlling the AR logistic function with the sequencer and distorting and +filtering with the modular. This is probably my favourite track. Nickel itch +is a skin irritation caused by that metal which afflicts manual workers in +electroplating shops. + +### 30 Processor + +More sequenced/timed control of the AR logistic noise + +### 31 Two Against One + +Trying to drive the Fibonacci algorithm with the sequencer ended up with one +really good track and a bunch of failed attempts to make a bassline to go with +it. Then I decided to use the attempts by themselves. Then I came back to do +the mixdown and thought of adding the original track over the top. This is +my second favourite after Nickel Itch. \ No newline at end of file