/[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 3054 by schoenebeck, Thu Dec 15 12:47:45 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-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 EG (0..1 range)          pLFO1 = new LFOUnsigned(1.0f);  // amplitude LFO (0..1 range)
33          pLFO2 = new LFOUnsigned(1.0f);  // filter EG (0..1 range)          pLFO2 = new LFOUnsigned(1.0f);  // filter LFO (0..1 range)
34          pLFO3 = new LFOSigned(1200.0f); // pitch EG (-1200..+1200 range)          pLFO3 = new LFOSigned(1200.0f); // pitch LFO (-1200..+1200 range)
35          PlaybackState = playback_state_end;          PlaybackState = playback_state_end;
36          SynthesisMode = 0; // set all mode bits to 0 first          SynthesisMode = 0; // set all mode bits to 0 first
37          // select synthesis implementation (asm core is not supported ATM)          // select synthesis implementation (asm core is not supported ATM)
# 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());
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);
133          float volume = CalculateVolume(velocityAttenuation);          float volume = CalculateVolume(velocityAttenuation) * pKeyInfo->Volume;
134          if (volume <= 0) return -1;          if (volume <= 0) return -1;
135    
136          // select channel mode (mono or stereo)          // select channel mode (mono or stereo)
# Line 123  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 * AbstractEngine::PanCurve[64 - RgnInfo.Pan];          VolumeLeft  = volume * pKeyInfo->PanLeft;
145          VolumeRight = volume * AbstractEngine::PanCurve[64 + RgnInfo.Pan];          VolumeRight = volume * pKeyInfo->PanRight;
146    
147          float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;          // this rate is used for rather mellow volume fades
148            const float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;
149            // this rate is used for very fast volume fades
150            const float quickRampRate = RTMath::Min(subfragmentRate, GetEngine()->SampleRate * 0.001f /* 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 155  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 171  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 196  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              EG2.trigger (              // setup EG 3 (VCO EG)
268                  uint(RgnInfo.EG2PreAttack),              {
269                  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
270                  false,                  bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;
271                  RgnInfo.EG2Decay1 * egInfo.Decay * velrelease,                  float eg3depth = (bPortamento)
272                  RgnInfo.EG2Decay2 * egInfo.Decay * velrelease,                               ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey()) * 100)
273                  RgnInfo.EG2InfiniteSustain,                               : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);
274                  uint(RgnInfo.EG2Sustain),                  float eg3time = (bPortamento)
275                  RgnInfo.EG2Release * egInfo.Release * velrelease,                              ? pEngineChannel->PortamentoTime
276                  velocityAttenuation,                              : RgnInfo.EG3Attack;
277                  GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE                  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 292  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 305  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          finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];          MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey());
378          finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];  
379          finalSynthesisParameters.pSrc      = pSrc;          const bool bVoiceRequiresDedicatedRouting =
380                pEngineChannel->GetFxSendCount() > 0 &&
381                (pMidiKeyInfo->ReverbSend || pMidiKeyInfo->ChorusSend);
382            
383            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];
394                finalSynthesisParameters.pOutRight = &GetEngine()->pDedicatedVoiceChannelRight->Buffer()[Skip];
395            } else {
396                finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];
397                finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];
398            }
399            finalSynthesisParameters.pSrc = pSrc;
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 332  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 341  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 356  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              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend;              PanLeftSmoother.update(AbstractEngine::PanCurve[128 - pan] * NotePanLeft);
457              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();              PanRightSmoother.update(AbstractEngine::PanCurve[pan]      * NotePanRight);
458    
459                finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend * NotePitch;
460    
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 368  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                   EG2.getSegmentType() == gig::EGADSR::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                        itKillEvent = Pool<Event>::Iterator();
527                    }*/
528                    // TODO: ^^^
529    
530                    fFinalVolume   *= pSignalUnitRack->GetEndpointUnit()->GetVolume();
531                    fFinalCutoff    = pSignalUnitRack->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff);
532                    fFinalResonance = pSignalUnitRack->GetEndpointUnit()->CalculateResonance(fFinalResonance);
533                    
534                    finalSynthesisParameters.fFinalPitch =
535                        pSignalUnitRack->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);
536                        
537              }              }
538              switch (EG2.getSegmentType()) {  
539                  case gig::EGADSR::segment_lin:              fFinalCutoff    *= NoteCutoff;
540                      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());  
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 443  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 (EG2.active()) {                  EG3.increment(1);
603                  EG2.increment(1);                  if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
604                  if (!EG2.toStageEndLeft()) EG2.update(gig::EGADSR::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) {
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] = {
627                    pMidiKeyInfo->ReverbSend,
628                    pMidiKeyInfo->ChorusSend
629                };
630                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                  if (itEvent->Param.CC.Controller == pLFO2->ExtController) {                      ProcessChannelPressureEvent(itEvent);
                     pLFO2->update(itEvent->Param.CC.Value);  
660                  }                  }
661                  if (itEvent->Param.CC.Controller == pLFO3->ExtController) {                  if (pSignalUnitRack == NULL) {
662                      pLFO3->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
663                            pLFO1->update(itEvent->Param.CC.Value);
664                        }
665                        if (itEvent->Param.CC.Controller == pLFO2->ExtController) {
666                            pLFO2->update(itEvent->Param.CC.Value);
667                        }
668                        if (itEvent->Param.CC.Controller == pLFO3->ExtController) {
669                            pLFO3->update(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 527  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 537  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                      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);
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    
754                        case Event::synth_param_attack:
755                        case Event::synth_param_decay:
756                        case Event::synth_param_release:
757                            break; // noop
758                  }                  }
759              }              }
760          }          }
# Line 568  namespace LinuxSampler { Line 781  namespace LinuxSampler {
781       * @param itNoteOffEvent - event which causes this voice to die soon       * @param itNoteOffEvent - event which causes this voice to die soon
782       */       */
783      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
784          const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());          if (pSignalUnitRack == NULL) {
785          pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;              const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
786                pEngineChannel->PortamentoPos = (float) MIDIKey() + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
787            } else {
788                // TODO:
789            }
790      }      }
791    
792      /**      /**
# Line 593  namespace LinuxSampler { Line 810  namespace LinuxSampler {
810    
811      Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {      Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {
812          PitchInfo pitch;          PitchInfo pitch;
813          double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey % 12];          double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
814    
815          // GSt behaviour: maximum transpose up is 40 semitones. If          // GSt behaviour: maximum transpose up is 40 semitones. If
816          // MIDI key is more than 40 semitones above unity note,          // MIDI key is more than 40 semitones above unity note,
817          // the transpose is not done.          // the transpose is not done.
818          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;
819    
820          pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));          pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
821          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 823  namespace LinuxSampler {
823    
824          return pitch;          return pitch;
825      }      }
826        
827        void AbstractVoice::onScaleTuningChanged() {
828            PitchInfo pitch = this->Pitch;
829            double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
830            
831            // GSt behaviour: maximum transpose up is 40 semitones. If
832            // MIDI key is more than 40 semitones above unity note,
833            // the transpose is not done.
834            if (!SmplInfo.Unpitched && (MIDIKey() - (int) RgnInfo.UnityNote) < 40) pitchbasecents += (MIDIKey() - (int) RgnInfo.UnityNote) * 100;
835            
836            pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
837            this->Pitch = pitch;
838        }
839    
840      double AbstractVoice::CalculateVolume(double velocityAttenuation) {      double AbstractVoice::CalculateVolume(double velocityAttenuation) {
841          // 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 848  namespace LinuxSampler {
848          // the volume of release triggered samples depends on note length          // the volume of release triggered samples depends on note length
849          if (Type & Voice::type_release_trigger) {          if (Type & Voice::type_release_trigger) {
850              float noteLength = float(GetEngine()->FrameTime + Delay -              float noteLength = float(GetEngine()->FrameTime + Delay -
851                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;                  GetNoteOnTime(MIDIKey()) ) / GetEngine()->SampleRate;
852    
853              volume *= GetReleaseTriggerAttenuation(noteLength);              volume *= GetReleaseTriggerAttenuation(noteLength);
854          }          }
# Line 631  namespace LinuxSampler { Line 861  namespace LinuxSampler {
861      }      }
862    
863      void AbstractVoice::EnterReleaseStage() {      void AbstractVoice::EnterReleaseStage() {
864          pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);          if (pSignalUnitRack == NULL) {
865          EG2.update(gig::EGADSR::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
866                pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
867            } else {
868                pSignalUnitRack->EnterReleaseStage();
869            }
870        }
871    
872        bool AbstractVoice::EG1Finished() {
873            if (pSignalUnitRack == NULL) {
874                return pEG1->getSegmentType() == EG::segment_end;
875            } else {
876                return !pSignalUnitRack->GetEndpointUnit()->Active();
877            }
878      }      }
879    
880  } // namespace LinuxSampler  } // namespace LinuxSampler

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

  ViewVC Help
Powered by ViewVC