/[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 246 - (show annotations) (download)
Sun Sep 19 14:12:55 2004 UTC (19 years, 6 months ago) by schoenebeck
File size: 49657 byte(s)
just tidied up event type specific parameters (that is note-on specific
parameters, controle change specific parameters, etc.) in Event class

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 PanLeft = float(RTMath::Max(pDimRgn->Pan, 0)) / -64.0f;
259 PanRight = float(RTMath::Min(pDimRgn->Pan, 0)) / 63.0f;
260
261 pSample = pDimRgn->pSample; // sample won't change until the voice is finished
262
263 Pos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
264
265 // Check if the sample needs disk streaming or is too short for that
266 long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;
267 DiskVoice = cachedsamples < pSample->SamplesTotal;
268
269 if (DiskVoice) { // voice to be streamed from disk
270 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)
271
272 // check if there's a loop defined which completely fits into the cached (RAM) part of the sample
273 if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {
274 RAMLoop = true;
275 LoopCyclesLeft = pSample->LoopPlayCount;
276 }
277 else RAMLoop = false;
278
279 if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {
280 dmsg(1,("Disk stream order failed!\n"));
281 KillImmediately();
282 return -1;
283 }
284 dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s)\n", cachedsamples, pSample->SamplesTotal, MaxRAMPos, (RAMLoop) ? "yes" : "no"));
285 }
286 else { // RAM only voice
287 MaxRAMPos = cachedsamples;
288 if (pSample->Loops) {
289 RAMLoop = true;
290 LoopCyclesLeft = pSample->LoopPlayCount;
291 }
292 else RAMLoop = false;
293 dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));
294 }
295
296
297 // calculate initial pitch value
298 {
299 double pitchbasecents = pDimRgn->FineTune * 10 + (int) pEngine->ScaleTuning[MIDIKey % 12];
300 if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;
301 this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate()));
302 this->PitchBend = RTMath::CentsToFreqRatio(((double) PitchBend / 8192.0) * 200.0); // pitchbend wheel +-2 semitones = 200 cents
303 }
304
305
306 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)
307
308
309 // setup EG 1 (VCA EG)
310 {
311 // get current value of EG1 controller
312 double eg1controllervalue;
313 switch (pDimRgn->EG1Controller.type) {
314 case ::gig::eg1_ctrl_t::type_none: // no controller defined
315 eg1controllervalue = 0;
316 break;
317 case ::gig::eg1_ctrl_t::type_channelaftertouch:
318 eg1controllervalue = 0; // TODO: aftertouch not yet supported
319 break;
320 case ::gig::eg1_ctrl_t::type_velocity:
321 eg1controllervalue = pNoteOnEvent->Param.Note.Velocity;
322 break;
323 case ::gig::eg1_ctrl_t::type_controlchange: // MIDI control change controller
324 eg1controllervalue = pEngine->ControllerTable[pDimRgn->EG1Controller.controller_number];
325 break;
326 }
327 if (pDimRgn->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue;
328
329 // calculate influence of EG1 controller on EG1's parameters (TODO: needs to be fine tuned)
330 double eg1attack = (pDimRgn->EG1ControllerAttackInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerAttackInfluence) * eg1controllervalue : 0.0;
331 double eg1decay = (pDimRgn->EG1ControllerDecayInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence) * eg1controllervalue : 0.0;
332 double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 0.0;
333
334 pEG1->Trigger(pDimRgn->EG1PreAttack,
335 pDimRgn->EG1Attack + eg1attack,
336 pDimRgn->EG1Hold,
337 pSample->LoopStart,
338 pDimRgn->EG1Decay1 + eg1decay,
339 pDimRgn->EG1Decay2 + eg1decay,
340 pDimRgn->EG1InfiniteSustain,
341 pDimRgn->EG1Sustain,
342 pDimRgn->EG1Release + eg1release,
343 Delay);
344 }
345
346
347 #if ENABLE_FILTER
348 // setup EG 2 (VCF Cutoff EG)
349 {
350 // get current value of EG2 controller
351 double eg2controllervalue;
352 switch (pDimRgn->EG2Controller.type) {
353 case ::gig::eg2_ctrl_t::type_none: // no controller defined
354 eg2controllervalue = 0;
355 break;
356 case ::gig::eg2_ctrl_t::type_channelaftertouch:
357 eg2controllervalue = 0; // TODO: aftertouch not yet supported
358 break;
359 case ::gig::eg2_ctrl_t::type_velocity:
360 eg2controllervalue = pNoteOnEvent->Param.Note.Velocity;
361 break;
362 case ::gig::eg2_ctrl_t::type_controlchange: // MIDI control change controller
363 eg2controllervalue = pEngine->ControllerTable[pDimRgn->EG2Controller.controller_number];
364 break;
365 }
366 if (pDimRgn->EG2ControllerInvert) eg2controllervalue = 127 - eg2controllervalue;
367
368 // calculate influence of EG2 controller on EG2's parameters (TODO: needs to be fine tuned)
369 double eg2attack = (pDimRgn->EG2ControllerAttackInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerAttackInfluence) * eg2controllervalue : 0.0;
370 double eg2decay = (pDimRgn->EG2ControllerDecayInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerDecayInfluence) * eg2controllervalue : 0.0;
371 double eg2release = (pDimRgn->EG2ControllerReleaseInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerReleaseInfluence) * eg2controllervalue : 0.0;
372
373 pEG2->Trigger(pDimRgn->EG2PreAttack,
374 pDimRgn->EG2Attack + eg2attack,
375 false,
376 pSample->LoopStart,
377 pDimRgn->EG2Decay1 + eg2decay,
378 pDimRgn->EG2Decay2 + eg2decay,
379 pDimRgn->EG2InfiniteSustain,
380 pDimRgn->EG2Sustain,
381 pDimRgn->EG2Release + eg2release,
382 Delay);
383 }
384 #endif // ENABLE_FILTER
385
386
387 // setup EG 3 (VCO EG)
388 {
389 double eg3depth = RTMath::CentsToFreqRatio(pDimRgn->EG3Depth);
390 pEG3->Trigger(eg3depth, pDimRgn->EG3Attack, Delay);
391 }
392
393
394 // setup LFO 1 (VCA LFO)
395 {
396 uint16_t lfo1_internal_depth;
397 switch (pDimRgn->LFO1Controller) {
398 case ::gig::lfo1_ctrl_internal:
399 lfo1_internal_depth = pDimRgn->LFO1InternalDepth;
400 pLFO1->ExtController = 0; // no external controller
401 break;
402 case ::gig::lfo1_ctrl_modwheel:
403 lfo1_internal_depth = 0;
404 pLFO1->ExtController = 1; // MIDI controller 1
405 break;
406 case ::gig::lfo1_ctrl_breath:
407 lfo1_internal_depth = 0;
408 pLFO1->ExtController = 2; // MIDI controller 2
409 break;
410 case ::gig::lfo1_ctrl_internal_modwheel:
411 lfo1_internal_depth = pDimRgn->LFO1InternalDepth;
412 pLFO1->ExtController = 1; // MIDI controller 1
413 break;
414 case ::gig::lfo1_ctrl_internal_breath:
415 lfo1_internal_depth = pDimRgn->LFO1InternalDepth;
416 pLFO1->ExtController = 2; // MIDI controller 2
417 break;
418 default:
419 lfo1_internal_depth = 0;
420 pLFO1->ExtController = 0; // no external controller
421 }
422 pLFO1->Trigger(pDimRgn->LFO1Frequency,
423 lfo1_internal_depth,
424 pDimRgn->LFO1ControlDepth,
425 pEngine->ControllerTable[pLFO1->ExtController],
426 pDimRgn->LFO1FlipPhase,
427 pEngine->SampleRate,
428 Delay);
429 }
430
431 #if ENABLE_FILTER
432 // setup LFO 2 (VCF Cutoff LFO)
433 {
434 uint16_t lfo2_internal_depth;
435 switch (pDimRgn->LFO2Controller) {
436 case ::gig::lfo2_ctrl_internal:
437 lfo2_internal_depth = pDimRgn->LFO2InternalDepth;
438 pLFO2->ExtController = 0; // no external controller
439 break;
440 case ::gig::lfo2_ctrl_modwheel:
441 lfo2_internal_depth = 0;
442 pLFO2->ExtController = 1; // MIDI controller 1
443 break;
444 case ::gig::lfo2_ctrl_foot:
445 lfo2_internal_depth = 0;
446 pLFO2->ExtController = 4; // MIDI controller 4
447 break;
448 case ::gig::lfo2_ctrl_internal_modwheel:
449 lfo2_internal_depth = pDimRgn->LFO2InternalDepth;
450 pLFO2->ExtController = 1; // MIDI controller 1
451 break;
452 case ::gig::lfo2_ctrl_internal_foot:
453 lfo2_internal_depth = pDimRgn->LFO2InternalDepth;
454 pLFO2->ExtController = 4; // MIDI controller 4
455 break;
456 default:
457 lfo2_internal_depth = 0;
458 pLFO2->ExtController = 0; // no external controller
459 }
460 pLFO2->Trigger(pDimRgn->LFO2Frequency,
461 lfo2_internal_depth,
462 pDimRgn->LFO2ControlDepth,
463 pEngine->ControllerTable[pLFO2->ExtController],
464 pDimRgn->LFO2FlipPhase,
465 pEngine->SampleRate,
466 Delay);
467 }
468 #endif // ENABLE_FILTER
469
470 // setup LFO 3 (VCO LFO)
471 {
472 uint16_t lfo3_internal_depth;
473 switch (pDimRgn->LFO3Controller) {
474 case ::gig::lfo3_ctrl_internal:
475 lfo3_internal_depth = pDimRgn->LFO3InternalDepth;
476 pLFO3->ExtController = 0; // no external controller
477 break;
478 case ::gig::lfo3_ctrl_modwheel:
479 lfo3_internal_depth = 0;
480 pLFO3->ExtController = 1; // MIDI controller 1
481 break;
482 case ::gig::lfo3_ctrl_aftertouch:
483 lfo3_internal_depth = 0;
484 pLFO3->ExtController = 0; // TODO: aftertouch not implemented yet
485 break;
486 case ::gig::lfo3_ctrl_internal_modwheel:
487 lfo3_internal_depth = pDimRgn->LFO3InternalDepth;
488 pLFO3->ExtController = 1; // MIDI controller 1
489 break;
490 case ::gig::lfo3_ctrl_internal_aftertouch:
491 lfo3_internal_depth = pDimRgn->LFO3InternalDepth;
492 pLFO1->ExtController = 0; // TODO: aftertouch not implemented yet
493 break;
494 default:
495 lfo3_internal_depth = 0;
496 pLFO3->ExtController = 0; // no external controller
497 }
498 pLFO3->Trigger(pDimRgn->LFO3Frequency,
499 lfo3_internal_depth,
500 pDimRgn->LFO3ControlDepth,
501 pEngine->ControllerTable[pLFO3->ExtController],
502 false,
503 pEngine->SampleRate,
504 Delay);
505 }
506
507 #if ENABLE_FILTER
508 #if FORCE_FILTER_USAGE
509 FilterLeft.Enabled = FilterRight.Enabled = true;
510 #else // use filter only if instrument file told so
511 FilterLeft.Enabled = FilterRight.Enabled = pDimRgn->VCFEnabled;
512 #endif // FORCE_FILTER_USAGE
513 if (pDimRgn->VCFEnabled) {
514 #ifdef OVERRIDE_FILTER_CUTOFF_CTRL
515 VCFCutoffCtrl.controller = OVERRIDE_FILTER_CUTOFF_CTRL;
516 #else // use the one defined in the instrument file
517 switch (pDimRgn->VCFCutoffController) {
518 case ::gig::vcf_cutoff_ctrl_modwheel:
519 VCFCutoffCtrl.controller = 1;
520 break;
521 case ::gig::vcf_cutoff_ctrl_effect1:
522 VCFCutoffCtrl.controller = 12;
523 break;
524 case ::gig::vcf_cutoff_ctrl_effect2:
525 VCFCutoffCtrl.controller = 13;
526 break;
527 case ::gig::vcf_cutoff_ctrl_breath:
528 VCFCutoffCtrl.controller = 2;
529 break;
530 case ::gig::vcf_cutoff_ctrl_foot:
531 VCFCutoffCtrl.controller = 4;
532 break;
533 case ::gig::vcf_cutoff_ctrl_sustainpedal:
534 VCFCutoffCtrl.controller = 64;
535 break;
536 case ::gig::vcf_cutoff_ctrl_softpedal:
537 VCFCutoffCtrl.controller = 67;
538 break;
539 case ::gig::vcf_cutoff_ctrl_genpurpose7:
540 VCFCutoffCtrl.controller = 82;
541 break;
542 case ::gig::vcf_cutoff_ctrl_genpurpose8:
543 VCFCutoffCtrl.controller = 83;
544 break;
545 case ::gig::vcf_cutoff_ctrl_aftertouch: //TODO: not implemented yet
546 case ::gig::vcf_cutoff_ctrl_none:
547 default:
548 VCFCutoffCtrl.controller = 0;
549 break;
550 }
551 #endif // OVERRIDE_FILTER_CUTOFF_CTRL
552
553 #ifdef OVERRIDE_FILTER_RES_CTRL
554 VCFResonanceCtrl.controller = OVERRIDE_FILTER_RES_CTRL;
555 #else // use the one defined in the instrument file
556 switch (pDimRgn->VCFResonanceController) {
557 case ::gig::vcf_res_ctrl_genpurpose3:
558 VCFResonanceCtrl.controller = 18;
559 break;
560 case ::gig::vcf_res_ctrl_genpurpose4:
561 VCFResonanceCtrl.controller = 19;
562 break;
563 case ::gig::vcf_res_ctrl_genpurpose5:
564 VCFResonanceCtrl.controller = 80;
565 break;
566 case ::gig::vcf_res_ctrl_genpurpose6:
567 VCFResonanceCtrl.controller = 81;
568 break;
569 case ::gig::vcf_res_ctrl_none:
570 default:
571 VCFResonanceCtrl.controller = 0;
572 }
573 #endif // OVERRIDE_FILTER_RES_CTRL
574
575 #ifndef OVERRIDE_FILTER_TYPE
576 FilterLeft.SetType(pDimRgn->VCFType);
577 FilterRight.SetType(pDimRgn->VCFType);
578 #else // override filter type
579 FilterLeft.SetType(OVERRIDE_FILTER_TYPE);
580 FilterRight.SetType(OVERRIDE_FILTER_TYPE);
581 #endif // OVERRIDE_FILTER_TYPE
582
583 VCFCutoffCtrl.value = pEngine->ControllerTable[VCFCutoffCtrl.controller];
584 VCFResonanceCtrl.value = pEngine->ControllerTable[VCFResonanceCtrl.controller];
585
586 // calculate cutoff frequency
587 float cutoff = (!VCFCutoffCtrl.controller)
588 ? exp((float) (127 - pNoteOnEvent->Param.Note.Velocity) * (float) pDimRgn->VCFVelocityScale * 6.2E-5f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX
589 : exp((float) VCFCutoffCtrl.value * 0.00787402f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX;
590
591 // calculate resonance
592 float resonance = (float) VCFResonanceCtrl.value * 0.00787f; // 0.0..1.0
593 if (pDimRgn->VCFKeyboardTracking) {
594 resonance += (float) (pNoteOnEvent->Param.Note.Key - pDimRgn->VCFKeyboardTrackingBreakpoint) * 0.00787f;
595 }
596 Constrain(resonance, 0.0, 1.0); // correct resonance if outside allowed value range (0.0..1.0)
597
598 VCFCutoffCtrl.fvalue = cutoff - FILTER_CUTOFF_MIN;
599 VCFResonanceCtrl.fvalue = resonance;
600
601 FilterLeft.SetParameters(cutoff, resonance, pEngine->SampleRate);
602 FilterRight.SetParameters(cutoff, resonance, pEngine->SampleRate);
603
604 FilterUpdateCounter = -1;
605 }
606 else {
607 VCFCutoffCtrl.controller = 0;
608 VCFResonanceCtrl.controller = 0;
609 }
610 #endif // ENABLE_FILTER
611
612 return 0; // success
613 }
614
615 /**
616 * Renders the audio data for this voice for the current audio fragment.
617 * The sample input data can either come from RAM (cached sample or sample
618 * part) or directly from disk. The output signal will be rendered by
619 * resampling / interpolation. If this voice is a disk streaming voice and
620 * the voice completely played back the cached RAM part of the sample, it
621 * will automatically switch to disk playback for the next RenderAudio()
622 * call.
623 *
624 * @param Samples - number of samples to be rendered in this audio fragment cycle
625 */
626 void Voice::Render(uint Samples) {
627
628 // Reset the synthesis parameter matrix
629 pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngine->GlobalVolume);
630 pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase);
631 #if ENABLE_FILTER
632 pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue);
633 pEngine->ResetSynthesisParameters(Event::destination_vcfr, VCFResonanceCtrl.fvalue);
634 #endif // ENABLE_FILTER
635
636
637 // Apply events to the synthesis parameter matrix
638 ProcessEvents(Samples);
639
640
641 // Let all modulators write their parameter changes to the synthesis parameter matrix for the current audio fragment
642 pEG1->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->PitchBase * this->PitchBend, pKillEvent);
643 #if ENABLE_FILTER
644 pEG2->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);
645 #endif // ENABLE_FILTER
646 pEG3->Process(Samples);
647 pLFO1->Process(Samples);
648 #if ENABLE_FILTER
649 pLFO2->Process(Samples);
650 #endif // ENABLE_FILTER
651 pLFO3->Process(Samples);
652
653
654 #if ENABLE_FILTER
655 CalculateBiquadParameters(Samples); // calculate the final biquad filter parameters
656 #endif // ENABLE_FILTER
657
658
659 switch (this->PlaybackState) {
660
661 case playback_state_ram: {
662 if (RAMLoop) InterpolateAndLoop(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
663 else InterpolateNoLoop(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
664 if (DiskVoice) {
665 // check if we reached the allowed limit of the sample RAM cache
666 if (Pos > MaxRAMPos) {
667 dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos));
668 this->PlaybackState = playback_state_disk;
669 }
670 }
671 else if (Pos >= pSample->GetCache().Size / pSample->FrameSize) {
672 this->PlaybackState = playback_state_end;
673 }
674 }
675 break;
676
677 case playback_state_disk: {
678 if (!DiskStreamRef.pStream) {
679 // check if the disk thread created our ordered disk stream in the meantime
680 DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);
681 if (!DiskStreamRef.pStream) {
682 std::cout << stderr << "Disk stream not available in time!" << std::endl << std::flush;
683 KillImmediately();
684 return;
685 }
686 DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (RTMath::DoubleToInt(Pos) - MaxRAMPos));
687 Pos -= RTMath::DoubleToInt(Pos);
688 }
689
690 // add silence sample at the end if we reached the end of the stream (for the interpolator)
691 if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels) {
692 DiskStreamRef.pStream->WriteSilence((pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels);
693 this->PlaybackState = playback_state_end;
694 }
695
696 sample_t* ptr = DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from
697 InterpolateNoLoop(Samples, ptr, Delay);
698 DiskStreamRef.pStream->IncrementReadPos(RTMath::DoubleToInt(Pos) * pSample->Channels);
699 Pos -= RTMath::DoubleToInt(Pos);
700 }
701 break;
702
703 case playback_state_end:
704 KillImmediately(); // free voice
705 break;
706 }
707
708
709 // Reset synthesis event lists (except VCO, as VCO events apply channel wide currently)
710 pEngine->pSynthesisEvents[Event::destination_vca]->clear();
711 #if ENABLE_FILTER
712 pEngine->pSynthesisEvents[Event::destination_vcfc]->clear();
713 pEngine->pSynthesisEvents[Event::destination_vcfr]->clear();
714 #endif // ENABLE_FILTER
715
716 // Reset delay
717 Delay = 0;
718
719 pTriggerEvent = NULL;
720
721 // If release stage finished, let the voice be killed
722 if (pEG1->GetStage() == EGADSR::stage_end) this->PlaybackState = playback_state_end;
723 }
724
725 /**
726 * Resets voice variables. Should only be called if rendering process is
727 * suspended / not running.
728 */
729 void Voice::Reset() {
730 pLFO1->Reset();
731 pLFO2->Reset();
732 pLFO3->Reset();
733 DiskStreamRef.pStream = NULL;
734 DiskStreamRef.hStream = 0;
735 DiskStreamRef.State = Stream::state_unused;
736 DiskStreamRef.OrderID = 0;
737 Active = false;
738 }
739
740 /**
741 * Process the control change event lists of the engine for the current
742 * audio fragment. Event values will be applied to the synthesis parameter
743 * matrix.
744 *
745 * @param Samples - number of samples to be rendered in this audio fragment cycle
746 */
747 void Voice::ProcessEvents(uint Samples) {
748
749 // dispatch control change events
750 Event* pCCEvent = pEngine->pCCEvents->first();
751 if (Delay) { // skip events that happened before this voice was triggered
752 while (pCCEvent && pCCEvent->FragmentPos() <= Delay) pCCEvent = pEngine->pCCEvents->next();
753 }
754 while (pCCEvent) {
755 if (pCCEvent->Param.CC.Controller) { // if valid MIDI controller
756 #if ENABLE_FILTER
757 if (pCCEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {
758 pEngine->pSynthesisEvents[Event::destination_vcfc]->alloc_assign(*pCCEvent);
759 }
760 if (pCCEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
761 pEngine->pSynthesisEvents[Event::destination_vcfr]->alloc_assign(*pCCEvent);
762 }
763 #endif // ENABLE_FILTER
764 if (pCCEvent->Param.CC.Controller == pLFO1->ExtController) {
765 pLFO1->SendEvent(pCCEvent);
766 }
767 #if ENABLE_FILTER
768 if (pCCEvent->Param.CC.Controller == pLFO2->ExtController) {
769 pLFO2->SendEvent(pCCEvent);
770 }
771 #endif // ENABLE_FILTER
772 if (pCCEvent->Param.CC.Controller == pLFO3->ExtController) {
773 pLFO3->SendEvent(pCCEvent);
774 }
775 if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange &&
776 pCCEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) { // if crossfade event
777 pEngine->pSynthesisEvents[Event::destination_vca]->alloc_assign(*pCCEvent);
778 }
779 }
780
781 pCCEvent = pEngine->pCCEvents->next();
782 }
783
784
785 // process pitch events
786 {
787 RTEList<Event>* pVCOEventList = pEngine->pSynthesisEvents[Event::destination_vco];
788 Event* pVCOEvent = pVCOEventList->first();
789 if (Delay) { // skip events that happened before this voice was triggered
790 while (pVCOEvent && pVCOEvent->FragmentPos() <= Delay) pVCOEvent = pVCOEventList->next();
791 }
792 // apply old pitchbend value until first pitch event occurs
793 if (this->PitchBend != 1.0) {
794 uint end = (pVCOEvent) ? pVCOEvent->FragmentPos() : Samples;
795 for (uint i = Delay; i < end; i++) {
796 pEngine->pSynthesisParameters[Event::destination_vco][i] *= this->PitchBend;
797 }
798 }
799 float pitch;
800 while (pVCOEvent) {
801 Event* pNextVCOEvent = pVCOEventList->next();
802
803 // calculate the influence length of this event (in sample points)
804 uint end = (pNextVCOEvent) ? pNextVCOEvent->FragmentPos() : Samples;
805
806 pitch = RTMath::CentsToFreqRatio(((double) pVCOEvent->Param.Pitch.Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents
807
808 // apply pitch value to the pitch parameter sequence
809 for (uint i = pVCOEvent->FragmentPos(); i < end; i++) {
810 pEngine->pSynthesisParameters[Event::destination_vco][i] *= pitch;
811 }
812
813 pVCOEvent = pNextVCOEvent;
814 }
815 if (pVCOEventList->last()) this->PitchBend = pitch;
816 }
817
818 // process volume / attenuation events (TODO: we only handle and _expect_ crossfade events here ATM !)
819 {
820 RTEList<Event>* pVCAEventList = pEngine->pSynthesisEvents[Event::destination_vca];
821 Event* pVCAEvent = pVCAEventList->first();
822 if (Delay) { // skip events that happened before this voice was triggered
823 while (pVCAEvent && pVCAEvent->FragmentPos() <= Delay) pVCAEvent = pVCAEventList->next();
824 }
825 float crossfadevolume;
826 while (pVCAEvent) {
827 Event* pNextVCAEvent = pVCAEventList->next();
828
829 // calculate the influence length of this event (in sample points)
830 uint end = (pNextVCAEvent) ? pNextVCAEvent->FragmentPos() : Samples;
831
832 crossfadevolume = CrossfadeAttenuation(pVCAEvent->Param.CC.Value);
833
834 float effective_volume = crossfadevolume * this->Volume * pEngine->GlobalVolume;
835
836 // apply volume value to the volume parameter sequence
837 for (uint i = pVCAEvent->FragmentPos(); i < end; i++) {
838 pEngine->pSynthesisParameters[Event::destination_vca][i] = effective_volume;
839 }
840
841 pVCAEvent = pNextVCAEvent;
842 }
843 if (pVCAEventList->last()) this->CrossfadeVolume = crossfadevolume;
844 }
845
846 #if ENABLE_FILTER
847 // process filter cutoff events
848 {
849 RTEList<Event>* pCutoffEventList = pEngine->pSynthesisEvents[Event::destination_vcfc];
850 Event* pCutoffEvent = pCutoffEventList->first();
851 if (Delay) { // skip events that happened before this voice was triggered
852 while (pCutoffEvent && pCutoffEvent->FragmentPos() <= Delay) pCutoffEvent = pCutoffEventList->next();
853 }
854 float cutoff;
855 while (pCutoffEvent) {
856 Event* pNextCutoffEvent = pCutoffEventList->next();
857
858 // calculate the influence length of this event (in sample points)
859 uint end = (pNextCutoffEvent) ? pNextCutoffEvent->FragmentPos() : Samples;
860
861 cutoff = exp((float) pCutoffEvent->Param.CC.Value * 0.00787402f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX - FILTER_CUTOFF_MIN;
862
863 // apply cutoff frequency to the cutoff parameter sequence
864 for (uint i = pCutoffEvent->FragmentPos(); i < end; i++) {
865 pEngine->pSynthesisParameters[Event::destination_vcfc][i] = cutoff;
866 }
867
868 pCutoffEvent = pNextCutoffEvent;
869 }
870 if (pCutoffEventList->last()) VCFCutoffCtrl.fvalue = cutoff; // needed for initialization of parameter matrix next time
871 }
872
873 // process filter resonance events
874 {
875 RTEList<Event>* pResonanceEventList = pEngine->pSynthesisEvents[Event::destination_vcfr];
876 Event* pResonanceEvent = pResonanceEventList->first();
877 if (Delay) { // skip events that happened before this voice was triggered
878 while (pResonanceEvent && pResonanceEvent->FragmentPos() <= Delay) pResonanceEvent = pResonanceEventList->next();
879 }
880 while (pResonanceEvent) {
881 Event* pNextResonanceEvent = pResonanceEventList->next();
882
883 // calculate the influence length of this event (in sample points)
884 uint end = (pNextResonanceEvent) ? pNextResonanceEvent->FragmentPos() : Samples;
885
886 // convert absolute controller value to differential
887 int ctrldelta = pResonanceEvent->Param.CC.Value - VCFResonanceCtrl.value;
888 VCFResonanceCtrl.value = pResonanceEvent->Param.CC.Value;
889
890 float resonancedelta = (float) ctrldelta * 0.00787f; // 0.0..1.0
891
892 // apply cutoff frequency to the cutoff parameter sequence
893 for (uint i = pResonanceEvent->FragmentPos(); i < end; i++) {
894 pEngine->pSynthesisParameters[Event::destination_vcfr][i] += resonancedelta;
895 }
896
897 pResonanceEvent = pNextResonanceEvent;
898 }
899 if (pResonanceEventList->last()) VCFResonanceCtrl.fvalue = pResonanceEventList->last()->Param.CC.Value * 0.00787f; // needed for initialization of parameter matrix next time
900 }
901 #endif // ENABLE_FILTER
902 }
903
904 #if ENABLE_FILTER
905 /**
906 * Calculate all necessary, final biquad filter parameters.
907 *
908 * @param Samples - number of samples to be rendered in this audio fragment cycle
909 */
910 void Voice::CalculateBiquadParameters(uint Samples) {
911 if (!FilterLeft.Enabled) return;
912
913 biquad_param_t bqbase;
914 biquad_param_t bqmain;
915 float prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][0];
916 float prev_res = pEngine->pSynthesisParameters[Event::destination_vcfr][0];
917 FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
918 pEngine->pBasicFilterParameters[0] = bqbase;
919 pEngine->pMainFilterParameters[0] = bqmain;
920
921 float* bq;
922 for (int i = 1; i < Samples; i++) {
923 // recalculate biquad parameters if cutoff or resonance differ from previous sample point
924 if (!(i & FILTER_UPDATE_MASK)) if (pEngine->pSynthesisParameters[Event::destination_vcfr][i] != prev_res ||
925 pEngine->pSynthesisParameters[Event::destination_vcfc][i] != prev_cutoff) {
926 prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i];
927 prev_res = pEngine->pSynthesisParameters[Event::destination_vcfr][i];
928 FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
929 }
930
931 //same as 'pEngine->pBasicFilterParameters[i] = bqbase;'
932 bq = (float*) &pEngine->pBasicFilterParameters[i];
933 bq[0] = bqbase.a1;
934 bq[1] = bqbase.a2;
935 bq[2] = bqbase.b0;
936 bq[3] = bqbase.b1;
937 bq[4] = bqbase.b2;
938
939 // same as 'pEngine->pMainFilterParameters[i] = bqmain;'
940 bq = (float*) &pEngine->pMainFilterParameters[i];
941 bq[0] = bqmain.a1;
942 bq[1] = bqmain.a2;
943 bq[2] = bqmain.b0;
944 bq[3] = bqmain.b1;
945 bq[4] = bqmain.b2;
946 }
947 }
948 #endif // ENABLE_FILTER
949
950 /**
951 * Interpolates the input audio data (without looping).
952 *
953 * @param Samples - number of sample points to be rendered in this audio
954 * fragment cycle
955 * @param pSrc - pointer to input sample data
956 * @param Skip - number of sample points to skip in output buffer
957 */
958 void Voice::InterpolateNoLoop(uint Samples, sample_t* pSrc, uint Skip) {
959 int i = Skip;
960
961 // FIXME: assuming either mono or stereo
962 if (this->pSample->Channels == 2) { // Stereo Sample
963 while (i < Samples) InterpolateStereo(pSrc, i);
964 }
965 else { // Mono Sample
966 while (i < Samples) InterpolateMono(pSrc, i);
967 }
968 }
969
970 /**
971 * Interpolates the input audio data, this method honors looping.
972 *
973 * @param Samples - number of sample points to be rendered in this audio
974 * fragment cycle
975 * @param pSrc - pointer to input sample data
976 * @param Skip - number of sample points to skip in output buffer
977 */
978 void Voice::InterpolateAndLoop(uint Samples, sample_t* pSrc, uint Skip) {
979 int i = Skip;
980
981 // FIXME: assuming either mono or stereo
982 if (pSample->Channels == 2) { // Stereo Sample
983 if (pSample->LoopPlayCount) {
984 // render loop (loop count limited)
985 while (i < Samples && LoopCyclesLeft) {
986 InterpolateStereo(pSrc, i);
987 if (Pos > pSample->LoopEnd) {
988 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
989 LoopCyclesLeft--;
990 }
991 }
992 // render on without loop
993 while (i < Samples) InterpolateStereo(pSrc, i);
994 }
995 else { // render loop (endless loop)
996 while (i < Samples) {
997 InterpolateStereo(pSrc, i);
998 if (Pos > pSample->LoopEnd) {
999 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);
1000 }
1001 }
1002 }
1003 }
1004 else { // Mono Sample
1005 if (pSample->LoopPlayCount) {
1006 // render loop (loop count limited)
1007 while (i < Samples && LoopCyclesLeft) {
1008 InterpolateMono(pSrc, i);
1009 if (Pos > pSample->LoopEnd) {
1010 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
1011 LoopCyclesLeft--;
1012 }
1013 }
1014 // render on without loop
1015 while (i < Samples) InterpolateMono(pSrc, i);
1016 }
1017 else { // render loop (endless loop)
1018 while (i < Samples) {
1019 InterpolateMono(pSrc, i);
1020 if (Pos > pSample->LoopEnd) {
1021 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
1022 }
1023 }
1024 }
1025 }
1026 }
1027
1028 /**
1029 * Immediately kill the voice. This method should not be used to kill
1030 * a normal, active voice, because it doesn't take care of things like
1031 * fading down the volume level to avoid clicks and regular processing
1032 * until the kill event actually occured!
1033 *
1034 * @see Kill()
1035 */
1036 void Voice::KillImmediately() {
1037 if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
1038 pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
1039 }
1040 Reset();
1041 }
1042
1043 /**
1044 * Kill the voice in regular sense. Let the voice render audio until
1045 * the kill event actually occured and then fade down the volume level
1046 * very quickly and let the voice die finally. Unlike a normal release
1047 * of a voice, a kill process cannot be cancalled and is therefore
1048 * usually used for voice stealing and key group conflicts.
1049 *
1050 * @param pKillEvent - event which caused the voice to be killed
1051 */
1052 void Voice::Kill(Event* pKillEvent) {
1053 if (pTriggerEvent && pKillEvent->FragmentPos() <= pTriggerEvent->FragmentPos()) return;
1054 this->pKillEvent = pKillEvent;
1055 }
1056
1057 }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC