110 |
SmplInfo = GetSampleInfo(); |
SmplInfo = GetSampleInfo(); |
111 |
RgnInfo = GetRegionInfo(); |
RgnInfo = GetRegionInfo(); |
112 |
InstrInfo = GetInstrumentInfo(); |
InstrInfo = GetInstrumentInfo(); |
113 |
|
|
114 |
|
AboutToTrigger(); |
115 |
|
|
116 |
// calculate volume |
// calculate volume |
117 |
const double velocityAttenuation = GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity); |
const double velocityAttenuation = GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity); |
178 |
// the length of the decay and release curves are dependent on the velocity |
// the length of the decay and release curves are dependent on the velocity |
179 |
const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity); |
const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity); |
180 |
|
|
181 |
// setup EG 1 (VCA EG) |
if (GetSignalUnitRack() == NULL) { // setup EG 1 (VCA EG) |
|
{ |
|
182 |
// get current value of EG1 controller |
// get current value of EG1 controller |
183 |
double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity); |
double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity); |
184 |
|
|
186 |
EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue); |
EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue); |
187 |
|
|
188 |
TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity); |
TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity); |
189 |
|
} else { |
190 |
|
GetSignalUnitRack()->Trigger(); |
191 |
} |
} |
192 |
|
|
193 |
#ifdef CONFIG_INTERPOLATE_VOLUME |
#ifdef CONFIG_INTERPOLATE_VOLUME |
200 |
else |
else |
201 |
#else |
#else |
202 |
{ |
{ |
203 |
float finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel(); |
float finalVolume; |
204 |
|
if (GetSignalUnitRack() == NULL) { |
205 |
|
finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel(); |
206 |
|
} else { |
207 |
|
finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * GetSignalUnitRack()->GetEndpointUnit()->GetVolume(); |
208 |
|
} |
209 |
|
|
210 |
finalSynthesisParameters.fFinalVolumeLeft = finalVolume * VolumeLeft * pEngineChannel->GlobalPanLeft; |
finalSynthesisParameters.fFinalVolumeLeft = finalVolume * VolumeLeft * pEngineChannel->GlobalPanLeft; |
211 |
finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight; |
finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight; |
213 |
#endif |
#endif |
214 |
#endif |
#endif |
215 |
|
|
216 |
// setup EG 2 (VCF Cutoff EG) |
if (GetSignalUnitRack() == NULL) { |
217 |
{ |
// setup EG 2 (VCF Cutoff EG) |
218 |
// get current value of EG2 controller |
{ |
219 |
double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity); |
// get current value of EG2 controller |
220 |
|
double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity); |
221 |
|
|
222 |
|
// calculate influence of EG2 controller on EG2's parameters |
223 |
|
EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue); |
224 |
|
|
225 |
|
TriggerEG2(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity); |
226 |
|
} |
227 |
|
|
|
// calculate influence of EG2 controller on EG2's parameters |
|
|
EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue); |
|
228 |
|
|
229 |
TriggerEG2(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity); |
// setup EG 3 (VCO EG) |
230 |
} |
{ |
231 |
|
// if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch |
232 |
|
bool bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f; |
233 |
|
float eg3depth = (bPortamento) |
234 |
|
? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100) |
235 |
|
: RTMath::CentsToFreqRatio(RgnInfo.EG3Depth); |
236 |
|
float eg3time = (bPortamento) |
237 |
|
? pEngineChannel->PortamentoTime |
238 |
|
: RgnInfo.EG3Attack; |
239 |
|
EG3.trigger(eg3depth, eg3time, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
240 |
|
dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time)); |
241 |
|
} |
242 |
|
|
243 |
|
|
244 |
// setup EG 3 (VCO EG) |
// setup LFO 1 (VCA LFO) |
245 |
{ |
InitLFO1(); |
246 |
// if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch |
// setup LFO 2 (VCF Cutoff LFO) |
247 |
bool bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f; |
InitLFO2(); |
248 |
float eg3depth = (bPortamento) |
// setup LFO 3 (VCO LFO) |
249 |
? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100) |
InitLFO3(); |
|
: RTMath::CentsToFreqRatio(RgnInfo.EG3Depth); |
|
|
float eg3time = (bPortamento) |
|
|
? pEngineChannel->PortamentoTime |
|
|
: RgnInfo.EG3Attack; |
|
|
EG3.trigger(eg3depth, eg3time, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
|
dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time)); |
|
250 |
} |
} |
251 |
|
|
252 |
|
|
|
// setup LFO 1 (VCA LFO) |
|
|
InitLFO1(); |
|
|
// setup LFO 2 (VCF Cutoff LFO) |
|
|
InitLFO2(); |
|
|
// setup LFO 3 (VCO LFO) |
|
|
InitLFO3(); |
|
|
|
|
|
|
|
253 |
#if CONFIG_FORCE_FILTER |
#if CONFIG_FORCE_FILTER |
254 |
const bool bUseFilter = true; |
const bool bUseFilter = true; |
255 |
#else // use filter only if instrument file told so |
#else // use filter only if instrument file told so |
352 |
// drivers that use Samples < MaxSamplesPerCycle). |
// drivers that use Samples < MaxSamplesPerCycle). |
353 |
// End the EG1 here, at pos 0, with a shorter max fade |
// End the EG1 here, at pos 0, with a shorter max fade |
354 |
// out time. |
// out time. |
355 |
pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
if (GetSignalUnitRack() == NULL) { |
356 |
|
pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
357 |
|
} else { |
358 |
|
// TODO: |
359 |
|
} |
360 |
itKillEvent = Pool<Event>::Iterator(); |
itKillEvent = Pool<Event>::Iterator(); |
361 |
} else { |
} else { |
362 |
killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos); |
killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos); |
384 |
processTransitionEvents(itNoteEvent, iSubFragmentEnd); |
processTransitionEvents(itNoteEvent, iSubFragmentEnd); |
385 |
processGroupEvents(itGroupEvent, iSubFragmentEnd); |
processGroupEvents(itGroupEvent, iSubFragmentEnd); |
386 |
|
|
387 |
// if the voice was killed in this subfragment, or if the |
if (GetSignalUnitRack() == NULL) { |
388 |
// filter EG is finished, switch EG1 to fade out stage |
// if the voice was killed in this subfragment, or if the |
389 |
if ((itKillEvent && killPos <= iSubFragmentEnd) || |
// filter EG is finished, switch EG1 to fade out stage |
390 |
(SYNTHESIS_MODE_GET_FILTER(SynthesisMode) && |
if ((itKillEvent && killPos <= iSubFragmentEnd) || |
391 |
pEG2->getSegmentType() == EG::segment_end)) { |
(SYNTHESIS_MODE_GET_FILTER(SynthesisMode) && |
392 |
pEG1->enterFadeOutStage(); |
pEG2->getSegmentType() == EG::segment_end)) { |
393 |
itKillEvent = Pool<Event>::Iterator(); |
pEG1->enterFadeOutStage(); |
394 |
} |
itKillEvent = Pool<Event>::Iterator(); |
395 |
|
} |
|
// process envelope generators |
|
|
switch (pEG1->getSegmentType()) { |
|
|
case EG::segment_lin: |
|
|
fFinalVolume *= pEG1->processLin(); |
|
|
break; |
|
|
case EG::segment_exp: |
|
|
fFinalVolume *= pEG1->processExp(); |
|
|
break; |
|
|
case EG::segment_end: |
|
|
fFinalVolume *= pEG1->getLevel(); |
|
|
break; // noop |
|
|
case EG::segment_pow: |
|
|
fFinalVolume *= pEG1->processPow(); |
|
|
break; |
|
|
} |
|
|
switch (pEG2->getSegmentType()) { |
|
|
case EG::segment_lin: |
|
|
fFinalCutoff *= pEG2->processLin(); |
|
|
break; |
|
|
case EG::segment_exp: |
|
|
fFinalCutoff *= pEG2->processExp(); |
|
|
break; |
|
|
case EG::segment_end: |
|
|
fFinalCutoff *= pEG2->getLevel(); |
|
|
break; // noop |
|
|
case EG::segment_pow: |
|
|
fFinalCutoff *= pEG2->processPow(); |
|
|
break; |
|
|
} |
|
|
if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render(); |
|
396 |
|
|
397 |
// process low frequency oscillators |
// process envelope generators |
398 |
if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render()); |
switch (pEG1->getSegmentType()) { |
399 |
if (bLFO2Enabled) fFinalCutoff *= pLFO2->render(); |
case EG::segment_lin: |
400 |
if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render()); |
fFinalVolume *= pEG1->processLin(); |
401 |
|
break; |
402 |
|
case EG::segment_exp: |
403 |
|
fFinalVolume *= pEG1->processExp(); |
404 |
|
break; |
405 |
|
case EG::segment_end: |
406 |
|
fFinalVolume *= pEG1->getLevel(); |
407 |
|
break; // noop |
408 |
|
case EG::segment_pow: |
409 |
|
fFinalVolume *= pEG1->processPow(); |
410 |
|
break; |
411 |
|
} |
412 |
|
switch (pEG2->getSegmentType()) { |
413 |
|
case EG::segment_lin: |
414 |
|
fFinalCutoff *= pEG2->processLin(); |
415 |
|
break; |
416 |
|
case EG::segment_exp: |
417 |
|
fFinalCutoff *= pEG2->processExp(); |
418 |
|
break; |
419 |
|
case EG::segment_end: |
420 |
|
fFinalCutoff *= pEG2->getLevel(); |
421 |
|
break; // noop |
422 |
|
case EG::segment_pow: |
423 |
|
fFinalCutoff *= pEG2->processPow(); |
424 |
|
break; |
425 |
|
} |
426 |
|
if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render(); |
427 |
|
|
428 |
|
// process low frequency oscillators |
429 |
|
if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render()); |
430 |
|
if (bLFO2Enabled) fFinalCutoff *= pLFO2->render(); |
431 |
|
if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render()); |
432 |
|
} else { |
433 |
|
// if the voice was killed in this subfragment, or if the |
434 |
|
// filter EG is finished, switch EG1 to fade out stage |
435 |
|
/*if ((itKillEvent && killPos <= iSubFragmentEnd) || |
436 |
|
(SYNTHESIS_MODE_GET_FILTER(SynthesisMode) && |
437 |
|
pEG2->getSegmentType() == EG::segment_end)) { |
438 |
|
pEG1->enterFadeOutStage(); |
439 |
|
itKillEvent = Pool<Event>::Iterator(); |
440 |
|
}*/ |
441 |
|
// TODO: ^^^ |
442 |
|
|
443 |
|
fFinalVolume *= GetSignalUnitRack()->GetEndpointUnit()->GetVolume(); |
444 |
|
fFinalCutoff = GetSignalUnitRack()->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff); |
445 |
|
fFinalResonance = GetSignalUnitRack()->GetEndpointUnit()->CalculateResonance(fFinalResonance); |
446 |
|
|
447 |
|
finalSynthesisParameters.fFinalPitch = |
448 |
|
GetSignalUnitRack()->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch); |
449 |
|
|
450 |
|
} |
451 |
|
|
452 |
// limit the pitch so we don't read outside the buffer |
// limit the pitch so we don't read outside the buffer |
453 |
finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH)); |
finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH)); |
454 |
|
|
483 |
// render audio for one subfragment |
// render audio for one subfragment |
484 |
RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop); |
RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop); |
485 |
|
|
486 |
// stop the rendering if volume EG is finished |
if (GetSignalUnitRack() == NULL) { |
487 |
if (pEG1->getSegmentType() == EG::segment_end) break; |
// stop the rendering if volume EG is finished |
488 |
|
if (pEG1->getSegmentType() == EG::segment_end) break; |
489 |
|
} else { |
490 |
|
// stop the rendering if the endpoint unit is not active |
491 |
|
if (!GetSignalUnitRack()->GetEndpointUnit()->Active()) break; |
492 |
|
} |
493 |
|
|
494 |
const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch; |
const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch; |
495 |
|
|
496 |
// increment envelopes' positions |
if (GetSignalUnitRack() == NULL) { |
497 |
if (pEG1->active()) { |
// increment envelopes' positions |
498 |
|
if (pEG1->active()) { |
499 |
|
|
500 |
|
// if sample has a loop and loop start has been reached in this subfragment, send a special event to EG1 to let it finish the attack hold stage |
501 |
|
if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) { |
502 |
|
pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
503 |
|
} |
504 |
|
|
505 |
// if sample has a loop and loop start has been reached in this subfragment, send a special event to EG1 to let it finish the attack hold stage |
pEG1->increment(1); |
506 |
if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) { |
if (!pEG1->toStageEndLeft()) pEG1->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
507 |
} |
} |
508 |
|
if (pEG2->active()) { |
509 |
pEG1->increment(1); |
pEG2->increment(1); |
510 |
if (!pEG1->toStageEndLeft()) pEG1->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
if (!pEG2->toStageEndLeft()) pEG2->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
511 |
} |
} |
512 |
if (pEG2->active()) { |
EG3.increment(1); |
513 |
pEG2->increment(1); |
if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached |
514 |
if (!pEG2->toStageEndLeft()) pEG2->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
} else { |
515 |
|
// if sample has a loop and loop start has been reached in this subfragment, send a special event to EG1 to let it finish the attack hold stage |
516 |
|
/*if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) { |
517 |
|
pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
518 |
|
}*/ |
519 |
|
// TODO: ^^^ |
520 |
|
|
521 |
|
GetSignalUnitRack()->Increment(); |
522 |
} |
} |
|
EG3.increment(1); |
|
|
if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached |
|
523 |
|
|
524 |
Pos = newPos; |
Pos = newPos; |
525 |
i = iSubFragmentEnd; |
i = iSubFragmentEnd; |
550 |
if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) { |
if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) { |
551 |
processResonanceEvent(itEvent); |
processResonanceEvent(itEvent); |
552 |
} |
} |
553 |
if (itEvent->Param.CC.Controller == pLFO1->ExtController) { |
if (GetSignalUnitRack() == NULL) { |
554 |
pLFO1->update(itEvent->Param.CC.Value); |
if (itEvent->Param.CC.Controller == pLFO1->ExtController) { |
555 |
} |
pLFO1->update(itEvent->Param.CC.Value); |
556 |
if (itEvent->Param.CC.Controller == pLFO2->ExtController) { |
} |
557 |
pLFO2->update(itEvent->Param.CC.Value); |
if (itEvent->Param.CC.Controller == pLFO2->ExtController) { |
558 |
} |
pLFO2->update(itEvent->Param.CC.Value); |
559 |
if (itEvent->Param.CC.Controller == pLFO3->ExtController) { |
} |
560 |
pLFO3->update(itEvent->Param.CC.Value); |
if (itEvent->Param.CC.Controller == pLFO3->ExtController) { |
561 |
|
pLFO3->update(itEvent->Param.CC.Value); |
562 |
|
} |
563 |
} |
} |
564 |
if (itEvent->Param.CC.Controller == 7) { // volume |
if (itEvent->Param.CC.Controller == 7) { // volume |
565 |
VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]); |
VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]); |
572 |
} |
} |
573 |
|
|
574 |
ProcessCCEvent(itEvent); |
ProcessCCEvent(itEvent); |
575 |
|
if (GetSignalUnitRack() != NULL) { |
576 |
|
GetSignalUnitRack()->ProcessCCEvent(itEvent); |
577 |
|
} |
578 |
} |
} |
579 |
} |
} |
580 |
|
|
606 |
if (itEvent->Type == Event::type_release) { |
if (itEvent->Type == Event::type_release) { |
607 |
EnterReleaseStage(); |
EnterReleaseStage(); |
608 |
} else if (itEvent->Type == Event::type_cancel_release) { |
} else if (itEvent->Type == Event::type_cancel_release) { |
609 |
pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
if (GetSignalUnitRack() == NULL) { |
610 |
pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
611 |
|
pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
612 |
|
} else { |
613 |
|
GetSignalUnitRack()->CancelRelease(); |
614 |
|
} |
615 |
} |
} |
616 |
} |
} |
617 |
} |
} |
638 |
* @param itNoteOffEvent - event which causes this voice to die soon |
* @param itNoteOffEvent - event which causes this voice to die soon |
639 |
*/ |
*/ |
640 |
void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) { |
void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) { |
641 |
const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos()); |
if (GetSignalUnitRack() == NULL) { |
642 |
pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f; |
const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos()); |
643 |
|
pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f; |
644 |
|
} else { |
645 |
|
// TODO: |
646 |
|
} |
647 |
} |
} |
648 |
|
|
649 |
/** |
/** |
705 |
} |
} |
706 |
|
|
707 |
void AbstractVoice::EnterReleaseStage() { |
void AbstractVoice::EnterReleaseStage() { |
708 |
pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
if (GetSignalUnitRack() == NULL) { |
709 |
pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
710 |
|
pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
711 |
|
} else { |
712 |
|
GetSignalUnitRack()->EnterReleaseStage(); |
713 |
|
} |
714 |
|
} |
715 |
|
|
716 |
|
bool AbstractVoice::EG1Finished() { |
717 |
|
if (GetSignalUnitRack() == NULL) { |
718 |
|
return pEG1->getSegmentType() == EG::segment_end; |
719 |
|
} else { |
720 |
|
return !GetSignalUnitRack()->GetEndpointUnit()->Active(); |
721 |
|
} |
722 |
} |
} |
723 |
|
|
724 |
} // namespace LinuxSampler |
} // namespace LinuxSampler |