--- linuxsampler/trunk/src/engines/common/AbstractVoice.cpp 2011/07/25 17:21:16 2216 +++ linuxsampler/trunk/src/engines/common/AbstractVoice.cpp 2011/12/09 15:04:55 2297 @@ -26,7 +26,7 @@ namespace LinuxSampler { - AbstractVoice::AbstractVoice() { + AbstractVoice::AbstractVoice(SignalUnitRack* pRack): pSignalUnitRack(pRack) { pEngineChannel = NULL; pLFO1 = new LFOUnsigned(1.0f); // amplitude LFO (0..1 range) pLFO2 = new LFOUnsigned(1.0f); // filter LFO (0..1 range) @@ -99,6 +99,9 @@ Type = VoiceType; MIDIKey = itNoteOnEvent->Param.Note.Key; + MIDIVelocity = itNoteOnEvent->Param.Note.Velocity; + MIDIPan = pEngineChannel->ControllerTable[10]; + if (MIDIPan == 0 && pEngineChannel->GlobalPanRight == 1) MIDIPan = 64; // workaround used to determine whether the MIDI pan has not been set PlaybackState = playback_state_init; // mark voice as triggered, but no audio rendered yet Delay = itNoteOnEvent->FragmentPos(); itTriggerEvent = itNoteOnEvent; @@ -177,7 +180,7 @@ // the length of the decay and release curves are dependent on the velocity const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity); - if (GetSignalUnitRack() == NULL) { // setup EG 1 (VCA EG) + if (pSignalUnitRack == NULL) { // setup EG 1 (VCA EG) // get current value of EG1 controller double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity); @@ -186,7 +189,7 @@ TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity); } else { - GetSignalUnitRack()->Trigger(); + pSignalUnitRack->Trigger(); } #ifdef CONFIG_INTERPOLATE_VOLUME @@ -200,10 +203,10 @@ #else { float finalVolume; - if (GetSignalUnitRack() == NULL) { + if (pSignalUnitRack == NULL) { finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel(); } else { - finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * GetSignalUnitRack()->GetEndpointUnit()->GetVolume(); + finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pSignalUnitRack->GetEndpointUnit()->GetVolume(); } finalSynthesisParameters.fFinalVolumeLeft = finalVolume * VolumeLeft * pEngineChannel->GlobalPanLeft; @@ -212,7 +215,7 @@ #endif #endif - if (GetSignalUnitRack() == NULL) { + if (pSignalUnitRack == NULL) { // setup EG 2 (VCF Cutoff EG) { // get current value of EG2 controller @@ -309,14 +312,39 @@ * @param Skip - number of sample points to skip in output buffer */ void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) { + bool delay = false; // Whether the voice playback should be delayed for this call + + if (pSignalUnitRack != NULL) { + uint delaySteps = pSignalUnitRack->GetEndpointUnit()->DelayTrigger(); + if (delaySteps > 0) { // delay on the endpoint unit means delay of the voice playback + if (delaySteps >= Samples) { + pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(Samples); + delay = true; + } else { + pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(delaySteps); + Samples -= delaySteps; + Skip += delaySteps; + } + } + } + AbstractEngineChannel* pChannel = pEngineChannel; MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey); const bool bVoiceRequiresDedicatedRouting = pEngineChannel->GetFxSendCount() > 0 && (pMidiKeyInfo->ReverbSend || pMidiKeyInfo->ChorusSend); + + const bool bEq = + pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && GetEngine()->pEq->HasSupport(); - if (bVoiceRequiresDedicatedRouting) { + if (bEq) { + GetEngine()->pEq->GetInChannelLeft()->Clear(); + GetEngine()->pEq->GetInChannelRight()->Clear(); + finalSynthesisParameters.pOutLeft = &GetEngine()->pEq->GetInChannelLeft()->Buffer()[Skip]; + finalSynthesisParameters.pOutRight = &GetEngine()->pEq->GetInChannelRight()->Buffer()[Skip]; + pSignalUnitRack->UpdateEqSettings(GetEngine()->pEq); + } else if (bVoiceRequiresDedicatedRouting) { finalSynthesisParameters.pOutLeft = &GetEngine()->pDedicatedVoiceChannelLeft->Buffer()[Skip]; finalSynthesisParameters.pOutRight = &GetEngine()->pDedicatedVoiceChannelRight->Buffer()[Skip]; } else { @@ -356,7 +384,7 @@ // drivers that use Samples < MaxSamplesPerCycle). // End the EG1 here, at pos 0, with a shorter max fade // out time. - if (GetSignalUnitRack() == NULL) { + if (pSignalUnitRack == NULL) { pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); } else { // TODO: @@ -377,6 +405,11 @@ // process MIDI control change and pitchbend events for this subfragment processCCEvents(itCCEvent, iSubFragmentEnd); + uint8_t pan = MIDIPan; + if (pSignalUnitRack != NULL) pan = pSignalUnitRack->GetEndpointUnit()->CaluclatePan(pan); + + PanLeftSmoother.update(AbstractEngine::PanCurve[128 - pan]); + PanRightSmoother.update(AbstractEngine::PanCurve[pan]); finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend; float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render(); @@ -387,8 +420,8 @@ // process transition events (note on, note off & sustain pedal) processTransitionEvents(itNoteEvent, iSubFragmentEnd); processGroupEvents(itGroupEvent, iSubFragmentEnd); - - if (GetSignalUnitRack() == NULL) { + + if (pSignalUnitRack == NULL) { // if the voice was killed in this subfragment, or if the // filter EG is finished, switch EG1 to fade out stage if ((itKillEvent && killPos <= iSubFragmentEnd) || @@ -444,12 +477,12 @@ }*/ // TODO: ^^^ - fFinalVolume *= GetSignalUnitRack()->GetEndpointUnit()->GetVolume(); - fFinalCutoff = GetSignalUnitRack()->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff); - fFinalResonance = GetSignalUnitRack()->GetEndpointUnit()->CalculateResonance(fFinalResonance); + fFinalVolume *= pSignalUnitRack->GetEndpointUnit()->GetVolume(); + fFinalCutoff = pSignalUnitRack->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff); + fFinalResonance = pSignalUnitRack->GetEndpointUnit()->CalculateResonance(fFinalResonance); finalSynthesisParameters.fFinalPitch = - GetSignalUnitRack()->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch); + pSignalUnitRack->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch); } @@ -485,19 +518,19 @@ fFinalVolume * VolumeRight * PanRightSmoother.render(); #endif // render audio for one subfragment - RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop); + if (!delay) RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop); - if (GetSignalUnitRack() == NULL) { + if (pSignalUnitRack == NULL) { // stop the rendering if volume EG is finished if (pEG1->getSegmentType() == EG::segment_end) break; } else { // stop the rendering if the endpoint unit is not active - if (!GetSignalUnitRack()->GetEndpointUnit()->Active()) break; + if (!pSignalUnitRack->GetEndpointUnit()->Active()) break; } const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch; - if (GetSignalUnitRack() == NULL) { + if (pSignalUnitRack == NULL) { // increment envelopes' positions if (pEG1->active()) { @@ -522,19 +555,30 @@ }*/ // TODO: ^^^ - GetSignalUnitRack()->Increment(); + if (!delay) pSignalUnitRack->Increment(); } Pos = newPos; i = iSubFragmentEnd; } + + if (delay) return; if (bVoiceRequiresDedicatedRouting) { + if (bEq) { + GetEngine()->pEq->RenderAudio(Samples); + GetEngine()->pEq->GetOutChannelLeft()->CopyTo(GetEngine()->pDedicatedVoiceChannelLeft, Samples); + GetEngine()->pEq->GetOutChannelRight()->CopyTo(GetEngine()->pDedicatedVoiceChannelRight, Samples); + } optional effectSendLevels[2] = { pMidiKeyInfo->ReverbSend, pMidiKeyInfo->ChorusSend }; GetEngine()->RouteDedicatedVoiceChannels(pEngineChannel, effectSendLevels, Samples); + } else if (bEq) { + GetEngine()->pEq->RenderAudio(Samples); + GetEngine()->pEq->GetOutChannelLeft()->CopyTo(pChannel->pChannelLeft, Samples); + GetEngine()->pEq->GetOutChannelRight()->CopyTo(pChannel->pChannelRight, Samples); } } @@ -554,7 +598,7 @@ if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) { processResonanceEvent(itEvent); } - if (GetSignalUnitRack() == NULL) { + if (pSignalUnitRack == NULL) { if (itEvent->Param.CC.Controller == pLFO1->ExtController) { pLFO1->update(itEvent->Param.CC.Value); } @@ -568,16 +612,15 @@ if (itEvent->Param.CC.Controller == 7) { // volume VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]); } else if (itEvent->Param.CC.Controller == 10) { // panpot - PanLeftSmoother.update(AbstractEngine::PanCurve[128 - itEvent->Param.CC.Value]); - PanRightSmoother.update(AbstractEngine::PanCurve[itEvent->Param.CC.Value]); + MIDIPan = itEvent->Param.CC.Value; } } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event processPitchEvent(itEvent); } ProcessCCEvent(itEvent); - if (GetSignalUnitRack() != NULL) { - GetSignalUnitRack()->ProcessCCEvent(itEvent); + if (pSignalUnitRack != NULL) { + pSignalUnitRack->ProcessCCEvent(itEvent); } } } @@ -610,11 +653,11 @@ if (itEvent->Type == Event::type_release) { EnterReleaseStage(); } else if (itEvent->Type == Event::type_cancel_release) { - if (GetSignalUnitRack() == NULL) { + if (pSignalUnitRack == NULL) { pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); } else { - GetSignalUnitRack()->CancelRelease(); + pSignalUnitRack->CancelRelease(); } } } @@ -642,7 +685,7 @@ * @param itNoteOffEvent - event which causes this voice to die soon */ void AbstractVoice::UpdatePortamentoPos(Pool::Iterator& itNoteOffEvent) { - if (GetSignalUnitRack() == NULL) { + if (pSignalUnitRack == NULL) { const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos()); pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f; } else { @@ -709,19 +752,19 @@ } void AbstractVoice::EnterReleaseStage() { - if (GetSignalUnitRack() == NULL) { + if (pSignalUnitRack == NULL) { pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); } else { - GetSignalUnitRack()->EnterReleaseStage(); + pSignalUnitRack->EnterReleaseStage(); } } bool AbstractVoice::EG1Finished() { - if (GetSignalUnitRack() == NULL) { + if (pSignalUnitRack == NULL) { return pEG1->getSegmentType() == EG::segment_end; } else { - return !GetSignalUnitRack()->GetEndpointUnit()->Active(); + return !pSignalUnitRack->GetEndpointUnit()->Active(); } }