public override void Release() { if (State < ADSRState.Releasing) { if (adsr.R == 0) { curVelocity = 0; Stop(); } else if (curVelocity == 0 && prevVelocity == 0) { Stop(); } else { nextState = ADSRState.Releasing; } } }
public void Clock() { if ((waveform & 0x1) != 0) { if (state == ADSRState.Release) { state = ADSRState.Attack; } } else { state = ADSRState.Release; } ++adsrCounter; adsrCounter &= 0x7fff; ushort adsrTarget = 9; switch (state) { case ADSRState.Attack: adsrTarget = adsrRateTable[ad >> 4]; if (adsrCounter == adsrTarget) { adsrCounter = 0; adsrExpCounter = 0; ++volumeLevel; if (volumeLevel == 0xff) { state = ADSRState.Decay; } } break; case ADSRState.Decay: adsrTarget = adsrRateTable[ad & 0xf]; if (adsrCounter == adsrTarget) { adsrCounter = 0; byte adsrExpTarget = volumeLevel < 0x5d ? expTargetTable[volumeLevel] : (byte)1; ++adsrExpCounter; if (adsrExpCounter >= adsrExpTarget) { adsrExpCounter = 0; if (volumeLevel > sustainLevels[sr >> 4]) { --volumeLevel; } } } break; case ADSRState.Release: adsrTarget = adsrRateTable[sr & 0xf]; if (adsrCounter == adsrTarget) { adsrCounter = 0; if (volumeLevel > 0) { byte adsrExpTarget = volumeLevel < 0x5d ? expTargetTable[volumeLevel] : (byte)1; ++adsrExpCounter; if (adsrExpCounter >= adsrExpTarget) { adsrExpCounter = 0; --volumeLevel; } } } break; } uint lastAccumulator = accumulator; accumulator += frequency; accumulator &= 0xffffff; if ((waveform & 0x8) != 0) { accumulator = 0; //noiseGenerator = 0x7ffff8; } // Optimization: run noise generator only when necessary if ((waveform & 0x80) != 0) { if ((lastAccumulator & 0x80000) == 0 && (accumulator & 0x80000) != 0) { uint temp = noiseGenerator; uint step = (temp & 0x400000) ^ ((temp & 0x20000) << 5); temp <<= 1; if (step > 0) { temp |= 1; } noiseGenerator = temp & 0x7fffff; } } doSync = ((lastAccumulator & 0x800000) == 0 && (accumulator & 0x800000) != 0); }
protected void StepEnvelope() { void dec() { prevVelocity = curVelocity; processStep = 0; if (curVelocity - 1 <= sustainVelocity) { curVelocity = sustainVelocity; nextState = ADSRState.Playing; } else { curVelocity = (byte)(curVelocity - 1).Clamp(0, 0xF); } } void sus() { prevVelocity = curVelocity; processStep = 0; } void rel() { if (adsr.R == 0) { prevVelocity = 0; curVelocity = 0; Stop(); } else { prevVelocity = curVelocity; processStep = 0; if (curVelocity - 1 <= 0) { nextState = ADSRState.Dying; curVelocity = 0; } else { curVelocity--; } } } switch (State) { case ADSRState.Initializing: nextState = ADSRState.Rising; prevPan = curPan; processStep = 0; if ((adsr.A | adsr.D) == 0 || (sustainVelocity == 0 && peakVelocity == 0)) { State = ADSRState.Playing; prevVelocity = sustainVelocity; curVelocity = sustainVelocity; return; } else if (adsr.A == 0 && adsr.S < 0xF) { State = ADSRState.Decaying; prevVelocity = peakVelocity; curVelocity = (byte)(peakVelocity - 1).Clamp(0, 0xF); if (curVelocity < sustainVelocity) { curVelocity = sustainVelocity; } return; } else if (adsr.A == 0) { State = ADSRState.Playing; prevVelocity = sustainVelocity; curVelocity = sustainVelocity; return; } else { State = ADSRState.Rising; prevVelocity = 0; curVelocity = 1; return; } case ADSRState.Rising: if (++processStep >= Config.Instance.InterFrames * adsr.A) { if (nextState == ADSRState.Decaying) { State = ADSRState.Decaying; dec(); return; } if (nextState == ADSRState.Playing) { State = ADSRState.Playing; sus(); return; } if (nextState == ADSRState.Releasing) { State = ADSRState.Releasing; rel(); return; } prevVelocity = curVelocity; processStep = 0; if (++curVelocity >= peakVelocity) { if (adsr.D == 0) { nextState = ADSRState.Playing; } else if (peakVelocity == sustainVelocity) { nextState = ADSRState.Playing; curVelocity = peakVelocity; } else { curVelocity = peakVelocity; nextState = ADSRState.Decaying; } } } break; case ADSRState.Decaying: if (++processStep >= Config.Instance.InterFrames * adsr.D) { if (nextState == ADSRState.Playing) { State = ADSRState.Playing; sus(); return; } if (nextState == ADSRState.Releasing) { State = ADSRState.Releasing; rel(); return; } dec(); } break; case ADSRState.Playing: if (++processStep >= Config.Instance.InterFrames) { if (nextState == ADSRState.Releasing) { State = ADSRState.Releasing; rel(); return; } sus(); } break; case ADSRState.Releasing: if (++processStep >= Config.Instance.InterFrames * adsr.R) { if (nextState == ADSRState.Dying) { Stop(); return; } rel(); } break; } }