/[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 2114 by persson, Tue Aug 10 12:05:19 2010 UTC revision 2297 by iliev, Fri Dec 9 15:04:55 2011 UTC
# Line 4  Line 4 
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2010 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2011 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;
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)
# Line 99  namespace LinuxSampler { Line 99  namespace LinuxSampler {
99    
100          Type            = VoiceType;          Type            = VoiceType;
101          MIDIKey         = itNoteOnEvent->Param.Note.Key;          MIDIKey         = itNoteOnEvent->Param.Note.Key;
102            MIDIVelocity    = itNoteOnEvent->Param.Note.Velocity;
103            MIDIPan         = pEngineChannel->ControllerTable[10];
104            if (MIDIPan == 0 && pEngineChannel->GlobalPanRight == 1) MIDIPan = 64; // workaround used to determine whether the MIDI pan has not been set
105          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
106          Delay           = itNoteOnEvent->FragmentPos();          Delay           = itNoteOnEvent->FragmentPos();
107          itTriggerEvent  = itNoteOnEvent;          itTriggerEvent  = itNoteOnEvent;
108          itKillEvent     = Pool<Event>::Iterator();          itKillEvent     = Pool<Event>::Iterator();
109            MidiKeyBase* pKeyInfo = GetMidiKeyInfo(MIDIKey);
110    
111          pGroupEvents = iKeyGroup ? pEngineChannel->ActiveKeyGroups[iKeyGroup] : 0;          pGroupEvents = iKeyGroup ? pEngineChannel->ActiveKeyGroups[iKeyGroup] : 0;
112    
113          SmplInfo   = GetSampleInfo();          SmplInfo   = GetSampleInfo();
114          RgnInfo    = GetRegionInfo();          RgnInfo    = GetRegionInfo();
115          InstrInfo  = GetInstrumentInfo();          InstrInfo  = GetInstrumentInfo();
116            
117            AboutToTrigger();
118    
119          // calculate volume          // calculate volume
120          const double velocityAttenuation = GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity);          const double velocityAttenuation = GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity);
121          float volume = CalculateVolume(velocityAttenuation);          float volume = CalculateVolume(velocityAttenuation) * pKeyInfo->Volume;
122          if (volume <= 0) return -1;          if (volume <= 0) return -1;
123    
124          // select channel mode (mono or stereo)          // select channel mode (mono or stereo)
# Line 123  namespace LinuxSampler { Line 129  namespace LinuxSampler {
129          // get starting crossfade volume level          // get starting crossfade volume level
130          float crossfadeVolume = CalculateCrossfadeVolume(itNoteOnEvent->Param.Note.Velocity);          float crossfadeVolume = CalculateCrossfadeVolume(itNoteOnEvent->Param.Note.Velocity);
131    
132          VolumeLeft  = volume * AbstractEngine::PanCurve[64 - RgnInfo.Pan];          VolumeLeft  = volume * pKeyInfo->PanLeft  * AbstractEngine::PanCurve[64 - RgnInfo.Pan];
133          VolumeRight = volume * AbstractEngine::PanCurve[64 + RgnInfo.Pan];          VolumeRight = volume * pKeyInfo->PanRight * AbstractEngine::PanCurve[64 + RgnInfo.Pan];
134    
135          float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;          float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;
136          CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);          CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);
# Line 132  namespace LinuxSampler { Line 138  namespace LinuxSampler {
138          PanLeftSmoother.trigger(pEngineChannel->GlobalPanLeft, subfragmentRate);          PanLeftSmoother.trigger(pEngineChannel->GlobalPanLeft, subfragmentRate);
139          PanRightSmoother.trigger(pEngineChannel->GlobalPanRight, subfragmentRate);          PanRightSmoother.trigger(pEngineChannel->GlobalPanRight, subfragmentRate);
140    
         finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)  
         Pos = RgnInfo.SampleStartOffset;  
   
141          // 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
142          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;
143          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;
144    
145            SetSampleStartOffset();
146    
147          if (DiskVoice) { // voice to be streamed from disk          if (DiskVoice) { // voice to be streamed from disk
148              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {
149                  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 180  namespace LinuxSampler {
180          // 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
181          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);
182    
183          // setup EG 1 (VCA EG)          if (pSignalUnitRack == NULL) { // setup EG 1 (VCA EG)
         {  
184              // get current value of EG1 controller              // get current value of EG1 controller
185              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);
186    
# Line 184  namespace LinuxSampler { Line 188  namespace LinuxSampler {
188              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);
189    
190              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
191            } else {
192                pSignalUnitRack->Trigger();
193          }          }
194    
195  #ifdef CONFIG_INTERPOLATE_VOLUME  #ifdef CONFIG_INTERPOLATE_VOLUME
# Line 196  namespace LinuxSampler { Line 202  namespace LinuxSampler {
202          else          else
203      #else      #else
204          {          {
205              float finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();              float finalVolume;
206                if (pSignalUnitRack == NULL) {
207                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();
208                } else {
209                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pSignalUnitRack->GetEndpointUnit()->GetVolume();
210                }
211    
212              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * pEngineChannel->GlobalPanLeft;              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * pEngineChannel->GlobalPanLeft;
213              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight;              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight;
# Line 204  namespace LinuxSampler { Line 215  namespace LinuxSampler {
215      #endif      #endif
216  #endif  #endif
217    
218          // setup EG 2 (VCF Cutoff EG)          if (pSignalUnitRack == NULL) {
219          {              // setup EG 2 (VCF Cutoff EG)
220              // get current value of EG2 controller              {
221              double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);                  // get current value of EG2 controller
222                    double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);
223    
224                    // calculate influence of EG2 controller on EG2's parameters
225                    EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);
226    
227                    TriggerEG2(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
228                }
229    
             // calculate influence of EG2 controller on EG2's parameters  
             EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);  
230    
231              EG2.trigger (              // setup EG 3 (VCO EG)
232                  uint(RgnInfo.EG2PreAttack),              {
233                  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
234                  false,                  bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;
235                  RgnInfo.EG2Decay1 * egInfo.Decay * velrelease,                  float eg3depth = (bPortamento)
236                  RgnInfo.EG2Decay2 * egInfo.Decay * velrelease,                               ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100)
237                  RgnInfo.EG2InfiniteSustain,                               : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);
238                  uint(RgnInfo.EG2Sustain),                  float eg3time = (bPortamento)
239                  RgnInfo.EG2Release * egInfo.Release * velrelease,                              ? pEngineChannel->PortamentoTime
240                  velocityAttenuation,                              : RgnInfo.EG3Attack;
241                  GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE                  EG3.trigger(eg3depth, eg3time, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
242              );                  dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time));
243          }              }
244    
245    
246          // setup EG 3 (VCO EG)              // setup LFO 1 (VCA LFO)
247          {              InitLFO1();
248              // 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)
249              bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;              InitLFO2();
250              float eg3depth = (bPortamento)              // setup LFO 3 (VCO LFO)
251                           ? 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));  
252          }          }
253    
254    
         // setup LFO 1 (VCA LFO)  
         InitLFO1();  
         // setup LFO 2 (VCF Cutoff LFO)  
         InitLFO2();  
         // setup LFO 3 (VCO LFO)  
         InitLFO3();  
   
   
255          #if CONFIG_FORCE_FILTER          #if CONFIG_FORCE_FILTER
256          const bool bUseFilter = true;          const bool bUseFilter = true;
257          #else // use filter only if instrument file told so          #else // use filter only if instrument file told so
# Line 295  namespace LinuxSampler { Line 297  namespace LinuxSampler {
297    
298          return 0; // success          return 0; // success
299      }      }
300        
301        void AbstractVoice::SetSampleStartOffset() {
302            finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
303            Pos = RgnInfo.SampleStartOffset;
304        }
305    
306      /**      /**
307       *  Synthesizes the current audio fragment for this voice.       *  Synthesizes the current audio fragment for this voice.
# Line 305  namespace LinuxSampler { Line 312  namespace LinuxSampler {
312       *  @param Skip    - number of sample points to skip in output buffer       *  @param Skip    - number of sample points to skip in output buffer
313       */       */
314      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
315            bool delay = false; // Whether the voice playback should be delayed for this call
316            
317            if (pSignalUnitRack != NULL) {
318                uint delaySteps = pSignalUnitRack->GetEndpointUnit()->DelayTrigger();
319                if (delaySteps > 0) { // delay on the endpoint unit means delay of the voice playback
320                    if (delaySteps >= Samples) {
321                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(Samples);
322                        delay = true;
323                    } else {
324                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(delaySteps);
325                        Samples -= delaySteps;
326                        Skip += delaySteps;
327                    }
328                }
329            }
330            
331          AbstractEngineChannel* pChannel = pEngineChannel;          AbstractEngineChannel* pChannel = pEngineChannel;
332          finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];          MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey);
333          finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];  
334          finalSynthesisParameters.pSrc      = pSrc;          const bool bVoiceRequiresDedicatedRouting =
335                pEngineChannel->GetFxSendCount() > 0 &&
336                (pMidiKeyInfo->ReverbSend || pMidiKeyInfo->ChorusSend);
337            
338            const bool bEq =
339                pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && GetEngine()->pEq->HasSupport();
340    
341            if (bEq) {
342                GetEngine()->pEq->GetInChannelLeft()->Clear();
343                GetEngine()->pEq->GetInChannelRight()->Clear();
344                finalSynthesisParameters.pOutLeft  = &GetEngine()->pEq->GetInChannelLeft()->Buffer()[Skip];
345                finalSynthesisParameters.pOutRight = &GetEngine()->pEq->GetInChannelRight()->Buffer()[Skip];
346                pSignalUnitRack->UpdateEqSettings(GetEngine()->pEq);
347            } else if (bVoiceRequiresDedicatedRouting) {
348                finalSynthesisParameters.pOutLeft  = &GetEngine()->pDedicatedVoiceChannelLeft->Buffer()[Skip];
349                finalSynthesisParameters.pOutRight = &GetEngine()->pDedicatedVoiceChannelRight->Buffer()[Skip];
350            } else {
351                finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];
352                finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];
353            }
354            finalSynthesisParameters.pSrc = pSrc;
355    
356          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();
357          RTList<Event>::Iterator itNoteEvent;          RTList<Event>::Iterator itNoteEvent;
# Line 341  namespace LinuxSampler { Line 384  namespace LinuxSampler {
384                  // drivers that use Samples < MaxSamplesPerCycle).                  // drivers that use Samples < MaxSamplesPerCycle).
385                  // End the EG1 here, at pos 0, with a shorter max fade                  // End the EG1 here, at pos 0, with a shorter max fade
386                  // out time.                  // out time.
387                  pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (pSignalUnitRack == NULL) {
388                        pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
389                    } else {
390                        // TODO:
391                    }
392                  itKillEvent = Pool<Event>::Iterator();                  itKillEvent = Pool<Event>::Iterator();
393              } else {              } else {
394                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);
# Line 358  namespace LinuxSampler { Line 405  namespace LinuxSampler {
405    
406              // process MIDI control change and pitchbend events for this subfragment              // process MIDI control change and pitchbend events for this subfragment
407              processCCEvents(itCCEvent, iSubFragmentEnd);              processCCEvents(itCCEvent, iSubFragmentEnd);
408                uint8_t pan = MIDIPan;
409                if (pSignalUnitRack != NULL) pan = pSignalUnitRack->GetEndpointUnit()->CaluclatePan(pan);
410                
411                PanLeftSmoother.update(AbstractEngine::PanCurve[128 - pan]);
412                PanRightSmoother.update(AbstractEngine::PanCurve[pan]);
413    
414              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend;              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend;
415              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();
# Line 368  namespace LinuxSampler { Line 420  namespace LinuxSampler {
420              // process transition events (note on, note off & sustain pedal)              // process transition events (note on, note off & sustain pedal)
421              processTransitionEvents(itNoteEvent, iSubFragmentEnd);              processTransitionEvents(itNoteEvent, iSubFragmentEnd);
422              processGroupEvents(itGroupEvent, iSubFragmentEnd);              processGroupEvents(itGroupEvent, iSubFragmentEnd);
423                
424                if (pSignalUnitRack == NULL) {
425                    // if the voice was killed in this subfragment, or if the
426                    // filter EG is finished, switch EG1 to fade out stage
427                    if ((itKillEvent && killPos <= iSubFragmentEnd) ||
428                        (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
429                        pEG2->getSegmentType() == EG::segment_end)) {
430                        pEG1->enterFadeOutStage();
431                        itKillEvent = Pool<Event>::Iterator();
432                    }
433    
434              // if the voice was killed in this subfragment, or if the                  // process envelope generators
435              // filter EG is finished, switch EG1 to fade out stage                  switch (pEG1->getSegmentType()) {
436              if ((itKillEvent && killPos <= iSubFragmentEnd) ||                      case EG::segment_lin:
437                  (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&                          fFinalVolume *= pEG1->processLin();
438                   EG2.getSegmentType() == gig::EGADSR::segment_end)) {                          break;
439                  pEG1->enterFadeOutStage();                      case EG::segment_exp:
440                  itKillEvent = Pool<Event>::Iterator();                          fFinalVolume *= pEG1->processExp();
441              }                          break;
442                        case EG::segment_end:
443                            fFinalVolume *= pEG1->getLevel();
444                            break; // noop
445                        case EG::segment_pow:
446                            fFinalVolume *= pEG1->processPow();
447                            break;
448                    }
449                    switch (pEG2->getSegmentType()) {
450                        case EG::segment_lin:
451                            fFinalCutoff *= pEG2->processLin();
452                            break;
453                        case EG::segment_exp:
454                            fFinalCutoff *= pEG2->processExp();
455                            break;
456                        case EG::segment_end:
457                            fFinalCutoff *= pEG2->getLevel();
458                            break; // noop
459                        case EG::segment_pow:
460                            fFinalCutoff *= pEG2->processPow();
461                            break;
462                    }
463                    if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();
464    
465              // process envelope generators                  // process low frequency oscillators
466              switch (pEG1->getSegmentType()) {                  if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());
467                  case EG::segment_lin:                  if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();
468                      fFinalVolume *= pEG1->processLin();                  if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
469                      break;              } else {
470                  case EG::segment_exp:                  // if the voice was killed in this subfragment, or if the
471                      fFinalVolume *= pEG1->processExp();                  // filter EG is finished, switch EG1 to fade out stage
472                      break;                  /*if ((itKillEvent && killPos <= iSubFragmentEnd) ||
473                  case EG::segment_end:                      (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
474                      fFinalVolume *= pEG1->getLevel();                      pEG2->getSegmentType() == EG::segment_end)) {
475                      break; // noop                      pEG1->enterFadeOutStage();
476                  case EG::segment_pow:                      itKillEvent = Pool<Event>::Iterator();
477                      fFinalVolume *= pEG1->processPow();                  }*/
478                      break;                  // TODO: ^^^
479    
480                    fFinalVolume   *= pSignalUnitRack->GetEndpointUnit()->GetVolume();
481                    fFinalCutoff    = pSignalUnitRack->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff);
482                    fFinalResonance = pSignalUnitRack->GetEndpointUnit()->CalculateResonance(fFinalResonance);
483                    
484                    finalSynthesisParameters.fFinalPitch =
485                        pSignalUnitRack->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);
486                        
487              }              }
488              switch (EG2.getSegmentType()) {              
                 case gig::EGADSR::segment_lin:  
                     fFinalCutoff *= EG2.processLin();  
                     break;  
                 case gig::EGADSR::segment_exp:  
                     fFinalCutoff *= EG2.processExp();  
                     break;  
                 case gig::EGADSR::segment_end:  
                     fFinalCutoff *= EG2.getLevel();  
                     break; // noop  
             }  
             if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();  
   
             // process low frequency oscillators  
             if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());  
             if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();  
             if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());  
   
489              // limit the pitch so we don't read outside the buffer              // limit the pitch so we don't read outside the buffer
490              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));
491    
# Line 443  namespace LinuxSampler { Line 518  namespace LinuxSampler {
518                  fFinalVolume * VolumeRight * PanRightSmoother.render();                  fFinalVolume * VolumeRight * PanRightSmoother.render();
519  #endif  #endif
520              // render audio for one subfragment              // render audio for one subfragment
521              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);              if (!delay) RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
522    
523              // stop the rendering if volume EG is finished              if (pSignalUnitRack == NULL) {
524              if (pEG1->getSegmentType() == EG::segment_end) break;                  // stop the rendering if volume EG is finished
525                    if (pEG1->getSegmentType() == EG::segment_end) break;
526                } else {
527                    // stop the rendering if the endpoint unit is not active
528                    if (!pSignalUnitRack->GetEndpointUnit()->Active()) break;
529                }
530    
531              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
532    
533              // increment envelopes' positions              if (pSignalUnitRack == NULL) {
534              if (pEG1->active()) {                  // increment envelopes' positions
535                    if (pEG1->active()) {
536    
537                        // 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
538                        if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
539                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
540                        }
541    
542                  // 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);
543                  if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {                      if (!pEG1->toStageEndLeft()) pEG1->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
                     pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);  
544                  }                  }
545                    if (pEG2->active()) {
546                  pEG1->increment(1);                      pEG2->increment(1);
547                  if (!pEG1->toStageEndLeft()) pEG1->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                      if (!pEG2->toStageEndLeft()) pEG2->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
548              }                  }
549              if (EG2.active()) {                  EG3.increment(1);
550                  EG2.increment(1);                  if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
551                  if (!EG2.toStageEndLeft()) EG2.update(gig::EGADSR::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              } else {
552                        // 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
553                        /*if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
554                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
555                        }*/
556                    // TODO: ^^^
557                    
558                    if (!delay) pSignalUnitRack->Increment();
559              }              }
             EG3.increment(1);  
             if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached  
560    
561              Pos = newPos;              Pos = newPos;
562              i = iSubFragmentEnd;              i = iSubFragmentEnd;
563          }          }
564            
565            if (delay) return;
566    
567            if (bVoiceRequiresDedicatedRouting) {
568                if (bEq) {
569                    GetEngine()->pEq->RenderAudio(Samples);
570                    GetEngine()->pEq->GetOutChannelLeft()->CopyTo(GetEngine()->pDedicatedVoiceChannelLeft, Samples);
571                    GetEngine()->pEq->GetOutChannelRight()->CopyTo(GetEngine()->pDedicatedVoiceChannelRight, Samples);
572                }
573                optional<float> effectSendLevels[2] = {
574                    pMidiKeyInfo->ReverbSend,
575                    pMidiKeyInfo->ChorusSend
576                };
577                GetEngine()->RouteDedicatedVoiceChannels(pEngineChannel, effectSendLevels, Samples);
578            } else if (bEq) {
579                GetEngine()->pEq->RenderAudio(Samples);
580                GetEngine()->pEq->GetOutChannelLeft()->CopyTo(pChannel->pChannelLeft, Samples);
581                GetEngine()->pEq->GetOutChannelRight()->CopyTo(pChannel->pChannelRight, Samples);
582            }
583      }      }
584    
585      /**      /**
# Line 489  namespace LinuxSampler { Line 598  namespace LinuxSampler {
598                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
599                      processResonanceEvent(itEvent);                      processResonanceEvent(itEvent);
600                  }                  }
601                  if (itEvent->Param.CC.Controller == pLFO1->ExtController) {                  if (pSignalUnitRack == NULL) {
602                      pLFO1->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
603                  }                          pLFO1->update(itEvent->Param.CC.Value);
604                  if (itEvent->Param.CC.Controller == pLFO2->ExtController) {                      }
605                      pLFO2->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO2->ExtController) {
606                  }                          pLFO2->update(itEvent->Param.CC.Value);
607                  if (itEvent->Param.CC.Controller == pLFO3->ExtController) {                      }
608                      pLFO3->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO3->ExtController) {
609                            pLFO3->update(itEvent->Param.CC.Value);
610                        }
611                  }                  }
612                  if (itEvent->Param.CC.Controller == 7) { // volume                  if (itEvent->Param.CC.Controller == 7) { // volume
613                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);
614                  } else if (itEvent->Param.CC.Controller == 10) { // panpot                  } else if (itEvent->Param.CC.Controller == 10) { // panpot
615                      PanLeftSmoother.update(AbstractEngine::PanCurve[128 - itEvent->Param.CC.Value]);                      MIDIPan = itEvent->Param.CC.Value;
                     PanRightSmoother.update(AbstractEngine::PanCurve[itEvent->Param.CC.Value]);  
616                  }                  }
617              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event
618                  processPitchEvent(itEvent);                  processPitchEvent(itEvent);
619              }              }
620    
621              ProcessCCEvent(itEvent);              ProcessCCEvent(itEvent);
622                if (pSignalUnitRack != NULL) {
623                    pSignalUnitRack->ProcessCCEvent(itEvent);
624                }
625          }          }
626      }      }
627    
# Line 535  namespace LinuxSampler { Line 648  namespace LinuxSampler {
648       */       */
649      void AbstractVoice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {      void AbstractVoice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {
650          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
651              if (Type != Voice::type_release_trigger) {              // some voice types ignore note off
652                if (!(Type & (Voice::type_one_shot | Voice::type_release_trigger | Voice::type_controller_triggered))) {
653                  if (itEvent->Type == Event::type_release) {                  if (itEvent->Type == Event::type_release) {
654                      EnterReleaseStage();                      EnterReleaseStage();
655                  } else if (itEvent->Type == Event::type_cancel_release) {                  } else if (itEvent->Type == Event::type_cancel_release) {
656                      pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                      if (pSignalUnitRack == NULL) {
657                      EG2.update(gig::EGADSR::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                          pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
658                            pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
659                        } else {
660                            pSignalUnitRack->CancelRelease();
661                        }
662                  }                  }
663              }              }
664          }          }
# Line 568  namespace LinuxSampler { Line 685  namespace LinuxSampler {
685       * @param itNoteOffEvent - event which causes this voice to die soon       * @param itNoteOffEvent - event which causes this voice to die soon
686       */       */
687      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
688          const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());          if (pSignalUnitRack == NULL) {
689          pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;              const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
690                pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
691            } else {
692                // TODO:
693            }
694      }      }
695    
696      /**      /**
# Line 616  namespace LinuxSampler { Line 737  namespace LinuxSampler {
737          volume *= GetSampleAttenuation() * pEngineChannel->GlobalVolume * GLOBAL_VOLUME;          volume *= GetSampleAttenuation() * pEngineChannel->GlobalVolume * GLOBAL_VOLUME;
738    
739          // the volume of release triggered samples depends on note length          // the volume of release triggered samples depends on note length
740          if (Type == Voice::type_release_trigger) {          if (Type & Voice::type_release_trigger) {
741              float noteLength = float(GetEngine()->FrameTime + Delay -              float noteLength = float(GetEngine()->FrameTime + Delay -
742                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;
743    
# Line 631  namespace LinuxSampler { Line 752  namespace LinuxSampler {
752      }      }
753    
754      void AbstractVoice::EnterReleaseStage() {      void AbstractVoice::EnterReleaseStage() {
755          pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);          if (pSignalUnitRack == NULL) {
756          EG2.update(gig::EGADSR::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
757                pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
758            } else {
759                pSignalUnitRack->EnterReleaseStage();
760            }
761        }
762    
763        bool AbstractVoice::EG1Finished() {
764            if (pSignalUnitRack == NULL) {
765                return pEG1->getSegmentType() == EG::segment_end;
766            } else {
767                return !pSignalUnitRack->GetEndpointUnit()->Active();
768            }
769      }      }
770    
771  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.2114  
changed lines
  Added in v.2297

  ViewVC Help
Powered by ViewVC