/[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 319 - (show annotations) (download)
Mon Dec 13 00:46:42 2004 UTC (13 years, 6 months ago) by schoenebeck
File size: 49056 byte(s)
* introduced 'synthesis mode' to reduce the amount of code and conditionals
  for the current synthesis case in the main synthesis loop
* support for MMX and SSE(1) in the core synthesis algorithms (CPU feature
  detection at runtime, only x86 so far)

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

  ViewVC Help
Powered by ViewVC