ADSR and filters

This commit is contained in:
Dejvino
2026-02-27 22:23:59 +01:00
parent c8bdf3ee13
commit f80daed222
3 changed files with 199 additions and 27 deletions
+84 -16
View File
@@ -24,11 +24,20 @@ SynthEngine::SynthEngine(uint32_t sampleRate)
_increment(0),
_volume(0.5f),
_waveform(SAWTOOTH),
_isGateOpen(false)
_isGateOpen(false),
_envState(ENV_IDLE),
_envLevel(0.0f),
_attackInc(0.0f),
_decayDec(0.0f),
_sustainLevel(1.0f),
_releaseDec(0.0f),
_lpAlpha(1.0f), _hpAlpha(0.0f),
_lpVal(0.0f), _hpVal(0.0f)
{
fill_sine_table();
// Initialize with a default frequency
setFrequency(440.0f);
setADSR(0.05f, 0.1f, 0.7f, 0.2f); // Default envelope
}
void SynthEngine::setFrequency(float freq) {
@@ -52,6 +61,31 @@ void SynthEngine::setWaveform(Waveform form) {
void SynthEngine::setGate(bool isOpen) {
_isGateOpen = isOpen;
if (isOpen) {
_envState = ENV_ATTACK;
} else {
_envState = ENV_RELEASE;
}
}
void SynthEngine::setADSR(float attack, float decay, float sustain, float release) {
// Calculate increments per sample based on time in seconds
// Avoid division by zero
_attackInc = (attack > 0.001f) ? (1.0f / (attack * _sampleRate)) : 1.0f;
_decayDec = (decay > 0.001f) ? (1.0f / (decay * _sampleRate)) : 1.0f;
_sustainLevel = sustain;
_releaseDec = (release > 0.001f) ? (1.0f / (release * _sampleRate)) : 1.0f;
}
void SynthEngine::setFilter(float lpCutoff, float hpCutoff) {
// Simple one-pole filter coefficient calculation: alpha = 2*PI*fc/fs
_lpAlpha = 2.0f * M_PI * lpCutoff / _sampleRate;
if (_lpAlpha > 1.0f) _lpAlpha = 1.0f;
if (_lpAlpha < 0.0f) _lpAlpha = 0.0f;
_hpAlpha = 2.0f * M_PI * hpCutoff / _sampleRate;
if (_hpAlpha > 1.0f) _hpAlpha = 1.0f;
if (_hpAlpha < 0.0f) _hpAlpha = 0.0f;
}
float SynthEngine::getFrequency() const {
@@ -63,22 +97,56 @@ void SynthEngine::process(int16_t* buffer, uint32_t numFrames) {
_phase += _increment;
int16_t sample = 0;
if (_isGateOpen) {
switch (_waveform) {
case SAWTOOTH:
sample = static_cast<int16_t>(_phase >> 16);
break;
case SQUARE:
sample = (_phase < 0x80000000) ? 32767 : -32768;
break;
case SINE:
// Use top 8 bits of phase as index into sine table
sample = sine_table[(_phase >> 24) & 0xFF];
break;
}
// Oscillator Generation
switch (_waveform) {
case SAWTOOTH:
sample = static_cast<int16_t>(_phase >> 16);
break;
case SQUARE:
sample = (_phase < 0x80000000) ? 32767 : -32768;
break;
case SINE:
sample = sine_table[(_phase >> 24) & 0xFF];
break;
}
// Apply volume and write to buffer
buffer[i] = static_cast<int16_t>(sample * _volume);
float sampleF = static_cast<float>(sample);
// Apply Filters (One-pole)
// Low Pass
_lpVal += _lpAlpha * (sampleF - _lpVal);
sampleF = _lpVal;
// High Pass (implemented as Input - LowPass(hp_cutoff))
_hpVal += _hpAlpha * (sampleF - _hpVal);
sampleF = sampleF - _hpVal;
// Apply ADSR Envelope
switch (_envState) {
case ENV_ATTACK:
_envLevel += _attackInc;
if (_envLevel >= 1.0f) { _envLevel = 1.0f; _envState = ENV_DECAY; }
break;
case ENV_DECAY:
_envLevel -= _decayDec;
if (_envLevel <= _sustainLevel) { _envLevel = _sustainLevel; _envState = ENV_SUSTAIN; }
break;
case ENV_SUSTAIN:
_envLevel = _sustainLevel;
break;
case ENV_RELEASE:
_envLevel -= _releaseDec;
if (_envLevel <= 0.0f) { _envLevel = 0.0f; _envState = ENV_IDLE; }
break;
case ENV_IDLE:
_envLevel = 0.0f;
break;
}
sampleF *= _envLevel;
// Apply Master Volume and write to buffer
buffer[i] = static_cast<int16_t>(sampleF * _volume);
}
}