--- linuxsampler/trunk/src/engines/common/AbstractVoice.cpp 2010/02/23 18:32:31 2061 +++ linuxsampler/trunk/src/engines/common/AbstractVoice.cpp 2010/08/10 12:05:19 2114 @@ -32,7 +32,6 @@ pLFO2 = new LFOUnsigned(1.0f); // filter EG (0..1 range) pLFO3 = new LFOSigned(1200.0f); // pitch EG (-1200..+1200 range) PlaybackState = playback_state_end; - KeyGroup = 0; SynthesisMode = 0; // set all mode bits to 0 first // select synthesis implementation (asm core is not supported ATM) #if 0 // CONFIG_ASM && ARCH_X86 @@ -104,7 +103,8 @@ Delay = itNoteOnEvent->FragmentPos(); itTriggerEvent = itNoteOnEvent; itKillEvent = Pool::Iterator(); - KeyGroup = iKeyGroup; + + pGroupEvents = iKeyGroup ? pEngineChannel->ActiveKeyGroups[iKeyGroup] : 0; SmplInfo = GetSampleInfo(); RgnInfo = GetRegionInfo(); @@ -314,8 +314,13 @@ RTList::Iterator itNoteEvent; GetFirstEventOnKey(MIDIKey, itNoteEvent); + RTList::Iterator itGroupEvent; + if (pGroupEvents) itGroupEvent = pGroupEvents->first(); + if (itTriggerEvent) { // skip events that happened before this voice was triggered while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent; + while (itGroupEvent && itGroupEvent->FragmentPos() <= Skip) ++itGroupEvent; + // we can't simply compare the timestamp here, because note events // might happen on the same time stamp, so we have to deal on the // actual sequence the note events arrived instead (see bug #112) @@ -362,6 +367,7 @@ // process transition events (note on, note off & sustain pedal) processTransitionEvents(itNoteEvent, iSubFragmentEnd); + processGroupEvents(itGroupEvent, iSubFragmentEnd); // if the voice was killed in this subfragment, or if the // filter EG is finished, switch EG1 to fade out stage @@ -529,16 +535,30 @@ */ void AbstractVoice::processTransitionEvents(RTList::Iterator& itEvent, uint End) { for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) { - if (itEvent->Type == Event::type_release) { - pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); - EG2.update(gig::EGADSR::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); - } else if (itEvent->Type == Event::type_cancel_release) { - pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); - EG2.update(gig::EGADSR::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); + if (Type != Voice::type_release_trigger) { + + if (itEvent->Type == Event::type_release) { + EnterReleaseStage(); + } else if (itEvent->Type == Event::type_cancel_release) { + pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); + EG2.update(gig::EGADSR::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); + } } } } + /** + * Process given list of events aimed at all voices in a key group. + * + * @param itEvent - iterator pointing to the next event to be processed + * @param End - youngest time stamp where processing should be stopped + */ + void AbstractVoice::processGroupEvents(RTList::Iterator& itEvent, uint End) { + for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) { + ProcessGroupEvent(itEvent); + } + } + /** @brief Update current portamento position. * * Will be called when portamento mode is enabled to get the final @@ -609,4 +629,10 @@ float AbstractVoice::GetReleaseTriggerAttenuation(float noteLength) { return 1 - RgnInfo.ReleaseTriggerDecay * noteLength; } + + void AbstractVoice::EnterReleaseStage() { + pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); + EG2.update(gig::EGADSR::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); + } + } // namespace LinuxSampler