/[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 2115 by persson, Thu Aug 12 15:36:15 2010 UTC revision 2953 by schoenebeck, Sat Jul 16 11:24:39 2016 UTC
# Line 4  Line 4 
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-2008 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2010 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2015 Christian Schoenebeck and Grigor Iliev        *
8   *                                                                         *   *                                                                         *
9   *   This program is free software; you can redistribute it and/or modify  *   *   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  *   *   it under the terms of the GNU General Public License as published by  *
# Line 26  Line 26 
26    
27  namespace LinuxSampler {  namespace LinuxSampler {
28    
29      AbstractVoice::AbstractVoice() {      AbstractVoice::AbstractVoice(SignalUnitRack* pRack): pSignalUnitRack(pRack) {
30          pEngineChannel = NULL;          pEngineChannel = NULL;
31          pLFO1 = new LFOUnsigned(1.0f);  // amplitude EG (0..1 range)          pLFO1 = new LFOUnsigned(1.0f);  // amplitude LFO (0..1 range)
32          pLFO2 = new LFOUnsigned(1.0f);  // filter EG (0..1 range)          pLFO2 = new LFOUnsigned(1.0f);  // filter LFO (0..1 range)
33          pLFO3 = new LFOSigned(1200.0f); // pitch EG (-1200..+1200 range)          pLFO3 = new LFOSigned(1200.0f); // pitch LFO (-1200..+1200 range)
34          PlaybackState = playback_state_end;          PlaybackState = playback_state_end;
35          SynthesisMode = 0; // set all mode bits to 0 first          SynthesisMode = 0; // set all mode bits to 0 first
36          // select synthesis implementation (asm core is not supported ATM)          // select synthesis implementation (asm core is not supported ATM)
# Line 43  namespace LinuxSampler { Line 43  namespace LinuxSampler {
43    
44          finalSynthesisParameters.filterLeft.Reset();          finalSynthesisParameters.filterLeft.Reset();
45          finalSynthesisParameters.filterRight.Reset();          finalSynthesisParameters.filterRight.Reset();
46            
47            pEq          = NULL;
48            bEqSupport   = false;
49      }      }
50    
51      AbstractVoice::~AbstractVoice() {      AbstractVoice::~AbstractVoice() {
52          if (pLFO1) delete pLFO1;          if (pLFO1) delete pLFO1;
53          if (pLFO2) delete pLFO2;          if (pLFO2) delete pLFO2;
54          if (pLFO3) delete pLFO3;          if (pLFO3) delete pLFO3;
55            
56            if(pEq != NULL) delete pEq;
57        }
58                
59        void AbstractVoice::CreateEq() {
60            if(!bEqSupport) return;
61            if(pEq != NULL) delete pEq;
62            pEq = new EqSupport;
63            pEq->InitEffect(GetEngine()->pAudioOutputDevice);
64      }      }
65    
66      /**      /**
# Line 98  namespace LinuxSampler { Line 110  namespace LinuxSampler {
110          #endif // CONFIG_DEVMODE          #endif // CONFIG_DEVMODE
111    
112          Type            = VoiceType;          Type            = VoiceType;
113          MIDIKey         = itNoteOnEvent->Param.Note.Key;          pNote           = pEngineChannel->pEngine->NoteByID( itNoteOnEvent->Param.Note.ID );
114          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
115          Delay           = itNoteOnEvent->FragmentPos();          Delay           = itNoteOnEvent->FragmentPos();
116          itTriggerEvent  = itNoteOnEvent;          itTriggerEvent  = itNoteOnEvent;
117          itKillEvent     = Pool<Event>::Iterator();          itKillEvent     = Pool<Event>::Iterator();
118            MidiKeyBase* pKeyInfo = GetMidiKeyInfo(MIDIKey());
119    
120          pGroupEvents = iKeyGroup ? pEngineChannel->ActiveKeyGroups[iKeyGroup] : 0;          pGroupEvents = iKeyGroup ? pEngineChannel->ActiveKeyGroups[iKeyGroup] : 0;
121    
122          SmplInfo   = GetSampleInfo();          SmplInfo   = GetSampleInfo();
123          RgnInfo    = GetRegionInfo();          RgnInfo    = GetRegionInfo();
124          InstrInfo  = GetInstrumentInfo();          InstrInfo  = GetInstrumentInfo();
125            
126            MIDIPan    = CalculatePan(pEngineChannel->iLastPanRequest);
127    
128            AboutToTrigger();
129    
130          // calculate volume          // calculate volume
131          const double velocityAttenuation = GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity);          const double velocityAttenuation = GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity);
132          float volume = CalculateVolume(velocityAttenuation);          float volume = CalculateVolume(velocityAttenuation) * pKeyInfo->Volume;
133          if (volume <= 0) return -1;          if (volume <= 0) return -1;
134    
135          // select channel mode (mono or stereo)          // select channel mode (mono or stereo)
# Line 123  namespace LinuxSampler { Line 140  namespace LinuxSampler {
140          // get starting crossfade volume level          // get starting crossfade volume level
141          float crossfadeVolume = CalculateCrossfadeVolume(itNoteOnEvent->Param.Note.Velocity);          float crossfadeVolume = CalculateCrossfadeVolume(itNoteOnEvent->Param.Note.Velocity);
142    
143          VolumeLeft  = volume * AbstractEngine::PanCurve[64 - RgnInfo.Pan];          VolumeLeft  = volume * pKeyInfo->PanLeft;
144          VolumeRight = volume * AbstractEngine::PanCurve[64 + RgnInfo.Pan];          VolumeRight = volume * pKeyInfo->PanRight;
145    
146          float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;          float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;
147          CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);          CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);
148          VolumeSmoother.trigger(pEngineChannel->MidiVolume, subfragmentRate);          VolumeSmoother.trigger(pEngineChannel->MidiVolume, subfragmentRate);
149          PanLeftSmoother.trigger(pEngineChannel->GlobalPanLeft, subfragmentRate);          NoteVolumeSmoother.trigger(pNote ? pNote->Override.Volume : 1.f, subfragmentRate);
         PanRightSmoother.trigger(pEngineChannel->GlobalPanRight, subfragmentRate);  
   
         finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)  
         Pos = RgnInfo.SampleStartOffset;  
150    
151          // 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
152          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;
153          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;
154    
155            SetSampleStartOffset();
156    
157          if (DiskVoice) { // voice to be streamed from disk          if (DiskVoice) { // voice to be streamed from disk
158              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {
159                  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 170  namespace LinuxSampler {
170              RAMLoop = (SmplInfo.HasLoops && (SmplInfo.LoopStart + SmplInfo.LoopLength) <= MaxRAMPos);              RAMLoop = (SmplInfo.HasLoops && (SmplInfo.LoopStart + SmplInfo.LoopLength) <= MaxRAMPos);
171    
172              if (OrderNewStream()) return -1;              if (OrderNewStream()) return -1;
173              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"));
174          }          }
175          else { // RAM only voice          else { // RAM only voice
176              MaxRAMPos = cachedsamples;              MaxRAMPos = cachedsamples;
# Line 171  namespace LinuxSampler { Line 186  namespace LinuxSampler {
186          }          }
187    
188          Pitch = CalculatePitchInfo(PitchBend);          Pitch = CalculatePitchInfo(PitchBend);
189            NotePitch = (pNote) ? pNote->Override.Pitch : 1.0f;
190            NoteCutoff = (pNote) ? pNote->Override.Cutoff : 1.0f;
191            NoteResonance = (pNote) ? pNote->Override.Resonance : 1.0f;
192    
193          // 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
194          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);
195    
196          // setup EG 1 (VCA EG)          if (pSignalUnitRack == NULL) { // setup EG 1 (VCA EG)
         {  
197              // get current value of EG1 controller              // get current value of EG1 controller
198              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);
199    
200              // calculate influence of EG1 controller on EG1's parameters              // calculate influence of EG1 controller on EG1's parameters
201              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);
202    
203                if (pNote) {
204                    egInfo.Attack  *= pNote->Override.Attack;
205                    egInfo.Decay   *= pNote->Override.Decay;
206                    egInfo.Release *= pNote->Override.Release;
207                }
208    
209              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
210            } else {
211                pSignalUnitRack->Trigger();
212          }          }
213    
214            const uint8_t pan = (pSignalUnitRack) ? pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan) : MIDIPan;
215            NotePanLeft  = (pNote) ? AbstractEngine::PanCurveValueNorm(pNote->Override.Pan, 0 /*left*/ ) : 1.f;
216            NotePanRight = (pNote) ? AbstractEngine::PanCurveValueNorm(pNote->Override.Pan, 1 /*right*/) : 1.f;
217            PanLeftSmoother.trigger(
218                AbstractEngine::PanCurve[128 - pan] * NotePanLeft,
219                subfragmentRate
220            );
221            PanRightSmoother.trigger(
222                AbstractEngine::PanCurve[pan] * NotePanRight,
223                subfragmentRate
224            );
225    
226  #ifdef CONFIG_INTERPOLATE_VOLUME  #ifdef CONFIG_INTERPOLATE_VOLUME
227          // setup initial volume in synthesis parameters          // setup initial volume in synthesis parameters
228      #ifdef CONFIG_PROCESS_MUTED_CHANNELS      #ifdef CONFIG_PROCESS_MUTED_CHANNELS
# Line 196  namespace LinuxSampler { Line 233  namespace LinuxSampler {
233          else          else
234      #else      #else
235          {          {
236              float finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();              float finalVolume;
237                if (pSignalUnitRack == NULL) {
238                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();
239                } else {
240                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pSignalUnitRack->GetEndpointUnit()->GetVolume();
241                }
242    
243              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * pEngineChannel->GlobalPanLeft;              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * PanLeftSmoother.render();
244              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight;              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * PanRightSmoother.render();
245          }          }
246      #endif      #endif
247  #endif  #endif
248    
249          // setup EG 2 (VCF Cutoff EG)          if (pSignalUnitRack == NULL) {
250          {              // setup EG 2 (VCF Cutoff EG)
251              // get current value of EG2 controller              {
252              double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);                  // get current value of EG2 controller
253                    double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);
254    
255                    // calculate influence of EG2 controller on EG2's parameters
256                    EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);
257    
258                    TriggerEG2(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
259                }
260    
             // calculate influence of EG2 controller on EG2's parameters  
             EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);  
261    
262              EG2.trigger (              // setup EG 3 (VCO EG)
263                  uint(RgnInfo.EG2PreAttack),              {
264                  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
265                  false,                  bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;
266                  RgnInfo.EG2Decay1 * egInfo.Decay * velrelease,                  float eg3depth = (bPortamento)
267                  RgnInfo.EG2Decay2 * egInfo.Decay * velrelease,                               ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey()) * 100)
268                  RgnInfo.EG2InfiniteSustain,                               : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);
269                  uint(RgnInfo.EG2Sustain),                  float eg3time = (bPortamento)
270                  RgnInfo.EG2Release * egInfo.Release * velrelease,                              ? pEngineChannel->PortamentoTime
271                  velocityAttenuation,                              : RgnInfo.EG3Attack;
272                  GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE                  EG3.trigger(eg3depth, eg3time, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
273              );                  dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time));
274          }              }
275    
276    
277          // setup EG 3 (VCO EG)              // setup LFO 1 (VCA LFO)
278          {              InitLFO1();
279              // 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)
280              bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;              InitLFO2();
281              float eg3depth = (bPortamento)              // setup LFO 3 (VCO LFO)
282                           ? 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));  
283          }          }
284    
285    
         // setup LFO 1 (VCA LFO)  
         InitLFO1();  
         // setup LFO 2 (VCF Cutoff LFO)  
         InitLFO2();  
         // setup LFO 3 (VCO LFO)  
         InitLFO3();  
   
   
286          #if CONFIG_FORCE_FILTER          #if CONFIG_FORCE_FILTER
287          const bool bUseFilter = true;          const bool bUseFilter = true;
288          #else // use filter only if instrument file told so          #else // use filter only if instrument file told so
# Line 292  namespace LinuxSampler { Line 325  namespace LinuxSampler {
325              VCFCutoffCtrl.controller    = 0;              VCFCutoffCtrl.controller    = 0;
326              VCFResonanceCtrl.controller = 0;              VCFResonanceCtrl.controller = 0;
327          }          }
328            
329            const bool bEq =
330                pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && pEq->HasSupport();
331    
332            if (bEq) {
333                pEq->GetInChannelLeft()->Clear();
334                pEq->GetInChannelRight()->Clear();
335                pEq->RenderAudio(GetEngine()->pAudioOutputDevice->MaxSamplesPerCycle());
336            }
337    
338          return 0; // success          return 0; // success
339      }      }
340        
341        void AbstractVoice::SetSampleStartOffset() {
342            finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
343            Pos = RgnInfo.SampleStartOffset;
344        }
345    
346      /**      /**
347       *  Synthesizes the current audio fragment for this voice.       *  Synthesizes the current audio fragment for this voice.
# Line 305  namespace LinuxSampler { Line 352  namespace LinuxSampler {
352       *  @param Skip    - number of sample points to skip in output buffer       *  @param Skip    - number of sample points to skip in output buffer
353       */       */
354      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
355            bool delay = false; // Whether the voice playback should be delayed for this call
356            
357            if (pSignalUnitRack != NULL) {
358                uint delaySteps = pSignalUnitRack->GetEndpointUnit()->DelayTrigger();
359                if (delaySteps > 0) { // delay on the endpoint unit means delay of the voice playback
360                    if (delaySteps >= Samples) {
361                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(Samples);
362                        delay = true;
363                    } else {
364                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(delaySteps);
365                        Samples -= delaySteps;
366                        Skip += delaySteps;
367                    }
368                }
369            }
370            
371          AbstractEngineChannel* pChannel = pEngineChannel;          AbstractEngineChannel* pChannel = pEngineChannel;
372          finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];          MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey());
373          finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];  
374          finalSynthesisParameters.pSrc      = pSrc;          const bool bVoiceRequiresDedicatedRouting =
375                pEngineChannel->GetFxSendCount() > 0 &&
376                (pMidiKeyInfo->ReverbSend || pMidiKeyInfo->ChorusSend);
377            
378            const bool bEq =
379                pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && pEq->HasSupport();
380    
381            if (bEq) {
382                pEq->GetInChannelLeft()->Clear();
383                pEq->GetInChannelRight()->Clear();
384                finalSynthesisParameters.pOutLeft  = &pEq->GetInChannelLeft()->Buffer()[Skip];
385                finalSynthesisParameters.pOutRight = &pEq->GetInChannelRight()->Buffer()[Skip];
386                pSignalUnitRack->UpdateEqSettings(pEq);
387            } else if (bVoiceRequiresDedicatedRouting) {
388                finalSynthesisParameters.pOutLeft  = &GetEngine()->pDedicatedVoiceChannelLeft->Buffer()[Skip];
389                finalSynthesisParameters.pOutRight = &GetEngine()->pDedicatedVoiceChannelRight->Buffer()[Skip];
390            } else {
391                finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];
392                finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];
393            }
394            finalSynthesisParameters.pSrc = pSrc;
395    
396          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();
397          RTList<Event>::Iterator itNoteEvent;          RTList<Event>::Iterator itNoteEvent;
398          GetFirstEventOnKey(MIDIKey, itNoteEvent);          GetFirstEventOnKey(HostKey(), itNoteEvent);
399    
400          RTList<Event>::Iterator itGroupEvent;          RTList<Event>::Iterator itGroupEvent;
401          if (pGroupEvents) itGroupEvent = pGroupEvents->first();          if (pGroupEvents && !Orphan) itGroupEvent = pGroupEvents->first();
402    
403          if (itTriggerEvent) { // skip events that happened before this voice was triggered          if (itTriggerEvent) { // skip events that happened before this voice was triggered
404              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;
# Line 341  namespace LinuxSampler { Line 424  namespace LinuxSampler {
424                  // drivers that use Samples < MaxSamplesPerCycle).                  // drivers that use Samples < MaxSamplesPerCycle).
425                  // End the EG1 here, at pos 0, with a shorter max fade                  // End the EG1 here, at pos 0, with a shorter max fade
426                  // out time.                  // out time.
427                  pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (pSignalUnitRack == NULL) {
428                        pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
429                    } else {
430                        pSignalUnitRack->EnterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
431                    }
432                  itKillEvent = Pool<Event>::Iterator();                  itKillEvent = Pool<Event>::Iterator();
433              } else {              } else {
434                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);
# Line 356  namespace LinuxSampler { Line 443  namespace LinuxSampler {
443              fFinalCutoff    = VCFCutoffCtrl.fvalue;              fFinalCutoff    = VCFCutoffCtrl.fvalue;
444              fFinalResonance = VCFResonanceCtrl.fvalue;              fFinalResonance = VCFResonanceCtrl.fvalue;
445    
446              // process MIDI control change and pitchbend events for this subfragment              // process MIDI control change, aftertouch and pitchbend events for this subfragment
447              processCCEvents(itCCEvent, iSubFragmentEnd);              processCCEvents(itCCEvent, iSubFragmentEnd);
448                uint8_t pan = MIDIPan;
449                if (pSignalUnitRack != NULL) pan = pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan);
450    
451                PanLeftSmoother.update(AbstractEngine::PanCurve[128 - pan] * NotePanLeft);
452                PanRightSmoother.update(AbstractEngine::PanCurve[pan]      * NotePanRight);
453    
454              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend;              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend * NotePitch;
455              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();  
456                float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render() * NoteVolumeSmoother.render();
457  #ifdef CONFIG_PROCESS_MUTED_CHANNELS  #ifdef CONFIG_PROCESS_MUTED_CHANNELS
458              if (pChannel->GetMute()) fFinalVolume = 0;              if (pChannel->GetMute()) fFinalVolume = 0;
459  #endif  #endif
# Line 368  namespace LinuxSampler { Line 461  namespace LinuxSampler {
461              // process transition events (note on, note off & sustain pedal)              // process transition events (note on, note off & sustain pedal)
462              processTransitionEvents(itNoteEvent, iSubFragmentEnd);              processTransitionEvents(itNoteEvent, iSubFragmentEnd);
463              processGroupEvents(itGroupEvent, iSubFragmentEnd);              processGroupEvents(itGroupEvent, iSubFragmentEnd);
464                
465                if (pSignalUnitRack == NULL) {
466                    // if the voice was killed in this subfragment, or if the
467                    // filter EG is finished, switch EG1 to fade out stage
468                    if ((itKillEvent && killPos <= iSubFragmentEnd) ||
469                        (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
470                        pEG2->getSegmentType() == EG::segment_end)) {
471                        pEG1->enterFadeOutStage();
472                        itKillEvent = Pool<Event>::Iterator();
473                    }
474    
475              // if the voice was killed in this subfragment, or if the                  // process envelope generators
476              // filter EG is finished, switch EG1 to fade out stage                  switch (pEG1->getSegmentType()) {
477              if ((itKillEvent && killPos <= iSubFragmentEnd) ||                      case EG::segment_lin:
478                  (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&                          fFinalVolume *= pEG1->processLin();
479                   EG2.getSegmentType() == gig::EGADSR::segment_end)) {                          break;
480                  pEG1->enterFadeOutStage();                      case EG::segment_exp:
481                  itKillEvent = Pool<Event>::Iterator();                          fFinalVolume *= pEG1->processExp();
482              }                          break;
483                        case EG::segment_end:
484                            fFinalVolume *= pEG1->getLevel();
485                            break; // noop
486                        case EG::segment_pow:
487                            fFinalVolume *= pEG1->processPow();
488                            break;
489                    }
490                    switch (pEG2->getSegmentType()) {
491                        case EG::segment_lin:
492                            fFinalCutoff *= pEG2->processLin();
493                            break;
494                        case EG::segment_exp:
495                            fFinalCutoff *= pEG2->processExp();
496                            break;
497                        case EG::segment_end:
498                            fFinalCutoff *= pEG2->getLevel();
499                            break; // noop
500                        case EG::segment_pow:
501                            fFinalCutoff *= pEG2->processPow();
502                            break;
503                    }
504                    if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();
505    
506              // process envelope generators                  // process low frequency oscillators
507              switch (pEG1->getSegmentType()) {                  if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());
508                  case EG::segment_lin:                  if (bLFO2Enabled) fFinalCutoff *= (1.0f - pLFO2->render());
509                      fFinalVolume *= pEG1->processLin();                  if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
510                      break;              } else {
511                  case EG::segment_exp:                  // if the voice was killed in this subfragment, enter fade out stage
512                      fFinalVolume *= pEG1->processExp();                  if (itKillEvent && killPos <= iSubFragmentEnd) {
513                      break;                      pSignalUnitRack->EnterFadeOutStage();
514                  case EG::segment_end:                      itKillEvent = Pool<Event>::Iterator();
515                      fFinalVolume *= pEG1->getLevel();                  }
516                      break; // noop                  
517                  case EG::segment_pow:                  // if the filter EG is finished, switch EG1 to fade out stage
518                      fFinalVolume *= pEG1->processPow();                  /*if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
519                      break;                      pEG2->getSegmentType() == EG::segment_end) {
520                        pEG1->enterFadeOutStage();
521                        itKillEvent = Pool<Event>::Iterator();
522                    }*/
523                    // TODO: ^^^
524    
525                    fFinalVolume   *= pSignalUnitRack->GetEndpointUnit()->GetVolume();
526                    fFinalCutoff    = pSignalUnitRack->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff);
527                    fFinalResonance = pSignalUnitRack->GetEndpointUnit()->CalculateResonance(fFinalResonance);
528                    
529                    finalSynthesisParameters.fFinalPitch =
530                        pSignalUnitRack->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);
531                        
532              }              }
533              switch (EG2.getSegmentType()) {  
534                  case gig::EGADSR::segment_lin:              fFinalCutoff    *= NoteCutoff;
535                      fFinalCutoff *= EG2.processLin();              fFinalResonance *= NoteResonance;
                     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());  
536    
537              // limit the pitch so we don't read outside the buffer              // limit the pitch so we don't read outside the buffer
538              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));
# Line 443  namespace LinuxSampler { Line 566  namespace LinuxSampler {
566                  fFinalVolume * VolumeRight * PanRightSmoother.render();                  fFinalVolume * VolumeRight * PanRightSmoother.render();
567  #endif  #endif
568              // render audio for one subfragment              // render audio for one subfragment
569              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);              if (!delay) RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
570    
571              // stop the rendering if volume EG is finished              if (pSignalUnitRack == NULL) {
572              if (pEG1->getSegmentType() == EG::segment_end) break;                  // stop the rendering if volume EG is finished
573                    if (pEG1->getSegmentType() == EG::segment_end) break;
574                } else {
575                    // stop the rendering if the endpoint unit is not active
576                    if (!pSignalUnitRack->GetEndpointUnit()->Active()) break;
577                }
578    
579              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
580    
581              // increment envelopes' positions              if (pSignalUnitRack == NULL) {
582              if (pEG1->active()) {                  // increment envelopes' positions
583                    if (pEG1->active()) {
584    
585                        // 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
586                        if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
587                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
588                        }
589    
590                  // 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);
591                  if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {                      if (!pEG1->toStageEndLeft()) pEG1->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
                     pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);  
592                  }                  }
593                    if (pEG2->active()) {
594                  pEG1->increment(1);                      pEG2->increment(1);
595                  if (!pEG1->toStageEndLeft()) pEG1->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                      if (!pEG2->toStageEndLeft()) pEG2->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
596              }                  }
597              if (EG2.active()) {                  EG3.increment(1);
598                  EG2.increment(1);                  if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
599                  if (!EG2.toStageEndLeft()) EG2.update(gig::EGADSR::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              } else {
600                        // 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
601                        /*if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
602                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
603                        }*/
604                    // TODO: ^^^
605                    
606                    if (!delay) pSignalUnitRack->Increment();
607              }              }
             EG3.increment(1);  
             if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached  
608    
609              Pos = newPos;              Pos = newPos;
610              i = iSubFragmentEnd;              i = iSubFragmentEnd;
611          }          }
612            
613            if (delay) return;
614    
615            if (bVoiceRequiresDedicatedRouting) {
616                if (bEq) {
617                    pEq->RenderAudio(Samples);
618                    pEq->GetOutChannelLeft()->CopyTo(GetEngine()->pDedicatedVoiceChannelLeft, Samples);
619                    pEq->GetOutChannelRight()->CopyTo(GetEngine()->pDedicatedVoiceChannelRight, Samples);
620                }
621                optional<float> effectSendLevels[2] = {
622                    pMidiKeyInfo->ReverbSend,
623                    pMidiKeyInfo->ChorusSend
624                };
625                GetEngine()->RouteDedicatedVoiceChannels(pEngineChannel, effectSendLevels, Samples);
626            } else if (bEq) {
627                pEq->RenderAudio(Samples);
628                pEq->GetOutChannelLeft()->MixTo(pChannel->pChannelLeft, Samples);
629                pEq->GetOutChannelRight()->MixTo(pChannel->pChannelRight, Samples);
630            }
631      }      }
632    
633      /**      /**
634       * Process given list of MIDI control change and pitch bend events for       * Process given list of MIDI control change, aftertouch and pitch bend
635       * the given time.       * events for the given time.
636       *       *
637       * @param itEvent - iterator pointing to the next event to be processed       * @param itEvent - iterator pointing to the next event to be processed
638       * @param End     - youngest time stamp where processing should be stopped       * @param End     - youngest time stamp where processing should be stopped
# Line 489  namespace LinuxSampler { Line 646  namespace LinuxSampler {
646                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
647                      processResonanceEvent(itEvent);                      processResonanceEvent(itEvent);
648                  }                  }
649                  if (itEvent->Param.CC.Controller == pLFO1->ExtController) {                  if (pSignalUnitRack == NULL) {
650                      pLFO1->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
651                  }                          pLFO1->update(itEvent->Param.CC.Value);
652                  if (itEvent->Param.CC.Controller == pLFO2->ExtController) {                      }
653                      pLFO2->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO2->ExtController) {
654                  }                          pLFO2->update(itEvent->Param.CC.Value);
655                  if (itEvent->Param.CC.Controller == pLFO3->ExtController) {                      }
656                      pLFO3->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO3->ExtController) {
657                            pLFO3->update(itEvent->Param.CC.Value);
658                        }
659                  }                  }
660                  if (itEvent->Param.CC.Controller == 7) { // volume                  if (itEvent->Param.CC.Controller == 7) { // volume
661                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);
662                  } else if (itEvent->Param.CC.Controller == 10) { // panpot                  } else if (itEvent->Param.CC.Controller == 10) { // panpot
663                      PanLeftSmoother.update(AbstractEngine::PanCurve[128 - itEvent->Param.CC.Value]);                      MIDIPan = CalculatePan(itEvent->Param.CC.Value);
                     PanRightSmoother.update(AbstractEngine::PanCurve[itEvent->Param.CC.Value]);  
664                  }                  }
665              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event
666                  processPitchEvent(itEvent);                  processPitchEvent(itEvent);
667                } else if (itEvent->Type == Event::type_channel_pressure) {
668                    ProcessChannelPressureEvent(itEvent);
669                } else if (itEvent->Type == Event::type_note_pressure) {
670                    ProcessPolyphonicKeyPressureEvent(itEvent);
671              }              }
672    
673              ProcessCCEvent(itEvent);              ProcessCCEvent(itEvent);
674                if (pSignalUnitRack != NULL) {
675                    pSignalUnitRack->ProcessCCEvent(itEvent);
676                }
677          }          }
678      }      }
679    
# Line 527  namespace LinuxSampler { Line 692  namespace LinuxSampler {
692      }      }
693    
694      /**      /**
695       * 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
696       * for the given time.       * note synthesis parameter events for the given time.
697       *       *
698       * @param itEvent - iterator pointing to the next event to be processed       * @param itEvent - iterator pointing to the next event to be processed
699       * @param End     - youngest time stamp where processing should be stopped       * @param End     - youngest time stamp where processing should be stopped
# Line 537  namespace LinuxSampler { Line 702  namespace LinuxSampler {
702          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
703              // some voice types ignore note off              // some voice types ignore note off
704              if (!(Type & (Voice::type_one_shot | Voice::type_release_trigger | Voice::type_controller_triggered))) {              if (!(Type & (Voice::type_one_shot | Voice::type_release_trigger | Voice::type_controller_triggered))) {
705                  if (itEvent->Type == Event::type_release) {                  if (itEvent->Type == Event::type_release_key) {
706                      EnterReleaseStage();                      EnterReleaseStage();
707                  } else if (itEvent->Type == Event::type_cancel_release) {                  } else if (itEvent->Type == Event::type_cancel_release_key) {
708                      pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                      if (pSignalUnitRack == NULL) {
709                      EG2.update(gig::EGADSR::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                          pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
710                            pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
711                        } else {
712                            pSignalUnitRack->CancelRelease();
713                        }
714                    }
715                }
716                // process stop-note events (caused by built-in instrument script function note_off())
717                if (itEvent->Type == Event::type_release_note && pNote &&
718                    pEngineChannel->pEngine->NoteByID( itEvent->Param.Note.ID ) == pNote)
719                {
720                    EnterReleaseStage();
721                }
722                // process synthesis parameter events (caused by built-in realt-time instrument script functions)
723                if (itEvent->Type == Event::type_note_synth_param && pNote &&
724                    pEngineChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID ) == pNote)
725                {
726                    switch (itEvent->Param.NoteSynthParam.Type) {
727                        case Event::synth_param_volume:
728                            NoteVolumeSmoother.update(itEvent->Param.NoteSynthParam.AbsValue);
729                            break;
730                        case Event::synth_param_pitch:
731                            NotePitch = itEvent->Param.NoteSynthParam.AbsValue;
732                            break;
733                        case Event::synth_param_pan:
734                            NotePanLeft  = AbstractEngine::PanCurveValueNorm(itEvent->Param.NoteSynthParam.AbsValue, 0 /*left*/);
735                            NotePanRight = AbstractEngine::PanCurveValueNorm(itEvent->Param.NoteSynthParam.AbsValue, 1 /*right*/);
736                            break;
737                        case Event::synth_param_cutoff:
738                            NoteCutoff = itEvent->Param.NoteSynthParam.AbsValue;
739                            break;
740                        case Event::synth_param_resonance:
741                            NoteResonance = itEvent->Param.NoteSynthParam.AbsValue;
742                            break;
743                  }                  }
744              }              }
745          }          }
# Line 568  namespace LinuxSampler { Line 766  namespace LinuxSampler {
766       * @param itNoteOffEvent - event which causes this voice to die soon       * @param itNoteOffEvent - event which causes this voice to die soon
767       */       */
768      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
769          const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());          if (pSignalUnitRack == NULL) {
770          pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;              const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
771                pEngineChannel->PortamentoPos = (float) MIDIKey() + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
772            } else {
773                // TODO:
774            }
775      }      }
776    
777      /**      /**
# Line 593  namespace LinuxSampler { Line 795  namespace LinuxSampler {
795    
796      Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {      Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {
797          PitchInfo pitch;          PitchInfo pitch;
798          double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey % 12];          double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
799    
800          // GSt behaviour: maximum transpose up is 40 semitones. If          // GSt behaviour: maximum transpose up is 40 semitones. If
801          // MIDI key is more than 40 semitones above unity note,          // MIDI key is more than 40 semitones above unity note,
802          // the transpose is not done.          // the transpose is not done.
803          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;
804    
805          pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));          pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
806          pitch.PitchBendRange = 1.0 / 8192.0 * 100.0 * InstrInfo.PitchbendRange;          pitch.PitchBendRange = 1.0 / 8192.0 * 100.0 * InstrInfo.PitchbendRange;
# Line 606  namespace LinuxSampler { Line 808  namespace LinuxSampler {
808    
809          return pitch;          return pitch;
810      }      }
811        
812        void AbstractVoice::onScaleTuningChanged() {
813            PitchInfo pitch = this->Pitch;
814            double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
815            
816            // GSt behaviour: maximum transpose up is 40 semitones. If
817            // MIDI key is more than 40 semitones above unity note,
818            // the transpose is not done.
819            if (!SmplInfo.Unpitched && (MIDIKey() - (int) RgnInfo.UnityNote) < 40) pitchbasecents += (MIDIKey() - (int) RgnInfo.UnityNote) * 100;
820            
821            pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
822            this->Pitch = pitch;
823        }
824    
825      double AbstractVoice::CalculateVolume(double velocityAttenuation) {      double AbstractVoice::CalculateVolume(double velocityAttenuation) {
826          // For 16 bit samples, we downscale by 32768 to convert from          // For 16 bit samples, we downscale by 32768 to convert from
# Line 618  namespace LinuxSampler { Line 833  namespace LinuxSampler {
833          // the volume of release triggered samples depends on note length          // the volume of release triggered samples depends on note length
834          if (Type & Voice::type_release_trigger) {          if (Type & Voice::type_release_trigger) {
835              float noteLength = float(GetEngine()->FrameTime + Delay -              float noteLength = float(GetEngine()->FrameTime + Delay -
836                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;                  GetNoteOnTime(MIDIKey()) ) / GetEngine()->SampleRate;
837    
838              volume *= GetReleaseTriggerAttenuation(noteLength);              volume *= GetReleaseTriggerAttenuation(noteLength);
839          }          }
# Line 631  namespace LinuxSampler { Line 846  namespace LinuxSampler {
846      }      }
847    
848      void AbstractVoice::EnterReleaseStage() {      void AbstractVoice::EnterReleaseStage() {
849          pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);          if (pSignalUnitRack == NULL) {
850          EG2.update(gig::EGADSR::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
851                pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
852            } else {
853                pSignalUnitRack->EnterReleaseStage();
854            }
855        }
856    
857        bool AbstractVoice::EG1Finished() {
858            if (pSignalUnitRack == NULL) {
859                return pEG1->getSegmentType() == EG::segment_end;
860            } else {
861                return !pSignalUnitRack->GetEndpointUnit()->Active();
862            }
863      }      }
864    
865  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.2115  
changed lines
  Added in v.2953

  ViewVC Help
Powered by ViewVC