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 |
|
#include "Profiler.h" |
27 |
|
|
28 |
#include "Voice.h" |
#include "Voice.h" |
29 |
|
|
31 |
|
|
32 |
const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff()); |
const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff()); |
33 |
|
|
|
const int Voice::FILTER_UPDATE_MASK(CalculateFilterUpdateMask()); |
|
|
|
|
34 |
float Voice::CalculateFilterCutoffCoeff() { |
float Voice::CalculateFilterCutoffCoeff() { |
35 |
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; |
|
36 |
} |
} |
37 |
|
|
38 |
Voice::Voice() { |
Voice::Voice() { |
39 |
pEngine = NULL; |
pEngine = NULL; |
40 |
pDiskThread = NULL; |
pDiskThread = NULL; |
41 |
PlaybackState = playback_state_end; |
PlaybackState = playback_state_end; |
42 |
pEG1 = NULL; |
pLFO1 = new LFOUnsigned(1.0f); // amplitude EG (0..1 range) |
43 |
pEG2 = NULL; |
pLFO2 = new LFOUnsigned(1.0f); // filter EG (0..1 range) |
44 |
pEG3 = NULL; |
pLFO3 = new LFOSigned(1200.0f); // pitch EG (-1200..+1200 range) |
|
pVCAManipulator = NULL; |
|
|
pVCFCManipulator = NULL; |
|
|
pVCOManipulator = NULL; |
|
|
pLFO1 = NULL; |
|
|
pLFO2 = NULL; |
|
|
pLFO3 = NULL; |
|
45 |
KeyGroup = 0; |
KeyGroup = 0; |
46 |
SynthesisMode = 0; // set all mode bits to 0 first |
SynthesisMode = 0; // set all mode bits to 0 first |
47 |
// select synthesis implementation (currently either pure C++ or MMX+SSE(1)) |
// select synthesis implementation (currently either pure C++ or MMX+SSE(1)) |
50 |
#else |
#else |
51 |
SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false); |
SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false); |
52 |
#endif |
#endif |
53 |
SYNTHESIS_MODE_SET_PROFILING(SynthesisMode, true); |
SYNTHESIS_MODE_SET_PROFILING(SynthesisMode, Profiler::isEnabled()); |
54 |
|
|
55 |
FilterLeft.Reset(); |
finalSynthesisParameters.filterLeft.Reset(); |
56 |
FilterRight.Reset(); |
finalSynthesisParameters.filterRight.Reset(); |
57 |
} |
} |
58 |
|
|
59 |
Voice::~Voice() { |
Voice::~Voice() { |
|
if (pEG1) delete pEG1; |
|
|
if (pEG2) delete pEG2; |
|
|
if (pEG3) delete pEG3; |
|
60 |
if (pLFO1) delete pLFO1; |
if (pLFO1) delete pLFO1; |
61 |
if (pLFO2) delete pLFO2; |
if (pLFO2) delete pLFO2; |
62 |
if (pLFO3) delete pLFO3; |
if (pLFO3) delete pLFO3; |
|
if (pVCAManipulator) delete pVCAManipulator; |
|
|
if (pVCFCManipulator) delete pVCFCManipulator; |
|
|
if (pVCOManipulator) delete pVCOManipulator; |
|
63 |
} |
} |
64 |
|
|
65 |
void Voice::SetEngine(Engine* pEngine) { |
void Voice::SetEngine(Engine* pEngine) { |
66 |
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. |
|
|
|
|
67 |
this->pDiskThread = pEngine->pDiskThread; |
this->pDiskThread = pEngine->pDiskThread; |
68 |
dmsg(6,("Voice::SetEngine()\n")); |
dmsg(6,("Voice::SetEngine()\n")); |
69 |
} |
} |
139 |
PanLeft = 1.0f - float(RTMath::Max(pDimRgn->Pan, 0)) / 63.0f; |
PanLeft = 1.0f - float(RTMath::Max(pDimRgn->Pan, 0)) / 63.0f; |
140 |
PanRight = 1.0f - float(RTMath::Min(pDimRgn->Pan, 0)) / -64.0f; |
PanRight = 1.0f - float(RTMath::Min(pDimRgn->Pan, 0)) / -64.0f; |
141 |
|
|
142 |
Pos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points) |
finalSynthesisParameters.dPos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points) |
143 |
|
|
144 |
// Check if the sample needs disk streaming or is too short for that |
// Check if the sample needs disk streaming or is too short for that |
145 |
long cachedsamples = pSample->GetCache().Size / pSample->FrameSize; |
long cachedsamples = pSample->GetCache().Size / pSample->FrameSize; |
150 |
|
|
151 |
// check if there's a loop defined which completely fits into the cached (RAM) part of the sample |
// check if there's a loop defined which completely fits into the cached (RAM) part of the sample |
152 |
if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) { |
if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) { |
153 |
RAMLoop = true; |
RAMLoop = true; |
154 |
LoopCyclesLeft = pSample->LoopPlayCount; |
loop.uiTotalCycles = pSample->LoopPlayCount; |
155 |
|
loop.uiCyclesLeft = pSample->LoopPlayCount; |
156 |
|
loop.uiStart = pSample->LoopStart; |
157 |
|
loop.uiEnd = pSample->LoopEnd; |
158 |
|
loop.uiSize = pSample->LoopSize; |
159 |
} |
} |
160 |
else RAMLoop = false; |
else RAMLoop = false; |
161 |
|
|
169 |
else { // RAM only voice |
else { // RAM only voice |
170 |
MaxRAMPos = cachedsamples; |
MaxRAMPos = cachedsamples; |
171 |
if (pSample->Loops) { |
if (pSample->Loops) { |
172 |
RAMLoop = true; |
RAMLoop = true; |
173 |
LoopCyclesLeft = pSample->LoopPlayCount; |
loop.uiCyclesLeft = pSample->LoopPlayCount; |
174 |
} |
} |
175 |
else RAMLoop = false; |
else RAMLoop = false; |
176 |
dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no")); |
dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no")); |
181 |
{ |
{ |
182 |
double pitchbasecents = pDimRgn->FineTune + (int) pEngine->ScaleTuning[MIDIKey % 12]; |
double pitchbasecents = pDimRgn->FineTune + (int) pEngine->ScaleTuning[MIDIKey % 12]; |
183 |
if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100; |
if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100; |
184 |
this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate())); |
this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->SampleRate)); |
185 |
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 |
186 |
} |
} |
187 |
|
|
208 |
} |
} |
209 |
if (pDimRgn->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue; |
if (pDimRgn->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue; |
210 |
|
|
211 |
// calculate influence of EG1 controller on EG1's parameters (TODO: needs to be fine tuned) |
// calculate influence of EG1 controller on EG1's parameters |
212 |
double eg1attack = (pDimRgn->EG1ControllerAttackInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerAttackInfluence) * eg1controllervalue : 0.0; |
// (eg1attack is different from the others) |
213 |
double eg1decay = (pDimRgn->EG1ControllerDecayInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence) * eg1controllervalue : 0.0; |
double eg1attack = (pDimRgn->EG1ControllerAttackInfluence) ? |
214 |
double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 0.0; |
1 + 0.031 * (double) (pDimRgn->EG1ControllerAttackInfluence == 1 ? |
215 |
|
1 : 1 << pDimRgn->EG1ControllerAttackInfluence) * eg1controllervalue : 1.0; |
216 |
pEG1->Trigger(pDimRgn->EG1PreAttack, |
double eg1decay = (pDimRgn->EG1ControllerDecayInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence) * eg1controllervalue : 1.0; |
217 |
pDimRgn->EG1Attack + eg1attack, |
double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 1.0; |
218 |
pDimRgn->EG1Hold, |
|
219 |
pSample->LoopStart, |
EG1.trigger(pDimRgn->EG1PreAttack, |
220 |
(pDimRgn->EG1Decay1 + eg1decay) * velrelease, |
pDimRgn->EG1Attack * eg1attack, |
221 |
(pDimRgn->EG1Decay2 + eg1decay) * velrelease, |
pDimRgn->EG1Hold, |
222 |
pDimRgn->EG1InfiniteSustain, |
pSample->LoopStart, |
223 |
pDimRgn->EG1Sustain, |
pDimRgn->EG1Decay1 * eg1decay * velrelease, |
224 |
(pDimRgn->EG1Release + eg1release) * velrelease, |
pDimRgn->EG1Decay2 * eg1decay * velrelease, |
225 |
// the SSE synthesis implementation requires |
pDimRgn->EG1InfiniteSustain, |
226 |
// the vca start to be 16 byte aligned |
pDimRgn->EG1Sustain, |
227 |
SYNTHESIS_MODE_GET_IMPLEMENTATION(SynthesisMode) ? |
pDimRgn->EG1Release * eg1release * velrelease, |
228 |
Delay & 0xfffffffc : Delay, |
velocityAttenuation, |
229 |
velocityAttenuation); |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
230 |
} |
} |
231 |
|
|
232 |
|
|
250 |
} |
} |
251 |
if (pDimRgn->EG2ControllerInvert) eg2controllervalue = 127 - eg2controllervalue; |
if (pDimRgn->EG2ControllerInvert) eg2controllervalue = 127 - eg2controllervalue; |
252 |
|
|
253 |
// calculate influence of EG2 controller on EG2's parameters (TODO: needs to be fine tuned) |
// calculate influence of EG2 controller on EG2's parameters |
254 |
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; |
255 |
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; |
256 |
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; |
257 |
|
|
258 |
pEG2->Trigger(pDimRgn->EG2PreAttack, |
EG2.trigger(pDimRgn->EG2PreAttack, |
259 |
pDimRgn->EG2Attack + eg2attack, |
pDimRgn->EG2Attack * eg2attack, |
260 |
false, |
false, |
261 |
pSample->LoopStart, |
pSample->LoopStart, |
262 |
(pDimRgn->EG2Decay1 + eg2decay) * velrelease, |
pDimRgn->EG2Decay1 * eg2decay * velrelease, |
263 |
(pDimRgn->EG2Decay2 + eg2decay) * velrelease, |
pDimRgn->EG2Decay2 * eg2decay * velrelease, |
264 |
pDimRgn->EG2InfiniteSustain, |
pDimRgn->EG2InfiniteSustain, |
265 |
pDimRgn->EG2Sustain, |
pDimRgn->EG2Sustain, |
266 |
(pDimRgn->EG2Release + eg2release) * velrelease, |
pDimRgn->EG2Release * eg2release * velrelease, |
267 |
Delay, |
velocityAttenuation, |
268 |
velocityAttenuation); |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
269 |
} |
} |
270 |
|
|
271 |
|
|
272 |
// setup EG 3 (VCO EG) |
// setup EG 3 (VCO EG) |
273 |
{ |
{ |
274 |
double eg3depth = RTMath::CentsToFreqRatio(pDimRgn->EG3Depth); |
double eg3depth = RTMath::CentsToFreqRatio(pDimRgn->EG3Depth); |
275 |
pEG3->Trigger(eg3depth, pDimRgn->EG3Attack, Delay); |
EG3.trigger(eg3depth, pDimRgn->EG3Attack, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
276 |
} |
} |
277 |
|
|
278 |
|
|
283 |
case ::gig::lfo1_ctrl_internal: |
case ::gig::lfo1_ctrl_internal: |
284 |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
285 |
pLFO1->ExtController = 0; // no external controller |
pLFO1->ExtController = 0; // no external controller |
286 |
|
bLFO1Enabled = (lfo1_internal_depth > 0); |
287 |
break; |
break; |
288 |
case ::gig::lfo1_ctrl_modwheel: |
case ::gig::lfo1_ctrl_modwheel: |
289 |
lfo1_internal_depth = 0; |
lfo1_internal_depth = 0; |
290 |
pLFO1->ExtController = 1; // MIDI controller 1 |
pLFO1->ExtController = 1; // MIDI controller 1 |
291 |
|
bLFO1Enabled = (pDimRgn->LFO1ControlDepth > 0); |
292 |
break; |
break; |
293 |
case ::gig::lfo1_ctrl_breath: |
case ::gig::lfo1_ctrl_breath: |
294 |
lfo1_internal_depth = 0; |
lfo1_internal_depth = 0; |
295 |
pLFO1->ExtController = 2; // MIDI controller 2 |
pLFO1->ExtController = 2; // MIDI controller 2 |
296 |
|
bLFO1Enabled = (pDimRgn->LFO1ControlDepth > 0); |
297 |
break; |
break; |
298 |
case ::gig::lfo1_ctrl_internal_modwheel: |
case ::gig::lfo1_ctrl_internal_modwheel: |
299 |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
300 |
pLFO1->ExtController = 1; // MIDI controller 1 |
pLFO1->ExtController = 1; // MIDI controller 1 |
301 |
|
bLFO1Enabled = (lfo1_internal_depth > 0 || pDimRgn->LFO1ControlDepth > 0); |
302 |
break; |
break; |
303 |
case ::gig::lfo1_ctrl_internal_breath: |
case ::gig::lfo1_ctrl_internal_breath: |
304 |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
305 |
pLFO1->ExtController = 2; // MIDI controller 2 |
pLFO1->ExtController = 2; // MIDI controller 2 |
306 |
|
bLFO1Enabled = (lfo1_internal_depth > 0 || pDimRgn->LFO1ControlDepth > 0); |
307 |
break; |
break; |
308 |
default: |
default: |
309 |
lfo1_internal_depth = 0; |
lfo1_internal_depth = 0; |
310 |
pLFO1->ExtController = 0; // no external controller |
pLFO1->ExtController = 0; // no external controller |
311 |
|
bLFO1Enabled = false; |
312 |
} |
} |
313 |
pLFO1->Trigger(pDimRgn->LFO1Frequency, |
if (bLFO1Enabled) pLFO1->trigger(pDimRgn->LFO1Frequency, |
314 |
lfo1_internal_depth, |
start_level_max, |
315 |
pDimRgn->LFO1ControlDepth, |
lfo1_internal_depth, |
316 |
pEngineChannel->ControllerTable[pLFO1->ExtController], |
pDimRgn->LFO1ControlDepth, |
317 |
pDimRgn->LFO1FlipPhase, |
pDimRgn->LFO1FlipPhase, |
318 |
pEngine->SampleRate, |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
Delay); |
|
319 |
} |
} |
320 |
|
|
321 |
|
|
326 |
case ::gig::lfo2_ctrl_internal: |
case ::gig::lfo2_ctrl_internal: |
327 |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
328 |
pLFO2->ExtController = 0; // no external controller |
pLFO2->ExtController = 0; // no external controller |
329 |
|
bLFO2Enabled = (lfo2_internal_depth > 0); |
330 |
break; |
break; |
331 |
case ::gig::lfo2_ctrl_modwheel: |
case ::gig::lfo2_ctrl_modwheel: |
332 |
lfo2_internal_depth = 0; |
lfo2_internal_depth = 0; |
333 |
pLFO2->ExtController = 1; // MIDI controller 1 |
pLFO2->ExtController = 1; // MIDI controller 1 |
334 |
|
bLFO2Enabled = (pDimRgn->LFO2ControlDepth > 0); |
335 |
break; |
break; |
336 |
case ::gig::lfo2_ctrl_foot: |
case ::gig::lfo2_ctrl_foot: |
337 |
lfo2_internal_depth = 0; |
lfo2_internal_depth = 0; |
338 |
pLFO2->ExtController = 4; // MIDI controller 4 |
pLFO2->ExtController = 4; // MIDI controller 4 |
339 |
|
bLFO2Enabled = (pDimRgn->LFO2ControlDepth > 0); |
340 |
break; |
break; |
341 |
case ::gig::lfo2_ctrl_internal_modwheel: |
case ::gig::lfo2_ctrl_internal_modwheel: |
342 |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
343 |
pLFO2->ExtController = 1; // MIDI controller 1 |
pLFO2->ExtController = 1; // MIDI controller 1 |
344 |
|
bLFO2Enabled = (lfo2_internal_depth > 0 || pDimRgn->LFO2ControlDepth > 0); |
345 |
break; |
break; |
346 |
case ::gig::lfo2_ctrl_internal_foot: |
case ::gig::lfo2_ctrl_internal_foot: |
347 |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
348 |
pLFO2->ExtController = 4; // MIDI controller 4 |
pLFO2->ExtController = 4; // MIDI controller 4 |
349 |
|
bLFO2Enabled = (lfo2_internal_depth > 0 || pDimRgn->LFO2ControlDepth > 0); |
350 |
break; |
break; |
351 |
default: |
default: |
352 |
lfo2_internal_depth = 0; |
lfo2_internal_depth = 0; |
353 |
pLFO2->ExtController = 0; // no external controller |
pLFO2->ExtController = 0; // no external controller |
354 |
|
bLFO2Enabled = false; |
355 |
} |
} |
356 |
pLFO2->Trigger(pDimRgn->LFO2Frequency, |
if (bLFO2Enabled) pLFO2->trigger(pDimRgn->LFO2Frequency, |
357 |
lfo2_internal_depth, |
start_level_max, |
358 |
pDimRgn->LFO2ControlDepth, |
lfo2_internal_depth, |
359 |
pEngineChannel->ControllerTable[pLFO2->ExtController], |
pDimRgn->LFO2ControlDepth, |
360 |
pDimRgn->LFO2FlipPhase, |
pDimRgn->LFO2FlipPhase, |
361 |
pEngine->SampleRate, |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
Delay); |
|
362 |
} |
} |
363 |
|
|
364 |
|
|
369 |
case ::gig::lfo3_ctrl_internal: |
case ::gig::lfo3_ctrl_internal: |
370 |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
371 |
pLFO3->ExtController = 0; // no external controller |
pLFO3->ExtController = 0; // no external controller |
372 |
|
bLFO3Enabled = (lfo3_internal_depth > 0); |
373 |
break; |
break; |
374 |
case ::gig::lfo3_ctrl_modwheel: |
case ::gig::lfo3_ctrl_modwheel: |
375 |
lfo3_internal_depth = 0; |
lfo3_internal_depth = 0; |
376 |
pLFO3->ExtController = 1; // MIDI controller 1 |
pLFO3->ExtController = 1; // MIDI controller 1 |
377 |
|
bLFO3Enabled = (pDimRgn->LFO3ControlDepth > 0); |
378 |
break; |
break; |
379 |
case ::gig::lfo3_ctrl_aftertouch: |
case ::gig::lfo3_ctrl_aftertouch: |
380 |
lfo3_internal_depth = 0; |
lfo3_internal_depth = 0; |
381 |
pLFO3->ExtController = 0; // TODO: aftertouch not implemented yet |
pLFO3->ExtController = 0; // TODO: aftertouch not implemented yet |
382 |
|
bLFO3Enabled = false; // see TODO comment in line above |
383 |
break; |
break; |
384 |
case ::gig::lfo3_ctrl_internal_modwheel: |
case ::gig::lfo3_ctrl_internal_modwheel: |
385 |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
386 |
pLFO3->ExtController = 1; // MIDI controller 1 |
pLFO3->ExtController = 1; // MIDI controller 1 |
387 |
|
bLFO3Enabled = (lfo3_internal_depth > 0 || pDimRgn->LFO3ControlDepth > 0); |
388 |
break; |
break; |
389 |
case ::gig::lfo3_ctrl_internal_aftertouch: |
case ::gig::lfo3_ctrl_internal_aftertouch: |
390 |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
391 |
pLFO1->ExtController = 0; // TODO: aftertouch not implemented yet |
pLFO1->ExtController = 0; // TODO: aftertouch not implemented yet |
392 |
|
bLFO3Enabled = (lfo3_internal_depth > 0 /*|| pDimRgn->LFO3ControlDepth > 0*/); // see TODO comment in line above |
393 |
break; |
break; |
394 |
default: |
default: |
395 |
lfo3_internal_depth = 0; |
lfo3_internal_depth = 0; |
396 |
pLFO3->ExtController = 0; // no external controller |
pLFO3->ExtController = 0; // no external controller |
397 |
|
bLFO3Enabled = false; |
398 |
} |
} |
399 |
pLFO3->Trigger(pDimRgn->LFO3Frequency, |
if (bLFO3Enabled) pLFO3->trigger(pDimRgn->LFO3Frequency, |
400 |
lfo3_internal_depth, |
start_level_mid, |
401 |
pDimRgn->LFO3ControlDepth, |
lfo3_internal_depth, |
402 |
pEngineChannel->ControllerTable[pLFO3->ExtController], |
pDimRgn->LFO3ControlDepth, |
403 |
false, |
false, |
404 |
pEngine->SampleRate, |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
Delay); |
|
405 |
} |
} |
406 |
|
|
407 |
|
|
474 |
#endif // CONFIG_OVERRIDE_RESONANCE_CTRL |
#endif // CONFIG_OVERRIDE_RESONANCE_CTRL |
475 |
|
|
476 |
#ifndef CONFIG_OVERRIDE_FILTER_TYPE |
#ifndef CONFIG_OVERRIDE_FILTER_TYPE |
477 |
FilterLeft.SetType(pDimRgn->VCFType); |
finalSynthesisParameters.filterLeft.SetType(pDimRgn->VCFType); |
478 |
FilterRight.SetType(pDimRgn->VCFType); |
finalSynthesisParameters.filterRight.SetType(pDimRgn->VCFType); |
479 |
#else // override filter type |
#else // override filter type |
480 |
FilterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE); |
FilterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE); |
481 |
FilterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE); |
FilterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE); |
485 |
VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller]; |
VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller]; |
486 |
|
|
487 |
// calculate cutoff frequency |
// calculate cutoff frequency |
488 |
float cutoff = (!VCFCutoffCtrl.controller) |
float cutoff = pDimRgn->GetVelocityCutoff(itNoteOnEvent->Param.Note.Velocity); |
489 |
? exp((float) (127 - itNoteOnEvent->Param.Note.Velocity) * (float) pDimRgn->VCFVelocityScale * 6.2E-5f * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MAX |
if (pDimRgn->VCFKeyboardTracking) { |
490 |
: 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) |
491 |
|
} |
492 |
|
CutoffBase = cutoff; |
493 |
|
|
494 |
|
int cvalue; |
495 |
|
if (VCFCutoffCtrl.controller) { |
496 |
|
cvalue = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller]; |
497 |
|
if (pDimRgn->VCFCutoffControllerInvert) cvalue = 127 - cvalue; |
498 |
|
if (cvalue < pDimRgn->VCFVelocityScale) cvalue = pDimRgn->VCFVelocityScale; |
499 |
|
} |
500 |
|
else { |
501 |
|
cvalue = pDimRgn->VCFCutoff; |
502 |
|
} |
503 |
|
cutoff *= float(cvalue) * 0.00787402f; // (1 / 127) |
504 |
|
if (cutoff > 1.0) cutoff = 1.0; |
505 |
|
cutoff = exp(cutoff * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MIN; |
506 |
|
|
507 |
// calculate resonance |
// calculate resonance |
508 |
float resonance = (float) VCFResonanceCtrl.value * 0.00787f; // 0.0..1.0 |
float resonance = (float) VCFResonanceCtrl.value * 0.00787f; // 0.0..1.0 |
513 |
|
|
514 |
VCFCutoffCtrl.fvalue = cutoff - CONFIG_FILTER_CUTOFF_MIN; |
VCFCutoffCtrl.fvalue = cutoff - CONFIG_FILTER_CUTOFF_MIN; |
515 |
VCFResonanceCtrl.fvalue = resonance; |
VCFResonanceCtrl.fvalue = resonance; |
|
|
|
|
FilterUpdateCounter = -1; |
|
516 |
} |
} |
517 |
else { |
else { |
518 |
VCFCutoffCtrl.controller = 0; |
VCFCutoffCtrl.controller = 0; |
536 |
void Voice::Render(uint Samples) { |
void Voice::Render(uint Samples) { |
537 |
|
|
538 |
// 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); |
|
539 |
SYNTHESIS_MODE_SET_LOOP(SynthesisMode, false); |
SYNTHESIS_MODE_SET_LOOP(SynthesisMode, false); |
540 |
|
|
|
// 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 |
|
|
|
|
541 |
switch (this->PlaybackState) { |
switch (this->PlaybackState) { |
542 |
|
|
543 |
case playback_state_init: |
case playback_state_init: |
552 |
|
|
553 |
if (DiskVoice) { |
if (DiskVoice) { |
554 |
// check if we reached the allowed limit of the sample RAM cache |
// check if we reached the allowed limit of the sample RAM cache |
555 |
if (Pos > MaxRAMPos) { |
if (finalSynthesisParameters.dPos > MaxRAMPos) { |
556 |
dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos)); |
dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", finalSynthesisParameters.dPos)); |
557 |
this->PlaybackState = playback_state_disk; |
this->PlaybackState = playback_state_disk; |
558 |
} |
} |
559 |
} |
} else if (finalSynthesisParameters.dPos >= pSample->GetCache().Size / pSample->FrameSize) { |
|
else if (Pos >= pSample->GetCache().Size / pSample->FrameSize) { |
|
560 |
this->PlaybackState = playback_state_end; |
this->PlaybackState = playback_state_end; |
561 |
} |
} |
562 |
} |
} |
571 |
KillImmediately(); |
KillImmediately(); |
572 |
return; |
return; |
573 |
} |
} |
574 |
DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(Pos) - MaxRAMPos)); |
DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(finalSynthesisParameters.dPos) - MaxRAMPos)); |
575 |
Pos -= int(Pos); |
finalSynthesisParameters.dPos -= int(finalSynthesisParameters.dPos); |
576 |
RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet |
RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet |
577 |
} |
} |
578 |
|
|
593 |
// render current audio fragment |
// render current audio fragment |
594 |
Synthesize(Samples, ptr, Delay); |
Synthesize(Samples, ptr, Delay); |
595 |
|
|
596 |
const int iPos = (int) Pos; |
const int iPos = (int) finalSynthesisParameters.dPos; |
597 |
const int readSampleWords = iPos * pSample->Channels; // amount of sample words actually been read |
const int readSampleWords = iPos * pSample->Channels; // amount of sample words actually been read |
598 |
DiskStreamRef.pStream->IncrementReadPos(readSampleWords); |
DiskStreamRef.pStream->IncrementReadPos(readSampleWords); |
599 |
Pos -= iPos; // just keep fractional part of Pos |
finalSynthesisParameters.dPos -= iPos; // just keep fractional part of playback position |
600 |
|
|
601 |
// change state of voice to 'end' if we really reached the end of the sample data |
// change state of voice to 'end' if we really reached the end of the sample data |
602 |
if (RealSampleWordsLeftToRead >= 0) { |
if (RealSampleWordsLeftToRead >= 0) { |
611 |
break; |
break; |
612 |
} |
} |
613 |
|
|
|
// Reset synthesis event lists (except VCO, as VCO events apply channel wide currently) |
|
|
pEngineChannel->pSynthesisEvents[Event::destination_vca]->clear(); |
|
|
pEngineChannel->pSynthesisEvents[Event::destination_vcfc]->clear(); |
|
|
pEngineChannel->pSynthesisEvents[Event::destination_vcfr]->clear(); |
|
|
|
|
614 |
// Reset delay |
// Reset delay |
615 |
Delay = 0; |
Delay = 0; |
616 |
|
|
617 |
itTriggerEvent = Pool<Event>::Iterator(); |
itTriggerEvent = Pool<Event>::Iterator(); |
618 |
|
|
619 |
// If sample stream or release stage finished, kill the voice |
// If sample stream or release stage finished, kill the voice |
620 |
if (PlaybackState == playback_state_end || pEG1->GetStage() == EGADSR::stage_end) KillImmediately(); |
if (PlaybackState == playback_state_end || EG1.getSegmentType() == EGADSR::segment_end) KillImmediately(); |
621 |
} |
} |
622 |
|
|
623 |
/** |
/** |
625 |
* suspended / not running. |
* suspended / not running. |
626 |
*/ |
*/ |
627 |
void Voice::Reset() { |
void Voice::Reset() { |
628 |
pLFO1->Reset(); |
finalSynthesisParameters.filterLeft.Reset(); |
629 |
pLFO2->Reset(); |
finalSynthesisParameters.filterRight.Reset(); |
|
pLFO3->Reset(); |
|
|
FilterLeft.Reset(); |
|
|
FilterRight.Reset(); |
|
630 |
DiskStreamRef.pStream = NULL; |
DiskStreamRef.pStream = NULL; |
631 |
DiskStreamRef.hStream = 0; |
DiskStreamRef.hStream = 0; |
632 |
DiskStreamRef.State = Stream::state_unused; |
DiskStreamRef.State = Stream::state_unused; |
637 |
} |
} |
638 |
|
|
639 |
/** |
/** |
640 |
* 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 |
641 |
* audio fragment. Event values will be applied to the synthesis parameter |
* for the given time. |
|
* matrix. |
|
642 |
* |
* |
643 |
* @param Samples - number of samples to be rendered in this audio fragment cycle |
* @param itEvent - iterator pointing to the next event to be processed |
644 |
|
* @param End - youngest time stamp where processing should be stopped |
645 |
*/ |
*/ |
646 |
void Voice::ProcessEvents(uint Samples) { |
void Voice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) { |
647 |
|
for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) { |
648 |
// dispatch control change events |
if (itEvent->Type == Event::type_release) { |
649 |
RTList<Event>::Iterator itCCEvent = pEngineChannel->pCCEvents->first(); |
EG1.update(EGADSR::event_release, finalSynthesisParameters.dPos, finalSynthesisParameters.fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
650 |
if (Delay) { // skip events that happened before this voice was triggered |
EG2.update(EGADSR::event_release, finalSynthesisParameters.dPos, finalSynthesisParameters.fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
651 |
while (itCCEvent && itCCEvent->FragmentPos() <= Delay) ++itCCEvent; |
} else if (itEvent->Type == Event::type_cancel_release) { |
652 |
} |
EG1.update(EGADSR::event_cancel_release, finalSynthesisParameters.dPos, finalSynthesisParameters.fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
653 |
while (itCCEvent) { |
EG2.update(EGADSR::event_cancel_release, finalSynthesisParameters.dPos, finalSynthesisParameters.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; |
|
|
} |
|
654 |
} |
} |
|
|
|
|
++itCCEvent; |
|
655 |
} |
} |
656 |
|
} |
657 |
|
|
658 |
|
/** |
659 |
// process pitch events |
* Process given list of MIDI control change and pitch bend events for |
660 |
{ |
* the given time. |
661 |
RTList<Event>* pVCOEventList = pEngineChannel->pSynthesisEvents[Event::destination_vco]; |
* |
662 |
RTList<Event>::Iterator itVCOEvent = pVCOEventList->first(); |
* @param itEvent - iterator pointing to the next event to be processed |
663 |
if (Delay) { // skip events that happened before this voice was triggered |
* @param End - youngest time stamp where processing should be stopped |
664 |
while (itVCOEvent && itVCOEvent->FragmentPos() <= Delay) ++itVCOEvent; |
*/ |
665 |
} |
void Voice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) { |
666 |
// apply old pitchbend value until first pitch event occurs |
for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) { |
667 |
if (this->PitchBend != 1.0) { |
if (itEvent->Type == Event::type_control_change && |
668 |
uint end = (itVCOEvent) ? itVCOEvent->FragmentPos() : Samples; |
itEvent->Param.CC.Controller) { // if (valid) MIDI control change event |
669 |
for (uint i = Delay; i < end; i++) { |
if (itEvent->Param.CC.Controller == VCFCutoffCtrl.controller) { |
670 |
pEngine->pSynthesisParameters[Event::destination_vco][i] *= this->PitchBend; |
processCutoffEvent(itEvent); |
671 |
|
} |
672 |
|
if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) { |
673 |
|
processResonanceEvent(itEvent); |
674 |
} |
} |
675 |
} |
if (itEvent->Param.CC.Controller == pLFO1->ExtController) { |
676 |
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; |
|
677 |
} |
} |
678 |
|
if (itEvent->Param.CC.Controller == pLFO2->ExtController) { |
679 |
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); |
|
|
|
|
|
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; |
|
680 |
} |
} |
681 |
|
if (itEvent->Param.CC.Controller == pLFO3->ExtController) { |
682 |
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; |
|
|
|
|
|
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; |
|
683 |
} |
} |
684 |
|
if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange && |
685 |
itCutoffEvent = itNextCutoffEvent; |
itEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) { |
686 |
} |
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; |
|
687 |
} |
} |
688 |
|
} else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event |
689 |
itResonanceEvent = itNextResonanceEvent; |
processPitchEvent(itEvent); |
690 |
} |
} |
|
if (!pResonanceEventList->isEmpty()) VCFResonanceCtrl.fvalue = pResonanceEventList->last()->Param.CC.Value * 0.00787f; // needed for initialization of parameter matrix next time |
|
691 |
} |
} |
692 |
} |
} |
693 |
|
|
694 |
/** |
void Voice::processPitchEvent(RTList<Event>::Iterator& itEvent) { |
695 |
* 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 |
696 |
* |
finalSynthesisParameters.fFinalPitch *= pitch; |
697 |
* @param Samples - number of samples to be rendered in this audio fragment cycle |
PitchBend = pitch; |
698 |
*/ |
} |
|
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); |
|
|
} |
|
|
} |
|
699 |
|
|
700 |
//same as 'pEngine->pBasicFilterParameters[i] = bqbase;' |
void Voice::processCrossFadeEvent(RTList<Event>::Iterator& itEvent) { |
701 |
bq = (float*) &pEngine->pBasicFilterParameters[i]; |
CrossfadeVolume = CrossfadeAttenuation(itEvent->Param.CC.Value); |
702 |
bq[0] = bqbase.b0; |
#if CONFIG_PROCESS_MUTED_CHANNELS |
703 |
bq[1] = bqbase.b1; |
const float effectiveVolume = CrossfadeVolume * Volume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume); |
704 |
bq[2] = bqbase.b2; |
#else |
705 |
bq[3] = bqbase.a1; |
const float effectiveVolume = CrossfadeVolume * Volume * pEngineChannel->GlobalVolume; |
706 |
bq[4] = bqbase.a2; |
#endif |
707 |
|
fFinalVolume = effectiveVolume; |
708 |
// same as 'pEngine->pMainFilterParameters[i] = bqmain;' |
} |
709 |
bq = (float*) &pEngine->pMainFilterParameters[i]; |
|
710 |
bq[0] = bqmain.b0; |
void Voice::processCutoffEvent(RTList<Event>::Iterator& itEvent) { |
711 |
bq[1] = bqmain.b1; |
int ccvalue = itEvent->Param.CC.Value; |
712 |
bq[2] = bqmain.b2; |
if (VCFCutoffCtrl.value == ccvalue) return; |
713 |
bq[3] = bqmain.a1; |
VCFCutoffCtrl.value == ccvalue; |
714 |
bq[4] = bqmain.a2; |
if (pDimRgn->VCFCutoffControllerInvert) ccvalue = 127 - ccvalue; |
715 |
} |
if (ccvalue < pDimRgn->VCFVelocityScale) ccvalue = pDimRgn->VCFVelocityScale; |
716 |
|
float cutoff = CutoffBase * float(ccvalue) * 0.00787402f; // (1 / 127) |
717 |
|
if (cutoff > 1.0) cutoff = 1.0; |
718 |
|
cutoff = exp(cutoff * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MIN - CONFIG_FILTER_CUTOFF_MIN; |
719 |
|
VCFCutoffCtrl.fvalue = cutoff; // needed for initialization of fFinalCutoff next time |
720 |
|
fFinalCutoff = cutoff; |
721 |
|
} |
722 |
|
|
723 |
|
void Voice::processResonanceEvent(RTList<Event>::Iterator& itEvent) { |
724 |
|
// convert absolute controller value to differential |
725 |
|
const int ctrldelta = itEvent->Param.CC.Value - VCFResonanceCtrl.value; |
726 |
|
VCFResonanceCtrl.value = itEvent->Param.CC.Value; |
727 |
|
const float resonancedelta = (float) ctrldelta * 0.00787f; // 0.0..1.0 |
728 |
|
fFinalResonance += resonancedelta; |
729 |
|
// needed for initialization of parameter |
730 |
|
VCFResonanceCtrl.fvalue = itEvent->Param.CC.Value * 0.00787f; |
731 |
} |
} |
732 |
|
|
733 |
/** |
/** |
739 |
* @param Skip - number of sample points to skip in output buffer |
* @param Skip - number of sample points to skip in output buffer |
740 |
*/ |
*/ |
741 |
void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) { |
void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) { |
742 |
RunSynthesisFunction(SynthesisMode, *this, Samples, pSrc, Skip); |
finalSynthesisParameters.pOutLeft = &pEngineChannel->pOutputLeft[Skip]; |
743 |
|
finalSynthesisParameters.pOutRight = &pEngineChannel->pOutputRight[Skip]; |
744 |
|
finalSynthesisParameters.pSrc = pSrc; |
745 |
|
|
746 |
|
RTList<Event>::Iterator itCCEvent = pEngineChannel->pEvents->first(); |
747 |
|
RTList<Event>::Iterator itNoteEvent = pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents->first(); |
748 |
|
|
749 |
|
if (Skip) { // skip events that happened before this voice was triggered |
750 |
|
while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent; |
751 |
|
while (itNoteEvent && itNoteEvent->FragmentPos() <= Skip) ++itNoteEvent; |
752 |
|
} |
753 |
|
|
754 |
|
uint i = Skip; |
755 |
|
while (i < Samples) { |
756 |
|
int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples); |
757 |
|
|
758 |
|
// initialize all final synthesis parameters |
759 |
|
finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend; |
760 |
|
#if CONFIG_PROCESS_MUTED_CHANNELS |
761 |
|
fFinalVolume = this->Volume * this->CrossfadeVolume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume); |
762 |
|
#else |
763 |
|
fFinalVolume = this->Volume * this->CrossfadeVolume * pEngineChannel->GlobalVolume; |
764 |
|
#endif |
765 |
|
fFinalCutoff = VCFCutoffCtrl.fvalue; |
766 |
|
fFinalResonance = VCFResonanceCtrl.fvalue; |
767 |
|
|
768 |
|
// process MIDI control change and pitchbend events for this subfragment |
769 |
|
processCCEvents(itCCEvent, iSubFragmentEnd); |
770 |
|
|
771 |
|
// process transition events (note on, note off & sustain pedal) |
772 |
|
processTransitionEvents(itNoteEvent, iSubFragmentEnd); |
773 |
|
|
774 |
|
// process envelope generators |
775 |
|
switch (EG1.getSegmentType()) { |
776 |
|
case EGADSR::segment_lin: |
777 |
|
fFinalVolume *= EG1.processLin(); |
778 |
|
break; |
779 |
|
case EGADSR::segment_exp: |
780 |
|
fFinalVolume *= EG1.processExp(); |
781 |
|
break; |
782 |
|
case EGADSR::segment_end: |
783 |
|
fFinalVolume *= EG1.getLevel(); |
784 |
|
break; // noop |
785 |
|
} |
786 |
|
switch (EG2.getSegmentType()) { |
787 |
|
case EGADSR::segment_lin: |
788 |
|
fFinalCutoff *= EG2.processLin(); |
789 |
|
break; |
790 |
|
case EGADSR::segment_exp: |
791 |
|
fFinalCutoff *= EG2.processExp(); |
792 |
|
break; |
793 |
|
case EGADSR::segment_end: |
794 |
|
fFinalCutoff *= EG2.getLevel(); |
795 |
|
break; // noop |
796 |
|
} |
797 |
|
if (EG3.active()) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(EG3.render()); |
798 |
|
|
799 |
|
// process low frequency oscillators |
800 |
|
if (bLFO1Enabled) fFinalVolume *= pLFO1->render(); |
801 |
|
if (bLFO2Enabled) fFinalCutoff *= pLFO2->render(); |
802 |
|
if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render()); |
803 |
|
|
804 |
|
// if filter enabled then update filter coefficients |
805 |
|
if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) { |
806 |
|
finalSynthesisParameters.filterLeft.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate); |
807 |
|
finalSynthesisParameters.filterRight.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate); |
808 |
|
} |
809 |
|
|
810 |
|
// do we need resampling? |
811 |
|
const float __PLUS_ONE_CENT = 1.000577789506554859250142541782224725466f; |
812 |
|
const float __MINUS_ONE_CENT = 0.9994225441413807496009516495583113737666f; |
813 |
|
const bool bResamplingRequired = !(finalSynthesisParameters.fFinalPitch <= __PLUS_ONE_CENT && |
814 |
|
finalSynthesisParameters.fFinalPitch >= __MINUS_ONE_CENT); |
815 |
|
SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, bResamplingRequired); |
816 |
|
|
817 |
|
// prepare final synthesis parameters structure |
818 |
|
finalSynthesisParameters.fFinalVolumeLeft = fFinalVolume * PanLeft; |
819 |
|
finalSynthesisParameters.fFinalVolumeRight = fFinalVolume * PanRight; |
820 |
|
finalSynthesisParameters.uiToGo = iSubFragmentEnd - i; |
821 |
|
|
822 |
|
// render audio for one subfragment |
823 |
|
RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop); |
824 |
|
|
825 |
|
// increment envelopes' positions |
826 |
|
if (EG1.active()) { |
827 |
|
EG1.increment(1); |
828 |
|
if (!EG1.toStageEndLeft()) EG1.update(EGADSR::event_stage_end, finalSynthesisParameters.dPos, finalSynthesisParameters.fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
829 |
|
} |
830 |
|
if (EG2.active()) { |
831 |
|
EG2.increment(1); |
832 |
|
if (!EG2.toStageEndLeft()) EG2.update(EGADSR::event_stage_end, finalSynthesisParameters.dPos, finalSynthesisParameters.fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
833 |
|
} |
834 |
|
EG3.increment(1); |
835 |
|
if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached |
836 |
|
|
837 |
|
i = iSubFragmentEnd; |
838 |
|
} |
839 |
} |
} |
840 |
|
|
841 |
/** |
/** |