/[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 687 - (show annotations) (download)
Tue Jul 12 22:37:21 2005 UTC (18 years, 9 months ago) by schoenebeck
File size: 48407 byte(s)
* minor efficiency fix (LFO preprocessing was performed even though the
  respective LFO was disabled by the instrument patch)

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

  ViewVC Help
Powered by ViewVC