From 0daca6f46bbce663268d0107277edd2013fcde53 Mon Sep 17 00:00:00 2001 From: Tom-on64 Date: Fri, 24 Apr 2026 19:09:27 +0200 Subject: [PATCH] SYNTH!!!111!!!1!!1!1!1!!1!1 --- CMakeLists.txt | 2 +- main.c | 3 +- synth.cc | 118 +++++++++++++++++++++++++++++++++++++++++++++++++ synth.h | 8 ++++ vco.c | 15 ------- vco.h | 2 - 6 files changed, 129 insertions(+), 19 deletions(-) delete mode 100644 vco.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 5223c92..77019d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ pico_sdk_init() file(GLOB_RECURSE DAISYSP_SOURCES "${CMAKE_CURRENT_LIST_DIR}/daisysp/**/*.cpp") -add_executable(sint-gauntlet ${DAISYSP_SOURCES} main.c buttons.c mux.c pwm.c vco.c) +add_executable(sint-gauntlet ${DAISYSP_SOURCES} main.c buttons.c mux.c pwm.c synth.cc) pico_set_program_name(sint-gauntlet "sint-gauntlet") pico_set_program_version(sint-gauntlet "0.1") diff --git a/main.c b/main.c index e9224b0..1324cf7 100644 --- a/main.c +++ b/main.c @@ -8,15 +8,16 @@ #include "hardware/gpio.h" #include "hardware/pwm.h" #include "hardware/adc.h" -#include "mux.h" #include "pico/multicore.h" #include "pico/stdlib.h" #include "buttons.h" +#include "synth.h" #include "const.h" #include "macro.h" #include "state.h" #include "pwm.h" +#include "mux.h" state_t state; diff --git a/synth.cc b/synth.cc index a1e0e3a..a60c5cc 100644 --- a/synth.cc +++ b/synth.cc @@ -1,6 +1,124 @@ +#include +#include +#include "state.h" +#include "const.h" +#include "daisysp.h" +#include "vco.h" +#include "dsp.h" + #include "synth.h" +using namespace daisysp; + +Oscillator osc; +Svf filter; +AdEnv vco_env; +AdEnv filter_env; + +// TODO: Reverb + +float clock_phase = 0.0f; +bool clock_trig = false; + +static inline auto vco_mode_to_daisy(vco_mode_t mode) { + switch (mode) { + case VCO_SQUARE: return daisysp::Oscillator::WAVE_SQUARE; + case VCO_TRIANGLE: return daisysp::Oscillator::WAVE_TRI; + case VCO_SAW: return daisysp::Oscillator::WAVE_SAW; + case VCO_SINE: + default: return daisysp::Oscillator::WAVE_SIN; + } +} + +static inline float pot_to_freq(float v, float min, float max) { return min * powf(max / min, v); } + +static inline float pot_to_time(float v, float min, float max) { return min * powf(max / min, v); } + +static inline float quantize(float freq, float temp) { + float midi = temp * log2f(freq / 440.0f) + 69.0f; + float note = roundf(midi); + return 440.0f * powf(2.0f, (midi - 69.0f) / temp); +} + +static inline float low_pass(float in, float* z, float coeff) { + *z += coeff * (in - *z); + return *z; +} + +void synth_init(void) { + osc.Init(SAMPLE_RATE); + osc.SetWaveform(vco_mode_to_daisy(VCO_SINE)); + osc.SetFreq(440.0f); + osc.SetAmp(1.0f); + + filter.Init(SAMPLE_RATE); + filter.SetFreq(2000.0f); + filter.SetRes(0.0f); + + vco_env.Init(SAMPLE_RATE); + vco_env.SetTime(ADENV_SEG_ATTACK, 0.01f); + vco_env.SetTime(ADENV_SEG_DECAY, 0.5f); + vco_env.SetMin(0.0f); + vco_env.SetMax(1.0f); + + filter_env.Init(SAMPLE_RATE); + filter_env.SetTime(ADENV_SEG_ATTACK, 0.01f); + filter_env.SetTime(ADENV_SEG_DECAY, 0.5f); + filter_env.SetMin(0.0f); + filter_env.SetMax(1.0f); + + clock_phase = 0.0f; + clock_trig = false; +} + float get_sample(void) { + float bps = state.clock_bpm / 60.0f; + float clock_inc = bps / SAMPLE_RATE; + clock_phase += clock_inc; + clock_trig = false; + if (clock_phase >= 1.0f) { + clock_phase -= 1.0f; + clock_trig = true; + } + + if (clock_trig) { + vco_env.Trigger(); + filter_env.Trigger(); + } + + vco_env.SetTime(ADENV_SEG_ATTACK, pot_to_time(state.env1_attack, ENV_ATTACK_MIN, ENV_ATTACK_MAX)); + vco_env.SetTime(ADENV_SEG_DECAY, pot_to_time(state.env1_release, ENV_RELEASE_MIN, ENV_RELEASE_MAX)); + filter_env.SetTime(ADENV_SEG_ATTACK, pot_to_time(state.env2_attack, ENV_ATTACK_MIN, ENV_ATTACK_MAX)); + filter_env.SetTime(ADENV_SEG_DECAY, pot_to_time(state.env2_release, ENV_RELEASE_MIN, ENV_RELEASE_MAX)); + + float vco_env_out = vco_env.Process(); + float filter_env_out = filter_env.Process(); + + float vco_freq = pot_to_freq(state.vco_freq, VCO_FREQ_MIN, VCO_FREQ_MAX); + if (state.quant_enabled) vco_freq = quantize(vco_freq, 12.0f); + + osc.SetFreq(vco_freq); + osc.SetWaveform(vco_mode_to_daisy(state.vco_mode)); + osc.SetAmp(1.0f); + + float vco_out = osc.Process(); + + float base_cutoff = pot_to_freq(state.filter_freq, FILTER_FREQ_MIN, FILTER_FREQ_MAX); + float mod_cutoff = base_cutoff + filter_env_out * (FILTER_FREQ_MAX - FILTER_FREQ_MIN); + mod_cutoff = fclamp(mod_cutoff, FILTER_FREQ_MIN, FILTER_FREQ_MAX); + + filter.SetFreq(mod_cutoff); + filter.SetRes(state.filter_resonance); + filter.Process(vco_out); + float filtered = filter.Low(); + + float vca_out = filtered * vco_env_out * state.vco_volume; + + float mix = vca_out; + mix = fclamp(mix, -1.0f, 1.0f); + + return mix; + return 0; } diff --git a/synth.h b/synth.h index 1de8ca5..e3f2fa0 100644 --- a/synth.h +++ b/synth.h @@ -1,4 +1,12 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + float get_sample(void); +#ifdef __cplusplus +} +#endif + diff --git a/vco.c b/vco.c deleted file mode 100644 index 17ccf0f..0000000 --- a/vco.c +++ /dev/null @@ -1,15 +0,0 @@ -#include "const.h" -#include "state.h" - -#include "vco.h" - -float phase = 0.0f; -float vco(void) { - float phase_inc = (state.vco_freq * 1760) / SAMPLE_RATE; - phase += phase_inc; - - if (phase >= 1.0f) phase -= 1.0f; - - return (phase * 2.0f) - 1.0f; -} - diff --git a/vco.h b/vco.h index 1670bcc..b168623 100644 --- a/vco.h +++ b/vco.h @@ -7,5 +7,3 @@ typedef enum { VCO_SAW = 3, } vco_mode_t; -float vco(void); -