Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //------------------------------------------------------------------------------------------------------------------------------------------
- // Get the phase parameters for the given envelope, phase and current envelope level
- //------------------------------------------------------------------------------------------------------------------------------------------
- static EnvPhaseParams getEnvPhaseParams(const AdsrEnvelope env, const EnvPhase phase, const int16_t envLevel) noexcept {
- // Envelope level shouldn't be negative, but just in case...
- const int32_t absEnvLevel = std::abs((int32_t) envLevel);
- // Gather basic info for the envelope phase
- int32_t targetLevel;
- int32_t stepUnscaled;
- uint32_t stepScale;
- bool bExponential;
- switch (phase) {
- // Attack phase: ramps up to the maximum volume always
- case EnvPhase::Attack: {
- targetLevel = MAX_ENV_LEVEL;
- stepScale = env.attackShift;
- stepUnscaled = 7 - (int32_t) env.attackStep;
- bExponential = env.bAttackExp;
- } break;
- // Decay phase: ramps down to the sustain level and always exponentially
- case EnvPhase::Decay: {
- targetLevel = std::min<int32_t>(((int32_t) env.sustainLevel + 1) * 2048, MAX_ENV_LEVEL);
- stepScale = env.decayShift;
- stepUnscaled = -8;
- bExponential = true;
- } break;
- // Sustain phase: has no target level (-1, lasts forever) and can ramp up or down
- case EnvPhase::Sustain: {
- targetLevel = -1;
- stepScale = env.sustainShift;
- stepUnscaled = (env.bSustainDec) ? (int32_t) env.sustainStep - 8 : 7 - (int32_t) env.sustainStep;
- bExponential = env.bSustainExp;
- } break;
- // Release, off or unknown phase: fade out to zero
- case EnvPhase::Release:
- case EnvPhase::Off:
- default: {
- targetLevel = MIN_ENV_LEVEL;
- stepScale = env.releaseShift;
- stepUnscaled = -8;
- bExponential = env.bReleaseExp;
- } break;
- }
- // Scale the step accordingly and decide how many cycles an envelope step takes
- const int32_t stepScaleMultiplier = 1 << std::max<int32_t>(0, 11 - stepScale);
- EnvPhaseParams params;
- params.targetLevel = targetLevel;
- params.stepCycles = 1 << std::max<int32_t>(0, stepScale - 11);
- params.step = stepUnscaled * stepScaleMultiplier;
- if (bExponential) {
- // Adjustments based on the current envelope level when the envelope mode is 'exponential'.
- // Slower fade-outs as the envelope level decreases & 4x slower fade-ins when envelope level surpasses '0x6000'.
- if ((stepUnscaled > 0) && (absEnvLevel > 0x6000)) {
- params.stepCycles *= 4;
- }
- else if (stepUnscaled < 0) {
- params.step = (int32_t)(((int64_t) params.step * absEnvLevel) >> 15);
- }
- }
- return params;
- }
- //------------------------------------------------------------------------------------------------------------------------------------------
- // Step the ADSR envelope for the given voice
- //------------------------------------------------------------------------------------------------------------------------------------------
- static void stepVoiceEnvelope(Voice& voice) noexcept {
- // Don't process the envelope if we must wait a few more cycles
- if (voice.envWaitCycles > 0) {
- voice.envWaitCycles--;
- if (voice.envWaitCycles > 0)
- return;
- }
- // Step the envelope in it's current phase and compute the new envelope level
- const EnvPhaseParams envParams = getEnvPhaseParams(voice.env, voice.envPhase, voice.envLevel);
- int32_t newEnvLevel = std::clamp<int32_t>(voice.envLevel + envParams.step, MIN_ENV_LEVEL, MAX_ENV_LEVEL);
- // Do state transitions when ramping up or down, unless we're in the 'sustain' phase (targetLevel < 0)
- bool bReachedTargetLevel = false;
- if (envParams.targetLevel >= 0) {
- if (envParams.step > 0) {
- bReachedTargetLevel = (newEnvLevel >= envParams.targetLevel);
- } else if (envParams.step < 0) {
- bReachedTargetLevel = (newEnvLevel <= envParams.targetLevel);
- }
- }
- if (bReachedTargetLevel) {
- newEnvLevel = envParams.targetLevel;
- voice.envPhase = getNextEnvPhase(voice.envPhase);
- voice.envWaitCycles = 0;
- } else {
- voice.envWaitCycles = envParams.stepCycles;
- }
- voice.envLevel = (int16_t) newEnvLevel;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement