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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2032 by persson, Fri Nov 20 20:13:08 2009 UTC revision 3246 by schoenebeck, Sun May 28 22:22:56 2017 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2009 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009 Grigor Iliev                                       *   *   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  *   *   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  *   *   it under the terms of the GNU General Public License as published by  *
# Line 26  Line 27 
27    
28  namespace LinuxSampler {  namespace LinuxSampler {
29    
30      AbstractVoice::AbstractVoice() {      AbstractVoice::AbstractVoice(SignalUnitRack* pRack): pSignalUnitRack(pRack) {
31          pEngineChannel = NULL;          pEngineChannel = NULL;
32          pLFO1 = new LFOUnsigned(1.0f);  // amplitude EG (0..1 range)          pLFO1 = new LFOUnsigned(1.0f);  // amplitude LFO (0..1 range)
33          pLFO2 = new LFOUnsigned(1.0f);  // filter EG (0..1 range)          pLFO2 = new LFOUnsigned(1.0f);  // filter LFO (0..1 range)
34          pLFO3 = new LFOSigned(1200.0f); // pitch EG (-1200..+1200 range)          pLFO3 = new LFOSigned(1200.0f); // pitch LFO (-1200..+1200 range)
35          PlaybackState = playback_state_end;          PlaybackState = playback_state_end;
         KeyGroup = 0;  
36          SynthesisMode = 0; // set all mode bits to 0 first          SynthesisMode = 0; // set all mode bits to 0 first
37          // select synthesis implementation (asm core is not supported ATM)          // select synthesis implementation (asm core is not supported ATM)
38          #if 0 // CONFIG_ASM && ARCH_X86          #if 0 // CONFIG_ASM && ARCH_X86
# Line 44  namespace LinuxSampler { Line 44  namespace LinuxSampler {
44    
45          finalSynthesisParameters.filterLeft.Reset();          finalSynthesisParameters.filterLeft.Reset();
46          finalSynthesisParameters.filterRight.Reset();          finalSynthesisParameters.filterRight.Reset();
47            
48            pEq          = NULL;
49            bEqSupport   = false;
50      }      }
51    
52      AbstractVoice::~AbstractVoice() {      AbstractVoice::~AbstractVoice() {
53          if (pLFO1) delete pLFO1;          if (pLFO1) delete pLFO1;
54          if (pLFO2) delete pLFO2;          if (pLFO2) delete pLFO2;
55          if (pLFO3) delete pLFO3;          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       *  Resets voice variables. Should only be called if rendering process is
69       *  suspended / not running.       *  suspended / not running.
# Line 99  namespace LinuxSampler { Line 111  namespace LinuxSampler {
111          #endif // CONFIG_DEVMODE          #endif // CONFIG_DEVMODE
112    
113          Type            = VoiceType;          Type            = VoiceType;
114          MIDIKey         = itNoteOnEvent->Param.Note.Key;          pNote           = pEngineChannel->pEngine->NoteByID( itNoteOnEvent->Param.Note.ID );
115          PlaybackState   = playback_state_init; // mark voice as triggered, but no audio rendered yet          PlaybackState   = playback_state_init; // mark voice as triggered, but no audio rendered yet
116          Delay           = itNoteOnEvent->FragmentPos();          Delay           = itNoteOnEvent->FragmentPos();
117          itTriggerEvent  = itNoteOnEvent;          itTriggerEvent  = itNoteOnEvent;
118          itKillEvent     = Pool<Event>::Iterator();          itKillEvent     = Pool<Event>::Iterator();
119          KeyGroup        = iKeyGroup;          MidiKeyBase* pKeyInfo = GetMidiKeyInfo(MIDIKey());
120    
121            pGroupEvents = iKeyGroup ? pEngineChannel->ActiveKeyGroups[iKeyGroup] : 0;
122    
123          SmplInfo   = GetSampleInfo();          SmplInfo   = GetSampleInfo();
124          RgnInfo    = GetRegionInfo();          RgnInfo    = GetRegionInfo();
125          InstrInfo  = GetInstrumentInfo();          InstrInfo  = GetInstrumentInfo();
126            
127            MIDIPan    = CalculatePan(pEngineChannel->iLastPanRequest);
128    
129            AboutToTrigger();
130    
131          // calculate volume          // calculate volume
132          const double velocityAttenuation = GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity);          const double velocityAttenuation = GetVelocityAttenuation(MIDIVelocity());
133          float volume = CalculateVolume(velocityAttenuation);          float volume = CalculateVolume(velocityAttenuation) * pKeyInfo->Volume;
134          if (volume <= 0) return -1;          if (volume <= 0) return -1;
135    
136          // select channel mode (mono or stereo)          // select channel mode (mono or stereo)
# Line 121  namespace LinuxSampler { Line 139  namespace LinuxSampler {
139          SYNTHESIS_MODE_SET_BITDEPTH24(SynthesisMode, SmplInfo.BitDepth == 24);          SYNTHESIS_MODE_SET_BITDEPTH24(SynthesisMode, SmplInfo.BitDepth == 24);
140    
141          // get starting crossfade volume level          // get starting crossfade volume level
142          float crossfadeVolume = CalculateCrossfadeVolume(itNoteOnEvent->Param.Note.Velocity);          float crossfadeVolume = CalculateCrossfadeVolume(MIDIVelocity());
143    
144          VolumeLeft  = volume * AbstractEngine::PanCurve[64 - RgnInfo.Pan];          VolumeLeft  = volume * pKeyInfo->PanLeft;
145          VolumeRight = volume * AbstractEngine::PanCurve[64 + RgnInfo.Pan];          VolumeRight = volume * pKeyInfo->PanRight;
146    
147          float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;          // 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);          CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);
         VolumeSmoother.trigger(pEngineChannel->MidiVolume, subfragmentRate);  
         PanLeftSmoother.trigger(pEngineChannel->GlobalPanLeft, subfragmentRate);  
         PanRightSmoother.trigger(pEngineChannel->GlobalPanRight, subfragmentRate);  
152    
153          finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)          VolumeSmoother.trigger(pEngineChannel->MidiVolume, subfragmentRate);
154          Pos = RgnInfo.SampleStartOffset;          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          // Check if the sample needs disk streaming or is too short for that
159          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;
160          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;
161    
162            SetSampleStartOffset();
163    
164          if (DiskVoice) { // voice to be streamed from disk          if (DiskVoice) { // voice to be streamed from disk
165              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {              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)                  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)
# Line 155  namespace LinuxSampler { Line 177  namespace LinuxSampler {
177              RAMLoop = (SmplInfo.HasLoops && (SmplInfo.LoopStart + SmplInfo.LoopLength) <= MaxRAMPos);              RAMLoop = (SmplInfo.HasLoops && (SmplInfo.LoopStart + SmplInfo.LoopLength) <= MaxRAMPos);
178    
179              if (OrderNewStream()) return -1;              if (OrderNewStream()) return -1;
180              dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s)\n", cachedsamples, SmplInfo.TotalFrameCount, MaxRAMPos, (RAMLoop) ? "yes" : "no"));              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          else { // RAM only voice
183              MaxRAMPos = cachedsamples;              MaxRAMPos = cachedsamples;
# Line 171  namespace LinuxSampler { Line 193  namespace LinuxSampler {
193          }          }
194    
195          Pitch = CalculatePitchInfo(PitchBend);          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          // the length of the decay and release curves are dependent on the velocity
203          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);          const double velrelease = 1 / GetVelocityRelease(MIDIVelocity());
204    
205          // setup EG 1 (VCA EG)          if (pSignalUnitRack == NULL) { // setup EG 1 (VCA EG)
         {  
206              // get current value of EG1 controller              // get current value of EG1 controller
207              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);              double eg1controllervalue = GetEG1ControllerValue(MIDIVelocity());
208    
209              // calculate influence of EG1 controller on EG1's parameters              // calculate influence of EG1 controller on EG1's parameters
210              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);
211    
212              EG1.trigger (              if (pNote) {
213                  RgnInfo.EG1PreAttack,                  egInfo.Attack  *= pNote->Override.Attack;
214                  RgnInfo.EG1Attack * egInfo.Attack,                  egInfo.Decay   *= pNote->Override.Decay;
215                  RgnInfo.EG1Hold,                  egInfo.Release *= pNote->Override.Release;
216                  RgnInfo.EG1Decay1 * egInfo.Decay * velrelease,              }
217                  RgnInfo.EG1Decay2 * egInfo.Decay * velrelease,  
218                  RgnInfo.EG1InfiniteSustain,              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, MIDIVelocity());
219                  RgnInfo.EG1Sustain,          } else {
220                  RgnInfo.EG1Release * egInfo.Release * velrelease,              pSignalUnitRack->Trigger();
                 velocityAttenuation,  
                 GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE  
             );  
221          }          }
222    
223            const uint8_t pan = (pSignalUnitRack) ? pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan) : MIDIPan;
224            NotePanLeft  = (pNote) ? AbstractEngine::PanCurveValueNorm(pNote->Override.Pan, 0 /*left*/ ) : 1.f;
225            NotePanRight = (pNote) ? AbstractEngine::PanCurveValueNorm(pNote->Override.Pan, 1 /*right*/) : 1.f;
226            PanLeftSmoother.trigger(
227                AbstractEngine::PanCurve[128 - pan] * NotePanLeft,
228                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)
229            );
230            PanRightSmoother.trigger(
231                AbstractEngine::PanCurve[pan] * NotePanRight,
232                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)
233            );
234    
235  #ifdef CONFIG_INTERPOLATE_VOLUME  #ifdef CONFIG_INTERPOLATE_VOLUME
236          // setup initial volume in synthesis parameters          // setup initial volume in synthesis parameters
237      #ifdef CONFIG_PROCESS_MUTED_CHANNELS      #ifdef CONFIG_PROCESS_MUTED_CHANNELS
# Line 207  namespace LinuxSampler { Line 242  namespace LinuxSampler {
242          else          else
243      #else      #else
244          {          {
245              float finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * EG1.getLevel();              float finalVolume;
246                if (pSignalUnitRack == NULL) {
247                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();
248                } else {
249                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pSignalUnitRack->GetEndpointUnit()->GetVolume();
250                }
251    
252              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * pEngineChannel->GlobalPanLeft;              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * PanLeftSmoother.render();
253              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight;              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * PanRightSmoother.render();
254          }          }
255      #endif      #endif
256  #endif  #endif
257    
258          // setup EG 2 (VCF Cutoff EG)          if (pSignalUnitRack == NULL) {
259          {              // setup EG 2 (VCF Cutoff EG)
260              // get current value of EG2 controller              {
261              double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);                  // get current value of EG2 controller
262                    double eg2controllervalue = GetEG2ControllerValue(MIDIVelocity());
263    
264                    // calculate influence of EG2 controller on EG2's parameters
265                    EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);
266    
267                    TriggerEG2(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, MIDIVelocity());
268                }
269    
             // calculate influence of EG2 controller on EG2's parameters  
             EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);  
270    
271              EG2.trigger (              // setup EG 3 (VCO EG)
272                  RgnInfo.EG2PreAttack,              {
273                  RgnInfo.EG2Attack * egInfo.Attack,                  // if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch
274                  false,                  bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;
275                  RgnInfo.EG2Decay1 * egInfo.Decay * velrelease,                  float eg3depth = (bPortamento)
276                  RgnInfo.EG2Decay2 * egInfo.Decay * velrelease,                               ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey()) * 100)
277                  RgnInfo.EG2InfiniteSustain,                               : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);
278                  RgnInfo.EG2Sustain,                  float eg3time = (bPortamento)
279                  RgnInfo.EG2Release * egInfo.Release * velrelease,                              ? pEngineChannel->PortamentoTime
280                  velocityAttenuation,                              : RgnInfo.EG3Attack;
281                  GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE                  EG3.trigger(eg3depth, eg3time, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
282              );                  dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time));
283          }              }
284    
285    
286          // setup EG 3 (VCO EG)              // setup LFO 1 (VCA LFO)
287          {              InitLFO1();
288              // if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch              // setup LFO 2 (VCF Cutoff LFO)
289              bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;              InitLFO2();
290              float eg3depth = (bPortamento)              // setup LFO 3 (VCO LFO)
291                           ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100)              InitLFO3();
                          : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);  
             float eg3time = (bPortamento)  
                         ? pEngineChannel->PortamentoTime  
                         : RgnInfo.EG3Attack;  
             EG3.trigger(eg3depth, eg3time, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);  
             dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time));  
292          }          }
293    
294    
         // setup LFO 1 (VCA LFO)  
         InitLFO1();  
         // setup LFO 2 (VCF Cutoff LFO)  
         InitLFO2();  
         // setup LFO 3 (VCO LFO)  
         InitLFO3();  
   
   
295          #if CONFIG_FORCE_FILTER          #if CONFIG_FORCE_FILTER
296          const bool bUseFilter = true;          const bool bUseFilter = true;
297          #else // use filter only if instrument file told so          #else // use filter only if instrument file told so
# Line 292  namespace LinuxSampler { Line 323  namespace LinuxSampler {
323              VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller];              VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller];
324    
325              // calculate cutoff frequency              // calculate cutoff frequency
326              CutoffBase = CalculateCutoffBase(itNoteOnEvent->Param.Note.Velocity);              CutoffBase = CalculateCutoffBase(MIDIVelocity());
327    
328              VCFCutoffCtrl.fvalue = CalculateFinalCutoff(CutoffBase);              VCFCutoffCtrl.fvalue = CalculateFinalCutoff(CutoffBase);
329    
# Line 303  namespace LinuxSampler { Line 334  namespace LinuxSampler {
334              VCFCutoffCtrl.controller    = 0;              VCFCutoffCtrl.controller    = 0;
335              VCFResonanceCtrl.controller = 0;              VCFResonanceCtrl.controller = 0;
336          }          }
337            
338            const bool bEq =
339                pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && pEq->HasSupport();
340    
341            if (bEq) {
342                pEq->GetInChannelLeft()->Clear();
343                pEq->GetInChannelRight()->Clear();
344                pEq->RenderAudio(GetEngine()->pAudioOutputDevice->MaxSamplesPerCycle());
345            }
346    
347          return 0; // success          return 0; // success
348      }      }
349        
350        void AbstractVoice::SetSampleStartOffset() {
351            finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
352            Pos = RgnInfo.SampleStartOffset;
353        }
354    
355      /**      /**
356       *  Synthesizes the current audio fragment for this voice.       *  Synthesizes the current audio fragment for this voice.
# Line 316  namespace LinuxSampler { Line 361  namespace LinuxSampler {
361       *  @param Skip    - number of sample points to skip in output buffer       *  @param Skip    - number of sample points to skip in output buffer
362       */       */
363      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
364            bool delay = false; // Whether the voice playback should be delayed for this call
365            
366            if (pSignalUnitRack != NULL) {
367                uint delaySteps = pSignalUnitRack->GetEndpointUnit()->DelayTrigger();
368                if (delaySteps > 0) { // delay on the endpoint unit means delay of the voice playback
369                    if (delaySteps >= Samples) {
370                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(Samples);
371                        delay = true;
372                    } else {
373                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(delaySteps);
374                        Samples -= delaySteps;
375                        Skip += delaySteps;
376                    }
377                }
378            }
379            
380          AbstractEngineChannel* pChannel = pEngineChannel;          AbstractEngineChannel* pChannel = pEngineChannel;
381          finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];          MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey());
382          finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];  
383          finalSynthesisParameters.pSrc      = pSrc;          const bool bVoiceRequiresDedicatedRouting =
384                pEngineChannel->GetFxSendCount() > 0 &&
385                (pMidiKeyInfo->ReverbSend || pMidiKeyInfo->ChorusSend);
386            
387            const bool bEq =
388                pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && pEq->HasSupport();
389    
390            if (bEq) {
391                pEq->GetInChannelLeft()->Clear();
392                pEq->GetInChannelRight()->Clear();
393                finalSynthesisParameters.pOutLeft  = &pEq->GetInChannelLeft()->Buffer()[Skip];
394                finalSynthesisParameters.pOutRight = &pEq->GetInChannelRight()->Buffer()[Skip];
395                pSignalUnitRack->UpdateEqSettings(pEq);
396            } else if (bVoiceRequiresDedicatedRouting) {
397                finalSynthesisParameters.pOutLeft  = &GetEngine()->pDedicatedVoiceChannelLeft->Buffer()[Skip];
398                finalSynthesisParameters.pOutRight = &GetEngine()->pDedicatedVoiceChannelRight->Buffer()[Skip];
399            } else {
400                finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];
401                finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];
402            }
403            finalSynthesisParameters.pSrc = pSrc;
404    
405          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();
406          RTList<Event>::Iterator itNoteEvent;          RTList<Event>::Iterator itNoteEvent;
407          GetFirstEventOnKey(MIDIKey, itNoteEvent);          GetFirstEventOnKey(HostKey(), itNoteEvent);
408    
409            RTList<Event>::Iterator itGroupEvent;
410            if (pGroupEvents && !Orphan) itGroupEvent = pGroupEvents->first();
411    
412          if (itTriggerEvent) { // skip events that happened before this voice was triggered          if (itTriggerEvent) { // skip events that happened before this voice was triggered
413              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;
414                while (itGroupEvent && itGroupEvent->FragmentPos() <= Skip) ++itGroupEvent;
415    
416              // we can't simply compare the timestamp here, because note events              // we can't simply compare the timestamp here, because note events
417              // might happen on the same time stamp, so we have to deal on the              // might happen on the same time stamp, so we have to deal on the
418              // actual sequence the note events arrived instead (see bug #112)              // actual sequence the note events arrived instead (see bug #112)
# Line 338  namespace LinuxSampler { Line 424  namespace LinuxSampler {
424              }              }
425          }          }
426    
427          uint killPos;          uint killPos = 0;
428          if (itKillEvent) {          if (itKillEvent) {
429              int maxFadeOutPos = Samples - GetEngine()->GetMinFadeOutSamples();              int maxFadeOutPos = Samples - GetEngine()->GetMinFadeOutSamples();
430              if (maxFadeOutPos < 0) {              if (maxFadeOutPos < 0) {
# Line 347  namespace LinuxSampler { Line 433  namespace LinuxSampler {
433                  // drivers that use Samples < MaxSamplesPerCycle).                  // drivers that use Samples < MaxSamplesPerCycle).
434                  // End the EG1 here, at pos 0, with a shorter max fade                  // End the EG1 here, at pos 0, with a shorter max fade
435                  // out time.                  // out time.
436                  EG1.enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (pSignalUnitRack == NULL) {
437                        pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
438                    } else {
439                        pSignalUnitRack->EnterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
440                    }
441                  itKillEvent = Pool<Event>::Iterator();                  itKillEvent = Pool<Event>::Iterator();
442              } else {              } else {
443                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);
# Line 362  namespace LinuxSampler { Line 452  namespace LinuxSampler {
452              fFinalCutoff    = VCFCutoffCtrl.fvalue;              fFinalCutoff    = VCFCutoffCtrl.fvalue;
453              fFinalResonance = VCFResonanceCtrl.fvalue;              fFinalResonance = VCFResonanceCtrl.fvalue;
454    
455              // process MIDI control change and pitchbend events for this subfragment              // process MIDI control change, aftertouch and pitchbend events for this subfragment
456              processCCEvents(itCCEvent, iSubFragmentEnd);              processCCEvents(itCCEvent, iSubFragmentEnd);
457                uint8_t pan = MIDIPan;
458                if (pSignalUnitRack != NULL) pan = pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan);
459    
460                PanLeftSmoother.update(AbstractEngine::PanCurve[128 - pan] * NotePanLeft);
461                PanRightSmoother.update(AbstractEngine::PanCurve[pan]      * NotePanRight);
462    
463              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend;              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend * NotePitch.render();
464              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();  
465                float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render() * NoteVolume.render();
466  #ifdef CONFIG_PROCESS_MUTED_CHANNELS  #ifdef CONFIG_PROCESS_MUTED_CHANNELS
467              if (pChannel->GetMute()) fFinalVolume = 0;              if (pChannel->GetMute()) fFinalVolume = 0;
468  #endif  #endif
469    
470              // process transition events (note on, note off & sustain pedal)              // process transition events (note on, note off & sustain pedal)
471              processTransitionEvents(itNoteEvent, iSubFragmentEnd);              processTransitionEvents(itNoteEvent, iSubFragmentEnd);
472                processGroupEvents(itGroupEvent, iSubFragmentEnd);
473                
474                if (pSignalUnitRack == NULL) {
475                    // if the voice was killed in this subfragment, or if the
476                    // filter EG is finished, switch EG1 to fade out stage
477                    if ((itKillEvent && killPos <= iSubFragmentEnd) ||
478                        (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
479                        pEG2->getSegmentType() == EG::segment_end)) {
480                        pEG1->enterFadeOutStage();
481                        itKillEvent = Pool<Event>::Iterator();
482                    }
483    
484              // if the voice was killed in this subfragment, or if the                  // process envelope generators
485              // filter EG is finished, switch EG1 to fade out stage                  switch (pEG1->getSegmentType()) {
486              if ((itKillEvent && killPos <= iSubFragmentEnd) ||                      case EG::segment_lin:
487                  (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&                          fFinalVolume *= pEG1->processLin();
488                   EG2.getSegmentType() == gig::EGADSR::segment_end)) {                          break;
489                  EG1.enterFadeOutStage();                      case EG::segment_exp:
490                  itKillEvent = Pool<Event>::Iterator();                          fFinalVolume *= pEG1->processExp();
491                            break;
492                        case EG::segment_end:
493                            fFinalVolume *= pEG1->getLevel();
494                            break; // noop
495                        case EG::segment_pow:
496                            fFinalVolume *= pEG1->processPow();
497                            break;
498                    }
499                    switch (pEG2->getSegmentType()) {
500                        case EG::segment_lin:
501                            fFinalCutoff *= pEG2->processLin();
502                            break;
503                        case EG::segment_exp:
504                            fFinalCutoff *= pEG2->processExp();
505                            break;
506                        case EG::segment_end:
507                            fFinalCutoff *= pEG2->getLevel();
508                            break; // noop
509                        case EG::segment_pow:
510                            fFinalCutoff *= pEG2->processPow();
511                            break;
512                    }
513                    if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();
514    
515                    // process low frequency oscillators
516                    if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());
517                    if (bLFO2Enabled) fFinalCutoff *= (1.0f - pLFO2->render());
518                    if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
519                } else {
520                    // if the voice was killed in this subfragment, enter fade out stage
521                    if (itKillEvent && killPos <= iSubFragmentEnd) {
522                        pSignalUnitRack->EnterFadeOutStage();
523                        itKillEvent = Pool<Event>::Iterator();
524                    }
525                    
526                    // if the filter EG is finished, switch EG1 to fade out stage
527                    /*if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
528                        pEG2->getSegmentType() == EG::segment_end) {
529                        pEG1->enterFadeOutStage();
530                        itKillEvent = Pool<Event>::Iterator();
531                    }*/
532                    // TODO: ^^^
533    
534                    fFinalVolume   *= pSignalUnitRack->GetEndpointUnit()->GetVolume();
535                    fFinalCutoff    = pSignalUnitRack->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff);
536                    fFinalResonance = pSignalUnitRack->GetEndpointUnit()->CalculateResonance(fFinalResonance);
537                    
538                    finalSynthesisParameters.fFinalPitch =
539                        pSignalUnitRack->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);
540                        
541              }              }
542    
543              // process envelope generators              fFinalCutoff    *= NoteCutoff;
544              switch (EG1.getSegmentType()) {              fFinalResonance *= NoteResonance;
                 case gig::EGADSR::segment_lin:  
                     fFinalVolume *= EG1.processLin();  
                     break;  
                 case gig::EGADSR::segment_exp:  
                     fFinalVolume *= EG1.processExp();  
                     break;  
                 case gig::EGADSR::segment_end:  
                     fFinalVolume *= EG1.getLevel();  
                     break; // noop  
             }  
             switch (EG2.getSegmentType()) {  
                 case gig::EGADSR::segment_lin:  
                     fFinalCutoff *= EG2.processLin();  
                     break;  
                 case gig::EGADSR::segment_exp:  
                     fFinalCutoff *= EG2.processExp();  
                     break;  
                 case gig::EGADSR::segment_end:  
                     fFinalCutoff *= EG2.getLevel();  
                     break; // noop  
             }  
             if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();  
   
             // process low frequency oscillators  
             if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());  
             if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();  
             if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());  
545    
546              // limit the pitch so we don't read outside the buffer              // limit the pitch so we don't read outside the buffer
547              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));
# Line 445  namespace LinuxSampler { Line 575  namespace LinuxSampler {
575                  fFinalVolume * VolumeRight * PanRightSmoother.render();                  fFinalVolume * VolumeRight * PanRightSmoother.render();
576  #endif  #endif
577              // render audio for one subfragment              // render audio for one subfragment
578              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);              if (!delay) RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
579    
580              // stop the rendering if volume EG is finished              if (pSignalUnitRack == NULL) {
581              if (EG1.getSegmentType() == gig::EGADSR::segment_end) break;                  // stop the rendering if volume EG is finished
582                    if (pEG1->getSegmentType() == EG::segment_end) break;
583                } else {
584                    // stop the rendering if the endpoint unit is not active
585                    if (!pSignalUnitRack->GetEndpointUnit()->Active()) break;
586                }
587    
588              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
589    
590              // increment envelopes' positions              if (pSignalUnitRack == NULL) {
591              if (EG1.active()) {                  // increment envelopes' positions
592                    if (pEG1->active()) {
593    
594                        // 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
595                        if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
596                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
597                        }
598    
599                  // 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                      pEG1->increment(1);
600                  if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {                      if (!pEG1->toStageEndLeft()) pEG1->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
                     EG1.update(gig::EGADSR::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);  
601                  }                  }
602                    if (pEG2->active()) {
603                  EG1.increment(1);                      pEG2->increment(1);
604                  if (!EG1.toStageEndLeft()) EG1.update(gig::EGADSR::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                      if (!pEG2->toStageEndLeft()) pEG2->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
605              }                  }
606              if (EG2.active()) {                  EG3.increment(1);
607                  EG2.increment(1);                  if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
608                  if (!EG2.toStageEndLeft()) EG2.update(gig::EGADSR::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              } else {
609                        // 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
610                        /*if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
611                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
612                        }*/
613                    // TODO: ^^^
614                    
615                    if (!delay) pSignalUnitRack->Increment();
616              }              }
             EG3.increment(1);  
             if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached  
617    
618              Pos = newPos;              Pos = newPos;
619              i = iSubFragmentEnd;              i = iSubFragmentEnd;
620          }          }
621            
622            if (delay) return;
623    
624            if (bVoiceRequiresDedicatedRouting) {
625                if (bEq) {
626                    pEq->RenderAudio(Samples);
627                    pEq->GetOutChannelLeft()->CopyTo(GetEngine()->pDedicatedVoiceChannelLeft, Samples);
628                    pEq->GetOutChannelRight()->CopyTo(GetEngine()->pDedicatedVoiceChannelRight, Samples);
629                }
630                optional<float> effectSendLevels[2] = {
631                    pMidiKeyInfo->ReverbSend,
632                    pMidiKeyInfo->ChorusSend
633                };
634                GetEngine()->RouteDedicatedVoiceChannels(pEngineChannel, effectSendLevels, Samples);
635            } else if (bEq) {
636                pEq->RenderAudio(Samples);
637                pEq->GetOutChannelLeft()->MixTo(pChannel->pChannelLeft, Samples);
638                pEq->GetOutChannelRight()->MixTo(pChannel->pChannelRight, Samples);
639            }
640      }      }
641        
642      /**      /**
643       * Process given list of MIDI control change and pitch bend events for       * Process given list of MIDI control change, aftertouch and pitch bend
644       * the given time.       * events for the given time.
645       *       *
646       * @param itEvent - iterator pointing to the next event to be processed       * @param itEvent - iterator pointing to the next event to be processed
647       * @param End     - youngest time stamp where processing should be stopped       * @param End     - youngest time stamp where processing should be stopped
648       */       */
649      void AbstractVoice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) {      void AbstractVoice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) {
650          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
651              if (itEvent->Type == Event::type_control_change && itEvent->Param.CC.Controller) { // if (valid) MIDI control change event              if ((itEvent->Type == Event::type_control_change || itEvent->Type == Event::type_channel_pressure)
652                    && itEvent->Param.CC.Controller) // if (valid) MIDI control change event
653                {
654                  if (itEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {                  if (itEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {
655                      ProcessCutoffEvent(itEvent);                      ProcessCutoffEvent(itEvent);
656                  }                  }
657                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
658                      processResonanceEvent(itEvent);                      processResonanceEvent(itEvent);
659                  }                  }
660                  if (itEvent->Param.CC.Controller == pLFO1->ExtController) {                  if (itEvent->Param.CC.Controller == CTRL_TABLE_IDX_AFTERTOUCH ||
661                      pLFO1->update(itEvent->Param.CC.Value);                      itEvent->Type == Event::type_channel_pressure)
662                  }                  {
663                  if (itEvent->Param.CC.Controller == pLFO2->ExtController) {                      ProcessChannelPressureEvent(itEvent);
                     pLFO2->update(itEvent->Param.CC.Value);  
664                  }                  }
665                  if (itEvent->Param.CC.Controller == pLFO3->ExtController) {                  if (pSignalUnitRack == NULL) {
666                      pLFO3->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
667                            pLFO1->updateByMIDICtrlValue(itEvent->Param.CC.Value);
668                        }
669                        if (itEvent->Param.CC.Controller == pLFO2->ExtController) {
670                            pLFO2->updateByMIDICtrlValue(itEvent->Param.CC.Value);
671                        }
672                        if (itEvent->Param.CC.Controller == pLFO3->ExtController) {
673                            pLFO3->updateByMIDICtrlValue(itEvent->Param.CC.Value);
674                        }
675                  }                  }
676                  if (itEvent->Param.CC.Controller == 7) { // volume                  if (itEvent->Param.CC.Controller == 7) { // volume
677                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);
678                  } else if (itEvent->Param.CC.Controller == 10) { // panpot                  } else if (itEvent->Param.CC.Controller == 10) { // panpot
679                      PanLeftSmoother.update(AbstractEngine::PanCurve[128 - itEvent->Param.CC.Value]);                      MIDIPan = CalculatePan(itEvent->Param.CC.Value);
                     PanRightSmoother.update(AbstractEngine::PanCurve[itEvent->Param.CC.Value]);  
680                  }                  }
681              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event
682                  processPitchEvent(itEvent);                  processPitchEvent(itEvent);
683                } else if (itEvent->Type == Event::type_note_pressure) {
684                    ProcessPolyphonicKeyPressureEvent(itEvent);
685              }              }
686    
687              ProcessCCEvent(itEvent);              ProcessCCEvent(itEvent);
688                if (pSignalUnitRack != NULL) {
689                    pSignalUnitRack->ProcessCCEvent(itEvent);
690                }
691          }          }
692      }      }
693    
# Line 529  namespace LinuxSampler { Line 706  namespace LinuxSampler {
706      }      }
707    
708      /**      /**
709       * Process given list of MIDI note on, note off and sustain pedal events       * Process given list of MIDI note on, note off, sustain pedal events and
710       * for the given time.       * note synthesis parameter events for the given time.
711       *       *
712       * @param itEvent - iterator pointing to the next event to be processed       * @param itEvent - iterator pointing to the next event to be processed
713       * @param End     - youngest time stamp where processing should be stopped       * @param End     - youngest time stamp where processing should be stopped
714       */       */
715      void AbstractVoice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {      void AbstractVoice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {
716          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
717              if (itEvent->Type == Event::type_release) {              // some voice types ignore note off
718                  EG1.update(gig::EGADSR::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              if (!(Type & (Voice::type_one_shot | Voice::type_release_trigger | Voice::type_controller_triggered))) {
719                  EG2.update(gig::EGADSR::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (itEvent->Type == Event::type_release_key) {
720              } else if (itEvent->Type == Event::type_cancel_release) {                      EnterReleaseStage();
721                  EG1.update(gig::EGADSR::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  } else if (itEvent->Type == Event::type_cancel_release_key) {
722                  EG2.update(gig::EGADSR::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                      if (pSignalUnitRack == NULL) {
723                            pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
724                            pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
725                        } else {
726                            pSignalUnitRack->CancelRelease();
727                        }
728                    }
729                }
730                // process stop-note events (caused by built-in instrument script function note_off())
731                if (itEvent->Type == Event::type_release_note && pNote &&
732                    pEngineChannel->pEngine->NoteByID( itEvent->Param.Note.ID ) == pNote)
733                {
734                    EnterReleaseStage();
735                }
736                // process kill-note events (caused by built-in instrument script function fade_out())
737                if (itEvent->Type == Event::type_kill_note && pNote &&
738                    pEngineChannel->pEngine->NoteByID( itEvent->Param.Note.ID ) == pNote)
739                {
740                    Kill(itEvent);
741                }
742                // process synthesis parameter events (caused by built-in realt-time instrument script functions)
743                if (itEvent->Type == Event::type_note_synth_param && pNote &&
744                    pEngineChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID ) == pNote)
745                {
746                    switch (itEvent->Param.NoteSynthParam.Type) {
747                        case Event::synth_param_volume:
748                            NoteVolume.fadeTo(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
749                            break;
750                        case Event::synth_param_volume_time:
751                            NoteVolume.setDefaultDuration(itEvent->Param.NoteSynthParam.AbsValue);
752                            break;
753                        case Event::synth_param_volume_curve:
754                            NoteVolume.setCurve((fade_curve_t)itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
755                            break;
756                        case Event::synth_param_pitch:
757                            NotePitch.fadeTo(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
758                            break;
759                        case Event::synth_param_pitch_time:
760                            NotePitch.setDefaultDuration(itEvent->Param.NoteSynthParam.AbsValue);
761                            break;
762                        case Event::synth_param_pitch_curve:
763                            NotePitch.setCurve((fade_curve_t)itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
764                            break;
765                        case Event::synth_param_pan:
766                            NotePanLeft  = AbstractEngine::PanCurveValueNorm(itEvent->Param.NoteSynthParam.AbsValue, 0 /*left*/);
767                            NotePanRight = AbstractEngine::PanCurveValueNorm(itEvent->Param.NoteSynthParam.AbsValue, 1 /*right*/);
768                            break;
769                        case Event::synth_param_cutoff:
770                            NoteCutoff = itEvent->Param.NoteSynthParam.AbsValue;
771                            break;
772                        case Event::synth_param_resonance:
773                            NoteResonance = itEvent->Param.NoteSynthParam.AbsValue;
774                            break;
775                        case Event::synth_param_amp_lfo_depth:
776                            pLFO1->setScriptDepthFactor(itEvent->Param.NoteSynthParam.AbsValue);
777                            break;
778                        case Event::synth_param_amp_lfo_freq:
779                            pLFO1->setScriptFrequencyFactor(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
780                            break;
781                        case Event::synth_param_pitch_lfo_depth:
782                            pLFO3->setScriptDepthFactor(itEvent->Param.NoteSynthParam.AbsValue);
783                            break;
784                        case Event::synth_param_pitch_lfo_freq:
785                            pLFO3->setScriptFrequencyFactor(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
786                            break;
787    
788                        case Event::synth_param_attack:
789                        case Event::synth_param_decay:
790                        case Event::synth_param_release:
791                            break; // noop
792                    }
793              }              }
794          }          }
795      }      }
796    
797        /**
798         * Process given list of events aimed at all voices in a key group.
799         *
800         * @param itEvent - iterator pointing to the next event to be processed
801         * @param End     - youngest time stamp where processing should be stopped
802         */
803        void AbstractVoice::processGroupEvents(RTList<Event>::Iterator& itEvent, uint End) {
804            for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
805                ProcessGroupEvent(itEvent);
806            }
807        }
808    
809      /** @brief Update current portamento position.      /** @brief Update current portamento position.
810       *       *
811       * Will be called when portamento mode is enabled to get the final       * Will be called when portamento mode is enabled to get the final
# Line 556  namespace LinuxSampler { Line 815  namespace LinuxSampler {
815       * @param itNoteOffEvent - event which causes this voice to die soon       * @param itNoteOffEvent - event which causes this voice to die soon
816       */       */
817      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
818          const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());          if (pSignalUnitRack == NULL) {
819          pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;              const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
820                pEngineChannel->PortamentoPos = (float) MIDIKey() + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
821            } else {
822                // TODO:
823            }
824      }      }
825    
826      /**      /**
# Line 581  namespace LinuxSampler { Line 844  namespace LinuxSampler {
844    
845      Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {      Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {
846          PitchInfo pitch;          PitchInfo pitch;
847          double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey % 12];          double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
848    
849          // GSt behaviour: maximum transpose up is 40 semitones. If          // GSt behaviour: maximum transpose up is 40 semitones. If
850          // MIDI key is more than 40 semitones above unity note,          // MIDI key is more than 40 semitones above unity note,
851          // the transpose is not done.          // the transpose is not done.
852          if (!SmplInfo.Unpitched && (MIDIKey - (int) RgnInfo.UnityNote) < 40) pitchbasecents += (MIDIKey - (int) RgnInfo.UnityNote) * 100;          if (!SmplInfo.Unpitched && (MIDIKey() - (int) RgnInfo.UnityNote) < 40) pitchbasecents += (MIDIKey() - (int) RgnInfo.UnityNote) * 100;
853    
854          pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));          pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
855          pitch.PitchBendRange = 1.0 / 8192.0 * 100.0 * InstrInfo.PitchbendRange;          pitch.PitchBendRange = 1.0 / 8192.0 * 100.0 * InstrInfo.PitchbendRange;
# Line 594  namespace LinuxSampler { Line 857  namespace LinuxSampler {
857    
858          return pitch;          return pitch;
859      }      }
860        
861        void AbstractVoice::onScaleTuningChanged() {
862            PitchInfo pitch = this->Pitch;
863            double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
864            
865            // GSt behaviour: maximum transpose up is 40 semitones. If
866            // MIDI key is more than 40 semitones above unity note,
867            // the transpose is not done.
868            if (!SmplInfo.Unpitched && (MIDIKey() - (int) RgnInfo.UnityNote) < 40) pitchbasecents += (MIDIKey() - (int) RgnInfo.UnityNote) * 100;
869            
870            pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
871            this->Pitch = pitch;
872        }
873    
874      double AbstractVoice::CalculateVolume(double velocityAttenuation) {      double AbstractVoice::CalculateVolume(double velocityAttenuation) {
875          // For 16 bit samples, we downscale by 32768 to convert from          // For 16 bit samples, we downscale by 32768 to convert from
# Line 604  namespace LinuxSampler { Line 880  namespace LinuxSampler {
880          volume *= GetSampleAttenuation() * pEngineChannel->GlobalVolume * GLOBAL_VOLUME;          volume *= GetSampleAttenuation() * pEngineChannel->GlobalVolume * GLOBAL_VOLUME;
881    
882          // the volume of release triggered samples depends on note length          // the volume of release triggered samples depends on note length
883          if (Type == Voice::type_release_trigger) {          if (Type & Voice::type_release_trigger) {
884              float noteLength = float(GetEngine()->FrameTime + Delay -              float noteLength = float(GetEngine()->FrameTime + Delay -
885                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;                  GetNoteOnTime(MIDIKey()) ) / GetEngine()->SampleRate;
886    
887              float attenuation = 1 - 0.01053 * (256 >> RgnInfo.ReleaseTriggerDecay) * noteLength;              volume *= GetReleaseTriggerAttenuation(noteLength);
             volume *= attenuation;  
888          }          }
889    
890          return volume;          return volume;
891      }      }
892    
893        float AbstractVoice::GetReleaseTriggerAttenuation(float noteLength) {
894            return 1 - RgnInfo.ReleaseTriggerDecay * noteLength;
895        }
896    
897        void AbstractVoice::EnterReleaseStage() {
898            if (pSignalUnitRack == NULL) {
899                pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
900                pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
901            } else {
902                pSignalUnitRack->EnterReleaseStage();
903            }
904        }
905    
906        bool AbstractVoice::EG1Finished() {
907            if (pSignalUnitRack == NULL) {
908                return pEG1->getSegmentType() == EG::segment_end;
909            } else {
910                return !pSignalUnitRack->GetEndpointUnit()->Active();
911            }
912        }
913    
914  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.2032  
changed lines
  Added in v.3246

  ViewVC Help
Powered by ViewVC