From ce5c9e76a303c12b731fdcd2f5a07f5925ae6ee2 Mon Sep 17 00:00:00 2001 From: Blitblank Date: Thu, 25 Dec 2025 22:25:37 -0600 Subject: [PATCH] full adsr --- src/ParameterStore.h | 8 ++-- src/synth/Envelope.h | 2 +- src/synth/Synth.cpp | 7 +--- src/ui/MainWindow.cpp | 36 +++++++++++------ src/ui/MainWindow.h | 8 +--- src/ui/MainWindow.ui | 92 +++++++++++++++++++++++-------------------- 6 files changed, 81 insertions(+), 72 deletions(-) diff --git a/src/ParameterStore.h b/src/ParameterStore.h index 48aa4a7..292fe8f 100644 --- a/src/ParameterStore.h +++ b/src/ParameterStore.h @@ -36,10 +36,10 @@ struct ParamDef { constexpr std::array(ParamId::Count)> PARAM_DEFS {{ { 100.0f, 20.0f, 600.0f}, // Osc1Freq { 0.8f, 0.0f, 1.0f}, // Osc1Gain - { 10.0f, 0.0f, 1000.0f}, // Osc1VolumeEnvA, - { 10.0f, 0.0f, 1000.0f}, // Osc1VolumeEnvD, - { 10.0f, 0.0f, 1000.0f}, // Osc1VolumeEnvS, - { 0.2f, 0.0f, 2.0f}, // Osc1VolumeEnvR, + { 0.05f, 0.0f, 2.0f}, // Osc1VolumeEnvA, + { 0.2f, 0.0f, 2.0f}, // Osc1VolumeEnvD, + { 0.7f, 0.0f, 1.0f}, // Osc1VolumeEnvS, + { 0.2f, 0.0f, 2.0f}, // Osc1VolumeEnvR, { 10.0f, 0.0f, 1000.0f}, // FilterCutoffEnvA, { 10.0f, 0.0f, 1000.0f}, // FilterCutoffEnvD, { 10.0f, 0.0f, 1000.0f}, // FilterCutoffEnvS, diff --git a/src/synth/Envelope.h b/src/synth/Envelope.h index 3d9a858..0815672 100644 --- a/src/synth/Envelope.h +++ b/src/synth/Envelope.h @@ -21,7 +21,7 @@ public: // setters void setSampleRate(float sampleRate) { sampleRate_ = sampleRate; } - void set(float a, float d, float s, float r) { setAttack(a); setDecay(a); setSustain(a); setRelease(a); } + void set(float a, float d, float s, float r) { setAttack(a); setDecay(d); setSustain(s); setRelease(r); } void setAttack(float seconds) { attack_ = std::max(seconds, 0.0001f); } void setDecay(float seconds) { decay_ = std::max(seconds, 0.0001f); } void setSustain(float level) { sustain_ = level; } diff --git a/src/synth/Synth.cpp b/src/synth/Synth.cpp index 262351d..052046b 100644 --- a/src/synth/Synth.cpp +++ b/src/synth/Synth.cpp @@ -31,7 +31,6 @@ inline float Synth::noteToFrequency(uint8_t note) { return SYNTH_PITCH_STANDARD * pow(2.0f, static_cast(note - SYNTH_MIDI_HOME) / static_cast(SYNTH_NOTES_PER_OCTAVE)); } -// TODO: stop popping on note-offs void Synth::handleNoteEvent(const NoteEvent& event) { if(event.type == NoteEventType::NoteOn) { // add note to activeNotes list @@ -73,8 +72,7 @@ void Synth::process(float* out, uint32_t nFrames, uint32_t sampleRate) { for(auto& p : params_) p.update(); // TODO: profile this // process all envelopes - //gainEnvelope_.set(0.05f, 0.2f, 0.7f, getParam(ParamId::Osc1VolumeEnvR)); - gainEnvelope_.setRelease(getParam(ParamId::Osc1VolumeEnvR)); + gainEnvelope_.set(getParam(ParamId::Osc1VolumeEnvA), getParam(ParamId::Osc1VolumeEnvD), getParam(ParamId::Osc1VolumeEnvS), getParam(ParamId::Osc1VolumeEnvR)); float gain = gainEnvelope_.process(); // skip if no active notes @@ -90,8 +88,7 @@ void Synth::process(float* out, uint32_t nFrames, uint32_t sampleRate) { // TODO: wavetables // TODO: wavetables should be scaled by their RMS for equal loudness (prelim standard = 0.707) float sineSample = std::sin(phase_); - float squareSample = -0.707f; - if(phase_ >= M_PI) squareSample = 0.707f; + float squareSample = (phase_ >= M_PI) ? 0.707f : -0.707f; float sawSample = phase_ * 4.0f / M_PI * frequency_ / static_cast(sampleRate); sampleOut = sawSample * gain; diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp index ed34a43..b5e3328 100644 --- a/src/ui/MainWindow.cpp +++ b/src/ui/MainWindow.cpp @@ -15,20 +15,33 @@ MainWindow::MainWindow(QWidget *parent) : setFocusPolicy(Qt::StrongFocus); // Initialize UI - updateCounterLabel(); // Connect buttons to slots - connect(ui_->buttonIncrement, &QPushButton::clicked, this, &MainWindow::onIncrementClicked); connect(ui_->buttonReset, &QPushButton::clicked, this, &MainWindow::onResetClicked); // synth business audio_->start(); // slider business + connect(ui_->sliderGainA, &SmartSlider::valueChanged, this, [this](float v) { + audio_->parameters()->set(ParamId::Osc1VolumeEnvA, v); // bind valueChanged signal to the ParameterStore + }); + connect(ui_->sliderGainD, &SmartSlider::valueChanged, this, [this](float v) { + audio_->parameters()->set(ParamId::Osc1VolumeEnvD, v); // bind valueChanged signal to the ParameterStore + }); + connect(ui_->sliderGainS, &SmartSlider::valueChanged, this, [this](float v) { + audio_->parameters()->set(ParamId::Osc1VolumeEnvS, v); // bind valueChanged signal to the ParameterStore + }); connect(ui_->sliderGainR, &SmartSlider::valueChanged, this, [this](float v) { audio_->parameters()->set(ParamId::Osc1VolumeEnvR, v); // bind valueChanged signal to the ParameterStore }); // initialize to defaults + ui_->sliderGainA->setRange(PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvA)].min, PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvA)].max); + ui_->sliderGainA->setValue(PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvA)].def); + ui_->sliderGainD->setRange(PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvD)].min, PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvD)].max); + ui_->sliderGainD->setValue(PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvD)].def); + ui_->sliderGainS->setRange(PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvS)].min, PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvS)].max); + ui_->sliderGainS->setValue(PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvS)].def); ui_->sliderGainR->setRange(PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvR)].min, PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvR)].max); ui_->sliderGainR->setValue(PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvR)].def); // TODO: package a smartSlider into an envelope controller widget @@ -47,16 +60,15 @@ void MainWindow::keyReleaseEvent(QKeyEvent* event) { keyboard_.handleKeyRelease(event); } -void MainWindow::onIncrementClicked() { - counter_++; - updateCounterLabel(); -} - void MainWindow::onResetClicked() { - counter_ = 0; - updateCounterLabel(); -} -void MainWindow::updateCounterLabel() { - ui_->labelCounter->setText(QString::number(counter_)); + // initialize to defaults + ui_->sliderGainA->setRange(PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvA)].min, PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvA)].max); + ui_->sliderGainA->setValue(PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvA)].def); + ui_->sliderGainD->setRange(PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvD)].min, PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvD)].max); + ui_->sliderGainD->setValue(PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvD)].def); + ui_->sliderGainS->setRange(PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvS)].min, PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvS)].max); + ui_->sliderGainS->setValue(PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvS)].def); + ui_->sliderGainR->setRange(PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvR)].min, PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvR)].max); + ui_->sliderGainR->setValue(PARAM_DEFS[static_cast(ParamId::Osc1VolumeEnvR)].def); } diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h index f8066e7..c90629c 100644 --- a/src/ui/MainWindow.h +++ b/src/ui/MainWindow.h @@ -11,7 +11,7 @@ namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { - + Q_OBJECT public: @@ -23,16 +23,10 @@ protected: void keyReleaseEvent(QKeyEvent* event) override; private slots: - void onIncrementClicked(); void onResetClicked(); private: Ui::MainWindow *ui_; - int counter_ = 0; - - int value = 0; - - void updateCounterLabel(); AudioEngine* audio_ = nullptr; KeyboardController keyboard_; diff --git a/src/ui/MainWindow.ui b/src/ui/MainWindow.ui index 7c22374..7da2b67 100644 --- a/src/ui/MainWindow.ui +++ b/src/ui/MainWindow.ui @@ -13,30 +13,15 @@ MainWindow + + true + - - - - 50 - 70 - 101 - 31 - - - - - 15 - - - - Increment - - - 50 - 100 + 10 + 10 101 31 @@ -50,36 +35,57 @@ Reset - - - - 30 - 20 - 151 - 41 - - - - - 30 - - - - Counter - - - Qt::AlignmentFlag::AlignCenter - - - 340 - 120 + 580 + 180 171 321 + + true + + + + + + 40 + 180 + 171 + 321 + + + + true + + + + + + 220 + 180 + 171 + 321 + + + + true + + + + + + 400 + 180 + 171 + 321 + + + + true +