/[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 841 - (show annotations) (download)
Sat Mar 4 16:23:53 2006 UTC (13 years, 7 months ago) by persson
File size: 48126 byte(s)
* fixed concurrency problems between the main thread doing
  lscp notifications and the lscp thread
* bug fix: the LFOs were not properly initialized

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

  ViewVC Help
Powered by ViewVC