--- linuxsampler/trunk/src/engines/gig/EGADSR.cpp 2004/09/12 14:48:19 239 +++ linuxsampler/trunk/src/engines/gig/EGADSR.cpp 2004/10/14 21:31:26 285 @@ -24,12 +24,12 @@ namespace LinuxSampler { namespace gig { - const float EGADSR::EndCoeff(CalculateEndCoeff()); + const float EGADSR::FadeOutCoeff(CalculateFadeOutCoeff()); - float EGADSR::CalculateEndCoeff() { - const double sampleRate = 44100.0; // even if the sample rate will be 192kHz it won't hurt at all - const double killSteps = EG_MIN_RELEASE_TIME * sampleRate; - return float(exp(1.0 / killSteps) - 1.0); + float EGADSR::CalculateFadeOutCoeff() { + const float sampleRate = 44100.0; // even if the sample rate will be 192kHz it won't hurt at all + const float killSteps = EG_MIN_RELEASE_TIME * sampleRate; + return -1.0f / killSteps; } EGADSR::EGADSR(gig::Engine* pEngine, Event::destination_t ModulationDestination) { @@ -46,31 +46,25 @@ * @param TotalSamples - total number of sample points to be rendered in this * audio fragment cycle by the audio engine * @param pEvents - event list with "release" and "cancel release" events - * @param pTriggerEvent - event that caused triggering of the voice (only if + * @param itTriggerEvent - event that caused triggering of the voice (only if * the voice was triggered in the current audio * fragment, NULL otherwise) * @param SamplePos - current playback position * @param CurrentPitch - current pitch value for playback - * @param pKillEvent - (optional) event which caused this voice to be killed + * @param itKillEvent - (optional) event which caused this voice to be killed */ - void EGADSR::Process(uint TotalSamples, RTEList* pEvents, Event* pTriggerEvent, double SamplePos, double CurrentPitch, Event* pKillEvent) { - Event* pTransitionEvent; - if (pTriggerEvent) { // skip all events which occured before this voice was triggered - pEvents->set_current(pTriggerEvent); - pTransitionEvent = pEvents->next(); - } - else { - pTransitionEvent = pEvents->first(); - } + void EGADSR::Process(uint TotalSamples, RTList* pEvents, RTList::Iterator itTriggerEvent, double SamplePos, double CurrentPitch, RTList::Iterator itKillEvent) { + // skip all events which occured before this voice was triggered + RTList::Iterator itTransitionEvent = (itTriggerEvent) ? ++itTriggerEvent : pEvents->first(); - // if the voice was killed in this fragment we only process the time before this kill event and then switch to 'stage_end' - int Samples = (pKillEvent) ? pKillEvent->FragmentPos() : (int) TotalSamples; + // if the voice was killed in this fragment we only process the time before this kill event, then switch to 'stage_fadeout' + int Samples = (itKillEvent) ? RTMath::Min(itKillEvent->FragmentPos(), pEngine->MaxFadeOutPos) : (int) TotalSamples; int iSample = TriggerDelay; while (iSample < TotalSamples) { // if the voice was killed in this fragment and we already processed the time before this kill event - if (pKillEvent && iSample >= Samples) Stage = stage_end; + if (itKillEvent && iSample >= Samples) Stage = stage_fadeout; switch (Stage) { case stage_attack: { @@ -83,8 +77,8 @@ pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level; } if (iSample == TotalSamples) { // postpone last transition event for the next audio fragment - Event* pLastEvent = pEvents->last(); - if (pLastEvent) ReleasePostponed = (pLastEvent->Type == Event::type_release); + RTList::Iterator itLastEvent = pEvents->last(); + if (itLastEvent) ReleasePostponed = (itLastEvent->Type == Event::type_release); } if (!AttackStepsLeft) Stage = (ReleasePostponed) ? stage_release : (HoldAttack) ? stage_attack_hold : stage_decay1; break; @@ -97,10 +91,10 @@ int holdstepsleft = (int) (LoopStart - SamplePos / CurrentPitch); // FIXME: just an approximation, inaccuracy grows with higher audio fragment size, sufficient for usual fragment sizes though int to_process = RTMath::Min(holdstepsleft, Samples - iSample); int process_end = iSample + to_process; - if (pTransitionEvent && pTransitionEvent->FragmentPos() <= process_end) { - process_end = pTransitionEvent->FragmentPos(); - Stage = (pTransitionEvent->Type == Event::type_release) ? stage_release : (InfiniteSustain) ? stage_sustain : stage_decay2; - pTransitionEvent = pEvents->next(); + if (itTransitionEvent && itTransitionEvent->FragmentPos() <= process_end) { + process_end = itTransitionEvent->FragmentPos(); + Stage = (itTransitionEvent->Type == Event::type_release) ? stage_release : (InfiniteSustain) ? stage_sustain : stage_decay2; + ++itTransitionEvent; } else if (to_process == holdstepsleft) Stage = stage_decay1; while (iSample < process_end) { @@ -111,10 +105,10 @@ case stage_decay1: { int to_process = RTMath::Min(Samples - iSample, Decay1StepsLeft); int process_end = iSample + to_process; - if (pTransitionEvent && pTransitionEvent->FragmentPos() <= process_end) { - process_end = pTransitionEvent->FragmentPos(); - Stage = (pTransitionEvent->Type == Event::type_release) ? stage_release : (InfiniteSustain) ? stage_sustain : stage_decay2; - pTransitionEvent = pEvents->next(); + if (itTransitionEvent && itTransitionEvent->FragmentPos() <= process_end) { + process_end = itTransitionEvent->FragmentPos(); + Stage = (itTransitionEvent->Type == Event::type_release) ? stage_release : (InfiniteSustain) ? stage_sustain : stage_decay2; + ++itTransitionEvent; } else { Decay1StepsLeft -= to_process; @@ -128,25 +122,25 @@ } case stage_decay2: { int process_end; - if (pTransitionEvent && pTransitionEvent->Type == Event::type_release && pTransitionEvent->FragmentPos() <= Samples) { - process_end = pTransitionEvent->FragmentPos(); - pTransitionEvent = pEvents->next(); - Stage = stage_release; // switch to release stage soon + if (itTransitionEvent && itTransitionEvent->Type == Event::type_release && itTransitionEvent->FragmentPos() <= Samples) { + process_end = itTransitionEvent->FragmentPos(); + ++itTransitionEvent; + Stage = stage_release; // switch to release stage soon } else process_end = Samples; while (iSample < process_end) { Level += Level * Decay2Coeff; pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level; } - if (Level <= EG_ENVELOPE_LIMIT) Stage = stage_end; + if (Level <= EG_ENVELOPE_LIMIT) Stage = stage_fadeout; break; } case stage_sustain: { int process_end; - if (pTransitionEvent && pTransitionEvent->Type == Event::type_release && pTransitionEvent->FragmentPos() <= Samples) { - process_end = pTransitionEvent->FragmentPos(); - pTransitionEvent = pEvents->next(); - Stage = stage_release; // switch to release stage soon + if (itTransitionEvent && itTransitionEvent->Type == Event::type_release && itTransitionEvent->FragmentPos() <= Samples) { + process_end = itTransitionEvent->FragmentPos(); + ++itTransitionEvent; + Stage = stage_release; // switch to release stage soon } else process_end = Samples; while (iSample < process_end) { @@ -156,28 +150,42 @@ } case stage_release: { int process_end; - if (pTransitionEvent && pTransitionEvent->Type == Event::type_cancel_release && pTransitionEvent->FragmentPos() <= Samples) { - process_end = pTransitionEvent->FragmentPos(); - pTransitionEvent = pEvents->next(); - Stage = (InfiniteSustain) ? stage_sustain : stage_decay2; // switch back to sustain / decay2 stage soon + if (itTransitionEvent && itTransitionEvent->Type == Event::type_cancel_release && itTransitionEvent->FragmentPos() <= Samples) { + process_end = itTransitionEvent->FragmentPos(); + ++itTransitionEvent; + Stage = (InfiniteSustain) ? stage_sustain : stage_decay2; // switch back to sustain / decay2 stage soon } else process_end = Samples; while (iSample < process_end) { Level += Level * ReleaseCoeff; pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level; } - if (Level <= EG_ENVELOPE_LIMIT) Stage = stage_end; + if (Level <= EG_ENVELOPE_LIMIT) Stage = stage_fadeout; break; } + case stage_fadeout: { + int to_process = RTMath::Min(int(Level / (-FadeOutCoeff)), TotalSamples - iSample); + int process_end = iSample + to_process; + while (iSample < process_end) { + Level += FadeOutCoeff; + pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level; + } + Stage = stage_end; + if (Level > -FadeOutCoeff) dmsg(1,("EGADSR: Warning, final fade out level too high, may result in click sound!\n")); + } //Fall through here instead of breaking otherwise we can get back into stage_fadeout and loop forever! case stage_end: { while (iSample < TotalSamples) { - Level += Level * EndCoeff; - pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level; + pEngine->pSynthesisParameters[ModulationDestination][iSample++] = 0.0f; } break; } } } + + if (itKillEvent && Stage != stage_end) { + dmsg(1,("EGADSR: VOICE KILLING NOT COMPLETED !!!\n")); + dmsg(1,("EGADSR: Stage=%d,iSample=%d,Samples=%d, TotalSamples=%d, MaxFadoutPos=%d\n",Stage,iSample,Samples,TotalSamples,pEngine->MaxFadeOutPos)); + } } /**