/[svn]/linuxsampler/trunk/src/voice.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/voice.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 38 - (show annotations) (download)
Tue Mar 16 13:25:39 2004 UTC (20 years, 1 month ago) by schoenebeck
File size: 29524 byte(s)
* added filters (lowpass, bandpass and highpass), note that filter code is
  currently disabled by default, you have to explicitly enable it in
  src/voice.h by setting define ENABLE_FILTER to 1
* src/eg_vca.cpp: Decay_1 stage now using exponential curve

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003 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 "voice.h"
24
25 // FIXME: no support for layers (nor crossfades) yet
26
27 DiskThread* Voice::pDiskThread = NULL;
28 AudioThread* Voice::pEngine = NULL;
29
30 Voice::Voice() {
31 Active = false;
32 }
33
34 Voice::~Voice() {
35 }
36
37 /**
38 * Initializes and triggers the voice, a disk stream will be launched if
39 * needed.
40 *
41 * @param pNoteOnEvent - event that caused triggering of this voice
42 * @param Pitch - MIDI detune factor (-8192 ... +8191)
43 * @param pInstrument - points to the loaded instrument which provides sample wave(s) and articulation data
44 * @returns 0 on success, a value < 0 if something failed
45 */
46 int Voice::Trigger(ModulationSystem::Event* pNoteOnEvent, int Pitch, gig::Instrument* pInstrument) {
47 Active = true;
48 MIDIKey = pNoteOnEvent->Key;
49 pRegion = pInstrument->GetRegion(MIDIKey);
50 PlaybackState = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed
51 Pos = 0;
52 ReleaseVelocity = 127; // default release velocity value
53 Delay = pNoteOnEvent->FragmentPos();
54 pTriggerEvent = pNoteOnEvent;
55
56 if (!pRegion) {
57 std::cerr << "Audio Thread: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush;
58 Kill();
59 return -1;
60 }
61
62 //TODO: current MIDI controller values are not taken into account yet
63 gig::DimensionRegion* pDimRgn = NULL;
64 for (int i = pRegion->Dimensions - 1; i >= 0; i--) { // Check if instrument has a velocity split
65 if (pRegion->pDimensionDefinitions[i].dimension == gig::dimension_velocity) {
66 uint DimValues[5] = {0,0,0,0,0};
67 DimValues[i] = pNoteOnEvent->Velocity;
68 pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);
69 break;
70 }
71 }
72 if (!pDimRgn) { // if there was no velocity split
73 pDimRgn = pRegion->GetDimensionRegionByValue(0,0,0,0,0);
74 }
75
76 pSample = pDimRgn->pSample; // sample won't change until the voice is finished
77
78 // Check if the sample needs disk streaming or is too short for that
79 long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;
80 DiskVoice = cachedsamples < pSample->SamplesTotal;
81
82 if (DiskVoice) { // voice to be streamed from disk
83 MaxRAMPos = cachedsamples - (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)
84
85 // check if there's a loop defined which completely fits into the cached (RAM) part of the sample
86 if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {
87 RAMLoop = true;
88 LoopCyclesLeft = pSample->LoopPlayCount;
89 }
90 else RAMLoop = false;
91
92 if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {
93 dmsg(1,("Disk stream order failed!\n"));
94 Kill();
95 return -1;
96 }
97 dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s)\n", cachedsamples, pSample->SamplesTotal, MaxRAMPos, (RAMLoop) ? "yes" : "no"));
98 }
99 else { // RAM only voice
100 MaxRAMPos = cachedsamples;
101 if (pSample->Loops) {
102 RAMLoop = true;
103 LoopCyclesLeft = pSample->LoopPlayCount;
104 }
105 else RAMLoop = false;
106 dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));
107 }
108
109
110 // Pitch according to keyboard position (if 'PitchTrack' is set) and given detune factor
111 this->Pitch = ((double) Pitch / 8192.0) / 12.0 + ((pDimRgn->PitchTrack) ? pow(2, ((double) (MIDIKey - (int) pDimRgn->UnityNote) + (double) pDimRgn->FineTune / 100.0) / 12.0)
112 : pow(2, ((double) pDimRgn->FineTune / 100.0) / 12.0));
113
114 Volume = pDimRgn->GetVelocityAttenuation(pNoteOnEvent->Velocity);
115
116 // get current value of EG1 controller
117 double eg1controllervalue;
118 switch (pDimRgn->EG1Controller.type) {
119 case gig::eg1_ctrl_t::type_none: // no controller defined
120 eg1controllervalue = 0;
121 break;
122 case gig::eg1_ctrl_t::type_channelaftertouch:
123 eg1controllervalue = 0; // TODO: aftertouch not yet supported
124 break;
125 case gig::eg1_ctrl_t::type_velocity:
126 eg1controllervalue = pNoteOnEvent->Velocity;
127 break;
128 case gig::eg1_ctrl_t::type_controlchange: // MIDI control change controller
129 eg1controllervalue = pEngine->ControllerTable[pDimRgn->EG1Controller.controller_number];
130 break;
131 }
132 if (pDimRgn->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue;
133
134 // calculate influence of EG1 controller on EG1's parameters (TODO: needs to be fine tuned)
135 double eg1attack = (pDimRgn->EG1ControllerAttackInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerAttackInfluence) * eg1controllervalue : 0.0;
136 double eg1decay = (pDimRgn->EG1ControllerDecayInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence) * eg1controllervalue : 0.0;
137 double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 0.0;
138
139 EG1.Trigger(pDimRgn->EG1PreAttack,
140 pDimRgn->EG1Attack + eg1attack,
141 pDimRgn->EG1Hold,
142 pSample->LoopStart,
143 pDimRgn->EG1Decay1 + eg1decay,
144 pDimRgn->EG1Decay2 + eg1decay,
145 pDimRgn->EG1InfiniteSustain,
146 pDimRgn->EG1Sustain,
147 pDimRgn->EG1Release + eg1release,
148 Delay);
149
150 #if ENABLE_FILTER
151 #if FORCE_FILTER_USAGE
152 FilterLeft.Enabled = FilterRight.Enabled = true;
153 #else // use filter only if instrument file told so
154 FilterLeft.Enabled = FilterRight.Enabled = pDimRgn->VCFEnabled;
155 #endif // FORCE_FILTER_USAGE
156 if (pDimRgn->VCFEnabled) {
157 #ifdef OVERRIDE_FILTER_CUTOFF_CTRL
158 VCFCutoffCtrl.controller = OVERRIDE_FILTER_CUTOFF_CTRL;
159 #else // use the one defined in the instrument file
160 switch (pDimRgn->VCFCutoffController) {
161 case gig::vcf_cutoff_ctrl_modwheel:
162 VCFCutoffCtrl.controller = 1;
163 break;
164 case gig::vcf_cutoff_ctrl_effect1:
165 VCFCutoffCtrl.controller = 12;
166 break;
167 case gig::vcf_cutoff_ctrl_effect2:
168 VCFCutoffCtrl.controller = 13;
169 break;
170 case gig::vcf_cutoff_ctrl_breath:
171 VCFCutoffCtrl.controller = 2;
172 break;
173 case gig::vcf_cutoff_ctrl_foot:
174 VCFCutoffCtrl.controller = 4;
175 break;
176 case gig::vcf_cutoff_ctrl_sustainpedal:
177 VCFCutoffCtrl.controller = 64;
178 break;
179 case gig::vcf_cutoff_ctrl_softpedal:
180 VCFCutoffCtrl.controller = 67;
181 break;
182 case gig::vcf_cutoff_ctrl_genpurpose7:
183 VCFCutoffCtrl.controller = 82;
184 break;
185 case gig::vcf_cutoff_ctrl_genpurpose8:
186 VCFCutoffCtrl.controller = 83;
187 break;
188 case gig::vcf_cutoff_ctrl_aftertouch: //TODO: not implemented yet
189 case gig::vcf_cutoff_ctrl_none:
190 default:
191 VCFCutoffCtrl.controller = 0;
192 break;
193 }
194 #endif // OVERRIDE_FILTER_CUTOFF_CTRL
195
196 #ifdef OVERRIDE_FILTER_RES_CTRL
197 VCFResonanceCtrl.controller = OVERRIDE_FILTER_RES_CTRL;
198 #else // use the one defined in the instrument file
199 switch (pDimRgn->VCFResonanceController) {
200 case gig::vcf_res_ctrl_genpurpose3:
201 VCFResonanceCtrl.controller = 18;
202 break;
203 case gig::vcf_res_ctrl_genpurpose4:
204 VCFResonanceCtrl.controller = 19;
205 break;
206 case gig::vcf_res_ctrl_genpurpose5:
207 VCFResonanceCtrl.controller = 80;
208 break;
209 case gig::vcf_res_ctrl_genpurpose6:
210 VCFResonanceCtrl.controller = 81;
211 break;
212 case gig::vcf_res_ctrl_none:
213 default:
214 VCFResonanceCtrl.controller = 0;
215 }
216 #endif // OVERRIDE_FILTER_RES_CTRL
217
218 #ifndef OVERRIDE_FILTER_TYPE
219 FilterLeft.SetType(pDimRgn->VCFType);
220 FilterRight.SetType(pDimRgn->VCFType);
221 #else // override filter type
222 FilterLeft.SetType(OVERRIDE_FILTER_TYPE);
223 FilterRight.SetType(OVERRIDE_FILTER_TYPE);
224 #endif // OVERRIDE_FILTER_TYPE
225
226 VCFCutoffCtrl.value = pEngine->ControllerTable[VCFCutoffCtrl.controller];
227 VCFResonanceCtrl.value = pEngine->ControllerTable[VCFResonanceCtrl.controller];
228
229 // calculate cutoff frequency
230 float cutoff = (!VCFCutoffCtrl.controller && pDimRgn->VCFVelocityScale)
231 ? (float) pNoteOnEvent->Velocity * pDimRgn->VCFVelocityScale * 0.31f + 20.0f // 20Hz..5kHz
232 : (float) (127 - VCFCutoffCtrl.value) * 39.4f + 20.0f; // 20Hz..5kHz (inverted)
233
234 // calculate resonance
235 float resonance = (float) VCFResonanceCtrl.value * 0.00787f; // 0.0..1.0
236 if (pDimRgn->VCFKeyboardTracking) {
237 resonance += (float) (pNoteOnEvent->Key - pDimRgn->VCFKeyboardTrackingBreakpoint) * 0.00787f;
238 }
239 Constrain(resonance, 0.0, 1.0); // correct resonance if outside allowed value range (0.0..1.0)
240
241 FilterLeft.SetParameters(cutoff, resonance, ModulationSystem::SampleRate());
242 FilterRight.SetParameters(cutoff, resonance, ModulationSystem::SampleRate());
243 }
244 else {
245 VCFCutoffCtrl.controller = 0;
246 VCFResonanceCtrl.controller = 0;
247 }
248 #endif // ENABLE_FILTER
249
250 // ************************************************
251 // TODO: ARTICULATION DATA HANDLING IS MISSING HERE
252 // ************************************************
253
254 return 0; // success
255 }
256
257 /**
258 * Renders the audio data for this voice for the current audio fragment.
259 * The sample input data can either come from RAM (cached sample or sample
260 * part) or directly from disk. The output signal will be rendered by
261 * resampling / interpolation. If this voice is a disk streaming voice and
262 * the voice completely played back the cached RAM part of the sample, it
263 * will automatically switch to disk playback for the next RenderAudio()
264 * call.
265 *
266 * @param Samples - number of samples to be rendered in this audio fragment cycle
267 */
268 void Voice::Render(uint Samples) {
269
270 // Reset the synthesis parameter matrix
271 ModulationSystem::ResetDestinationParameter(ModulationSystem::destination_vca, this->Volume);
272 ModulationSystem::ResetDestinationParameter(ModulationSystem::destination_vco, this->Pitch);
273 #if ENABLE_FILTER
274 ModulationSystem::ResetDestinationParameter(ModulationSystem::destination_vcfc, FilterLeft.Cutoff()); // intialize with last cutoff value from previous render cycle
275 ModulationSystem::ResetDestinationParameter(ModulationSystem::destination_vcfr, FilterLeft.Resonance()); // intialize with last resonance value from previous render cycle
276
277
278 // Reset synthesis event lists (except VCO, as VCO events apply channel wide currently)
279 pEngine->pSynthesisEvents[ModulationSystem::destination_vcfc]->clear();
280 pEngine->pSynthesisEvents[ModulationSystem::destination_vcfr]->clear();
281 #endif // ENABLE_FILTER
282
283
284 // Apply events to the synthesis parameter matrix
285 ProcessEvents(Samples);
286
287
288 // Let all modulators write their parameter changes to the synthesis parameter matrix for the current audio fragment
289 EG1.Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->Pitch);
290
291
292 switch (this->PlaybackState) {
293
294 case playback_state_ram: {
295 if (RAMLoop) InterpolateAndLoop(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
296 else Interpolate(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
297 if (DiskVoice) {
298 // check if we reached the allowed limit of the sample RAM cache
299 if (Pos > MaxRAMPos) {
300 dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos));
301 this->PlaybackState = playback_state_disk;
302 }
303 }
304 else if (Pos >= pSample->GetCache().Size / pSample->FrameSize) {
305 this->PlaybackState = playback_state_end;
306 }
307 }
308 break;
309
310 case playback_state_disk: {
311 if (!DiskStreamRef.pStream) {
312 // check if the disk thread created our ordered disk stream in the meantime
313 DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);
314 if (!DiskStreamRef.pStream) {
315 std::cout << stderr << "Disk stream not available in time!" << std::endl << std::flush;
316 Kill();
317 return;
318 }
319 DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (double_to_int(Pos) - MaxRAMPos));
320 Pos -= double_to_int(Pos);
321 }
322
323 // add silence sample at the end if we reached the end of the stream (for the interpolator)
324 if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels) {
325 DiskStreamRef.pStream->WriteSilence((MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels);
326 this->PlaybackState = playback_state_end;
327 }
328
329 sample_t* ptr = DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from
330 Interpolate(Samples, ptr, Delay);
331 DiskStreamRef.pStream->IncrementReadPos(double_to_int(Pos) * pSample->Channels);
332 Pos -= double_to_int(Pos);
333 }
334 break;
335
336 case playback_state_end:
337 Kill(); // free voice
338 break;
339 }
340
341
342 // Reset delay
343 Delay = 0;
344
345 pTriggerEvent = NULL;
346
347 // If release stage finished, let the voice be killed
348 if (EG1.GetStage() == EG_VCA::stage_end) this->PlaybackState = playback_state_end;
349 }
350
351 /**
352 * Resets voice variables. Should only be called if rendering process is
353 * suspended / not running.
354 */
355 void Voice::Reset() {
356 DiskStreamRef.pStream = NULL;
357 DiskStreamRef.hStream = 0;
358 DiskStreamRef.State = Stream::state_unused;
359 DiskStreamRef.OrderID = 0;
360 Active = false;
361 }
362
363 /**
364 * Process the control change event lists of the engine for the current
365 * audio fragment. Event values will be applied to the synthesis parameter
366 * matrix.
367 *
368 * @param Samples - number of samples to be rendered in this audio fragment cycle
369 */
370 void Voice::ProcessEvents(uint Samples) {
371 #if ENABLE_FILTER
372 // dispatch control change events
373 ModulationSystem::Event* pCCEvent = pEngine->pCCEvents->first();
374 while (pCCEvent) {
375 if (pCCEvent->Controller == VCFCutoffCtrl.controller) {
376 pEngine->pSynthesisEvents[ModulationSystem::destination_vcfc]->alloc_assign(*pCCEvent);
377 }
378 if (pCCEvent->Controller == VCFResonanceCtrl.controller) {
379 pEngine->pSynthesisEvents[ModulationSystem::destination_vcfr]->alloc_assign(*pCCEvent);
380 }
381
382 pCCEvent = pEngine->pCCEvents->next();
383 }
384 #endif // ENABLE_FILTER
385
386 // process pitch events
387 RTEList<ModulationSystem::Event>* pVCOEventList = pEngine->pSynthesisEvents[ModulationSystem::destination_vco];
388 ModulationSystem::Event* pVCOEvent = pVCOEventList->first();
389 while (pVCOEvent) {
390 ModulationSystem::Event* pNextVCOEvent = pVCOEventList->next();
391
392 // calculate the influence length of this event (in sample points)
393 uint end = (pNextVCOEvent) ? pNextVCOEvent->FragmentPos() : Samples;
394
395 this->Pitch += ((double) pVCOEvent->Pitch / 8192.0) / 12.0; // +- one semitone
396
397 // apply pitch value to the pitch parameter sequence
398 for (uint i = pVCOEvent->FragmentPos(); i < end; i++) {
399 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i] = this->Pitch;
400 }
401
402 pVCOEvent = pNextVCOEvent;
403 }
404
405 #if ENABLE_FILTER
406 // process filter cutoff events
407 RTEList<ModulationSystem::Event>* pCutoffEventList = pEngine->pSynthesisEvents[ModulationSystem::destination_vcfc];
408 ModulationSystem::Event* pCutoffEvent = pCutoffEventList->first();
409 while (pCutoffEvent) {
410 ModulationSystem::Event* pNextCutoffEvent = pCutoffEventList->next();
411
412 // calculate the influence length of this event (in sample points)
413 uint end = (pNextCutoffEvent) ? pNextCutoffEvent->FragmentPos() : Samples;
414
415 // convert absolute controller value to differential
416 int ctrldelta = pCutoffEvent->Value - VCFCutoffCtrl.value;
417 VCFCutoffCtrl.value = pCutoffEvent->Value;
418
419 float cutoffdelta = (float) ctrldelta * -39.4f; // (20Hz)..5kHz (inverted)
420
421 // apply cutoff frequency to the cutoff parameter sequence
422 for (uint i = pCutoffEvent->FragmentPos(); i < end; i++) {
423 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i] += cutoffdelta;
424 }
425
426 pCutoffEvent = pNextCutoffEvent;
427 }
428
429 // process filter resonance events
430 RTEList<ModulationSystem::Event>* pResonanceEventList = pEngine->pSynthesisEvents[ModulationSystem::destination_vcfr];
431 ModulationSystem::Event* pResonanceEvent = pResonanceEventList->first();
432 while (pResonanceEvent) {
433 ModulationSystem::Event* pNextResonanceEvent = pResonanceEventList->next();
434
435 // calculate the influence length of this event (in sample points)
436 uint end = (pNextResonanceEvent) ? pNextResonanceEvent->FragmentPos() : Samples;
437
438 // convert absolute controller value to differential
439 int ctrldelta = pResonanceEvent->Value - VCFResonanceCtrl.value;
440 VCFResonanceCtrl.value = pResonanceEvent->Value;
441
442 float resonancedelta = (float) ctrldelta * 0.00787f; // 0.0..1.0
443
444 // apply cutoff frequency to the cutoff parameter sequence
445 for (uint i = pResonanceEvent->FragmentPos(); i < end; i++) {
446 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i] += resonancedelta;
447 }
448
449 pResonanceEvent = pNextResonanceEvent;
450 }
451 #endif // ENABLE_FILTER
452 }
453
454 /**
455 * Interpolates the input audio data (no loop).
456 *
457 * @param Samples - number of sample points to be rendered in this audio
458 * fragment cycle
459 * @param pSrc - pointer to input sample data
460 * @param Skip - number of sample points to skip in output buffer
461 */
462 void Voice::Interpolate(uint Samples, sample_t* pSrc, uint Skip) {
463 int i = Skip;
464
465 // FIXME: assuming either mono or stereo
466 if (this->pSample->Channels == 2) { // Stereo Sample
467 while (i < Samples) {
468 InterpolateOneStep_Stereo(pSrc, i,
469 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
470 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i],
471 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i],
472 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i]);
473 }
474
475 #if ENABLE_FILTER
476 // to save the last filter setting for the next render cycle (only needed when we update the filter not-sample-accurate)
477 ForceUpdateFilter_Stereo(ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][Samples - 1],
478 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][Samples - 1]);
479 #endif // ENABLE_FILTER
480 }
481 else { // Mono Sample
482 while (i < Samples) {
483 InterpolateOneStep_Mono(pSrc, i,
484 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
485 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i],
486 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i],
487 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i]);
488 }
489
490 #if ENABLE_FILTER
491 // to save the last filter setting for the next render cycle (only needed when we update the filter not-sample-accurate)
492 ForceUpdateFilter_Mono(ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][Samples - 1],
493 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][Samples - 1]);
494 #endif // ENABLE_FILTER
495 }
496 }
497
498 /**
499 * Interpolates the input audio data, this method honors looping.
500 *
501 * @param Samples - number of sample points to be rendered in this audio
502 * fragment cycle
503 * @param pSrc - pointer to input sample data
504 * @param Skip - number of sample points to skip in output buffer
505 */
506 void Voice::InterpolateAndLoop(uint Samples, sample_t* pSrc, uint Skip) {
507 int i = Skip;
508
509 // FIXME: assuming either mono or stereo
510 if (pSample->Channels == 2) { // Stereo Sample
511 if (pSample->LoopPlayCount) {
512 // render loop (loop count limited)
513 while (i < Samples && LoopCyclesLeft) {
514 InterpolateOneStep_Stereo(pSrc, i,
515 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
516 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i],
517 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i],
518 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i]);
519 if (Pos > pSample->LoopEnd) {
520 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
521 LoopCyclesLeft--;
522 }
523 }
524 // render on without loop
525 while (i < Samples) {
526 InterpolateOneStep_Stereo(pSrc, i,
527 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
528 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i],
529 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i],
530 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i]);
531 }
532 }
533 else { // render loop (endless loop)
534 while (i < Samples) {
535 InterpolateOneStep_Stereo(pSrc, i,
536 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
537 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i],
538 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i],
539 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i]);
540 if (Pos > pSample->LoopEnd) {
541 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);
542 }
543 }
544 }
545 #if ENABLE_FILTER
546 // to save the last filter setting for the next render cycle (only needed when we update the filter not-sample-accurate)
547 ForceUpdateFilter_Stereo(ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][Samples - 1],
548 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][Samples - 1]);
549 #endif // ENABLE_FILTER
550 }
551 else { // Mono Sample
552 if (pSample->LoopPlayCount) {
553 // render loop (loop count limited)
554 while (i < Samples && LoopCyclesLeft) {
555 InterpolateOneStep_Mono(pSrc, i,
556 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
557 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i],
558 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i],
559 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i]);
560 if (Pos > pSample->LoopEnd) {
561 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
562 LoopCyclesLeft--;
563 }
564 }
565 // render on without loop
566 while (i < Samples) {
567 InterpolateOneStep_Mono(pSrc, i,
568 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
569 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i],
570 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i],
571 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i]);
572 }
573 }
574 else { // render loop (endless loop)
575 while (i < Samples) {
576 InterpolateOneStep_Mono(pSrc, i,
577 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
578 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i],
579 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i],
580 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i]);
581 if (Pos > pSample->LoopEnd) {
582 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
583 }
584 }
585 }
586 #if ENABLE_FILTER
587 // to save the last filter setting for the next render cycle (only needed when we update the filter not-sample-accurate)
588 ForceUpdateFilter_Mono(ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][Samples - 1],
589 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][Samples - 1]);
590 #endif // ENABLE_FILTER
591 }
592 }
593
594 /**
595 * Immediately kill the voice.
596 */
597 void Voice::Kill() {
598 if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
599 pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
600 }
601 Reset();
602 }

  ViewVC Help
Powered by ViewVC