/[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 2032 by persson, Fri Nov 20 20:13:08 2009 UTC revision 2935 by schoenebeck, Sun Jul 10 14:24:13 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;          if (volume <= 0) return -1;
134    
135          // select channel mode (mono or stereo)          // select channel mode (mono or stereo)
# Line 123  namespace LinuxSampler { Line 140  namespace LinuxSampler {
140          // get starting crossfade volume level          // get starting crossfade volume level
141          float crossfadeVolume = CalculateCrossfadeVolume(itNoteOnEvent->Param.Note.Velocity);          float crossfadeVolume = CalculateCrossfadeVolume(itNoteOnEvent->Param.Note.Velocity);
142    
143          VolumeLeft  = volume * AbstractEngine::PanCurve[64 - RgnInfo.Pan];          VolumeLeft  = volume * pKeyInfo->PanLeft;
144          VolumeRight = volume * AbstractEngine::PanCurve[64 + RgnInfo.Pan];          VolumeRight = volume * pKeyInfo->PanRight;
145    
146          float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;          float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;
147          CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);          CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);
148          VolumeSmoother.trigger(pEngineChannel->MidiVolume, subfragmentRate);          VolumeSmoother.trigger(pEngineChannel->MidiVolume, subfragmentRate);
149          PanLeftSmoother.trigger(pEngineChannel->GlobalPanLeft, subfragmentRate);          NoteVolumeSmoother.trigger(pNote ? pNote->Override.Volume : 1.f, subfragmentRate);
         PanRightSmoother.trigger(pEngineChannel->GlobalPanRight, subfragmentRate);  
   
         finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)  
         Pos = RgnInfo.SampleStartOffset;  
150    
151          // Check if the sample needs disk streaming or is too short for that          // Check if the sample needs disk streaming or is too short for that
152          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;
153          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;
154    
155            SetSampleStartOffset();
156    
157          if (DiskVoice) { // voice to be streamed from disk          if (DiskVoice) { // voice to be streamed from disk
158              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {
159                  MaxRAMPos = cachedsamples - (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH) / SmplInfo.ChannelCount; //TODO: this calculation is too pessimistic and may better be moved to Render() method, so it calculates MaxRAMPos dependent to the current demand of sample points to be rendered (e.g. in case of JACK)                  MaxRAMPos = cachedsamples - (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH) / SmplInfo.ChannelCount; //TODO: this calculation is too pessimistic and may better be moved to Render() method, so it calculates MaxRAMPos dependent to the current demand of sample points to be rendered (e.g. in case of JACK)
# Line 155  namespace LinuxSampler { Line 170  namespace LinuxSampler {
170              RAMLoop = (SmplInfo.HasLoops && (SmplInfo.LoopStart + SmplInfo.LoopLength) <= MaxRAMPos);              RAMLoop = (SmplInfo.HasLoops && (SmplInfo.LoopStart + SmplInfo.LoopLength) <= MaxRAMPos);
171    
172              if (OrderNewStream()) return -1;              if (OrderNewStream()) return -1;
173              dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s)\n", cachedsamples, SmplInfo.TotalFrameCount, MaxRAMPos, (RAMLoop) ? "yes" : "no"));              dmsg(4,("Disk voice launched (cached samples: %ld, total Samples: %d, MaxRAMPos: %lu, RAMLooping: %s)\n", cachedsamples, SmplInfo.TotalFrameCount, MaxRAMPos, (RAMLoop) ? "yes" : "no"));
174          }          }
175          else { // RAM only voice          else { // RAM only voice
176              MaxRAMPos = cachedsamples;              MaxRAMPos = cachedsamples;
# Line 171  namespace LinuxSampler { Line 186  namespace LinuxSampler {
186          }          }
187    
188          Pitch = CalculatePitchInfo(PitchBend);          Pitch = CalculatePitchInfo(PitchBend);
189            NotePitch = (pNote) ? pNote->Override.Pitch : 1.0f;
190            NoteCutoff = (pNote) ? pNote->Override.Cutoff : 1.0f;
191            NoteResonance = (pNote) ? pNote->Override.Resonance : 1.0f;
192    
193          // the length of the decay and release curves are dependent on the velocity          // the length of the decay and release curves are dependent on the velocity
194          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);
195    
196          // setup EG 1 (VCA EG)          if (pSignalUnitRack == NULL) { // setup EG 1 (VCA EG)
         {  
197              // get current value of EG1 controller              // get current value of EG1 controller
198              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);
199    
200              // calculate influence of EG1 controller on EG1's parameters              // calculate influence of EG1 controller on EG1's parameters
201              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);
202    
203              EG1.trigger (              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
204                  RgnInfo.EG1PreAttack,          } else {
205                  RgnInfo.EG1Attack * egInfo.Attack,              pSignalUnitRack->Trigger();
                 RgnInfo.EG1Hold,  
                 RgnInfo.EG1Decay1 * egInfo.Decay * velrelease,  
                 RgnInfo.EG1Decay2 * egInfo.Decay * velrelease,  
                 RgnInfo.EG1InfiniteSustain,  
                 RgnInfo.EG1Sustain,  
                 RgnInfo.EG1Release * egInfo.Release * velrelease,  
                 velocityAttenuation,  
                 GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE  
             );  
206          }          }
207    
208            const uint8_t pan = (pSignalUnitRack) ? pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan) : MIDIPan;
209            NotePanLeft  = (pNote) ? AbstractEngine::PanCurveValueNorm(pNote->Override.Pan, 0 /*left*/ ) : 1.f;
210            NotePanRight = (pNote) ? AbstractEngine::PanCurveValueNorm(pNote->Override.Pan, 1 /*right*/) : 1.f;
211            PanLeftSmoother.trigger(
212                AbstractEngine::PanCurve[128 - pan] * NotePanLeft,
213                subfragmentRate
214            );
215            PanRightSmoother.trigger(
216                AbstractEngine::PanCurve[pan] * NotePanRight,
217                subfragmentRate
218            );
219    
220  #ifdef CONFIG_INTERPOLATE_VOLUME  #ifdef CONFIG_INTERPOLATE_VOLUME
221          // setup initial volume in synthesis parameters          // setup initial volume in synthesis parameters
222      #ifdef CONFIG_PROCESS_MUTED_CHANNELS      #ifdef CONFIG_PROCESS_MUTED_CHANNELS
# Line 207  namespace LinuxSampler { Line 227  namespace LinuxSampler {
227          else          else
228      #else      #else
229          {          {
230              float finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * EG1.getLevel();              float finalVolume;
231                if (pSignalUnitRack == NULL) {
232                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();
233                } else {
234                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pSignalUnitRack->GetEndpointUnit()->GetVolume();
235                }
236    
237              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * pEngineChannel->GlobalPanLeft;              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * PanLeftSmoother.render();
238              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight;              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * PanRightSmoother.render();
239          }          }
240      #endif      #endif
241  #endif  #endif
242    
243          // setup EG 2 (VCF Cutoff EG)          if (pSignalUnitRack == NULL) {
244          {              // setup EG 2 (VCF Cutoff EG)
245              // get current value of EG2 controller              {
246              double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);                  // get current value of EG2 controller
247                    double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);
248    
249                    // calculate influence of EG2 controller on EG2's parameters
250                    EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);
251    
252                    TriggerEG2(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
253                }
254    
             // calculate influence of EG2 controller on EG2's parameters  
             EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);  
255    
256              EG2.trigger (              // setup EG 3 (VCO EG)
257                  RgnInfo.EG2PreAttack,              {
258                  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
259                  false,                  bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;
260                  RgnInfo.EG2Decay1 * egInfo.Decay * velrelease,                  float eg3depth = (bPortamento)
261                  RgnInfo.EG2Decay2 * egInfo.Decay * velrelease,                               ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey()) * 100)
262                  RgnInfo.EG2InfiniteSustain,                               : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);
263                  RgnInfo.EG2Sustain,                  float eg3time = (bPortamento)
264                  RgnInfo.EG2Release * egInfo.Release * velrelease,                              ? pEngineChannel->PortamentoTime
265                  velocityAttenuation,                              : RgnInfo.EG3Attack;
266                  GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE                  EG3.trigger(eg3depth, eg3time, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
267              );                  dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time));
268          }              }
269    
270    
271          // setup EG 3 (VCO EG)              // setup LFO 1 (VCA LFO)
272          {              InitLFO1();
273              // 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)
274              bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;              InitLFO2();
275              float eg3depth = (bPortamento)              // setup LFO 3 (VCO LFO)
276                           ? 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));  
277          }          }
278    
279    
         // setup LFO 1 (VCA LFO)  
         InitLFO1();  
         // setup LFO 2 (VCF Cutoff LFO)  
         InitLFO2();  
         // setup LFO 3 (VCO LFO)  
         InitLFO3();  
   
   
280          #if CONFIG_FORCE_FILTER          #if CONFIG_FORCE_FILTER
281          const bool bUseFilter = true;          const bool bUseFilter = true;
282          #else // use filter only if instrument file told so          #else // use filter only if instrument file told so
# Line 303  namespace LinuxSampler { Line 319  namespace LinuxSampler {
319              VCFCutoffCtrl.controller    = 0;              VCFCutoffCtrl.controller    = 0;
320              VCFResonanceCtrl.controller = 0;              VCFResonanceCtrl.controller = 0;
321          }          }
322            
323            const bool bEq =
324                pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && pEq->HasSupport();
325    
326            if (bEq) {
327                pEq->GetInChannelLeft()->Clear();
328                pEq->GetInChannelRight()->Clear();
329                pEq->RenderAudio(GetEngine()->pAudioOutputDevice->MaxSamplesPerCycle());
330            }
331    
332          return 0; // success          return 0; // success
333      }      }
334        
335        void AbstractVoice::SetSampleStartOffset() {
336            finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
337            Pos = RgnInfo.SampleStartOffset;
338        }
339    
340      /**      /**
341       *  Synthesizes the current audio fragment for this voice.       *  Synthesizes the current audio fragment for this voice.
# Line 316  namespace LinuxSampler { Line 346  namespace LinuxSampler {
346       *  @param Skip    - number of sample points to skip in output buffer       *  @param Skip    - number of sample points to skip in output buffer
347       */       */
348      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
349            bool delay = false; // Whether the voice playback should be delayed for this call
350            
351            if (pSignalUnitRack != NULL) {
352                uint delaySteps = pSignalUnitRack->GetEndpointUnit()->DelayTrigger();
353                if (delaySteps > 0) { // delay on the endpoint unit means delay of the voice playback
354                    if (delaySteps >= Samples) {
355                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(Samples);
356                        delay = true;
357                    } else {
358                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(delaySteps);
359                        Samples -= delaySteps;
360                        Skip += delaySteps;
361                    }
362                }
363            }
364            
365          AbstractEngineChannel* pChannel = pEngineChannel;          AbstractEngineChannel* pChannel = pEngineChannel;
366          finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];          MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey());
367          finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];  
368          finalSynthesisParameters.pSrc      = pSrc;          const bool bVoiceRequiresDedicatedRouting =
369                pEngineChannel->GetFxSendCount() > 0 &&
370                (pMidiKeyInfo->ReverbSend || pMidiKeyInfo->ChorusSend);
371            
372            const bool bEq =
373                pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && pEq->HasSupport();
374    
375            if (bEq) {
376                pEq->GetInChannelLeft()->Clear();
377                pEq->GetInChannelRight()->Clear();
378                finalSynthesisParameters.pOutLeft  = &pEq->GetInChannelLeft()->Buffer()[Skip];
379                finalSynthesisParameters.pOutRight = &pEq->GetInChannelRight()->Buffer()[Skip];
380                pSignalUnitRack->UpdateEqSettings(pEq);
381            } else if (bVoiceRequiresDedicatedRouting) {
382                finalSynthesisParameters.pOutLeft  = &GetEngine()->pDedicatedVoiceChannelLeft->Buffer()[Skip];
383                finalSynthesisParameters.pOutRight = &GetEngine()->pDedicatedVoiceChannelRight->Buffer()[Skip];
384            } else {
385                finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];
386                finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];
387            }
388            finalSynthesisParameters.pSrc = pSrc;
389    
390          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();
391          RTList<Event>::Iterator itNoteEvent;          RTList<Event>::Iterator itNoteEvent;
392          GetFirstEventOnKey(MIDIKey, itNoteEvent);          GetFirstEventOnKey(HostKey(), itNoteEvent);
393    
394            RTList<Event>::Iterator itGroupEvent;
395            if (pGroupEvents && !Orphan) itGroupEvent = pGroupEvents->first();
396    
397          if (itTriggerEvent) { // skip events that happened before this voice was triggered          if (itTriggerEvent) { // skip events that happened before this voice was triggered
398              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;
399                while (itGroupEvent && itGroupEvent->FragmentPos() <= Skip) ++itGroupEvent;
400    
401              // we can't simply compare the timestamp here, because note events              // we can't simply compare the timestamp here, because note events
402              // 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
403              // actual sequence the note events arrived instead (see bug #112)              // actual sequence the note events arrived instead (see bug #112)
# Line 347  namespace LinuxSampler { Line 418  namespace LinuxSampler {
418                  // drivers that use Samples < MaxSamplesPerCycle).                  // drivers that use Samples < MaxSamplesPerCycle).
419                  // End the EG1 here, at pos 0, with a shorter max fade                  // End the EG1 here, at pos 0, with a shorter max fade
420                  // out time.                  // out time.
421                  EG1.enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (pSignalUnitRack == NULL) {
422                        pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
423                    } else {
424                        pSignalUnitRack->EnterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
425                    }
426                  itKillEvent = Pool<Event>::Iterator();                  itKillEvent = Pool<Event>::Iterator();
427              } else {              } else {
428                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);
# Line 362  namespace LinuxSampler { Line 437  namespace LinuxSampler {
437              fFinalCutoff    = VCFCutoffCtrl.fvalue;              fFinalCutoff    = VCFCutoffCtrl.fvalue;
438              fFinalResonance = VCFResonanceCtrl.fvalue;              fFinalResonance = VCFResonanceCtrl.fvalue;
439    
440              // process MIDI control change and pitchbend events for this subfragment              // process MIDI control change, aftertouch and pitchbend events for this subfragment
441              processCCEvents(itCCEvent, iSubFragmentEnd);              processCCEvents(itCCEvent, iSubFragmentEnd);
442                uint8_t pan = MIDIPan;
443                if (pSignalUnitRack != NULL) pan = pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan);
444    
445              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend;              PanLeftSmoother.update(AbstractEngine::PanCurve[128 - pan] * NotePanLeft);
446              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();              PanRightSmoother.update(AbstractEngine::PanCurve[pan]      * NotePanRight);
447    
448                finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend * NotePitch;
449    
450                float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render() * NoteVolumeSmoother.render();
451  #ifdef CONFIG_PROCESS_MUTED_CHANNELS  #ifdef CONFIG_PROCESS_MUTED_CHANNELS
452              if (pChannel->GetMute()) fFinalVolume = 0;              if (pChannel->GetMute()) fFinalVolume = 0;
453  #endif  #endif
454    
455              // process transition events (note on, note off & sustain pedal)              // process transition events (note on, note off & sustain pedal)
456              processTransitionEvents(itNoteEvent, iSubFragmentEnd);              processTransitionEvents(itNoteEvent, iSubFragmentEnd);
457                processGroupEvents(itGroupEvent, iSubFragmentEnd);
458                
459                if (pSignalUnitRack == NULL) {
460                    // if the voice was killed in this subfragment, or if the
461                    // filter EG is finished, switch EG1 to fade out stage
462                    if ((itKillEvent && killPos <= iSubFragmentEnd) ||
463                        (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
464                        pEG2->getSegmentType() == EG::segment_end)) {
465                        pEG1->enterFadeOutStage();
466                        itKillEvent = Pool<Event>::Iterator();
467                    }
468    
469              // if the voice was killed in this subfragment, or if the                  // process envelope generators
470              // filter EG is finished, switch EG1 to fade out stage                  switch (pEG1->getSegmentType()) {
471              if ((itKillEvent && killPos <= iSubFragmentEnd) ||                      case EG::segment_lin:
472                  (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&                          fFinalVolume *= pEG1->processLin();
473                   EG2.getSegmentType() == gig::EGADSR::segment_end)) {                          break;
474                  EG1.enterFadeOutStage();                      case EG::segment_exp:
475                  itKillEvent = Pool<Event>::Iterator();                          fFinalVolume *= pEG1->processExp();
476                            break;
477                        case EG::segment_end:
478                            fFinalVolume *= pEG1->getLevel();
479                            break; // noop
480                        case EG::segment_pow:
481                            fFinalVolume *= pEG1->processPow();
482                            break;
483                    }
484                    switch (pEG2->getSegmentType()) {
485                        case EG::segment_lin:
486                            fFinalCutoff *= pEG2->processLin();
487                            break;
488                        case EG::segment_exp:
489                            fFinalCutoff *= pEG2->processExp();
490                            break;
491                        case EG::segment_end:
492                            fFinalCutoff *= pEG2->getLevel();
493                            break; // noop
494                        case EG::segment_pow:
495                            fFinalCutoff *= pEG2->processPow();
496                            break;
497                    }
498                    if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();
499    
500                    // process low frequency oscillators
501                    if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());
502                    if (bLFO2Enabled) fFinalCutoff *= (1.0f - pLFO2->render());
503                    if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
504                } else {
505                    // if the voice was killed in this subfragment, enter fade out stage
506                    if (itKillEvent && killPos <= iSubFragmentEnd) {
507                        pSignalUnitRack->EnterFadeOutStage();
508                        itKillEvent = Pool<Event>::Iterator();
509                    }
510                    
511                    // if the filter EG is finished, switch EG1 to fade out stage
512                    /*if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
513                        pEG2->getSegmentType() == EG::segment_end) {
514                        pEG1->enterFadeOutStage();
515                        itKillEvent = Pool<Event>::Iterator();
516                    }*/
517                    // TODO: ^^^
518    
519                    fFinalVolume   *= pSignalUnitRack->GetEndpointUnit()->GetVolume();
520                    fFinalCutoff    = pSignalUnitRack->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff);
521                    fFinalResonance = pSignalUnitRack->GetEndpointUnit()->CalculateResonance(fFinalResonance);
522                    
523                    finalSynthesisParameters.fFinalPitch =
524                        pSignalUnitRack->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);
525                        
526              }              }
527    
528              // process envelope generators              fFinalCutoff    *= NoteCutoff;
529              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());  
530    
531              // limit the pitch so we don't read outside the buffer              // limit the pitch so we don't read outside the buffer
532              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));
# Line 445  namespace LinuxSampler { Line 560  namespace LinuxSampler {
560                  fFinalVolume * VolumeRight * PanRightSmoother.render();                  fFinalVolume * VolumeRight * PanRightSmoother.render();
561  #endif  #endif
562              // render audio for one subfragment              // render audio for one subfragment
563              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);              if (!delay) RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
564    
565              // stop the rendering if volume EG is finished              if (pSignalUnitRack == NULL) {
566              if (EG1.getSegmentType() == gig::EGADSR::segment_end) break;                  // stop the rendering if volume EG is finished
567                    if (pEG1->getSegmentType() == EG::segment_end) break;
568                } else {
569                    // stop the rendering if the endpoint unit is not active
570                    if (!pSignalUnitRack->GetEndpointUnit()->Active()) break;
571                }
572    
573              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
574    
575              // increment envelopes' positions              if (pSignalUnitRack == NULL) {
576              if (EG1.active()) {                  // increment envelopes' positions
577                    if (pEG1->active()) {
578    
579                        // 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
580                        if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
581                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
582                        }
583    
584                  // 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);
585                  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);  
586                  }                  }
587                    if (pEG2->active()) {
588                  EG1.increment(1);                      pEG2->increment(1);
589                  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);
590              }                  }
591              if (EG2.active()) {                  EG3.increment(1);
592                  EG2.increment(1);                  if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
593                  if (!EG2.toStageEndLeft()) EG2.update(gig::EGADSR::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              } else {
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
595                        /*if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
596                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
597                        }*/
598                    // TODO: ^^^
599                    
600                    if (!delay) pSignalUnitRack->Increment();
601              }              }
             EG3.increment(1);  
             if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached  
602    
603              Pos = newPos;              Pos = newPos;
604              i = iSubFragmentEnd;              i = iSubFragmentEnd;
605          }          }
606            
607            if (delay) return;
608    
609            if (bVoiceRequiresDedicatedRouting) {
610                if (bEq) {
611                    pEq->RenderAudio(Samples);
612                    pEq->GetOutChannelLeft()->CopyTo(GetEngine()->pDedicatedVoiceChannelLeft, Samples);
613                    pEq->GetOutChannelRight()->CopyTo(GetEngine()->pDedicatedVoiceChannelRight, Samples);
614                }
615                optional<float> effectSendLevels[2] = {
616                    pMidiKeyInfo->ReverbSend,
617                    pMidiKeyInfo->ChorusSend
618                };
619                GetEngine()->RouteDedicatedVoiceChannels(pEngineChannel, effectSendLevels, Samples);
620            } else if (bEq) {
621                pEq->RenderAudio(Samples);
622                pEq->GetOutChannelLeft()->MixTo(pChannel->pChannelLeft, Samples);
623                pEq->GetOutChannelRight()->MixTo(pChannel->pChannelRight, Samples);
624            }
625      }      }
626        
627      /**      /**
628       * Process given list of MIDI control change and pitch bend events for       * Process given list of MIDI control change, aftertouch and pitch bend
629       * the given time.       * events for the given time.
630       *       *
631       * @param itEvent - iterator pointing to the next event to be processed       * @param itEvent - iterator pointing to the next event to be processed
632       * @param End     - youngest time stamp where processing should be stopped       * @param End     - youngest time stamp where processing should be stopped
# Line 491  namespace LinuxSampler { Line 640  namespace LinuxSampler {
640                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
641                      processResonanceEvent(itEvent);                      processResonanceEvent(itEvent);
642                  }                  }
643                  if (itEvent->Param.CC.Controller == pLFO1->ExtController) {                  if (pSignalUnitRack == NULL) {
644                      pLFO1->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
645                  }                          pLFO1->update(itEvent->Param.CC.Value);
646                  if (itEvent->Param.CC.Controller == pLFO2->ExtController) {                      }
647                      pLFO2->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO2->ExtController) {
648                  }                          pLFO2->update(itEvent->Param.CC.Value);
649                  if (itEvent->Param.CC.Controller == pLFO3->ExtController) {                      }
650                      pLFO3->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO3->ExtController) {
651                            pLFO3->update(itEvent->Param.CC.Value);
652                        }
653                  }                  }
654                  if (itEvent->Param.CC.Controller == 7) { // volume                  if (itEvent->Param.CC.Controller == 7) { // volume
655                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);
656                  } else if (itEvent->Param.CC.Controller == 10) { // panpot                  } else if (itEvent->Param.CC.Controller == 10) { // panpot
657                      PanLeftSmoother.update(AbstractEngine::PanCurve[128 - itEvent->Param.CC.Value]);                      MIDIPan = CalculatePan(itEvent->Param.CC.Value);
                     PanRightSmoother.update(AbstractEngine::PanCurve[itEvent->Param.CC.Value]);  
658                  }                  }
659              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event
660                  processPitchEvent(itEvent);                  processPitchEvent(itEvent);
661                } else if (itEvent->Type == Event::type_channel_pressure) {
662                    ProcessChannelPressureEvent(itEvent);
663                } else if (itEvent->Type == Event::type_note_pressure) {
664                    ProcessPolyphonicKeyPressureEvent(itEvent);
665              }              }
666    
667              ProcessCCEvent(itEvent);              ProcessCCEvent(itEvent);
668                if (pSignalUnitRack != NULL) {
669                    pSignalUnitRack->ProcessCCEvent(itEvent);
670                }
671          }          }
672      }      }
673    
# Line 529  namespace LinuxSampler { Line 686  namespace LinuxSampler {
686      }      }
687    
688      /**      /**
689       * 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
690       * for the given time.       * note synthesis parameter events for the given time.
691       *       *
692       * @param itEvent - iterator pointing to the next event to be processed       * @param itEvent - iterator pointing to the next event to be processed
693       * @param End     - youngest time stamp where processing should be stopped       * @param End     - youngest time stamp where processing should be stopped
694       */       */
695      void AbstractVoice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {      void AbstractVoice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {
696          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
697              if (itEvent->Type == Event::type_release) {              // some voice types ignore note off
698                  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))) {
699                  EG2.update(gig::EGADSR::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (itEvent->Type == Event::type_release) {
700              } else if (itEvent->Type == Event::type_cancel_release) {                      EnterReleaseStage();
701                  EG1.update(gig::EGADSR::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  } else if (itEvent->Type == Event::type_cancel_release) {
702                  EG2.update(gig::EGADSR::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                      if (pSignalUnitRack == NULL) {
703                            pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
704                            pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
705                        } else {
706                            pSignalUnitRack->CancelRelease();
707                        }
708                    }
709                }
710                // process synthesis parameter events (caused by built-in realt-time instrument script functions)
711                if (itEvent->Type == Event::type_note_synth_param && pNote &&
712                    pEngineChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID ) == pNote)
713                {
714                    switch (itEvent->Param.NoteSynthParam.Type) {
715                        case Event::synth_param_volume:
716                            NoteVolumeSmoother.update(itEvent->Param.NoteSynthParam.AbsValue);
717                            break;
718                        case Event::synth_param_pitch:
719                            NotePitch = itEvent->Param.NoteSynthParam.AbsValue;
720                            break;
721                        case Event::synth_param_pan:
722                            NotePanLeft  = AbstractEngine::PanCurveValueNorm(itEvent->Param.NoteSynthParam.AbsValue, 0 /*left*/);
723                            NotePanRight = AbstractEngine::PanCurveValueNorm(itEvent->Param.NoteSynthParam.AbsValue, 1 /*right*/);
724                            break;
725                        case Event::synth_param_cutoff:
726                            NoteCutoff = itEvent->Param.NoteSynthParam.AbsValue;
727                            break;
728                        case Event::synth_param_resonance:
729                            NoteResonance = itEvent->Param.NoteSynthParam.AbsValue;
730                            break;
731                    }
732              }              }
733          }          }
734      }      }
735    
736        /**
737         * Process given list of events aimed at all voices in a key group.
738         *
739         * @param itEvent - iterator pointing to the next event to be processed
740         * @param End     - youngest time stamp where processing should be stopped
741         */
742        void AbstractVoice::processGroupEvents(RTList<Event>::Iterator& itEvent, uint End) {
743            for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
744                ProcessGroupEvent(itEvent);
745            }
746        }
747    
748      /** @brief Update current portamento position.      /** @brief Update current portamento position.
749       *       *
750       * 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 556  namespace LinuxSampler { Line 754  namespace LinuxSampler {
754       * @param itNoteOffEvent - event which causes this voice to die soon       * @param itNoteOffEvent - event which causes this voice to die soon
755       */       */
756      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
757          const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());          if (pSignalUnitRack == NULL) {
758          pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;              const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
759                pEngineChannel->PortamentoPos = (float) MIDIKey() + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
760            } else {
761                // TODO:
762            }
763      }      }
764    
765      /**      /**
# Line 581  namespace LinuxSampler { Line 783  namespace LinuxSampler {
783    
784      Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {      Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {
785          PitchInfo pitch;          PitchInfo pitch;
786          double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey % 12];          double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
787    
788          // GSt behaviour: maximum transpose up is 40 semitones. If          // GSt behaviour: maximum transpose up is 40 semitones. If
789          // MIDI key is more than 40 semitones above unity note,          // MIDI key is more than 40 semitones above unity note,
790          // the transpose is not done.          // the transpose is not done.
791          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;
792    
793          pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));          pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
794          pitch.PitchBendRange = 1.0 / 8192.0 * 100.0 * InstrInfo.PitchbendRange;          pitch.PitchBendRange = 1.0 / 8192.0 * 100.0 * InstrInfo.PitchbendRange;
# Line 594  namespace LinuxSampler { Line 796  namespace LinuxSampler {
796    
797          return pitch;          return pitch;
798      }      }
799        
800        void AbstractVoice::onScaleTuningChanged() {
801            PitchInfo pitch = this->Pitch;
802            double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
803            
804            // GSt behaviour: maximum transpose up is 40 semitones. If
805            // MIDI key is more than 40 semitones above unity note,
806            // the transpose is not done.
807            if (!SmplInfo.Unpitched && (MIDIKey() - (int) RgnInfo.UnityNote) < 40) pitchbasecents += (MIDIKey() - (int) RgnInfo.UnityNote) * 100;
808            
809            pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
810            this->Pitch = pitch;
811        }
812    
813      double AbstractVoice::CalculateVolume(double velocityAttenuation) {      double AbstractVoice::CalculateVolume(double velocityAttenuation) {
814          // For 16 bit samples, we downscale by 32768 to convert from          // For 16 bit samples, we downscale by 32768 to convert from
# Line 604  namespace LinuxSampler { Line 819  namespace LinuxSampler {
819          volume *= GetSampleAttenuation() * pEngineChannel->GlobalVolume * GLOBAL_VOLUME;          volume *= GetSampleAttenuation() * pEngineChannel->GlobalVolume * GLOBAL_VOLUME;
820    
821          // the volume of release triggered samples depends on note length          // the volume of release triggered samples depends on note length
822          if (Type == Voice::type_release_trigger) {          if (Type & Voice::type_release_trigger) {
823              float noteLength = float(GetEngine()->FrameTime + Delay -              float noteLength = float(GetEngine()->FrameTime + Delay -
824                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;                  GetNoteOnTime(MIDIKey()) ) / GetEngine()->SampleRate;
825    
826              float attenuation = 1 - 0.01053 * (256 >> RgnInfo.ReleaseTriggerDecay) * noteLength;              volume *= GetReleaseTriggerAttenuation(noteLength);
             volume *= attenuation;  
827          }          }
828    
829          return volume;          return volume;
830      }      }
831    
832        float AbstractVoice::GetReleaseTriggerAttenuation(float noteLength) {
833            return 1 - RgnInfo.ReleaseTriggerDecay * noteLength;
834        }
835    
836        void AbstractVoice::EnterReleaseStage() {
837            if (pSignalUnitRack == NULL) {
838                pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
839                pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
840            } else {
841                pSignalUnitRack->EnterReleaseStage();
842            }
843        }
844    
845        bool AbstractVoice::EG1Finished() {
846            if (pSignalUnitRack == NULL) {
847                return pEG1->getSegmentType() == EG::segment_end;
848            } else {
849                return !pSignalUnitRack->GetEndpointUnit()->Active();
850            }
851        }
852    
853  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.2032  
changed lines
  Added in v.2935

  ViewVC Help
Powered by ViewVC