/[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 922 - (show annotations) (download)
Mon Oct 2 18:40:10 2006 UTC (12 years, 2 months ago) by persson
File size: 47949 byte(s)
* small fix of LFO1 behaviour (dampening from max volume instead of
  amplifying from 0)
* added checks for bad MIDI data

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

  ViewVC Help
Powered by ViewVC