added waveform selectors

This commit is contained in:
2025-12-27 14:30:49 -06:00
parent 6b52f8fa4f
commit 814002f0d9
9 changed files with 354 additions and 79 deletions

View File

@@ -7,6 +7,7 @@ Envelope::Envelope() {
void Envelope::noteOn() {
state_ = State::Attack;
// there's interntionally no envelope value_ reset here because slurs
}
void Envelope::noteOff() {
@@ -26,7 +27,7 @@ float Envelope::process() {
state_ = State::Decay;
}
break;
case State::Decay: // TODO: if noteOff occurs during decay, release doesn't trigger until decay finishes
case State::Decay:
value_ -= (1.0f - sustain_) / (decay_ * sampleRate_);
if(value_ <= sustain_) {
value_ = sustain_;

View File

@@ -4,6 +4,8 @@
#include <vector>
#include <atomic>
// the scope buffer is used by the ui to visualize the audio waveform
// the ui thread shouldn't read directly from memory being read from/written to so it copies the data into this class
class ScopeBuffer {
public:
@@ -22,6 +24,7 @@ public:
// NOTE: there are limits to the wavelengths that the scope can show cleanly due to the size of the audio buffer
// at a buffer size of 256 at 44100hz the min visible steady frequency is ~172hz
// the min visible steady frequency can be lowered by increasing buffer size (increases latency) or decreasing sample rate (decreases audio fidelity)
private:
std::vector<float> buffer_;

View File

@@ -94,8 +94,25 @@ void Synth::process(float* out, uint32_t nFrames, uint32_t sampleRate) {
// TODO: wavetables should be scaled by their RMS for equal loudness (prelim standard = 0.707)
float sineSample = std::sin(phase_);
float squareSample = (phase_ >= M_PI) ? 0.707f : -0.707f;
float sawSample = ((phase_ / M_PI) - 1.0f) / 0.577f * 0.707f;
sampleOut = squareSample * gain;
float sawSample = ((phase_ / M_PI) - 1.0f) / 0.577f * 0.707f;
// switch statement will be replaced with an array index for our array of wavetables
switch (static_cast<int32_t>(std::round(getParam(ParamId::Osc1WaveSelector1)))) {
case 0:
sampleOut = sineSample * gain;
break;
case 1:
sampleOut = squareSample * gain;
break;
case 2:
sampleOut = sawSample * gain;
break;
case 3:
// TODO: no triable wave yet :(
sampleOut = sineSample * gain;
break;
default: // unreachable
break;
}
// write to buffer
out[2*i] = sampleOut; // left
@@ -113,6 +130,7 @@ void Synth::process(float* out, uint32_t nFrames, uint32_t sampleRate) {
if(!triggered) {
scope_->setTrigger(i); // this is where we consider the start of a waveform
triggered = true;
// TODO: investigate triggering accross buffers when a single wave period transcends a single audio buffer
}
}
}