This repository has been archived on 2026-05-26. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
daisy-fm-synth/daisy.ino
T
2024-09-24 17:37:50 +02:00

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);
}
}