/[svn]/linuxsampler/trunk/src/engines/gig/Voice.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/gig/Voice.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 325 - (show annotations) (download)
Tue Dec 21 04:54:37 2004 UTC (19 years, 3 months ago) by senkov
File size: 49636 byte(s)
* Added some profiling capabilities, bugs.

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
20 * MA 02111-1307 USA *
21 ***************************************************************************/
22
23 #include "EGADSR.h"
24 #include "Manipulator.h"
25 #include "../../common/Features.h"
26 #include "Synthesizer.h"
27
28 #include "Voice.h"
29
30 namespace LinuxSampler { namespace gig {
31
32 const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff());
33
34 const int Voice::FILTER_UPDATE_MASK(CalculateFilterUpdateMask());
35
36 float Voice::CalculateFilterCutoffCoeff() {
37 return log(FILTER_CUTOFF_MIN / FILTER_CUTOFF_MAX);
38 }
39
40 int Voice::CalculateFilterUpdateMask() {
41 if (FILTER_UPDATE_PERIOD <= 0) return 0;
42 int power_of_two;
43 for (power_of_two = 0; 1<<power_of_two < FILTER_UPDATE_PERIOD; power_of_two++);
44 return (1 << power_of_two) - 1;
45 }
46
47 Voice::Voice() {
48 pEngine = NULL;
49 pDiskThread = NULL;
50 PlaybackState = playback_state_end;
51 pEG1 = NULL;
52 pEG2 = NULL;
53 pEG3 = NULL;
54 pVCAManipulator = NULL;
55 pVCFCManipulator = NULL;
56 pVCOManipulator = NULL;
57 pLFO1 = NULL;
58 pLFO2 = NULL;
59 pLFO3 = NULL;
60 KeyGroup = 0;
61
62 // select synthesis implementation (currently either pure C++ or MMX+SSE(1))
63 SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, Features::supportsMMX() && Features::supportsSSE());
64 SYNTHESIS_MODE_SET_PROFILING(SynthesisMode, true);
65 }
66
67 Voice::~Voice() {
68 if (pEG1) delete pEG1;
69 if (pEG2) delete pEG2;
70 if (pEG3) delete pEG3;
71 if (pLFO1) delete pLFO1;
72 if (pLFO2) delete pLFO2;
73 if (pLFO3) delete pLFO3;
74 if (pVCAManipulator) delete pVCAManipulator;
75 if (pVCFCManipulator) delete pVCFCManipulator;
76 if (pVCOManipulator) delete pVCOManipulator;
77 }
78
79 void Voice::SetEngine(Engine* pEngine) {
80 this->pEngine = pEngine;
81
82 // delete old objects
83 if (pEG1) delete pEG1;
84 if (pEG2) delete pEG2;
85 if (pEG3) delete pEG3;
86 if (pVCAManipulator) delete pVCAManipulator;
87 if (pVCFCManipulator) delete pVCFCManipulator;
88 if (pVCOManipulator) delete pVCOManipulator;
89 if (pLFO1) delete pLFO1;
90 if (pLFO2) delete pLFO2;
91 if (pLFO3) delete pLFO3;
92
93 // create new ones
94 pEG1 = new EGADSR(pEngine, Event::destination_vca);
95 pEG2 = new EGADSR(pEngine, Event::destination_vcfc);
96 pEG3 = new EGDecay(pEngine, Event::destination_vco);
97 pVCAManipulator = new VCAManipulator(pEngine);
98 pVCFCManipulator = new VCFCManipulator(pEngine);
99 pVCOManipulator = new VCOManipulator(pEngine);
100 pLFO1 = new LFO<gig::VCAManipulator>(0.0f, 1.0f, LFO<VCAManipulator>::propagation_top_down, pVCAManipulator, pEngine->pEventPool);
101 pLFO2 = new LFO<gig::VCFCManipulator>(0.0f, 1.0f, LFO<VCFCManipulator>::propagation_top_down, pVCFCManipulator, pEngine->pEventPool);
102 pLFO3 = new LFO<gig::VCOManipulator>(-1200.0f, 1200.0f, LFO<VCOManipulator>::propagation_middle_balanced, pVCOManipulator, pEngine->pEventPool); // +-1 octave (+-1200 cents) max.
103
104 this->pDiskThread = pEngine->pDiskThread;
105 dmsg(6,("Voice::SetEngine()\n"));
106 }
107
108 /**
109 * Initializes and triggers the voice, a disk stream will be launched if
110 * needed.
111 *
112 * @param itNoteOnEvent - event that caused triggering of this voice
113 * @param PitchBend - MIDI detune factor (-8192 ... +8191)
114 * @param pInstrument - points to the loaded instrument which provides sample wave(s) and articulation data
115 * @param iLayer - layer number this voice refers to (only if this is a layered sound of course)
116 * @param ReleaseTriggerVoice - if this new voice is a release trigger voice (optional, default = false)
117 * @param VoiceStealing - wether the voice is allowed to steal voices for further subvoices
118 * @returns 0 on success, a value < 0 if something failed
119 */
120 int Voice::Trigger(Pool<Event>::Iterator& itNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing) {
121 if (!pInstrument) {
122 dmsg(1,("voice::trigger: !pInstrument\n"));
123 exit(EXIT_FAILURE);
124 }
125 if (itNoteOnEvent->FragmentPos() > pEngine->MaxSamplesPerCycle) { // FIXME: should be removed before the final release (purpose: just a sanity check for debugging)
126 dmsg(1,("Voice::Trigger(): ERROR, TriggerDelay > Totalsamples\n"));
127 }
128
129 Type = type_normal;
130 MIDIKey = itNoteOnEvent->Param.Note.Key;
131 pRegion = pInstrument->GetRegion(MIDIKey);
132 PlaybackState = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed
133 Delay = itNoteOnEvent->FragmentPos();
134 itTriggerEvent = itNoteOnEvent;
135 itKillEvent = Pool<Event>::Iterator();
136 itChildVoice = Pool<Voice>::Iterator();
137
138 if (!pRegion) {
139 std::cerr << "gig::Voice: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush;
140 KillImmediately();
141 return -1;
142 }
143
144 KeyGroup = pRegion->KeyGroup;
145
146 // get current dimension values to select the right dimension region
147 //FIXME: controller values for selecting the dimension region here are currently not sample accurate
148 uint DimValues[5] = {0,0,0,0,0};
149 for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
150 switch (pRegion->pDimensionDefinitions[i].dimension) {
151 case ::gig::dimension_samplechannel:
152 DimValues[i] = 0; //TODO: we currently ignore this dimension
153 break;
154 case ::gig::dimension_layer:
155 DimValues[i] = iLayer;
156 // if this is the 1st layer then spawn further voices for all the other layers
157 if (iLayer == 0)
158 for (int iNewLayer = 1; iNewLayer < pRegion->pDimensionDefinitions[i].zones; iNewLayer++)
159 itChildVoice = pEngine->LaunchVoice(itNoteOnEvent, iNewLayer, ReleaseTriggerVoice, VoiceStealing);
160 break;
161 case ::gig::dimension_velocity:
162 DimValues[i] = itNoteOnEvent->Param.Note.Velocity;
163 break;
164 case ::gig::dimension_channelaftertouch:
165 DimValues[i] = 0; //TODO: we currently ignore this dimension
166 break;
167 case ::gig::dimension_releasetrigger:
168 Type = (ReleaseTriggerVoice) ? type_release_trigger : (!iLayer) ? type_release_trigger_required : type_normal;
169 DimValues[i] = (uint) ReleaseTriggerVoice;
170 break;
171 case ::gig::dimension_keyboard:
172 DimValues[i] = (uint) itNoteOnEvent->Param.Note.Key;
173 break;
174 case ::gig::dimension_modwheel:
175 DimValues[i] = pEngine->ControllerTable[1];
176 break;
177 case ::gig::dimension_breath:
178 DimValues[i] = pEngine->ControllerTable[2];
179 break;
180 case ::gig::dimension_foot:
181 DimValues[i] = pEngine->ControllerTable[4];
182 break;
183 case ::gig::dimension_portamentotime:
184 DimValues[i] = pEngine->ControllerTable[5];
185 break;
186 case ::gig::dimension_effect1:
187 DimValues[i] = pEngine->ControllerTable[12];
188 break;
189 case ::gig::dimension_effect2:
190 DimValues[i] = pEngine->ControllerTable[13];
191 break;
192 case ::gig::dimension_genpurpose1:
193 DimValues[i] = pEngine->ControllerTable[16];
194 break;
195 case ::gig::dimension_genpurpose2:
196 DimValues[i] = pEngine->ControllerTable[17];
197 break;
198 case ::gig::dimension_genpurpose3:
199 DimValues[i] = pEngine->ControllerTable[18];
200 break;
201 case ::gig::dimension_genpurpose4:
202 DimValues[i] = pEngine->ControllerTable[19];
203 break;
204 case ::gig::dimension_sustainpedal:
205 DimValues[i] = pEngine->ControllerTable[64];
206 break;
207 case ::gig::dimension_portamento:
208 DimValues[i] = pEngine->ControllerTable[65];
209 break;
210 case ::gig::dimension_sostenutopedal:
211 DimValues[i] = pEngine->ControllerTable[66];
212 break;
213 case ::gig::dimension_softpedal:
214 DimValues[i] = pEngine->ControllerTable[67];
215 break;
216 case ::gig::dimension_genpurpose5:
217 DimValues[i] = pEngine->ControllerTable[80];
218 break;
219 case ::gig::dimension_genpurpose6:
220 DimValues[i] = pEngine->ControllerTable[81];
221 break;
222 case ::gig::dimension_genpurpose7:
223 DimValues[i] = pEngine->ControllerTable[82];
224 break;
225 case ::gig::dimension_genpurpose8:
226 DimValues[i] = pEngine->ControllerTable[83];
227 break;
228 case ::gig::dimension_effect1depth:
229 DimValues[i] = pEngine->ControllerTable[91];
230 break;
231 case ::gig::dimension_effect2depth:
232 DimValues[i] = pEngine->ControllerTable[92];
233 break;
234 case ::gig::dimension_effect3depth:
235 DimValues[i] = pEngine->ControllerTable[93];
236 break;
237 case ::gig::dimension_effect4depth:
238 DimValues[i] = pEngine->ControllerTable[94];
239 break;
240 case ::gig::dimension_effect5depth:
241 DimValues[i] = pEngine->ControllerTable[95];
242 break;
243 case ::gig::dimension_none:
244 std::cerr << "gig::Voice::Trigger() Error: dimension=none\n" << std::flush;
245 break;
246 default:
247 std::cerr << "gig::Voice::Trigger() Error: Unknown dimension\n" << std::flush;
248 }
249 }
250 pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);
251
252 pSample = pDimRgn->pSample; // sample won't change until the voice is finished
253
254 // select channel mode (mono or stereo)
255 SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2);
256
257 // get starting crossfade volume level
258 switch (pDimRgn->AttenuationController.type) {
259 case ::gig::attenuation_ctrl_t::type_channelaftertouch:
260 CrossfadeVolume = 1.0f; //TODO: aftertouch not supported yet
261 break;
262 case ::gig::attenuation_ctrl_t::type_velocity:
263 CrossfadeVolume = CrossfadeAttenuation(itNoteOnEvent->Param.Note.Velocity);
264 break;
265 case ::gig::attenuation_ctrl_t::type_controlchange: //FIXME: currently not sample accurate
266 CrossfadeVolume = CrossfadeAttenuation(pEngine->ControllerTable[pDimRgn->AttenuationController.controller_number]);
267 break;
268 case ::gig::attenuation_ctrl_t::type_none: // no crossfade defined
269 default:
270 CrossfadeVolume = 1.0f;
271 }
272
273 PanLeft = 1.0f - float(RTMath::Max(pDimRgn->Pan, 0)) / 63.0f;
274 PanRight = 1.0f - float(RTMath::Min(pDimRgn->Pan, 0)) / -64.0f;
275
276 Pos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
277
278 // Check if the sample needs disk streaming or is too short for that
279 long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;
280 DiskVoice = cachedsamples < pSample->SamplesTotal;
281
282 if (DiskVoice) { // voice to be streamed from disk
283 MaxRAMPos = cachedsamples - (pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels; //TODO: this calculation is too pessimistic and may better be moved to Render() method, so it calculates MaxRAMPos dependent to the current demand of sample points to be rendered (e.g. in case of JACK)
284
285 // check if there's a loop defined which completely fits into the cached (RAM) part of the sample
286 if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {
287 RAMLoop = true;
288 LoopCyclesLeft = pSample->LoopPlayCount;
289 }
290 else RAMLoop = false;
291
292 if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {
293 dmsg(1,("Disk stream order failed!\n"));
294 KillImmediately();
295 return -1;
296 }
297 dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s)\n", cachedsamples, pSample->SamplesTotal, MaxRAMPos, (RAMLoop) ? "yes" : "no"));
298 }
299 else { // RAM only voice
300 MaxRAMPos = cachedsamples;
301 if (pSample->Loops) {
302 RAMLoop = true;
303 LoopCyclesLeft = pSample->LoopPlayCount;
304 }
305 else RAMLoop = false;
306 dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));
307 }
308
309
310 // calculate initial pitch value
311 {
312 double pitchbasecents = pDimRgn->FineTune * 10 + (int) pEngine->ScaleTuning[MIDIKey % 12];
313 if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;
314 this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate()));
315 this->PitchBend = RTMath::CentsToFreqRatio(((double) PitchBend / 8192.0) * 200.0); // pitchbend wheel +-2 semitones = 200 cents
316 }
317
318 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)
319
320 // setup EG 1 (VCA EG)
321 {
322 // get current value of EG1 controller
323 double eg1controllervalue;
324 switch (pDimRgn->EG1Controller.type) {
325 case ::gig::eg1_ctrl_t::type_none: // no controller defined
326 eg1controllervalue = 0;
327 break;
328 case ::gig::eg1_ctrl_t::type_channelaftertouch:
329 eg1controllervalue = 0; // TODO: aftertouch not yet supported
330 break;
331 case ::gig::eg1_ctrl_t::type_velocity:
332 eg1controllervalue = itNoteOnEvent->Param.Note.Velocity;
333 break;
334 case ::gig::eg1_ctrl_t::type_controlchange: // MIDI control change controller
335 eg1controllervalue = pEngine->ControllerTable[pDimRgn->EG1Controller.controller_number];
336 break;
337 }
338 if (pDimRgn->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue;
339
340 // calculate influence of EG1 controller on EG1's parameters (TODO: needs to be fine tuned)
341 double eg1attack = (pDimRgn->EG1ControllerAttackInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerAttackInfluence) * eg1controllervalue : 0.0;
342 double eg1decay = (pDimRgn->EG1ControllerDecayInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence) * eg1controllervalue : 0.0;
343 double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 0.0;
344
345 pEG1->Trigger(pDimRgn->EG1PreAttack,
346 pDimRgn->EG1Attack + eg1attack,
347 pDimRgn->EG1Hold,
348 pSample->LoopStart,
349 pDimRgn->EG1Decay1 + eg1decay,
350 pDimRgn->EG1Decay2 + eg1decay,
351 pDimRgn->EG1InfiniteSustain,
352 pDimRgn->EG1Sustain,
353 pDimRgn->EG1Release + eg1release,
354 Delay);
355 }
356
357
358 // setup EG 2 (VCF Cutoff EG)
359 {
360 // get current value of EG2 controller
361 double eg2controllervalue;
362 switch (pDimRgn->EG2Controller.type) {
363 case ::gig::eg2_ctrl_t::type_none: // no controller defined
364 eg2controllervalue = 0;
365 break;
366 case ::gig::eg2_ctrl_t::type_channelaftertouch:
367 eg2controllervalue = 0; // TODO: aftertouch not yet supported
368 break;
369 case ::gig::eg2_ctrl_t::type_velocity:
370 eg2controllervalue = itNoteOnEvent->Param.Note.Velocity;
371 break;
372 case ::gig::eg2_ctrl_t::type_controlchange: // MIDI control change controller
373 eg2controllervalue = pEngine->ControllerTable[pDimRgn->EG2Controller.controller_number];
374 break;
375 }
376 if (pDimRgn->EG2ControllerInvert) eg2controllervalue = 127 - eg2controllervalue;
377
378 // calculate influence of EG2 controller on EG2's parameters (TODO: needs to be fine tuned)
379 double eg2attack = (pDimRgn->EG2ControllerAttackInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerAttackInfluence) * eg2controllervalue : 0.0;
380 double eg2decay = (pDimRgn->EG2ControllerDecayInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerDecayInfluence) * eg2controllervalue : 0.0;
381 double eg2release = (pDimRgn->EG2ControllerReleaseInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerReleaseInfluence) * eg2controllervalue : 0.0;
382
383 pEG2->Trigger(pDimRgn->EG2PreAttack,
384 pDimRgn->EG2Attack + eg2attack,
385 false,
386 pSample->LoopStart,
387 pDimRgn->EG2Decay1 + eg2decay,
388 pDimRgn->EG2Decay2 + eg2decay,
389 pDimRgn->EG2InfiniteSustain,
390 pDimRgn->EG2Sustain,
391 pDimRgn->EG2Release + eg2release,
392 Delay);
393 }
394
395
396 // setup EG 3 (VCO EG)
397 {
398 double eg3depth = RTMath::CentsToFreqRatio(pDimRgn->EG3Depth);
399 pEG3->Trigger(eg3depth, pDimRgn->EG3Attack, Delay);
400 }
401
402
403 // setup LFO 1 (VCA LFO)
404 {
405 uint16_t lfo1_internal_depth;
406 switch (pDimRgn->LFO1Controller) {
407 case ::gig::lfo1_ctrl_internal:
408 lfo1_internal_depth = pDimRgn->LFO1InternalDepth;
409 pLFO1->ExtController = 0; // no external controller
410 break;
411 case ::gig::lfo1_ctrl_modwheel:
412 lfo1_internal_depth = 0;
413 pLFO1->ExtController = 1; // MIDI controller 1
414 break;
415 case ::gig::lfo1_ctrl_breath:
416 lfo1_internal_depth = 0;
417 pLFO1->ExtController = 2; // MIDI controller 2
418 break;
419 case ::gig::lfo1_ctrl_internal_modwheel:
420 lfo1_internal_depth = pDimRgn->LFO1InternalDepth;
421 pLFO1->ExtController = 1; // MIDI controller 1
422 break;
423 case ::gig::lfo1_ctrl_internal_breath:
424 lfo1_internal_depth = pDimRgn->LFO1InternalDepth;
425 pLFO1->ExtController = 2; // MIDI controller 2
426 break;
427 default:
428 lfo1_internal_depth = 0;
429 pLFO1->ExtController = 0; // no external controller
430 }
431 pLFO1->Trigger(pDimRgn->LFO1Frequency,
432 lfo1_internal_depth,
433 pDimRgn->LFO1ControlDepth,
434 pEngine->ControllerTable[pLFO1->ExtController],
435 pDimRgn->LFO1FlipPhase,
436 pEngine->SampleRate,
437 Delay);
438 }
439
440
441 // setup LFO 2 (VCF Cutoff LFO)
442 {
443 uint16_t lfo2_internal_depth;
444 switch (pDimRgn->LFO2Controller) {
445 case ::gig::lfo2_ctrl_internal:
446 lfo2_internal_depth = pDimRgn->LFO2InternalDepth;
447 pLFO2->ExtController = 0; // no external controller
448 break;
449 case ::gig::lfo2_ctrl_modwheel:
450 lfo2_internal_depth = 0;
451 pLFO2->ExtController = 1; // MIDI controller 1
452 break;
453 case ::gig::lfo2_ctrl_foot:
454 lfo2_internal_depth = 0;
455 pLFO2->ExtController = 4; // MIDI controller 4
456 break;
457 case ::gig::lfo2_ctrl_internal_modwheel:
458 lfo2_internal_depth = pDimRgn->LFO2InternalDepth;
459 pLFO2->ExtController = 1; // MIDI controller 1
460 break;
461 case ::gig::lfo2_ctrl_internal_foot:
462 lfo2_internal_depth = pDimRgn->LFO2InternalDepth;
463 pLFO2->ExtController = 4; // MIDI controller 4
464 break;
465 default:
466 lfo2_internal_depth = 0;
467 pLFO2->ExtController = 0; // no external controller
468 }
469 pLFO2->Trigger(pDimRgn->LFO2Frequency,
470 lfo2_internal_depth,
471 pDimRgn->LFO2ControlDepth,
472 pEngine->ControllerTable[pLFO2->ExtController],
473 pDimRgn->LFO2FlipPhase,
474 pEngine->SampleRate,
475 Delay);
476 }
477
478
479 // setup LFO 3 (VCO LFO)
480 {
481 uint16_t lfo3_internal_depth;
482 switch (pDimRgn->LFO3Controller) {
483 case ::gig::lfo3_ctrl_internal:
484 lfo3_internal_depth = pDimRgn->LFO3InternalDepth;
485 pLFO3->ExtController = 0; // no external controller
486 break;
487 case ::gig::lfo3_ctrl_modwheel:
488 lfo3_internal_depth = 0;
489 pLFO3->ExtController = 1; // MIDI controller 1
490 break;
491 case ::gig::lfo3_ctrl_aftertouch:
492 lfo3_internal_depth = 0;
493 pLFO3->ExtController = 0; // TODO: aftertouch not implemented yet
494 break;
495 case ::gig::lfo3_ctrl_internal_modwheel:
496 lfo3_internal_depth = pDimRgn->LFO3InternalDepth;
497 pLFO3->ExtController = 1; // MIDI controller 1
498 break;
499 case ::gig::lfo3_ctrl_internal_aftertouch:
500 lfo3_internal_depth = pDimRgn->LFO3InternalDepth;
501 pLFO1->ExtController = 0; // TODO: aftertouch not implemented yet
502 break;
503 default:
504 lfo3_internal_depth = 0;
505 pLFO3->ExtController = 0; // no external controller
506 }
507 pLFO3->Trigger(pDimRgn->LFO3Frequency,
508 lfo3_internal_depth,
509 pDimRgn->LFO3ControlDepth,
510 pEngine->ControllerTable[pLFO3->ExtController],
511 false,
512 pEngine->SampleRate,
513 Delay);
514 }
515
516
517 #if FORCE_FILTER_USAGE
518 SYNTHESIS_MODE_SET_FILTER(SynthesisMode, true);
519 #else // use filter only if instrument file told so
520 SYNTHESIS_MODE_SET_FILTER(SynthesisMode, pDimRgn->VCFEnabled);
521 #endif // FORCE_FILTER_USAGE
522 if (pDimRgn->VCFEnabled) {
523 #ifdef OVERRIDE_FILTER_CUTOFF_CTRL
524 VCFCutoffCtrl.controller = OVERRIDE_FILTER_CUTOFF_CTRL;
525 #else // use the one defined in the instrument file
526 switch (pDimRgn->VCFCutoffController) {
527 case ::gig::vcf_cutoff_ctrl_modwheel:
528 VCFCutoffCtrl.controller = 1;
529 break;
530 case ::gig::vcf_cutoff_ctrl_effect1:
531 VCFCutoffCtrl.controller = 12;
532 break;
533 case ::gig::vcf_cutoff_ctrl_effect2:
534 VCFCutoffCtrl.controller = 13;
535 break;
536 case ::gig::vcf_cutoff_ctrl_breath:
537 VCFCutoffCtrl.controller = 2;
538 break;
539 case ::gig::vcf_cutoff_ctrl_foot:
540 VCFCutoffCtrl.controller = 4;
541 break;
542 case ::gig::vcf_cutoff_ctrl_sustainpedal:
543 VCFCutoffCtrl.controller = 64;
544 break;
545 case ::gig::vcf_cutoff_ctrl_softpedal:
546 VCFCutoffCtrl.controller = 67;
547 break;
548 case ::gig::vcf_cutoff_ctrl_genpurpose7:
549 VCFCutoffCtrl.controller = 82;
550 break;
551 case ::gig::vcf_cutoff_ctrl_genpurpose8:
552 VCFCutoffCtrl.controller = 83;
553 break;
554 case ::gig::vcf_cutoff_ctrl_aftertouch: //TODO: not implemented yet
555 case ::gig::vcf_cutoff_ctrl_none:
556 default:
557 VCFCutoffCtrl.controller = 0;
558 break;
559 }
560 #endif // OVERRIDE_FILTER_CUTOFF_CTRL
561
562 #ifdef OVERRIDE_FILTER_RES_CTRL
563 VCFResonanceCtrl.controller = OVERRIDE_FILTER_RES_CTRL;
564 #else // use the one defined in the instrument file
565 switch (pDimRgn->VCFResonanceController) {
566 case ::gig::vcf_res_ctrl_genpurpose3:
567 VCFResonanceCtrl.controller = 18;
568 break;
569 case ::gig::vcf_res_ctrl_genpurpose4:
570 VCFResonanceCtrl.controller = 19;
571 break;
572 case ::gig::vcf_res_ctrl_genpurpose5:
573 VCFResonanceCtrl.controller = 80;
574 break;
575 case ::gig::vcf_res_ctrl_genpurpose6:
576 VCFResonanceCtrl.controller = 81;
577 break;
578 case ::gig::vcf_res_ctrl_none:
579 default:
580 VCFResonanceCtrl.controller = 0;
581 }
582 #endif // OVERRIDE_FILTER_RES_CTRL
583
584 #ifndef OVERRIDE_FILTER_TYPE
585 FilterLeft.SetType(pDimRgn->VCFType);
586 FilterRight.SetType(pDimRgn->VCFType);
587 #else // override filter type
588 FilterLeft.SetType(OVERRIDE_FILTER_TYPE);
589 FilterRight.SetType(OVERRIDE_FILTER_TYPE);
590 #endif // OVERRIDE_FILTER_TYPE
591
592 VCFCutoffCtrl.value = pEngine->ControllerTable[VCFCutoffCtrl.controller];
593 VCFResonanceCtrl.value = pEngine->ControllerTable[VCFResonanceCtrl.controller];
594
595 // calculate cutoff frequency
596 float cutoff = (!VCFCutoffCtrl.controller)
597 ? exp((float) (127 - itNoteOnEvent->Param.Note.Velocity) * (float) pDimRgn->VCFVelocityScale * 6.2E-5f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX
598 : exp((float) VCFCutoffCtrl.value * 0.00787402f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX;
599
600 // calculate resonance
601 float resonance = (float) VCFResonanceCtrl.value * 0.00787f; // 0.0..1.0
602 if (pDimRgn->VCFKeyboardTracking) {
603 resonance += (float) (itNoteOnEvent->Param.Note.Key - pDimRgn->VCFKeyboardTrackingBreakpoint) * 0.00787f;
604 }
605 Constrain(resonance, 0.0, 1.0); // correct resonance if outside allowed value range (0.0..1.0)
606
607 VCFCutoffCtrl.fvalue = cutoff - FILTER_CUTOFF_MIN;
608 VCFResonanceCtrl.fvalue = resonance;
609
610 FilterUpdateCounter = -1;
611 }
612 else {
613 VCFCutoffCtrl.controller = 0;
614 VCFResonanceCtrl.controller = 0;
615 }
616
617 return 0; // success
618 }
619
620 /**
621 * Renders the audio data for this voice for the current audio fragment.
622 * The sample input data can either come from RAM (cached sample or sample
623 * part) or directly from disk. The output signal will be rendered by
624 * resampling / interpolation. If this voice is a disk streaming voice and
625 * the voice completely played back the cached RAM part of the sample, it
626 * will automatically switch to disk playback for the next RenderAudio()
627 * call.
628 *
629 * @param Samples - number of samples to be rendered in this audio fragment cycle
630 */
631 void Voice::Render(uint Samples) {
632
633 // select default values for synthesis mode bits
634 SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, (PitchBase * PitchBend) != 1.0f);
635 SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, true);
636 SYNTHESIS_MODE_SET_LOOP(SynthesisMode, false);
637
638 // Reset the synthesis parameter matrix
639
640 pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngine->GlobalVolume);
641 pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase);
642 pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue);
643 pEngine->ResetSynthesisParameters(Event::destination_vcfr, VCFResonanceCtrl.fvalue);
644
645 // Apply events to the synthesis parameter matrix
646 ProcessEvents(Samples);
647
648 // Let all modulators write their parameter changes to the synthesis parameter matrix for the current audio fragment
649 pEG1->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend, itKillEvent);
650 pEG2->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);
651 if (pEG3->Process(Samples)) { // if pitch EG is active
652 SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true);
653 SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false);
654 }
655 pLFO1->Process(Samples);
656 pLFO2->Process(Samples);
657 if (pLFO3->Process(Samples)) { // if pitch LFO modulation is active
658 SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true);
659 SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false);
660 }
661
662 if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode))
663 CalculateBiquadParameters(Samples); // calculate the final biquad filter parameters
664
665 switch (this->PlaybackState) {
666
667 case playback_state_ram: {
668 if (RAMLoop) SYNTHESIS_MODE_SET_LOOP(SynthesisMode, true); // enable looping
669
670 // render current fragment
671 Synthesize(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
672
673 if (DiskVoice) {
674 // check if we reached the allowed limit of the sample RAM cache
675 if (Pos > MaxRAMPos) {
676 dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos));
677 this->PlaybackState = playback_state_disk;
678 }
679 }
680 else if (Pos >= pSample->GetCache().Size / pSample->FrameSize) {
681 this->PlaybackState = playback_state_end;
682 }
683 }
684 break;
685
686 case playback_state_disk: {
687 if (!DiskStreamRef.pStream) {
688 // check if the disk thread created our ordered disk stream in the meantime
689 DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);
690 if (!DiskStreamRef.pStream) {
691 std::cout << stderr << "Disk stream not available in time!" << std::endl << std::flush;
692 KillImmediately();
693 return;
694 }
695 DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(Pos) - MaxRAMPos));
696 Pos -= int(Pos);
697 }
698
699 const int sampleWordsLeftToRead = DiskStreamRef.pStream->GetReadSpace();
700
701 // add silence sample at the end if we reached the end of the stream (for the interpolator)
702 if (DiskStreamRef.State == Stream::state_end) {
703 const int maxSampleWordsPerCycle = (pEngine->MaxSamplesPerCycle << MAX_PITCH) * pSample->Channels + 6; // +6 for the interpolator algorithm
704 if (sampleWordsLeftToRead <= maxSampleWordsPerCycle) {
705 DiskStreamRef.pStream->WriteSilence(maxSampleWordsPerCycle - sampleWordsLeftToRead);
706 }
707 }
708
709 sample_t* ptr = DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from
710
711 // render current audio fragment
712 Synthesize(Samples, ptr, Delay);
713
714 const int iPos = (int) Pos;
715 const int readSampleWords = iPos * pSample->Channels; // amount of sample words actually been read
716 DiskStreamRef.pStream->IncrementReadPos(readSampleWords);
717 Pos -= iPos; // just keep fractional part of Pos
718
719 // change state of voice to 'end' if we really reached the end of the sample data
720 if (DiskStreamRef.State == Stream::state_end && readSampleWords >= sampleWordsLeftToRead) this->PlaybackState = playback_state_end;
721 }
722 break;
723
724 case playback_state_end:
725 std::cerr << "gig::Voice::Render(): entered with playback_state_end, this is a bug!\n" << std::flush;
726 break;
727 }
728
729 // Reset synthesis event lists (except VCO, as VCO events apply channel wide currently)
730 pEngine->pSynthesisEvents[Event::destination_vca]->clear();
731 pEngine->pSynthesisEvents[Event::destination_vcfc]->clear();
732 pEngine->pSynthesisEvents[Event::destination_vcfr]->clear();
733
734 // Reset delay
735 Delay = 0;
736
737 itTriggerEvent = Pool<Event>::Iterator();
738
739 // If sample stream or release stage finished, kill the voice
740 if (PlaybackState == playback_state_end || pEG1->GetStage() == EGADSR::stage_end) KillImmediately();
741 }
742
743 /**
744 * Resets voice variables. Should only be called if rendering process is
745 * suspended / not running.
746 */
747 void Voice::Reset() {
748 pLFO1->Reset();
749 pLFO2->Reset();
750 pLFO3->Reset();
751 FilterLeft.Reset();
752 FilterRight.Reset();
753 DiskStreamRef.pStream = NULL;
754 DiskStreamRef.hStream = 0;
755 DiskStreamRef.State = Stream::state_unused;
756 DiskStreamRef.OrderID = 0;
757 PlaybackState = playback_state_end;
758 itTriggerEvent = Pool<Event>::Iterator();
759 itKillEvent = Pool<Event>::Iterator();
760 }
761
762 /**
763 * Process the control change event lists of the engine for the current
764 * audio fragment. Event values will be applied to the synthesis parameter
765 * matrix.
766 *
767 * @param Samples - number of samples to be rendered in this audio fragment cycle
768 */
769 void Voice::ProcessEvents(uint Samples) {
770
771 // dispatch control change events
772 RTList<Event>::Iterator itCCEvent = pEngine->pCCEvents->first();
773 if (Delay) { // skip events that happened before this voice was triggered
774 while (itCCEvent && itCCEvent->FragmentPos() <= Delay) ++itCCEvent;
775 }
776 while (itCCEvent) {
777 if (itCCEvent->Param.CC.Controller) { // if valid MIDI controller
778 if (itCCEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {
779 *pEngine->pSynthesisEvents[Event::destination_vcfc]->allocAppend() = *itCCEvent;
780 }
781 if (itCCEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
782 *pEngine->pSynthesisEvents[Event::destination_vcfr]->allocAppend() = *itCCEvent;
783 }
784 if (itCCEvent->Param.CC.Controller == pLFO1->ExtController) {
785 pLFO1->SendEvent(itCCEvent);
786 }
787 if (itCCEvent->Param.CC.Controller == pLFO2->ExtController) {
788 pLFO2->SendEvent(itCCEvent);
789 }
790 if (itCCEvent->Param.CC.Controller == pLFO3->ExtController) {
791 pLFO3->SendEvent(itCCEvent);
792 }
793 if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange &&
794 itCCEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) { // if crossfade event
795 *pEngine->pSynthesisEvents[Event::destination_vca]->allocAppend() = *itCCEvent;
796 }
797 }
798
799 ++itCCEvent;
800 }
801
802
803 // process pitch events
804 {
805 RTList<Event>* pVCOEventList = pEngine->pSynthesisEvents[Event::destination_vco];
806 RTList<Event>::Iterator itVCOEvent = pVCOEventList->first();
807 if (Delay) { // skip events that happened before this voice was triggered
808 while (itVCOEvent && itVCOEvent->FragmentPos() <= Delay) ++itVCOEvent;
809 }
810 // apply old pitchbend value until first pitch event occurs
811 if (this->PitchBend != 1.0) {
812 uint end = (itVCOEvent) ? itVCOEvent->FragmentPos() : Samples;
813 for (uint i = Delay; i < end; i++) {
814 pEngine->pSynthesisParameters[Event::destination_vco][i] *= this->PitchBend;
815 }
816 }
817 float pitch;
818 while (itVCOEvent) {
819 RTList<Event>::Iterator itNextVCOEvent = itVCOEvent;
820 ++itNextVCOEvent;
821
822 // calculate the influence length of this event (in sample points)
823 uint end = (itNextVCOEvent) ? itNextVCOEvent->FragmentPos() : Samples;
824
825 pitch = RTMath::CentsToFreqRatio(((double) itVCOEvent->Param.Pitch.Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents
826
827 // apply pitch value to the pitch parameter sequence
828 for (uint i = itVCOEvent->FragmentPos(); i < end; i++) {
829 pEngine->pSynthesisParameters[Event::destination_vco][i] *= pitch;
830 }
831
832 itVCOEvent = itNextVCOEvent;
833 }
834 if (!pVCOEventList->isEmpty()) {
835 this->PitchBend = pitch;
836 SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true);
837 SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false);
838 }
839 }
840
841 // process volume / attenuation events (TODO: we only handle and _expect_ crossfade events here ATM !)
842 {
843 RTList<Event>* pVCAEventList = pEngine->pSynthesisEvents[Event::destination_vca];
844 RTList<Event>::Iterator itVCAEvent = pVCAEventList->first();
845 if (Delay) { // skip events that happened before this voice was triggered
846 while (itVCAEvent && itVCAEvent->FragmentPos() <= Delay) ++itVCAEvent;
847 }
848 float crossfadevolume;
849 while (itVCAEvent) {
850 RTList<Event>::Iterator itNextVCAEvent = itVCAEvent;
851 ++itNextVCAEvent;
852
853 // calculate the influence length of this event (in sample points)
854 uint end = (itNextVCAEvent) ? itNextVCAEvent->FragmentPos() : Samples;
855
856 crossfadevolume = CrossfadeAttenuation(itVCAEvent->Param.CC.Value);
857
858 float effective_volume = crossfadevolume * this->Volume * pEngine->GlobalVolume;
859
860 // apply volume value to the volume parameter sequence
861 for (uint i = itVCAEvent->FragmentPos(); i < end; i++) {
862 pEngine->pSynthesisParameters[Event::destination_vca][i] = effective_volume;
863 }
864
865 itVCAEvent = itNextVCAEvent;
866 }
867 if (!pVCAEventList->isEmpty()) this->CrossfadeVolume = crossfadevolume;
868 }
869
870 // process filter cutoff events
871 {
872 RTList<Event>* pCutoffEventList = pEngine->pSynthesisEvents[Event::destination_vcfc];
873 RTList<Event>::Iterator itCutoffEvent = pCutoffEventList->first();
874 if (Delay) { // skip events that happened before this voice was triggered
875 while (itCutoffEvent && itCutoffEvent->FragmentPos() <= Delay) ++itCutoffEvent;
876 }
877 float cutoff;
878 while (itCutoffEvent) {
879 RTList<Event>::Iterator itNextCutoffEvent = itCutoffEvent;
880 ++itNextCutoffEvent;
881
882 // calculate the influence length of this event (in sample points)
883 uint end = (itNextCutoffEvent) ? itNextCutoffEvent->FragmentPos() : Samples;
884
885 cutoff = exp((float) itCutoffEvent->Param.CC.Value * 0.00787402f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX - FILTER_CUTOFF_MIN;
886
887 // apply cutoff frequency to the cutoff parameter sequence
888 for (uint i = itCutoffEvent->FragmentPos(); i < end; i++) {
889 pEngine->pSynthesisParameters[Event::destination_vcfc][i] = cutoff;
890 }
891
892 itCutoffEvent = itNextCutoffEvent;
893 }
894 if (!pCutoffEventList->isEmpty()) VCFCutoffCtrl.fvalue = cutoff; // needed for initialization of parameter matrix next time
895 }
896
897 // process filter resonance events
898 {
899 RTList<Event>* pResonanceEventList = pEngine->pSynthesisEvents[Event::destination_vcfr];
900 RTList<Event>::Iterator itResonanceEvent = pResonanceEventList->first();
901 if (Delay) { // skip events that happened before this voice was triggered
902 while (itResonanceEvent && itResonanceEvent->FragmentPos() <= Delay) ++itResonanceEvent;
903 }
904 while (itResonanceEvent) {
905 RTList<Event>::Iterator itNextResonanceEvent = itResonanceEvent;
906 ++itNextResonanceEvent;
907
908 // calculate the influence length of this event (in sample points)
909 uint end = (itNextResonanceEvent) ? itNextResonanceEvent->FragmentPos() : Samples;
910
911 // convert absolute controller value to differential
912 int ctrldelta = itResonanceEvent->Param.CC.Value - VCFResonanceCtrl.value;
913 VCFResonanceCtrl.value = itResonanceEvent->Param.CC.Value;
914
915 float resonancedelta = (float) ctrldelta * 0.00787f; // 0.0..1.0
916
917 // apply cutoff frequency to the cutoff parameter sequence
918 for (uint i = itResonanceEvent->FragmentPos(); i < end; i++) {
919 pEngine->pSynthesisParameters[Event::destination_vcfr][i] += resonancedelta;
920 }
921
922 itResonanceEvent = itNextResonanceEvent;
923 }
924 if (!pResonanceEventList->isEmpty()) VCFResonanceCtrl.fvalue = pResonanceEventList->last()->Param.CC.Value * 0.00787f; // needed for initialization of parameter matrix next time
925 }
926 }
927
928 /**
929 * Calculate all necessary, final biquad filter parameters.
930 *
931 * @param Samples - number of samples to be rendered in this audio fragment cycle
932 */
933 void Voice::CalculateBiquadParameters(uint Samples) {
934 biquad_param_t bqbase;
935 biquad_param_t bqmain;
936 float prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][0];
937 float prev_res = pEngine->pSynthesisParameters[Event::destination_vcfr][0];
938 FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
939 FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
940 pEngine->pBasicFilterParameters[0] = bqbase;
941 pEngine->pMainFilterParameters[0] = bqmain;
942
943 float* bq;
944 for (int i = 1; i < Samples; i++) {
945 // recalculate biquad parameters if cutoff or resonance differ from previous sample point
946 if (!(i & FILTER_UPDATE_MASK)) {
947 if (pEngine->pSynthesisParameters[Event::destination_vcfr][i] != prev_res ||
948 pEngine->pSynthesisParameters[Event::destination_vcfc][i] != prev_cutoff)
949 {
950 prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i];
951 prev_res = pEngine->pSynthesisParameters[Event::destination_vcfr][i];
952 FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
953 FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
954 }
955 }
956
957 //same as 'pEngine->pBasicFilterParameters[i] = bqbase;'
958 bq = (float*) &pEngine->pBasicFilterParameters[i];
959 bq[0] = bqbase.b0;
960 bq[1] = bqbase.b1;
961 bq[2] = bqbase.b2;
962 bq[3] = bqbase.a1;
963 bq[4] = bqbase.a2;
964
965 // same as 'pEngine->pMainFilterParameters[i] = bqmain;'
966 bq = (float*) &pEngine->pMainFilterParameters[i];
967 bq[0] = bqmain.b0;
968 bq[1] = bqmain.b1;
969 bq[2] = bqmain.b2;
970 bq[3] = bqmain.a1;
971 bq[4] = bqmain.a2;
972 }
973 }
974
975 /**
976 * Synthesizes the current audio fragment for this voice.
977 *
978 * @param Samples - number of sample points to be rendered in this audio
979 * fragment cycle
980 * @param pSrc - pointer to input sample data
981 * @param Skip - number of sample points to skip in output buffer
982 */
983 void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
984 RunSynthesisFunction(SynthesisMode, *this, Samples, pSrc, Skip);
985 }
986
987 /**
988 * Immediately kill the voice. This method should not be used to kill
989 * a normal, active voice, because it doesn't take care of things like
990 * fading down the volume level to avoid clicks and regular processing
991 * until the kill event actually occured!
992 *
993 * @see Kill()
994 */
995 void Voice::KillImmediately() {
996 if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
997 pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
998 }
999 Reset();
1000 }
1001
1002 /**
1003 * Kill the voice in regular sense. Let the voice render audio until
1004 * the kill event actually occured and then fade down the volume level
1005 * very quickly and let the voice die finally. Unlike a normal release
1006 * of a voice, a kill process cannot be cancalled and is therefore
1007 * usually used for voice stealing and key group conflicts.
1008 *
1009 * @param itKillEvent - event which caused the voice to be killed
1010 */
1011 void Voice::Kill(Pool<Event>::Iterator& itKillEvent) {
1012 //FIXME: just two sanity checks for debugging, can be removed
1013 if (!itKillEvent) dmsg(1,("gig::Voice::Kill(): ERROR, !itKillEvent !!!\n"));
1014 if (itKillEvent && !itKillEvent.isValid()) dmsg(1,("gig::Voice::Kill(): ERROR, itKillEvent invalid !!!\n"));
1015
1016 if (itTriggerEvent && itKillEvent->FragmentPos() <= itTriggerEvent->FragmentPos()) return;
1017 this->itKillEvent = itKillEvent;
1018 }
1019
1020 }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC