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

Legend:
Removed from v.2055  
changed lines
  Added in v.3188

  ViewVC Help
Powered by ViewVC