From 774980200c2d3c94aa7f451c07fd1d6ec914f7ae Mon Sep 17 00:00:00 2001 From: Tom-on64 Date: Sat, 25 Apr 2026 09:07:02 +0200 Subject: [PATCH] Finished hopefully --- buttons.c | 27 ++++++++++----------- buttons.h | 2 -- const.h | 2 ++ main.c | 2 +- synth.cc | 71 ++++++++++++++++++++++++++++++++++++++----------------- synth.h | 7 ++++++ 6 files changed, 72 insertions(+), 39 deletions(-) diff --git a/buttons.c b/buttons.c index 8710d2c..c048392 100644 --- a/buttons.c +++ b/buttons.c @@ -4,22 +4,21 @@ #include #include "hardware/gpio.h" -void handle_vco_change(void) { - static bool btn_prev = false; +void check_button_change(uint pin, bool* btn_state) { + static bool btn_prev[32] = { false }; + bool btn_now = gpio_get(pin); + if (btn_now && !btn_prev[pin]) *btn_state = !*btn_state; + btn_prev[pin] = btn_now; +} - bool btn_now = gpio_get(VCO_BUTTON); - if (btn_now && !btn_prev) { +void update_buttons() { + check_button_change(QUANT_BUTTON, &state.quant_enabled); + check_button_change(AMEN_BUTTON, &state.amen_enabled); + + bool vco_change; + check_button_change(VCO_BUTTON, &vco_change); + if (vco_change) { if (state.vco_mode == VCO_SAW) state.vco_mode = VCO_SINE; otherwise state.vco_mode++; } } - -void update_button(uint pin, bool *button_state) { - if(gpio_get(pin) != *button_state) *button_state = !*button_state; -} - -void update_buttons() { - update_button(QUANT_BUTTON, &state.quant_enabled); - update_button(AMEN_BUTTON, &state.amen_enabled); - handle_vco_change(); -} diff --git a/buttons.h b/buttons.h index 4de50ea..19c7da1 100644 --- a/buttons.h +++ b/buttons.h @@ -1,7 +1,5 @@ #pragma once #include -void handle_vco_change(uint gpio, uint32_t events); -void update_button(uint pin, bool *button_state); void update_buttons(); diff --git a/const.h b/const.h index d23dfa9..b833363 100644 --- a/const.h +++ b/const.h @@ -37,6 +37,8 @@ #define REVERB_AMOUNT_MIN 0.0f #define REVERB_AMOUNT_MAX 1.0f +#define AMEN_BPM 85.0f +#define AMEN_BARS 4.0f #define otherwise else diff --git a/main.c b/main.c index c9d6192..4cf5ad7 100644 --- a/main.c +++ b/main.c @@ -77,6 +77,6 @@ __attribute__((noreturn)) int main() { init_all(); multicore_launch_core1(core1_main); - while (1) {} + while (1); } diff --git a/synth.cc b/synth.cc index bffdb6c..43c170f 100644 --- a/synth.cc +++ b/synth.cc @@ -46,7 +46,7 @@ static inline float pot_to_time(float v, float min, float max) { return min * po 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); + return 440.0f * powf(2.0f, (note - 69.0f) / temp); } static inline float low_pass(float in, float* z, float coeff) { @@ -55,14 +55,14 @@ static inline float low_pass(float in, float* z, float coeff) { } float reverb(float in, float amount) { - float damp0 = 0.0f, damp1 = 0.0f, damp2 = 0.0f, damp3 = 0.0f; + static float damp0 = 0.0f, damp1 = 0.0f, damp2 = 0.0f, damp3 = 0.0f; float feedback = 0.84f; float damp = 0.3f; - float c0 = comb0.Read(); low_pass(in + c0 * feedback, &damp0, damp0); comb0.Write(damp0); - float c1 = comb1.Read(); low_pass(in + c1 * feedback, &damp1, damp1); comb1.Write(damp1); - float c2 = comb2.Read(); low_pass(in + c2 * feedback, &damp2, damp2); comb2.Write(damp2); - float c3 = comb3.Read(); low_pass(in + c3 * feedback, &damp3, damp3); comb3.Write(damp3); + float c0 = comb0.Read(); low_pass(in + c0 * feedback, &damp0, damp); comb0.Write(damp0); + float c1 = comb1.Read(); low_pass(in + c1 * feedback, &damp1, damp); comb1.Write(damp1); + float c2 = comb2.Read(); low_pass(in + c2 * feedback, &damp2, damp); comb2.Write(damp2); + float c3 = comb3.Read(); low_pass(in + c3 * feedback, &damp3, damp); comb3.Write(damp3); float wet = (c0 + c1 + c2 + c3) * 0.25f; @@ -80,11 +80,28 @@ float reverb(float in, float amount) { return in + amount * (wet - in); } +#include "amenbreak.h" + +float amenbreak(float beat_samples, float playback_rate) { + amen_length = beat_samples * 4.0f * AMEN_BARS; + + uint32_t idx0 = (uint32_t)amen_phase % amen_sample_count; + uint32_t idx1 = (idx0 + 1) % amen_sample_count; + float frac = amen_phase - floorf(amen_phase); + float s0 = amen_samples[idx0] * (1.0f / 32768.0f); + float s1 = amen_samples[idx1] * (1.0f / 32768.0f); + float amen_out = s0 + frac * (s1 - s0); + + amen_phase += playback_rate; + if (amen_phase >= amen_length) amen_phase -= amen_length; + return amen_out; +} + void synth_init(void) { osc.Init(SAMPLE_RATE); - osc.SetWaveform(vco_mode_to_daisy(VCO_SINE)); + osc.SetWaveform(vco_mode_to_daisy(VCO_SAW)); osc.SetFreq(440.0f); - osc.SetAmp(1.0f); + osc.SetAmp(2.0f); filter.Init(SAMPLE_RATE); filter.SetFreq(2000.0f); @@ -92,7 +109,7 @@ void synth_init(void) { vco_env.Init(SAMPLE_RATE); vco_env.SetTime(ADENV_SEG_ATTACK, 0.01f); - vco_env.SetTime(ADENV_SEG_DECAY, 0.5f); + vco_env.SetTime(ADENV_SEG_DECAY, 0.8f); vco_env.SetMin(0.0f); vco_env.SetMax(1.0f); @@ -106,11 +123,18 @@ void synth_init(void) { clock_phase = 0.0f; clock_trig = false; + + amen_phase = 0.0f; + state.amen_enabled = true; + state.reverb_amount = 1.0; } float get_sample(void) { - float bps = pot_to_time(state.clock_bpm, BPM_MIN, BPM_MAX) / 60.0f; - float clock_inc = bps / SAMPLE_RATE; + float bpm = BPM_MIN + state.clock_bpm * (BPM_MAX - BPM_MIN); + float beat_samples = SAMPLE_RATE * 60.0f / bpm; + float playback_rate = bpm / AMEN_BPM; + + float clock_inc = bpm / 60.0f / SAMPLE_RATE; clock_phase += clock_inc; clock_trig = false; if (clock_phase >= 1.0f) { @@ -123,10 +147,10 @@ float get_sample(void) { 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)); + 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(); @@ -134,9 +158,9 @@ float get_sample(void) { 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); + osc.SetFreq(vco_freq); + osc.SetWaveform(vco_mode_to_daisy(state.vco_mode)); + osc.SetAmp(1.0f); float vco_out = osc.Process(); @@ -144,16 +168,19 @@ float get_sample(void) { 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.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 reverb_out = reverb(vca_out, state.reverb_amount); + float reverb_out = vca_out; //reverb(vca_out, state.reverb_amount); - float mix = reverb_out; + float amen_out = 0.0f; + if (state.amen_enabled) amen_out = amenbreak(beat_samples, playback_rate); + + float mix = reverb_out + amen_out; mix = fclamp(mix, -1.0f, 1.0f); return mix; diff --git a/synth.h b/synth.h index f6f1096..94ec0c1 100644 --- a/synth.h +++ b/synth.h @@ -1,5 +1,12 @@ #pragma once +#define COMB0_SIZE 1103 +#define COMB1_SIZE 1361 +#define COMB2_SIZE 1499 +#define COMB3_SIZE 1693 +#define AP0_SIZE 131 +#define AP1_SIZE 43 + #ifdef __cplusplus extern "C" { #endif