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

Legend:
Removed from v.2015  
changed lines
  Added in v.3034

  ViewVC Help
Powered by ViewVC