Skip to content
Snippets Groups Projects
Commit fa981f98 authored by David Huss's avatar David Huss :speech_balloon:
Browse files

Add Hihat

parent 16cfc379
Branches
No related tags found
No related merge requests found
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "Hardware.h" #include "Hardware.h"
#include "Kick.h" #include "Kick.h"
#include "Snare.h" #include "Snare.h"
#include "HiHat.h"
// Hardware definitions // Hardware definitions
#define MODESWITCH_PIN_A 0 #define MODESWITCH_PIN_A 0
...@@ -17,9 +18,10 @@ ...@@ -17,9 +18,10 @@
// KICKDRUM SETTINGS // KICKDRUM SETTINGS
#define KICK_BASE_FREQ 0.22 #define KICK_BASE_FREQ 0.22
#define KICK_FREQ_RANGE 10.0 #define KICK_FREQ_RANGE 10.0
#define KICK_SIGH_DELAY_MS 300 #define KICK_SIGH_DELAY_MS 200
#define KICK_SIGH_AMOUNT 0.04 #define KICK_SIGH_AMOUNT 0.08
#define KICK_SIGH_SPEED 0.0004 #define KICK_SIGH_SPEED 0.0005
#define KICK_SATURATION 2.0
// SNAREDRUM SETTINGS // SNAREDRUM SETTINGS
#define SNARE_BASE_FREQ 0.5 #define SNARE_BASE_FREQ 0.5
...@@ -28,25 +30,27 @@ ...@@ -28,25 +30,27 @@
#define SNARE_SIGH_AMOUNT 0.1 #define SNARE_SIGH_AMOUNT 0.1
#define SNARE_SIGH_SPEED 0.0004 #define SNARE_SIGH_SPEED 0.0004
// HIHAT SETTINGS
#define HIHAT_BASE_FREQ 0.5
#define HIHAT_FREQ_RANGE 20.0
// Switch // Create the Instruments
OnOffOnSwitch mode_switch(MODESWITCH_PIN_A, MODESWITCH_PIN_B);
Kick kick; Kick kick;
Snare snare; Snare snare;
HiHat hihat;
float pitch_sigh = 0.0;
bool gate_high, old_gate_high;//push sw // Switch
int freq_pot; OnOffOnSwitch mode_switch(MODESWITCH_PIN_A, MODESWITCH_PIN_B);
// Variables that store the read values of the switches and potentiometers
bool gate_high, old_gate_high;
int freq_pot;
int chord_pot; int chord_pot;
int inv_pot; int inv_pot;
int voct_input; int voct_input;
// Slice of the Hardware Timer
int slice_num = 0; int slice_num = 0;
...@@ -57,19 +61,19 @@ void setup() { ...@@ -57,19 +61,19 @@ void setup() {
// to the pins 0 and 1. // to the pins 0 and 1.
mode_switch.setup(); mode_switch.setup();
// Push Button // Push Button with internal pullup resistor
pinMode(PUSHBUTTON_PIN, INPUT_PULLUP);//push sw pinMode(PUSHBUTTON_PIN, INPUT_PULLUP);
// delay(1000);
// Setup the kick
kick.setup(); kick.setup();
kick.base_frequency = KICK_BASE_FREQ; kick.base_frequency = KICK_BASE_FREQ;
kick.frequency_range = KICK_FREQ_RANGE; kick.frequency_range = KICK_FREQ_RANGE;
kick.pitch_envelope_sigh.delay = KICK_SIGH_DELAY_MS; kick.pitch_envelope_sigh.delay = KICK_SIGH_DELAY_MS;
kick.pitch_envelope_sigh.amount = KICK_SIGH_AMOUNT; kick.pitch_envelope_sigh.amount = KICK_SIGH_AMOUNT;
kick.pitch_envelope_sigh.speed = KICK_SIGH_SPEED; kick.pitch_envelope_sigh.speed = KICK_SIGH_SPEED;
kick.setSaturation(KICK_SATURATION);
// Setup the snare
snare.setup(); snare.setup();
snare.base_frequency = SNARE_BASE_FREQ; snare.base_frequency = SNARE_BASE_FREQ;
snare.frequency_range = SNARE_FREQ_RANGE; snare.frequency_range = SNARE_FREQ_RANGE;
...@@ -77,7 +81,12 @@ void setup() { ...@@ -77,7 +81,12 @@ void setup() {
snare.pitch_envelope_sigh.amount = SNARE_SIGH_AMOUNT; snare.pitch_envelope_sigh.amount = SNARE_SIGH_AMOUNT;
snare.pitch_envelope_sigh.speed = SNARE_SIGH_SPEED; snare.pitch_envelope_sigh.speed = SNARE_SIGH_SPEED;
//-------------------PWM setting------------------------------- // Setup the hihat
hihat.setup();
hihat.base_frequency = HIHAT_BASE_FREQ;
hihat.frequency_range = HIHAT_FREQ_RANGE;
// Setup the PWM timer
gpio_set_function(2, GPIO_FUNC_PWM);// set GP2 function PWM gpio_set_function(2, GPIO_FUNC_PWM);// set GP2 function PWM
slice_num = pwm_gpio_to_slice_num(2);// GP2 PWM slice slice_num = pwm_gpio_to_slice_num(2);// GP2 PWM slice
...@@ -94,90 +103,94 @@ void setup() { ...@@ -94,90 +103,94 @@ void setup() {
} }
void loop() { void loop() {
// put your main code here, to run repeatedly: // Store the state of the previous gate for debouncing
old_gate_high = gate_high; old_gate_high = gate_high;
// Read the potentiometers and CV Inputs
freq_pot = analogRead(FREQ_POT_PIN); freq_pot = analogRead(FREQ_POT_PIN);
chord_pot = map(analogRead(CHORD_POT_PIN), 0, 1023, 1023, 0); chord_pot = map(analogRead(CHORD_POT_PIN), 0, 1023, 1023, 0);
inv_pot = map(analogRead(INV_POT_PIN), 0, 1023, 1023, 0); inv_pot = map(analogRead(INV_POT_PIN), 0, 1023, 1023, 0);
voct_input = analogRead(VOCT_PIN); voct_input = analogRead(VOCT_PIN);
// Read IO // Read Switches and Gates
mode_switch.read(); mode_switch.read();
readGates(); readGates();
// Update Modulation // Update Modulation for each instrument (depending on mode)
if (mode_switch.mode == 0) { if (mode_switch.mode == 0) {
// Modulation updates for Kick // Modulation updates for Kick
kick.setFrequency(freq_pot/1023.0); kick.setFrequency((float)freq_pot/1023.0);
// Bigger decay values make the envelope shorter kick.setVolumeDecay((float)chord_pot/1023.0);
kick.setVolumeDecay(0.000005 + (float)chord_pot/1023.0/3000.0); kick.setPitchDecay((float)inv_pot/1023.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 // 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.setPitchAmount(2.0 + (1023.0-(float)inv_pot)/1023.0*8.5);
kick.update(); kick.update();
} else if (mode_switch.mode == 1) { } else if (mode_switch.mode == 1) {
// Modulation updates for Snare // Modulation updates for Snare
snare.setFrequency(freq_pot/1023.0); snare.setFrequency((float)freq_pot/1023.0);
// Bigger decay values make the envelope shorter snare.setVolumeDecay((float)chord_pot/1023.0);
snare.setVolumeDecay(0.00005 + (float)chord_pot/1023.0/100.0); snare.setPitchDecay((float)inv_pot/1023.0);
snare.setPitchDecay(0.00001 + (float)inv_pot/1023.0/200.0);
// Increase the amount of the pitch envelope if the pitch decay is longer // 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.setPitchAmount((1023.0-(float)inv_pot)/1023.0);
float freq = 0.0+(1023.0-(float)inv_pot)*5.0; snare.setLpfFrequency(1023.0-(float)inv_pot);
Serial.println(freq);
snare.setLpfFrequency(freq);
snare.update(); snare.update();
} else if (mode_switch.mode == 2) {
// Modulation updates for Hihat
hihat.setFrequency((float)freq_pot/1023.0);
hihat.setVolumeDecay((float)chord_pot/1023.0);
hihat.setWavetableStart((1023.0-(float)inv_pot)/1023.0);
hihat.setHpfFrequency((float)inv_pot/1023.0);
hihat.update();
} }
// Serial.println("Min:0,Max:1023");
// Serial.println(kick.render());
} }
// Timer that pushes out the actual audio with a fixed frequency // 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 // Code inside this block needs to be _fast_ in order to meet the
// deadlines, otherwise crackling will be heard
void on_pwm_wrap() { void on_pwm_wrap() {
// Clear the PWM register // Clear the PWM register
pwm_clear_irq(slice_num); pwm_clear_irq(slice_num);
// Set the output to the actual calculated sample // Set the output to the actual calculated sample
if (mode_switch.mode == 0){ if (mode_switch.mode == 0){
// Render the next kick sample and advance the oscillator
pwm_set_chan_level(slice_num, PWM_CHAN_A, kick.render()); pwm_set_chan_level(slice_num, PWM_CHAN_A, kick.render());
kick.advanceOscillator(); kick.advanceOscillator();
} else if (mode_switch.mode == 1){ } else if (mode_switch.mode == 1){
// Render the next snare sample and advance the oscillator
pwm_set_chan_level(slice_num, PWM_CHAN_A, snare.render()); pwm_set_chan_level(slice_num, PWM_CHAN_A, snare.render());
snare.advanceOscillator(); snare.advanceOscillator();
} else if (mode_switch.mode == 2){ } else if (mode_switch.mode == 2){
pwm_set_chan_level(slice_num, PWM_CHAN_A, 511); // Render the next hihat sample and advance the oscillator
// kick.advanceOscillator(); pwm_set_chan_level(slice_num, PWM_CHAN_A, hihat.render());
hihat.advanceOscillator();
} }
} }
// Reads the push button and V/Oct Input in order to trigger the gate // Reads the push button and V/Oct Input in order to trigger the gate
void readGates() { void readGates() {
// Read the push button // Read the push button (invert the read value as we us a internal pullup resistor)
gate_high = !digitalRead(PUSHBUTTON_PIN); gate_high = !digitalRead(PUSHBUTTON_PIN);
// If there is a value bigger than 1 on the V/Oct Input, trigger the drum // If there is a value bigger than 1 on the V/Oct Input, trigger the drum
if (voct_input > 512) { gate_high = 1; } if (voct_input > 512) { gate_high = 1; }
// If the module is first starting, supress any accidental triggering // If the module is first starting, supress any accidental triggering for 500 ms
if (millis() < 500) { gate_high = 0; } if (millis() < 500) { gate_high = 0; }
// If there is a gate // If there is a gate
if (gate_high == 1) { if (gate_high == 1) {
// Trigger only on first rising flank // Trigger only on first rising flank
if (old_gate_high == 0) { if (old_gate_high == 0) {
// (Re-)Trigger the Kick // (Re-)Trigger the Instruments
if (mode_switch.mode == 0){ if (mode_switch.mode == 0){
kick.trigger(); kick.trigger();
} else if (mode_switch.mode == 1){ } else if (mode_switch.mode == 1){
snare.trigger(); snare.trigger();
} else if (mode_switch.mode == 2){ } else if (mode_switch.mode == 2){
// kick.trigger(); hihat.trigger();
} }
} }
} }
......
...@@ -88,3 +88,9 @@ void HPF::reset() { ...@@ -88,3 +88,9 @@ void HPF::reset() {
this->buf0 = 0.0; this->buf0 = 0.0;
this->buf1 = 0.0; this->buf1 = 0.0;
} }
float saturate(float x) {
return tanh(x);
}
Source diff could not be displayed: it is too large. Options to address this: view the blob.
#define SAMPLES 1048 #define SAMPLES 1024
...@@ -8,6 +8,8 @@ class Kick { ...@@ -8,6 +8,8 @@ class Kick {
float frequency; float frequency;
float base_frequency; float base_frequency;
float frequency_range; float frequency_range;
float saturation = 2;
float gain = 1.0;
EnvelopeSimpleLinear volume_envelope; EnvelopeSimpleLinear volume_envelope;
EnvelopeSimpleLog pitch_envelope; EnvelopeSimpleLog pitch_envelope;
EnvelopeSigh pitch_envelope_sigh; EnvelopeSigh pitch_envelope_sigh;
...@@ -23,6 +25,7 @@ class Kick { ...@@ -23,6 +25,7 @@ class Kick {
void setPitchDecay(float speed); void setPitchDecay(float speed);
void setPitchAmount(float amount); void setPitchAmount(float amount);
void setFrequency(float frequency); void setFrequency(float frequency);
void setSaturation(float saturation);
private: private:
int wavetable[SAMPLES]; int wavetable[SAMPLES];
...@@ -30,16 +33,16 @@ class Kick { ...@@ -30,16 +33,16 @@ class Kick {
}; };
void Kick::setup() { void Kick::setup() {
// Fill the wavetable with a sine-wave // Fill the wavetable with a sine-wave with values from 511 to -511
for (int i = 0; i < SAMPLES; i++) { for (int i = 0; i < SAMPLES; i++) {
this->wavetable[i] = (sin(2 * M_PI * i / SAMPLES)) * 511; this->wavetable[i] = saturate(this->saturation*sin(2 * M_PI * i / SAMPLES)) * 511;
} }
this->volume_envelope.amount = 1.0; this->volume_envelope.amount = 1.0;
lpf.setFrequency(1000.0); lpf.setFrequency(1000.0);
lpf.setResonance(0.99); lpf.setResonance(0.4);
hpf.setFrequency(30.0); hpf.setFrequency(30.0);
hpf.setResonance(0.5); hpf.setResonance(0.4);
} }
void Kick::update() { void Kick::update() {
...@@ -63,7 +66,7 @@ void Kick::trigger() { ...@@ -63,7 +66,7 @@ void Kick::trigger() {
float Kick::render() { float Kick::render() {
float orig_sample = this->volume_envelope.value * this->wavetable[(int)this->osc_progress]; float orig_sample = this->volume_envelope.value * this->wavetable[(int)this->osc_progress];
float filtered_sample = hpf.render(lpf.render(orig_sample)); float filtered_sample = hpf.render(lpf.render(orig_sample));
float sample = orig_sample*0.75 + filtered_sample*0.2; float sample = (orig_sample*2.0 + filtered_sample*0.3) * this->gain;
return sample / 2 + 511; return sample / 2 + 511;
} }
...@@ -75,10 +78,12 @@ void Kick::advanceOscillator() { ...@@ -75,10 +78,12 @@ void Kick::advanceOscillator() {
} }
void Kick::setVolumeDecay(float speed) { void Kick::setVolumeDecay(float speed) {
speed = 0.000005 + speed / 500.0;
this->volume_envelope.setSpeed(speed); this->volume_envelope.setSpeed(speed);
} }
void Kick::setPitchDecay(float speed) { void Kick::setPitchDecay(float speed) {
speed = 0.00001 + speed / 800.0;
this->pitch_envelope.setSpeed(speed); this->pitch_envelope.setSpeed(speed);
} }
...@@ -89,3 +94,7 @@ void Kick::setPitchAmount(float amount) { ...@@ -89,3 +94,7 @@ void Kick::setPitchAmount(float amount) {
void Kick::setFrequency(float frequency) { void Kick::setFrequency(float frequency) {
this->frequency = this->base_frequency + frequency * this->frequency_range; this->frequency = this->base_frequency + frequency * this->frequency_range;
} }
void Kick::setSaturation(float saturation) {
this->saturation = 1. + max(0.0, saturation);
}
\ No newline at end of file
#define SAMPLES 1048 #define SAMPLES 1024
...@@ -9,10 +9,12 @@ class Snare { ...@@ -9,10 +9,12 @@ class Snare {
float base_frequency; float base_frequency;
float frequency_range; float frequency_range;
EnvelopeSimpleLog volume_envelope; EnvelopeSimpleLog volume_envelope;
EnvelopeSimpleLog volume_envelope2;
EnvelopeSimpleLog pitch_envelope; EnvelopeSimpleLog pitch_envelope;
EnvelopeSigh pitch_envelope_sigh; EnvelopeSigh pitch_envelope_sigh;
LPF lpf; LPF lpf;
HPF hpf; HPF hpf;
float gain = 0.3;
void setup(); void setup();
void update(); void update();
void reset(); void reset();
...@@ -30,6 +32,7 @@ class Snare { ...@@ -30,6 +32,7 @@ class Snare {
int sinetable[SAMPLES]; int sinetable[SAMPLES];
int noisetable[SAMPLES]; int noisetable[SAMPLES];
float osc_progress = 0.0; float osc_progress = 0.0;
float osc_progress2 = 0.0;
}; };
void Snare::setup() { void Snare::setup() {
...@@ -47,7 +50,9 @@ void Snare::setup() { ...@@ -47,7 +50,9 @@ void Snare::setup() {
this->volume_envelope.amount = 1.0; this->volume_envelope.amount = 1.0;
this->hpf.setFrequency(200.0); this->hpf.setFrequency(200.0);
this->volume_envelope.setSnap(0.0005); this->volume_envelope.setSnap(0.0005);
this->volume_envelope2.setSnap(0.0005);
this->pitch_envelope.setSnap(0.0005); this->pitch_envelope.setSnap(0.0005);
// lpf.addFrequency(pitch_envelope.value*100.0 + pitch_envelope_sigh.value*50.0);
} }
...@@ -70,10 +75,10 @@ void Snare::trigger() { ...@@ -70,10 +75,10 @@ void Snare::trigger() {
} }
float Snare::render() { float Snare::render() {
float orig_sample = this->volume_envelope.value * (this->sinetable[(int)this->osc_progress] + this->pitch_envelope.value * noisetable[(int)this->osc_progress]); float orig_sample = this->volume_envelope.value * (this->sinetable[(int)this->osc_progress]
// lpf.addFrequency(pitch_envelope.value*500.0); + this->pitch_envelope.value * noisetable[(int)this->osc_progress]);
float filtered_sample = hpf.render(lpf.render(orig_sample)); float filtered_sample = hpf.render(lpf.render(orig_sample));
float sample = orig_sample/2 + filtered_sample/2; float sample = (orig_sample/2 + filtered_sample/2) * this->gain;
return sample / 2 + 511; return sample / 2 + 511;
} }
...@@ -82,17 +87,30 @@ void Snare::advanceOscillator() { ...@@ -82,17 +87,30 @@ void Snare::advanceOscillator() {
if (this->osc_progress > SAMPLES) { if (this->osc_progress > SAMPLES) {
this->osc_progress = 0; this->osc_progress = 0;
} }
this->osc_progress2 += this->frequency/2+ this->pitch_envelope.value*0.97 + this->pitch_envelope_sigh.value*1.2;
if (this->osc_progress2 > SAMPLES) {
this->osc_progress2 = 0;
}
} }
void Snare::setVolumeDecay(float speed) { void Snare::setVolumeDecay(float speed) {
// Describes the decay speed of the volume envelopes. Incoming speed
// variable is assumed to be in the range 0.0 to 1.0
speed = 0.0001 + speed / 100.0;
this->volume_envelope.setSpeed(speed); this->volume_envelope.setSpeed(speed);
this->volume_envelope2.setSpeed(speed*2);
} }
void Snare::setPitchDecay(float speed) { void Snare::setPitchDecay(float speed) {
// Describes the decay speed of the pitch envelope. Incoming speed
// variable is assumed to be in the range 0.0 to 1.0
speed = 0.005 + speed / 120.0;
this->pitch_envelope.setSpeed(speed); this->pitch_envelope.setSpeed(speed);
} }
void Snare::setPitchAmount(float amount) { void Snare::setPitchAmount(float amount) {
amount = 2.0 + amount * 8.5;
this->pitch_envelope.setAmount(amount); this->pitch_envelope.setAmount(amount);
} }
...@@ -101,7 +119,10 @@ void Snare::setFrequency(float frequency) { ...@@ -101,7 +119,10 @@ void Snare::setFrequency(float frequency) {
} }
void Snare::setLpfFrequency(float frequency) { void Snare::setLpfFrequency(float frequency) {
// Set the frequency of the Lowpass filter
frequency = 150.0 + frequency * 5.0;
this->lpf.setFrequency(frequency); this->lpf.setFrequency(frequency);
this->gain = map(frequency, 150, 5115, 1.0, 0.05);
} }
void Snare::setLpfResonance(float resonance) { void Snare::setLpfResonance(float resonance) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment