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

Add Hihat

parent 16cfc379
No related branches found
No related tags found
No related merge requests found
......@@ -4,6 +4,7 @@
#include "Hardware.h"
#include "Kick.h"
#include "Snare.h"
#include "HiHat.h"
// Hardware definitions
#define MODESWITCH_PIN_A 0
......@@ -17,9 +18,10 @@
// KICKDRUM SETTINGS
#define KICK_BASE_FREQ 0.22
#define KICK_FREQ_RANGE 10.0
#define KICK_SIGH_DELAY_MS 300
#define KICK_SIGH_AMOUNT 0.04
#define KICK_SIGH_SPEED 0.0004
#define KICK_SIGH_DELAY_MS 200
#define KICK_SIGH_AMOUNT 0.08
#define KICK_SIGH_SPEED 0.0005
#define KICK_SATURATION 2.0
// SNAREDRUM SETTINGS
#define SNARE_BASE_FREQ 0.5
......@@ -28,25 +30,27 @@
#define SNARE_SIGH_AMOUNT 0.1
#define SNARE_SIGH_SPEED 0.0004
// HIHAT SETTINGS
#define HIHAT_BASE_FREQ 0.5
#define HIHAT_FREQ_RANGE 20.0
// Switch
OnOffOnSwitch mode_switch(MODESWITCH_PIN_A, MODESWITCH_PIN_B);
// Create the Instruments
Kick kick;
Snare snare;
HiHat hihat;
float pitch_sigh = 0.0;
bool gate_high, old_gate_high;//push sw
int freq_pot;
// Switch
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 inv_pot;
int voct_input;
// Slice of the Hardware Timer
int slice_num = 0;
......@@ -57,19 +61,19 @@ void setup() {
// to the pins 0 and 1.
mode_switch.setup();
// Push Button
pinMode(PUSHBUTTON_PIN, INPUT_PULLUP);//push sw
// delay(1000);
// Push Button with internal pullup resistor
pinMode(PUSHBUTTON_PIN, INPUT_PULLUP);
// Setup the kick
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;
kick.setSaturation(KICK_SATURATION);
// Setup the snare
snare.setup();
snare.base_frequency = SNARE_BASE_FREQ;
snare.frequency_range = SNARE_FREQ_RANGE;
......@@ -77,7 +81,12 @@ void setup() {
snare.pitch_envelope_sigh.amount = SNARE_SIGH_AMOUNT;
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
slice_num = pwm_gpio_to_slice_num(2);// GP2 PWM slice
......@@ -94,90 +103,94 @@ void setup() {
}
void loop() {
// put your main code here, to run repeatedly:
// Store the state of the previous gate for debouncing
old_gate_high = gate_high;
// Read the potentiometers and CV Inputs
freq_pot = analogRead(FREQ_POT_PIN);
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);
// Read IO
// Read Switches and Gates
mode_switch.read();
readGates();
// Update Modulation
// Update Modulation for each instrument (depending on mode)
if (mode_switch.mode == 0) {
// Modulation updates for Kick
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);
kick.setFrequency((float)freq_pot/1023.0);
kick.setVolumeDecay((float)chord_pot/1023.0);
kick.setPitchDecay((float)inv_pot/1023.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) {
// Modulation updates for Snare
snare.setFrequency(freq_pot/1023.0);
// Bigger decay values make the envelope shorter
snare.setVolumeDecay(0.00005 + (float)chord_pot/1023.0/100.0);
snare.setPitchDecay(0.00001 + (float)inv_pot/1023.0/200.0);
snare.setFrequency((float)freq_pot/1023.0);
snare.setVolumeDecay((float)chord_pot/1023.0);
snare.setPitchDecay((float)inv_pot/1023.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);
float freq = 0.0+(1023.0-(float)inv_pot)*5.0;
Serial.println(freq);
snare.setLpfFrequency(freq);
snare.setPitchAmount((1023.0-(float)inv_pot)/1023.0);
snare.setLpfFrequency(1023.0-(float)inv_pot);
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
// 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() {
// Clear the PWM register
pwm_clear_irq(slice_num);
// Set the output to the actual calculated sample
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());
kick.advanceOscillator();
} 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());
snare.advanceOscillator();
} else if (mode_switch.mode == 2){
pwm_set_chan_level(slice_num, PWM_CHAN_A, 511);
// kick.advanceOscillator();
// Render the next hihat sample and advance the oscillator
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
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);
// If there is a value bigger than 1 on the V/Oct Input, trigger the drum
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 there is a gate
if (gate_high == 1) {
// Trigger only on first rising flank
if (old_gate_high == 0) {
// (Re-)Trigger the Kick
// (Re-)Trigger the Instruments
if (mode_switch.mode == 0){
kick.trigger();
} else if (mode_switch.mode == 1){
snare.trigger();
} else if (mode_switch.mode == 2){
// kick.trigger();
hihat.trigger();
}
}
}
......
......@@ -88,3 +88,9 @@ void HPF::reset() {
this->buf0 = 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 {
float frequency;
float base_frequency;
float frequency_range;
float saturation = 2;
float gain = 1.0;
EnvelopeSimpleLinear volume_envelope;
EnvelopeSimpleLog pitch_envelope;
EnvelopeSigh pitch_envelope_sigh;
......@@ -23,6 +25,7 @@ class Kick {
void setPitchDecay(float speed);
void setPitchAmount(float amount);
void setFrequency(float frequency);
void setSaturation(float saturation);
private:
int wavetable[SAMPLES];
......@@ -30,16 +33,16 @@ class Kick {
};
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++) {
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;
lpf.setFrequency(1000.0);
lpf.setResonance(0.99);
lpf.setResonance(0.4);
hpf.setFrequency(30.0);
hpf.setResonance(0.5);
hpf.setResonance(0.4);
}
void Kick::update() {
......@@ -63,7 +66,7 @@ void Kick::trigger() {
float Kick::render() {
float orig_sample = this->volume_envelope.value * this->wavetable[(int)this->osc_progress];
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;
}
......@@ -75,10 +78,12 @@ void Kick::advanceOscillator() {
}
void Kick::setVolumeDecay(float speed) {
speed = 0.000005 + speed / 500.0;
this->volume_envelope.setSpeed(speed);
}
void Kick::setPitchDecay(float speed) {
speed = 0.00001 + speed / 800.0;
this->pitch_envelope.setSpeed(speed);
}
......@@ -89,3 +94,7 @@ void Kick::setPitchAmount(float amount) {
void Kick::setFrequency(float frequency) {
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 {
float base_frequency;
float frequency_range;
EnvelopeSimpleLog volume_envelope;
EnvelopeSimpleLog volume_envelope2;
EnvelopeSimpleLog pitch_envelope;
EnvelopeSigh pitch_envelope_sigh;
LPF lpf;
HPF hpf;
float gain = 0.3;
void setup();
void update();
void reset();
......@@ -30,6 +32,7 @@ class Snare {
int sinetable[SAMPLES];
int noisetable[SAMPLES];
float osc_progress = 0.0;
float osc_progress2 = 0.0;
};
void Snare::setup() {
......@@ -47,7 +50,9 @@ void Snare::setup() {
this->volume_envelope.amount = 1.0;
this->hpf.setFrequency(200.0);
this->volume_envelope.setSnap(0.0005);
this->volume_envelope2.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() {
}
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]);
// lpf.addFrequency(pitch_envelope.value*500.0);
float orig_sample = this->volume_envelope.value * (this->sinetable[(int)this->osc_progress]
+ this->pitch_envelope.value * noisetable[(int)this->osc_progress]);
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;
}
......@@ -82,17 +87,30 @@ void Snare::advanceOscillator() {
if (this->osc_progress > SAMPLES) {
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) {
// 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_envelope2.setSpeed(speed*2);
}
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);
}
void Snare::setPitchAmount(float amount) {
amount = 2.0 + amount * 8.5;
this->pitch_envelope.setAmount(amount);
}
......@@ -101,7 +119,10 @@ void Snare::setFrequency(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->gain = map(frequency, 150, 5115, 1.0, 0.05);
}
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