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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2015 - (hide annotations) (download)
Sun Oct 25 22:22:52 2009 UTC (14 years, 5 months ago) by iliev
File size: 30091 byte(s)
* Refactoring: moved the independent code from gig::Voice to base classes
* SoundFont format engine: implemented EG1 & EG2

1 iliev 2015 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6     * Copyright (C) 2005-2009 Christian Schoenebeck *
7     * Copyright (C) 2009 Grigor Iliev *
8     * *
9     * This program is free software; you can redistribute it and/or modify *
10     * it under the terms of the GNU General Public License as published by *
11     * the Free Software Foundation; either version 2 of the License, or *
12     * (at your option) any later version. *
13     * *
14     * This program is distributed in the hope that it will be useful, *
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17     * GNU General Public License for more details. *
18     * *
19     * You should have received a copy of the GNU General Public License *
20     * along with this program; if not, write to the Free Software *
21     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
22     * MA 02111-1307 USA *
23     ***************************************************************************/
24    
25     #include "AbstractVoice.h"
26    
27     namespace LinuxSampler {
28    
29     AbstractVoice::AbstractVoice() {
30     pEngineChannel = NULL;
31     pLFO1 = new LFOUnsigned(1.0f); // amplitude EG (0..1 range)
32     pLFO2 = new LFOUnsigned(1.0f); // filter EG (0..1 range)
33     pLFO3 = new LFOSigned(1200.0f); // pitch EG (-1200..+1200 range)
34     PlaybackState = playback_state_end;
35     KeyGroup = 0;
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    
49     AbstractVoice::~AbstractVoice() {
50     if (pLFO1) delete pLFO1;
51     if (pLFO2) delete pLFO2;
52     if (pLFO3) delete pLFO3;
53     }
54    
55     /**
56     * Resets voice variables. Should only be called if rendering process is
57     * suspended / not running.
58     */
59     void AbstractVoice::Reset() {
60     finalSynthesisParameters.filterLeft.Reset();
61     finalSynthesisParameters.filterRight.Reset();
62     DiskStreamRef.pStream = NULL;
63     DiskStreamRef.hStream = 0;
64     DiskStreamRef.State = Stream::state_unused;
65     DiskStreamRef.OrderID = 0;
66     PlaybackState = playback_state_end;
67     itTriggerEvent = Pool<Event>::Iterator();
68     itKillEvent = Pool<Event>::Iterator();
69     }
70    
71     /**
72     * Initializes and triggers the voice, a disk stream will be launched if
73     * needed.
74     *
75     * @param pEngineChannel - engine channel on which this voice was ordered
76     * @param itNoteOnEvent - event that caused triggering of this voice
77     * @param PitchBend - MIDI detune factor (-8192 ... +8191)
78     * @param pRegion- points to the region which provides sample wave(s) and articulation data
79     * @param VoiceType - type of this voice
80     * @param iKeyGroup - a value > 0 defines a key group in which this voice is member of
81     * @returns 0 on success, a value < 0 if the voice wasn't triggered
82     * (either due to an error or e.g. because no region is
83     * defined for the given key)
84     */
85     int AbstractVoice::Trigger (
86     AbstractEngineChannel* pEngineChannel,
87     Pool<Event>::Iterator& itNoteOnEvent,
88     int PitchBend,
89     type_t VoiceType,
90     int iKeyGroup
91     ) {
92     this->pEngineChannel = pEngineChannel;
93     Orphan = false;
94    
95     #if CONFIG_DEVMODE
96     if (itNoteOnEvent->FragmentPos() > GetEngine()->MaxSamplesPerCycle) { // just a sanity check for debugging
97     dmsg(1,("Voice::Trigger(): ERROR, TriggerDelay > Totalsamples\n"));
98     }
99     #endif // CONFIG_DEVMODE
100    
101     Type = VoiceType;
102     MIDIKey = itNoteOnEvent->Param.Note.Key;
103     PlaybackState = playback_state_init; // mark voice as triggered, but no audio rendered yet
104     Delay = itNoteOnEvent->FragmentPos();
105     itTriggerEvent = itNoteOnEvent;
106     itKillEvent = Pool<Event>::Iterator();
107     KeyGroup = iKeyGroup;
108    
109     SmplInfo = GetSampleInfo();
110     RgnInfo = GetRegionInfo();
111     InstrInfo = GetInstrumentInfo();
112    
113     // calculate volume
114     const double velocityAttenuation = GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity);
115     float volume = CalculateVolume(velocityAttenuation);
116    
117     // select channel mode (mono or stereo)
118     SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, SmplInfo.ChannelCount == 2);
119     // select bit depth (16 or 24)
120     SYNTHESIS_MODE_SET_BITDEPTH24(SynthesisMode, SmplInfo.BitDepth == 24);
121    
122     // get starting crossfade volume level
123     float crossfadeVolume = CalculateCrossfadeVolume(itNoteOnEvent->Param.Note.Velocity);
124    
125     VolumeLeft = volume * AbstractEngine::PanCurve[64 - RgnInfo.Pan];
126     VolumeRight = volume * AbstractEngine::PanCurve[64 + RgnInfo.Pan];
127    
128     float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;
129     CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);
130     VolumeSmoother.trigger(pEngineChannel->MidiVolume, subfragmentRate);
131     PanLeftSmoother.trigger(pEngineChannel->GlobalPanLeft, subfragmentRate);
132     PanRightSmoother.trigger(pEngineChannel->GlobalPanRight, subfragmentRate);
133    
134     finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
135     Pos = RgnInfo.SampleStartOffset;
136    
137     // Check if the sample needs disk streaming or is too short for that
138     long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;
139     DiskVoice = cachedsamples < SmplInfo.TotalFrameCount;
140    
141     if (DiskVoice) { // voice to be streamed from disk
142     if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {
143     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)
144     } else {
145     // The cache is too small to fit a max sample buffer.
146     // Setting MaxRAMPos to 0 will probably cause a click
147     // in the audio, but it's better than not handling
148     // this case at all, which would have caused the
149     // unsigned MaxRAMPos to be set to a negative number.
150     MaxRAMPos = 0;
151     }
152    
153     // check if there's a loop defined which completely fits into the cached (RAM) part of the sample
154     RAMLoop = (SmplInfo.HasLoops && (SmplInfo.LoopStart + SmplInfo.LoopLength) <= MaxRAMPos);
155    
156     if (OrderNewStream()) return -1;
157     dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s)\n", cachedsamples, SmplInfo.TotalFrameCount, MaxRAMPos, (RAMLoop) ? "yes" : "no"));
158     }
159     else { // RAM only voice
160     MaxRAMPos = cachedsamples;
161     RAMLoop = (SmplInfo.HasLoops);
162     dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));
163     }
164     if (RAMLoop) {
165     loop.uiTotalCycles = SmplInfo.LoopPlayCount;
166     loop.uiCyclesLeft = SmplInfo.LoopPlayCount;
167     loop.uiStart = SmplInfo.LoopStart;
168     loop.uiEnd = SmplInfo.LoopStart + SmplInfo.LoopLength;
169     loop.uiSize = SmplInfo.LoopLength;
170     }
171    
172     Pitch = CalculatePitchInfo(PitchBend);
173    
174     // the length of the decay and release curves are dependent on the velocity
175     const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);
176    
177     // setup EG 1 (VCA EG)
178     {
179     // get current value of EG1 controller
180     double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);
181    
182     // calculate influence of EG1 controller on EG1's parameters
183     EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);
184    
185     EG1.trigger (
186     RgnInfo.EG1PreAttack,
187     RgnInfo.EG1Attack * egInfo.Attack,
188     RgnInfo.EG1Hold,
189     RgnInfo.EG1Decay1 * egInfo.Decay * velrelease,
190     RgnInfo.EG1Decay2 * egInfo.Decay * velrelease,
191     RgnInfo.EG1InfiniteSustain,
192     RgnInfo.EG1Sustain,
193     RgnInfo.EG1Release * egInfo.Release * velrelease,
194     velocityAttenuation,
195     GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE
196     );
197     }
198    
199     #ifdef CONFIG_INTERPOLATE_VOLUME
200     // setup initial volume in synthesis parameters
201     #ifdef CONFIG_PROCESS_MUTED_CHANNELS
202     if (pEngineChannel->GetMute()) {
203     finalSynthesisParameters.fFinalVolumeLeft = 0;
204     finalSynthesisParameters.fFinalVolumeRight = 0;
205     }
206     else
207     #else
208     {
209     float finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * EG1.getLevel();
210    
211     finalSynthesisParameters.fFinalVolumeLeft = finalVolume * VolumeLeft * pEngineChannel->GlobalPanLeft;
212     finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight;
213     }
214     #endif
215     #endif
216    
217     // setup EG 2 (VCF Cutoff EG)
218     {
219     // get current value of EG2 controller
220     double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);
221    
222     // calculate influence of EG2 controller on EG2's parameters
223     EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);
224    
225     EG2.trigger (
226     RgnInfo.EG2PreAttack,
227     RgnInfo.EG2Attack * egInfo.Attack,
228     false,
229     RgnInfo.EG2Decay1 * egInfo.Decay * velrelease,
230     RgnInfo.EG2Decay2 * egInfo.Decay * velrelease,
231     RgnInfo.EG2InfiniteSustain,
232     RgnInfo.EG2Sustain,
233     RgnInfo.EG2Release * egInfo.Release * velrelease,
234     velocityAttenuation,
235     GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE
236     );
237     }
238    
239    
240     // setup EG 3 (VCO EG)
241     {
242     // if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch
243     bool bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;
244     float eg3depth = (bPortamento)
245     ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100)
246     : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);
247     float eg3time = (bPortamento)
248     ? pEngineChannel->PortamentoTime
249     : RgnInfo.EG3Attack;
250     EG3.trigger(eg3depth, eg3time, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
251     dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time));
252     }
253    
254    
255     // setup LFO 1 (VCA LFO)
256     InitLFO1();
257     // setup LFO 2 (VCF Cutoff LFO)
258     InitLFO2();
259     // setup LFO 3 (VCO LFO)
260     InitLFO3();
261    
262    
263     #if CONFIG_FORCE_FILTER
264     const bool bUseFilter = true;
265     #else // use filter only if instrument file told so
266     const bool bUseFilter = RgnInfo.VCFEnabled;
267     #endif // CONFIG_FORCE_FILTER
268     SYNTHESIS_MODE_SET_FILTER(SynthesisMode, bUseFilter);
269     if (bUseFilter) {
270     #ifdef CONFIG_OVERRIDE_CUTOFF_CTRL
271     VCFCutoffCtrl.controller = CONFIG_OVERRIDE_CUTOFF_CTRL;
272     #else // use the one defined in the instrument file
273     VCFCutoffCtrl.controller = GetVCFCutoffCtrl();
274     #endif // CONFIG_OVERRIDE_CUTOFF_CTRL
275    
276     #ifdef CONFIG_OVERRIDE_RESONANCE_CTRL
277     VCFResonanceCtrl.controller = CONFIG_OVERRIDE_RESONANCE_CTRL;
278     #else // use the one defined in the instrument file
279     VCFResonanceCtrl.controller = GetVCFResonanceCtrl();
280     #endif // CONFIG_OVERRIDE_RESONANCE_CTRL
281    
282     #ifndef CONFIG_OVERRIDE_FILTER_TYPE
283     finalSynthesisParameters.filterLeft.SetType(RgnInfo.VCFType);
284     finalSynthesisParameters.filterRight.SetType(RgnInfo.VCFType);
285     #else // override filter type
286     finalSynthesisParameters.filterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE);
287     finalSynthesisParameters.filterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE);
288     #endif // CONFIG_OVERRIDE_FILTER_TYPE
289    
290     VCFCutoffCtrl.value = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller];
291     VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller];
292    
293     // calculate cutoff frequency
294     CutoffBase = CalculateCutoffBase(itNoteOnEvent->Param.Note.Velocity);
295    
296     VCFCutoffCtrl.fvalue = CalculateFinalCutoff(CutoffBase);
297    
298     // calculate resonance
299     float resonance = (float) (VCFResonanceCtrl.controller ? VCFResonanceCtrl.value : RgnInfo.VCFResonance);
300     VCFResonanceCtrl.fvalue = resonance;
301     } else {
302     VCFCutoffCtrl.controller = 0;
303     VCFResonanceCtrl.controller = 0;
304     }
305    
306     return 0; // success
307     }
308    
309     /**
310     * Synthesizes the current audio fragment for this voice.
311     *
312     * @param Samples - number of sample points to be rendered in this audio
313     * fragment cycle
314     * @param pSrc - pointer to input sample data
315     * @param Skip - number of sample points to skip in output buffer
316     */
317     void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
318     AbstractEngineChannel* pChannel = pEngineChannel;
319     finalSynthesisParameters.pOutLeft = &pChannel->pChannelLeft->Buffer()[Skip];
320     finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];
321     finalSynthesisParameters.pSrc = pSrc;
322    
323     RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();
324     RTList<Event>::Iterator itNoteEvent;
325     GetFirstEventOnKey(MIDIKey, itNoteEvent);
326    
327     if (itTriggerEvent) { // skip events that happened before this voice was triggered
328     while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;
329     // we can't simply compare the timestamp here, because note events
330     // might happen on the same time stamp, so we have to deal on the
331     // actual sequence the note events arrived instead (see bug #112)
332     for (; itNoteEvent; ++itNoteEvent) {
333     if (itTriggerEvent == itNoteEvent) {
334     ++itNoteEvent;
335     break;
336     }
337     }
338     }
339    
340     uint killPos;
341     if (itKillEvent) {
342     int maxFadeOutPos = Samples - GetEngine()->GetMinFadeOutSamples();
343     if (maxFadeOutPos < 0) {
344     // There's not enough space in buffer to do a fade out
345     // from max volume (this can only happen for audio
346     // drivers that use Samples < MaxSamplesPerCycle).
347     // End the EG1 here, at pos 0, with a shorter max fade
348     // out time.
349     EG1.enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
350     itKillEvent = Pool<Event>::Iterator();
351     } else {
352     killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);
353     }
354     }
355    
356     uint i = Skip;
357     while (i < Samples) {
358     int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples);
359    
360     // initialize all final synthesis parameters
361     fFinalCutoff = VCFCutoffCtrl.fvalue;
362     fFinalResonance = VCFResonanceCtrl.fvalue;
363    
364     // process MIDI control change and pitchbend events for this subfragment
365     processCCEvents(itCCEvent, iSubFragmentEnd);
366    
367     finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend;
368     float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();
369     #ifdef CONFIG_PROCESS_MUTED_CHANNELS
370     if (pChannel->GetMute()) fFinalVolume = 0;
371     #endif
372    
373     // process transition events (note on, note off & sustain pedal)
374     processTransitionEvents(itNoteEvent, iSubFragmentEnd);
375    
376     // if the voice was killed in this subfragment, or if the
377     // filter EG is finished, switch EG1 to fade out stage
378     if ((itKillEvent && killPos <= iSubFragmentEnd) ||
379     (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
380     EG2.getSegmentType() == gig::EGADSR::segment_end)) {
381     EG1.enterFadeOutStage();
382     itKillEvent = Pool<Event>::Iterator();
383     }
384    
385     // process envelope generators
386     switch (EG1.getSegmentType()) {
387     case gig::EGADSR::segment_lin:
388     fFinalVolume *= EG1.processLin();
389     break;
390     case gig::EGADSR::segment_exp:
391     fFinalVolume *= EG1.processExp();
392     break;
393     case gig::EGADSR::segment_end:
394     fFinalVolume *= EG1.getLevel();
395     break; // noop
396     }
397     switch (EG2.getSegmentType()) {
398     case gig::EGADSR::segment_lin:
399     fFinalCutoff *= EG2.processLin();
400     break;
401     case gig::EGADSR::segment_exp:
402     fFinalCutoff *= EG2.processExp();
403     break;
404     case gig::EGADSR::segment_end:
405     fFinalCutoff *= EG2.getLevel();
406     break; // noop
407     }
408     if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();
409    
410     // process low frequency oscillators
411     if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());
412     if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();
413     if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
414    
415     // limit the pitch so we don't read outside the buffer
416     finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));
417    
418     // if filter enabled then update filter coefficients
419     if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) {
420     finalSynthesisParameters.filterLeft.SetParameters(fFinalCutoff, fFinalResonance, GetEngine()->SampleRate);
421     finalSynthesisParameters.filterRight.SetParameters(fFinalCutoff, fFinalResonance, GetEngine()->SampleRate);
422     }
423    
424     // do we need resampling?
425     const float __PLUS_ONE_CENT = 1.000577789506554859250142541782224725466f;
426     const float __MINUS_ONE_CENT = 0.9994225441413807496009516495583113737666f;
427     const bool bResamplingRequired = !(finalSynthesisParameters.fFinalPitch <= __PLUS_ONE_CENT &&
428     finalSynthesisParameters.fFinalPitch >= __MINUS_ONE_CENT);
429     SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, bResamplingRequired);
430    
431     // prepare final synthesis parameters structure
432     finalSynthesisParameters.uiToGo = iSubFragmentEnd - i;
433     #ifdef CONFIG_INTERPOLATE_VOLUME
434     finalSynthesisParameters.fFinalVolumeDeltaLeft =
435     (fFinalVolume * VolumeLeft * PanLeftSmoother.render() -
436     finalSynthesisParameters.fFinalVolumeLeft) / finalSynthesisParameters.uiToGo;
437     finalSynthesisParameters.fFinalVolumeDeltaRight =
438     (fFinalVolume * VolumeRight * PanRightSmoother.render() -
439     finalSynthesisParameters.fFinalVolumeRight) / finalSynthesisParameters.uiToGo;
440     #else
441     finalSynthesisParameters.fFinalVolumeLeft =
442     fFinalVolume * VolumeLeft * PanLeftSmoother.render();
443     finalSynthesisParameters.fFinalVolumeRight =
444     fFinalVolume * VolumeRight * PanRightSmoother.render();
445     #endif
446     // render audio for one subfragment
447     RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
448    
449     // stop the rendering if volume EG is finished
450     if (EG1.getSegmentType() == gig::EGADSR::segment_end) break;
451    
452     const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
453    
454     // increment envelopes' positions
455     if (EG1.active()) {
456    
457     // 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
458     if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
459     EG1.update(gig::EGADSR::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
460     }
461    
462     EG1.increment(1);
463     if (!EG1.toStageEndLeft()) EG1.update(gig::EGADSR::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
464     }
465     if (EG2.active()) {
466     EG2.increment(1);
467     if (!EG2.toStageEndLeft()) EG2.update(gig::EGADSR::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
468     }
469     EG3.increment(1);
470     if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
471    
472     Pos = newPos;
473     i = iSubFragmentEnd;
474     }
475     }
476    
477     /**
478     * Process given list of MIDI control change and pitch bend events for
479     * the given time.
480     *
481     * @param itEvent - iterator pointing to the next event to be processed
482     * @param End - youngest time stamp where processing should be stopped
483     */
484     void AbstractVoice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) {
485     for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
486     if (itEvent->Type == Event::type_control_change && itEvent->Param.CC.Controller) { // if (valid) MIDI control change event
487     if (itEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {
488     ProcessCutoffEvent(itEvent);
489     }
490     if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
491     processResonanceEvent(itEvent);
492     }
493     if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
494     pLFO1->update(itEvent->Param.CC.Value);
495     }
496     if (itEvent->Param.CC.Controller == pLFO2->ExtController) {
497     pLFO2->update(itEvent->Param.CC.Value);
498     }
499     if (itEvent->Param.CC.Controller == pLFO3->ExtController) {
500     pLFO3->update(itEvent->Param.CC.Value);
501     }
502     if (itEvent->Param.CC.Controller == 7) { // volume
503     VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);
504     } else if (itEvent->Param.CC.Controller == 10) { // panpot
505     PanLeftSmoother.update(AbstractEngine::PanCurve[128 - itEvent->Param.CC.Value]);
506     PanRightSmoother.update(AbstractEngine::PanCurve[itEvent->Param.CC.Value]);
507     }
508     } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event
509     processPitchEvent(itEvent);
510     }
511    
512     ProcessCCEvent(itEvent);
513     }
514     }
515    
516     void AbstractVoice::processPitchEvent(RTList<Event>::Iterator& itEvent) {
517     Pitch.PitchBend = RTMath::CentsToFreqRatio(itEvent->Param.Pitch.Pitch * Pitch.PitchBendRange);
518     }
519    
520     void AbstractVoice::processResonanceEvent(RTList<Event>::Iterator& itEvent) {
521     // convert absolute controller value to differential
522     const int ctrldelta = itEvent->Param.CC.Value - VCFResonanceCtrl.value;
523     VCFResonanceCtrl.value = itEvent->Param.CC.Value;
524     const float resonancedelta = (float) ctrldelta;
525     fFinalResonance += resonancedelta;
526     // needed for initialization of parameter
527     VCFResonanceCtrl.fvalue = itEvent->Param.CC.Value;
528     }
529    
530     /**
531     * Process given list of MIDI note on, note off and sustain pedal events
532     * for the given time.
533     *
534     * @param itEvent - iterator pointing to the next event to be processed
535     * @param End - youngest time stamp where processing should be stopped
536     */
537     void AbstractVoice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {
538     for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
539     if (itEvent->Type == Event::type_release) {
540     EG1.update(gig::EGADSR::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
541     EG2.update(gig::EGADSR::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
542     } else if (itEvent->Type == Event::type_cancel_release) {
543     EG1.update(gig::EGADSR::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
544     EG2.update(gig::EGADSR::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
545     }
546     }
547     }
548    
549     /** @brief Update current portamento position.
550     *
551     * Will be called when portamento mode is enabled to get the final
552     * portamento position of this active voice from where the next voice(s)
553     * might continue to slide on.
554     *
555     * @param itNoteOffEvent - event which causes this voice to die soon
556     */
557     void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
558     const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
559     pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
560     }
561    
562     /**
563     * Kill the voice in regular sense. Let the voice render audio until
564     * the kill event actually occured and then fade down the volume level
565     * very quickly and let the voice die finally. Unlike a normal release
566     * of a voice, a kill process cannot be cancalled and is therefore
567     * usually used for voice stealing and key group conflicts.
568     *
569     * @param itKillEvent - event which caused the voice to be killed
570     */
571     void AbstractVoice::Kill(Pool<Event>::Iterator& itKillEvent) {
572     #if CONFIG_DEVMODE
573     if (!itKillEvent) dmsg(1,("AbstractVoice::Kill(): ERROR, !itKillEvent !!!\n"));
574     if (itKillEvent && !itKillEvent.isValid()) dmsg(1,("AbstractVoice::Kill(): ERROR, itKillEvent invalid !!!\n"));
575     #endif // CONFIG_DEVMODE
576    
577     if (itTriggerEvent && itKillEvent->FragmentPos() <= itTriggerEvent->FragmentPos()) return;
578     this->itKillEvent = itKillEvent;
579     }
580    
581     Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {
582     PitchInfo pitch;
583     double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey % 12];
584    
585     // GSt behaviour: maximum transpose up is 40 semitones. If
586     // MIDI key is more than 40 semitones above unity note,
587     // the transpose is not done.
588     if (!SmplInfo.Unpitched && (MIDIKey - (int) RgnInfo.UnityNote) < 40) pitchbasecents += (MIDIKey - (int) RgnInfo.UnityNote) * 100;
589    
590     pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
591     pitch.PitchBendRange = 1.0 / 8192.0 * 100.0 * InstrInfo.PitchbendRange;
592     pitch.PitchBend = RTMath::CentsToFreqRatio(PitchBend * pitch.PitchBendRange);
593    
594     return pitch;
595     }
596    
597     double AbstractVoice::CalculateVolume(double velocityAttenuation) {
598     // For 16 bit samples, we downscale by 32768 to convert from
599     // int16 value range to DSP value range (which is
600     // -1.0..1.0). For 24 bit, we downscale from int32.
601     float volume = velocityAttenuation / (SmplInfo.BitDepth == 16 ? 32768.0f : 32768.0f * 65536.0f);
602    
603     volume *= GetSampleAttenuation() * pEngineChannel->GlobalVolume * GLOBAL_VOLUME;
604    
605     // the volume of release triggered samples depends on note length
606     if (Type == Voice::type_release_trigger) {
607     float noteLength = float(GetEngine()->FrameTime + Delay -
608     GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;
609    
610     float attenuation = 1 - 0.01053 * (256 >> RgnInfo.ReleaseTriggerDecay) * noteLength;
611     if (attenuation <= 0) return -1;
612     volume *= attenuation;
613     }
614    
615     return volume;
616     }
617     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC