104 |
// calculate volume |
// calculate volume |
105 |
const double velocityAttenuation = pDimRgn->GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity); |
const double velocityAttenuation = pDimRgn->GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity); |
106 |
|
|
107 |
Volume = velocityAttenuation / 32768.0f; // we downscale by 32768 to convert from int16 value range to DSP value range (which is -1.0..1.0) |
float volume = velocityAttenuation / 32768.0f; // we downscale by 32768 to convert from int16 value range to DSP value range (which is -1.0..1.0) |
108 |
|
|
109 |
Volume *= pDimRgn->SampleAttenuation; |
volume *= pDimRgn->SampleAttenuation; |
110 |
|
|
111 |
// the volume of release triggered samples depends on note length |
// the volume of release triggered samples depends on note length |
112 |
if (Type == type_release_trigger) { |
if (Type == type_release_trigger) { |
114 |
pEngineChannel->pMIDIKeyInfo[MIDIKey].NoteOnTime) / pEngine->SampleRate; |
pEngineChannel->pMIDIKeyInfo[MIDIKey].NoteOnTime) / pEngine->SampleRate; |
115 |
float attenuation = 1 - 0.01053 * (256 >> pDimRgn->ReleaseTriggerDecay) * noteLength; |
float attenuation = 1 - 0.01053 * (256 >> pDimRgn->ReleaseTriggerDecay) * noteLength; |
116 |
if (attenuation <= 0) return -1; |
if (attenuation <= 0) return -1; |
117 |
Volume *= attenuation; |
volume *= attenuation; |
118 |
} |
} |
119 |
|
|
120 |
// select channel mode (mono or stereo) |
// select channel mode (mono or stereo) |
121 |
SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2); |
SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2); |
122 |
|
|
123 |
// get starting crossfade volume level |
// get starting crossfade volume level |
124 |
|
float crossfadeVolume; |
125 |
switch (pDimRgn->AttenuationController.type) { |
switch (pDimRgn->AttenuationController.type) { |
126 |
case ::gig::attenuation_ctrl_t::type_channelaftertouch: |
case ::gig::attenuation_ctrl_t::type_channelaftertouch: |
127 |
CrossfadeVolume = 1.0f; //TODO: aftertouch not supported yet |
crossfadeVolume = 1.0f; //TODO: aftertouch not supported yet |
128 |
break; |
break; |
129 |
case ::gig::attenuation_ctrl_t::type_velocity: |
case ::gig::attenuation_ctrl_t::type_velocity: |
130 |
CrossfadeVolume = CrossfadeAttenuation(itNoteOnEvent->Param.Note.Velocity); |
crossfadeVolume = Engine::CrossfadeCurve[CrossfadeAttenuation(itNoteOnEvent->Param.Note.Velocity)]; |
131 |
break; |
break; |
132 |
case ::gig::attenuation_ctrl_t::type_controlchange: //FIXME: currently not sample accurate |
case ::gig::attenuation_ctrl_t::type_controlchange: //FIXME: currently not sample accurate |
133 |
CrossfadeVolume = CrossfadeAttenuation(pEngineChannel->ControllerTable[pDimRgn->AttenuationController.controller_number]); |
crossfadeVolume = Engine::CrossfadeCurve[CrossfadeAttenuation(pEngineChannel->ControllerTable[pDimRgn->AttenuationController.controller_number])]; |
134 |
break; |
break; |
135 |
case ::gig::attenuation_ctrl_t::type_none: // no crossfade defined |
case ::gig::attenuation_ctrl_t::type_none: // no crossfade defined |
136 |
default: |
default: |
137 |
CrossfadeVolume = 1.0f; |
crossfadeVolume = 1.0f; |
138 |
} |
} |
139 |
|
|
140 |
PanLeft = Engine::PanCurve[64 - pDimRgn->Pan]; |
VolumeLeft = volume * Engine::PanCurve[64 - pDimRgn->Pan]; |
141 |
PanRight = Engine::PanCurve[64 + pDimRgn->Pan]; |
VolumeRight = volume * Engine::PanCurve[64 + pDimRgn->Pan]; |
142 |
|
|
143 |
|
float subfragmentRate = pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE; |
144 |
|
CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate); |
145 |
|
VolumeSmoother.trigger(pEngineChannel->GlobalVolume, subfragmentRate); |
146 |
|
PanLeftSmoother.trigger(pEngineChannel->GlobalPanLeft, subfragmentRate); |
147 |
|
PanRightSmoother.trigger(pEngineChannel->GlobalPanRight, subfragmentRate); |
148 |
|
|
149 |
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) |
150 |
Pos = pDimRgn->SampleStartOffset; |
Pos = pDimRgn->SampleStartOffset; |
230 |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
231 |
} |
} |
232 |
|
|
233 |
|
#ifdef CONFIG_INTERPOLATE_VOLUME |
234 |
// setup initial volume in synthesis parameters |
// setup initial volume in synthesis parameters |
235 |
fFinalVolume = getVolume() * EG1.getLevel(); |
#ifdef CONFIG_PROCESS_MUTED_CHANNELS |
236 |
finalSynthesisParameters.fFinalVolumeLeft = fFinalVolume * PanLeft * pEngineChannel->GlobalPanLeft; |
if (pEngineChannel->GetMute()) { |
237 |
finalSynthesisParameters.fFinalVolumeRight = fFinalVolume * PanRight * pEngineChannel->GlobalPanRight; |
finalSynthesisParameters.fFinalVolumeLeft = 0; |
238 |
|
finalSynthesisParameters.fFinalVolumeRight = 0; |
239 |
|
} |
240 |
|
else |
241 |
|
#else |
242 |
|
{ |
243 |
|
float finalVolume = pEngineChannel->GlobalVolume * crossfadeVolume * EG1.getLevel(); |
244 |
|
|
245 |
|
finalSynthesisParameters.fFinalVolumeLeft = finalVolume * VolumeLeft * pEngineChannel->GlobalPanLeft; |
246 |
|
finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight; |
247 |
|
} |
248 |
|
#endif |
249 |
|
#endif |
250 |
|
|
251 |
// setup EG 2 (VCF Cutoff EG) |
// setup EG 2 (VCF Cutoff EG) |
252 |
{ |
{ |
664 |
* for the given time. |
* for the given time. |
665 |
* |
* |
666 |
* @param itEvent - iterator pointing to the next event to be processed |
* @param itEvent - iterator pointing to the next event to be processed |
667 |
* @param End - youngest time stamp where processing should be stopped |
* @param End - youngest time stamp where processing should be stopped |
668 |
*/ |
*/ |
669 |
void Voice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) { |
void Voice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) { |
670 |
for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) { |
for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) { |
683 |
* the given time. |
* the given time. |
684 |
* |
* |
685 |
* @param itEvent - iterator pointing to the next event to be processed |
* @param itEvent - iterator pointing to the next event to be processed |
686 |
* @param End - youngest time stamp where processing should be stopped |
* @param End - youngest time stamp where processing should be stopped |
687 |
*/ |
*/ |
688 |
void Voice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) { |
void Voice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) { |
689 |
for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) { |
for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) { |
706 |
} |
} |
707 |
if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange && |
if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange && |
708 |
itEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) { |
itEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) { |
709 |
processCrossFadeEvent(itEvent); |
CrossfadeSmoother.update(Engine::CrossfadeCurve[CrossfadeAttenuation(itEvent->Param.CC.Value)]); |
710 |
|
} |
711 |
|
if (itEvent->Param.CC.Controller == 7) { // volume |
712 |
|
VolumeSmoother.update(Engine::VolumeCurve[itEvent->Param.CC.Value] * CONFIG_GLOBAL_ATTENUATION); |
713 |
|
} else if (itEvent->Param.CC.Controller == 10) { // panpot |
714 |
|
PanLeftSmoother.update(Engine::PanCurve[128 - itEvent->Param.CC.Value]); |
715 |
|
PanRightSmoother.update(Engine::PanCurve[itEvent->Param.CC.Value]); |
716 |
} |
} |
717 |
} else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event |
} else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event |
718 |
processPitchEvent(itEvent); |
processPitchEvent(itEvent); |
726 |
PitchBend = pitch; |
PitchBend = pitch; |
727 |
} |
} |
728 |
|
|
|
void Voice::processCrossFadeEvent(RTList<Event>::Iterator& itEvent) { |
|
|
CrossfadeVolume = CrossfadeAttenuation(itEvent->Param.CC.Value); |
|
|
fFinalVolume = getVolume(); |
|
|
} |
|
|
|
|
|
float Voice::getVolume() { |
|
|
#if CONFIG_PROCESS_MUTED_CHANNELS |
|
|
return pEngineChannel->GetMute() ? 0 : (Volume * CrossfadeVolume * pEngineChannel->GlobalVolume); |
|
|
#else |
|
|
return Volume * CrossfadeVolume * pEngineChannel->GlobalVolume; |
|
|
#endif |
|
|
} |
|
|
|
|
729 |
void Voice::processCutoffEvent(RTList<Event>::Iterator& itEvent) { |
void Voice::processCutoffEvent(RTList<Event>::Iterator& itEvent) { |
730 |
int ccvalue = itEvent->Param.CC.Value; |
int ccvalue = itEvent->Param.CC.Value; |
731 |
if (VCFCutoffCtrl.value == ccvalue) return; |
if (VCFCutoffCtrl.value == ccvalue) return; |
775 |
uint killPos; |
uint killPos; |
776 |
if (itKillEvent) killPos = RTMath::Min(itKillEvent->FragmentPos(), pEngine->MaxFadeOutPos); |
if (itKillEvent) killPos = RTMath::Min(itKillEvent->FragmentPos(), pEngine->MaxFadeOutPos); |
777 |
|
|
|
float fFinalPanLeft = PanLeft * pEngineChannel->GlobalPanLeft; |
|
|
float fFinalPanRight = PanRight * pEngineChannel->GlobalPanRight; |
|
|
|
|
778 |
uint i = Skip; |
uint i = Skip; |
779 |
while (i < Samples) { |
while (i < Samples) { |
780 |
int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples); |
int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples); |
781 |
|
|
782 |
// initialize all final synthesis parameters |
// initialize all final synthesis parameters |
783 |
finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend; |
finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend; |
|
fFinalVolume = getVolume(); |
|
784 |
fFinalCutoff = VCFCutoffCtrl.fvalue; |
fFinalCutoff = VCFCutoffCtrl.fvalue; |
785 |
fFinalResonance = VCFResonanceCtrl.fvalue; |
fFinalResonance = VCFResonanceCtrl.fvalue; |
786 |
|
|
787 |
// process MIDI control change and pitchbend events for this subfragment |
// process MIDI control change and pitchbend events for this subfragment |
788 |
processCCEvents(itCCEvent, iSubFragmentEnd); |
processCCEvents(itCCEvent, iSubFragmentEnd); |
789 |
|
|
790 |
|
float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render(); |
791 |
|
#ifdef CONFIG_PROCESS_MUTED_CHANNELS |
792 |
|
if (pEngineChannel->GetMute()) fFinalVolume = 0; |
793 |
|
#endif |
794 |
|
|
795 |
// process transition events (note on, note off & sustain pedal) |
// process transition events (note on, note off & sustain pedal) |
796 |
processTransitionEvents(itNoteEvent, iSubFragmentEnd); |
processTransitionEvents(itNoteEvent, iSubFragmentEnd); |
797 |
|
|
848 |
finalSynthesisParameters.uiToGo = iSubFragmentEnd - i; |
finalSynthesisParameters.uiToGo = iSubFragmentEnd - i; |
849 |
#ifdef CONFIG_INTERPOLATE_VOLUME |
#ifdef CONFIG_INTERPOLATE_VOLUME |
850 |
finalSynthesisParameters.fFinalVolumeDeltaLeft = |
finalSynthesisParameters.fFinalVolumeDeltaLeft = |
851 |
(fFinalVolume * fFinalPanLeft - finalSynthesisParameters.fFinalVolumeLeft) / finalSynthesisParameters.uiToGo; |
(fFinalVolume * VolumeLeft * PanLeftSmoother.render() - |
852 |
|
finalSynthesisParameters.fFinalVolumeLeft) / finalSynthesisParameters.uiToGo; |
853 |
finalSynthesisParameters.fFinalVolumeDeltaRight = |
finalSynthesisParameters.fFinalVolumeDeltaRight = |
854 |
(fFinalVolume * fFinalPanRight - finalSynthesisParameters.fFinalVolumeRight) / finalSynthesisParameters.uiToGo; |
(fFinalVolume * VolumeRight * PanRightSmoother.render() - |
855 |
|
finalSynthesisParameters.fFinalVolumeRight) / finalSynthesisParameters.uiToGo; |
856 |
#else |
#else |
857 |
finalSynthesisParameters.fFinalVolumeLeft = fFinalVolume * fFinalPanLeft; |
finalSynthesisParameters.fFinalVolumeLeft = |
858 |
finalSynthesisParameters.fFinalVolumeRight = fFinalVolume * fFinalPanRight; |
fFinalVolume * VolumeLeft * PanLeftSmoother.render(); |
859 |
|
finalSynthesisParameters.fFinalVolumeRight = |
860 |
|
fFinalVolume * VolumeRight * PanRightSmoother.render(); |
861 |
#endif |
#endif |
862 |
// render audio for one subfragment |
// render audio for one subfragment |
863 |
RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop); |
RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop); |