/[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 2175 by persson, Mon Apr 25 08:12:36 2011 UTC revision 3118 by schoenebeck, Fri Apr 21 13:33:03 2017 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-2011 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *
8     *   Copyright (C) 2013-2016 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 LFO (0..1 range)          pLFO1 = new LFOUnsigned(1.0f);  // amplitude LFO (0..1 range)
33          pLFO2 = new LFOUnsigned(1.0f);  // filter LFO (0..1 range)          pLFO2 = new LFOUnsigned(1.0f);  // filter LFO (0..1 range)
# Line 43  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      /**      /**
# Line 98  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          MidiKeyBase* pKeyInfo = GetMidiKeyInfo(MIDIKey);          MidiKeyBase* pKeyInfo = GetMidiKeyInfo(MIDIKey());
120    
121          pGroupEvents = iKeyGroup ? pEngineChannel->ActiveKeyGroups[iKeyGroup] : 0;          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(itNoteOnEvent->Param.Note.Velocity);
# Line 124  namespace LinuxSampler { Line 141  namespace LinuxSampler {
141          // get starting crossfade volume level          // get starting crossfade volume level
142          float crossfadeVolume = CalculateCrossfadeVolume(itNoteOnEvent->Param.Note.Velocity);          float crossfadeVolume = CalculateCrossfadeVolume(itNoteOnEvent->Param.Note.Velocity);
143    
144          VolumeLeft  = volume * pKeyInfo->PanLeft  * AbstractEngine::PanCurve[64 - RgnInfo.Pan];          VolumeLeft  = volume * pKeyInfo->PanLeft;
145          VolumeRight = volume * pKeyInfo->PanRight * 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 /* 1ms */);
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;          NoteVolumeSmoother.trigger(pNote ? pNote->Override.Volume : 1.f, quickRampRate);
155    
156          // 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
157          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;
158          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;
159    
160            SetSampleStartOffset();
161    
162          if (DiskVoice) { // voice to be streamed from disk          if (DiskVoice) { // voice to be streamed from disk
163              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {
164                  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 156  namespace LinuxSampler { Line 175  namespace LinuxSampler {
175              RAMLoop = (SmplInfo.HasLoops && (SmplInfo.LoopStart + SmplInfo.LoopLength) <= MaxRAMPos);              RAMLoop = (SmplInfo.HasLoops && (SmplInfo.LoopStart + SmplInfo.LoopLength) <= MaxRAMPos);
176    
177              if (OrderNewStream()) return -1;              if (OrderNewStream()) return -1;
178              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"));
179          }          }
180          else { // RAM only voice          else { // RAM only voice
181              MaxRAMPos = cachedsamples;              MaxRAMPos = cachedsamples;
# Line 172  namespace LinuxSampler { Line 191  namespace LinuxSampler {
191          }          }
192    
193          Pitch = CalculatePitchInfo(PitchBend);          Pitch = CalculatePitchInfo(PitchBend);
194            NotePitch = (pNote) ? pNote->Override.Pitch : 1.0f;
195            NoteCutoff = (pNote) ? pNote->Override.Cutoff : 1.0f;
196            NoteResonance = (pNote) ? pNote->Override.Resonance : 1.0f;
197    
198          // 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
199          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);
200    
201          // setup EG 1 (VCA EG)          if (pSignalUnitRack == NULL) { // setup EG 1 (VCA EG)
         {  
202              // get current value of EG1 controller              // get current value of EG1 controller
203              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);
204    
205              // calculate influence of EG1 controller on EG1's parameters              // calculate influence of EG1 controller on EG1's parameters
206              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);
207    
208                if (pNote) {
209                    egInfo.Attack  *= pNote->Override.Attack;
210                    egInfo.Decay   *= pNote->Override.Decay;
211                    egInfo.Release *= pNote->Override.Release;
212                }
213    
214              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
215            } else {
216                pSignalUnitRack->Trigger();
217          }          }
218    
219            const uint8_t pan = (pSignalUnitRack) ? pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan) : MIDIPan;
220            NotePanLeft  = (pNote) ? AbstractEngine::PanCurveValueNorm(pNote->Override.Pan, 0 /*left*/ ) : 1.f;
221            NotePanRight = (pNote) ? AbstractEngine::PanCurveValueNorm(pNote->Override.Pan, 1 /*right*/) : 1.f;
222            PanLeftSmoother.trigger(
223                AbstractEngine::PanCurve[128 - pan] * NotePanLeft,
224                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)
225            );
226            PanRightSmoother.trigger(
227                AbstractEngine::PanCurve[pan] * NotePanRight,
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    
231  #ifdef CONFIG_INTERPOLATE_VOLUME  #ifdef CONFIG_INTERPOLATE_VOLUME
232          // setup initial volume in synthesis parameters          // setup initial volume in synthesis parameters
233      #ifdef CONFIG_PROCESS_MUTED_CHANNELS      #ifdef CONFIG_PROCESS_MUTED_CHANNELS
# Line 197  namespace LinuxSampler { Line 238  namespace LinuxSampler {
238          else          else
239      #else      #else
240          {          {
241              float finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();              float finalVolume;
242                if (pSignalUnitRack == NULL) {
243                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();
244                } else {
245                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pSignalUnitRack->GetEndpointUnit()->GetVolume();
246                }
247    
248              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * pEngineChannel->GlobalPanLeft;              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * PanLeftSmoother.render();
249              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight;              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * PanRightSmoother.render();
250          }          }
251      #endif      #endif
252  #endif  #endif
253    
254          // setup EG 2 (VCF Cutoff EG)          if (pSignalUnitRack == NULL) {
255          {              // setup EG 2 (VCF Cutoff EG)
256              // get current value of EG2 controller              {
257              double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);                  // get current value of EG2 controller
258                    double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);
259    
260                    // calculate influence of EG2 controller on EG2's parameters
261                    EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);
262    
263                    TriggerEG2(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
264                }
265    
             // calculate influence of EG2 controller on EG2's parameters  
             EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);  
266    
267              TriggerEG2(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);              // setup EG 3 (VCO EG)
268          }              {
269                    // if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch
270                    bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;
271                    float eg3depth = (bPortamento)
272                                 ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey()) * 100)
273                                 : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);
274                    float eg3time = (bPortamento)
275                                ? pEngineChannel->PortamentoTime
276                                : RgnInfo.EG3Attack;
277                    EG3.trigger(eg3depth, eg3time, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
278                    dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time));
279                }
280    
281    
282          // setup EG 3 (VCO EG)              // setup LFO 1 (VCA LFO)
283          {              InitLFO1();
284              // 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)
285              bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;              InitLFO2();
286              float eg3depth = (bPortamento)              // setup LFO 3 (VCO LFO)
287                           ? 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));  
288          }          }
289    
290    
         // setup LFO 1 (VCA LFO)  
         InitLFO1();  
         // setup LFO 2 (VCF Cutoff LFO)  
         InitLFO2();  
         // setup LFO 3 (VCO LFO)  
         InitLFO3();  
   
   
291          #if CONFIG_FORCE_FILTER          #if CONFIG_FORCE_FILTER
292          const bool bUseFilter = true;          const bool bUseFilter = true;
293          #else // use filter only if instrument file told so          #else // use filter only if instrument file told so
# Line 282  namespace LinuxSampler { Line 330  namespace LinuxSampler {
330              VCFCutoffCtrl.controller    = 0;              VCFCutoffCtrl.controller    = 0;
331              VCFResonanceCtrl.controller = 0;              VCFResonanceCtrl.controller = 0;
332          }          }
333            
334            const bool bEq =
335                pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && pEq->HasSupport();
336    
337            if (bEq) {
338                pEq->GetInChannelLeft()->Clear();
339                pEq->GetInChannelRight()->Clear();
340                pEq->RenderAudio(GetEngine()->pAudioOutputDevice->MaxSamplesPerCycle());
341            }
342    
343          return 0; // success          return 0; // success
344      }      }
345        
346        void AbstractVoice::SetSampleStartOffset() {
347            finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
348            Pos = RgnInfo.SampleStartOffset;
349        }
350    
351      /**      /**
352       *  Synthesizes the current audio fragment for this voice.       *  Synthesizes the current audio fragment for this voice.
# Line 295  namespace LinuxSampler { Line 357  namespace LinuxSampler {
357       *  @param Skip    - number of sample points to skip in output buffer       *  @param Skip    - number of sample points to skip in output buffer
358       */       */
359      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
360            bool delay = false; // Whether the voice playback should be delayed for this call
361            
362            if (pSignalUnitRack != NULL) {
363                uint delaySteps = pSignalUnitRack->GetEndpointUnit()->DelayTrigger();
364                if (delaySteps > 0) { // delay on the endpoint unit means delay of the voice playback
365                    if (delaySteps >= Samples) {
366                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(Samples);
367                        delay = true;
368                    } else {
369                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(delaySteps);
370                        Samples -= delaySteps;
371                        Skip += delaySteps;
372                    }
373                }
374            }
375            
376          AbstractEngineChannel* pChannel = pEngineChannel;          AbstractEngineChannel* pChannel = pEngineChannel;
377          MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey);          MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey());
378    
379          const bool bVoiceRequiresDedicatedRouting =          const bool bVoiceRequiresDedicatedRouting =
380              pEngineChannel->GetFxSendCount() > 0 &&              pEngineChannel->GetFxSendCount() > 0 &&
381              (pMidiKeyInfo->ReverbSend || pMidiKeyInfo->ChorusSend);              (pMidiKeyInfo->ReverbSend || pMidiKeyInfo->ChorusSend);
382            
383          if (bVoiceRequiresDedicatedRouting) {          const bool bEq =
384                pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && pEq->HasSupport();
385    
386            if (bEq) {
387                pEq->GetInChannelLeft()->Clear();
388                pEq->GetInChannelRight()->Clear();
389                finalSynthesisParameters.pOutLeft  = &pEq->GetInChannelLeft()->Buffer()[Skip];
390                finalSynthesisParameters.pOutRight = &pEq->GetInChannelRight()->Buffer()[Skip];
391                pSignalUnitRack->UpdateEqSettings(pEq);
392            } else if (bVoiceRequiresDedicatedRouting) {
393              finalSynthesisParameters.pOutLeft  = &GetEngine()->pDedicatedVoiceChannelLeft->Buffer()[Skip];              finalSynthesisParameters.pOutLeft  = &GetEngine()->pDedicatedVoiceChannelLeft->Buffer()[Skip];
394              finalSynthesisParameters.pOutRight = &GetEngine()->pDedicatedVoiceChannelRight->Buffer()[Skip];              finalSynthesisParameters.pOutRight = &GetEngine()->pDedicatedVoiceChannelRight->Buffer()[Skip];
395          } else {          } else {
# Line 313  namespace LinuxSampler { Line 400  namespace LinuxSampler {
400    
401          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();
402          RTList<Event>::Iterator itNoteEvent;          RTList<Event>::Iterator itNoteEvent;
403          GetFirstEventOnKey(MIDIKey, itNoteEvent);          GetFirstEventOnKey(HostKey(), itNoteEvent);
404    
405          RTList<Event>::Iterator itGroupEvent;          RTList<Event>::Iterator itGroupEvent;
406          if (pGroupEvents) itGroupEvent = pGroupEvents->first();          if (pGroupEvents && !Orphan) itGroupEvent = pGroupEvents->first();
407    
408          if (itTriggerEvent) { // skip events that happened before this voice was triggered          if (itTriggerEvent) { // skip events that happened before this voice was triggered
409              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;
# Line 333  namespace LinuxSampler { Line 420  namespace LinuxSampler {
420              }              }
421          }          }
422    
423          uint killPos;          uint killPos = 0;
424          if (itKillEvent) {          if (itKillEvent) {
425              int maxFadeOutPos = Samples - GetEngine()->GetMinFadeOutSamples();              int maxFadeOutPos = Samples - GetEngine()->GetMinFadeOutSamples();
426              if (maxFadeOutPos < 0) {              if (maxFadeOutPos < 0) {
# Line 342  namespace LinuxSampler { Line 429  namespace LinuxSampler {
429                  // drivers that use Samples < MaxSamplesPerCycle).                  // drivers that use Samples < MaxSamplesPerCycle).
430                  // End the EG1 here, at pos 0, with a shorter max fade                  // End the EG1 here, at pos 0, with a shorter max fade
431                  // out time.                  // out time.
432                  pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (pSignalUnitRack == NULL) {
433                        pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
434                    } else {
435                        pSignalUnitRack->EnterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
436                    }
437                  itKillEvent = Pool<Event>::Iterator();                  itKillEvent = Pool<Event>::Iterator();
438              } else {              } else {
439                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);
# Line 357  namespace LinuxSampler { Line 448  namespace LinuxSampler {
448              fFinalCutoff    = VCFCutoffCtrl.fvalue;              fFinalCutoff    = VCFCutoffCtrl.fvalue;
449              fFinalResonance = VCFResonanceCtrl.fvalue;              fFinalResonance = VCFResonanceCtrl.fvalue;
450    
451              // process MIDI control change and pitchbend events for this subfragment              // process MIDI control change, aftertouch and pitchbend events for this subfragment
452              processCCEvents(itCCEvent, iSubFragmentEnd);              processCCEvents(itCCEvent, iSubFragmentEnd);
453                uint8_t pan = MIDIPan;
454                if (pSignalUnitRack != NULL) pan = pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan);
455    
456                PanLeftSmoother.update(AbstractEngine::PanCurve[128 - pan] * NotePanLeft);
457                PanRightSmoother.update(AbstractEngine::PanCurve[pan]      * NotePanRight);
458    
459              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend;              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend * NotePitch;
460              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();  
461                float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render() * NoteVolumeSmoother.render();
462  #ifdef CONFIG_PROCESS_MUTED_CHANNELS  #ifdef CONFIG_PROCESS_MUTED_CHANNELS
463              if (pChannel->GetMute()) fFinalVolume = 0;              if (pChannel->GetMute()) fFinalVolume = 0;
464  #endif  #endif
# Line 369  namespace LinuxSampler { Line 466  namespace LinuxSampler {
466              // process transition events (note on, note off & sustain pedal)              // process transition events (note on, note off & sustain pedal)
467              processTransitionEvents(itNoteEvent, iSubFragmentEnd);              processTransitionEvents(itNoteEvent, iSubFragmentEnd);
468              processGroupEvents(itGroupEvent, iSubFragmentEnd);              processGroupEvents(itGroupEvent, iSubFragmentEnd);
469                
470                if (pSignalUnitRack == NULL) {
471                    // if the voice was killed in this subfragment, or if the
472                    // filter EG is finished, switch EG1 to fade out stage
473                    if ((itKillEvent && killPos <= iSubFragmentEnd) ||
474                        (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
475                        pEG2->getSegmentType() == EG::segment_end)) {
476                        pEG1->enterFadeOutStage();
477                        itKillEvent = Pool<Event>::Iterator();
478                    }
479    
480              // if the voice was killed in this subfragment, or if the                  // process envelope generators
481              // filter EG is finished, switch EG1 to fade out stage                  switch (pEG1->getSegmentType()) {
482              if ((itKillEvent && killPos <= iSubFragmentEnd) ||                      case EG::segment_lin:
483                  (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&                          fFinalVolume *= pEG1->processLin();
484                   pEG2->getSegmentType() == EG::segment_end)) {                          break;
485                  pEG1->enterFadeOutStage();                      case EG::segment_exp:
486                  itKillEvent = Pool<Event>::Iterator();                          fFinalVolume *= pEG1->processExp();
487              }                          break;
488                        case EG::segment_end:
489                            fFinalVolume *= pEG1->getLevel();
490                            break; // noop
491                        case EG::segment_pow:
492                            fFinalVolume *= pEG1->processPow();
493                            break;
494                    }
495                    switch (pEG2->getSegmentType()) {
496                        case EG::segment_lin:
497                            fFinalCutoff *= pEG2->processLin();
498                            break;
499                        case EG::segment_exp:
500                            fFinalCutoff *= pEG2->processExp();
501                            break;
502                        case EG::segment_end:
503                            fFinalCutoff *= pEG2->getLevel();
504                            break; // noop
505                        case EG::segment_pow:
506                            fFinalCutoff *= pEG2->processPow();
507                            break;
508                    }
509                    if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();
510    
511              // process envelope generators                  // process low frequency oscillators
512              switch (pEG1->getSegmentType()) {                  if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());
513                  case EG::segment_lin:                  if (bLFO2Enabled) fFinalCutoff *= (1.0f - pLFO2->render());
514                      fFinalVolume *= pEG1->processLin();                  if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
515                      break;              } else {
516                  case EG::segment_exp:                  // if the voice was killed in this subfragment, enter fade out stage
517                      fFinalVolume *= pEG1->processExp();                  if (itKillEvent && killPos <= iSubFragmentEnd) {
518                      break;                      pSignalUnitRack->EnterFadeOutStage();
519                  case EG::segment_end:                      itKillEvent = Pool<Event>::Iterator();
520                      fFinalVolume *= pEG1->getLevel();                  }
521                      break; // noop                  
522                  case EG::segment_pow:                  // if the filter EG is finished, switch EG1 to fade out stage
523                      fFinalVolume *= pEG1->processPow();                  /*if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
524                      break;                      pEG2->getSegmentType() == EG::segment_end) {
525              }                      pEG1->enterFadeOutStage();
526              switch (pEG2->getSegmentType()) {                      itKillEvent = Pool<Event>::Iterator();
527                  case EG::segment_lin:                  }*/
528                      fFinalCutoff *= pEG2->processLin();                  // TODO: ^^^
529                      break;  
530                  case EG::segment_exp:                  fFinalVolume   *= pSignalUnitRack->GetEndpointUnit()->GetVolume();
531                      fFinalCutoff *= pEG2->processExp();                  fFinalCutoff    = pSignalUnitRack->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff);
532                      break;                  fFinalResonance = pSignalUnitRack->GetEndpointUnit()->CalculateResonance(fFinalResonance);
533                  case EG::segment_end:                  
534                      fFinalCutoff *= pEG2->getLevel();                  finalSynthesisParameters.fFinalPitch =
535                      break; // noop                      pSignalUnitRack->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);
536                  case EG::segment_pow:                      
                     fFinalCutoff *= pEG2->processPow();  
                     break;  
537              }              }
             if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();  
538    
539              // process low frequency oscillators              fFinalCutoff    *= NoteCutoff;
540              if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());              fFinalResonance *= NoteResonance;
             if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();  
             if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());  
541    
542              // limit the pitch so we don't read outside the buffer              // limit the pitch so we don't read outside the buffer
543              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));
# Line 447  namespace LinuxSampler { Line 571  namespace LinuxSampler {
571                  fFinalVolume * VolumeRight * PanRightSmoother.render();                  fFinalVolume * VolumeRight * PanRightSmoother.render();
572  #endif  #endif
573              // render audio for one subfragment              // render audio for one subfragment
574              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);              if (!delay) RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
575    
576              // stop the rendering if volume EG is finished              if (pSignalUnitRack == NULL) {
577              if (pEG1->getSegmentType() == EG::segment_end) break;                  // stop the rendering if volume EG is finished
578                    if (pEG1->getSegmentType() == EG::segment_end) break;
579                } else {
580                    // stop the rendering if the endpoint unit is not active
581                    if (!pSignalUnitRack->GetEndpointUnit()->Active()) break;
582                }
583    
584              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
585    
586              // increment envelopes' positions              if (pSignalUnitRack == NULL) {
587              if (pEG1->active()) {                  // increment envelopes' positions
588                    if (pEG1->active()) {
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
591                        if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
592                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
593                        }
594    
595                  // 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);
596                  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);  
597                  }                  }
598                    if (pEG2->active()) {
599                  pEG1->increment(1);                      pEG2->increment(1);
600                  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);
601              }                  }
602              if (pEG2->active()) {                  EG3.increment(1);
603                  pEG2->increment(1);                  if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
604                  if (!pEG2->toStageEndLeft()) pEG2->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              } else {
605                        // 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
606                        /*if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
607                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
608                        }*/
609                    // TODO: ^^^
610                    
611                    if (!delay) pSignalUnitRack->Increment();
612              }              }
             EG3.increment(1);  
             if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached  
613    
614              Pos = newPos;              Pos = newPos;
615              i = iSubFragmentEnd;              i = iSubFragmentEnd;
616          }          }
617            
618            if (delay) return;
619    
620          if (bVoiceRequiresDedicatedRouting) {          if (bVoiceRequiresDedicatedRouting) {
621                if (bEq) {
622                    pEq->RenderAudio(Samples);
623                    pEq->GetOutChannelLeft()->CopyTo(GetEngine()->pDedicatedVoiceChannelLeft, Samples);
624                    pEq->GetOutChannelRight()->CopyTo(GetEngine()->pDedicatedVoiceChannelRight, Samples);
625                }
626              optional<float> effectSendLevels[2] = {              optional<float> effectSendLevels[2] = {
627                  pMidiKeyInfo->ReverbSend,                  pMidiKeyInfo->ReverbSend,
628                  pMidiKeyInfo->ChorusSend                  pMidiKeyInfo->ChorusSend
629              };              };
630              GetEngine()->RouteDedicatedVoiceChannels(pEngineChannel, effectSendLevels, Samples);              GetEngine()->RouteDedicatedVoiceChannels(pEngineChannel, effectSendLevels, Samples);
631            } else if (bEq) {
632                pEq->RenderAudio(Samples);
633                pEq->GetOutChannelLeft()->MixTo(pChannel->pChannelLeft, Samples);
634                pEq->GetOutChannelRight()->MixTo(pChannel->pChannelRight, Samples);
635          }          }
636      }      }
637    
638      /**      /**
639       * Process given list of MIDI control change and pitch bend events for       * Process given list of MIDI control change, aftertouch and pitch bend
640       * the given time.       * events for the given time.
641       *       *
642       * @param itEvent - iterator pointing to the next event to be processed       * @param itEvent - iterator pointing to the next event to be processed
643       * @param End     - youngest time stamp where processing should be stopped       * @param End     - youngest time stamp where processing should be stopped
644       */       */
645      void AbstractVoice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) {      void AbstractVoice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) {
646          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
647              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)
648                    && itEvent->Param.CC.Controller) // if (valid) MIDI control change event
649                {
650                  if (itEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {                  if (itEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {
651                      ProcessCutoffEvent(itEvent);                      ProcessCutoffEvent(itEvent);
652                  }                  }
653                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
654                      processResonanceEvent(itEvent);                      processResonanceEvent(itEvent);
655                  }                  }
656                  if (itEvent->Param.CC.Controller == pLFO1->ExtController) {                  if (itEvent->Param.CC.Controller == CTRL_TABLE_IDX_AFTERTOUCH ||
657                      pLFO1->update(itEvent->Param.CC.Value);                      itEvent->Type == Event::type_channel_pressure)
658                    {
659                        ProcessChannelPressureEvent(itEvent);
660                  }                  }
661                  if (itEvent->Param.CC.Controller == pLFO2->ExtController) {                  if (pSignalUnitRack == NULL) {
662                      pLFO2->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
663                  }                          pLFO1->updateByMIDICtrlValue(itEvent->Param.CC.Value);
664                  if (itEvent->Param.CC.Controller == pLFO3->ExtController) {                      }
665                      pLFO3->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO2->ExtController) {
666                            pLFO2->updateByMIDICtrlValue(itEvent->Param.CC.Value);
667                        }
668                        if (itEvent->Param.CC.Controller == pLFO3->ExtController) {
669                            pLFO3->updateByMIDICtrlValue(itEvent->Param.CC.Value);
670                        }
671                  }                  }
672                  if (itEvent->Param.CC.Controller == 7) { // volume                  if (itEvent->Param.CC.Controller == 7) { // volume
673                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);
674                  } else if (itEvent->Param.CC.Controller == 10) { // panpot                  } else if (itEvent->Param.CC.Controller == 10) { // panpot
675                      PanLeftSmoother.update(AbstractEngine::PanCurve[128 - itEvent->Param.CC.Value]);                      MIDIPan = CalculatePan(itEvent->Param.CC.Value);
                     PanRightSmoother.update(AbstractEngine::PanCurve[itEvent->Param.CC.Value]);  
676                  }                  }
677              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event
678                  processPitchEvent(itEvent);                  processPitchEvent(itEvent);
679                } else if (itEvent->Type == Event::type_note_pressure) {
680                    ProcessPolyphonicKeyPressureEvent(itEvent);
681              }              }
682    
683              ProcessCCEvent(itEvent);              ProcessCCEvent(itEvent);
684                if (pSignalUnitRack != NULL) {
685                    pSignalUnitRack->ProcessCCEvent(itEvent);
686                }
687          }          }
688      }      }
689    
# Line 539  namespace LinuxSampler { Line 702  namespace LinuxSampler {
702      }      }
703    
704      /**      /**
705       * 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
706       * for the given time.       * note synthesis parameter events for the given time.
707       *       *
708       * @param itEvent - iterator pointing to the next event to be processed       * @param itEvent - iterator pointing to the next event to be processed
709       * @param End     - youngest time stamp where processing should be stopped       * @param End     - youngest time stamp where processing should be stopped
# Line 549  namespace LinuxSampler { Line 712  namespace LinuxSampler {
712          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
713              // some voice types ignore note off              // some voice types ignore note off
714              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))) {
715                  if (itEvent->Type == Event::type_release) {                  if (itEvent->Type == Event::type_release_key) {
716                      EnterReleaseStage();                      EnterReleaseStage();
717                  } else if (itEvent->Type == Event::type_cancel_release) {                  } else if (itEvent->Type == Event::type_cancel_release_key) {
718                      pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                      if (pSignalUnitRack == NULL) {
719                      pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                          pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
720                            pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
721                        } else {
722                            pSignalUnitRack->CancelRelease();
723                        }
724                    }
725                }
726                // process stop-note events (caused by built-in instrument script function note_off())
727                if (itEvent->Type == Event::type_release_note && pNote &&
728                    pEngineChannel->pEngine->NoteByID( itEvent->Param.Note.ID ) == pNote)
729                {
730                    EnterReleaseStage();
731                }
732                // process synthesis parameter events (caused by built-in realt-time instrument script functions)
733                if (itEvent->Type == Event::type_note_synth_param && pNote &&
734                    pEngineChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID ) == pNote)
735                {
736                    switch (itEvent->Param.NoteSynthParam.Type) {
737                        case Event::synth_param_volume:
738                            NoteVolumeSmoother.update(itEvent->Param.NoteSynthParam.AbsValue);
739                            break;
740                        case Event::synth_param_pitch:
741                            NotePitch = itEvent->Param.NoteSynthParam.AbsValue;
742                            break;
743                        case Event::synth_param_pan:
744                            NotePanLeft  = AbstractEngine::PanCurveValueNorm(itEvent->Param.NoteSynthParam.AbsValue, 0 /*left*/);
745                            NotePanRight = AbstractEngine::PanCurveValueNorm(itEvent->Param.NoteSynthParam.AbsValue, 1 /*right*/);
746                            break;
747                        case Event::synth_param_cutoff:
748                            NoteCutoff = itEvent->Param.NoteSynthParam.AbsValue;
749                            break;
750                        case Event::synth_param_resonance:
751                            NoteResonance = itEvent->Param.NoteSynthParam.AbsValue;
752                            break;
753                        case Event::synth_param_amp_lfo_depth:
754                            pLFO1->setScriptDepthFactor(itEvent->Param.NoteSynthParam.AbsValue);
755                            break;
756                        case Event::synth_param_amp_lfo_freq:
757                            pLFO1->setScriptFrequencyFactor(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
758                            break;
759                        case Event::synth_param_pitch_lfo_depth:
760                            pLFO3->setScriptDepthFactor(itEvent->Param.NoteSynthParam.AbsValue);
761                            break;
762                        case Event::synth_param_pitch_lfo_freq:
763                            pLFO3->setScriptFrequencyFactor(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
764                            break;
765    
766                        case Event::synth_param_attack:
767                        case Event::synth_param_decay:
768                        case Event::synth_param_release:
769                            break; // noop
770                  }                  }
771              }              }
772          }          }
# Line 580  namespace LinuxSampler { Line 793  namespace LinuxSampler {
793       * @param itNoteOffEvent - event which causes this voice to die soon       * @param itNoteOffEvent - event which causes this voice to die soon
794       */       */
795      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
796          const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());          if (pSignalUnitRack == NULL) {
797          pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;              const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
798                pEngineChannel->PortamentoPos = (float) MIDIKey() + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
799            } else {
800                // TODO:
801            }
802      }      }
803    
804      /**      /**
# Line 605  namespace LinuxSampler { Line 822  namespace LinuxSampler {
822    
823      Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {      Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {
824          PitchInfo pitch;          PitchInfo pitch;
825          double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey % 12];          double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
826    
827          // GSt behaviour: maximum transpose up is 40 semitones. If          // GSt behaviour: maximum transpose up is 40 semitones. If
828          // MIDI key is more than 40 semitones above unity note,          // MIDI key is more than 40 semitones above unity note,
829          // the transpose is not done.          // the transpose is not done.
830          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;
831    
832          pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));          pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
833          pitch.PitchBendRange = 1.0 / 8192.0 * 100.0 * InstrInfo.PitchbendRange;          pitch.PitchBendRange = 1.0 / 8192.0 * 100.0 * InstrInfo.PitchbendRange;
# Line 618  namespace LinuxSampler { Line 835  namespace LinuxSampler {
835    
836          return pitch;          return pitch;
837      }      }
838        
839        void AbstractVoice::onScaleTuningChanged() {
840            PitchInfo pitch = this->Pitch;
841            double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
842            
843            // GSt behaviour: maximum transpose up is 40 semitones. If
844            // MIDI key is more than 40 semitones above unity note,
845            // the transpose is not done.
846            if (!SmplInfo.Unpitched && (MIDIKey() - (int) RgnInfo.UnityNote) < 40) pitchbasecents += (MIDIKey() - (int) RgnInfo.UnityNote) * 100;
847            
848            pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
849            this->Pitch = pitch;
850        }
851    
852      double AbstractVoice::CalculateVolume(double velocityAttenuation) {      double AbstractVoice::CalculateVolume(double velocityAttenuation) {
853          // For 16 bit samples, we downscale by 32768 to convert from          // For 16 bit samples, we downscale by 32768 to convert from
# Line 630  namespace LinuxSampler { Line 860  namespace LinuxSampler {
860          // the volume of release triggered samples depends on note length          // the volume of release triggered samples depends on note length
861          if (Type & Voice::type_release_trigger) {          if (Type & Voice::type_release_trigger) {
862              float noteLength = float(GetEngine()->FrameTime + Delay -              float noteLength = float(GetEngine()->FrameTime + Delay -
863                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;                  GetNoteOnTime(MIDIKey()) ) / GetEngine()->SampleRate;
864    
865              volume *= GetReleaseTriggerAttenuation(noteLength);              volume *= GetReleaseTriggerAttenuation(noteLength);
866          }          }
# Line 643  namespace LinuxSampler { Line 873  namespace LinuxSampler {
873      }      }
874    
875      void AbstractVoice::EnterReleaseStage() {      void AbstractVoice::EnterReleaseStage() {
876          pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);          if (pSignalUnitRack == NULL) {
877          pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
878                pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
879            } else {
880                pSignalUnitRack->EnterReleaseStage();
881            }
882        }
883    
884        bool AbstractVoice::EG1Finished() {
885            if (pSignalUnitRack == NULL) {
886                return pEG1->getSegmentType() == EG::segment_end;
887            } else {
888                return !pSignalUnitRack->GetEndpointUnit()->Active();
889            }
890      }      }
891    
892  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.2175  
changed lines
  Added in v.3118

  ViewVC Help
Powered by ViewVC