/[svn]/linuxsampler/trunk/src/engines/common/AbstractVoice.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/common/AbstractVoice.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3335 - (show annotations) (download)
Sun Jul 30 14:33:15 2017 UTC (6 years, 8 months ago) by schoenebeck
File size: 47466 byte(s)
* NKSP: Added built-in script function "change_pan_time()".
* NKSP: Added built-in script function "change_pan_curve()".
* Bumped version (2.0.0.svn75).

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005-2008 Christian Schoenebeck *
7 * Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev *
8 * Copyright (C) 2013-2017 Christian Schoenebeck and Andreas Persson *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the Free Software *
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
23 * MA 02111-1307 USA *
24 ***************************************************************************/
25
26 #include "AbstractVoice.h"
27
28 namespace LinuxSampler {
29
30 AbstractVoice::AbstractVoice(SignalUnitRack* pRack): pSignalUnitRack(pRack) {
31 pEngineChannel = NULL;
32 pLFO1 = new LFOUnsigned(1.0f); // amplitude LFO (0..1 range)
33 pLFO2 = new LFOUnsigned(1.0f); // filter LFO (0..1 range)
34 pLFO3 = new LFOSigned(1200.0f); // pitch LFO (-1200..+1200 range)
35 PlaybackState = playback_state_end;
36 SynthesisMode = 0; // set all mode bits to 0 first
37 // select synthesis implementation (asm core is not supported ATM)
38 #if 0 // CONFIG_ASM && ARCH_X86
39 SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, Features::supportsMMX() && Features::supportsSSE());
40 #else
41 SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false);
42 #endif
43 SYNTHESIS_MODE_SET_PROFILING(SynthesisMode, gig::Profiler::isEnabled());
44
45 finalSynthesisParameters.filterLeft.Reset();
46 finalSynthesisParameters.filterRight.Reset();
47
48 pEq = NULL;
49 bEqSupport = false;
50 }
51
52 AbstractVoice::~AbstractVoice() {
53 if (pLFO1) delete pLFO1;
54 if (pLFO2) delete pLFO2;
55 if (pLFO3) delete pLFO3;
56
57 if(pEq != NULL) delete pEq;
58 }
59
60 void AbstractVoice::CreateEq() {
61 if(!bEqSupport) return;
62 if(pEq != NULL) delete pEq;
63 pEq = new EqSupport;
64 pEq->InitEffect(GetEngine()->pAudioOutputDevice);
65 }
66
67 /**
68 * Resets voice variables. Should only be called if rendering process is
69 * suspended / not running.
70 */
71 void AbstractVoice::Reset() {
72 finalSynthesisParameters.filterLeft.Reset();
73 finalSynthesisParameters.filterRight.Reset();
74 DiskStreamRef.pStream = NULL;
75 DiskStreamRef.hStream = 0;
76 DiskStreamRef.State = Stream::state_unused;
77 DiskStreamRef.OrderID = 0;
78 PlaybackState = playback_state_end;
79 itTriggerEvent = Pool<Event>::Iterator();
80 itKillEvent = Pool<Event>::Iterator();
81 }
82
83 /**
84 * Initializes and triggers the voice, a disk stream will be launched if
85 * needed.
86 *
87 * @param pEngineChannel - engine channel on which this voice was ordered
88 * @param itNoteOnEvent - event that caused triggering of this voice
89 * @param PitchBend - MIDI detune factor (-8192 ... +8191)
90 * @param pRegion- points to the region which provides sample wave(s) and articulation data
91 * @param VoiceType - type of this voice
92 * @param iKeyGroup - a value > 0 defines a key group in which this voice is member of
93 * @returns 0 on success, a value < 0 if the voice wasn't triggered
94 * (either due to an error or e.g. because no region is
95 * defined for the given key)
96 */
97 int AbstractVoice::Trigger (
98 AbstractEngineChannel* pEngineChannel,
99 Pool<Event>::Iterator& itNoteOnEvent,
100 int PitchBend,
101 type_t VoiceType,
102 int iKeyGroup
103 ) {
104 this->pEngineChannel = pEngineChannel;
105 Orphan = false;
106
107 #if CONFIG_DEVMODE
108 if (itNoteOnEvent->FragmentPos() > GetEngine()->MaxSamplesPerCycle) { // just a sanity check for debugging
109 dmsg(1,("Voice::Trigger(): ERROR, TriggerDelay > Totalsamples\n"));
110 }
111 #endif // CONFIG_DEVMODE
112
113 Type = VoiceType;
114 pNote = pEngineChannel->pEngine->NoteByID( itNoteOnEvent->Param.Note.ID );
115 PlaybackState = playback_state_init; // mark voice as triggered, but no audio rendered yet
116 Delay = itNoteOnEvent->FragmentPos();
117 itTriggerEvent = itNoteOnEvent;
118 itKillEvent = Pool<Event>::Iterator();
119 MidiKeyBase* pKeyInfo = GetMidiKeyInfo(MIDIKey());
120
121 pGroupEvents = iKeyGroup ? pEngineChannel->ActiveKeyGroups[iKeyGroup] : 0;
122
123 SmplInfo = GetSampleInfo();
124 RgnInfo = GetRegionInfo();
125 InstrInfo = GetInstrumentInfo();
126
127 MIDIPan = CalculatePan(pEngineChannel->iLastPanRequest);
128
129 AboutToTrigger();
130
131 // calculate volume
132 const double velocityAttenuation = GetVelocityAttenuation(MIDIVelocity());
133 float volume = CalculateVolume(velocityAttenuation) * pKeyInfo->Volume;
134 if (volume <= 0) return -1;
135
136 // select channel mode (mono or stereo)
137 SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, SmplInfo.ChannelCount == 2);
138 // select bit depth (16 or 24)
139 SYNTHESIS_MODE_SET_BITDEPTH24(SynthesisMode, SmplInfo.BitDepth == 24);
140
141 // get starting crossfade volume level
142 float crossfadeVolume = CalculateCrossfadeVolume(MIDIVelocity());
143
144 VolumeLeft = volume * pKeyInfo->PanLeft;
145 VolumeRight = volume * pKeyInfo->PanRight;
146
147 // this rate is used for rather mellow volume fades
148 const float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;
149 // this rate is used for very fast volume fades
150 const float quickRampRate = RTMath::Min(subfragmentRate, GetEngine()->SampleRate * 0.001f /* approx. 13ms */);
151 CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);
152
153 VolumeSmoother.trigger(pEngineChannel->MidiVolume, subfragmentRate);
154 NoteVolume.setCurveOnly(pNote ? pNote->Override.VolumeCurve : DEFAULT_FADE_CURVE);
155 NoteVolume.setCurrentValue(pNote ? pNote->Override.Volume : 1.f);
156 NoteVolume.setDefaultDuration(pNote ? pNote->Override.VolumeTime : DEFAULT_NOTE_VOLUME_TIME_S);
157
158 // Check if the sample needs disk streaming or is too short for that
159 long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;
160 DiskVoice = cachedsamples < SmplInfo.TotalFrameCount;
161
162 SetSampleStartOffset();
163
164 if (DiskVoice) { // voice to be streamed from disk
165 if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {
166 MaxRAMPos = cachedsamples - (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH) / SmplInfo.ChannelCount; //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)
167 } else {
168 // The cache is too small to fit a max sample buffer.
169 // Setting MaxRAMPos to 0 will probably cause a click
170 // in the audio, but it's better than not handling
171 // this case at all, which would have caused the
172 // unsigned MaxRAMPos to be set to a negative number.
173 MaxRAMPos = 0;
174 }
175
176 // check if there's a loop defined which completely fits into the cached (RAM) part of the sample
177 RAMLoop = (SmplInfo.HasLoops && (SmplInfo.LoopStart + SmplInfo.LoopLength) <= MaxRAMPos);
178
179 if (OrderNewStream()) return -1;
180 dmsg(4,("Disk voice launched (cached samples: %ld, total Samples: %d, MaxRAMPos: %lu, RAMLooping: %s)\n", cachedsamples, SmplInfo.TotalFrameCount, MaxRAMPos, (RAMLoop) ? "yes" : "no"));
181 }
182 else { // RAM only voice
183 MaxRAMPos = cachedsamples;
184 RAMLoop = (SmplInfo.HasLoops);
185 dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));
186 }
187 if (RAMLoop) {
188 loop.uiTotalCycles = SmplInfo.LoopPlayCount;
189 loop.uiCyclesLeft = SmplInfo.LoopPlayCount;
190 loop.uiStart = SmplInfo.LoopStart;
191 loop.uiEnd = SmplInfo.LoopStart + SmplInfo.LoopLength;
192 loop.uiSize = SmplInfo.LoopLength;
193 }
194
195 Pitch = CalculatePitchInfo(PitchBend);
196 NotePitch.setCurveOnly(pNote ? pNote->Override.PitchCurve : DEFAULT_FADE_CURVE);
197 NotePitch.setCurrentValue(pNote ? pNote->Override.Pitch : 1.0f);
198 NotePitch.setDefaultDuration(pNote ? pNote->Override.PitchTime : DEFAULT_NOTE_PITCH_TIME_S);
199 NoteCutoff = (pNote) ? pNote->Override.Cutoff : 1.0f;
200 NoteResonance = (pNote) ? pNote->Override.Resonance : 1.0f;
201
202 // the length of the decay and release curves are dependent on the velocity
203 const double velrelease = 1 / GetVelocityRelease(MIDIVelocity());
204
205 if (pSignalUnitRack == NULL) { // setup EG 1 (VCA EG)
206 // get current value of EG1 controller
207 double eg1controllervalue = GetEG1ControllerValue(MIDIVelocity());
208
209 // calculate influence of EG1 controller on EG1's parameters
210 EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);
211
212 if (pNote) {
213 egInfo.Attack *= pNote->Override.Attack;
214 egInfo.Decay *= pNote->Override.Decay;
215 egInfo.Release *= pNote->Override.Release;
216 }
217
218 TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, MIDIVelocity());
219 } else {
220 pSignalUnitRack->Trigger();
221 }
222
223 const uint8_t pan = (pSignalUnitRack) ? pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan) : MIDIPan;
224 for (int c = 0; c < 2; ++c) {
225 float value = (pNote) ? AbstractEngine::PanCurveValueNorm(pNote->Override.Pan, c) : 1.f;
226 NotePan[c].setCurveOnly(pNote ? pNote->Override.PanCurve : DEFAULT_FADE_CURVE);
227 NotePan[c].setCurrentValue(value);
228 NotePan[c].setDefaultDuration(pNote ? pNote->Override.PanTime : DEFAULT_NOTE_PAN_TIME_S);
229 }
230
231 PanLeftSmoother.trigger(
232 AbstractEngine::PanCurve[128 - pan],
233 quickRampRate //NOTE: maybe we should have 2 separate pan smoothers, one for MIDI CC10 (with slow rate) and one for instrument script change_pan() calls (with fast rate)
234 );
235 PanRightSmoother.trigger(
236 AbstractEngine::PanCurve[pan],
237 quickRampRate //NOTE: maybe we should have 2 separate pan smoothers, one for MIDI CC10 (with slow rate) and one for instrument script change_pan() calls (with fast rate)
238 );
239
240 #ifdef CONFIG_INTERPOLATE_VOLUME
241 // setup initial volume in synthesis parameters
242 #ifdef CONFIG_PROCESS_MUTED_CHANNELS
243 if (pEngineChannel->GetMute()) {
244 finalSynthesisParameters.fFinalVolumeLeft = 0;
245 finalSynthesisParameters.fFinalVolumeRight = 0;
246 }
247 else
248 #else
249 {
250 float finalVolume;
251 if (pSignalUnitRack == NULL) {
252 finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();
253 } else {
254 finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pSignalUnitRack->GetEndpointUnit()->GetVolume();
255 }
256 finalVolume *= NoteVolume.currentValue();
257
258 finalSynthesisParameters.fFinalVolumeLeft = finalVolume * VolumeLeft * PanLeftSmoother.render() * NotePan[0].currentValue();
259 finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * PanRightSmoother.render() * NotePan[1].currentValue();
260 }
261 #endif
262 #endif
263
264 if (pSignalUnitRack == NULL) {
265 // setup EG 2 (VCF Cutoff EG)
266 {
267 // get current value of EG2 controller
268 double eg2controllervalue = GetEG2ControllerValue(MIDIVelocity());
269
270 // calculate influence of EG2 controller on EG2's parameters
271 EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);
272
273 TriggerEG2(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, MIDIVelocity());
274 }
275
276
277 // setup EG 3 (VCO EG)
278 {
279 // if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch
280 bool bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;
281 float eg3depth = (bPortamento)
282 ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey()) * 100)
283 : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);
284 float eg3time = (bPortamento)
285 ? pEngineChannel->PortamentoTime
286 : RgnInfo.EG3Attack;
287 EG3.trigger(eg3depth, eg3time, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
288 dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time));
289 }
290
291
292 // setup LFO 1 (VCA LFO)
293 InitLFO1();
294 // setup LFO 2 (VCF Cutoff LFO)
295 InitLFO2();
296 // setup LFO 3 (VCO LFO)
297 InitLFO3();
298 }
299
300
301 #if CONFIG_FORCE_FILTER
302 const bool bUseFilter = true;
303 #else // use filter only if instrument file told so
304 const bool bUseFilter = RgnInfo.VCFEnabled;
305 #endif // CONFIG_FORCE_FILTER
306 SYNTHESIS_MODE_SET_FILTER(SynthesisMode, bUseFilter);
307 if (bUseFilter) {
308 #ifdef CONFIG_OVERRIDE_CUTOFF_CTRL
309 VCFCutoffCtrl.controller = CONFIG_OVERRIDE_CUTOFF_CTRL;
310 #else // use the one defined in the instrument file
311 VCFCutoffCtrl.controller = GetVCFCutoffCtrl();
312 #endif // CONFIG_OVERRIDE_CUTOFF_CTRL
313
314 #ifdef CONFIG_OVERRIDE_RESONANCE_CTRL
315 VCFResonanceCtrl.controller = CONFIG_OVERRIDE_RESONANCE_CTRL;
316 #else // use the one defined in the instrument file
317 VCFResonanceCtrl.controller = GetVCFResonanceCtrl();
318 #endif // CONFIG_OVERRIDE_RESONANCE_CTRL
319
320 #ifndef CONFIG_OVERRIDE_FILTER_TYPE
321 finalSynthesisParameters.filterLeft.SetType(RgnInfo.VCFType);
322 finalSynthesisParameters.filterRight.SetType(RgnInfo.VCFType);
323 #else // override filter type
324 finalSynthesisParameters.filterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE);
325 finalSynthesisParameters.filterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE);
326 #endif // CONFIG_OVERRIDE_FILTER_TYPE
327
328 VCFCutoffCtrl.value = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller];
329 VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller];
330
331 // calculate cutoff frequency
332 CutoffBase = CalculateCutoffBase(MIDIVelocity());
333
334 VCFCutoffCtrl.fvalue = CalculateFinalCutoff(CutoffBase);
335
336 // calculate resonance
337 float resonance = (float) (VCFResonanceCtrl.controller ? VCFResonanceCtrl.value : RgnInfo.VCFResonance);
338 VCFResonanceCtrl.fvalue = resonance;
339 } else {
340 VCFCutoffCtrl.controller = 0;
341 VCFResonanceCtrl.controller = 0;
342 }
343
344 const bool bEq =
345 pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && pEq->HasSupport();
346
347 if (bEq) {
348 pEq->GetInChannelLeft()->Clear();
349 pEq->GetInChannelRight()->Clear();
350 pEq->RenderAudio(GetEngine()->pAudioOutputDevice->MaxSamplesPerCycle());
351 }
352
353 return 0; // success
354 }
355
356 void AbstractVoice::SetSampleStartOffset() {
357 double pos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample
358
359 // if another sample playback start position was requested by instrument
360 // script (built-in script function play_note())
361 if (pNote && pNote->Override.SampleOffset >= 0) {
362 double overridePos =
363 double(SmplInfo.SampleRate) * double(pNote->Override.SampleOffset) / 1000000.0;
364 if (overridePos < SmplInfo.TotalFrameCount)
365 pos = overridePos;
366 }
367
368 finalSynthesisParameters.dPos = pos;
369 Pos = pos;
370 }
371
372 /**
373 * Synthesizes the current audio fragment for this voice.
374 *
375 * @param Samples - number of sample points to be rendered in this audio
376 * fragment cycle
377 * @param pSrc - pointer to input sample data
378 * @param Skip - number of sample points to skip in output buffer
379 */
380 void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
381 bool delay = false; // Whether the voice playback should be delayed for this call
382
383 if (pSignalUnitRack != NULL) {
384 uint delaySteps = pSignalUnitRack->GetEndpointUnit()->DelayTrigger();
385 if (delaySteps > 0) { // delay on the endpoint unit means delay of the voice playback
386 if (delaySteps >= Samples) {
387 pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(Samples);
388 delay = true;
389 } else {
390 pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(delaySteps);
391 Samples -= delaySteps;
392 Skip += delaySteps;
393 }
394 }
395 }
396
397 AbstractEngineChannel* pChannel = pEngineChannel;
398 MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey());
399
400 const bool bVoiceRequiresDedicatedRouting =
401 pEngineChannel->GetFxSendCount() > 0 &&
402 (pMidiKeyInfo->ReverbSend || pMidiKeyInfo->ChorusSend);
403
404 const bool bEq =
405 pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && pEq->HasSupport();
406
407 if (bEq) {
408 pEq->GetInChannelLeft()->Clear();
409 pEq->GetInChannelRight()->Clear();
410 finalSynthesisParameters.pOutLeft = &pEq->GetInChannelLeft()->Buffer()[Skip];
411 finalSynthesisParameters.pOutRight = &pEq->GetInChannelRight()->Buffer()[Skip];
412 pSignalUnitRack->UpdateEqSettings(pEq);
413 } else if (bVoiceRequiresDedicatedRouting) {
414 finalSynthesisParameters.pOutLeft = &GetEngine()->pDedicatedVoiceChannelLeft->Buffer()[Skip];
415 finalSynthesisParameters.pOutRight = &GetEngine()->pDedicatedVoiceChannelRight->Buffer()[Skip];
416 } else {
417 finalSynthesisParameters.pOutLeft = &pChannel->pChannelLeft->Buffer()[Skip];
418 finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];
419 }
420 finalSynthesisParameters.pSrc = pSrc;
421
422 RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();
423 RTList<Event>::Iterator itNoteEvent;
424 GetFirstEventOnKey(HostKey(), itNoteEvent);
425
426 RTList<Event>::Iterator itGroupEvent;
427 if (pGroupEvents && !Orphan) itGroupEvent = pGroupEvents->first();
428
429 if (itTriggerEvent) { // skip events that happened before this voice was triggered
430 while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;
431 while (itGroupEvent && itGroupEvent->FragmentPos() <= Skip) ++itGroupEvent;
432
433 // we can't simply compare the timestamp here, because note events
434 // might happen on the same time stamp, so we have to deal on the
435 // actual sequence the note events arrived instead (see bug #112)
436 for (; itNoteEvent; ++itNoteEvent) {
437 if (itTriggerEvent == itNoteEvent) {
438 ++itNoteEvent;
439 break;
440 }
441 }
442 }
443
444 uint killPos = 0;
445 if (itKillEvent) {
446 int maxFadeOutPos = Samples - GetEngine()->GetMinFadeOutSamples();
447 if (maxFadeOutPos < 0) {
448 // There's not enough space in buffer to do a fade out
449 // from max volume (this can only happen for audio
450 // drivers that use Samples < MaxSamplesPerCycle).
451 // End the EG1 here, at pos 0, with a shorter max fade
452 // out time.
453 if (pSignalUnitRack == NULL) {
454 pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
455 } else {
456 pSignalUnitRack->EnterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
457 }
458 itKillEvent = Pool<Event>::Iterator();
459 } else {
460 killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);
461 }
462 }
463
464 uint i = Skip;
465 while (i < Samples) {
466 int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples);
467
468 // initialize all final synthesis parameters
469 fFinalCutoff = VCFCutoffCtrl.fvalue;
470 fFinalResonance = VCFResonanceCtrl.fvalue;
471
472 // process MIDI control change, aftertouch and pitchbend events for this subfragment
473 processCCEvents(itCCEvent, iSubFragmentEnd);
474 uint8_t pan = MIDIPan;
475 if (pSignalUnitRack != NULL) pan = pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan);
476
477 PanLeftSmoother.update(AbstractEngine::PanCurve[128 - pan]);
478 PanRightSmoother.update(AbstractEngine::PanCurve[pan]);
479
480 finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend * NotePitch.render();
481
482 float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render() * NoteVolume.render();
483 #ifdef CONFIG_PROCESS_MUTED_CHANNELS
484 if (pChannel->GetMute()) fFinalVolume = 0;
485 #endif
486
487 // process transition events (note on, note off & sustain pedal)
488 processTransitionEvents(itNoteEvent, iSubFragmentEnd);
489 processGroupEvents(itGroupEvent, iSubFragmentEnd);
490
491 if (pSignalUnitRack == NULL) {
492 // if the voice was killed in this subfragment, or if the
493 // filter EG is finished, switch EG1 to fade out stage
494 if ((itKillEvent && killPos <= iSubFragmentEnd) ||
495 (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
496 pEG2->getSegmentType() == EG::segment_end)) {
497 pEG1->enterFadeOutStage();
498 itKillEvent = Pool<Event>::Iterator();
499 }
500
501 // process envelope generators
502 switch (pEG1->getSegmentType()) {
503 case EG::segment_lin:
504 fFinalVolume *= pEG1->processLin();
505 break;
506 case EG::segment_exp:
507 fFinalVolume *= pEG1->processExp();
508 break;
509 case EG::segment_end:
510 fFinalVolume *= pEG1->getLevel();
511 break; // noop
512 case EG::segment_pow:
513 fFinalVolume *= pEG1->processPow();
514 break;
515 }
516 switch (pEG2->getSegmentType()) {
517 case EG::segment_lin:
518 fFinalCutoff *= pEG2->processLin();
519 break;
520 case EG::segment_exp:
521 fFinalCutoff *= pEG2->processExp();
522 break;
523 case EG::segment_end:
524 fFinalCutoff *= pEG2->getLevel();
525 break; // noop
526 case EG::segment_pow:
527 fFinalCutoff *= pEG2->processPow();
528 break;
529 }
530 if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();
531
532 // process low frequency oscillators
533 if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());
534 if (bLFO2Enabled) fFinalCutoff *= (1.0f - pLFO2->render());
535 if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
536 } else {
537 // if the voice was killed in this subfragment, enter fade out stage
538 if (itKillEvent && killPos <= iSubFragmentEnd) {
539 pSignalUnitRack->EnterFadeOutStage();
540 itKillEvent = Pool<Event>::Iterator();
541 }
542
543 // if the filter EG is finished, switch EG1 to fade out stage
544 /*if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
545 pEG2->getSegmentType() == EG::segment_end) {
546 pEG1->enterFadeOutStage();
547 itKillEvent = Pool<Event>::Iterator();
548 }*/
549 // TODO: ^^^
550
551 fFinalVolume *= pSignalUnitRack->GetEndpointUnit()->GetVolume();
552 fFinalCutoff = pSignalUnitRack->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff);
553 fFinalResonance = pSignalUnitRack->GetEndpointUnit()->CalculateResonance(fFinalResonance);
554
555 finalSynthesisParameters.fFinalPitch =
556 pSignalUnitRack->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);
557
558 }
559
560 fFinalCutoff *= NoteCutoff;
561 fFinalResonance *= NoteResonance;
562
563 // limit the pitch so we don't read outside the buffer
564 finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));
565
566 // if filter enabled then update filter coefficients
567 if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) {
568 finalSynthesisParameters.filterLeft.SetParameters(fFinalCutoff, fFinalResonance, GetEngine()->SampleRate);
569 finalSynthesisParameters.filterRight.SetParameters(fFinalCutoff, fFinalResonance, GetEngine()->SampleRate);
570 }
571
572 // do we need resampling?
573 const float __PLUS_ONE_CENT = 1.000577789506554859250142541782224725466f;
574 const float __MINUS_ONE_CENT = 0.9994225441413807496009516495583113737666f;
575 const bool bResamplingRequired = !(finalSynthesisParameters.fFinalPitch <= __PLUS_ONE_CENT &&
576 finalSynthesisParameters.fFinalPitch >= __MINUS_ONE_CENT);
577 SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, bResamplingRequired);
578
579 // prepare final synthesis parameters structure
580 finalSynthesisParameters.uiToGo = iSubFragmentEnd - i;
581 #ifdef CONFIG_INTERPOLATE_VOLUME
582 finalSynthesisParameters.fFinalVolumeDeltaLeft =
583 (fFinalVolume * VolumeLeft * PanLeftSmoother.render() * NotePan[0].render() -
584 finalSynthesisParameters.fFinalVolumeLeft) / finalSynthesisParameters.uiToGo;
585 finalSynthesisParameters.fFinalVolumeDeltaRight =
586 (fFinalVolume * VolumeRight * PanRightSmoother.render() * NotePan[1].render() -
587 finalSynthesisParameters.fFinalVolumeRight) / finalSynthesisParameters.uiToGo;
588 #else
589 finalSynthesisParameters.fFinalVolumeLeft =
590 fFinalVolume * VolumeLeft * PanLeftSmoother.render() * NotePan[0].render();
591 finalSynthesisParameters.fFinalVolumeRight =
592 fFinalVolume * VolumeRight * PanRightSmoother.render() * NotePan[1].render();
593 #endif
594 // render audio for one subfragment
595 if (!delay) RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
596
597 if (pSignalUnitRack == NULL) {
598 // stop the rendering if volume EG is finished
599 if (pEG1->getSegmentType() == EG::segment_end) break;
600 } else {
601 // stop the rendering if the endpoint unit is not active
602 if (!pSignalUnitRack->GetEndpointUnit()->Active()) break;
603 }
604
605 const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
606
607 if (pSignalUnitRack == NULL) {
608 // increment envelopes' positions
609 if (pEG1->active()) {
610
611 // if sample has a loop and loop start has been reached in this subfragment, send a special event to EG1 to let it finish the attack hold stage
612 if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
613 pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
614 }
615
616 pEG1->increment(1);
617 if (!pEG1->toStageEndLeft()) pEG1->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
618 }
619 if (pEG2->active()) {
620 pEG2->increment(1);
621 if (!pEG2->toStageEndLeft()) pEG2->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
622 }
623 EG3.increment(1);
624 if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
625 } else {
626 // if sample has a loop and loop start has been reached in this subfragment, send a special event to EG1 to let it finish the attack hold stage
627 /*if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
628 pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
629 }*/
630 // TODO: ^^^
631
632 if (!delay) pSignalUnitRack->Increment();
633 }
634
635 Pos = newPos;
636 i = iSubFragmentEnd;
637 }
638
639 if (delay) return;
640
641 if (bVoiceRequiresDedicatedRouting) {
642 if (bEq) {
643 pEq->RenderAudio(Samples);
644 pEq->GetOutChannelLeft()->CopyTo(GetEngine()->pDedicatedVoiceChannelLeft, Samples);
645 pEq->GetOutChannelRight()->CopyTo(GetEngine()->pDedicatedVoiceChannelRight, Samples);
646 }
647 optional<float> effectSendLevels[2] = {
648 pMidiKeyInfo->ReverbSend,
649 pMidiKeyInfo->ChorusSend
650 };
651 GetEngine()->RouteDedicatedVoiceChannels(pEngineChannel, effectSendLevels, Samples);
652 } else if (bEq) {
653 pEq->RenderAudio(Samples);
654 pEq->GetOutChannelLeft()->MixTo(pChannel->pChannelLeft, Samples);
655 pEq->GetOutChannelRight()->MixTo(pChannel->pChannelRight, Samples);
656 }
657 }
658
659 /**
660 * Process given list of MIDI control change, aftertouch and pitch bend
661 * events for the given time.
662 *
663 * @param itEvent - iterator pointing to the next event to be processed
664 * @param End - youngest time stamp where processing should be stopped
665 */
666 void AbstractVoice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) {
667 for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
668 if ((itEvent->Type == Event::type_control_change || itEvent->Type == Event::type_channel_pressure)
669 && itEvent->Param.CC.Controller) // if (valid) MIDI control change event
670 {
671 if (itEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {
672 ProcessCutoffEvent(itEvent);
673 }
674 if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
675 processResonanceEvent(itEvent);
676 }
677 if (itEvent->Param.CC.Controller == CTRL_TABLE_IDX_AFTERTOUCH ||
678 itEvent->Type == Event::type_channel_pressure)
679 {
680 ProcessChannelPressureEvent(itEvent);
681 }
682 if (pSignalUnitRack == NULL) {
683 if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
684 pLFO1->updateByMIDICtrlValue(itEvent->Param.CC.Value);
685 }
686 if (itEvent->Param.CC.Controller == pLFO2->ExtController) {
687 pLFO2->updateByMIDICtrlValue(itEvent->Param.CC.Value);
688 }
689 if (itEvent->Param.CC.Controller == pLFO3->ExtController) {
690 pLFO3->updateByMIDICtrlValue(itEvent->Param.CC.Value);
691 }
692 }
693 if (itEvent->Param.CC.Controller == 7) { // volume
694 VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);
695 } else if (itEvent->Param.CC.Controller == 10) { // panpot
696 MIDIPan = CalculatePan(itEvent->Param.CC.Value);
697 }
698 } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event
699 processPitchEvent(itEvent);
700 } else if (itEvent->Type == Event::type_note_pressure) {
701 ProcessPolyphonicKeyPressureEvent(itEvent);
702 }
703
704 ProcessCCEvent(itEvent);
705 if (pSignalUnitRack != NULL) {
706 pSignalUnitRack->ProcessCCEvent(itEvent);
707 }
708 }
709 }
710
711 void AbstractVoice::processPitchEvent(RTList<Event>::Iterator& itEvent) {
712 Pitch.PitchBend = RTMath::CentsToFreqRatio(itEvent->Param.Pitch.Pitch * Pitch.PitchBendRange);
713 }
714
715 void AbstractVoice::processResonanceEvent(RTList<Event>::Iterator& itEvent) {
716 // convert absolute controller value to differential
717 const int ctrldelta = itEvent->Param.CC.Value - VCFResonanceCtrl.value;
718 VCFResonanceCtrl.value = itEvent->Param.CC.Value;
719 const float resonancedelta = (float) ctrldelta;
720 fFinalResonance += resonancedelta;
721 // needed for initialization of parameter
722 VCFResonanceCtrl.fvalue = itEvent->Param.CC.Value;
723 }
724
725 /**
726 * Process given list of MIDI note on, note off, sustain pedal events and
727 * note synthesis parameter events for the given time.
728 *
729 * @param itEvent - iterator pointing to the next event to be processed
730 * @param End - youngest time stamp where processing should be stopped
731 */
732 void AbstractVoice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {
733 for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
734 // some voice types ignore note off
735 if (!(Type & (Voice::type_one_shot | Voice::type_release_trigger | Voice::type_controller_triggered))) {
736 if (itEvent->Type == Event::type_release_key) {
737 EnterReleaseStage();
738 } else if (itEvent->Type == Event::type_cancel_release_key) {
739 if (pSignalUnitRack == NULL) {
740 pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
741 pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
742 } else {
743 pSignalUnitRack->CancelRelease();
744 }
745 }
746 }
747 // process stop-note events (caused by built-in instrument script function note_off())
748 if (itEvent->Type == Event::type_release_note && pNote &&
749 pEngineChannel->pEngine->NoteByID( itEvent->Param.Note.ID ) == pNote)
750 {
751 EnterReleaseStage();
752 }
753 // process kill-note events (caused by built-in instrument script function fade_out())
754 if (itEvent->Type == Event::type_kill_note && pNote &&
755 pEngineChannel->pEngine->NoteByID( itEvent->Param.Note.ID ) == pNote)
756 {
757 Kill(itEvent);
758 }
759 // process synthesis parameter events (caused by built-in realt-time instrument script functions)
760 if (itEvent->Type == Event::type_note_synth_param && pNote &&
761 pEngineChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID ) == pNote)
762 {
763 switch (itEvent->Param.NoteSynthParam.Type) {
764 case Event::synth_param_volume:
765 NoteVolume.fadeTo(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
766 break;
767 case Event::synth_param_volume_time:
768 NoteVolume.setDefaultDuration(itEvent->Param.NoteSynthParam.AbsValue);
769 break;
770 case Event::synth_param_volume_curve:
771 NoteVolume.setCurve((fade_curve_t)itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
772 break;
773 case Event::synth_param_pitch:
774 NotePitch.fadeTo(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
775 break;
776 case Event::synth_param_pitch_time:
777 NotePitch.setDefaultDuration(itEvent->Param.NoteSynthParam.AbsValue);
778 break;
779 case Event::synth_param_pitch_curve:
780 NotePitch.setCurve((fade_curve_t)itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
781 break;
782 case Event::synth_param_pan:
783 NotePan[0].fadeTo(
784 AbstractEngine::PanCurveValueNorm(itEvent->Param.NoteSynthParam.AbsValue, 0 /*left*/),
785 GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE
786 );
787 NotePan[1].fadeTo(
788 AbstractEngine::PanCurveValueNorm(itEvent->Param.NoteSynthParam.AbsValue, 1 /*right*/),
789 GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE
790 );
791 break;
792 case Event::synth_param_pan_time:
793 NotePan[0].setDefaultDuration(itEvent->Param.NoteSynthParam.AbsValue);
794 NotePan[1].setDefaultDuration(itEvent->Param.NoteSynthParam.AbsValue);
795 break;
796 case Event::synth_param_pan_curve:
797 NotePan[0].setCurve((fade_curve_t)itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
798 NotePan[1].setCurve((fade_curve_t)itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
799 break;
800 case Event::synth_param_cutoff:
801 NoteCutoff = itEvent->Param.NoteSynthParam.AbsValue;
802 break;
803 case Event::synth_param_resonance:
804 NoteResonance = itEvent->Param.NoteSynthParam.AbsValue;
805 break;
806 case Event::synth_param_amp_lfo_depth:
807 pLFO1->setScriptDepthFactor(itEvent->Param.NoteSynthParam.AbsValue);
808 break;
809 case Event::synth_param_amp_lfo_freq:
810 pLFO1->setScriptFrequencyFactor(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
811 break;
812 case Event::synth_param_pitch_lfo_depth:
813 pLFO3->setScriptDepthFactor(itEvent->Param.NoteSynthParam.AbsValue);
814 break;
815 case Event::synth_param_pitch_lfo_freq:
816 pLFO3->setScriptFrequencyFactor(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
817 break;
818
819 case Event::synth_param_attack:
820 case Event::synth_param_decay:
821 case Event::synth_param_sustain:
822 case Event::synth_param_release:
823 break; // noop
824 }
825 }
826 }
827 }
828
829 /**
830 * Process given list of events aimed at all voices in a key group.
831 *
832 * @param itEvent - iterator pointing to the next event to be processed
833 * @param End - youngest time stamp where processing should be stopped
834 */
835 void AbstractVoice::processGroupEvents(RTList<Event>::Iterator& itEvent, uint End) {
836 for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
837 ProcessGroupEvent(itEvent);
838 }
839 }
840
841 /** @brief Update current portamento position.
842 *
843 * Will be called when portamento mode is enabled to get the final
844 * portamento position of this active voice from where the next voice(s)
845 * might continue to slide on.
846 *
847 * @param itNoteOffEvent - event which causes this voice to die soon
848 */
849 void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
850 if (pSignalUnitRack == NULL) {
851 const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
852 pEngineChannel->PortamentoPos = (float) MIDIKey() + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
853 } else {
854 // TODO:
855 }
856 }
857
858 /**
859 * Kill the voice in regular sense. Let the voice render audio until
860 * the kill event actually occured and then fade down the volume level
861 * very quickly and let the voice die finally. Unlike a normal release
862 * of a voice, a kill process cannot be cancalled and is therefore
863 * usually used for voice stealing and key group conflicts.
864 *
865 * @param itKillEvent - event which caused the voice to be killed
866 */
867 void AbstractVoice::Kill(Pool<Event>::Iterator& itKillEvent) {
868 #if CONFIG_DEVMODE
869 if (!itKillEvent) dmsg(1,("AbstractVoice::Kill(): ERROR, !itKillEvent !!!\n"));
870 if (itKillEvent && !itKillEvent.isValid()) dmsg(1,("AbstractVoice::Kill(): ERROR, itKillEvent invalid !!!\n"));
871 #endif // CONFIG_DEVMODE
872
873 if (itTriggerEvent && itKillEvent->FragmentPos() <= itTriggerEvent->FragmentPos()) return;
874 this->itKillEvent = itKillEvent;
875 }
876
877 Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {
878 PitchInfo pitch;
879 double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
880
881 // GSt behaviour: maximum transpose up is 40 semitones. If
882 // MIDI key is more than 40 semitones above unity note,
883 // the transpose is not done.
884 //
885 // Update: Removed this GSt misbehavior. I don't think that any stock
886 // gig sound requires it to resemble its original sound.
887 // -- Christian, 2017-07-09
888 if (!SmplInfo.Unpitched /* && (MIDIKey() - (int) RgnInfo.UnityNote) < 40*/)
889 pitchbasecents += (MIDIKey() - (int) RgnInfo.UnityNote) * 100;
890
891 pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
892 pitch.PitchBendRange = 1.0 / 8192.0 * 100.0 * InstrInfo.PitchbendRange;
893 pitch.PitchBend = RTMath::CentsToFreqRatio(PitchBend * pitch.PitchBendRange);
894
895 return pitch;
896 }
897
898 void AbstractVoice::onScaleTuningChanged() {
899 PitchInfo pitch = this->Pitch;
900 double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
901
902 // GSt behaviour: maximum transpose up is 40 semitones. If
903 // MIDI key is more than 40 semitones above unity note,
904 // the transpose is not done.
905 //
906 // Update: Removed this GSt misbehavior. I don't think that any stock
907 // gig sound requires it to resemble its original sound.
908 // -- Christian, 2017-07-09
909 if (!SmplInfo.Unpitched /* && (MIDIKey() - (int) RgnInfo.UnityNote) < 40*/)
910 pitchbasecents += (MIDIKey() - (int) RgnInfo.UnityNote) * 100;
911
912 pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
913 this->Pitch = pitch;
914 }
915
916 double AbstractVoice::CalculateVolume(double velocityAttenuation) {
917 // For 16 bit samples, we downscale by 32768 to convert from
918 // int16 value range to DSP value range (which is
919 // -1.0..1.0). For 24 bit, we downscale from int32.
920 float volume = velocityAttenuation / (SmplInfo.BitDepth == 16 ? 32768.0f : 32768.0f * 65536.0f);
921
922 volume *= GetSampleAttenuation() * pEngineChannel->GlobalVolume * GLOBAL_VOLUME;
923
924 // the volume of release triggered samples depends on note length
925 if (Type & Voice::type_release_trigger) {
926 float noteLength = float(GetEngine()->FrameTime + Delay -
927 GetNoteOnTime(MIDIKey()) ) / GetEngine()->SampleRate;
928
929 volume *= GetReleaseTriggerAttenuation(noteLength);
930 }
931
932 return volume;
933 }
934
935 float AbstractVoice::GetReleaseTriggerAttenuation(float noteLength) {
936 return 1 - RgnInfo.ReleaseTriggerDecay * noteLength;
937 }
938
939 void AbstractVoice::EnterReleaseStage() {
940 if (pSignalUnitRack == NULL) {
941 pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
942 pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
943 } else {
944 pSignalUnitRack->EnterReleaseStage();
945 }
946 }
947
948 bool AbstractVoice::EG1Finished() {
949 if (pSignalUnitRack == NULL) {
950 return pEG1->getSegmentType() == EG::segment_end;
951 } else {
952 return !pSignalUnitRack->GetEndpointUnit()->Active();
953 }
954 }
955
956 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC