Archived
336 lines
8.5 KiB
Arduino
336 lines
8.5 KiB
Arduino
#include "DaisyDuino.h"
|
|||
|
|
#include "math.h"
|
||
|
|
|
||
|
|
#define PIN_A4 11
|
||
|
|
#define PIN_AS4 14
|
||
|
|
#define PIN_B4 10
|
||
|
|
#define PIN_C5 9
|
||
|
|
#define PIN_CS5 13
|
||
|
|
#define PIN_D5 8
|
||
|
|
#define PIN_DS5 12
|
||
|
|
#define PIN_E5 7
|
||
|
|
#define PIN_F5 3
|
||
|
|
#define PIN_FS5 6
|
||
|
|
#define PIN_G5 2
|
||
|
|
#define PIN_GS5 5
|
||
|
|
#define PIN_A5 1
|
||
|
|
#define PIN_AS5 4
|
||
|
|
#define PIN_B5 0
|
||
|
|
|
||
|
|
#define PIN_MUX_ADSR_A 16
|
||
|
|
#define PIN_MUX_ADSR_B 17
|
||
|
|
#define PIN_MUX_ADSR_C 18
|
||
|
|
#define PIN_MUX_ADSR_ADC A8
|
||
|
|
|
||
|
|
#define PIN_MUX_ADSR_VOL_ATTACK 3
|
||
|
|
#define PIN_MUX_ADSR_VOL_DECAY 0
|
||
|
|
#define PIN_MUX_ADSR_VOL_SUSTAIN 1
|
||
|
|
#define PIN_MUX_ADSR_VOL_RELEASE 2
|
||
|
|
#define PIN_MUX_ADSR_FLT_ATTACK 5
|
||
|
|
#define PIN_MUX_ADSR_FLT_DECAY 7
|
||
|
|
#define PIN_MUX_ADSR_FLT_SUSTAIN 6
|
||
|
|
#define PIN_MUX_ADSR_FLT_RELEASE 4
|
||
|
|
|
||
|
|
#define PIN_MUX_FM_A 20
|
||
|
|
#define PIN_MUX_FM_B 21
|
||
|
|
#define PIN_MUX_FM_C 22
|
||
|
|
#define PIN_MUX_FM_ADC A4
|
||
|
|
|
||
|
|
#define PIN_MUX_FM_CAR_SIN 7
|
||
|
|
#define PIN_MUX_FM_CAR_SQ 5
|
||
|
|
#define PIN_MUX_FM_CAR_SAW 0
|
||
|
|
#define PIN_MUX_FM_MOD_SIN 3
|
||
|
|
#define PIN_MUX_FM_MOD_SQ 1
|
||
|
|
#define PIN_MUX_FM_MOD_SAW 2
|
||
|
|
#define PIN_MUX_FM_WET 4
|
||
|
|
#define PIN_MUX_FM_DEV 6
|
||
|
|
|
||
|
|
#define PIN_VOL A9
|
||
|
|
#define PIN_PITCH A11
|
||
|
|
|
||
|
|
#define PIN_FLT_Q A0
|
||
|
|
#define PIN_FLT_SWITCH D25
|
||
|
|
|
||
|
|
#define ANALOG_MAX 1023.0
|
||
|
|
#define FM_FREQ_MAX 120.0
|
||
|
|
|
||
|
|
DaisyHardware hw;
|
||
|
|
|
||
|
|
size_t num_channels;
|
||
|
|
size_t sample_rate = 44000;
|
||
|
|
|
||
|
|
Adsr volEnv;
|
||
|
|
Oscillator osc;
|
||
|
|
|
||
|
|
float vol = 0.0;
|
||
|
|
|
||
|
|
size_t key_count = 15;
|
||
|
|
int keys_pins[] = {PIN_A4, PIN_AS4, PIN_B4, PIN_C5, PIN_CS5, PIN_D5, PIN_DS5, PIN_E5, PIN_F5, PIN_FS5, PIN_G5, PIN_GS5, PIN_A5, PIN_AS5, PIN_B5};
|
||
|
|
float keys_pitches[] = {440.0, 466.1638, 493.8833, 523.2511, 554.3653, 587.3295, 622.254, 659.2551, 698.4565, 739.9888, 783.9909, 830.6094, 880.0, 932.3275, 987.7666};
|
||
|
|
bool keys_pressed[] = {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false};
|
||
|
|
Adsr keys_adsr_vol[15];
|
||
|
|
Adsr keys_adsr_flt[15];
|
||
|
|
Oscillator keys_osc[15];
|
||
|
|
Oscillator keys_osc_mod[15];
|
||
|
|
Svf filters[15];
|
||
|
|
Flanger flanger;
|
||
|
|
SampleRateReducer smp;
|
||
|
|
Overdrive dist;
|
||
|
|
|
||
|
|
bool use_high_pass;
|
||
|
|
|
||
|
|
float vol_adsr_attack;
|
||
|
|
float vol_adsr_decay;
|
||
|
|
float vol_adsr_sustain;
|
||
|
|
float vol_adsr_release;
|
||
|
|
|
||
|
|
float mod_wet;
|
||
|
|
float mod_dev;
|
||
|
|
float dist_val;
|
||
|
|
|
||
|
|
float pitch_dev;
|
||
|
|
float key_pitch;
|
||
|
|
|
||
|
|
Limiter limiter;
|
||
|
|
|
||
|
|
float adsr_max_seconds = 8.0;
|
||
|
|
|
||
|
|
void Callback(float **in, float **out, size_t size) {
|
||
|
|
for (size_t i = 0; i < size; i += 1) {
|
||
|
|
float osc_out = 0.0;
|
||
|
|
float osc_result = 0.0;
|
||
|
|
float env_result = 0.0;
|
||
|
|
float flt_result = 0.0;
|
||
|
|
for (int k = 0; k < key_count; k += 1) {
|
||
|
|
// filters[k].SetFreq(1000);
|
||
|
|
|
||
|
|
env_result = keys_adsr_vol[k].Process(keys_pressed[k]);
|
||
|
|
if (env_result == 0.0) {
|
||
|
|
// skip processing the oscillator if it wouldn't play a sound anyway to save on processing power
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
keys_osc[k].SetAmp(env_result);
|
||
|
|
// osc_result = dist.Process(smp.Process(keys_osc[k].Process()));
|
||
|
|
osc_result = keys_osc[k].Process();
|
||
|
|
// filters[k].Process(osc_result);
|
||
|
|
|
||
|
|
if (mod_wet > 0.04) {
|
||
|
|
osc_result = (osc_result * (1 - mod_wet)) + ((osc_result * keys_osc_mod[k].Process()) * mod_wet);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (use_high_pass) {
|
||
|
|
osc_result = flanger.Process(osc_result);
|
||
|
|
}
|
||
|
|
|
||
|
|
osc_result = smp.Process(osc_result);
|
||
|
|
|
||
|
|
osc_result = ((osc_result * (dist_val - 1)) * -1) + dist.Process(osc_result);
|
||
|
|
|
||
|
|
osc_out += osc_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
osc_out *= vol;
|
||
|
|
|
||
|
|
limiter.ProcessBlock(&osc_out, 1, 1.0);
|
||
|
|
for (size_t chn = 0; chn < num_channels; chn++) {
|
||
|
|
out[chn][i] = osc_out;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void setup() {
|
||
|
|
hw = DAISY.init(DAISY_SEED, AUDIO_SR_48K);
|
||
|
|
num_channels = hw.num_channels;
|
||
|
|
sample_rate = DAISY.get_samplerate();
|
||
|
|
|
||
|
|
float sample_rate = DAISY.get_samplerate();
|
||
|
|
Serial.begin(9600);
|
||
|
|
analogReadResolution(10);
|
||
|
|
|
||
|
|
limiter.Init();
|
||
|
|
|
||
|
|
pinMode(PIN_MUX_ADSR_A, OUTPUT);
|
||
|
|
pinMode(PIN_MUX_ADSR_B, OUTPUT);
|
||
|
|
pinMode(PIN_MUX_ADSR_C, OUTPUT);
|
||
|
|
pinMode(PIN_MUX_FM_A, OUTPUT);
|
||
|
|
pinMode(PIN_MUX_FM_B, OUTPUT);
|
||
|
|
pinMode(PIN_MUX_FM_C, OUTPUT);
|
||
|
|
|
||
|
|
pinMode(PIN_FLT_SWITCH, INPUT_PULLUP);
|
||
|
|
|
||
|
|
for (int k = 0; k < key_count; k += 1) {
|
||
|
|
pinMode(keys_pins[k], INPUT_PULLUP);
|
||
|
|
keys_osc[k].Init(sample_rate);
|
||
|
|
keys_osc[k].SetWaveform(Oscillator::WAVE_SIN);
|
||
|
|
// keys_osc[k].SetFreq(keys_pitches[k]);
|
||
|
|
keys_osc[k].SetAmp(0.25);
|
||
|
|
|
||
|
|
keys_osc_mod[k].Init(sample_rate);
|
||
|
|
keys_osc_mod[k].SetWaveform(Oscillator::WAVE_SIN);
|
||
|
|
// keys_osc_mod[k].SetFreq(keys_pitches[k]);
|
||
|
|
keys_osc_mod[k].SetAmp(0.25);
|
||
|
|
|
||
|
|
keys_adsr_vol[k].Init(sample_rate);
|
||
|
|
keys_adsr_flt[k].Init(sample_rate);
|
||
|
|
|
||
|
|
filters[k].Init(sample_rate);
|
||
|
|
// filters[k].SetFilterMode(FilterMode::LOW_PASS);
|
||
|
|
}
|
||
|
|
|
||
|
|
flanger.Init(sample_rate);
|
||
|
|
smp.Init();
|
||
|
|
dist.Init();
|
||
|
|
|
||
|
|
DAISY.begin(Callback);
|
||
|
|
}
|
||
|
|
|
||
|
|
void loop() {
|
||
|
|
|
||
|
|
vol_adsr_attack = (get_mux_adsr_value(PIN_MUX_ADSR_VOL_ATTACK) / ANALOG_MAX) * adsr_max_seconds;
|
||
|
|
vol_adsr_decay = (get_mux_adsr_value(PIN_MUX_ADSR_VOL_DECAY) / ANALOG_MAX) * adsr_max_seconds;
|
||
|
|
vol_adsr_sustain = get_mux_adsr_value(PIN_MUX_ADSR_VOL_SUSTAIN) / ANALOG_MAX;
|
||
|
|
vol_adsr_release = (get_mux_adsr_value(PIN_MUX_ADSR_VOL_RELEASE) / ANALOG_MAX) * adsr_max_seconds;
|
||
|
|
|
||
|
|
// Modulator deviation
|
||
|
|
mod_dev = FM_FREQ_MAX * (((get_mux_fm_value(PIN_MUX_FM_DEV) / ANALOG_MAX) * 2.0) - 1.0);
|
||
|
|
|
||
|
|
// Pitch control
|
||
|
|
pitch_dev = (((analogRead(PIN_PITCH) / ANALOG_MAX) * 24.0) - 12.0);
|
||
|
|
if (pitch_dev < 0.15 && pitch_dev > -0.15) {
|
||
|
|
pitch_dev = 0.0;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int k = 0; k < key_count; k += 1) {
|
||
|
|
key_pitch = pow(pow(2.0, 1.0/12.0), (49.0 + k + pitch_dev) - (49.0)) * 440.0;
|
||
|
|
|
||
|
|
// Played keys
|
||
|
|
keys_pressed[k] = digitalRead(keys_pins[k]) == 0;
|
||
|
|
|
||
|
|
keys_osc[k].SetFreq(key_pitch);
|
||
|
|
keys_osc_mod[k].SetFreq(key_pitch);
|
||
|
|
|
||
|
|
// Volume ADSR
|
||
|
|
keys_adsr_vol[k].SetTime(ADSR_SEG_ATTACK, vol_adsr_attack);
|
||
|
|
keys_adsr_vol[k].SetTime(ADSR_SEG_DECAY, vol_adsr_decay);
|
||
|
|
keys_adsr_vol[k].SetSustainLevel(vol_adsr_sustain);
|
||
|
|
keys_adsr_vol[k].SetTime(ADSR_SEG_RELEASE, vol_adsr_release);
|
||
|
|
|
||
|
|
keys_osc_mod[k].SetFreq(keys_pitches[k] + mod_dev);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Volume control
|
||
|
|
vol = analogRead(PIN_VOL) / ANALOG_MAX;
|
||
|
|
|
||
|
|
// Flanger
|
||
|
|
flanger.SetLfoFreq(get_mux_adsr_value(PIN_MUX_ADSR_FLT_ATTACK) / ANALOG_MAX);
|
||
|
|
flanger.SetLfoDepth(get_mux_adsr_value(PIN_MUX_ADSR_FLT_DECAY) / ANALOG_MAX);
|
||
|
|
flanger.SetDelay((analogRead(PIN_FLT_Q) / ANALOG_MAX) * 4.0);
|
||
|
|
|
||
|
|
// Distortion
|
||
|
|
dist_val = get_mux_adsr_value(PIN_MUX_ADSR_FLT_SUSTAIN) / ANALOG_MAX;
|
||
|
|
dist.SetDrive(dist_val);
|
||
|
|
|
||
|
|
// Sample Rate Reducer
|
||
|
|
smp.SetFreq(pow(get_mux_adsr_value(PIN_MUX_ADSR_FLT_RELEASE) / ANALOG_MAX, 2.0));
|
||
|
|
|
||
|
|
// Carrier waveform
|
||
|
|
if (get_mux_fm_button(PIN_MUX_FM_CAR_SIN) == 0) {
|
||
|
|
set_car_osc(Oscillator::WAVE_SIN);
|
||
|
|
}
|
||
|
|
if (get_mux_fm_button(PIN_MUX_FM_CAR_SQ) == 0) {
|
||
|
|
set_car_osc(Oscillator::WAVE_POLYBLEP_SQUARE);
|
||
|
|
}
|
||
|
|
if (get_mux_fm_button(PIN_MUX_FM_CAR_SAW) == 0) {
|
||
|
|
set_car_osc(Oscillator::WAVE_POLYBLEP_SAW);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Modulator waveform
|
||
|
|
if (get_mux_fm_button(PIN_MUX_FM_MOD_SIN) == 0) {
|
||
|
|
set_mod_osc(Oscillator::WAVE_SIN);
|
||
|
|
}
|
||
|
|
if (get_mux_fm_button(PIN_MUX_FM_MOD_SQ) == 0) {
|
||
|
|
set_mod_osc(Oscillator::WAVE_POLYBLEP_SQUARE);
|
||
|
|
}
|
||
|
|
if (get_mux_fm_button(PIN_MUX_FM_MOD_SAW) == 0) {
|
||
|
|
set_mod_osc(Oscillator::WAVE_POLYBLEP_SAW);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Modulator wet
|
||
|
|
mod_wet = get_mux_fm_value(PIN_MUX_FM_WET) / ANALOG_MAX;
|
||
|
|
|
||
|
|
// Flanger on/off toggle
|
||
|
|
use_high_pass = digitalRead(PIN_FLT_SWITCH) == LOW;
|
||
|
|
|
||
|
|
// Refresh 20 times per second
|
||
|
|
delay(50);
|
||
|
|
}
|
||
|
|
|
||
|
|
float get_mux_adsr_value(int pin) {
|
||
|
|
int a = LOW;
|
||
|
|
int b = LOW;
|
||
|
|
int c = LOW;
|
||
|
|
if (pin % 2 != 0) {
|
||
|
|
a = HIGH;
|
||
|
|
}
|
||
|
|
if (pin == 2 || pin == 3 || pin > 5) {
|
||
|
|
b = HIGH;
|
||
|
|
}
|
||
|
|
if (pin > 3) {
|
||
|
|
c = HIGH;
|
||
|
|
}
|
||
|
|
digitalWrite(PIN_MUX_ADSR_A, a);
|
||
|
|
digitalWrite(PIN_MUX_ADSR_B, b);
|
||
|
|
digitalWrite(PIN_MUX_ADSR_C, c);
|
||
|
|
return analogRead(PIN_MUX_ADSR_ADC);
|
||
|
|
}
|
||
|
|
|
||
|
|
float get_mux_fm_value(int pin) {
|
||
|
|
int a = LOW;
|
||
|
|
int b = LOW;
|
||
|
|
int c = LOW;
|
||
|
|
if (pin % 2 != 0) {
|
||
|
|
a = HIGH;
|
||
|
|
}
|
||
|
|
if (pin == 2 || pin == 3 || pin > 5) {
|
||
|
|
b = HIGH;
|
||
|
|
}
|
||
|
|
if (pin > 3) {
|
||
|
|
c = HIGH;
|
||
|
|
}
|
||
|
|
digitalWrite(PIN_MUX_FM_A, a);
|
||
|
|
digitalWrite(PIN_MUX_FM_B, b);
|
||
|
|
digitalWrite(PIN_MUX_FM_C, c);
|
||
|
|
return analogRead(PIN_MUX_FM_ADC);
|
||
|
|
}
|
||
|
|
|
||
|
|
int get_mux_fm_button(int pin) {
|
||
|
|
int a = LOW;
|
||
|
|
int b = LOW;
|
||
|
|
int c = LOW;
|
||
|
|
if (pin % 2 != 0) {
|
||
|
|
a = HIGH;
|
||
|
|
}
|
||
|
|
if (pin == 2 || pin == 3 || pin > 5) {
|
||
|
|
b = HIGH;
|
||
|
|
}
|
||
|
|
if (pin > 3) {
|
||
|
|
c = HIGH;
|
||
|
|
}
|
||
|
|
digitalWrite(PIN_MUX_FM_A, a);
|
||
|
|
digitalWrite(PIN_MUX_FM_B, b);
|
||
|
|
digitalWrite(PIN_MUX_FM_C, c);
|
||
|
|
return analogRead(PIN_MUX_FM_ADC) < 0.1 ? 0 : 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
void set_car_osc(uint8_t waveform) {
|
||
|
|
for (int k = 0; k < key_count; k += 1) {
|
||
|
|
keys_osc[k].SetWaveform(waveform);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void set_mod_osc(uint8_t waveform) {
|
||
|
|
for (int k = 0; k < key_count; k += 1) {
|
||
|
|
keys_osc_mod[k].SetWaveform(waveform);
|
||
|
|
}
|
||
|
|
}
|