/[svn]/linuxsampler/trunk/src/engines/common/AbstractVoice.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/common/AbstractVoice.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2032 by persson, Fri Nov 20 20:13:08 2009 UTC revision 2327 by persson, Sat Mar 10 16:16:14 2012 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2009 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009 Grigor Iliev                                       *   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *
8   *                                                                         *   *                                                                         *
9   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
10   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 26  Line 26 
26    
27  namespace LinuxSampler {  namespace LinuxSampler {
28    
29      AbstractVoice::AbstractVoice() {      AbstractVoice::AbstractVoice(SignalUnitRack* pRack): pSignalUnitRack(pRack) {
30          pEngineChannel = NULL;          pEngineChannel = NULL;
31          pLFO1 = new LFOUnsigned(1.0f);  // amplitude EG (0..1 range)          pLFO1 = new LFOUnsigned(1.0f);  // amplitude LFO (0..1 range)
32          pLFO2 = new LFOUnsigned(1.0f);  // filter EG (0..1 range)          pLFO2 = new LFOUnsigned(1.0f);  // filter LFO (0..1 range)
33          pLFO3 = new LFOSigned(1200.0f); // pitch EG (-1200..+1200 range)          pLFO3 = new LFOSigned(1200.0f); // pitch LFO (-1200..+1200 range)
34          PlaybackState = playback_state_end;          PlaybackState = playback_state_end;
         KeyGroup = 0;  
35          SynthesisMode = 0; // set all mode bits to 0 first          SynthesisMode = 0; // set all mode bits to 0 first
36          // select synthesis implementation (asm core is not supported ATM)          // select synthesis implementation (asm core is not supported ATM)
37          #if 0 // CONFIG_ASM && ARCH_X86          #if 0 // CONFIG_ASM && ARCH_X86
# Line 44  namespace LinuxSampler { Line 43  namespace LinuxSampler {
43    
44          finalSynthesisParameters.filterLeft.Reset();          finalSynthesisParameters.filterLeft.Reset();
45          finalSynthesisParameters.filterRight.Reset();          finalSynthesisParameters.filterRight.Reset();
46            
47            pEq          = NULL;
48            bEqSupport   = false;
49      }      }
50    
51      AbstractVoice::~AbstractVoice() {      AbstractVoice::~AbstractVoice() {
52          if (pLFO1) delete pLFO1;          if (pLFO1) delete pLFO1;
53          if (pLFO2) delete pLFO2;          if (pLFO2) delete pLFO2;
54          if (pLFO3) delete pLFO3;          if (pLFO3) delete pLFO3;
55            
56            if(pEq != NULL) delete pEq;
57      }      }
58                    
59        void AbstractVoice::CreateEq() {
60            if(!bEqSupport) return;
61            if(pEq != NULL) delete pEq;
62            pEq = new EqSupport;
63            pEq->InitEffect(GetEngine()->pAudioOutputDevice);
64        }
65    
66      /**      /**
67       *  Resets voice variables. Should only be called if rendering process is       *  Resets voice variables. Should only be called if rendering process is
68       *  suspended / not running.       *  suspended / not running.
# Line 100  namespace LinuxSampler { Line 111  namespace LinuxSampler {
111    
112          Type            = VoiceType;          Type            = VoiceType;
113          MIDIKey         = itNoteOnEvent->Param.Note.Key;          MIDIKey         = itNoteOnEvent->Param.Note.Key;
114            MIDIVelocity    = itNoteOnEvent->Param.Note.Velocity;
115            MIDIPan         = pEngineChannel->ControllerTable[10];
116            if (MIDIPan == 0 && pEngineChannel->GlobalPanRight == 1) MIDIPan = 64; // workaround used to determine whether the MIDI pan has not been set
117          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
118          Delay           = itNoteOnEvent->FragmentPos();          Delay           = itNoteOnEvent->FragmentPos();
119          itTriggerEvent  = itNoteOnEvent;          itTriggerEvent  = itNoteOnEvent;
120          itKillEvent     = Pool<Event>::Iterator();          itKillEvent     = Pool<Event>::Iterator();
121          KeyGroup        = iKeyGroup;          MidiKeyBase* pKeyInfo = GetMidiKeyInfo(MIDIKey);
122    
123            pGroupEvents = iKeyGroup ? pEngineChannel->ActiveKeyGroups[iKeyGroup] : 0;
124    
125          SmplInfo   = GetSampleInfo();          SmplInfo   = GetSampleInfo();
126          RgnInfo    = GetRegionInfo();          RgnInfo    = GetRegionInfo();
127          InstrInfo  = GetInstrumentInfo();          InstrInfo  = GetInstrumentInfo();
128            
129            AboutToTrigger();
130    
131          // calculate volume          // calculate volume
132          const double velocityAttenuation = GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity);          const double velocityAttenuation = GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity);
133          float volume = CalculateVolume(velocityAttenuation);          float volume = CalculateVolume(velocityAttenuation) * pKeyInfo->Volume;
134          if (volume <= 0) return -1;          if (volume <= 0) return -1;
135    
136          // select channel mode (mono or stereo)          // select channel mode (mono or stereo)
# Line 123  namespace LinuxSampler { Line 141  namespace LinuxSampler {
141          // get starting crossfade volume level          // get starting crossfade volume level
142          float crossfadeVolume = CalculateCrossfadeVolume(itNoteOnEvent->Param.Note.Velocity);          float crossfadeVolume = CalculateCrossfadeVolume(itNoteOnEvent->Param.Note.Velocity);
143    
144          VolumeLeft  = volume * AbstractEngine::PanCurve[64 - RgnInfo.Pan];          VolumeLeft  = volume * pKeyInfo->PanLeft  * AbstractEngine::PanCurve[64 - RgnInfo.Pan];
145          VolumeRight = volume * AbstractEngine::PanCurve[64 + RgnInfo.Pan];          VolumeRight = volume * pKeyInfo->PanRight * AbstractEngine::PanCurve[64 + RgnInfo.Pan];
146    
147          float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;          float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;
148          CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);          CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);
# Line 132  namespace LinuxSampler { Line 150  namespace LinuxSampler {
150          PanLeftSmoother.trigger(pEngineChannel->GlobalPanLeft, subfragmentRate);          PanLeftSmoother.trigger(pEngineChannel->GlobalPanLeft, subfragmentRate);
151          PanRightSmoother.trigger(pEngineChannel->GlobalPanRight, subfragmentRate);          PanRightSmoother.trigger(pEngineChannel->GlobalPanRight, subfragmentRate);
152    
         finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)  
         Pos = RgnInfo.SampleStartOffset;  
   
153          // 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
154          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;
155          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;
156    
157            SetSampleStartOffset();
158    
159          if (DiskVoice) { // voice to be streamed from disk          if (DiskVoice) { // voice to be streamed from disk
160              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {
161                  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 175  namespace LinuxSampler { Line 192  namespace LinuxSampler {
192          // 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
193          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);
194    
195          // setup EG 1 (VCA EG)          if (pSignalUnitRack == NULL) { // setup EG 1 (VCA EG)
         {  
196              // get current value of EG1 controller              // get current value of EG1 controller
197              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);
198    
199              // calculate influence of EG1 controller on EG1's parameters              // calculate influence of EG1 controller on EG1's parameters
200              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);
201    
202              EG1.trigger (              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
203                  RgnInfo.EG1PreAttack,          } else {
204                  RgnInfo.EG1Attack * egInfo.Attack,              pSignalUnitRack->Trigger();
                 RgnInfo.EG1Hold,  
                 RgnInfo.EG1Decay1 * egInfo.Decay * velrelease,  
                 RgnInfo.EG1Decay2 * egInfo.Decay * velrelease,  
                 RgnInfo.EG1InfiniteSustain,  
                 RgnInfo.EG1Sustain,  
                 RgnInfo.EG1Release * egInfo.Release * velrelease,  
                 velocityAttenuation,  
                 GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE  
             );  
205          }          }
206    
207  #ifdef CONFIG_INTERPOLATE_VOLUME  #ifdef CONFIG_INTERPOLATE_VOLUME
# Line 207  namespace LinuxSampler { Line 214  namespace LinuxSampler {
214          else          else
215      #else      #else
216          {          {
217              float finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * EG1.getLevel();              float finalVolume;
218                if (pSignalUnitRack == NULL) {
219                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();
220                } else {
221                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pSignalUnitRack->GetEndpointUnit()->GetVolume();
222                }
223    
224              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * pEngineChannel->GlobalPanLeft;              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * pEngineChannel->GlobalPanLeft;
225              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight;              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight;
# Line 215  namespace LinuxSampler { Line 227  namespace LinuxSampler {
227      #endif      #endif
228  #endif  #endif
229    
230          // setup EG 2 (VCF Cutoff EG)          if (pSignalUnitRack == NULL) {
231          {              // setup EG 2 (VCF Cutoff EG)
232              // get current value of EG2 controller              {
233              double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);                  // get current value of EG2 controller
234                    double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);
235    
236                    // calculate influence of EG2 controller on EG2's parameters
237                    EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);
238    
239                    TriggerEG2(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
240                }
241    
             // calculate influence of EG2 controller on EG2's parameters  
             EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);  
242    
243              EG2.trigger (              // setup EG 3 (VCO EG)
244                  RgnInfo.EG2PreAttack,              {
245                  RgnInfo.EG2Attack * egInfo.Attack,                  // if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch
246                  false,                  bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;
247                  RgnInfo.EG2Decay1 * egInfo.Decay * velrelease,                  float eg3depth = (bPortamento)
248                  RgnInfo.EG2Decay2 * egInfo.Decay * velrelease,                               ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100)
249                  RgnInfo.EG2InfiniteSustain,                               : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);
250                  RgnInfo.EG2Sustain,                  float eg3time = (bPortamento)
251                  RgnInfo.EG2Release * egInfo.Release * velrelease,                              ? pEngineChannel->PortamentoTime
252                  velocityAttenuation,                              : RgnInfo.EG3Attack;
253                  GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE                  EG3.trigger(eg3depth, eg3time, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
254              );                  dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time));
255          }              }
256    
257    
258          // setup EG 3 (VCO EG)              // setup LFO 1 (VCA LFO)
259          {              InitLFO1();
260              // if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch              // setup LFO 2 (VCF Cutoff LFO)
261              bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;              InitLFO2();
262              float eg3depth = (bPortamento)              // setup LFO 3 (VCO LFO)
263                           ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100)              InitLFO3();
                          : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);  
             float eg3time = (bPortamento)  
                         ? pEngineChannel->PortamentoTime  
                         : RgnInfo.EG3Attack;  
             EG3.trigger(eg3depth, eg3time, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);  
             dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time));  
264          }          }
265    
266    
         // setup LFO 1 (VCA LFO)  
         InitLFO1();  
         // setup LFO 2 (VCF Cutoff LFO)  
         InitLFO2();  
         // setup LFO 3 (VCO LFO)  
         InitLFO3();  
   
   
267          #if CONFIG_FORCE_FILTER          #if CONFIG_FORCE_FILTER
268          const bool bUseFilter = true;          const bool bUseFilter = true;
269          #else // use filter only if instrument file told so          #else // use filter only if instrument file told so
# Line 303  namespace LinuxSampler { Line 306  namespace LinuxSampler {
306              VCFCutoffCtrl.controller    = 0;              VCFCutoffCtrl.controller    = 0;
307              VCFResonanceCtrl.controller = 0;              VCFResonanceCtrl.controller = 0;
308          }          }
309            
310            const bool bEq =
311                pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && pEq->HasSupport();
312    
313            if (bEq) {
314                pEq->GetInChannelLeft()->Clear();
315                pEq->GetInChannelRight()->Clear();
316                pEq->RenderAudio(GetEngine()->pAudioOutputDevice->MaxSamplesPerCycle());
317            }
318    
319          return 0; // success          return 0; // success
320      }      }
321        
322        void AbstractVoice::SetSampleStartOffset() {
323            finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
324            Pos = RgnInfo.SampleStartOffset;
325        }
326    
327      /**      /**
328       *  Synthesizes the current audio fragment for this voice.       *  Synthesizes the current audio fragment for this voice.
# Line 316  namespace LinuxSampler { Line 333  namespace LinuxSampler {
333       *  @param Skip    - number of sample points to skip in output buffer       *  @param Skip    - number of sample points to skip in output buffer
334       */       */
335      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
336            bool delay = false; // Whether the voice playback should be delayed for this call
337            
338            if (pSignalUnitRack != NULL) {
339                uint delaySteps = pSignalUnitRack->GetEndpointUnit()->DelayTrigger();
340                if (delaySteps > 0) { // delay on the endpoint unit means delay of the voice playback
341                    if (delaySteps >= Samples) {
342                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(Samples);
343                        delay = true;
344                    } else {
345                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(delaySteps);
346                        Samples -= delaySteps;
347                        Skip += delaySteps;
348                    }
349                }
350            }
351            
352          AbstractEngineChannel* pChannel = pEngineChannel;          AbstractEngineChannel* pChannel = pEngineChannel;
353          finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];          MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey);
354          finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];  
355          finalSynthesisParameters.pSrc      = pSrc;          const bool bVoiceRequiresDedicatedRouting =
356                pEngineChannel->GetFxSendCount() > 0 &&
357                (pMidiKeyInfo->ReverbSend || pMidiKeyInfo->ChorusSend);
358            
359            const bool bEq =
360                pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && pEq->HasSupport();
361    
362            if (bEq) {
363                pEq->GetInChannelLeft()->Clear();
364                pEq->GetInChannelRight()->Clear();
365                finalSynthesisParameters.pOutLeft  = &pEq->GetInChannelLeft()->Buffer()[Skip];
366                finalSynthesisParameters.pOutRight = &pEq->GetInChannelRight()->Buffer()[Skip];
367                pSignalUnitRack->UpdateEqSettings(pEq);
368            } else if (bVoiceRequiresDedicatedRouting) {
369                finalSynthesisParameters.pOutLeft  = &GetEngine()->pDedicatedVoiceChannelLeft->Buffer()[Skip];
370                finalSynthesisParameters.pOutRight = &GetEngine()->pDedicatedVoiceChannelRight->Buffer()[Skip];
371            } else {
372                finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];
373                finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];
374            }
375            finalSynthesisParameters.pSrc = pSrc;
376    
377          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();
378          RTList<Event>::Iterator itNoteEvent;          RTList<Event>::Iterator itNoteEvent;
379          GetFirstEventOnKey(MIDIKey, itNoteEvent);          GetFirstEventOnKey(MIDIKey, itNoteEvent);
380    
381            RTList<Event>::Iterator itGroupEvent;
382            if (pGroupEvents) itGroupEvent = pGroupEvents->first();
383    
384          if (itTriggerEvent) { // skip events that happened before this voice was triggered          if (itTriggerEvent) { // skip events that happened before this voice was triggered
385              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;
386                while (itGroupEvent && itGroupEvent->FragmentPos() <= Skip) ++itGroupEvent;
387    
388              // we can't simply compare the timestamp here, because note events              // we can't simply compare the timestamp here, because note events
389              // might happen on the same time stamp, so we have to deal on the              // might happen on the same time stamp, so we have to deal on the
390              // actual sequence the note events arrived instead (see bug #112)              // actual sequence the note events arrived instead (see bug #112)
# Line 347  namespace LinuxSampler { Line 405  namespace LinuxSampler {
405                  // drivers that use Samples < MaxSamplesPerCycle).                  // drivers that use Samples < MaxSamplesPerCycle).
406                  // End the EG1 here, at pos 0, with a shorter max fade                  // End the EG1 here, at pos 0, with a shorter max fade
407                  // out time.                  // out time.
408                  EG1.enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (pSignalUnitRack == NULL) {
409                        pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
410                    } else {
411                        pSignalUnitRack->EnterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
412                    }
413                  itKillEvent = Pool<Event>::Iterator();                  itKillEvent = Pool<Event>::Iterator();
414              } else {              } else {
415                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);
# Line 364  namespace LinuxSampler { Line 426  namespace LinuxSampler {
426    
427              // process MIDI control change and pitchbend events for this subfragment              // process MIDI control change and pitchbend events for this subfragment
428              processCCEvents(itCCEvent, iSubFragmentEnd);              processCCEvents(itCCEvent, iSubFragmentEnd);
429                uint8_t pan = MIDIPan;
430                if (pSignalUnitRack != NULL) pan = pSignalUnitRack->GetEndpointUnit()->CaluclatePan(pan);
431                
432                PanLeftSmoother.update(AbstractEngine::PanCurve[128 - pan]);
433                PanRightSmoother.update(AbstractEngine::PanCurve[pan]);
434    
435              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend;              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend;
436              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();
# Line 373  namespace LinuxSampler { Line 440  namespace LinuxSampler {
440    
441              // process transition events (note on, note off & sustain pedal)              // process transition events (note on, note off & sustain pedal)
442              processTransitionEvents(itNoteEvent, iSubFragmentEnd);              processTransitionEvents(itNoteEvent, iSubFragmentEnd);
443                processGroupEvents(itGroupEvent, iSubFragmentEnd);
444                
445                if (pSignalUnitRack == NULL) {
446                    // if the voice was killed in this subfragment, or if the
447                    // filter EG is finished, switch EG1 to fade out stage
448                    if ((itKillEvent && killPos <= iSubFragmentEnd) ||
449                        (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
450                        pEG2->getSegmentType() == EG::segment_end)) {
451                        pEG1->enterFadeOutStage();
452                        itKillEvent = Pool<Event>::Iterator();
453                    }
454    
455              // if the voice was killed in this subfragment, or if the                  // process envelope generators
456              // filter EG is finished, switch EG1 to fade out stage                  switch (pEG1->getSegmentType()) {
457              if ((itKillEvent && killPos <= iSubFragmentEnd) ||                      case EG::segment_lin:
458                  (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&                          fFinalVolume *= pEG1->processLin();
459                   EG2.getSegmentType() == gig::EGADSR::segment_end)) {                          break;
460                  EG1.enterFadeOutStage();                      case EG::segment_exp:
461                  itKillEvent = Pool<Event>::Iterator();                          fFinalVolume *= pEG1->processExp();
462              }                          break;
463                        case EG::segment_end:
464              // process envelope generators                          fFinalVolume *= pEG1->getLevel();
465              switch (EG1.getSegmentType()) {                          break; // noop
466                  case gig::EGADSR::segment_lin:                      case EG::segment_pow:
467                      fFinalVolume *= EG1.processLin();                          fFinalVolume *= pEG1->processPow();
468                      break;                          break;
469                  case gig::EGADSR::segment_exp:                  }
470                      fFinalVolume *= EG1.processExp();                  switch (pEG2->getSegmentType()) {
471                      break;                      case EG::segment_lin:
472                  case gig::EGADSR::segment_end:                          fFinalCutoff *= pEG2->processLin();
473                      fFinalVolume *= EG1.getLevel();                          break;
474                      break; // noop                      case EG::segment_exp:
475              }                          fFinalCutoff *= pEG2->processExp();
476              switch (EG2.getSegmentType()) {                          break;
477                  case gig::EGADSR::segment_lin:                      case EG::segment_end:
478                      fFinalCutoff *= EG2.processLin();                          fFinalCutoff *= pEG2->getLevel();
479                      break;                          break; // noop
480                  case gig::EGADSR::segment_exp:                      case EG::segment_pow:
481                      fFinalCutoff *= EG2.processExp();                          fFinalCutoff *= pEG2->processPow();
482                      break;                          break;
483                  case gig::EGADSR::segment_end:                  }
484                      fFinalCutoff *= EG2.getLevel();                  if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();
                     break; // noop  
             }  
             if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();  
   
             // process low frequency oscillators  
             if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());  
             if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();  
             if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());  
485    
486                    // process low frequency oscillators
487                    if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());
488                    if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();
489                    if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
490                } else {
491                    // if the voice was killed in this subfragment, enter fade out stage
492                    if (itKillEvent && killPos <= iSubFragmentEnd) {
493                        pSignalUnitRack->EnterFadeOutStage();
494                        itKillEvent = Pool<Event>::Iterator();
495                    }
496                    
497                    // if the filter EG is finished, switch EG1 to fade out stage
498                    /*if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
499                        pEG2->getSegmentType() == EG::segment_end) {
500                        pEG1->enterFadeOutStage();
501                        itKillEvent = Pool<Event>::Iterator();
502                    }*/
503                    // TODO: ^^^
504    
505                    fFinalVolume   *= pSignalUnitRack->GetEndpointUnit()->GetVolume();
506                    fFinalCutoff    = pSignalUnitRack->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff);
507                    fFinalResonance = pSignalUnitRack->GetEndpointUnit()->CalculateResonance(fFinalResonance);
508                    
509                    finalSynthesisParameters.fFinalPitch =
510                        pSignalUnitRack->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);
511                        
512                }
513                
514              // limit the pitch so we don't read outside the buffer              // limit the pitch so we don't read outside the buffer
515              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));
516    
# Line 445  namespace LinuxSampler { Line 543  namespace LinuxSampler {
543                  fFinalVolume * VolumeRight * PanRightSmoother.render();                  fFinalVolume * VolumeRight * PanRightSmoother.render();
544  #endif  #endif
545              // render audio for one subfragment              // render audio for one subfragment
546              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);              if (!delay) RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
547    
548              // stop the rendering if volume EG is finished              if (pSignalUnitRack == NULL) {
549              if (EG1.getSegmentType() == gig::EGADSR::segment_end) break;                  // stop the rendering if volume EG is finished
550                    if (pEG1->getSegmentType() == EG::segment_end) break;
551                } else {
552                    // stop the rendering if the endpoint unit is not active
553                    if (!pSignalUnitRack->GetEndpointUnit()->Active()) break;
554                }
555    
556              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
557    
558              // increment envelopes' positions              if (pSignalUnitRack == NULL) {
559              if (EG1.active()) {                  // increment envelopes' positions
560                    if (pEG1->active()) {
561    
562                        // if sample has a loop and loop start has been reached in this subfragment, send a special event to EG1 to let it finish the attack hold stage
563                        if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
564                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
565                        }
566    
567                  // if sample has a loop and loop start has been reached in this subfragment, send a special event to EG1 to let it finish the attack hold stage                      pEG1->increment(1);
568                  if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {                      if (!pEG1->toStageEndLeft()) pEG1->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
                     EG1.update(gig::EGADSR::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);  
569                  }                  }
570                    if (pEG2->active()) {
571                  EG1.increment(1);                      pEG2->increment(1);
572                  if (!EG1.toStageEndLeft()) EG1.update(gig::EGADSR::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                      if (!pEG2->toStageEndLeft()) pEG2->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
573              }                  }
574              if (EG2.active()) {                  EG3.increment(1);
575                  EG2.increment(1);                  if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
576                  if (!EG2.toStageEndLeft()) EG2.update(gig::EGADSR::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              } else {
577                        // if sample has a loop and loop start has been reached in this subfragment, send a special event to EG1 to let it finish the attack hold stage
578                        /*if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
579                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
580                        }*/
581                    // TODO: ^^^
582                    
583                    if (!delay) pSignalUnitRack->Increment();
584              }              }
             EG3.increment(1);  
             if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached  
585    
586              Pos = newPos;              Pos = newPos;
587              i = iSubFragmentEnd;              i = iSubFragmentEnd;
588          }          }
589            
590            if (delay) return;
591    
592            if (bVoiceRequiresDedicatedRouting) {
593                if (bEq) {
594                    pEq->RenderAudio(Samples);
595                    pEq->GetOutChannelLeft()->CopyTo(GetEngine()->pDedicatedVoiceChannelLeft, Samples);
596                    pEq->GetOutChannelRight()->CopyTo(GetEngine()->pDedicatedVoiceChannelRight, Samples);
597                }
598                optional<float> effectSendLevels[2] = {
599                    pMidiKeyInfo->ReverbSend,
600                    pMidiKeyInfo->ChorusSend
601                };
602                GetEngine()->RouteDedicatedVoiceChannels(pEngineChannel, effectSendLevels, Samples);
603            } else if (bEq) {
604                pEq->RenderAudio(Samples);
605                pEq->GetOutChannelLeft()->MixTo(pChannel->pChannelLeft, Samples);
606                pEq->GetOutChannelRight()->MixTo(pChannel->pChannelRight, Samples);
607            }
608      }      }
609        
610      /**      /**
611       * Process given list of MIDI control change and pitch bend events for       * Process given list of MIDI control change and pitch bend events for
612       * the given time.       * the given time.
# Line 491  namespace LinuxSampler { Line 623  namespace LinuxSampler {
623                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
624                      processResonanceEvent(itEvent);                      processResonanceEvent(itEvent);
625                  }                  }
626                  if (itEvent->Param.CC.Controller == pLFO1->ExtController) {                  if (pSignalUnitRack == NULL) {
627                      pLFO1->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
628                  }                          pLFO1->update(itEvent->Param.CC.Value);
629                  if (itEvent->Param.CC.Controller == pLFO2->ExtController) {                      }
630                      pLFO2->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO2->ExtController) {
631                  }                          pLFO2->update(itEvent->Param.CC.Value);
632                  if (itEvent->Param.CC.Controller == pLFO3->ExtController) {                      }
633                      pLFO3->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO3->ExtController) {
634                            pLFO3->update(itEvent->Param.CC.Value);
635                        }
636                  }                  }
637                  if (itEvent->Param.CC.Controller == 7) { // volume                  if (itEvent->Param.CC.Controller == 7) { // volume
638                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);
639                  } else if (itEvent->Param.CC.Controller == 10) { // panpot                  } else if (itEvent->Param.CC.Controller == 10) { // panpot
640                      PanLeftSmoother.update(AbstractEngine::PanCurve[128 - itEvent->Param.CC.Value]);                      MIDIPan = itEvent->Param.CC.Value;
                     PanRightSmoother.update(AbstractEngine::PanCurve[itEvent->Param.CC.Value]);  
641                  }                  }
642              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event
643                  processPitchEvent(itEvent);                  processPitchEvent(itEvent);
644              }              }
645    
646              ProcessCCEvent(itEvent);              ProcessCCEvent(itEvent);
647                if (pSignalUnitRack != NULL) {
648                    pSignalUnitRack->ProcessCCEvent(itEvent);
649                }
650          }          }
651      }      }
652    
# Line 537  namespace LinuxSampler { Line 673  namespace LinuxSampler {
673       */       */
674      void AbstractVoice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {      void AbstractVoice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {
675          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
676              if (itEvent->Type == Event::type_release) {              // some voice types ignore note off
677                  EG1.update(gig::EGADSR::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              if (!(Type & (Voice::type_one_shot | Voice::type_release_trigger | Voice::type_controller_triggered))) {
678                  EG2.update(gig::EGADSR::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (itEvent->Type == Event::type_release) {
679              } else if (itEvent->Type == Event::type_cancel_release) {                      EnterReleaseStage();
680                  EG1.update(gig::EGADSR::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  } else if (itEvent->Type == Event::type_cancel_release) {
681                  EG2.update(gig::EGADSR::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                      if (pSignalUnitRack == NULL) {
682                            pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
683                            pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
684                        } else {
685                            pSignalUnitRack->CancelRelease();
686                        }
687                    }
688              }              }
689          }          }
690      }      }
691    
692        /**
693         * Process given list of events aimed at all voices in a key group.
694         *
695         * @param itEvent - iterator pointing to the next event to be processed
696         * @param End     - youngest time stamp where processing should be stopped
697         */
698        void AbstractVoice::processGroupEvents(RTList<Event>::Iterator& itEvent, uint End) {
699            for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
700                ProcessGroupEvent(itEvent);
701            }
702        }
703    
704      /** @brief Update current portamento position.      /** @brief Update current portamento position.
705       *       *
706       * Will be called when portamento mode is enabled to get the final       * Will be called when portamento mode is enabled to get the final
# Line 556  namespace LinuxSampler { Line 710  namespace LinuxSampler {
710       * @param itNoteOffEvent - event which causes this voice to die soon       * @param itNoteOffEvent - event which causes this voice to die soon
711       */       */
712      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
713          const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());          if (pSignalUnitRack == NULL) {
714          pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;              const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
715                pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
716            } else {
717                // TODO:
718            }
719      }      }
720    
721      /**      /**
# Line 604  namespace LinuxSampler { Line 762  namespace LinuxSampler {
762          volume *= GetSampleAttenuation() * pEngineChannel->GlobalVolume * GLOBAL_VOLUME;          volume *= GetSampleAttenuation() * pEngineChannel->GlobalVolume * GLOBAL_VOLUME;
763    
764          // the volume of release triggered samples depends on note length          // the volume of release triggered samples depends on note length
765          if (Type == Voice::type_release_trigger) {          if (Type & Voice::type_release_trigger) {
766              float noteLength = float(GetEngine()->FrameTime + Delay -              float noteLength = float(GetEngine()->FrameTime + Delay -
767                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;
768    
769              float attenuation = 1 - 0.01053 * (256 >> RgnInfo.ReleaseTriggerDecay) * noteLength;              volume *= GetReleaseTriggerAttenuation(noteLength);
             volume *= attenuation;  
770          }          }
771    
772          return volume;          return volume;
773      }      }
774    
775        float AbstractVoice::GetReleaseTriggerAttenuation(float noteLength) {
776            return 1 - RgnInfo.ReleaseTriggerDecay * noteLength;
777        }
778    
779        void AbstractVoice::EnterReleaseStage() {
780            if (pSignalUnitRack == NULL) {
781                pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
782                pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
783            } else {
784                pSignalUnitRack->EnterReleaseStage();
785            }
786        }
787    
788        bool AbstractVoice::EG1Finished() {
789            if (pSignalUnitRack == NULL) {
790                return pEG1->getSegmentType() == EG::segment_end;
791            } else {
792                return !pSignalUnitRack->GetEndpointUnit()->Active();
793            }
794        }
795    
796  } // namespace LinuxSampler  } // namespace LinuxSampler

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

  ViewVC Help
Powered by ViewVC