/[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 2963 by schoenebeck, Sun Jul 17 18:41:21 2016 UTC
# Line 4  Line 4 
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2011 Christian Schoenebeck and 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 LFO (0..1 range)          pLFO1 = new LFOUnsigned(1.0f);  // amplitude LFO (0..1 range)
32          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 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      /**      /**
# Line 98  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          MidiKeyBase* pKeyInfo = GetMidiKeyInfo(MIDIKey);          MidiKeyBase* pKeyInfo = GetMidiKeyInfo(MIDIKey());
119    
120          pGroupEvents = iKeyGroup ? pEngineChannel->ActiveKeyGroups[iKeyGroup] : 0;          pGroupEvents = iKeyGroup ? pEngineChannel->ActiveKeyGroups[iKeyGroup] : 0;
121    
# Line 111  namespace LinuxSampler { Line 123  namespace LinuxSampler {
123          RgnInfo    = GetRegionInfo();          RgnInfo    = GetRegionInfo();
124          InstrInfo  = GetInstrumentInfo();          InstrInfo  = GetInstrumentInfo();
125                    
126            MIDIPan    = CalculatePan(pEngineChannel->iLastPanRequest);
127    
128          AboutToTrigger();          AboutToTrigger();
129    
130          // calculate volume          // calculate volume
# Line 126  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 * pKeyInfo->PanLeft  * AbstractEngine::PanCurve[64 - RgnInfo.Pan];          VolumeLeft  = volume * pKeyInfo->PanLeft;
144          VolumeRight = volume * pKeyInfo->PanRight * AbstractEngine::PanCurve[64 + RgnInfo.Pan];          VolumeRight = volume * pKeyInfo->PanRight;
145    
146          float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;          // this rate is used for rather mellow volume fades
147            const float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;
148            // this rate is used for very fast volume fades
149            const float quickRampRate = RTMath::Min(subfragmentRate, GetEngine()->SampleRate * 0.001f /* 1ms */);
150          CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);          CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);
         VolumeSmoother.trigger(pEngineChannel->MidiVolume, subfragmentRate);  
         PanLeftSmoother.trigger(pEngineChannel->GlobalPanLeft, subfragmentRate);  
         PanRightSmoother.trigger(pEngineChannel->GlobalPanRight, subfragmentRate);  
151    
152          finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)          VolumeSmoother.trigger(pEngineChannel->MidiVolume, subfragmentRate);
153          Pos = RgnInfo.SampleStartOffset;          NoteVolumeSmoother.trigger(pNote ? pNote->Override.Volume : 1.f, quickRampRate);
154    
155          // Check if the sample needs disk streaming or is too short for that          // Check if the sample needs disk streaming or is too short for that
156          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;
157          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;
158    
159            SetSampleStartOffset();
160    
161          if (DiskVoice) { // voice to be streamed from disk          if (DiskVoice) { // voice to be streamed from disk
162              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {
163                  MaxRAMPos = cachedsamples - (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH) / SmplInfo.ChannelCount; //TODO: this calculation is too pessimistic and may better be moved to Render() method, so it calculates MaxRAMPos dependent to the current demand of sample points to be rendered (e.g. in case of JACK)                  MaxRAMPos = cachedsamples - (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH) / SmplInfo.ChannelCount; //TODO: this calculation is too pessimistic and may better be moved to Render() method, so it calculates MaxRAMPos dependent to the current demand of sample points to be rendered (e.g. in case of JACK)
# Line 158  namespace LinuxSampler { Line 174  namespace LinuxSampler {
174              RAMLoop = (SmplInfo.HasLoops && (SmplInfo.LoopStart + SmplInfo.LoopLength) <= MaxRAMPos);              RAMLoop = (SmplInfo.HasLoops && (SmplInfo.LoopStart + SmplInfo.LoopLength) <= MaxRAMPos);
175    
176              if (OrderNewStream()) return -1;              if (OrderNewStream()) return -1;
177              dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s)\n", cachedsamples, SmplInfo.TotalFrameCount, MaxRAMPos, (RAMLoop) ? "yes" : "no"));              dmsg(4,("Disk voice launched (cached samples: %ld, total Samples: %d, MaxRAMPos: %lu, RAMLooping: %s)\n", cachedsamples, SmplInfo.TotalFrameCount, MaxRAMPos, (RAMLoop) ? "yes" : "no"));
178          }          }
179          else { // RAM only voice          else { // RAM only voice
180              MaxRAMPos = cachedsamples;              MaxRAMPos = cachedsamples;
# Line 174  namespace LinuxSampler { Line 190  namespace LinuxSampler {
190          }          }
191    
192          Pitch = CalculatePitchInfo(PitchBend);          Pitch = CalculatePitchInfo(PitchBend);
193            NotePitch = (pNote) ? pNote->Override.Pitch : 1.0f;
194            NoteCutoff = (pNote) ? pNote->Override.Cutoff : 1.0f;
195            NoteResonance = (pNote) ? pNote->Override.Resonance : 1.0f;
196    
197          // the length of the decay and release curves are dependent on the velocity          // the length of the decay and release curves are dependent on the velocity
198          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);
199    
200          if (GetSignalUnitRack() == NULL) { // setup EG 1 (VCA EG)          if (pSignalUnitRack == NULL) { // setup EG 1 (VCA EG)
201              // get current value of EG1 controller              // get current value of EG1 controller
202              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);
203    
204              // calculate influence of EG1 controller on EG1's parameters              // calculate influence of EG1 controller on EG1's parameters
205              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);
206    
207                if (pNote) {
208                    egInfo.Attack  *= pNote->Override.Attack;
209                    egInfo.Decay   *= pNote->Override.Decay;
210                    egInfo.Release *= pNote->Override.Release;
211                }
212    
213              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
214          } else {          } else {
215              GetSignalUnitRack()->Trigger();              pSignalUnitRack->Trigger();
216          }          }
217    
218            const uint8_t pan = (pSignalUnitRack) ? pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan) : MIDIPan;
219            NotePanLeft  = (pNote) ? AbstractEngine::PanCurveValueNorm(pNote->Override.Pan, 0 /*left*/ ) : 1.f;
220            NotePanRight = (pNote) ? AbstractEngine::PanCurveValueNorm(pNote->Override.Pan, 1 /*right*/) : 1.f;
221            PanLeftSmoother.trigger(
222                AbstractEngine::PanCurve[128 - pan] * NotePanLeft,
223                quickRampRate //NOTE: maybe we should have 2 separate pan smoothers, one for MIDI CC10 (with slow rate) and one for instrument script change_pan() calls (with fast rate)
224            );
225            PanRightSmoother.trigger(
226                AbstractEngine::PanCurve[pan] * NotePanRight,
227                quickRampRate //NOTE: maybe we should have 2 separate pan smoothers, one for MIDI CC10 (with slow rate) and one for instrument script change_pan() calls (with fast rate)
228            );
229    
230  #ifdef CONFIG_INTERPOLATE_VOLUME  #ifdef CONFIG_INTERPOLATE_VOLUME
231          // setup initial volume in synthesis parameters          // setup initial volume in synthesis parameters
232      #ifdef CONFIG_PROCESS_MUTED_CHANNELS      #ifdef CONFIG_PROCESS_MUTED_CHANNELS
# Line 201  namespace LinuxSampler { Line 238  namespace LinuxSampler {
238      #else      #else
239          {          {
240              float finalVolume;              float finalVolume;
241              if (GetSignalUnitRack() == NULL) {              if (pSignalUnitRack == NULL) {
242                  finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();                  finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();
243              } else {              } else {
244                  finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * GetSignalUnitRack()->GetEndpointUnit()->GetVolume();                  finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pSignalUnitRack->GetEndpointUnit()->GetVolume();
245              }              }
246    
247              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * pEngineChannel->GlobalPanLeft;              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * PanLeftSmoother.render();
248              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight;              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * PanRightSmoother.render();
249          }          }
250      #endif      #endif
251  #endif  #endif
252    
253          if (GetSignalUnitRack() == NULL) {          if (pSignalUnitRack == NULL) {
254              // setup EG 2 (VCF Cutoff EG)              // setup EG 2 (VCF Cutoff EG)
255              {              {
256                  // get current value of EG2 controller                  // get current value of EG2 controller
# Line 231  namespace LinuxSampler { Line 268  namespace LinuxSampler {
268                  // 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
269                  bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;                  bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;
270                  float eg3depth = (bPortamento)                  float eg3depth = (bPortamento)
271                               ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100)                               ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey()) * 100)
272                               : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);                               : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);
273                  float eg3time = (bPortamento)                  float eg3time = (bPortamento)
274                              ? pEngineChannel->PortamentoTime                              ? pEngineChannel->PortamentoTime
# Line 292  namespace LinuxSampler { Line 329  namespace LinuxSampler {
329              VCFCutoffCtrl.controller    = 0;              VCFCutoffCtrl.controller    = 0;
330              VCFResonanceCtrl.controller = 0;              VCFResonanceCtrl.controller = 0;
331          }          }
332            
333            const bool bEq =
334                pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && pEq->HasSupport();
335    
336            if (bEq) {
337                pEq->GetInChannelLeft()->Clear();
338                pEq->GetInChannelRight()->Clear();
339                pEq->RenderAudio(GetEngine()->pAudioOutputDevice->MaxSamplesPerCycle());
340            }
341    
342          return 0; // success          return 0; // success
343      }      }
344        
345        void AbstractVoice::SetSampleStartOffset() {
346            finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
347            Pos = RgnInfo.SampleStartOffset;
348        }
349    
350      /**      /**
351       *  Synthesizes the current audio fragment for this voice.       *  Synthesizes the current audio fragment for this voice.
# Line 305  namespace LinuxSampler { Line 356  namespace LinuxSampler {
356       *  @param Skip    - number of sample points to skip in output buffer       *  @param Skip    - number of sample points to skip in output buffer
357       */       */
358      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
359            bool delay = false; // Whether the voice playback should be delayed for this call
360            
361            if (pSignalUnitRack != NULL) {
362                uint delaySteps = pSignalUnitRack->GetEndpointUnit()->DelayTrigger();
363                if (delaySteps > 0) { // delay on the endpoint unit means delay of the voice playback
364                    if (delaySteps >= Samples) {
365                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(Samples);
366                        delay = true;
367                    } else {
368                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(delaySteps);
369                        Samples -= delaySteps;
370                        Skip += delaySteps;
371                    }
372                }
373            }
374            
375          AbstractEngineChannel* pChannel = pEngineChannel;          AbstractEngineChannel* pChannel = pEngineChannel;
376          MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey);          MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey());
377    
378          const bool bVoiceRequiresDedicatedRouting =          const bool bVoiceRequiresDedicatedRouting =
379              pEngineChannel->GetFxSendCount() > 0 &&              pEngineChannel->GetFxSendCount() > 0 &&
380              (pMidiKeyInfo->ReverbSend || pMidiKeyInfo->ChorusSend);              (pMidiKeyInfo->ReverbSend || pMidiKeyInfo->ChorusSend);
381            
382            const bool bEq =
383                pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && pEq->HasSupport();
384    
385          if (bVoiceRequiresDedicatedRouting) {          if (bEq) {
386                pEq->GetInChannelLeft()->Clear();
387                pEq->GetInChannelRight()->Clear();
388                finalSynthesisParameters.pOutLeft  = &pEq->GetInChannelLeft()->Buffer()[Skip];
389                finalSynthesisParameters.pOutRight = &pEq->GetInChannelRight()->Buffer()[Skip];
390                pSignalUnitRack->UpdateEqSettings(pEq);
391            } else if (bVoiceRequiresDedicatedRouting) {
392              finalSynthesisParameters.pOutLeft  = &GetEngine()->pDedicatedVoiceChannelLeft->Buffer()[Skip];              finalSynthesisParameters.pOutLeft  = &GetEngine()->pDedicatedVoiceChannelLeft->Buffer()[Skip];
393              finalSynthesisParameters.pOutRight = &GetEngine()->pDedicatedVoiceChannelRight->Buffer()[Skip];              finalSynthesisParameters.pOutRight = &GetEngine()->pDedicatedVoiceChannelRight->Buffer()[Skip];
394          } else {          } else {
# Line 323  namespace LinuxSampler { Line 399  namespace LinuxSampler {
399    
400          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();
401          RTList<Event>::Iterator itNoteEvent;          RTList<Event>::Iterator itNoteEvent;
402          GetFirstEventOnKey(MIDIKey, itNoteEvent);          GetFirstEventOnKey(HostKey(), itNoteEvent);
403    
404          RTList<Event>::Iterator itGroupEvent;          RTList<Event>::Iterator itGroupEvent;
405          if (pGroupEvents) itGroupEvent = pGroupEvents->first();          if (pGroupEvents && !Orphan) itGroupEvent = pGroupEvents->first();
406    
407          if (itTriggerEvent) { // skip events that happened before this voice was triggered          if (itTriggerEvent) { // skip events that happened before this voice was triggered
408              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;
# Line 352  namespace LinuxSampler { Line 428  namespace LinuxSampler {
428                  // drivers that use Samples < MaxSamplesPerCycle).                  // drivers that use Samples < MaxSamplesPerCycle).
429                  // End the EG1 here, at pos 0, with a shorter max fade                  // End the EG1 here, at pos 0, with a shorter max fade
430                  // out time.                  // out time.
431                  if (GetSignalUnitRack() == NULL) {                  if (pSignalUnitRack == NULL) {
432                      pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                      pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
433                  } else {                  } else {
434                      // TODO:                      pSignalUnitRack->EnterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
435                  }                  }
436                  itKillEvent = Pool<Event>::Iterator();                  itKillEvent = Pool<Event>::Iterator();
437              } else {              } else {
# Line 371  namespace LinuxSampler { Line 447  namespace LinuxSampler {
447              fFinalCutoff    = VCFCutoffCtrl.fvalue;              fFinalCutoff    = VCFCutoffCtrl.fvalue;
448              fFinalResonance = VCFResonanceCtrl.fvalue;              fFinalResonance = VCFResonanceCtrl.fvalue;
449    
450              // process MIDI control change and pitchbend events for this subfragment              // process MIDI control change, aftertouch and pitchbend events for this subfragment
451              processCCEvents(itCCEvent, iSubFragmentEnd);              processCCEvents(itCCEvent, iSubFragmentEnd);
452                uint8_t pan = MIDIPan;
453                if (pSignalUnitRack != NULL) pan = pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan);
454    
455              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend;              PanLeftSmoother.update(AbstractEngine::PanCurve[128 - pan] * NotePanLeft);
456              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();              PanRightSmoother.update(AbstractEngine::PanCurve[pan]      * NotePanRight);
457    
458                finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend * NotePitch;
459    
460                float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render() * NoteVolumeSmoother.render();
461  #ifdef CONFIG_PROCESS_MUTED_CHANNELS  #ifdef CONFIG_PROCESS_MUTED_CHANNELS
462              if (pChannel->GetMute()) fFinalVolume = 0;              if (pChannel->GetMute()) fFinalVolume = 0;
463  #endif  #endif
# Line 383  namespace LinuxSampler { Line 465  namespace LinuxSampler {
465              // process transition events (note on, note off & sustain pedal)              // process transition events (note on, note off & sustain pedal)
466              processTransitionEvents(itNoteEvent, iSubFragmentEnd);              processTransitionEvents(itNoteEvent, iSubFragmentEnd);
467              processGroupEvents(itGroupEvent, iSubFragmentEnd);              processGroupEvents(itGroupEvent, iSubFragmentEnd);
468                
469              if (GetSignalUnitRack() == NULL) {              if (pSignalUnitRack == NULL) {
470                  // if the voice was killed in this subfragment, or if the                  // if the voice was killed in this subfragment, or if the
471                  // filter EG is finished, switch EG1 to fade out stage                  // filter EG is finished, switch EG1 to fade out stage
472                  if ((itKillEvent && killPos <= iSubFragmentEnd) ||                  if ((itKillEvent && killPos <= iSubFragmentEnd) ||
# Line 427  namespace LinuxSampler { Line 509  namespace LinuxSampler {
509    
510                  // process low frequency oscillators                  // process low frequency oscillators
511                  if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());                  if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());
512                  if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();                  if (bLFO2Enabled) fFinalCutoff *= (1.0f - pLFO2->render());
513                  if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());                  if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
514              } else {              } else {
515                  // if the voice was killed in this subfragment, or if the                  // if the voice was killed in this subfragment, enter fade out stage
516                  // filter EG is finished, switch EG1 to fade out stage                  if (itKillEvent && killPos <= iSubFragmentEnd) {
517                  /*if ((itKillEvent && killPos <= iSubFragmentEnd) ||                      pSignalUnitRack->EnterFadeOutStage();
518                      (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&                      itKillEvent = Pool<Event>::Iterator();
519                      pEG2->getSegmentType() == EG::segment_end)) {                  }
520                    
521                    // if the filter EG is finished, switch EG1 to fade out stage
522                    /*if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
523                        pEG2->getSegmentType() == EG::segment_end) {
524                      pEG1->enterFadeOutStage();                      pEG1->enterFadeOutStage();
525                      itKillEvent = Pool<Event>::Iterator();                      itKillEvent = Pool<Event>::Iterator();
526                  }*/                  }*/
527                  // TODO: ^^^                  // TODO: ^^^
528    
529                  fFinalVolume   *= GetSignalUnitRack()->GetEndpointUnit()->GetVolume();                  fFinalVolume   *= pSignalUnitRack->GetEndpointUnit()->GetVolume();
530                  fFinalCutoff    = GetSignalUnitRack()->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff);                  fFinalCutoff    = pSignalUnitRack->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff);
531                  fFinalResonance = GetSignalUnitRack()->GetEndpointUnit()->CalculateResonance(fFinalResonance);                  fFinalResonance = pSignalUnitRack->GetEndpointUnit()->CalculateResonance(fFinalResonance);
532                                    
533                  finalSynthesisParameters.fFinalPitch =                  finalSynthesisParameters.fFinalPitch =
534                      GetSignalUnitRack()->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);                      pSignalUnitRack->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);
535                                            
536              }              }
537                
538                fFinalCutoff    *= NoteCutoff;
539                fFinalResonance *= NoteResonance;
540    
541              // limit the pitch so we don't read outside the buffer              // limit the pitch so we don't read outside the buffer
542              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));
543    
# Line 481  namespace LinuxSampler { Line 570  namespace LinuxSampler {
570                  fFinalVolume * VolumeRight * PanRightSmoother.render();                  fFinalVolume * VolumeRight * PanRightSmoother.render();
571  #endif  #endif
572              // render audio for one subfragment              // render audio for one subfragment
573              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);              if (!delay) RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
574    
575              if (GetSignalUnitRack() == NULL) {              if (pSignalUnitRack == NULL) {
576                  // stop the rendering if volume EG is finished                  // stop the rendering if volume EG is finished
577                  if (pEG1->getSegmentType() == EG::segment_end) break;                  if (pEG1->getSegmentType() == EG::segment_end) break;
578              } else {              } else {
579                  // stop the rendering if the endpoint unit is not active                  // stop the rendering if the endpoint unit is not active
580                  if (!GetSignalUnitRack()->GetEndpointUnit()->Active()) break;                  if (!pSignalUnitRack->GetEndpointUnit()->Active()) break;
581              }              }
582    
583              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
584    
585              if (GetSignalUnitRack() == NULL) {              if (pSignalUnitRack == NULL) {
586                  // increment envelopes' positions                  // increment envelopes' positions
587                  if (pEG1->active()) {                  if (pEG1->active()) {
588    
# Line 518  namespace LinuxSampler { Line 607  namespace LinuxSampler {
607                      }*/                      }*/
608                  // TODO: ^^^                  // TODO: ^^^
609                                    
610                  GetSignalUnitRack()->Increment();                  if (!delay) pSignalUnitRack->Increment();
611              }              }
612    
613              Pos = newPos;              Pos = newPos;
614              i = iSubFragmentEnd;              i = iSubFragmentEnd;
615          }          }
616            
617            if (delay) return;
618    
619          if (bVoiceRequiresDedicatedRouting) {          if (bVoiceRequiresDedicatedRouting) {
620                if (bEq) {
621                    pEq->RenderAudio(Samples);
622                    pEq->GetOutChannelLeft()->CopyTo(GetEngine()->pDedicatedVoiceChannelLeft, Samples);
623                    pEq->GetOutChannelRight()->CopyTo(GetEngine()->pDedicatedVoiceChannelRight, Samples);
624                }
625              optional<float> effectSendLevels[2] = {              optional<float> effectSendLevels[2] = {
626                  pMidiKeyInfo->ReverbSend,                  pMidiKeyInfo->ReverbSend,
627                  pMidiKeyInfo->ChorusSend                  pMidiKeyInfo->ChorusSend
628              };              };
629              GetEngine()->RouteDedicatedVoiceChannels(pEngineChannel, effectSendLevels, Samples);              GetEngine()->RouteDedicatedVoiceChannels(pEngineChannel, effectSendLevels, Samples);
630            } else if (bEq) {
631                pEq->RenderAudio(Samples);
632                pEq->GetOutChannelLeft()->MixTo(pChannel->pChannelLeft, Samples);
633                pEq->GetOutChannelRight()->MixTo(pChannel->pChannelRight, Samples);
634          }          }
635      }      }
636    
637      /**      /**
638       * Process given list of MIDI control change and pitch bend events for       * Process given list of MIDI control change, aftertouch and pitch bend
639       * the given time.       * events for the given time.
640       *       *
641       * @param itEvent - iterator pointing to the next event to be processed       * @param itEvent - iterator pointing to the next event to be processed
642       * @param End     - youngest time stamp where processing should be stopped       * @param End     - youngest time stamp where processing should be stopped
# Line 550  namespace LinuxSampler { Line 650  namespace LinuxSampler {
650                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
651                      processResonanceEvent(itEvent);                      processResonanceEvent(itEvent);
652                  }                  }
653                  if (GetSignalUnitRack() == NULL) {                  if (pSignalUnitRack == NULL) {
654                      if (itEvent->Param.CC.Controller == pLFO1->ExtController) {                      if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
655                          pLFO1->update(itEvent->Param.CC.Value);                          pLFO1->update(itEvent->Param.CC.Value);
656                      }                      }
# Line 564  namespace LinuxSampler { Line 664  namespace LinuxSampler {
664                  if (itEvent->Param.CC.Controller == 7) { // volume                  if (itEvent->Param.CC.Controller == 7) { // volume
665                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);
666                  } else if (itEvent->Param.CC.Controller == 10) { // panpot                  } else if (itEvent->Param.CC.Controller == 10) { // panpot
667                      PanLeftSmoother.update(AbstractEngine::PanCurve[128 - itEvent->Param.CC.Value]);                      MIDIPan = CalculatePan(itEvent->Param.CC.Value);
                     PanRightSmoother.update(AbstractEngine::PanCurve[itEvent->Param.CC.Value]);  
668                  }                  }
669              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event
670                  processPitchEvent(itEvent);                  processPitchEvent(itEvent);
671                } else if (itEvent->Type == Event::type_channel_pressure) {
672                    ProcessChannelPressureEvent(itEvent);
673                } else if (itEvent->Type == Event::type_note_pressure) {
674                    ProcessPolyphonicKeyPressureEvent(itEvent);
675              }              }
676    
677              ProcessCCEvent(itEvent);              ProcessCCEvent(itEvent);
678              if (GetSignalUnitRack() != NULL) {              if (pSignalUnitRack != NULL) {
679                  GetSignalUnitRack()->ProcessCCEvent(itEvent);                  pSignalUnitRack->ProcessCCEvent(itEvent);
680              }              }
681          }          }
682      }      }
# Line 593  namespace LinuxSampler { Line 696  namespace LinuxSampler {
696      }      }
697    
698      /**      /**
699       * 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
700       * for the given time.       * note synthesis parameter events for the given time.
701       *       *
702       * @param itEvent - iterator pointing to the next event to be processed       * @param itEvent - iterator pointing to the next event to be processed
703       * @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 706  namespace LinuxSampler {
706          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
707              // some voice types ignore note off              // some voice types ignore note off
708              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))) {
709                  if (itEvent->Type == Event::type_release) {                  if (itEvent->Type == Event::type_release_key) {
710                      EnterReleaseStage();                      EnterReleaseStage();
711                  } else if (itEvent->Type == Event::type_cancel_release) {                  } else if (itEvent->Type == Event::type_cancel_release_key) {
712                      if (GetSignalUnitRack() == NULL) {                      if (pSignalUnitRack == NULL) {
713                          pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                          pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
714                          pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                          pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
715                      } else {                      } else {
716                          GetSignalUnitRack()->CancelRelease();                          pSignalUnitRack->CancelRelease();
717                      }                      }
718                  }                  }
719              }              }
720                // process stop-note events (caused by built-in instrument script function note_off())
721                if (itEvent->Type == Event::type_release_note && pNote &&
722                    pEngineChannel->pEngine->NoteByID( itEvent->Param.Note.ID ) == pNote)
723                {
724                    EnterReleaseStage();
725                }
726                // process synthesis parameter events (caused by built-in realt-time instrument script functions)
727                if (itEvent->Type == Event::type_note_synth_param && pNote &&
728                    pEngineChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID ) == pNote)
729                {
730                    switch (itEvent->Param.NoteSynthParam.Type) {
731                        case Event::synth_param_volume:
732                            NoteVolumeSmoother.update(itEvent->Param.NoteSynthParam.AbsValue);
733                            break;
734                        case Event::synth_param_pitch:
735                            NotePitch = itEvent->Param.NoteSynthParam.AbsValue;
736                            break;
737                        case Event::synth_param_pan:
738                            NotePanLeft  = AbstractEngine::PanCurveValueNorm(itEvent->Param.NoteSynthParam.AbsValue, 0 /*left*/);
739                            NotePanRight = AbstractEngine::PanCurveValueNorm(itEvent->Param.NoteSynthParam.AbsValue, 1 /*right*/);
740                            break;
741                        case Event::synth_param_cutoff:
742                            NoteCutoff = itEvent->Param.NoteSynthParam.AbsValue;
743                            break;
744                        case Event::synth_param_resonance:
745                            NoteResonance = itEvent->Param.NoteSynthParam.AbsValue;
746                            break;
747                    }
748                }
749          }          }
750      }      }
751    
# Line 638  namespace LinuxSampler { Line 770  namespace LinuxSampler {
770       * @param itNoteOffEvent - event which causes this voice to die soon       * @param itNoteOffEvent - event which causes this voice to die soon
771       */       */
772      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
773          if (GetSignalUnitRack() == NULL) {          if (pSignalUnitRack == NULL) {
774              const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());              const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
775              pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;              pEngineChannel->PortamentoPos = (float) MIDIKey() + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
776          } else {          } else {
777              // TODO:              // TODO:
778          }          }
# Line 667  namespace LinuxSampler { Line 799  namespace LinuxSampler {
799    
800      Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {      Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {
801          PitchInfo pitch;          PitchInfo pitch;
802          double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey % 12];          double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
803    
804          // GSt behaviour: maximum transpose up is 40 semitones. If          // GSt behaviour: maximum transpose up is 40 semitones. If
805          // MIDI key is more than 40 semitones above unity note,          // MIDI key is more than 40 semitones above unity note,
806          // the transpose is not done.          // the transpose is not done.
807          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;
808    
809          pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));          pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
810          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 812  namespace LinuxSampler {
812    
813          return pitch;          return pitch;
814      }      }
815        
816        void AbstractVoice::onScaleTuningChanged() {
817            PitchInfo pitch = this->Pitch;
818            double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
819            
820            // GSt behaviour: maximum transpose up is 40 semitones. If
821            // MIDI key is more than 40 semitones above unity note,
822            // the transpose is not done.
823            if (!SmplInfo.Unpitched && (MIDIKey() - (int) RgnInfo.UnityNote) < 40) pitchbasecents += (MIDIKey() - (int) RgnInfo.UnityNote) * 100;
824            
825            pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
826            this->Pitch = pitch;
827        }
828    
829      double AbstractVoice::CalculateVolume(double velocityAttenuation) {      double AbstractVoice::CalculateVolume(double velocityAttenuation) {
830          // 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 837  namespace LinuxSampler {
837          // the volume of release triggered samples depends on note length          // the volume of release triggered samples depends on note length
838          if (Type & Voice::type_release_trigger) {          if (Type & Voice::type_release_trigger) {
839              float noteLength = float(GetEngine()->FrameTime + Delay -              float noteLength = float(GetEngine()->FrameTime + Delay -
840                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;                  GetNoteOnTime(MIDIKey()) ) / GetEngine()->SampleRate;
841    
842              volume *= GetReleaseTriggerAttenuation(noteLength);              volume *= GetReleaseTriggerAttenuation(noteLength);
843          }          }
# Line 705  namespace LinuxSampler { Line 850  namespace LinuxSampler {
850      }      }
851    
852      void AbstractVoice::EnterReleaseStage() {      void AbstractVoice::EnterReleaseStage() {
853          if (GetSignalUnitRack() == NULL) {          if (pSignalUnitRack == NULL) {
854              pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
855              pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
856          } else {          } else {
857              GetSignalUnitRack()->EnterReleaseStage();              pSignalUnitRack->EnterReleaseStage();
858          }          }
859      }      }
860    
861      bool AbstractVoice::EG1Finished() {      bool AbstractVoice::EG1Finished() {
862          if (GetSignalUnitRack() == NULL) {          if (pSignalUnitRack == NULL) {
863              return pEG1->getSegmentType() == EG::segment_end;              return pEG1->getSegmentType() == EG::segment_end;
864          } else {          } else {
865              return !GetSignalUnitRack()->GetEndpointUnit()->Active();              return !pSignalUnitRack->GetEndpointUnit()->Active();
866          }          }
867      }      }
868    

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

  ViewVC Help
Powered by ViewVC