21 |
* MA 02111-1307 USA * |
* MA 02111-1307 USA * |
22 |
***************************************************************************/ |
***************************************************************************/ |
23 |
|
|
|
#include "EGADSR.h" |
|
|
#include "Manipulator.h" |
|
24 |
#include "../../common/Features.h" |
#include "../../common/Features.h" |
25 |
#include "Synthesizer.h" |
#include "Synthesizer.h" |
26 |
|
|
30 |
|
|
31 |
const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff()); |
const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff()); |
32 |
|
|
|
const int Voice::FILTER_UPDATE_MASK(CalculateFilterUpdateMask()); |
|
|
|
|
33 |
float Voice::CalculateFilterCutoffCoeff() { |
float Voice::CalculateFilterCutoffCoeff() { |
34 |
return log(CONFIG_FILTER_CUTOFF_MAX / CONFIG_FILTER_CUTOFF_MIN); |
return log(CONFIG_FILTER_CUTOFF_MAX / CONFIG_FILTER_CUTOFF_MIN); |
35 |
} |
} |
36 |
|
|
|
int Voice::CalculateFilterUpdateMask() { |
|
|
if (CONFIG_FILTER_UPDATE_STEPS <= 0) return 0; |
|
|
int power_of_two; |
|
|
for (power_of_two = 0; 1<<power_of_two < CONFIG_FILTER_UPDATE_STEPS; power_of_two++); |
|
|
return (1 << power_of_two) - 1; |
|
|
} |
|
|
|
|
37 |
Voice::Voice() { |
Voice::Voice() { |
38 |
pEngine = NULL; |
pEngine = NULL; |
39 |
pDiskThread = NULL; |
pDiskThread = NULL; |
40 |
PlaybackState = playback_state_end; |
PlaybackState = playback_state_end; |
41 |
pEG1 = NULL; |
pLFO1 = new LFOUnsigned(1.0f); // amplitude EG (0..1 range) |
42 |
pEG2 = NULL; |
pLFO2 = new LFOUnsigned(1.0f); // filter EG (0..1 range) |
43 |
pEG3 = NULL; |
pLFO3 = new LFOSigned(1200.0f); // pitch EG (-1200..+1200 range) |
|
pVCAManipulator = NULL; |
|
|
pVCFCManipulator = NULL; |
|
|
pVCOManipulator = NULL; |
|
|
pLFO1 = NULL; |
|
|
pLFO2 = NULL; |
|
|
pLFO3 = NULL; |
|
44 |
KeyGroup = 0; |
KeyGroup = 0; |
45 |
SynthesisMode = 0; // set all mode bits to 0 first |
SynthesisMode = 0; // set all mode bits to 0 first |
46 |
// select synthesis implementation (currently either pure C++ or MMX+SSE(1)) |
// select synthesis implementation (currently either pure C++ or MMX+SSE(1)) |
56 |
} |
} |
57 |
|
|
58 |
Voice::~Voice() { |
Voice::~Voice() { |
|
if (pEG1) delete pEG1; |
|
|
if (pEG2) delete pEG2; |
|
|
if (pEG3) delete pEG3; |
|
59 |
if (pLFO1) delete pLFO1; |
if (pLFO1) delete pLFO1; |
60 |
if (pLFO2) delete pLFO2; |
if (pLFO2) delete pLFO2; |
61 |
if (pLFO3) delete pLFO3; |
if (pLFO3) delete pLFO3; |
|
if (pVCAManipulator) delete pVCAManipulator; |
|
|
if (pVCFCManipulator) delete pVCFCManipulator; |
|
|
if (pVCOManipulator) delete pVCOManipulator; |
|
62 |
} |
} |
63 |
|
|
64 |
void Voice::SetEngine(Engine* pEngine) { |
void Voice::SetEngine(Engine* pEngine) { |
65 |
this->pEngine = pEngine; |
this->pEngine = pEngine; |
|
|
|
|
// delete old objects |
|
|
if (pEG1) delete pEG1; |
|
|
if (pEG2) delete pEG2; |
|
|
if (pEG3) delete pEG3; |
|
|
if (pVCAManipulator) delete pVCAManipulator; |
|
|
if (pVCFCManipulator) delete pVCFCManipulator; |
|
|
if (pVCOManipulator) delete pVCOManipulator; |
|
|
if (pLFO1) delete pLFO1; |
|
|
if (pLFO2) delete pLFO2; |
|
|
if (pLFO3) delete pLFO3; |
|
|
|
|
|
// create new ones |
|
|
pEG1 = new EGADSR(pEngine, Event::destination_vca); |
|
|
pEG2 = new EGADSR(pEngine, Event::destination_vcfc); |
|
|
pEG3 = new EGDecay(pEngine, Event::destination_vco); |
|
|
pVCAManipulator = new VCAManipulator(pEngine); |
|
|
pVCFCManipulator = new VCFCManipulator(pEngine); |
|
|
pVCOManipulator = new VCOManipulator(pEngine); |
|
|
pLFO1 = new LFO<gig::VCAManipulator>(0.0f, 1.0f, LFO<VCAManipulator>::propagation_top_down, pVCAManipulator, pEngine->pEventPool); |
|
|
pLFO2 = new LFO<gig::VCFCManipulator>(0.0f, 1.0f, LFO<VCFCManipulator>::propagation_top_down, pVCFCManipulator, pEngine->pEventPool); |
|
|
pLFO3 = new LFO<gig::VCOManipulator>(-1200.0f, 1200.0f, LFO<VCOManipulator>::propagation_middle_balanced, pVCOManipulator, pEngine->pEventPool); // +-1 octave (+-1200 cents) max. |
|
|
|
|
66 |
this->pDiskThread = pEngine->pDiskThread; |
this->pDiskThread = pEngine->pDiskThread; |
67 |
dmsg(6,("Voice::SetEngine()\n")); |
dmsg(6,("Voice::SetEngine()\n")); |
68 |
} |
} |
176 |
{ |
{ |
177 |
double pitchbasecents = pDimRgn->FineTune + (int) pEngine->ScaleTuning[MIDIKey % 12]; |
double pitchbasecents = pDimRgn->FineTune + (int) pEngine->ScaleTuning[MIDIKey % 12]; |
178 |
if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100; |
if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100; |
179 |
this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate())); |
this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->SampleRate)); |
180 |
this->PitchBend = RTMath::CentsToFreqRatio(((double) PitchBend / 8192.0) * 200.0); // pitchbend wheel +-2 semitones = 200 cents |
this->PitchBend = RTMath::CentsToFreqRatio(((double) PitchBend / 8192.0) * 200.0); // pitchbend wheel +-2 semitones = 200 cents |
181 |
} |
} |
182 |
|
|
211 |
double eg1decay = (pDimRgn->EG1ControllerDecayInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence) * eg1controllervalue : 1.0; |
double eg1decay = (pDimRgn->EG1ControllerDecayInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence) * eg1controllervalue : 1.0; |
212 |
double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 1.0; |
double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 1.0; |
213 |
|
|
214 |
pEG1->Trigger(pDimRgn->EG1PreAttack, |
EG1.trigger(pDimRgn->EG1PreAttack, |
215 |
pDimRgn->EG1Attack * eg1attack, |
pDimRgn->EG1Attack * eg1attack, |
216 |
pDimRgn->EG1Hold, |
pDimRgn->EG1Hold, |
217 |
pSample->LoopStart, |
pSample->LoopStart, |
218 |
pDimRgn->EG1Decay1 * eg1decay * velrelease, |
pDimRgn->EG1Decay1 * eg1decay * velrelease, |
219 |
pDimRgn->EG1Decay2 * eg1decay * velrelease, |
pDimRgn->EG1Decay2 * eg1decay * velrelease, |
220 |
pDimRgn->EG1InfiniteSustain, |
pDimRgn->EG1InfiniteSustain, |
221 |
pDimRgn->EG1Sustain, |
pDimRgn->EG1Sustain, |
222 |
pDimRgn->EG1Release * eg1release * velrelease, |
pDimRgn->EG1Release * eg1release * velrelease, |
223 |
// the SSE synthesis implementation requires |
velocityAttenuation, |
224 |
// the vca start to be 16 byte aligned |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
SYNTHESIS_MODE_GET_IMPLEMENTATION(SynthesisMode) ? |
|
|
Delay & 0xfffffffc : Delay, |
|
|
velocityAttenuation); |
|
225 |
} |
} |
226 |
|
|
227 |
|
|
250 |
double eg2decay = (pDimRgn->EG2ControllerDecayInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerDecayInfluence) * eg2controllervalue : 1.0; |
double eg2decay = (pDimRgn->EG2ControllerDecayInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerDecayInfluence) * eg2controllervalue : 1.0; |
251 |
double eg2release = (pDimRgn->EG2ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerReleaseInfluence) * eg2controllervalue : 1.0; |
double eg2release = (pDimRgn->EG2ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerReleaseInfluence) * eg2controllervalue : 1.0; |
252 |
|
|
253 |
pEG2->Trigger(pDimRgn->EG2PreAttack, |
EG2.trigger(pDimRgn->EG2PreAttack, |
254 |
pDimRgn->EG2Attack * eg2attack, |
pDimRgn->EG2Attack * eg2attack, |
255 |
false, |
false, |
256 |
pSample->LoopStart, |
pSample->LoopStart, |
257 |
pDimRgn->EG2Decay1 * eg2decay * velrelease, |
pDimRgn->EG2Decay1 * eg2decay * velrelease, |
258 |
pDimRgn->EG2Decay2 * eg2decay * velrelease, |
pDimRgn->EG2Decay2 * eg2decay * velrelease, |
259 |
pDimRgn->EG2InfiniteSustain, |
pDimRgn->EG2InfiniteSustain, |
260 |
pDimRgn->EG2Sustain, |
pDimRgn->EG2Sustain, |
261 |
pDimRgn->EG2Release * eg2release * velrelease, |
pDimRgn->EG2Release * eg2release * velrelease, |
262 |
Delay, |
velocityAttenuation, |
263 |
velocityAttenuation); |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
264 |
} |
} |
265 |
|
|
266 |
|
|
267 |
// setup EG 3 (VCO EG) |
// setup EG 3 (VCO EG) |
268 |
{ |
{ |
269 |
double eg3depth = RTMath::CentsToFreqRatio(pDimRgn->EG3Depth); |
double eg3depth = RTMath::CentsToFreqRatio(pDimRgn->EG3Depth); |
270 |
pEG3->Trigger(eg3depth, pDimRgn->EG3Attack, Delay); |
EG3.trigger(eg3depth, pDimRgn->EG3Attack, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
271 |
} |
} |
272 |
|
|
273 |
|
|
305 |
pLFO1->ExtController = 0; // no external controller |
pLFO1->ExtController = 0; // no external controller |
306 |
bLFO1Enabled = false; |
bLFO1Enabled = false; |
307 |
} |
} |
308 |
if (bLFO1Enabled) pLFO1->Trigger(pDimRgn->LFO1Frequency, |
if (bLFO1Enabled) pLFO1->trigger(pDimRgn->LFO1Frequency, |
309 |
|
start_level_max, |
310 |
lfo1_internal_depth, |
lfo1_internal_depth, |
311 |
pDimRgn->LFO1ControlDepth, |
pDimRgn->LFO1ControlDepth, |
|
pEngineChannel->ControllerTable[pLFO1->ExtController], |
|
312 |
pDimRgn->LFO1FlipPhase, |
pDimRgn->LFO1FlipPhase, |
313 |
pEngine->SampleRate, |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
Delay); |
|
314 |
} |
} |
315 |
|
|
316 |
|
|
348 |
pLFO2->ExtController = 0; // no external controller |
pLFO2->ExtController = 0; // no external controller |
349 |
bLFO2Enabled = false; |
bLFO2Enabled = false; |
350 |
} |
} |
351 |
if (bLFO2Enabled) pLFO2->Trigger(pDimRgn->LFO2Frequency, |
if (bLFO2Enabled) pLFO2->trigger(pDimRgn->LFO2Frequency, |
352 |
|
start_level_max, |
353 |
lfo2_internal_depth, |
lfo2_internal_depth, |
354 |
pDimRgn->LFO2ControlDepth, |
pDimRgn->LFO2ControlDepth, |
|
pEngineChannel->ControllerTable[pLFO2->ExtController], |
|
355 |
pDimRgn->LFO2FlipPhase, |
pDimRgn->LFO2FlipPhase, |
356 |
pEngine->SampleRate, |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
Delay); |
|
357 |
} |
} |
358 |
|
|
359 |
|
|
391 |
pLFO3->ExtController = 0; // no external controller |
pLFO3->ExtController = 0; // no external controller |
392 |
bLFO3Enabled = false; |
bLFO3Enabled = false; |
393 |
} |
} |
394 |
if (bLFO3Enabled) pLFO3->Trigger(pDimRgn->LFO3Frequency, |
if (bLFO3Enabled) pLFO3->trigger(pDimRgn->LFO3Frequency, |
395 |
|
start_level_mid, |
396 |
lfo3_internal_depth, |
lfo3_internal_depth, |
397 |
pDimRgn->LFO3ControlDepth, |
pDimRgn->LFO3ControlDepth, |
|
pEngineChannel->ControllerTable[pLFO3->ExtController], |
|
398 |
false, |
false, |
399 |
pEngine->SampleRate, |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
Delay); |
|
400 |
} |
} |
401 |
|
|
402 |
|
|
508 |
|
|
509 |
VCFCutoffCtrl.fvalue = cutoff - CONFIG_FILTER_CUTOFF_MIN; |
VCFCutoffCtrl.fvalue = cutoff - CONFIG_FILTER_CUTOFF_MIN; |
510 |
VCFResonanceCtrl.fvalue = resonance; |
VCFResonanceCtrl.fvalue = resonance; |
|
|
|
|
FilterUpdateCounter = -1; |
|
511 |
} |
} |
512 |
else { |
else { |
513 |
VCFCutoffCtrl.controller = 0; |
VCFCutoffCtrl.controller = 0; |
531 |
void Voice::Render(uint Samples) { |
void Voice::Render(uint Samples) { |
532 |
|
|
533 |
// select default values for synthesis mode bits |
// select default values for synthesis mode bits |
|
SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, (PitchBase * PitchBend) != 1.0f); |
|
|
SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, true); |
|
534 |
SYNTHESIS_MODE_SET_LOOP(SynthesisMode, false); |
SYNTHESIS_MODE_SET_LOOP(SynthesisMode, false); |
535 |
|
|
|
// Reset the synthesis parameter matrix |
|
|
|
|
|
#if CONFIG_PROCESS_MUTED_CHANNELS |
|
|
pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume)); |
|
|
#else |
|
|
pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngineChannel->GlobalVolume); |
|
|
#endif |
|
|
pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase); |
|
|
pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue); |
|
|
pEngine->ResetSynthesisParameters(Event::destination_vcfr, VCFResonanceCtrl.fvalue); |
|
|
|
|
|
// Apply events to the synthesis parameter matrix |
|
|
ProcessEvents(Samples); |
|
|
|
|
|
// Let all modulators write their parameter changes to the synthesis parameter matrix for the current audio fragment |
|
|
pEG1->Process(Samples, pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend, itKillEvent); |
|
|
pEG2->Process(Samples, pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend); |
|
|
if (pEG3->Process(Samples)) { // if pitch EG is active |
|
|
SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true); |
|
|
SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false); |
|
|
} |
|
|
if (bLFO1Enabled) pLFO1->Process(Samples); |
|
|
if (bLFO2Enabled) pLFO2->Process(Samples); |
|
|
if (bLFO3Enabled) { |
|
|
if (pLFO3->Process(Samples)) { // if pitch LFO modulation is active |
|
|
SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true); |
|
|
SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false); |
|
|
} |
|
|
} |
|
|
|
|
|
if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) |
|
|
CalculateBiquadParameters(Samples); // calculate the final biquad filter parameters |
|
|
|
|
536 |
switch (this->PlaybackState) { |
switch (this->PlaybackState) { |
537 |
|
|
538 |
case playback_state_init: |
case playback_state_init: |
607 |
break; |
break; |
608 |
} |
} |
609 |
|
|
610 |
// Reset synthesis event lists (except VCO, as VCO events apply channel wide currently) |
// Reset synthesis event lists |
611 |
pEngineChannel->pSynthesisEvents[Event::destination_vca]->clear(); |
pEngineChannel->pEvents->clear(); |
|
pEngineChannel->pSynthesisEvents[Event::destination_vcfc]->clear(); |
|
|
pEngineChannel->pSynthesisEvents[Event::destination_vcfr]->clear(); |
|
612 |
|
|
613 |
// Reset delay |
// Reset delay |
614 |
Delay = 0; |
Delay = 0; |
616 |
itTriggerEvent = Pool<Event>::Iterator(); |
itTriggerEvent = Pool<Event>::Iterator(); |
617 |
|
|
618 |
// If sample stream or release stage finished, kill the voice |
// If sample stream or release stage finished, kill the voice |
619 |
if (PlaybackState == playback_state_end || pEG1->GetStage() == EGADSR::stage_end) KillImmediately(); |
if (PlaybackState == playback_state_end || EG1.getSegmentType() == EGADSR::segment_end) KillImmediately(); |
620 |
} |
} |
621 |
|
|
622 |
/** |
/** |
624 |
* suspended / not running. |
* suspended / not running. |
625 |
*/ |
*/ |
626 |
void Voice::Reset() { |
void Voice::Reset() { |
|
pLFO1->Reset(); |
|
|
pLFO2->Reset(); |
|
|
pLFO3->Reset(); |
|
627 |
FilterLeft.Reset(); |
FilterLeft.Reset(); |
628 |
FilterRight.Reset(); |
FilterRight.Reset(); |
629 |
DiskStreamRef.pStream = NULL; |
DiskStreamRef.pStream = NULL; |
636 |
} |
} |
637 |
|
|
638 |
/** |
/** |
639 |
* Process the control change event lists of the engine for the current |
* Process given list of MIDI note on, note off and sustain pedal events |
640 |
* audio fragment. Event values will be applied to the synthesis parameter |
* for the given time. |
|
* matrix. |
|
641 |
* |
* |
642 |
* @param Samples - number of samples to be rendered in this audio fragment cycle |
* @param itEvent - iterator pointing to the next event to be processed |
643 |
|
* @param End - youngest time stamp where processing should be stopped |
644 |
*/ |
*/ |
645 |
void Voice::ProcessEvents(uint Samples) { |
void Voice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) { |
646 |
|
for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) { |
647 |
// dispatch control change events |
if (itEvent->Type == Event::type_release) { |
648 |
RTList<Event>::Iterator itCCEvent = pEngineChannel->pCCEvents->first(); |
EG1.update(EGADSR::event_release, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
649 |
if (Delay) { // skip events that happened before this voice was triggered |
EG2.update(EGADSR::event_release, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
650 |
while (itCCEvent && itCCEvent->FragmentPos() <= Delay) ++itCCEvent; |
} else if (itEvent->Type == Event::type_cancel_release) { |
651 |
} |
EG1.update(EGADSR::event_cancel_release, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
652 |
while (itCCEvent) { |
EG2.update(EGADSR::event_cancel_release, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
if (itCCEvent->Param.CC.Controller) { // if valid MIDI controller |
|
|
if (itCCEvent->Param.CC.Controller == VCFCutoffCtrl.controller) { |
|
|
*pEngineChannel->pSynthesisEvents[Event::destination_vcfc]->allocAppend() = *itCCEvent; |
|
|
} |
|
|
if (itCCEvent->Param.CC.Controller == VCFResonanceCtrl.controller) { |
|
|
*pEngineChannel->pSynthesisEvents[Event::destination_vcfr]->allocAppend() = *itCCEvent; |
|
|
} |
|
|
if (itCCEvent->Param.CC.Controller == pLFO1->ExtController) { |
|
|
pLFO1->SendEvent(itCCEvent); |
|
|
} |
|
|
if (itCCEvent->Param.CC.Controller == pLFO2->ExtController) { |
|
|
pLFO2->SendEvent(itCCEvent); |
|
|
} |
|
|
if (itCCEvent->Param.CC.Controller == pLFO3->ExtController) { |
|
|
pLFO3->SendEvent(itCCEvent); |
|
|
} |
|
|
if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange && |
|
|
itCCEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) { // if crossfade event |
|
|
*pEngineChannel->pSynthesisEvents[Event::destination_vca]->allocAppend() = *itCCEvent; |
|
|
} |
|
653 |
} |
} |
|
|
|
|
++itCCEvent; |
|
654 |
} |
} |
655 |
|
} |
656 |
|
|
657 |
|
/** |
658 |
// process pitch events |
* Process given list of MIDI control change and pitch bend events for |
659 |
{ |
* the given time. |
660 |
RTList<Event>* pVCOEventList = pEngineChannel->pSynthesisEvents[Event::destination_vco]; |
* |
661 |
RTList<Event>::Iterator itVCOEvent = pVCOEventList->first(); |
* @param itEvent - iterator pointing to the next event to be processed |
662 |
if (Delay) { // skip events that happened before this voice was triggered |
* @param End - youngest time stamp where processing should be stopped |
663 |
while (itVCOEvent && itVCOEvent->FragmentPos() <= Delay) ++itVCOEvent; |
*/ |
664 |
} |
void Voice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) { |
665 |
// apply old pitchbend value until first pitch event occurs |
for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) { |
666 |
if (this->PitchBend != 1.0) { |
if (itEvent->Type == Event::type_control_change && |
667 |
uint end = (itVCOEvent) ? itVCOEvent->FragmentPos() : Samples; |
itEvent->Param.CC.Controller) { // if (valid) MIDI control change event |
668 |
for (uint i = Delay; i < end; i++) { |
if (itEvent->Param.CC.Controller == VCFCutoffCtrl.controller) { |
669 |
pEngine->pSynthesisParameters[Event::destination_vco][i] *= this->PitchBend; |
processCutoffEvent(itEvent); |
670 |
|
} |
671 |
|
if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) { |
672 |
|
processResonanceEvent(itEvent); |
673 |
} |
} |
674 |
} |
if (itEvent->Param.CC.Controller == pLFO1->ExtController) { |
675 |
float pitch; |
pLFO1->update(itEvent->Param.CC.Value); |
|
while (itVCOEvent) { |
|
|
RTList<Event>::Iterator itNextVCOEvent = itVCOEvent; |
|
|
++itNextVCOEvent; |
|
|
|
|
|
// calculate the influence length of this event (in sample points) |
|
|
uint end = (itNextVCOEvent) ? itNextVCOEvent->FragmentPos() : Samples; |
|
|
|
|
|
pitch = RTMath::CentsToFreqRatio(((double) itVCOEvent->Param.Pitch.Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents |
|
|
|
|
|
// apply pitch value to the pitch parameter sequence |
|
|
for (uint i = itVCOEvent->FragmentPos(); i < end; i++) { |
|
|
pEngine->pSynthesisParameters[Event::destination_vco][i] *= pitch; |
|
676 |
} |
} |
677 |
|
if (itEvent->Param.CC.Controller == pLFO2->ExtController) { |
678 |
itVCOEvent = itNextVCOEvent; |
pLFO2->update(itEvent->Param.CC.Value); |
|
} |
|
|
if (!pVCOEventList->isEmpty()) { |
|
|
this->PitchBend = pitch; |
|
|
SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true); |
|
|
SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false); |
|
|
} |
|
|
} |
|
|
|
|
|
// process volume / attenuation events (TODO: we only handle and _expect_ crossfade events here ATM !) |
|
|
{ |
|
|
RTList<Event>* pVCAEventList = pEngineChannel->pSynthesisEvents[Event::destination_vca]; |
|
|
RTList<Event>::Iterator itVCAEvent = pVCAEventList->first(); |
|
|
if (Delay) { // skip events that happened before this voice was triggered |
|
|
while (itVCAEvent && itVCAEvent->FragmentPos() <= Delay) ++itVCAEvent; |
|
|
} |
|
|
float crossfadevolume; |
|
|
while (itVCAEvent) { |
|
|
RTList<Event>::Iterator itNextVCAEvent = itVCAEvent; |
|
|
++itNextVCAEvent; |
|
|
|
|
|
// calculate the influence length of this event (in sample points) |
|
|
uint end = (itNextVCAEvent) ? itNextVCAEvent->FragmentPos() : Samples; |
|
|
|
|
|
crossfadevolume = CrossfadeAttenuation(itVCAEvent->Param.CC.Value); |
|
|
|
|
|
#if CONFIG_PROCESS_MUTED_CHANNELS |
|
|
float effective_volume = crossfadevolume * this->Volume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume); |
|
|
#else |
|
|
float effective_volume = crossfadevolume * this->Volume * pEngineChannel->GlobalVolume; |
|
|
#endif |
|
|
|
|
|
// apply volume value to the volume parameter sequence |
|
|
for (uint i = itVCAEvent->FragmentPos(); i < end; i++) { |
|
|
pEngine->pSynthesisParameters[Event::destination_vca][i] = effective_volume; |
|
679 |
} |
} |
680 |
|
if (itEvent->Param.CC.Controller == pLFO3->ExtController) { |
681 |
itVCAEvent = itNextVCAEvent; |
pLFO3->update(itEvent->Param.CC.Value); |
|
} |
|
|
if (!pVCAEventList->isEmpty()) this->CrossfadeVolume = crossfadevolume; |
|
|
} |
|
|
|
|
|
// process filter cutoff events |
|
|
{ |
|
|
RTList<Event>* pCutoffEventList = pEngineChannel->pSynthesisEvents[Event::destination_vcfc]; |
|
|
RTList<Event>::Iterator itCutoffEvent = pCutoffEventList->first(); |
|
|
if (Delay) { // skip events that happened before this voice was triggered |
|
|
while (itCutoffEvent && itCutoffEvent->FragmentPos() <= Delay) ++itCutoffEvent; |
|
|
} |
|
|
float cutoff; |
|
|
while (itCutoffEvent) { |
|
|
RTList<Event>::Iterator itNextCutoffEvent = itCutoffEvent; |
|
|
++itNextCutoffEvent; |
|
|
|
|
|
// calculate the influence length of this event (in sample points) |
|
|
uint end = (itNextCutoffEvent) ? itNextCutoffEvent->FragmentPos() : Samples; |
|
|
|
|
|
int cvalue = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller]; |
|
|
if (pDimRgn->VCFCutoffControllerInvert) cvalue = 127 - cvalue; |
|
|
if (cvalue < pDimRgn->VCFVelocityScale) cvalue = pDimRgn->VCFVelocityScale; |
|
|
cutoff = CutoffBase * float(cvalue) * 0.00787402f; // (1 / 127) |
|
|
if (cutoff > 1.0) cutoff = 1.0; |
|
|
cutoff = exp(cutoff * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MIN - CONFIG_FILTER_CUTOFF_MIN; |
|
|
|
|
|
// apply cutoff frequency to the cutoff parameter sequence |
|
|
for (uint i = itCutoffEvent->FragmentPos(); i < end; i++) { |
|
|
pEngine->pSynthesisParameters[Event::destination_vcfc][i] = cutoff; |
|
682 |
} |
} |
683 |
|
if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange && |
684 |
itCutoffEvent = itNextCutoffEvent; |
itEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) { |
685 |
} |
processCrossFadeEvent(itEvent); |
|
if (!pCutoffEventList->isEmpty()) VCFCutoffCtrl.fvalue = cutoff; // needed for initialization of parameter matrix next time |
|
|
} |
|
|
|
|
|
// process filter resonance events |
|
|
{ |
|
|
RTList<Event>* pResonanceEventList = pEngineChannel->pSynthesisEvents[Event::destination_vcfr]; |
|
|
RTList<Event>::Iterator itResonanceEvent = pResonanceEventList->first(); |
|
|
if (Delay) { // skip events that happened before this voice was triggered |
|
|
while (itResonanceEvent && itResonanceEvent->FragmentPos() <= Delay) ++itResonanceEvent; |
|
|
} |
|
|
while (itResonanceEvent) { |
|
|
RTList<Event>::Iterator itNextResonanceEvent = itResonanceEvent; |
|
|
++itNextResonanceEvent; |
|
|
|
|
|
// calculate the influence length of this event (in sample points) |
|
|
uint end = (itNextResonanceEvent) ? itNextResonanceEvent->FragmentPos() : Samples; |
|
|
|
|
|
// convert absolute controller value to differential |
|
|
int ctrldelta = itResonanceEvent->Param.CC.Value - VCFResonanceCtrl.value; |
|
|
VCFResonanceCtrl.value = itResonanceEvent->Param.CC.Value; |
|
|
|
|
|
float resonancedelta = (float) ctrldelta * 0.00787f; // 0.0..1.0 |
|
|
|
|
|
// apply cutoff frequency to the cutoff parameter sequence |
|
|
for (uint i = itResonanceEvent->FragmentPos(); i < end; i++) { |
|
|
pEngine->pSynthesisParameters[Event::destination_vcfr][i] += resonancedelta; |
|
686 |
} |
} |
687 |
|
} else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event |
688 |
itResonanceEvent = itNextResonanceEvent; |
processPitchEvent(itEvent); |
689 |
} |
} |
|
if (!pResonanceEventList->isEmpty()) VCFResonanceCtrl.fvalue = pResonanceEventList->last()->Param.CC.Value * 0.00787f; // needed for initialization of parameter matrix next time |
|
690 |
} |
} |
691 |
} |
} |
692 |
|
|
693 |
/** |
void Voice::processPitchEvent(RTList<Event>::Iterator& itEvent) { |
694 |
* Calculate all necessary, final biquad filter parameters. |
const float pitch = RTMath::CentsToFreqRatio(((double) itEvent->Param.Pitch.Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents |
695 |
* |
fFinalPitch *= pitch; |
696 |
* @param Samples - number of samples to be rendered in this audio fragment cycle |
} |
|
*/ |
|
|
void Voice::CalculateBiquadParameters(uint Samples) { |
|
|
biquad_param_t bqbase; |
|
|
biquad_param_t bqmain; |
|
|
float prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][0]; |
|
|
float prev_res = pEngine->pSynthesisParameters[Event::destination_vcfr][0]; |
|
|
FilterLeft.SetParameters( &bqbase, &bqmain, prev_cutoff + CONFIG_FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate); |
|
|
FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff + CONFIG_FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate); |
|
|
pEngine->pBasicFilterParameters[0] = bqbase; |
|
|
pEngine->pMainFilterParameters[0] = bqmain; |
|
|
|
|
|
float* bq; |
|
|
for (int i = 1; i < Samples; i++) { |
|
|
// recalculate biquad parameters if cutoff or resonance differ from previous sample point |
|
|
if (!(i & FILTER_UPDATE_MASK)) { |
|
|
if (pEngine->pSynthesisParameters[Event::destination_vcfr][i] != prev_res || |
|
|
pEngine->pSynthesisParameters[Event::destination_vcfc][i] != prev_cutoff) |
|
|
{ |
|
|
prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i]; |
|
|
prev_res = pEngine->pSynthesisParameters[Event::destination_vcfr][i]; |
|
|
FilterLeft.SetParameters( &bqbase, &bqmain, prev_cutoff + CONFIG_FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate); |
|
|
FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff + CONFIG_FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate); |
|
|
} |
|
|
} |
|
697 |
|
|
698 |
//same as 'pEngine->pBasicFilterParameters[i] = bqbase;' |
void Voice::processCrossFadeEvent(RTList<Event>::Iterator& itEvent) { |
699 |
bq = (float*) &pEngine->pBasicFilterParameters[i]; |
CrossfadeVolume = CrossfadeAttenuation(itEvent->Param.CC.Value); |
700 |
bq[0] = bqbase.b0; |
#if CONFIG_PROCESS_MUTED_CHANNELS |
701 |
bq[1] = bqbase.b1; |
const float effectiveVolume = CrossfadeVolume * Volume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume); |
702 |
bq[2] = bqbase.b2; |
#else |
703 |
bq[3] = bqbase.a1; |
const float effectiveVolume = CrossfadeVolume * Volume * pEngineChannel->GlobalVolume; |
704 |
bq[4] = bqbase.a2; |
#endif |
705 |
|
fFinalVolume = effectiveVolume; |
706 |
// same as 'pEngine->pMainFilterParameters[i] = bqmain;' |
} |
707 |
bq = (float*) &pEngine->pMainFilterParameters[i]; |
|
708 |
bq[0] = bqmain.b0; |
void Voice::processCutoffEvent(RTList<Event>::Iterator& itEvent) { |
709 |
bq[1] = bqmain.b1; |
int ccvalue = itEvent->Param.CC.Value; |
710 |
bq[2] = bqmain.b2; |
if (VCFCutoffCtrl.value == ccvalue) return; |
711 |
bq[3] = bqmain.a1; |
VCFCutoffCtrl.value == ccvalue; |
712 |
bq[4] = bqmain.a2; |
if (pDimRgn->VCFCutoffControllerInvert) ccvalue = 127 - ccvalue; |
713 |
} |
if (ccvalue < pDimRgn->VCFVelocityScale) ccvalue = pDimRgn->VCFVelocityScale; |
714 |
|
float cutoff = CutoffBase * float(ccvalue) * 0.00787402f; // (1 / 127) |
715 |
|
if (cutoff > 1.0) cutoff = 1.0; |
716 |
|
cutoff = exp(cutoff * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MIN - CONFIG_FILTER_CUTOFF_MIN; |
717 |
|
VCFCutoffCtrl.fvalue = cutoff; // needed for initialization of fFinalCutoff next time |
718 |
|
fFinalCutoff = cutoff; |
719 |
|
} |
720 |
|
|
721 |
|
void Voice::processResonanceEvent(RTList<Event>::Iterator& itEvent) { |
722 |
|
// convert absolute controller value to differential |
723 |
|
const int ctrldelta = itEvent->Param.CC.Value - VCFResonanceCtrl.value; |
724 |
|
VCFResonanceCtrl.value = itEvent->Param.CC.Value; |
725 |
|
const float resonancedelta = (float) ctrldelta * 0.00787f; // 0.0..1.0 |
726 |
|
fFinalResonance += resonancedelta; |
727 |
|
// needed for initialization of parameter |
728 |
|
VCFResonanceCtrl.fvalue = itEvent->Param.CC.Value * 0.00787f; |
729 |
} |
} |
730 |
|
|
731 |
/** |
/** |
737 |
* @param Skip - number of sample points to skip in output buffer |
* @param Skip - number of sample points to skip in output buffer |
738 |
*/ |
*/ |
739 |
void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) { |
void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) { |
740 |
RunSynthesisFunction(SynthesisMode, *this, Samples, pSrc, Skip); |
RTList<Event>::Iterator itCCEvent = pEngineChannel->pEvents->first(); |
741 |
|
RTList<Event>::Iterator itNoteEvent = pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents->first(); |
742 |
|
|
743 |
|
if (Skip) { // skip events that happened before this voice was triggered |
744 |
|
while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent; |
745 |
|
while (itNoteEvent && itNoteEvent->FragmentPos() <= Skip) ++itNoteEvent; |
746 |
|
} |
747 |
|
|
748 |
|
uint i = Skip; |
749 |
|
while (i < Samples) { |
750 |
|
int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples); |
751 |
|
|
752 |
|
// initialize all final synthesis parameters |
753 |
|
fFinalPitch = PitchBase * PitchBend; |
754 |
|
#if CONFIG_PROCESS_MUTED_CHANNELS |
755 |
|
fFinalVolume = this->Volume * this->CrossfadeVolume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume)); |
756 |
|
#else |
757 |
|
fFinalVolume = this->Volume * this->CrossfadeVolume * pEngineChannel->GlobalVolume; |
758 |
|
#endif |
759 |
|
fFinalCutoff = VCFCutoffCtrl.fvalue; |
760 |
|
fFinalResonance = VCFResonanceCtrl.fvalue; |
761 |
|
|
762 |
|
// process MIDI control change and pitchbend events for this subfragment |
763 |
|
processCCEvents(itCCEvent, iSubFragmentEnd); |
764 |
|
|
765 |
|
// process transition events (note on, note off & sustain pedal) |
766 |
|
processTransitionEvents(itNoteEvent, iSubFragmentEnd); |
767 |
|
|
768 |
|
// process envelope generators |
769 |
|
switch (EG1.getSegmentType()) { |
770 |
|
case EGADSR::segment_lin: |
771 |
|
fFinalVolume *= EG1.processLin(); |
772 |
|
break; |
773 |
|
case EGADSR::segment_exp: |
774 |
|
fFinalVolume *= EG1.processExp(); |
775 |
|
break; |
776 |
|
case EGADSR::segment_end: |
777 |
|
fFinalVolume *= EG1.getLevel(); |
778 |
|
break; // noop |
779 |
|
} |
780 |
|
switch (EG2.getSegmentType()) { |
781 |
|
case EGADSR::segment_lin: |
782 |
|
fFinalCutoff *= EG2.processLin(); |
783 |
|
break; |
784 |
|
case EGADSR::segment_exp: |
785 |
|
fFinalCutoff *= EG2.processExp(); |
786 |
|
break; |
787 |
|
case EGADSR::segment_end: |
788 |
|
fFinalCutoff *= EG2.getLevel(); |
789 |
|
break; // noop |
790 |
|
} |
791 |
|
fFinalPitch *= RTMath::CentsToFreqRatio(EG3.render()); |
792 |
|
|
793 |
|
// process low frequency oscillators |
794 |
|
if (bLFO1Enabled) fFinalVolume *= pLFO1->render(); |
795 |
|
if (bLFO2Enabled) fFinalCutoff *= pLFO2->render(); |
796 |
|
if (bLFO3Enabled) fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render()); |
797 |
|
|
798 |
|
// if filter enabled then update filter coefficients |
799 |
|
if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) { |
800 |
|
FilterLeft.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate); |
801 |
|
FilterRight.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate); |
802 |
|
} |
803 |
|
|
804 |
|
// how many steps do we calculate for this next subfragment |
805 |
|
const int steps = iSubFragmentEnd - i; |
806 |
|
|
807 |
|
// select the appropriate synthesis mode |
808 |
|
SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, fFinalPitch != 1.0f); |
809 |
|
|
810 |
|
// render audio for one subfragment |
811 |
|
RunSynthesisFunction(SynthesisMode, *this, iSubFragmentEnd, pSrc, i); |
812 |
|
|
813 |
|
// increment envelopes' positions |
814 |
|
if (EG1.active()) { |
815 |
|
EG1.increment(steps); |
816 |
|
if (!EG1.toStageEndLeft()) EG1.update(EGADSR::event_stage_end, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
817 |
|
} |
818 |
|
if (EG2.active()) { |
819 |
|
EG2.increment(steps); |
820 |
|
if (!EG2.toStageEndLeft()) EG2.update(EGADSR::event_stage_end, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
821 |
|
} |
822 |
|
EG3.increment(steps); |
823 |
|
if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached |
824 |
|
} |
825 |
} |
} |
826 |
|
|
827 |
/** |
/** |