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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 40 - (show annotations) (download)
Tue Mar 30 13:14:58 2004 UTC (20 years ago) by schoenebeck
File size: 38136 byte(s)
* added Envelope Generator 2 and 3 (filter cutoff EG and pitch EG) for
  accurate .gig playback
* fixed accuracy of pitch calculation
* changed filter cutoff range to 100Hz..10kHz with exponential curve, this
  value range can also be adjusted on compile time by setting
  FILTER_CUTOFF_MIN and FILTER_CUTOFF_MAX in src/voice.h to desired
  frequencies
* src/lfo.h: lfo is now generalized to a C++ template, which will be useful
  especially when we implement further engines

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 const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff());
30
31 float Voice::CalculateFilterCutoffCoeff() {
32 return log(FILTER_CUTOFF_MIN / FILTER_CUTOFF_MAX);
33 }
34
35 Voice::Voice() {
36 Active = false;
37 pEG1 = new EG_VCA(ModulationSystem::destination_vca);
38 pEG2 = new EG_VCA(ModulationSystem::destination_vcfc);
39 pEG3 = new EG_D(ModulationSystem::destination_vco);
40 pLFO1 = new LFO<VCAManipulator>(0.0f, 1.0f, LFO<VCAManipulator>::propagation_top_down, pEngine->pEventPool);
41 pLFO2 = new LFO<VCFCManipulator>(0.0f, 1.0f, LFO<VCFCManipulator>::propagation_top_down, pEngine->pEventPool);
42 pLFO3 = new LFO<VCOManipulator>(-1200.0f, 1200.0f, LFO<VCOManipulator>::propagation_middle_balanced, pEngine->pEventPool); // +-1 octave (+-1200 cents) max.
43 }
44
45 Voice::~Voice() {
46 if (pEG1) delete pEG1;
47 if (pEG2) delete pEG2;
48 if (pEG3) delete pEG3;
49 if (pLFO1) delete pLFO1;
50 if (pLFO2) delete pLFO2;
51 if (pLFO3) delete pLFO3;
52 }
53
54 /**
55 * Initializes and triggers the voice, a disk stream will be launched if
56 * needed.
57 *
58 * @param pNoteOnEvent - event that caused triggering of this voice
59 * @param PitchBend - MIDI detune factor (-8192 ... +8191)
60 * @param pInstrument - points to the loaded instrument which provides sample wave(s) and articulation data
61 * @returns 0 on success, a value < 0 if something failed
62 */
63 int Voice::Trigger(ModulationSystem::Event* pNoteOnEvent, int PitchBend, gig::Instrument* pInstrument) {
64 Active = true;
65 MIDIKey = pNoteOnEvent->Key;
66 pRegion = pInstrument->GetRegion(MIDIKey);
67 PlaybackState = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed
68 Pos = 0;
69 ReleaseVelocity = 127; // default release velocity value
70 Delay = pNoteOnEvent->FragmentPos();
71 pTriggerEvent = pNoteOnEvent;
72
73 if (!pRegion) {
74 std::cerr << "Audio Thread: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush;
75 Kill();
76 return -1;
77 }
78
79 //TODO: current MIDI controller values are not taken into account yet
80 gig::DimensionRegion* pDimRgn = NULL;
81 for (int i = pRegion->Dimensions - 1; i >= 0; i--) { // Check if instrument has a velocity split
82 if (pRegion->pDimensionDefinitions[i].dimension == gig::dimension_velocity) {
83 uint DimValues[5] = {0,0,0,0,0};
84 DimValues[i] = pNoteOnEvent->Velocity;
85 pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);
86 break;
87 }
88 }
89 if (!pDimRgn) { // if there was no velocity split
90 pDimRgn = pRegion->GetDimensionRegionByValue(0,0,0,0,0);
91 }
92
93 pSample = pDimRgn->pSample; // sample won't change until the voice is finished
94
95 // Check if the sample needs disk streaming or is too short for that
96 long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;
97 DiskVoice = cachedsamples < pSample->SamplesTotal;
98
99 if (DiskVoice) { // voice to be streamed from disk
100 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)
101
102 // check if there's a loop defined which completely fits into the cached (RAM) part of the sample
103 if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {
104 RAMLoop = true;
105 LoopCyclesLeft = pSample->LoopPlayCount;
106 }
107 else RAMLoop = false;
108
109 if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {
110 dmsg(1,("Disk stream order failed!\n"));
111 Kill();
112 return -1;
113 }
114 dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s)\n", cachedsamples, pSample->SamplesTotal, MaxRAMPos, (RAMLoop) ? "yes" : "no"));
115 }
116 else { // RAM only voice
117 MaxRAMPos = cachedsamples;
118 if (pSample->Loops) {
119 RAMLoop = true;
120 LoopCyclesLeft = pSample->LoopPlayCount;
121 }
122 else RAMLoop = false;
123 dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));
124 }
125
126
127 // calculate initial pitch value
128 {
129 double pitchbasecents = pDimRgn->FineTune * 10;
130 if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;
131 this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents);
132 this->PitchBend = RTMath::CentsToFreqRatio(((double) PitchBend / 8192.0) * 200.0); // pitchbend wheel +-2 semitones = 200 cents
133 }
134
135
136 Volume = pDimRgn->GetVelocityAttenuation(pNoteOnEvent->Velocity);
137
138
139 // setup EG 1 (VCA EG)
140 {
141 // get current value of EG1 controller
142 double eg1controllervalue;
143 switch (pDimRgn->EG1Controller.type) {
144 case gig::eg1_ctrl_t::type_none: // no controller defined
145 eg1controllervalue = 0;
146 break;
147 case gig::eg1_ctrl_t::type_channelaftertouch:
148 eg1controllervalue = 0; // TODO: aftertouch not yet supported
149 break;
150 case gig::eg1_ctrl_t::type_velocity:
151 eg1controllervalue = pNoteOnEvent->Velocity;
152 break;
153 case gig::eg1_ctrl_t::type_controlchange: // MIDI control change controller
154 eg1controllervalue = pEngine->ControllerTable[pDimRgn->EG1Controller.controller_number];
155 break;
156 }
157 if (pDimRgn->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue;
158
159 // calculate influence of EG1 controller on EG1's parameters (TODO: needs to be fine tuned)
160 double eg1attack = (pDimRgn->EG1ControllerAttackInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerAttackInfluence) * eg1controllervalue : 0.0;
161 double eg1decay = (pDimRgn->EG1ControllerDecayInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence) * eg1controllervalue : 0.0;
162 double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 0.0;
163
164 pEG1->Trigger(pDimRgn->EG1PreAttack,
165 pDimRgn->EG1Attack + eg1attack,
166 pDimRgn->EG1Hold,
167 pSample->LoopStart,
168 pDimRgn->EG1Decay1 + eg1decay,
169 pDimRgn->EG1Decay2 + eg1decay,
170 pDimRgn->EG1InfiniteSustain,
171 pDimRgn->EG1Sustain,
172 pDimRgn->EG1Release + eg1release,
173 Delay);
174 }
175
176
177 #if ENABLE_FILTER
178 // setup EG 2 (VCF Cutoff EG)
179 {
180 // get current value of EG2 controller
181 double eg2controllervalue;
182 switch (pDimRgn->EG2Controller.type) {
183 case gig::eg2_ctrl_t::type_none: // no controller defined
184 eg2controllervalue = 0;
185 break;
186 case gig::eg2_ctrl_t::type_channelaftertouch:
187 eg2controllervalue = 0; // TODO: aftertouch not yet supported
188 break;
189 case gig::eg2_ctrl_t::type_velocity:
190 eg2controllervalue = pNoteOnEvent->Velocity;
191 break;
192 case gig::eg2_ctrl_t::type_controlchange: // MIDI control change controller
193 eg2controllervalue = pEngine->ControllerTable[pDimRgn->EG2Controller.controller_number];
194 break;
195 }
196 if (pDimRgn->EG2ControllerInvert) eg2controllervalue = 127 - eg2controllervalue;
197
198 // calculate influence of EG2 controller on EG2's parameters (TODO: needs to be fine tuned)
199 double eg2attack = (pDimRgn->EG2ControllerAttackInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerAttackInfluence) * eg2controllervalue : 0.0;
200 double eg2decay = (pDimRgn->EG2ControllerDecayInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerDecayInfluence) * eg2controllervalue : 0.0;
201 double eg2release = (pDimRgn->EG2ControllerReleaseInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerReleaseInfluence) * eg2controllervalue : 0.0;
202
203 pEG2->Trigger(pDimRgn->EG2PreAttack,
204 pDimRgn->EG2Attack + eg2attack,
205 false,
206 pSample->LoopStart,
207 pDimRgn->EG2Decay1 + eg2decay,
208 pDimRgn->EG2Decay2 + eg2decay,
209 pDimRgn->EG2InfiniteSustain,
210 pDimRgn->EG2Sustain,
211 pDimRgn->EG2Release + eg2release,
212 Delay);
213 }
214 #endif // ENABLE_FILTER
215
216
217 // setup EG 3 (VCO EG)
218 {
219 double eg3depth = RTMath::CentsToFreqRatio(pDimRgn->EG3Depth);
220 pEG3->Trigger(eg3depth, pDimRgn->EG3Attack, Delay);
221 }
222
223
224 // setup LFO 1 (VCA LFO)
225 {
226 uint16_t lfo1_internal_depth;
227 switch (pDimRgn->LFO1Controller) {
228 case gig::lfo1_ctrl_internal:
229 lfo1_internal_depth = pDimRgn->LFO1InternalDepth;
230 pLFO1->ExtController = 0; // no external controller
231 break;
232 case gig::lfo1_ctrl_modwheel:
233 lfo1_internal_depth = 0;
234 pLFO1->ExtController = 1; // MIDI controller 1
235 break;
236 case gig::lfo1_ctrl_breath:
237 lfo1_internal_depth = 0;
238 pLFO1->ExtController = 2; // MIDI controller 2
239 break;
240 case gig::lfo1_ctrl_internal_modwheel:
241 lfo1_internal_depth = pDimRgn->LFO1InternalDepth;
242 pLFO1->ExtController = 1; // MIDI controller 1
243 break;
244 case gig::lfo1_ctrl_internal_breath:
245 lfo1_internal_depth = pDimRgn->LFO1InternalDepth;
246 pLFO1->ExtController = 2; // MIDI controller 2
247 break;
248 default:
249 lfo1_internal_depth = 0;
250 pLFO1->ExtController = 0; // no external controller
251 }
252 pLFO1->Trigger(pDimRgn->LFO1Frequency,
253 lfo1_internal_depth,
254 pDimRgn->LFO1ControlDepth,
255 pEngine->ControllerTable[pLFO1->ExtController],
256 pDimRgn->LFO1FlipPhase,
257 Delay);
258 }
259
260 #if ENABLE_FILTER
261 // setup LFO 2 (VCF Cutoff LFO)
262 {
263 uint16_t lfo2_internal_depth;
264 switch (pDimRgn->LFO2Controller) {
265 case gig::lfo2_ctrl_internal:
266 lfo2_internal_depth = pDimRgn->LFO2InternalDepth;
267 pLFO2->ExtController = 0; // no external controller
268 break;
269 case gig::lfo2_ctrl_modwheel:
270 lfo2_internal_depth = 0;
271 pLFO2->ExtController = 1; // MIDI controller 1
272 break;
273 case gig::lfo2_ctrl_foot:
274 lfo2_internal_depth = 0;
275 pLFO2->ExtController = 4; // MIDI controller 4
276 break;
277 case gig::lfo2_ctrl_internal_modwheel:
278 lfo2_internal_depth = pDimRgn->LFO2InternalDepth;
279 pLFO2->ExtController = 1; // MIDI controller 1
280 break;
281 case gig::lfo2_ctrl_internal_foot:
282 lfo2_internal_depth = pDimRgn->LFO2InternalDepth;
283 pLFO2->ExtController = 4; // MIDI controller 4
284 break;
285 default:
286 lfo2_internal_depth = 0;
287 pLFO2->ExtController = 0; // no external controller
288 }
289 pLFO2->Trigger(pDimRgn->LFO2Frequency,
290 lfo2_internal_depth,
291 pDimRgn->LFO2ControlDepth,
292 pEngine->ControllerTable[pLFO2->ExtController],
293 pDimRgn->LFO2FlipPhase,
294 Delay);
295 }
296 #endif // ENABLE_FILTER
297
298 // setup LFO 3 (VCO LFO)
299 {
300 uint16_t lfo3_internal_depth;
301 switch (pDimRgn->LFO3Controller) {
302 case gig::lfo3_ctrl_internal:
303 lfo3_internal_depth = pDimRgn->LFO3InternalDepth;
304 pLFO3->ExtController = 0; // no external controller
305 break;
306 case gig::lfo3_ctrl_modwheel:
307 lfo3_internal_depth = 0;
308 pLFO3->ExtController = 1; // MIDI controller 1
309 break;
310 case gig::lfo3_ctrl_aftertouch:
311 lfo3_internal_depth = 0;
312 pLFO3->ExtController = 0; // TODO: aftertouch not implemented yet
313 break;
314 case gig::lfo3_ctrl_internal_modwheel:
315 lfo3_internal_depth = pDimRgn->LFO3InternalDepth;
316 pLFO3->ExtController = 1; // MIDI controller 1
317 break;
318 case gig::lfo3_ctrl_internal_aftertouch:
319 lfo3_internal_depth = pDimRgn->LFO3InternalDepth;
320 pLFO1->ExtController = 0; // TODO: aftertouch not implemented yet
321 break;
322 default:
323 lfo3_internal_depth = 0;
324 pLFO3->ExtController = 0; // no external controller
325 }
326 pLFO3->Trigger(pDimRgn->LFO3Frequency,
327 lfo3_internal_depth,
328 pDimRgn->LFO3ControlDepth,
329 pEngine->ControllerTable[pLFO3->ExtController],
330 false,
331 Delay);
332 }
333
334 #if ENABLE_FILTER
335 #if FORCE_FILTER_USAGE
336 FilterLeft.Enabled = FilterRight.Enabled = true;
337 #else // use filter only if instrument file told so
338 FilterLeft.Enabled = FilterRight.Enabled = pDimRgn->VCFEnabled;
339 #endif // FORCE_FILTER_USAGE
340 if (pDimRgn->VCFEnabled) {
341 #ifdef OVERRIDE_FILTER_CUTOFF_CTRL
342 VCFCutoffCtrl.controller = OVERRIDE_FILTER_CUTOFF_CTRL;
343 #else // use the one defined in the instrument file
344 switch (pDimRgn->VCFCutoffController) {
345 case gig::vcf_cutoff_ctrl_modwheel:
346 VCFCutoffCtrl.controller = 1;
347 break;
348 case gig::vcf_cutoff_ctrl_effect1:
349 VCFCutoffCtrl.controller = 12;
350 break;
351 case gig::vcf_cutoff_ctrl_effect2:
352 VCFCutoffCtrl.controller = 13;
353 break;
354 case gig::vcf_cutoff_ctrl_breath:
355 VCFCutoffCtrl.controller = 2;
356 break;
357 case gig::vcf_cutoff_ctrl_foot:
358 VCFCutoffCtrl.controller = 4;
359 break;
360 case gig::vcf_cutoff_ctrl_sustainpedal:
361 VCFCutoffCtrl.controller = 64;
362 break;
363 case gig::vcf_cutoff_ctrl_softpedal:
364 VCFCutoffCtrl.controller = 67;
365 break;
366 case gig::vcf_cutoff_ctrl_genpurpose7:
367 VCFCutoffCtrl.controller = 82;
368 break;
369 case gig::vcf_cutoff_ctrl_genpurpose8:
370 VCFCutoffCtrl.controller = 83;
371 break;
372 case gig::vcf_cutoff_ctrl_aftertouch: //TODO: not implemented yet
373 case gig::vcf_cutoff_ctrl_none:
374 default:
375 VCFCutoffCtrl.controller = 0;
376 break;
377 }
378 #endif // OVERRIDE_FILTER_CUTOFF_CTRL
379
380 #ifdef OVERRIDE_FILTER_RES_CTRL
381 VCFResonanceCtrl.controller = OVERRIDE_FILTER_RES_CTRL;
382 #else // use the one defined in the instrument file
383 switch (pDimRgn->VCFResonanceController) {
384 case gig::vcf_res_ctrl_genpurpose3:
385 VCFResonanceCtrl.controller = 18;
386 break;
387 case gig::vcf_res_ctrl_genpurpose4:
388 VCFResonanceCtrl.controller = 19;
389 break;
390 case gig::vcf_res_ctrl_genpurpose5:
391 VCFResonanceCtrl.controller = 80;
392 break;
393 case gig::vcf_res_ctrl_genpurpose6:
394 VCFResonanceCtrl.controller = 81;
395 break;
396 case gig::vcf_res_ctrl_none:
397 default:
398 VCFResonanceCtrl.controller = 0;
399 }
400 #endif // OVERRIDE_FILTER_RES_CTRL
401
402 #ifndef OVERRIDE_FILTER_TYPE
403 FilterLeft.SetType(pDimRgn->VCFType);
404 FilterRight.SetType(pDimRgn->VCFType);
405 #else // override filter type
406 FilterLeft.SetType(OVERRIDE_FILTER_TYPE);
407 FilterRight.SetType(OVERRIDE_FILTER_TYPE);
408 #endif // OVERRIDE_FILTER_TYPE
409
410 VCFCutoffCtrl.value = pEngine->ControllerTable[VCFCutoffCtrl.controller];
411 VCFResonanceCtrl.value = pEngine->ControllerTable[VCFResonanceCtrl.controller];
412
413 // calculate cutoff frequency
414 float cutoff = (!VCFCutoffCtrl.controller)
415 ? exp((float) (127 - pNoteOnEvent->Velocity) * (float) pDimRgn->VCFVelocityScale * 6.2E-5f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX
416 : exp((float) VCFCutoffCtrl.value * 0.00787402f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX;
417
418 // calculate resonance
419 float resonance = (float) VCFResonanceCtrl.value * 0.00787f; // 0.0..1.0
420 if (pDimRgn->VCFKeyboardTracking) {
421 resonance += (float) (pNoteOnEvent->Key - pDimRgn->VCFKeyboardTrackingBreakpoint) * 0.00787f;
422 }
423 Constrain(resonance, 0.0, 1.0); // correct resonance if outside allowed value range (0.0..1.0)
424
425 VCFCutoffCtrl.fvalue = cutoff - FILTER_CUTOFF_MIN;
426 VCFResonanceCtrl.fvalue = resonance;
427
428 FilterLeft.SetParameters(cutoff, resonance, ModulationSystem::SampleRate());
429 FilterRight.SetParameters(cutoff, resonance, ModulationSystem::SampleRate());
430
431 FilterUpdateCounter = -1;
432 }
433 else {
434 VCFCutoffCtrl.controller = 0;
435 VCFResonanceCtrl.controller = 0;
436 }
437 #endif // ENABLE_FILTER
438
439 // ************************************************
440 // TODO: ARTICULATION DATA HANDLING IS MISSING HERE
441 // ************************************************
442
443 return 0; // success
444 }
445
446 /**
447 * Renders the audio data for this voice for the current audio fragment.
448 * The sample input data can either come from RAM (cached sample or sample
449 * part) or directly from disk. The output signal will be rendered by
450 * resampling / interpolation. If this voice is a disk streaming voice and
451 * the voice completely played back the cached RAM part of the sample, it
452 * will automatically switch to disk playback for the next RenderAudio()
453 * call.
454 *
455 * @param Samples - number of samples to be rendered in this audio fragment cycle
456 */
457 void Voice::Render(uint Samples) {
458
459 // Reset the synthesis parameter matrix
460 ModulationSystem::ResetDestinationParameter(ModulationSystem::destination_vca, this->Volume);
461 ModulationSystem::ResetDestinationParameter(ModulationSystem::destination_vco, this->PitchBase);
462 #if ENABLE_FILTER
463 ModulationSystem::ResetDestinationParameter(ModulationSystem::destination_vcfc, VCFCutoffCtrl.fvalue);
464 ModulationSystem::ResetDestinationParameter(ModulationSystem::destination_vcfr, VCFResonanceCtrl.fvalue);
465 #endif // ENABLE_FILTER
466
467
468 // Apply events to the synthesis parameter matrix
469 ProcessEvents(Samples);
470
471
472 // Let all modulators write their parameter changes to the synthesis parameter matrix for the current audio fragment
473 pEG1->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);
474 #if ENABLE_FILTER
475 pEG2->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);
476 #endif // ENABLE_FILTER
477 pEG3->Process(Samples);
478 pLFO1->Process(Samples);
479 #if ENABLE_FILTER
480 pLFO2->Process(Samples);
481 #endif // ENABLE_FILTER
482 pLFO3->Process(Samples);
483
484
485 switch (this->PlaybackState) {
486
487 case playback_state_ram: {
488 if (RAMLoop) InterpolateAndLoop(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
489 else Interpolate(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
490 if (DiskVoice) {
491 // check if we reached the allowed limit of the sample RAM cache
492 if (Pos > MaxRAMPos) {
493 dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos));
494 this->PlaybackState = playback_state_disk;
495 }
496 }
497 else if (Pos >= pSample->GetCache().Size / pSample->FrameSize) {
498 this->PlaybackState = playback_state_end;
499 }
500 }
501 break;
502
503 case playback_state_disk: {
504 if (!DiskStreamRef.pStream) {
505 // check if the disk thread created our ordered disk stream in the meantime
506 DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);
507 if (!DiskStreamRef.pStream) {
508 std::cout << stderr << "Disk stream not available in time!" << std::endl << std::flush;
509 Kill();
510 return;
511 }
512 DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (RTMath::DoubleToInt(Pos) - MaxRAMPos));
513 Pos -= RTMath::DoubleToInt(Pos);
514 }
515
516 // add silence sample at the end if we reached the end of the stream (for the interpolator)
517 if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels) {
518 DiskStreamRef.pStream->WriteSilence((MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels);
519 this->PlaybackState = playback_state_end;
520 }
521
522 sample_t* ptr = DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from
523 Interpolate(Samples, ptr, Delay);
524 DiskStreamRef.pStream->IncrementReadPos(RTMath::DoubleToInt(Pos) * pSample->Channels);
525 Pos -= RTMath::DoubleToInt(Pos);
526 }
527 break;
528
529 case playback_state_end:
530 Kill(); // free voice
531 break;
532 }
533
534
535 #if ENABLE_FILTER
536 // Reset synthesis event lists (except VCO, as VCO events apply channel wide currently)
537 pEngine->pSynthesisEvents[ModulationSystem::destination_vcfc]->clear();
538 pEngine->pSynthesisEvents[ModulationSystem::destination_vcfr]->clear();
539 #endif // ENABLE_FILTER
540
541 // Reset delay
542 Delay = 0;
543
544 pTriggerEvent = NULL;
545
546 // If release stage finished, let the voice be killed
547 if (pEG1->GetStage() == EG_VCA::stage_end) this->PlaybackState = playback_state_end;
548 }
549
550 /**
551 * Resets voice variables. Should only be called if rendering process is
552 * suspended / not running.
553 */
554 void Voice::Reset() {
555 pLFO1->Reset();
556 pLFO2->Reset();
557 pLFO3->Reset();
558 DiskStreamRef.pStream = NULL;
559 DiskStreamRef.hStream = 0;
560 DiskStreamRef.State = Stream::state_unused;
561 DiskStreamRef.OrderID = 0;
562 Active = false;
563 }
564
565 /**
566 * Process the control change event lists of the engine for the current
567 * audio fragment. Event values will be applied to the synthesis parameter
568 * matrix.
569 *
570 * @param Samples - number of samples to be rendered in this audio fragment cycle
571 */
572 void Voice::ProcessEvents(uint Samples) {
573
574 // dispatch control change events
575 ModulationSystem::Event* pCCEvent = pEngine->pCCEvents->first();
576 if (Delay) { // skip events that happened before this voice was triggered
577 while (pCCEvent && pCCEvent->FragmentPos() <= Delay) pCCEvent = pEngine->pCCEvents->next();
578 }
579 while (pCCEvent) {
580 if (pCCEvent->Controller) { // if valid MIDI controller
581 #if ENABLE_FILTER
582 if (pCCEvent->Controller == VCFCutoffCtrl.controller) {
583 pEngine->pSynthesisEvents[ModulationSystem::destination_vcfc]->alloc_assign(*pCCEvent);
584 }
585 if (pCCEvent->Controller == VCFResonanceCtrl.controller) {
586 pEngine->pSynthesisEvents[ModulationSystem::destination_vcfr]->alloc_assign(*pCCEvent);
587 }
588 #endif // ENABLE_FILTER
589 if (pCCEvent->Controller == pLFO1->ExtController) {
590 pLFO1->SendEvent(pCCEvent);
591 }
592 #if ENABLE_FILTER
593 if (pCCEvent->Controller == pLFO2->ExtController) {
594 pLFO2->SendEvent(pCCEvent);
595 }
596 #endif // ENABLE_FILTER
597 if (pCCEvent->Controller == pLFO3->ExtController) {
598 pLFO3->SendEvent(pCCEvent);
599 }
600 }
601
602 pCCEvent = pEngine->pCCEvents->next();
603 }
604
605
606 // process pitch events
607 {
608 RTEList<ModulationSystem::Event>* pVCOEventList = pEngine->pSynthesisEvents[ModulationSystem::destination_vco];
609 ModulationSystem::Event* pVCOEvent = pVCOEventList->first();
610 if (Delay) { // skip events that happened before this voice was triggered
611 while (pVCOEvent && pVCOEvent->FragmentPos() <= Delay) pVCOEvent = pVCOEventList->next();
612 }
613 // apply old pitchbend value until first pitch event occurs
614 if (this->PitchBend != 1.0) {
615 uint end = (pVCOEvent) ? pVCOEvent->FragmentPos() : Samples;
616 for (uint i = Delay; i < end; i++) {
617 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i] *= this->PitchBend;
618 }
619 }
620 float pitch;
621 while (pVCOEvent) {
622 ModulationSystem::Event* pNextVCOEvent = pVCOEventList->next();
623
624 // calculate the influence length of this event (in sample points)
625 uint end = (pNextVCOEvent) ? pNextVCOEvent->FragmentPos() : Samples;
626
627 pitch = RTMath::CentsToFreqRatio(((double) pVCOEvent->Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents
628
629 // apply pitch value to the pitch parameter sequence
630 for (uint i = pVCOEvent->FragmentPos(); i < end; i++) {
631 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i] *= pitch;
632 }
633
634 pVCOEvent = pNextVCOEvent;
635 }
636 if (pVCOEventList->last()) this->PitchBend = pitch;
637 }
638
639
640 #if ENABLE_FILTER
641 // process filter cutoff events
642 {
643 RTEList<ModulationSystem::Event>* pCutoffEventList = pEngine->pSynthesisEvents[ModulationSystem::destination_vcfc];
644 ModulationSystem::Event* pCutoffEvent = pCutoffEventList->first();
645 if (Delay) { // skip events that happened before this voice was triggered
646 while (pCutoffEvent && pCutoffEvent->FragmentPos() <= Delay) pCutoffEvent = pCutoffEventList->next();
647 }
648 float cutoff;
649 while (pCutoffEvent) {
650 ModulationSystem::Event* pNextCutoffEvent = pCutoffEventList->next();
651
652 // calculate the influence length of this event (in sample points)
653 uint end = (pNextCutoffEvent) ? pNextCutoffEvent->FragmentPos() : Samples;
654
655 cutoff = exp((float) pCutoffEvent->Value * 0.00787402f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX - FILTER_CUTOFF_MIN;
656
657 // apply cutoff frequency to the cutoff parameter sequence
658 for (uint i = pCutoffEvent->FragmentPos(); i < end; i++) {
659 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i] = cutoff;
660 }
661
662 pCutoffEvent = pNextCutoffEvent;
663 }
664 if (pCutoffEventList->last()) VCFCutoffCtrl.fvalue = cutoff; // needed for initialization of parameter matrix next time
665 }
666
667 // process filter resonance events
668 {
669 RTEList<ModulationSystem::Event>* pResonanceEventList = pEngine->pSynthesisEvents[ModulationSystem::destination_vcfr];
670 ModulationSystem::Event* pResonanceEvent = pResonanceEventList->first();
671 if (Delay) { // skip events that happened before this voice was triggered
672 while (pResonanceEvent && pResonanceEvent->FragmentPos() <= Delay) pResonanceEvent = pResonanceEventList->next();
673 }
674 while (pResonanceEvent) {
675 ModulationSystem::Event* pNextResonanceEvent = pResonanceEventList->next();
676
677 // calculate the influence length of this event (in sample points)
678 uint end = (pNextResonanceEvent) ? pNextResonanceEvent->FragmentPos() : Samples;
679
680 // convert absolute controller value to differential
681 int ctrldelta = pResonanceEvent->Value - VCFResonanceCtrl.value;
682 VCFResonanceCtrl.value = pResonanceEvent->Value;
683
684 float resonancedelta = (float) ctrldelta * 0.00787f; // 0.0..1.0
685
686 // apply cutoff frequency to the cutoff parameter sequence
687 for (uint i = pResonanceEvent->FragmentPos(); i < end; i++) {
688 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i] += resonancedelta;
689 }
690
691 pResonanceEvent = pNextResonanceEvent;
692 }
693 if (pResonanceEventList->last()) VCFResonanceCtrl.fvalue = pResonanceEventList->last()->Value * 0.00787f; // needed for initialization of parameter matrix next time
694 }
695 #endif // ENABLE_FILTER
696 }
697
698 /**
699 * Interpolates the input audio data (no loop).
700 *
701 * @param Samples - number of sample points to be rendered in this audio
702 * fragment cycle
703 * @param pSrc - pointer to input sample data
704 * @param Skip - number of sample points to skip in output buffer
705 */
706 void Voice::Interpolate(uint Samples, sample_t* pSrc, uint Skip) {
707 int i = Skip;
708
709 // FIXME: assuming either mono or stereo
710 if (this->pSample->Channels == 2) { // Stereo Sample
711 while (i < Samples) {
712 InterpolateOneStep_Stereo(pSrc, i,
713 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
714 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i],
715 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i],
716 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i]);
717 }
718 }
719 else { // Mono Sample
720 while (i < Samples) {
721 InterpolateOneStep_Mono(pSrc, i,
722 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
723 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i],
724 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i],
725 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i]);
726 }
727 }
728 }
729
730 /**
731 * Interpolates the input audio data, this method honors looping.
732 *
733 * @param Samples - number of sample points to be rendered in this audio
734 * fragment cycle
735 * @param pSrc - pointer to input sample data
736 * @param Skip - number of sample points to skip in output buffer
737 */
738 void Voice::InterpolateAndLoop(uint Samples, sample_t* pSrc, uint Skip) {
739 int i = Skip;
740
741 // FIXME: assuming either mono or stereo
742 if (pSample->Channels == 2) { // Stereo Sample
743 if (pSample->LoopPlayCount) {
744 // render loop (loop count limited)
745 while (i < Samples && LoopCyclesLeft) {
746 InterpolateOneStep_Stereo(pSrc, i,
747 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
748 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i],
749 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i],
750 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i]);
751 if (Pos > pSample->LoopEnd) {
752 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
753 LoopCyclesLeft--;
754 }
755 }
756 // render on without loop
757 while (i < Samples) {
758 InterpolateOneStep_Stereo(pSrc, i,
759 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
760 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i],
761 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i],
762 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i]);
763 }
764 }
765 else { // render loop (endless loop)
766 while (i < Samples) {
767 InterpolateOneStep_Stereo(pSrc, i,
768 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
769 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i],
770 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i],
771 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i]);
772 if (Pos > pSample->LoopEnd) {
773 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);
774 }
775 }
776 }
777 }
778 else { // Mono Sample
779 if (pSample->LoopPlayCount) {
780 // render loop (loop count limited)
781 while (i < Samples && LoopCyclesLeft) {
782 InterpolateOneStep_Mono(pSrc, i,
783 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
784 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i],
785 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i],
786 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i]);
787 if (Pos > pSample->LoopEnd) {
788 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
789 LoopCyclesLeft--;
790 }
791 }
792 // render on without loop
793 while (i < Samples) {
794 InterpolateOneStep_Mono(pSrc, i,
795 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
796 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i],
797 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i],
798 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i]);
799 }
800 }
801 else { // render loop (endless loop)
802 while (i < Samples) {
803 InterpolateOneStep_Mono(pSrc, i,
804 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
805 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i],
806 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][i],
807 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfr][i]);
808 if (Pos > pSample->LoopEnd) {
809 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
810 }
811 }
812 }
813 }
814 }
815
816 /**
817 * Immediately kill the voice.
818 */
819 void Voice::Kill() {
820 if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
821 pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
822 }
823 Reset();
824 }

  ViewVC Help
Powered by ViewVC