ADSR and filters
This commit is contained in:
+84
-16
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user