/[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 2205 by iliev, Mon Jul 11 17:52:01 2011 UTC revision 3251 by schoenebeck, Mon May 29 22:19:19 2017 UTC
# Line 4  Line 4 
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2011 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *
8     *   Copyright (C) 2013-2017 Christian Schoenebeck and Andreas Persson     *
9   *                                                                         *   *                                                                         *
10   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
11   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 26  Line 27 
27    
28  namespace LinuxSampler {  namespace LinuxSampler {
29    
30      AbstractVoice::AbstractVoice() {      AbstractVoice::AbstractVoice(SignalUnitRack* pRack): pSignalUnitRack(pRack) {
31          pEngineChannel = NULL;          pEngineChannel = NULL;
32          pLFO1 = new LFOUnsigned(1.0f);  // amplitude LFO (0..1 range)          pLFO1 = new LFOUnsigned(1.0f);  // amplitude LFO (0..1 range)
33          pLFO2 = new LFOUnsigned(1.0f);  // filter LFO (0..1 range)          pLFO2 = new LFOUnsigned(1.0f);  // filter LFO (0..1 range)
# Line 43  namespace LinuxSampler { Line 44  namespace LinuxSampler {
44    
45          finalSynthesisParameters.filterLeft.Reset();          finalSynthesisParameters.filterLeft.Reset();
46          finalSynthesisParameters.filterRight.Reset();          finalSynthesisParameters.filterRight.Reset();
47            
48            pEq          = NULL;
49            bEqSupport   = false;
50      }      }
51    
52      AbstractVoice::~AbstractVoice() {      AbstractVoice::~AbstractVoice() {
53          if (pLFO1) delete pLFO1;          if (pLFO1) delete pLFO1;
54          if (pLFO2) delete pLFO2;          if (pLFO2) delete pLFO2;
55          if (pLFO3) delete pLFO3;          if (pLFO3) delete pLFO3;
56            
57            if(pEq != NULL) delete pEq;
58        }
59                
60        void AbstractVoice::CreateEq() {
61            if(!bEqSupport) return;
62            if(pEq != NULL) delete pEq;
63            pEq = new EqSupport;
64            pEq->InitEffect(GetEngine()->pAudioOutputDevice);
65      }      }
66    
67      /**      /**
# Line 98  namespace LinuxSampler { Line 111  namespace LinuxSampler {
111          #endif // CONFIG_DEVMODE          #endif // CONFIG_DEVMODE
112    
113          Type            = VoiceType;          Type            = VoiceType;
114          MIDIKey         = itNoteOnEvent->Param.Note.Key;          pNote           = pEngineChannel->pEngine->NoteByID( itNoteOnEvent->Param.Note.ID );
115          PlaybackState   = playback_state_init; // mark voice as triggered, but no audio rendered yet          PlaybackState   = playback_state_init; // mark voice as triggered, but no audio rendered yet
116          Delay           = itNoteOnEvent->FragmentPos();          Delay           = itNoteOnEvent->FragmentPos();
117          itTriggerEvent  = itNoteOnEvent;          itTriggerEvent  = itNoteOnEvent;
118          itKillEvent     = Pool<Event>::Iterator();          itKillEvent     = Pool<Event>::Iterator();
119          MidiKeyBase* pKeyInfo = GetMidiKeyInfo(MIDIKey);          MidiKeyBase* pKeyInfo = GetMidiKeyInfo(MIDIKey());
120    
121          pGroupEvents = iKeyGroup ? pEngineChannel->ActiveKeyGroups[iKeyGroup] : 0;          pGroupEvents = iKeyGroup ? pEngineChannel->ActiveKeyGroups[iKeyGroup] : 0;
122    
# Line 111  namespace LinuxSampler { Line 124  namespace LinuxSampler {
124          RgnInfo    = GetRegionInfo();          RgnInfo    = GetRegionInfo();
125          InstrInfo  = GetInstrumentInfo();          InstrInfo  = GetInstrumentInfo();
126                    
127            MIDIPan    = CalculatePan(pEngineChannel->iLastPanRequest);
128    
129          AboutToTrigger();          AboutToTrigger();
130    
131          // calculate volume          // calculate volume
132          const double velocityAttenuation = GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity);          const double velocityAttenuation = GetVelocityAttenuation(MIDIVelocity());
133          float volume = CalculateVolume(velocityAttenuation) * pKeyInfo->Volume;          float volume = CalculateVolume(velocityAttenuation) * pKeyInfo->Volume;
134          if (volume <= 0) return -1;          if (volume <= 0) return -1;
135    
# Line 124  namespace LinuxSampler { Line 139  namespace LinuxSampler {
139          SYNTHESIS_MODE_SET_BITDEPTH24(SynthesisMode, SmplInfo.BitDepth == 24);          SYNTHESIS_MODE_SET_BITDEPTH24(SynthesisMode, SmplInfo.BitDepth == 24);
140    
141          // get starting crossfade volume level          // get starting crossfade volume level
142          float crossfadeVolume = CalculateCrossfadeVolume(itNoteOnEvent->Param.Note.Velocity);          float crossfadeVolume = CalculateCrossfadeVolume(MIDIVelocity());
143    
144          VolumeLeft  = volume * pKeyInfo->PanLeft  * AbstractEngine::PanCurve[64 - RgnInfo.Pan];          VolumeLeft  = volume * pKeyInfo->PanLeft;
145          VolumeRight = volume * pKeyInfo->PanRight * AbstractEngine::PanCurve[64 + RgnInfo.Pan];          VolumeRight = volume * pKeyInfo->PanRight;
146    
147          float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;          // this rate is used for rather mellow volume fades
148            const float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;
149            // this rate is used for very fast volume fades
150            const float quickRampRate = RTMath::Min(subfragmentRate, GetEngine()->SampleRate * 0.001f /* 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.setCurveOnly(pNote ? pNote->Override.VolumeCurve : DEFAULT_FADE_CURVE);
155            NoteVolume.setCurrentValue(pNote ? pNote->Override.Volume : 1.f);
156            NoteVolume.setDefaultDuration(pNote ? pNote->Override.VolumeTime : DEFAULT_NOTE_VOLUME_TIME_S);
157    
158          // 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
159          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;
160          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;
161    
162            SetSampleStartOffset();
163    
164          if (DiskVoice) { // voice to be streamed from disk          if (DiskVoice) { // voice to be streamed from disk
165              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {
166                  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 158  namespace LinuxSampler { Line 177  namespace LinuxSampler {
177              RAMLoop = (SmplInfo.HasLoops && (SmplInfo.LoopStart + SmplInfo.LoopLength) <= MaxRAMPos);              RAMLoop = (SmplInfo.HasLoops && (SmplInfo.LoopStart + SmplInfo.LoopLength) <= MaxRAMPos);
178    
179              if (OrderNewStream()) return -1;              if (OrderNewStream()) return -1;
180              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"));
181          }          }
182          else { // RAM only voice          else { // RAM only voice
183              MaxRAMPos = cachedsamples;              MaxRAMPos = cachedsamples;
# Line 174  namespace LinuxSampler { Line 193  namespace LinuxSampler {
193          }          }
194    
195          Pitch = CalculatePitchInfo(PitchBend);          Pitch = CalculatePitchInfo(PitchBend);
196            NotePitch.setCurveOnly(pNote ? pNote->Override.PitchCurve : DEFAULT_FADE_CURVE);
197            NotePitch.setCurrentValue(pNote ? pNote->Override.Pitch : 1.0f);
198            NotePitch.setDefaultDuration(pNote ? pNote->Override.PitchTime : DEFAULT_NOTE_PITCH_TIME_S);
199            NoteCutoff = (pNote) ? pNote->Override.Cutoff : 1.0f;
200            NoteResonance = (pNote) ? pNote->Override.Resonance : 1.0f;
201    
202          // 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
203          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);          const double velrelease = 1 / GetVelocityRelease(MIDIVelocity());
204    
205          if (GetSignalUnitRack() == NULL) { // setup EG 1 (VCA EG)          if (pSignalUnitRack == NULL) { // setup EG 1 (VCA EG)
206              // get current value of EG1 controller              // get current value of EG1 controller
207              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);              double eg1controllervalue = GetEG1ControllerValue(MIDIVelocity());
208    
209              // calculate influence of EG1 controller on EG1's parameters              // calculate influence of EG1 controller on EG1's parameters
210              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);
211    
212              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);              if (pNote) {
213                    egInfo.Attack  *= pNote->Override.Attack;
214                    egInfo.Decay   *= pNote->Override.Decay;
215                    egInfo.Release *= pNote->Override.Release;
216                }
217    
218                TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, MIDIVelocity());
219          } else {          } else {
220              GetSignalUnitRack()->Trigger();              pSignalUnitRack->Trigger();
221          }          }
222    
223            const uint8_t pan = (pSignalUnitRack) ? pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan) : MIDIPan;
224            NotePanLeft  = (pNote) ? AbstractEngine::PanCurveValueNorm(pNote->Override.Pan, 0 /*left*/ ) : 1.f;
225            NotePanRight = (pNote) ? AbstractEngine::PanCurveValueNorm(pNote->Override.Pan, 1 /*right*/) : 1.f;
226            PanLeftSmoother.trigger(
227                AbstractEngine::PanCurve[128 - pan] * NotePanLeft,
228                quickRampRate //NOTE: maybe we should have 2 separate pan smoothers, one for MIDI CC10 (with slow rate) and one for instrument script change_pan() calls (with fast rate)
229            );
230            PanRightSmoother.trigger(
231                AbstractEngine::PanCurve[pan] * NotePanRight,
232                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)
233            );
234    
235  #ifdef CONFIG_INTERPOLATE_VOLUME  #ifdef CONFIG_INTERPOLATE_VOLUME
236          // setup initial volume in synthesis parameters          // setup initial volume in synthesis parameters
237      #ifdef CONFIG_PROCESS_MUTED_CHANNELS      #ifdef CONFIG_PROCESS_MUTED_CHANNELS
# Line 201  namespace LinuxSampler { Line 243  namespace LinuxSampler {
243      #else      #else
244          {          {
245              float finalVolume;              float finalVolume;
246              if (GetSignalUnitRack() == NULL) {              if (pSignalUnitRack == NULL) {
247                  finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();                  finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();
248              } else {              } else {
249                  finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * GetSignalUnitRack()->GetEndpointUnit()->GetVolume();                  finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pSignalUnitRack->GetEndpointUnit()->GetVolume();
250              }              }
251    
252              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * pEngineChannel->GlobalPanLeft;              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * PanLeftSmoother.render();
253              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight;              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * PanRightSmoother.render();
254          }          }
255      #endif      #endif
256  #endif  #endif
257    
258          if (GetSignalUnitRack() == NULL) {          if (pSignalUnitRack == NULL) {
259              // setup EG 2 (VCF Cutoff EG)              // setup EG 2 (VCF Cutoff EG)
260              {              {
261                  // get current value of EG2 controller                  // get current value of EG2 controller
262                  double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);                  double eg2controllervalue = GetEG2ControllerValue(MIDIVelocity());
263    
264                  // calculate influence of EG2 controller on EG2's parameters                  // calculate influence of EG2 controller on EG2's parameters
265                  EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);                  EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);
266    
267                  TriggerEG2(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);                  TriggerEG2(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, MIDIVelocity());
268              }              }
269    
270    
# Line 231  namespace LinuxSampler { Line 273  namespace LinuxSampler {
273                  // if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch                  // if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch
274                  bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;                  bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;
275                  float eg3depth = (bPortamento)                  float eg3depth = (bPortamento)
276                               ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100)                               ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey()) * 100)
277                               : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);                               : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);
278                  float eg3time = (bPortamento)                  float eg3time = (bPortamento)
279                              ? pEngineChannel->PortamentoTime                              ? pEngineChannel->PortamentoTime
# Line 281  namespace LinuxSampler { Line 323  namespace LinuxSampler {
323              VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller];              VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller];
324    
325              // calculate cutoff frequency              // calculate cutoff frequency
326              CutoffBase = CalculateCutoffBase(itNoteOnEvent->Param.Note.Velocity);              CutoffBase = CalculateCutoffBase(MIDIVelocity());
327    
328              VCFCutoffCtrl.fvalue = CalculateFinalCutoff(CutoffBase);              VCFCutoffCtrl.fvalue = CalculateFinalCutoff(CutoffBase);
329    
# Line 292  namespace LinuxSampler { Line 334  namespace LinuxSampler {
334              VCFCutoffCtrl.controller    = 0;              VCFCutoffCtrl.controller    = 0;
335              VCFResonanceCtrl.controller = 0;              VCFResonanceCtrl.controller = 0;
336          }          }
337            
338            const bool bEq =
339                pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && pEq->HasSupport();
340    
341            if (bEq) {
342                pEq->GetInChannelLeft()->Clear();
343                pEq->GetInChannelRight()->Clear();
344                pEq->RenderAudio(GetEngine()->pAudioOutputDevice->MaxSamplesPerCycle());
345            }
346    
347          return 0; // success          return 0; // success
348      }      }
349        
350        void AbstractVoice::SetSampleStartOffset() {
351            double pos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample
352    
353            // if another sample playback start position was requested by instrument
354            // script (built-in script function play_note())
355            if (pNote && pNote->Override.SampleOffset >= 0) {
356                double overridePos =
357                    double(SmplInfo.SampleRate) * double(pNote->Override.SampleOffset) / 1000000.0;
358                if (overridePos < SmplInfo.TotalFrameCount)
359                    pos = overridePos;
360            }
361    
362            finalSynthesisParameters.dPos = pos;
363            Pos = pos;
364        }
365    
366      /**      /**
367       *  Synthesizes the current audio fragment for this voice.       *  Synthesizes the current audio fragment for this voice.
# Line 305  namespace LinuxSampler { Line 372  namespace LinuxSampler {
372       *  @param Skip    - number of sample points to skip in output buffer       *  @param Skip    - number of sample points to skip in output buffer
373       */       */
374      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
375            bool delay = false; // Whether the voice playback should be delayed for this call
376            
377            if (pSignalUnitRack != NULL) {
378                uint delaySteps = pSignalUnitRack->GetEndpointUnit()->DelayTrigger();
379                if (delaySteps > 0) { // delay on the endpoint unit means delay of the voice playback
380                    if (delaySteps >= Samples) {
381                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(Samples);
382                        delay = true;
383                    } else {
384                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(delaySteps);
385                        Samples -= delaySteps;
386                        Skip += delaySteps;
387                    }
388                }
389            }
390            
391          AbstractEngineChannel* pChannel = pEngineChannel;          AbstractEngineChannel* pChannel = pEngineChannel;
392          MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey);          MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey());
393    
394          const bool bVoiceRequiresDedicatedRouting =          const bool bVoiceRequiresDedicatedRouting =
395              pEngineChannel->GetFxSendCount() > 0 &&              pEngineChannel->GetFxSendCount() > 0 &&
396              (pMidiKeyInfo->ReverbSend || pMidiKeyInfo->ChorusSend);              (pMidiKeyInfo->ReverbSend || pMidiKeyInfo->ChorusSend);
397            
398            const bool bEq =
399                pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && pEq->HasSupport();
400    
401          if (bVoiceRequiresDedicatedRouting) {          if (bEq) {
402                pEq->GetInChannelLeft()->Clear();
403                pEq->GetInChannelRight()->Clear();
404                finalSynthesisParameters.pOutLeft  = &pEq->GetInChannelLeft()->Buffer()[Skip];
405                finalSynthesisParameters.pOutRight = &pEq->GetInChannelRight()->Buffer()[Skip];
406                pSignalUnitRack->UpdateEqSettings(pEq);
407            } else if (bVoiceRequiresDedicatedRouting) {
408              finalSynthesisParameters.pOutLeft  = &GetEngine()->pDedicatedVoiceChannelLeft->Buffer()[Skip];              finalSynthesisParameters.pOutLeft  = &GetEngine()->pDedicatedVoiceChannelLeft->Buffer()[Skip];
409              finalSynthesisParameters.pOutRight = &GetEngine()->pDedicatedVoiceChannelRight->Buffer()[Skip];              finalSynthesisParameters.pOutRight = &GetEngine()->pDedicatedVoiceChannelRight->Buffer()[Skip];
410          } else {          } else {
# Line 323  namespace LinuxSampler { Line 415  namespace LinuxSampler {
415    
416          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();
417          RTList<Event>::Iterator itNoteEvent;          RTList<Event>::Iterator itNoteEvent;
418          GetFirstEventOnKey(MIDIKey, itNoteEvent);          GetFirstEventOnKey(HostKey(), itNoteEvent);
419    
420          RTList<Event>::Iterator itGroupEvent;          RTList<Event>::Iterator itGroupEvent;
421          if (pGroupEvents) itGroupEvent = pGroupEvents->first();          if (pGroupEvents && !Orphan) itGroupEvent = pGroupEvents->first();
422    
423          if (itTriggerEvent) { // skip events that happened before this voice was triggered          if (itTriggerEvent) { // skip events that happened before this voice was triggered
424              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;
# Line 343  namespace LinuxSampler { Line 435  namespace LinuxSampler {
435              }              }
436          }          }
437    
438          uint killPos;          uint killPos = 0;
439          if (itKillEvent) {          if (itKillEvent) {
440              int maxFadeOutPos = Samples - GetEngine()->GetMinFadeOutSamples();              int maxFadeOutPos = Samples - GetEngine()->GetMinFadeOutSamples();
441              if (maxFadeOutPos < 0) {              if (maxFadeOutPos < 0) {
# Line 352  namespace LinuxSampler { Line 444  namespace LinuxSampler {
444                  // drivers that use Samples < MaxSamplesPerCycle).                  // drivers that use Samples < MaxSamplesPerCycle).
445                  // End the EG1 here, at pos 0, with a shorter max fade                  // End the EG1 here, at pos 0, with a shorter max fade
446                  // out time.                  // out time.
447                  if (GetSignalUnitRack() == NULL) {                  if (pSignalUnitRack == NULL) {
448                      pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                      pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
449                  } else {                  } else {
450                      // TODO:                      pSignalUnitRack->EnterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
451                  }                  }
452                  itKillEvent = Pool<Event>::Iterator();                  itKillEvent = Pool<Event>::Iterator();
453              } else {              } else {
# Line 371  namespace LinuxSampler { Line 463  namespace LinuxSampler {
463              fFinalCutoff    = VCFCutoffCtrl.fvalue;              fFinalCutoff    = VCFCutoffCtrl.fvalue;
464              fFinalResonance = VCFResonanceCtrl.fvalue;              fFinalResonance = VCFResonanceCtrl.fvalue;
465    
466              // process MIDI control change and pitchbend events for this subfragment              // process MIDI control change, aftertouch and pitchbend events for this subfragment
467              processCCEvents(itCCEvent, iSubFragmentEnd);              processCCEvents(itCCEvent, iSubFragmentEnd);
468                uint8_t pan = MIDIPan;
469                if (pSignalUnitRack != NULL) pan = pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan);
470    
471                PanLeftSmoother.update(AbstractEngine::PanCurve[128 - pan] * NotePanLeft);
472                PanRightSmoother.update(AbstractEngine::PanCurve[pan]      * NotePanRight);
473    
474                finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend * NotePitch.render();
475    
476              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend;              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render() * NoteVolume.render();
             float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();  
477  #ifdef CONFIG_PROCESS_MUTED_CHANNELS  #ifdef CONFIG_PROCESS_MUTED_CHANNELS
478              if (pChannel->GetMute()) fFinalVolume = 0;              if (pChannel->GetMute()) fFinalVolume = 0;
479  #endif  #endif
# Line 383  namespace LinuxSampler { Line 481  namespace LinuxSampler {
481              // process transition events (note on, note off & sustain pedal)              // process transition events (note on, note off & sustain pedal)
482              processTransitionEvents(itNoteEvent, iSubFragmentEnd);              processTransitionEvents(itNoteEvent, iSubFragmentEnd);
483              processGroupEvents(itGroupEvent, iSubFragmentEnd);              processGroupEvents(itGroupEvent, iSubFragmentEnd);
484                
485              if (GetSignalUnitRack() == NULL) {              if (pSignalUnitRack == NULL) {
486                  // if the voice was killed in this subfragment, or if the                  // if the voice was killed in this subfragment, or if the
487                  // filter EG is finished, switch EG1 to fade out stage                  // filter EG is finished, switch EG1 to fade out stage
488                  if ((itKillEvent && killPos <= iSubFragmentEnd) ||                  if ((itKillEvent && killPos <= iSubFragmentEnd) ||
# Line 427  namespace LinuxSampler { Line 525  namespace LinuxSampler {
525    
526                  // process low frequency oscillators                  // process low frequency oscillators
527                  if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());                  if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());
528                  if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();                  if (bLFO2Enabled) fFinalCutoff *= (1.0f - pLFO2->render());
529                  if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());                  if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
530              } else {              } else {
531                  // if the voice was killed in this subfragment, or if the                  // if the voice was killed in this subfragment, enter fade out stage
532                  // filter EG is finished, switch EG1 to fade out stage                  if (itKillEvent && killPos <= iSubFragmentEnd) {
533                  /*if ((itKillEvent && killPos <= iSubFragmentEnd) ||                      pSignalUnitRack->EnterFadeOutStage();
534                      (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&                      itKillEvent = Pool<Event>::Iterator();
535                      pEG2->getSegmentType() == EG::segment_end)) {                  }
536                    
537                    // if the filter EG is finished, switch EG1 to fade out stage
538                    /*if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
539                        pEG2->getSegmentType() == EG::segment_end) {
540                      pEG1->enterFadeOutStage();                      pEG1->enterFadeOutStage();
541                      itKillEvent = Pool<Event>::Iterator();                      itKillEvent = Pool<Event>::Iterator();
542                  }*/                  }*/
543                  // TODO: ^^^                  // TODO: ^^^
544    
545                  fFinalVolume   *= GetSignalUnitRack()->GetEndpointUnit()->GetVolume();                  fFinalVolume   *= pSignalUnitRack->GetEndpointUnit()->GetVolume();
546                  fFinalCutoff    = GetSignalUnitRack()->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff);                  fFinalCutoff    = pSignalUnitRack->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff);
547                  fFinalResonance = GetSignalUnitRack()->GetEndpointUnit()->CalculateResonance(fFinalResonance);                  fFinalResonance = pSignalUnitRack->GetEndpointUnit()->CalculateResonance(fFinalResonance);
548                                    
549                  finalSynthesisParameters.fFinalPitch =                  finalSynthesisParameters.fFinalPitch =
550                      GetSignalUnitRack()->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);                      pSignalUnitRack->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);
551                                            
552              }              }
553                
554                fFinalCutoff    *= NoteCutoff;
555                fFinalResonance *= NoteResonance;
556    
557              // limit the pitch so we don't read outside the buffer              // limit the pitch so we don't read outside the buffer
558              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));
559    
# Line 481  namespace LinuxSampler { Line 586  namespace LinuxSampler {
586                  fFinalVolume * VolumeRight * PanRightSmoother.render();                  fFinalVolume * VolumeRight * PanRightSmoother.render();
587  #endif  #endif
588              // render audio for one subfragment              // render audio for one subfragment
589              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);              if (!delay) RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
590    
591              if (GetSignalUnitRack() == NULL) {              if (pSignalUnitRack == NULL) {
592                  // stop the rendering if volume EG is finished                  // stop the rendering if volume EG is finished
593                  if (pEG1->getSegmentType() == EG::segment_end) break;                  if (pEG1->getSegmentType() == EG::segment_end) break;
594              } else {              } else {
595                  // stop the rendering if the endpoint unit is not active                  // stop the rendering if the endpoint unit is not active
596                  if (!GetSignalUnitRack()->GetEndpointUnit()->Active()) break;                  if (!pSignalUnitRack->GetEndpointUnit()->Active()) break;
597              }              }
598    
599              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
600    
601              if (GetSignalUnitRack() == NULL) {              if (pSignalUnitRack == NULL) {
602                  // increment envelopes' positions                  // increment envelopes' positions
603                  if (pEG1->active()) {                  if (pEG1->active()) {
604    
# Line 518  namespace LinuxSampler { Line 623  namespace LinuxSampler {
623                      }*/                      }*/
624                  // TODO: ^^^                  // TODO: ^^^
625                                    
626                  GetSignalUnitRack()->Increment();                  if (!delay) pSignalUnitRack->Increment();
627              }              }
628    
629              Pos = newPos;              Pos = newPos;
630              i = iSubFragmentEnd;              i = iSubFragmentEnd;
631          }          }
632            
633            if (delay) return;
634    
635          if (bVoiceRequiresDedicatedRouting) {          if (bVoiceRequiresDedicatedRouting) {
636                if (bEq) {
637                    pEq->RenderAudio(Samples);
638                    pEq->GetOutChannelLeft()->CopyTo(GetEngine()->pDedicatedVoiceChannelLeft, Samples);
639                    pEq->GetOutChannelRight()->CopyTo(GetEngine()->pDedicatedVoiceChannelRight, Samples);
640                }
641              optional<float> effectSendLevels[2] = {              optional<float> effectSendLevels[2] = {
642                  pMidiKeyInfo->ReverbSend,                  pMidiKeyInfo->ReverbSend,
643                  pMidiKeyInfo->ChorusSend                  pMidiKeyInfo->ChorusSend
644              };              };
645              GetEngine()->RouteDedicatedVoiceChannels(pEngineChannel, effectSendLevels, Samples);              GetEngine()->RouteDedicatedVoiceChannels(pEngineChannel, effectSendLevels, Samples);
646            } else if (bEq) {
647                pEq->RenderAudio(Samples);
648                pEq->GetOutChannelLeft()->MixTo(pChannel->pChannelLeft, Samples);
649                pEq->GetOutChannelRight()->MixTo(pChannel->pChannelRight, Samples);
650          }          }
651      }      }
652    
653      /**      /**
654       * Process given list of MIDI control change and pitch bend events for       * Process given list of MIDI control change, aftertouch and pitch bend
655       * the given time.       * events for the given time.
656       *       *
657       * @param itEvent - iterator pointing to the next event to be processed       * @param itEvent - iterator pointing to the next event to be processed
658       * @param End     - youngest time stamp where processing should be stopped       * @param End     - youngest time stamp where processing should be stopped
659       */       */
660      void AbstractVoice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) {      void AbstractVoice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) {
661          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
662              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)
663                    && itEvent->Param.CC.Controller) // if (valid) MIDI control change event
664                {
665                  if (itEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {                  if (itEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {
666                      ProcessCutoffEvent(itEvent);                      ProcessCutoffEvent(itEvent);
667                  }                  }
668                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
669                      processResonanceEvent(itEvent);                      processResonanceEvent(itEvent);
670                  }                  }
671                  if (GetSignalUnitRack() == NULL) {                  if (itEvent->Param.CC.Controller == CTRL_TABLE_IDX_AFTERTOUCH ||
672                        itEvent->Type == Event::type_channel_pressure)
673                    {
674                        ProcessChannelPressureEvent(itEvent);
675                    }
676                    if (pSignalUnitRack == NULL) {
677                      if (itEvent->Param.CC.Controller == pLFO1->ExtController) {                      if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
678                          pLFO1->update(itEvent->Param.CC.Value);                          pLFO1->updateByMIDICtrlValue(itEvent->Param.CC.Value);
679                      }                      }
680                      if (itEvent->Param.CC.Controller == pLFO2->ExtController) {                      if (itEvent->Param.CC.Controller == pLFO2->ExtController) {
681                          pLFO2->update(itEvent->Param.CC.Value);                          pLFO2->updateByMIDICtrlValue(itEvent->Param.CC.Value);
682                      }                      }
683                      if (itEvent->Param.CC.Controller == pLFO3->ExtController) {                      if (itEvent->Param.CC.Controller == pLFO3->ExtController) {
684                          pLFO3->update(itEvent->Param.CC.Value);                          pLFO3->updateByMIDICtrlValue(itEvent->Param.CC.Value);
685                      }                      }
686                  }                  }
687                  if (itEvent->Param.CC.Controller == 7) { // volume                  if (itEvent->Param.CC.Controller == 7) { // volume
688                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);
689                  } else if (itEvent->Param.CC.Controller == 10) { // panpot                  } else if (itEvent->Param.CC.Controller == 10) { // panpot
690                      PanLeftSmoother.update(AbstractEngine::PanCurve[128 - itEvent->Param.CC.Value]);                      MIDIPan = CalculatePan(itEvent->Param.CC.Value);
                     PanRightSmoother.update(AbstractEngine::PanCurve[itEvent->Param.CC.Value]);  
691                  }                  }
692              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event
693                  processPitchEvent(itEvent);                  processPitchEvent(itEvent);
694                } else if (itEvent->Type == Event::type_note_pressure) {
695                    ProcessPolyphonicKeyPressureEvent(itEvent);
696              }              }
697    
698              ProcessCCEvent(itEvent);              ProcessCCEvent(itEvent);
699              if (GetSignalUnitRack() != NULL) {              if (pSignalUnitRack != NULL) {
700                  GetSignalUnitRack()->ProcessCCEvent(itEvent);                  pSignalUnitRack->ProcessCCEvent(itEvent);
701              }              }
702          }          }
703      }      }
# Line 593  namespace LinuxSampler { Line 717  namespace LinuxSampler {
717      }      }
718    
719      /**      /**
720       * 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
721       * for the given time.       * note synthesis parameter events for the given time.
722       *       *
723       * @param itEvent - iterator pointing to the next event to be processed       * @param itEvent - iterator pointing to the next event to be processed
724       * @param End     - youngest time stamp where processing should be stopped       * @param End     - youngest time stamp where processing should be stopped
# Line 603  namespace LinuxSampler { Line 727  namespace LinuxSampler {
727          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
728              // some voice types ignore note off              // some voice types ignore note off
729              if (!(Type & (Voice::type_one_shot | Voice::type_release_trigger | Voice::type_controller_triggered))) {              if (!(Type & (Voice::type_one_shot | Voice::type_release_trigger | Voice::type_controller_triggered))) {
730                  if (itEvent->Type == Event::type_release) {                  if (itEvent->Type == Event::type_release_key) {
731                      EnterReleaseStage();                      EnterReleaseStage();
732                  } else if (itEvent->Type == Event::type_cancel_release) {                  } else if (itEvent->Type == Event::type_cancel_release_key) {
733                      if (GetSignalUnitRack() == NULL) {                      if (pSignalUnitRack == NULL) {
734                          pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                          pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
735                          pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                          pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
736                      } else {                      } else {
737                          GetSignalUnitRack()->CancelRelease();                          pSignalUnitRack->CancelRelease();
738                      }                      }
739                  }                  }
740              }              }
741                // process stop-note events (caused by built-in instrument script function note_off())
742                if (itEvent->Type == Event::type_release_note && pNote &&
743                    pEngineChannel->pEngine->NoteByID( itEvent->Param.Note.ID ) == pNote)
744                {
745                    EnterReleaseStage();
746                }
747                // process kill-note events (caused by built-in instrument script function fade_out())
748                if (itEvent->Type == Event::type_kill_note && pNote &&
749                    pEngineChannel->pEngine->NoteByID( itEvent->Param.Note.ID ) == pNote)
750                {
751                    Kill(itEvent);
752                }
753                // process synthesis parameter events (caused by built-in realt-time instrument script functions)
754                if (itEvent->Type == Event::type_note_synth_param && pNote &&
755                    pEngineChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID ) == pNote)
756                {
757                    switch (itEvent->Param.NoteSynthParam.Type) {
758                        case Event::synth_param_volume:
759                            NoteVolume.fadeTo(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
760                            break;
761                        case Event::synth_param_volume_time:
762                            NoteVolume.setDefaultDuration(itEvent->Param.NoteSynthParam.AbsValue);
763                            break;
764                        case Event::synth_param_volume_curve:
765                            NoteVolume.setCurve((fade_curve_t)itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
766                            break;
767                        case Event::synth_param_pitch:
768                            NotePitch.fadeTo(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
769                            break;
770                        case Event::synth_param_pitch_time:
771                            NotePitch.setDefaultDuration(itEvent->Param.NoteSynthParam.AbsValue);
772                            break;
773                        case Event::synth_param_pitch_curve:
774                            NotePitch.setCurve((fade_curve_t)itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
775                            break;
776                        case Event::synth_param_pan:
777                            NotePanLeft  = AbstractEngine::PanCurveValueNorm(itEvent->Param.NoteSynthParam.AbsValue, 0 /*left*/);
778                            NotePanRight = AbstractEngine::PanCurveValueNorm(itEvent->Param.NoteSynthParam.AbsValue, 1 /*right*/);
779                            break;
780                        case Event::synth_param_cutoff:
781                            NoteCutoff = itEvent->Param.NoteSynthParam.AbsValue;
782                            break;
783                        case Event::synth_param_resonance:
784                            NoteResonance = itEvent->Param.NoteSynthParam.AbsValue;
785                            break;
786                        case Event::synth_param_amp_lfo_depth:
787                            pLFO1->setScriptDepthFactor(itEvent->Param.NoteSynthParam.AbsValue);
788                            break;
789                        case Event::synth_param_amp_lfo_freq:
790                            pLFO1->setScriptFrequencyFactor(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
791                            break;
792                        case Event::synth_param_pitch_lfo_depth:
793                            pLFO3->setScriptDepthFactor(itEvent->Param.NoteSynthParam.AbsValue);
794                            break;
795                        case Event::synth_param_pitch_lfo_freq:
796                            pLFO3->setScriptFrequencyFactor(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
797                            break;
798    
799                        case Event::synth_param_attack:
800                        case Event::synth_param_decay:
801                        case Event::synth_param_release:
802                            break; // noop
803                    }
804                }
805          }          }
806      }      }
807    
# Line 638  namespace LinuxSampler { Line 826  namespace LinuxSampler {
826       * @param itNoteOffEvent - event which causes this voice to die soon       * @param itNoteOffEvent - event which causes this voice to die soon
827       */       */
828      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
829          if (GetSignalUnitRack() == NULL) {          if (pSignalUnitRack == NULL) {
830              const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());              const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
831              pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;              pEngineChannel->PortamentoPos = (float) MIDIKey() + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
832          } else {          } else {
833              // TODO:              // TODO:
834          }          }
# Line 667  namespace LinuxSampler { Line 855  namespace LinuxSampler {
855    
856      Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {      Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {
857          PitchInfo pitch;          PitchInfo pitch;
858          double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey % 12];          double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
859    
860          // GSt behaviour: maximum transpose up is 40 semitones. If          // GSt behaviour: maximum transpose up is 40 semitones. If
861          // MIDI key is more than 40 semitones above unity note,          // MIDI key is more than 40 semitones above unity note,
862          // the transpose is not done.          // the transpose is not done.
863          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;
864    
865          pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));          pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
866          pitch.PitchBendRange = 1.0 / 8192.0 * 100.0 * InstrInfo.PitchbendRange;          pitch.PitchBendRange = 1.0 / 8192.0 * 100.0 * InstrInfo.PitchbendRange;
# Line 680  namespace LinuxSampler { Line 868  namespace LinuxSampler {
868    
869          return pitch;          return pitch;
870      }      }
871        
872        void AbstractVoice::onScaleTuningChanged() {
873            PitchInfo pitch = this->Pitch;
874            double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
875            
876            // GSt behaviour: maximum transpose up is 40 semitones. If
877            // MIDI key is more than 40 semitones above unity note,
878            // the transpose is not done.
879            if (!SmplInfo.Unpitched && (MIDIKey() - (int) RgnInfo.UnityNote) < 40) pitchbasecents += (MIDIKey() - (int) RgnInfo.UnityNote) * 100;
880            
881            pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
882            this->Pitch = pitch;
883        }
884    
885      double AbstractVoice::CalculateVolume(double velocityAttenuation) {      double AbstractVoice::CalculateVolume(double velocityAttenuation) {
886          // For 16 bit samples, we downscale by 32768 to convert from          // For 16 bit samples, we downscale by 32768 to convert from
# Line 692  namespace LinuxSampler { Line 893  namespace LinuxSampler {
893          // the volume of release triggered samples depends on note length          // the volume of release triggered samples depends on note length
894          if (Type & Voice::type_release_trigger) {          if (Type & Voice::type_release_trigger) {
895              float noteLength = float(GetEngine()->FrameTime + Delay -              float noteLength = float(GetEngine()->FrameTime + Delay -
896                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;                  GetNoteOnTime(MIDIKey()) ) / GetEngine()->SampleRate;
897    
898              volume *= GetReleaseTriggerAttenuation(noteLength);              volume *= GetReleaseTriggerAttenuation(noteLength);
899          }          }
# Line 705  namespace LinuxSampler { Line 906  namespace LinuxSampler {
906      }      }
907    
908      void AbstractVoice::EnterReleaseStage() {      void AbstractVoice::EnterReleaseStage() {
909          if (GetSignalUnitRack() == NULL) {          if (pSignalUnitRack == NULL) {
910              pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
911              pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
912          } else {          } else {
913              GetSignalUnitRack()->EnterReleaseStage();              pSignalUnitRack->EnterReleaseStage();
914          }          }
915      }      }
916    
917      bool AbstractVoice::EG1Finished() {      bool AbstractVoice::EG1Finished() {
918          if (GetSignalUnitRack() == NULL) {          if (pSignalUnitRack == NULL) {
919              return pEG1->getSegmentType() == EG::segment_end;              return pEG1->getSegmentType() == EG::segment_end;
920          } else {          } else {
921              return !GetSignalUnitRack()->GetEndpointUnit()->Active();              return !pSignalUnitRack->GetEndpointUnit()->Active();
922          }          }
923      }      }
924    

Legend:
Removed from v.2205  
changed lines
  Added in v.3251

  ViewVC Help
Powered by ViewVC