diff --git a/05Wavetable/05Wavetable.ino b/05Wavetable/05Wavetable.ino index b7a78e0..c8e684f 100644 --- a/05Wavetable/05Wavetable.ino +++ b/05Wavetable/05Wavetable.ino @@ -92,7 +92,7 @@ void setwave(){ int val=0; //saw - val = dacmax * isamp / nsamp; + //val = dacmax * isamp / nsamp; //val = ( isamp < nsamp / 2 ) ? 0 : dacmax - 1; //sine //val=(sin(phi)+1.0)*dacmax/2; diff --git a/12SequencerII/12SequencerII.ino b/12SequencerII/12SequencerII.ino index 461c38b..fe96bfe 100644 --- a/12SequencerII/12SequencerII.ino +++ b/12SequencerII/12SequencerII.ino @@ -41,7 +41,7 @@ void setup() { // set compare match register for 1hz increments //OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536) //OCR1A = 7812;// = (16*10^6) / (1*1024) - 1 (must be <65536) - OCR1A = 800; + OCR1A = 2196; // about 135bpm? // turn on CTC mode TCCR1B |= (1 << WGM12); // Set CS10 and CS12 bits for 1024 escaler @@ -63,7 +63,6 @@ void setup() { mcp.setSpeed(800000L); make_tuning(12); note=0; - Serial.println("hello"); } void make_tuning(int edo) { diff --git a/21FMSynth/21FMSynth.ino b/21FMSynth/21FMSynth.ino new file mode 100644 index 0000000..a67fe25 --- /dev/null +++ b/21FMSynth/21FMSynth.ino @@ -0,0 +1,126 @@ +//waveform generator + +// hacked from https://www.instructables.com/Arduino-Waveform-Generator-1/ + +#include +#include + +Adafruit_MCP4728 mcp; + +#define nsamp 32 +#define dacmax 256 + +const byte nclk = 200; // a guess +long int freq; //frequency in Hz +long unsigned int phase; +long unsigned int phase_inc; + +int note = 0; +int gate; +int decay = 128; + +float pattern[16]; + +long unsigned int pattern_inc[4]; + +void setup() { + TIMSK0 &= ~_BV(TOIE0); // disable timer0 overflow interrupt + + cli(); + +//set timer1 interrupt at 1Hz + TCCR1A = 0;// set entire TCCR1A register to 0 + TCCR1B = 0;// same for TCCR1B + TCNT1 = 0;//initialize counter value to 0 + // set compare match register for 1hz increments + OCR1A = 3905;// = (16*10^6) / (1*1024) - 1 (must be <65536) + // turn on CTC mode + TCCR1B |= (1 << WGM12); + // Set CS10 and CS12 bits for 1024 prescaler + TCCR1B |= (1 << CS12) | (1 << CS10); + // enable timer compare interrupt + TIMSK1 |= (1 << OCIE1A); + + sei(); + + + Serial.begin(115200); + + if (!mcp.begin(0x64)) { + while (1) { + delay(100); + } + } + +// mcp.setSpeed(400000L); +// mcp.setSpeed(800000L); + mcp.setSpeed(800000L); + + freq=440; + phase=0; + //pattern[0] = 220.0; + // pattern[1] = 261.6255653005987; + // pattern[2] = 369.9944227116345; + // pattern[3] = 391.9954359817495; + for( int i = 0; i < 16; i++ ) { + pattern[i] = 440 + i * 80; + } + + pattern[1] = 0; + pattern[2] = 0; + + pattern[4] = 0; + pattern[5] = 0; + + + for( int i = 0; i < 16; i++ ) { + pattern_inc[i] = pattern[i] * 975592.231884058; + } + + setwave(); +} + +const float pi=3.14159265; +byte waveform[nsamp]; +byte phaseb = 0; +void setwave(){ + for (int isamp=0; isamp 15 ) { + note = 0; + } + phase_inc = pattern_inc[note]; + gate = 4095; +} + + + +void loop() { + phase += phase_inc; + int redphase = phase >> 27; + mcp.fastWrite(waveform[redphase] << 4, gate, 0, 0); + if( gate > 0 ) { + gate -= decay; + } +} + diff --git a/22Envelopes/22Envelopes.ino b/22Envelopes/22Envelopes.ino new file mode 100644 index 0000000..f1ecba1 --- /dev/null +++ b/22Envelopes/22Envelopes.ino @@ -0,0 +1,92 @@ +// Triggering shaped envelopes + +#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 + +//bool gates[] = { true, false, true, false, true, false, false, true }; + +bool gates[] = { true, false, false, false, true, false, false, false }; + + +int freqs[8]; + +int lpattern = 8; +int note = 0; + +bool trigger = false; +long t0 = 0; + + +void setup() { + + cli(); + +//set timer1 interrupt at 1Hz + TCCR1A = 0;// set entire TCCR1A register to 0 + TCCR1B = 0;// same for TCCR1B + TCNT1 = 0;//initialize counter value to 0 + // set compare match register for 1hz increments + //OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536) + //OCR1A = 7812;// = (16*10^6) / (1*1024) - 1 (must be <65536) + OCR1A = 10000; + // 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(); + + + + if (!mcp.begin(0x64)) { + while (1) { + delay(100); + } + } + + randomSeed(analogRead(A0)); + mcp.setSpeed(800000L); + + for( int i = 0; i < 8; i++ ) { + freqs[i] = random(10, 450); + } + + trigger = true; +} + + +ISR(TIMER1_COMPA_vect){ // called once every note + trigger = true; +} + + + +void loop() { + long now = millis(); + float f1; + int gate; + long freq; + if( trigger ) { + t0 = now; + trigger = false; + freq = freqs[note]; + gate = gates[note]; + note++; + if( note == lpattern ) { + note = 0; + } + } + f1 = 0.5 - 0.5 * sin((float)(now - t0) / (float)1000.0); + mcp.setChannelValue(MCP4728_CHANNEL_A, round(4095.0 * f1)); + mcp.setChannelValue(MCP4728_CHANNEL_B, gate ? 4095 : 0); +} + diff --git a/23SequencerEnvelope/23SequencerEnvelope.ino b/23SequencerEnvelope/23SequencerEnvelope.ino new file mode 100644 index 0000000..6461d5e --- /dev/null +++ b/23SequencerEnvelope/23SequencerEnvelope.ino @@ -0,0 +1,167 @@ +// 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 + + +int note = 0; + +// kick +// int pitch[] = { 8, -1, -1, -1, 8,-1, -1, -1, 8,-1, -1, -1, 8, -1, -1, 8, +// 8, -1, -1, -1, 8,-1, -1, -1, -1,-1, 8, -1, -1, 8, -1, 8, +// }; +// float 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,1,1,1,1, }; + + +// hi hat +// int pitch[] = { 8, 8, -1, 8, 8, 8, -1, 8, 8,8 , -1, 8, 8, 8, -1, 8, +// 8, 8, -1, 8, 8, 8, -1, 8, 8,8 , -1, 8, 8, 8, 8, 8, +// }; +// float 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,1,1,1,1, }; + +// bass triggers + +int pitch[] = { 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, }; + +float dur[] = { 8, 1, 1,1, 1,1,1,1, 1,1,1,1, 4, 1,1,1, +8, 1, 1,1, 1,1,1,1, 1,1,1,1, 4, 1,1,1,}; + + +int phrase = 32; + +int s; +int bpm = 110; +int beat_m = 100; // fix me coordinate with timer code +bool noteon = false; +int beat = false; +long notestart, notedur; + + +void setup() { + Serial.begin(115200); + + float freqint = 60.0 / (float)bpm; + + int ocr = round(16 * 10 ^ 6 / (1024.0 * freqint * 16)) - 1 + + Serial.println(ocr); + + if( ocr < 65536 ) { + + cli(); + + + + //set timer1 interrupt at 1Hz + TCCR1A = 0;// set entire TCCR1A register to 0 + TCCR1B = 0;// same for TCCR1B + TCNT1 = 0;//initialize counter value to 0 + // set compare match register for 1hz increments + //OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536) + //OCR1A = 7812;// = (16*10^6) / (1*1024) - 1 (must be <65536) + 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; +} + +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); + } + +} + +float mod_f(int x) { + return 1 - sq((float)x / 1000.0); +} + + + +ISR(TIMER1_COMPA_vect){ // called once every note + 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; + } + } else { + if( noteon ) { + mod = mod_f(now - notestart); + o = round(mod * 4095.0); + if( o > 4095 ) { + o = 4095; + } + if( o < 0 ) { + o = 0; + } + mcp.setChannelValue(MCP4728_CHANNEL_C, o); + if( now - notestart > notedur ) { + noteOff(); + noteon = false; + } + } + } +} + + +void noteOn(int note) { + if( note > -1 ) { + 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/24SequencerBPM/24SequencerBPM.ino b/24SequencerBPM/24SequencerBPM.ino new file mode 100644 index 0000000..cb2c1e8 --- /dev/null +++ b/24SequencerBPM/24SequencerBPM.ino @@ -0,0 +1,159 @@ +// 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, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, +-1, -1, -1, -1, -1, -1, -1, -1,-1, -1, -1, -1,-1, -1, -1, -1, }; +int dur[] = { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; + +int note = 0; +int phrase = 32; + +int s; +int bpm = 110; +float beat_s = 60.0 / (float)bpm; +float beat_m = 1000.0 * beat_s; +bool noteon = false; +int beat = false; +long notestart, notedur, barstart; + + +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 ) { + 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; + } + } + set_mod(MCP4728_CHANNEL_D, mod_bar(now - barstart)); + } +} + + +void noteOn(int note) { + if( note > -1 ) { + 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/25EnvelopesII/25EnvelopesII.ino b/25EnvelopesII/25EnvelopesII.ino new file mode 100644 index 0000000..6c7afd5 --- /dev/null +++ b/25EnvelopesII/25EnvelopesII.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[] = { 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, 2, 3,2, 4, 2,5, 0,1, 2, 3,2, 4, 2,5, 0,1, 2, 3,2, 4, 2,5, 0,1, 2, 3,2, 4, 2,5, 0, }; +int dur[] = { 0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.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; + + +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 * 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 ) { + 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; + } + } + set_mod(MCP4728_CHANNEL_D, mod_bar(now - barstart)); + } +} + + +void noteOn(int note) { + if( note > -1 ) { + 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/README.md b/README.md index 028fc94..bd8bb45 100644 --- a/README.md +++ b/README.md @@ -95,3 +95,9 @@ Using the random-note-clouds technique from the 8th but this time picking pitches from a hexany tuning, running it four times and drenching it in reverb +### 20 Fibomod + +Using the Fibonacci series modulo n, also known as the (Pisano period)[https://en.wikipedia.org/wiki/Pisano_period], as a wavetable, and incrementing n for each note in the sequence + + +