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_MIN / CONFIG_FILTER_CUTOFF_MAX); |
return log(CONFIG_FILTER_CUTOFF_MAX / CONFIG_FILTER_CUTOFF_MIN); |
|
} |
|
|
|
|
|
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; |
|
35 |
} |
} |
36 |
|
|
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)) |
47 |
#if ARCH_X86 |
#if CONFIG_ASM && ARCH_X86 |
48 |
SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, Features::supportsMMX() && Features::supportsSSE()); |
SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, Features::supportsMMX() && Features::supportsSSE()); |
49 |
#else |
#else |
50 |
SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false); |
SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false); |
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 |
} |
} |
71 |
* Initializes and triggers the voice, a disk stream will be launched if |
* Initializes and triggers the voice, a disk stream will be launched if |
72 |
* needed. |
* needed. |
73 |
* |
* |
74 |
* @param pEngineChannel - engine channel on which this voice was ordered |
* @param pEngineChannel - engine channel on which this voice was ordered |
75 |
* @param itNoteOnEvent - event that caused triggering of this voice |
* @param itNoteOnEvent - event that caused triggering of this voice |
76 |
* @param PitchBend - MIDI detune factor (-8192 ... +8191) |
* @param PitchBend - MIDI detune factor (-8192 ... +8191) |
77 |
* @param pInstrument - points to the loaded instrument which provides sample wave(s) and articulation data |
* @param pDimRgn - points to the dimension region which provides sample wave(s) and articulation data |
78 |
* @param iLayer - layer number this voice refers to (only if this is a layered sound of course) |
* @param VoiceType - type of this voice |
79 |
* @param ReleaseTriggerVoice - if this new voice is a release trigger voice (optional, default = false) |
* @param iKeyGroup - a value > 0 defines a key group in which this voice is member of |
|
* @param VoiceStealingAllowed - wether the voice is allowed to steal voices for further subvoices |
|
80 |
* @returns 0 on success, a value < 0 if the voice wasn't triggered |
* @returns 0 on success, a value < 0 if the voice wasn't triggered |
81 |
* (either due to an error or e.g. because no region is |
* (either due to an error or e.g. because no region is |
82 |
* defined for the given key) |
* defined for the given key) |
83 |
*/ |
*/ |
84 |
int Voice::Trigger(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealingAllowed) { |
int Voice::Trigger(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent, int PitchBend, ::gig::DimensionRegion* pDimRgn, type_t VoiceType, int iKeyGroup) { |
85 |
this->pEngineChannel = pEngineChannel; |
this->pEngineChannel = pEngineChannel; |
86 |
if (!pInstrument) { |
this->pDimRgn = pDimRgn; |
87 |
dmsg(1,("voice::trigger: !pInstrument\n")); |
|
88 |
exit(EXIT_FAILURE); |
#if CONFIG_DEVMODE |
89 |
} |
if (itNoteOnEvent->FragmentPos() > pEngine->MaxSamplesPerCycle) { // just a sanity check for debugging |
|
if (itNoteOnEvent->FragmentPos() > pEngine->MaxSamplesPerCycle) { // FIXME: should be removed before the final release (purpose: just a sanity check for debugging) |
|
90 |
dmsg(1,("Voice::Trigger(): ERROR, TriggerDelay > Totalsamples\n")); |
dmsg(1,("Voice::Trigger(): ERROR, TriggerDelay > Totalsamples\n")); |
91 |
} |
} |
92 |
|
#endif // CONFIG_DEVMODE |
93 |
|
|
94 |
Type = type_normal; |
Type = VoiceType; |
95 |
MIDIKey = itNoteOnEvent->Param.Note.Key; |
MIDIKey = itNoteOnEvent->Param.Note.Key; |
96 |
pRegion = pInstrument->GetRegion(MIDIKey); |
PlaybackState = playback_state_init; // mark voice as triggered, but no audio rendered yet |
|
PlaybackState = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed |
|
97 |
Delay = itNoteOnEvent->FragmentPos(); |
Delay = itNoteOnEvent->FragmentPos(); |
98 |
itTriggerEvent = itNoteOnEvent; |
itTriggerEvent = itNoteOnEvent; |
99 |
itKillEvent = Pool<Event>::Iterator(); |
itKillEvent = Pool<Event>::Iterator(); |
100 |
|
KeyGroup = iKeyGroup; |
101 |
|
pSample = pDimRgn->pSample; // sample won't change until the voice is finished |
102 |
|
|
103 |
if (!pRegion) { |
// calculate volume |
104 |
dmsg(4, ("gig::Voice: No Region defined for MIDI key %d\n", MIDIKey)); |
const double velocityAttenuation = pDimRgn->GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity); |
|
return -1; |
|
|
} |
|
105 |
|
|
106 |
// only mark the first voice of a layered voice (group) to be in a |
Volume = velocityAttenuation / 32768.0f; // we downscale by 32768 to convert from int16 value range to DSP value range (which is -1.0..1.0) |
|
// key group, so the layered voices won't kill each other |
|
|
KeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0; |
|
107 |
|
|
108 |
// get current dimension values to select the right dimension region |
Volume *= pDimRgn->SampleAttenuation; |
|
//FIXME: controller values for selecting the dimension region here are currently not sample accurate |
|
|
uint DimValues[8] = { 0 }; |
|
|
for (int i = pRegion->Dimensions - 1; i >= 0; i--) { |
|
|
switch (pRegion->pDimensionDefinitions[i].dimension) { |
|
|
case ::gig::dimension_samplechannel: |
|
|
DimValues[i] = 0; //TODO: we currently ignore this dimension |
|
|
break; |
|
|
case ::gig::dimension_layer: |
|
|
DimValues[i] = iLayer; |
|
|
break; |
|
|
case ::gig::dimension_velocity: |
|
|
DimValues[i] = itNoteOnEvent->Param.Note.Velocity; |
|
|
break; |
|
|
case ::gig::dimension_channelaftertouch: |
|
|
DimValues[i] = 0; //TODO: we currently ignore this dimension |
|
|
break; |
|
|
case ::gig::dimension_releasetrigger: |
|
|
Type = (ReleaseTriggerVoice) ? type_release_trigger : (!iLayer) ? type_release_trigger_required : type_normal; |
|
|
DimValues[i] = (uint) ReleaseTriggerVoice; |
|
|
break; |
|
|
case ::gig::dimension_keyboard: |
|
|
DimValues[i] = (uint) pEngineChannel->CurrentKeyDimension; |
|
|
break; |
|
|
case ::gig::dimension_roundrobin: |
|
|
DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on |
|
|
break; |
|
|
case ::gig::dimension_random: |
|
|
pEngine->RandomSeed = pEngine->RandomSeed * 1103515245 + 12345; // classic pseudo random number generator |
|
|
DimValues[i] = (uint) pEngine->RandomSeed >> (32 - pRegion->pDimensionDefinitions[i].bits); // highest bits are most random |
|
|
break; |
|
|
case ::gig::dimension_modwheel: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[1]; |
|
|
break; |
|
|
case ::gig::dimension_breath: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[2]; |
|
|
break; |
|
|
case ::gig::dimension_foot: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[4]; |
|
|
break; |
|
|
case ::gig::dimension_portamentotime: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[5]; |
|
|
break; |
|
|
case ::gig::dimension_effect1: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[12]; |
|
|
break; |
|
|
case ::gig::dimension_effect2: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[13]; |
|
|
break; |
|
|
case ::gig::dimension_genpurpose1: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[16]; |
|
|
break; |
|
|
case ::gig::dimension_genpurpose2: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[17]; |
|
|
break; |
|
|
case ::gig::dimension_genpurpose3: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[18]; |
|
|
break; |
|
|
case ::gig::dimension_genpurpose4: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[19]; |
|
|
break; |
|
|
case ::gig::dimension_sustainpedal: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[64]; |
|
|
break; |
|
|
case ::gig::dimension_portamento: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[65]; |
|
|
break; |
|
|
case ::gig::dimension_sostenutopedal: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[66]; |
|
|
break; |
|
|
case ::gig::dimension_softpedal: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[67]; |
|
|
break; |
|
|
case ::gig::dimension_genpurpose5: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[80]; |
|
|
break; |
|
|
case ::gig::dimension_genpurpose6: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[81]; |
|
|
break; |
|
|
case ::gig::dimension_genpurpose7: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[82]; |
|
|
break; |
|
|
case ::gig::dimension_genpurpose8: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[83]; |
|
|
break; |
|
|
case ::gig::dimension_effect1depth: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[91]; |
|
|
break; |
|
|
case ::gig::dimension_effect2depth: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[92]; |
|
|
break; |
|
|
case ::gig::dimension_effect3depth: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[93]; |
|
|
break; |
|
|
case ::gig::dimension_effect4depth: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[94]; |
|
|
break; |
|
|
case ::gig::dimension_effect5depth: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[95]; |
|
|
break; |
|
|
case ::gig::dimension_none: |
|
|
std::cerr << "gig::Voice::Trigger() Error: dimension=none\n" << std::flush; |
|
|
break; |
|
|
default: |
|
|
std::cerr << "gig::Voice::Trigger() Error: Unknown dimension\n" << std::flush; |
|
|
} |
|
|
} |
|
|
pDimRgn = pRegion->GetDimensionRegionByValue(DimValues); |
|
109 |
|
|
110 |
pSample = pDimRgn->pSample; // sample won't change until the voice is finished |
// the volume of release triggered samples depends on note length |
111 |
if (!pSample || !pSample->SamplesTotal) return -1; // no need to continue if sample is silent |
if (Type == type_release_trigger) { |
112 |
|
float noteLength = float(pEngine->FrameTime + Delay - |
113 |
|
pEngineChannel->pMIDIKeyInfo[MIDIKey].NoteOnTime) / pEngine->SampleRate; |
114 |
|
float attenuation = 1 - 0.01053 * (256 >> pDimRgn->ReleaseTriggerDecay) * noteLength; |
115 |
|
if (attenuation <= 0) return -1; |
116 |
|
Volume *= attenuation; |
117 |
|
} |
118 |
|
|
119 |
// select channel mode (mono or stereo) |
// select channel mode (mono or stereo) |
120 |
SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2); |
SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2); |
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 |
|
|
183 |
Volume = pDimRgn->GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity) / 32768.0f; // we downscale by 32768 to convert from int16 value range to DSP value range (which is -1.0..1.0) |
// the length of the decay and release curves are dependent on the velocity |
184 |
|
const double velrelease = 1 / pDimRgn->GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity); |
|
Volume *= pDimRgn->SampleAttenuation; |
|
185 |
|
|
186 |
// setup EG 1 (VCA EG) |
// setup EG 1 (VCA EG) |
187 |
{ |
{ |
203 |
} |
} |
204 |
if (pDimRgn->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue; |
if (pDimRgn->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue; |
205 |
|
|
206 |
// calculate influence of EG1 controller on EG1's parameters (TODO: needs to be fine tuned) |
// calculate influence of EG1 controller on EG1's parameters |
207 |
double eg1attack = (pDimRgn->EG1ControllerAttackInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerAttackInfluence) * eg1controllervalue : 0.0; |
// (eg1attack is different from the others) |
208 |
double eg1decay = (pDimRgn->EG1ControllerDecayInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence) * eg1controllervalue : 0.0; |
double eg1attack = (pDimRgn->EG1ControllerAttackInfluence) ? |
209 |
double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 0.0; |
1 + 0.031 * (double) (pDimRgn->EG1ControllerAttackInfluence == 1 ? |
210 |
|
1 : 1 << pDimRgn->EG1ControllerAttackInfluence) * eg1controllervalue : 1.0; |
211 |
pEG1->Trigger(pDimRgn->EG1PreAttack, |
double eg1decay = (pDimRgn->EG1ControllerDecayInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence) * eg1controllervalue : 1.0; |
212 |
pDimRgn->EG1Attack + eg1attack, |
double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 1.0; |
213 |
pDimRgn->EG1Hold, |
|
214 |
pSample->LoopStart, |
EG1.trigger(pDimRgn->EG1PreAttack, |
215 |
pDimRgn->EG1Decay1 + eg1decay, |
pDimRgn->EG1Attack * eg1attack, |
216 |
pDimRgn->EG1Decay2 + eg1decay, |
pDimRgn->EG1Hold, |
217 |
pDimRgn->EG1InfiniteSustain, |
pSample->LoopStart, |
218 |
pDimRgn->EG1Sustain, |
pDimRgn->EG1Decay1 * eg1decay * velrelease, |
219 |
pDimRgn->EG1Release + eg1release, |
pDimRgn->EG1Decay2 * eg1decay * velrelease, |
220 |
// the SSE synthesis implementation requires |
pDimRgn->EG1InfiniteSustain, |
221 |
// the vca start to be 16 byte aligned |
pDimRgn->EG1Sustain, |
222 |
SYNTHESIS_MODE_GET_IMPLEMENTATION(SynthesisMode) ? |
pDimRgn->EG1Release * eg1release * velrelease, |
223 |
Delay & 0xfffffffc : Delay); |
velocityAttenuation, |
224 |
|
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
225 |
} |
} |
226 |
|
|
227 |
|
|
245 |
} |
} |
246 |
if (pDimRgn->EG2ControllerInvert) eg2controllervalue = 127 - eg2controllervalue; |
if (pDimRgn->EG2ControllerInvert) eg2controllervalue = 127 - eg2controllervalue; |
247 |
|
|
248 |
// calculate influence of EG2 controller on EG2's parameters (TODO: needs to be fine tuned) |
// calculate influence of EG2 controller on EG2's parameters |
249 |
double eg2attack = (pDimRgn->EG2ControllerAttackInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerAttackInfluence) * eg2controllervalue : 0.0; |
double eg2attack = (pDimRgn->EG2ControllerAttackInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerAttackInfluence) * eg2controllervalue : 1.0; |
250 |
double eg2decay = (pDimRgn->EG2ControllerDecayInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerDecayInfluence) * eg2controllervalue : 0.0; |
double eg2decay = (pDimRgn->EG2ControllerDecayInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerDecayInfluence) * eg2controllervalue : 1.0; |
251 |
double eg2release = (pDimRgn->EG2ControllerReleaseInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerReleaseInfluence) * eg2controllervalue : 0.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, |
pDimRgn->EG2Decay1 * eg2decay * velrelease, |
258 |
pDimRgn->EG2Decay2 + eg2decay, |
pDimRgn->EG2Decay2 * eg2decay * velrelease, |
259 |
pDimRgn->EG2InfiniteSustain, |
pDimRgn->EG2InfiniteSustain, |
260 |
pDimRgn->EG2Sustain, |
pDimRgn->EG2Sustain, |
261 |
pDimRgn->EG2Release + eg2release, |
pDimRgn->EG2Release * eg2release * velrelease, |
262 |
Delay); |
velocityAttenuation, |
263 |
|
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 |
|
|
278 |
case ::gig::lfo1_ctrl_internal: |
case ::gig::lfo1_ctrl_internal: |
279 |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
280 |
pLFO1->ExtController = 0; // no external controller |
pLFO1->ExtController = 0; // no external controller |
281 |
|
bLFO1Enabled = (lfo1_internal_depth > 0); |
282 |
break; |
break; |
283 |
case ::gig::lfo1_ctrl_modwheel: |
case ::gig::lfo1_ctrl_modwheel: |
284 |
lfo1_internal_depth = 0; |
lfo1_internal_depth = 0; |
285 |
pLFO1->ExtController = 1; // MIDI controller 1 |
pLFO1->ExtController = 1; // MIDI controller 1 |
286 |
|
bLFO1Enabled = (pDimRgn->LFO1ControlDepth > 0); |
287 |
break; |
break; |
288 |
case ::gig::lfo1_ctrl_breath: |
case ::gig::lfo1_ctrl_breath: |
289 |
lfo1_internal_depth = 0; |
lfo1_internal_depth = 0; |
290 |
pLFO1->ExtController = 2; // MIDI controller 2 |
pLFO1->ExtController = 2; // MIDI controller 2 |
291 |
|
bLFO1Enabled = (pDimRgn->LFO1ControlDepth > 0); |
292 |
break; |
break; |
293 |
case ::gig::lfo1_ctrl_internal_modwheel: |
case ::gig::lfo1_ctrl_internal_modwheel: |
294 |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
295 |
pLFO1->ExtController = 1; // MIDI controller 1 |
pLFO1->ExtController = 1; // MIDI controller 1 |
296 |
|
bLFO1Enabled = (lfo1_internal_depth > 0 || pDimRgn->LFO1ControlDepth > 0); |
297 |
break; |
break; |
298 |
case ::gig::lfo1_ctrl_internal_breath: |
case ::gig::lfo1_ctrl_internal_breath: |
299 |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
300 |
pLFO1->ExtController = 2; // MIDI controller 2 |
pLFO1->ExtController = 2; // MIDI controller 2 |
301 |
|
bLFO1Enabled = (lfo1_internal_depth > 0 || pDimRgn->LFO1ControlDepth > 0); |
302 |
break; |
break; |
303 |
default: |
default: |
304 |
lfo1_internal_depth = 0; |
lfo1_internal_depth = 0; |
305 |
pLFO1->ExtController = 0; // no external controller |
pLFO1->ExtController = 0; // no external controller |
306 |
|
bLFO1Enabled = false; |
307 |
} |
} |
308 |
pLFO1->Trigger(pDimRgn->LFO1Frequency, |
if (bLFO1Enabled) pLFO1->trigger(pDimRgn->LFO1Frequency, |
309 |
lfo1_internal_depth, |
start_level_max, |
310 |
pDimRgn->LFO1ControlDepth, |
lfo1_internal_depth, |
311 |
pEngineChannel->ControllerTable[pLFO1->ExtController], |
pDimRgn->LFO1ControlDepth, |
312 |
pDimRgn->LFO1FlipPhase, |
pDimRgn->LFO1FlipPhase, |
313 |
pEngine->SampleRate, |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
Delay); |
|
314 |
} |
} |
315 |
|
|
316 |
|
|
321 |
case ::gig::lfo2_ctrl_internal: |
case ::gig::lfo2_ctrl_internal: |
322 |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
323 |
pLFO2->ExtController = 0; // no external controller |
pLFO2->ExtController = 0; // no external controller |
324 |
|
bLFO2Enabled = (lfo2_internal_depth > 0); |
325 |
break; |
break; |
326 |
case ::gig::lfo2_ctrl_modwheel: |
case ::gig::lfo2_ctrl_modwheel: |
327 |
lfo2_internal_depth = 0; |
lfo2_internal_depth = 0; |
328 |
pLFO2->ExtController = 1; // MIDI controller 1 |
pLFO2->ExtController = 1; // MIDI controller 1 |
329 |
|
bLFO2Enabled = (pDimRgn->LFO2ControlDepth > 0); |
330 |
break; |
break; |
331 |
case ::gig::lfo2_ctrl_foot: |
case ::gig::lfo2_ctrl_foot: |
332 |
lfo2_internal_depth = 0; |
lfo2_internal_depth = 0; |
333 |
pLFO2->ExtController = 4; // MIDI controller 4 |
pLFO2->ExtController = 4; // MIDI controller 4 |
334 |
|
bLFO2Enabled = (pDimRgn->LFO2ControlDepth > 0); |
335 |
break; |
break; |
336 |
case ::gig::lfo2_ctrl_internal_modwheel: |
case ::gig::lfo2_ctrl_internal_modwheel: |
337 |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
338 |
pLFO2->ExtController = 1; // MIDI controller 1 |
pLFO2->ExtController = 1; // MIDI controller 1 |
339 |
|
bLFO2Enabled = (lfo2_internal_depth > 0 || pDimRgn->LFO2ControlDepth > 0); |
340 |
break; |
break; |
341 |
case ::gig::lfo2_ctrl_internal_foot: |
case ::gig::lfo2_ctrl_internal_foot: |
342 |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
343 |
pLFO2->ExtController = 4; // MIDI controller 4 |
pLFO2->ExtController = 4; // MIDI controller 4 |
344 |
|
bLFO2Enabled = (lfo2_internal_depth > 0 || pDimRgn->LFO2ControlDepth > 0); |
345 |
break; |
break; |
346 |
default: |
default: |
347 |
lfo2_internal_depth = 0; |
lfo2_internal_depth = 0; |
348 |
pLFO2->ExtController = 0; // no external controller |
pLFO2->ExtController = 0; // no external controller |
349 |
|
bLFO2Enabled = false; |
350 |
} |
} |
351 |
pLFO2->Trigger(pDimRgn->LFO2Frequency, |
if (bLFO2Enabled) pLFO2->trigger(pDimRgn->LFO2Frequency, |
352 |
lfo2_internal_depth, |
start_level_max, |
353 |
pDimRgn->LFO2ControlDepth, |
lfo2_internal_depth, |
354 |
pEngineChannel->ControllerTable[pLFO2->ExtController], |
pDimRgn->LFO2ControlDepth, |
355 |
pDimRgn->LFO2FlipPhase, |
pDimRgn->LFO2FlipPhase, |
356 |
pEngine->SampleRate, |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
Delay); |
|
357 |
} |
} |
358 |
|
|
359 |
|
|
364 |
case ::gig::lfo3_ctrl_internal: |
case ::gig::lfo3_ctrl_internal: |
365 |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
366 |
pLFO3->ExtController = 0; // no external controller |
pLFO3->ExtController = 0; // no external controller |
367 |
|
bLFO3Enabled = (lfo3_internal_depth > 0); |
368 |
break; |
break; |
369 |
case ::gig::lfo3_ctrl_modwheel: |
case ::gig::lfo3_ctrl_modwheel: |
370 |
lfo3_internal_depth = 0; |
lfo3_internal_depth = 0; |
371 |
pLFO3->ExtController = 1; // MIDI controller 1 |
pLFO3->ExtController = 1; // MIDI controller 1 |
372 |
|
bLFO3Enabled = (pDimRgn->LFO3ControlDepth > 0); |
373 |
break; |
break; |
374 |
case ::gig::lfo3_ctrl_aftertouch: |
case ::gig::lfo3_ctrl_aftertouch: |
375 |
lfo3_internal_depth = 0; |
lfo3_internal_depth = 0; |
376 |
pLFO3->ExtController = 0; // TODO: aftertouch not implemented yet |
pLFO3->ExtController = 0; // TODO: aftertouch not implemented yet |
377 |
|
bLFO3Enabled = false; // see TODO comment in line above |
378 |
break; |
break; |
379 |
case ::gig::lfo3_ctrl_internal_modwheel: |
case ::gig::lfo3_ctrl_internal_modwheel: |
380 |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
381 |
pLFO3->ExtController = 1; // MIDI controller 1 |
pLFO3->ExtController = 1; // MIDI controller 1 |
382 |
|
bLFO3Enabled = (lfo3_internal_depth > 0 || pDimRgn->LFO3ControlDepth > 0); |
383 |
break; |
break; |
384 |
case ::gig::lfo3_ctrl_internal_aftertouch: |
case ::gig::lfo3_ctrl_internal_aftertouch: |
385 |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
386 |
pLFO1->ExtController = 0; // TODO: aftertouch not implemented yet |
pLFO1->ExtController = 0; // TODO: aftertouch not implemented yet |
387 |
|
bLFO3Enabled = (lfo3_internal_depth > 0 /*|| pDimRgn->LFO3ControlDepth > 0*/); // see TODO comment in line above |
388 |
break; |
break; |
389 |
default: |
default: |
390 |
lfo3_internal_depth = 0; |
lfo3_internal_depth = 0; |
391 |
pLFO3->ExtController = 0; // no external controller |
pLFO3->ExtController = 0; // no external controller |
392 |
|
bLFO3Enabled = false; |
393 |
} |
} |
394 |
pLFO3->Trigger(pDimRgn->LFO3Frequency, |
if (bLFO3Enabled) pLFO3->trigger(pDimRgn->LFO3Frequency, |
395 |
lfo3_internal_depth, |
start_level_mid, |
396 |
pDimRgn->LFO3ControlDepth, |
lfo3_internal_depth, |
397 |
pEngineChannel->ControllerTable[pLFO3->ExtController], |
pDimRgn->LFO3ControlDepth, |
398 |
false, |
false, |
399 |
pEngine->SampleRate, |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
Delay); |
|
400 |
} |
} |
401 |
|
|
402 |
|
|
480 |
VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller]; |
VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller]; |
481 |
|
|
482 |
// calculate cutoff frequency |
// calculate cutoff frequency |
483 |
float cutoff = (!VCFCutoffCtrl.controller) |
float cutoff = pDimRgn->GetVelocityCutoff(itNoteOnEvent->Param.Note.Velocity); |
484 |
? exp((float) (127 - itNoteOnEvent->Param.Note.Velocity) * (float) pDimRgn->VCFVelocityScale * 6.2E-5f * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MAX |
if (pDimRgn->VCFKeyboardTracking) { |
485 |
: exp((float) VCFCutoffCtrl.value * 0.00787402f * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MAX; |
cutoff *= exp((itNoteOnEvent->Param.Note.Key - pDimRgn->VCFKeyboardTrackingBreakpoint) * 0.057762265f); // (ln(2) / 12) |
486 |
|
} |
487 |
|
CutoffBase = cutoff; |
488 |
|
|
489 |
|
int cvalue; |
490 |
|
if (VCFCutoffCtrl.controller) { |
491 |
|
cvalue = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller]; |
492 |
|
if (pDimRgn->VCFCutoffControllerInvert) cvalue = 127 - cvalue; |
493 |
|
if (cvalue < pDimRgn->VCFVelocityScale) cvalue = pDimRgn->VCFVelocityScale; |
494 |
|
} |
495 |
|
else { |
496 |
|
cvalue = pDimRgn->VCFCutoff; |
497 |
|
} |
498 |
|
cutoff *= float(cvalue) * 0.00787402f; // (1 / 127) |
499 |
|
if (cutoff > 1.0) cutoff = 1.0; |
500 |
|
cutoff = exp(cutoff * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MIN; |
501 |
|
|
502 |
// calculate resonance |
// calculate resonance |
503 |
float resonance = (float) VCFResonanceCtrl.value * 0.00787f; // 0.0..1.0 |
float resonance = (float) VCFResonanceCtrl.value * 0.00787f; // 0.0..1.0 |
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 |
|
|
|
|
|
pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngineChannel->GlobalVolume); |
|
|
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); |
|
|
} |
|
|
pLFO1->Process(Samples); |
|
|
pLFO2->Process(Samples); |
|
|
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: |
539 |
|
this->PlaybackState = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed |
540 |
|
// no break - continue with playback_state_ram |
541 |
|
|
542 |
case playback_state_ram: { |
case playback_state_ram: { |
543 |
if (RAMLoop) SYNTHESIS_MODE_SET_LOOP(SynthesisMode, true); // enable looping |
if (RAMLoop) SYNTHESIS_MODE_SET_LOOP(SynthesisMode, true); // enable looping |
544 |
|
|
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 |
|
if (itEvent->Type == Event::type_release) { |
648 |
|
EG1.update(EGADSR::event_release, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
649 |
|
EG2.update(EGADSR::event_release, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
650 |
|
} 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 |
|
EG2.update(EGADSR::event_cancel_release, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
653 |
|
} |
654 |
|
} |
655 |
|
} |
656 |
|
|
657 |
// dispatch control change events |
/** |
658 |
RTList<Event>::Iterator itCCEvent = pEngineChannel->pCCEvents->first(); |
* Process given list of MIDI control change and pitch bend events for |
659 |
if (Delay) { // skip events that happened before this voice was triggered |
* the given time. |
660 |
while (itCCEvent && itCCEvent->FragmentPos() <= Delay) ++itCCEvent; |
* |
661 |
} |
* @param itEvent - iterator pointing to the next event to be processed |
662 |
while (itCCEvent) { |
* @param End - youngest time stamp where processing should be stopped |
663 |
if (itCCEvent->Param.CC.Controller) { // if valid MIDI controller |
*/ |
664 |
if (itCCEvent->Param.CC.Controller == VCFCutoffCtrl.controller) { |
void Voice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) { |
665 |
*pEngineChannel->pSynthesisEvents[Event::destination_vcfc]->allocAppend() = *itCCEvent; |
for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) { |
666 |
} |
if (itEvent->Type == Event::type_control_change && |
667 |
if (itCCEvent->Param.CC.Controller == VCFResonanceCtrl.controller) { |
itEvent->Param.CC.Controller) { // if (valid) MIDI control change event |
668 |
*pEngineChannel->pSynthesisEvents[Event::destination_vcfr]->allocAppend() = *itCCEvent; |
if (itEvent->Param.CC.Controller == VCFCutoffCtrl.controller) { |
669 |
|
processCutoffEvent(itEvent); |
670 |
|
} |
671 |
|
if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) { |
672 |
|
processResonanceEvent(itEvent); |
673 |
} |
} |
674 |
if (itCCEvent->Param.CC.Controller == pLFO1->ExtController) { |
if (itEvent->Param.CC.Controller == pLFO1->ExtController) { |
675 |
pLFO1->SendEvent(itCCEvent); |
pLFO1->update(itEvent->Param.CC.Value); |
676 |
} |
} |
677 |
if (itCCEvent->Param.CC.Controller == pLFO2->ExtController) { |
if (itEvent->Param.CC.Controller == pLFO2->ExtController) { |
678 |
pLFO2->SendEvent(itCCEvent); |
pLFO2->update(itEvent->Param.CC.Value); |
679 |
} |
} |
680 |
if (itCCEvent->Param.CC.Controller == pLFO3->ExtController) { |
if (itEvent->Param.CC.Controller == pLFO3->ExtController) { |
681 |
pLFO3->SendEvent(itCCEvent); |
pLFO3->update(itEvent->Param.CC.Value); |
682 |
} |
} |
683 |
if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange && |
if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange && |
684 |
itCCEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) { // if crossfade event |
itEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) { |
685 |
*pEngineChannel->pSynthesisEvents[Event::destination_vca]->allocAppend() = *itCCEvent; |
processCrossFadeEvent(itEvent); |
686 |
} |
} |
687 |
|
} else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event |
688 |
|
processPitchEvent(itEvent); |
689 |
} |
} |
690 |
|
} |
691 |
|
} |
692 |
|
|
693 |
|
void Voice::processPitchEvent(RTList<Event>::Iterator& itEvent) { |
694 |
|
const float pitch = RTMath::CentsToFreqRatio(((double) itEvent->Param.Pitch.Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents |
695 |
|
fFinalPitch *= pitch; |
696 |
|
} |
697 |
|
|
698 |
|
void Voice::processCrossFadeEvent(RTList<Event>::Iterator& itEvent) { |
699 |
|
CrossfadeVolume = CrossfadeAttenuation(itEvent->Param.CC.Value); |
700 |
|
#if CONFIG_PROCESS_MUTED_CHANNELS |
701 |
|
const float effectiveVolume = CrossfadeVolume * Volume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume); |
702 |
|
#else |
703 |
|
const float effectiveVolume = CrossfadeVolume * Volume * pEngineChannel->GlobalVolume; |
704 |
|
#endif |
705 |
|
fFinalVolume = effectiveVolume; |
706 |
|
} |
707 |
|
|
708 |
|
void Voice::processCutoffEvent(RTList<Event>::Iterator& itEvent) { |
709 |
|
int ccvalue = itEvent->Param.CC.Value; |
710 |
|
if (VCFCutoffCtrl.value == ccvalue) return; |
711 |
|
VCFCutoffCtrl.value == ccvalue; |
712 |
|
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 |
|
/** |
732 |
|
* Synthesizes the current audio fragment for this voice. |
733 |
|
* |
734 |
|
* @param Samples - number of sample points to be rendered in this audio |
735 |
|
* fragment cycle |
736 |
|
* @param pSrc - pointer to input sample data |
737 |
|
* @param Skip - number of sample points to skip in output buffer |
738 |
|
*/ |
739 |
|
void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) { |
740 |
|
RTList<Event>::Iterator itCCEvent = pEngineChannel->pEvents->first(); |
741 |
|
RTList<Event>::Iterator itNoteEvent = pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents->first(); |
742 |
|
|
743 |
++itCCEvent; |
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 |
// process pitch events |
// initialize all final synthesis parameters |
753 |
{ |
fFinalPitch = PitchBase * PitchBend; |
754 |
RTList<Event>* pVCOEventList = pEngineChannel->pSynthesisEvents[Event::destination_vco]; |
#if CONFIG_PROCESS_MUTED_CHANNELS |
755 |
RTList<Event>::Iterator itVCOEvent = pVCOEventList->first(); |
fFinalVolume = this->Volume * this->CrossfadeVolume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume); |
756 |
if (Delay) { // skip events that happened before this voice was triggered |
#else |
757 |
while (itVCOEvent && itVCOEvent->FragmentPos() <= Delay) ++itVCOEvent; |
fFinalVolume = this->Volume * this->CrossfadeVolume * pEngineChannel->GlobalVolume; |
758 |
} |
#endif |
759 |
// apply old pitchbend value until first pitch event occurs |
fFinalCutoff = VCFCutoffCtrl.fvalue; |
760 |
if (this->PitchBend != 1.0) { |
fFinalResonance = VCFResonanceCtrl.fvalue; |
761 |
uint end = (itVCOEvent) ? itVCOEvent->FragmentPos() : Samples; |
|
762 |
for (uint i = Delay; i < end; i++) { |
// process MIDI control change and pitchbend events for this subfragment |
763 |
pEngine->pSynthesisParameters[Event::destination_vco][i] *= this->PitchBend; |
processCCEvents(itCCEvent, iSubFragmentEnd); |
|
} |
|
|
} |
|
|
float pitch; |
|
|
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; |
|
|
} |
|
764 |
|
|
765 |
itVCOEvent = itNextVCOEvent; |
// 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 |
if (!pVCOEventList->isEmpty()) { |
switch (EG2.getSegmentType()) { |
781 |
this->PitchBend = pitch; |
case EGADSR::segment_lin: |
782 |
SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true); |
fFinalCutoff *= EG2.processLin(); |
783 |
SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false); |
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 volume / attenuation events (TODO: we only handle and _expect_ crossfade events here ATM !) |
// process low frequency oscillators |
794 |
{ |
if (bLFO1Enabled) fFinalVolume *= pLFO1->render(); |
795 |
RTList<Event>* pVCAEventList = pEngineChannel->pSynthesisEvents[Event::destination_vca]; |
if (bLFO2Enabled) fFinalCutoff *= pLFO2->render(); |
796 |
RTList<Event>::Iterator itVCAEvent = pVCAEventList->first(); |
if (bLFO3Enabled) fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render()); |
|
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); |
|
|
|
|
|
float effective_volume = crossfadevolume * this->Volume * pEngineChannel->GlobalVolume; |
|
|
|
|
|
// apply volume value to the volume parameter sequence |
|
|
for (uint i = itVCAEvent->FragmentPos(); i < end; i++) { |
|
|
pEngine->pSynthesisParameters[Event::destination_vca][i] = effective_volume; |
|
|
} |
|
797 |
|
|
798 |
itVCAEvent = itNextVCAEvent; |
// 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 |
} |
} |
|
if (!pVCAEventList->isEmpty()) this->CrossfadeVolume = crossfadevolume; |
|
|
} |
|
803 |
|
|
804 |
// process filter cutoff events |
// how many steps do we calculate for this next subfragment |
805 |
{ |
const int steps = iSubFragmentEnd - i; |
|
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; |
|
|
|
|
|
cutoff = exp((float) itCutoffEvent->Param.CC.Value * 0.00787402f * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MAX - 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; |
|
|
} |
|
806 |
|
|
807 |
itCutoffEvent = itNextCutoffEvent; |
// select the appropriate synthesis mode |
808 |
} |
SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, fFinalPitch != 1.0f); |
|
if (!pCutoffEventList->isEmpty()) VCFCutoffCtrl.fvalue = cutoff; // needed for initialization of parameter matrix next time |
|
|
} |
|
809 |
|
|
810 |
// process filter resonance events |
// render audio for one subfragment |
811 |
{ |
RunSynthesisFunction(SynthesisMode, *this, iSubFragmentEnd, pSrc, i); |
|
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; |
|
|
} |
|
812 |
|
|
813 |
itResonanceEvent = itNextResonanceEvent; |
// increment envelopes' positions |
814 |
|
if (EG1.active()) { |
815 |
|
EG1.increment(1); |
816 |
|
if (!EG1.toStageEndLeft()) EG1.update(EGADSR::event_stage_end, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
817 |
} |
} |
818 |
if (!pResonanceEventList->isEmpty()) VCFResonanceCtrl.fvalue = pResonanceEventList->last()->Param.CC.Value * 0.00787f; // needed for initialization of parameter matrix next time |
if (EG2.active()) { |
819 |
} |
EG2.increment(1); |
820 |
} |
if (!EG2.toStageEndLeft()) EG2.update(EGADSR::event_stage_end, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
|
|
|
/** |
|
|
* Calculate all necessary, final biquad filter parameters. |
|
|
* |
|
|
* @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); |
|
|
} |
|
821 |
} |
} |
822 |
|
EG3.increment(1); |
823 |
|
if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached |
824 |
|
|
825 |
//same as 'pEngine->pBasicFilterParameters[i] = bqbase;' |
i = iSubFragmentEnd; |
|
bq = (float*) &pEngine->pBasicFilterParameters[i]; |
|
|
bq[0] = bqbase.b0; |
|
|
bq[1] = bqbase.b1; |
|
|
bq[2] = bqbase.b2; |
|
|
bq[3] = bqbase.a1; |
|
|
bq[4] = bqbase.a2; |
|
|
|
|
|
// same as 'pEngine->pMainFilterParameters[i] = bqmain;' |
|
|
bq = (float*) &pEngine->pMainFilterParameters[i]; |
|
|
bq[0] = bqmain.b0; |
|
|
bq[1] = bqmain.b1; |
|
|
bq[2] = bqmain.b2; |
|
|
bq[3] = bqmain.a1; |
|
|
bq[4] = bqmain.a2; |
|
826 |
} |
} |
827 |
} |
} |
828 |
|
|
829 |
/** |
/** |
|
* Synthesizes the current audio fragment for this voice. |
|
|
* |
|
|
* @param Samples - number of sample points to be rendered in this audio |
|
|
* fragment cycle |
|
|
* @param pSrc - pointer to input sample data |
|
|
* @param Skip - number of sample points to skip in output buffer |
|
|
*/ |
|
|
void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) { |
|
|
RunSynthesisFunction(SynthesisMode, *this, Samples, pSrc, Skip); |
|
|
} |
|
|
|
|
|
/** |
|
830 |
* Immediately kill the voice. This method should not be used to kill |
* Immediately kill the voice. This method should not be used to kill |
831 |
* 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 |
832 |
* fading down the volume level to avoid clicks and regular processing |
* fading down the volume level to avoid clicks and regular processing |