3 |
* LinuxSampler - modular, streaming capable sampler * |
* LinuxSampler - modular, streaming capable sampler * |
4 |
* * |
* * |
5 |
* Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * |
* Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * |
6 |
* Copyright (C) 2005 Christian Schoenebeck * |
* Copyright (C) 2005, 2006 Christian Schoenebeck * |
7 |
* * |
* * |
8 |
* This program is free software; you can redistribute it and/or modify * |
* This program is free software; you can redistribute it and/or modify * |
9 |
* it under the terms of the GNU General Public License as published by * |
* it under the terms of the GNU General Public License as published by * |
136 |
CrossfadeVolume = 1.0f; |
CrossfadeVolume = 1.0f; |
137 |
} |
} |
138 |
|
|
139 |
PanLeft = 1.0f - float(RTMath::Max(pDimRgn->Pan, 0)) / 63.0f; |
PanLeft = Engine::PanCurve[64 - pDimRgn->Pan]; |
140 |
PanRight = 1.0f - float(RTMath::Min(pDimRgn->Pan, 0)) / -64.0f; |
PanRight = Engine::PanCurve[64 + pDimRgn->Pan]; |
141 |
|
|
142 |
finalSynthesisParameters.dPos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points) |
finalSynthesisParameters.dPos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points) |
143 |
Pos = pDimRgn->SampleStartOffset; |
Pos = pDimRgn->SampleStartOffset; |
223 |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
224 |
} |
} |
225 |
|
|
226 |
|
// setup initial volume in synthesis parameters |
227 |
|
fFinalVolume = getVolume() * EG1.getLevel(); |
228 |
|
finalSynthesisParameters.fFinalVolumeLeft = fFinalVolume * PanLeft * pEngineChannel->GlobalPanLeft; |
229 |
|
finalSynthesisParameters.fFinalVolumeRight = fFinalVolume * PanRight * pEngineChannel->GlobalPanRight; |
230 |
|
|
231 |
|
|
232 |
// setup EG 2 (VCF Cutoff EG) |
// setup EG 2 (VCF Cutoff EG) |
233 |
{ |
{ |
269 |
|
|
270 |
// setup EG 3 (VCO EG) |
// setup EG 3 (VCO EG) |
271 |
{ |
{ |
272 |
double eg3depth = RTMath::CentsToFreqRatio(pDimRgn->EG3Depth); |
// if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch |
273 |
EG3.trigger(eg3depth, pDimRgn->EG3Attack, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
bool bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f; |
274 |
|
float eg3depth = (bPortamento) |
275 |
|
? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100) |
276 |
|
: RTMath::CentsToFreqRatio(pDimRgn->EG3Depth); |
277 |
|
float eg3time = (bPortamento) |
278 |
|
? pEngineChannel->PortamentoTime |
279 |
|
: pDimRgn->EG3Attack; |
280 |
|
EG3.trigger(eg3depth, eg3time, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
281 |
|
dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time)); |
282 |
} |
} |
283 |
|
|
284 |
|
|
703 |
|
|
704 |
void Voice::processCrossFadeEvent(RTList<Event>::Iterator& itEvent) { |
void Voice::processCrossFadeEvent(RTList<Event>::Iterator& itEvent) { |
705 |
CrossfadeVolume = CrossfadeAttenuation(itEvent->Param.CC.Value); |
CrossfadeVolume = CrossfadeAttenuation(itEvent->Param.CC.Value); |
706 |
|
fFinalVolume = getVolume(); |
707 |
|
} |
708 |
|
|
709 |
|
float Voice::getVolume() { |
710 |
#if CONFIG_PROCESS_MUTED_CHANNELS |
#if CONFIG_PROCESS_MUTED_CHANNELS |
711 |
const float effectiveVolume = CrossfadeVolume * Volume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume); |
return pEngineChannel->GetMute() ? 0 : (Volume * CrossfadeVolume * pEngineChannel->GlobalVolume); |
712 |
#else |
#else |
713 |
const float effectiveVolume = CrossfadeVolume * Volume * pEngineChannel->GlobalVolume; |
return Volume * CrossfadeVolume * pEngineChannel->GlobalVolume; |
714 |
#endif |
#endif |
|
fFinalVolume = effectiveVolume; |
|
715 |
} |
} |
716 |
|
|
717 |
void Voice::processCutoffEvent(RTList<Event>::Iterator& itEvent) { |
void Voice::processCutoffEvent(RTList<Event>::Iterator& itEvent) { |
763 |
uint killPos; |
uint killPos; |
764 |
if (itKillEvent) killPos = RTMath::Min(itKillEvent->FragmentPos(), pEngine->MaxFadeOutPos); |
if (itKillEvent) killPos = RTMath::Min(itKillEvent->FragmentPos(), pEngine->MaxFadeOutPos); |
765 |
|
|
766 |
|
float fFinalPanLeft = PanLeft * pEngineChannel->GlobalPanLeft; |
767 |
|
float fFinalPanRight = PanRight * pEngineChannel->GlobalPanRight; |
768 |
|
|
769 |
uint i = Skip; |
uint i = Skip; |
770 |
while (i < Samples) { |
while (i < Samples) { |
771 |
int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples); |
int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples); |
772 |
|
|
773 |
// initialize all final synthesis parameters |
// initialize all final synthesis parameters |
774 |
finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend; |
finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend; |
775 |
#if CONFIG_PROCESS_MUTED_CHANNELS |
fFinalVolume = getVolume(); |
|
fFinalVolume = this->Volume * this->CrossfadeVolume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume); |
|
|
#else |
|
|
fFinalVolume = this->Volume * this->CrossfadeVolume * pEngineChannel->GlobalVolume; |
|
|
#endif |
|
776 |
fFinalCutoff = VCFCutoffCtrl.fvalue; |
fFinalCutoff = VCFCutoffCtrl.fvalue; |
777 |
fFinalResonance = VCFResonanceCtrl.fvalue; |
fFinalResonance = VCFResonanceCtrl.fvalue; |
778 |
|
|
811 |
fFinalCutoff *= EG2.getLevel(); |
fFinalCutoff *= EG2.getLevel(); |
812 |
break; // noop |
break; // noop |
813 |
} |
} |
814 |
if (EG3.active()) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(EG3.render()); |
if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render(); |
815 |
|
|
816 |
// process low frequency oscillators |
// process low frequency oscillators |
817 |
if (bLFO1Enabled) fFinalVolume *= pLFO1->render(); |
if (bLFO1Enabled) fFinalVolume *= pLFO1->render(); |
832 |
SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, bResamplingRequired); |
SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, bResamplingRequired); |
833 |
|
|
834 |
// prepare final synthesis parameters structure |
// prepare final synthesis parameters structure |
|
finalSynthesisParameters.fFinalVolumeLeft = fFinalVolume * PanLeft; |
|
|
finalSynthesisParameters.fFinalVolumeRight = fFinalVolume * PanRight; |
|
835 |
finalSynthesisParameters.uiToGo = iSubFragmentEnd - i; |
finalSynthesisParameters.uiToGo = iSubFragmentEnd - i; |
836 |
|
#ifdef CONFIG_INTERPOLATE_VOLUME |
837 |
|
finalSynthesisParameters.fFinalVolumeDeltaLeft = |
838 |
|
(fFinalVolume * fFinalPanLeft - finalSynthesisParameters.fFinalVolumeLeft) / finalSynthesisParameters.uiToGo; |
839 |
|
finalSynthesisParameters.fFinalVolumeDeltaRight = |
840 |
|
(fFinalVolume * fFinalPanRight - finalSynthesisParameters.fFinalVolumeRight) / finalSynthesisParameters.uiToGo; |
841 |
|
#else |
842 |
|
finalSynthesisParameters.fFinalVolumeLeft = fFinalVolume * fFinalPanLeft; |
843 |
|
finalSynthesisParameters.fFinalVolumeRight = fFinalVolume * fFinalPanRight; |
844 |
|
#endif |
845 |
// render audio for one subfragment |
// render audio for one subfragment |
846 |
RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop); |
RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop); |
847 |
|
|
848 |
|
// stop the rendering if volume EG is finished |
849 |
|
if (EG1.getSegmentType() == EGADSR::segment_end) break; |
850 |
|
|
851 |
const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch; |
const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch; |
852 |
|
|
853 |
// increment envelopes' positions |
// increment envelopes' positions |
873 |
} |
} |
874 |
} |
} |
875 |
|
|
876 |
|
/** @brief Update current portamento position. |
877 |
|
* |
878 |
|
* Will be called when portamento mode is enabled to get the final |
879 |
|
* portamento position of this active voice from where the next voice(s) |
880 |
|
* might continue to slide on. |
881 |
|
* |
882 |
|
* @param itNoteOffEvent - event which causes this voice to die soon |
883 |
|
*/ |
884 |
|
void Voice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) { |
885 |
|
const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos()); |
886 |
|
pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f; |
887 |
|
} |
888 |
|
|
889 |
/** |
/** |
890 |
* Immediately kill the voice. This method should not be used to kill |
* Immediately kill the voice. This method should not be used to kill |
891 |
* a normal, active voice, because it doesn't take care of things like |
* a normal, active voice, because it doesn't take care of things like |