diff --git a/Soft/Drum/Drum.ino b/Soft/Drum/Drum.ino index b1230a8f833b1b7ee6941bb7daa736b4000ba68d..4c9e5ae618893887171bd77c475ba979627b2697 100644 --- a/Soft/Drum/Drum.ino +++ b/Soft/Drum/Drum.ino @@ -1,5 +1,10 @@ #include <hardware/pwm.h> #include "Envelopes.h" +#include "Hardware.h" +#include "Kick.h" +#include "Snare.h" + +// Hardware definitions #define MODESWITCH_PIN_A 0 #define MODESWITCH_PIN_B 1 #define PUSHBUTTON_PIN 6 @@ -7,40 +12,40 @@ #define FREQ_POT_PIN 27 #define INV_POT_PIN 28 #define CHORD_POT_PIN 29 -#define DEBUG_MODE false -#define SAMPLES 512 // KICKDRUM SETTINGS -#define KICK_BASE_FREQ 0.15 -#define KICK_FREQ_RANGE 2.0 +#define KICK_BASE_FREQ 0.22 +#define KICK_FREQ_RANGE 10.0 #define KICK_SIGH_DELAY_MS 300 -#define KICK_SIGH_AMOUNT 0.02 +#define KICK_SIGH_AMOUNT 0.04 #define KICK_SIGH_SPEED 0.0004 +// SNAREDRUM SETTINGS +#define SNARE_BASE_FREQ 0.5 +#define SNARE_FREQ_RANGE 40.0 +#define SNARE_SIGH_DELAY_MS 100 +#define SNARE_SIGH_AMOUNT 0.1 +#define SNARE_SIGH_SPEED 0.0004 -int wave[SAMPLES]; -EnvelopeSimpleLinear kick_volume_envelope; -EnvelopeSimpleLog kick_pitch_envelope; -float pitch_sigh = 0.0; +// Switch +OnOffOnSwitch mode_switch(MODESWITCH_PIN_A, MODESWITCH_PIN_B); + +Kick kick; +Snare snare; -double last_trigger = 0; +float pitch_sigh = 0.0; bool gate_high, old_gate_high;//push sw int freq_pot; -float osc_freq; int chord_pot; -float volume_decay; int inv_pot; -float pitch_sigh_amount = KICK_SIGH_AMOUNT; -float pitch_sigh_speed = KICK_SIGH_SPEED; -float sigh_incrementer = 0.0; + int voct_input; -float osc_progress = 0; int slice_num = 0; @@ -49,17 +54,27 @@ void setup() { Serial.begin(9600); // Mode select switch is a On-Off-On switch with the outer pins connected // to the pins 0 and 1. - pinMode(MODESWITCH_PIN_A, INPUT_PULLUP); - pinMode(MODESWITCH_PIN_B, INPUT_PULLUP); + mode_switch.setup(); // Push Button pinMode(PUSHBUTTON_PIN, INPUT_PULLUP);//push sw // delay(1000); + - for (int i = 0; i < SAMPLES; i++) { - wave[i] = (sin(2 * M_PI * i / SAMPLES)) * 511; - // Serial.println(wave[i]); - } + kick.setup(); + kick.base_frequency = KICK_BASE_FREQ; + kick.frequency_range = KICK_FREQ_RANGE; + kick.pitch_envelope_sigh.delay = KICK_SIGH_DELAY_MS; + kick.pitch_envelope_sigh.amount = KICK_SIGH_AMOUNT; + kick.pitch_envelope_sigh.speed = KICK_SIGH_SPEED; + + + snare.setup(); + snare.base_frequency = SNARE_BASE_FREQ; + snare.frequency_range = SNARE_FREQ_RANGE; + snare.pitch_envelope_sigh.delay = SNARE_SIGH_DELAY_MS; + snare.pitch_envelope_sigh.amount = SNARE_SIGH_AMOUNT; + snare.pitch_envelope_sigh.speed = SNARE_SIGH_SPEED; //-------------------PWM setting------------------------------- gpio_set_function(2, GPIO_FUNC_PWM);// set GP2 function PWM @@ -84,53 +99,54 @@ void loop() { chord_pot = map(analogRead(CHORD_POT_PIN), 0, 1023, 1023, 0); inv_pot = map(analogRead(INV_POT_PIN), 0, 1023, 1023, 0); voct_input = analogRead(VOCT_PIN); - // Serial.println(voct_input); - osc_freq = KICK_BASE_FREQ + freq_pot/1023.0*KICK_FREQ_RANGE; - // Bigger decay values make the envelope shorter - kick_volume_envelope.setSpeed(0.000005 + (float)chord_pot/1023.0/3000.0); - kick_pitch_envelope.setSpeed(0.00001 + (float)inv_pot/1023.0/800.0); - // Increase the amount of the pitch envelope if the pitch decay is longer - kick_pitch_envelope.setAmount(2.0 + (1023.0-(float)inv_pot)/1023.0*8.5); - // kick_pitch_envelope.setAmount(0.0); - - // -------------------push sw , play wave------------------------------- + // Read IO + mode_switch.read(); readGates(); - updateKickEnvelopes(); -} - -void updateKickEnvelopes() { - // Increment the pitch sigh (a slight rise in pitch after - // the initial pitch envelope) - if ((millis() - last_trigger) > KICK_SIGH_DELAY_MS) { - sigh_incrementer += pitch_sigh_speed; - if (sigh_incrementer < 3.1415) { - pitch_sigh = max(0.0, sin(sigh_incrementer)); - } else { - pitch_sigh = 0.0; - } + // Update Modulation + if (mode_switch.mode == 0) { + kick.setFrequency(freq_pot/1023.0); + // Bigger decay values make the envelope shorter + kick.setVolumeDecay(0.000005 + (float)chord_pot/1023.0/3000.0); + kick.setPitchDecay(0.00001 + (float)inv_pot/1023.0/800.0); + // Increase the amount of the pitch envelope if the pitch decay is longer + kick.setPitchAmount(2.0 + (1023.0-(float)inv_pot)/1023.0*8.5); + kick.update(); + } else if (mode_switch.mode == 1) { + snare.setFrequency(freq_pot/1023.0); + // Bigger decay values make the envelope shorter + snare.setVolumeDecay(0.000005 + (float)chord_pot/1023.0/3000.0); + snare.setPitchDecay(0.00001 + (float)inv_pot/1023.0/800.0); + // Increase the amount of the pitch envelope if the pitch decay is longer + snare.setPitchAmount(2.0 + (1023.0-(float)inv_pot)/1023.0*8.5); + snare.update(); } - - kick_pitch_envelope.update(); - kick_volume_envelope.update(); + + + + // Serial.println("Min:0,Max:1023"); + // Serial.println(kick.render()); } + // Timer that pushes out the actual audio with a fixed frequency // Code inside this block needs to be fast in order to meet the deadlines void on_pwm_wrap() { + // Clear the PWM register pwm_clear_irq(slice_num); - - // Decrement the volume envelope - - // Set the output to the actual level - pwm_set_chan_level(slice_num, PWM_CHAN_A, kick_volume_envelope.value*wave[(int)osc_progress]/2+511); - // Advance the oscillator and reset it if it reached the end - osc_progress += osc_freq + kick_pitch_envelope.value + pitch_sigh * pitch_sigh_amount; - if (osc_progress > SAMPLES) { - osc_progress = 0; + // Set the output to the actual calculated sample + if (mode_switch.mode == 0){ + pwm_set_chan_level(slice_num, PWM_CHAN_A, kick.render()); + kick.advanceOscillator(); + } else if (mode_switch.mode == 1){ + pwm_set_chan_level(slice_num, PWM_CHAN_A, snare.render()); + snare.advanceOscillator(); + } else if (mode_switch.mode == 2){ + pwm_set_chan_level(slice_num, PWM_CHAN_A, 511); + // kick.advanceOscillator(); } } @@ -149,19 +165,14 @@ void readGates() { if (gate_high == 1) { // Trigger only on first rising flank if (old_gate_high == 0) { - // Reset the oscillator and the envelopes - osc_progress = 0; - last_trigger = millis(); - resetEnvelopes(); + // (Re-)Trigger the Kick + if (mode_switch.mode == 0){ + kick.trigger(); + } else if (mode_switch.mode == 1){ + snare.trigger(); + } else if (mode_switch.mode == 2){ + // kick.trigger(); + } } } -} - - - -void resetEnvelopes() { - kick_volume_envelope.reset(); - kick_pitch_envelope.reset(); - pitch_sigh = 0.0; - sigh_incrementer = 0.0; } \ No newline at end of file diff --git a/Soft/Drum/Envelopes.h b/Soft/Drum/Envelopes.h index defc48f21922bf10a49eb7bd896f17879d64699d..f5b7b96a56d4cb6de6adddfe1f51f8c170505677 100644 --- a/Soft/Drum/Envelopes.h +++ b/Soft/Drum/Envelopes.h @@ -66,38 +66,55 @@ void EnvelopeSimpleLog::setAmount(float amount) { this->amount = amount; } -// // ---- A simple logarithmic falling envelope ------- -// class EnvelopeSigh { -// public: -// float counter = 0.0; -// float value; -// float speed = 0.001; -// float delay = 300; -// float amount = 1.0; -// void update(); -// void reset(); -// void setAmount(float speed); -// void setSpeed(float speed); -// void setDelay(float speed); -// }; - -// void EnvelopeSimpleLog::update() { -// this->counter -= this->speed; -// if (this->counter <= 0.0) { -// this->counter = 0.0; -// } -// this->value = max(0.0, (log10(0.005 + 1.0 - this->counter)*-1.0))/2.3 * this->amount; -// } - -// void EnvelopeSimpleLog::reset() { -// this->counter = 1.0; -// this->value = 0.0; -// } - -// void EnvelopeSimpleLog::setSpeed(float speed) { -// this->speed = speed; -// } - -// void EnvelopeSimpleLog::setAmount(float amount) { -// this->amount = amount; -// } \ No newline at end of file +// ---- A sigh envelope ------- +class EnvelopeSigh { + public: + float counter = 0.0; + float value; + float speed = 0.001; + float delay = 300; + float amount = 1.0; + double last_trigger; + void update(); + void reset(); + void trigger(); + void setAmount(float speed); + void setSpeed(float speed); + void setDelay(float speed); +}; + +void EnvelopeSigh::update() { + this->counter -= this->speed; + if (this->counter <= 0.0) { + this->counter = 0.0; + } + if ((millis() - this->last_trigger) > this->delay) { + this->counter += this->speed; + if (this->counter < 3.1415) { + this->value = max(0.0, sin(this->counter)) * this->amount; + } else { + this->value = 0.0; + } + } +} + +void EnvelopeSigh::trigger() { + this->last_trigger = millis(); +} + +void EnvelopeSigh::reset() { + this->counter = 1.0; + this->value = 0.0; +} + +void EnvelopeSigh::setSpeed(float speed) { + this->speed = speed; +} + +void EnvelopeSigh::setAmount(float amount) { + this->amount = amount; +} + +void EnvelopeSigh::setDelay(float delay) { + this->delay = delay; +} \ No newline at end of file diff --git a/Soft/Drum/Hardware.h b/Soft/Drum/Hardware.h new file mode 100644 index 0000000000000000000000000000000000000000..19ef1c0aa262d243f7837e79cc1a56004c9e6730 --- /dev/null +++ b/Soft/Drum/Hardware.h @@ -0,0 +1,37 @@ +class OnOffOnSwitch { + public: + OnOffOnSwitch(int leftpin, int rightpin) { + this->leftpin = leftpin; + this->rightpin = rightpin; + } + int leftpin; + int rightpin; + int mode; + void setup(); + void read(); +}; + + + +void OnOffOnSwitch::setup() { + pinMode(this->leftpin, INPUT_PULLUP); + pinMode(this->rightpin, INPUT_PULLUP); +} + + +// Reads the mode switch, a tri-state On-Off-On toggle switch +// Assign the resulting mode to the mode_selection variable +void OnOffOnSwitch::read() { + bool left = digitalRead(this->leftpin); + bool right = digitalRead(this->rightpin); + if (left && right) { + // Center + this->mode = 1; + } else if (!left && right) { + // Left + this->mode = 2; + } else if (left && !right) { + // Right + this->mode = 0; + } +} \ No newline at end of file diff --git a/Soft/Drum/Kick.h b/Soft/Drum/Kick.h new file mode 100644 index 0000000000000000000000000000000000000000..56de9f73a3b6c435cfb451bf89566f6837430b63 --- /dev/null +++ b/Soft/Drum/Kick.h @@ -0,0 +1,82 @@ +#define SAMPLES 1048 + + + + +class Kick { + public: + float frequency; + float base_frequency; + float frequency_range; + EnvelopeSimpleLinear volume_envelope; + EnvelopeSimpleLog pitch_envelope; + EnvelopeSigh pitch_envelope_sigh; + void setup(); + void update(); + void reset(); + void trigger(); + float render(); + void advanceOscillator(); + void setVolumeDecay(float speed); + void setPitchDecay(float speed); + void setPitchAmount(float amount); + void setFrequency(float frequency); + + private: + int wavetable[SAMPLES]; + float osc_progress = 0.0; +}; + +void Kick::setup() { + // Fill the wavetable with a sine-wave + for (int i = 0; i < SAMPLES; i++) { + this->wavetable[i] = (sin(2 * M_PI * i / SAMPLES)) * 511; + } + + this->volume_envelope.amount = 1.0; +} + +void Kick::update() { + this->volume_envelope.update(); + this->pitch_envelope.update(); + this->pitch_envelope_sigh.update(); +} + +void Kick::reset() { + this->volume_envelope.reset(); + this->pitch_envelope.reset(); + this->pitch_envelope_sigh.reset(); + this->osc_progress = 0; +} + +void Kick::trigger() { + this->reset(); + this->pitch_envelope_sigh.trigger(); +} + +float Kick::render() { + return this->volume_envelope.value * this->wavetable[(int)this->osc_progress] / 2 + 511; +} + +void Kick::advanceOscillator() { + this->osc_progress += this->frequency + this->pitch_envelope.value + this->pitch_envelope_sigh.value; + if (this->osc_progress > SAMPLES) { + this->osc_progress = 0; + } +} + +void Kick::setVolumeDecay(float speed) { + this->volume_envelope.setSpeed(speed); +} + +void Kick::setPitchDecay(float speed) { + this->pitch_envelope.setSpeed(speed); +} + +void Kick::setPitchAmount(float amount) { + this->pitch_envelope.setAmount(amount); +} + +void Kick::setFrequency(float frequency) { + this->frequency = this->base_frequency + frequency * this->frequency_range; +} \ No newline at end of file diff --git a/Soft/Drum/Snare.h b/Soft/Drum/Snare.h new file mode 100644 index 0000000000000000000000000000000000000000..eb396d59c9984bd5a8298b2924b54013fb105b48 --- /dev/null +++ b/Soft/Drum/Snare.h @@ -0,0 +1,87 @@ +#define SAMPLES 1048 + + + + +class Snare { + public: + float frequency; + float base_frequency; + float frequency_range; + EnvelopeSimpleLinear volume_envelope; + EnvelopeSimpleLog pitch_envelope; + EnvelopeSigh pitch_envelope_sigh; + void setup(); + void update(); + void reset(); + void trigger(); + float render(); + void advanceOscillator(); + void setVolumeDecay(float speed); + void setPitchDecay(float speed); + void setPitchAmount(float amount); + void setFrequency(float frequency); + + private: + int sinetable[SAMPLES]; + int noisetable[SAMPLES]; + float osc_progress = 0.0; +}; + +void Snare::setup() { + // Fill the sinetable with a sine-wave + for (int i = 0; i < SAMPLES; i++) { + this->sinetable[i] = (sin(2 * M_PI * i / SAMPLES)) * 511; + } + + for (int i = 0; i < SAMPLES; i++) { + this->noisetable[i] = random(0, 1023); + } + + this->volume_envelope.amount = 1.0; +} + +void Snare::update() { + this->volume_envelope.update(); + this->pitch_envelope.update(); + this->pitch_envelope_sigh.update(); +} + +void Snare::reset() { + this->volume_envelope.reset(); + this->pitch_envelope.reset(); + this->pitch_envelope_sigh.reset(); + this->osc_progress = 0; +} + +void Snare::trigger() { + this->reset(); + this->pitch_envelope_sigh.trigger(); +} + +float Snare::render() { + return this->volume_envelope.value * (this->sinetable[(int)this->osc_progress] + this->pitch_envelope.value * noisetable[(int)this->osc_progress]) / 2 + 511; +} + +void Snare::advanceOscillator() { + this->osc_progress += this->frequency + this->pitch_envelope.value + this->pitch_envelope_sigh.value; + if (this->osc_progress > SAMPLES) { + this->osc_progress = 0; + } +} + +void Snare::setVolumeDecay(float speed) { + this->volume_envelope.setSpeed(speed); +} + +void Snare::setPitchDecay(float speed) { + this->pitch_envelope.setSpeed(speed); +} + +void Snare::setPitchAmount(float amount) { + this->pitch_envelope.setAmount(amount); +} + +void Snare::setFrequency(float frequency) { + this->frequency = this->base_frequency + frequency * this->frequency_range; +} \ No newline at end of file diff --git a/Soft/Rp2040/Rp2040.ino b/Soft/Rp2040/Rp2040.ino index 41fa6d625e962aed976f30d601e6682614196bca..a7a0d726ed67c327994345cd79f3eab88449d28f 100644 --- a/Soft/Rp2040/Rp2040.ino +++ b/Soft/Rp2040/Rp2040.ino @@ -21,7 +21,7 @@ int waveform_selection = 0; int f0 = 35; // base osc frequency int j = 0; -int select_mode = 0; // 0=chord without root , 1=chord with root,2=arpeggio +int mode_selection = 0; // 0=chord without root , 1=chord with root,2=arpeggio int inversion = 0; // 0-7 int old_invAD = 0; // countermeasure of input ADC noise int new_invAD = 0; // countermeasure of input ADC noise @@ -154,17 +154,17 @@ void on_pwm_wrap() { } } - if (select_mode != 2){ - if ((chord_mode==2 || chord_mode==3 || chord_mode==4) && select_mode == 0) { + if (mode_selection != 2){ + if ((chord_mode==2 || chord_mode==3 || chord_mode==4) && mode_selection == 0) { pwm_set_chan_level(slice_num, PWM_CHAN_A, wavetable[(int)osc_progress[0]]/4+wavetable[(int)osc_progress[1]]/4+wavetable[(int)osc_progress[3]]/4+511); - } else if ((chord_mode == 2 ||chord_mode == 3 ||chord_mode == 4) && select_mode == 1) { + } else if ((chord_mode == 2 ||chord_mode == 3 ||chord_mode == 4) && mode_selection == 1) { pwm_set_chan_level(slice_num, PWM_CHAN_A, wavetable[(int)osc_progress[0]]/4+wavetable[(int)osc_progress[1]]/4+wavetable[(int)osc_progress[2]]/4+wavetable[(int)osc_progress[4]]/4+511); - } else if ((chord_mode == 0 || chord_mode == 1|| chord_mode == 5) && select_mode == 0) { + } else if ((chord_mode == 0 || chord_mode == 1|| chord_mode == 5) && mode_selection == 0) { pwm_set_chan_level(slice_num, PWM_CHAN_A, wavetable[(int)osc_progress[0]]/5+wavetable[(int)osc_progress[1]]/5+wavetable[(int)osc_progress[2]]/5+wavetable[(int)osc_progress[3]]/5+511); - } else if ((chord_mode == 0 || chord_mode == 1|| chord_mode == 5) && select_mode == 1) { + } else if ((chord_mode == 0 || chord_mode == 1|| chord_mode == 5) && mode_selection == 1) { pwm_set_chan_level(slice_num, PWM_CHAN_A, wavetable[(int)osc_progress[0]]/5+wavetable[(int)osc_progress[1]]/5+wavetable[(int)osc_progress[2]]/5+wavetable[(int)osc_progress[3]]/5+wavetable[(int)osc_progress[4]]/5+511); } - } else if (select_mode == 2){ + } else if (mode_selection == 2){ pwm_set_chan_level(slice_num, PWM_CHAN_A, wavetable[(int)osc_progress[5]]/2+511); } } @@ -381,19 +381,19 @@ void loop() { } // Reads the mode switch, a tri-state On-Off-On toggle switch -// Assign the resulting mode to the select_mode variable +// Assign the resulting mode to the mode_selection variable void readModeSwitch() { bool left = digitalRead(MODESWITCH_PIN_A); bool right = digitalRead(MODESWITCH_PIN_B); if (left && right) { // Chord with bass - select_mode = 1; + mode_selection = 1; } else if (!left && right) { // Arpreggio - select_mode = 2; + mode_selection = 2; } else if (left && !right) { // Chord without bass - select_mode = 0; + mode_selection = 0; } }