/[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 247 - (show annotations) (download)
Sun Sep 19 23:44:23 2004 UTC (19 years, 6 months ago) by senkov
File size: 49675 byte(s)
* Small fix to pan coeff. calculation.
* (LS was silent with gigs where pan was 0).

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

  ViewVC Help
Powered by ViewVC