/[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 2216 by iliev, Mon Jul 25 17:21:16 2011 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-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 28  namespace LinuxSampler { Line 28  namespace LinuxSampler {
28    
29      AbstractVoice::AbstractVoice() {      AbstractVoice::AbstractVoice() {
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 51  namespace LinuxSampler { Line 50  namespace LinuxSampler {
50          if (pLFO2) delete pLFO2;          if (pLFO2) delete pLFO2;
51          if (pLFO3) delete pLFO3;          if (pLFO3) delete pLFO3;
52      }      }
53        
54      /**      /**
55       *  Resets voice variables. Should only be called if rendering process is       *  Resets voice variables. Should only be called if rendering process is
56       *  suspended / not running.       *  suspended / not running.
# Line 104  namespace LinuxSampler { Line 103  namespace LinuxSampler {
103          Delay           = itNoteOnEvent->FragmentPos();          Delay           = itNoteOnEvent->FragmentPos();
104          itTriggerEvent  = itNoteOnEvent;          itTriggerEvent  = itNoteOnEvent;
105          itKillEvent     = Pool<Event>::Iterator();          itKillEvent     = Pool<Event>::Iterator();
106          KeyGroup        = iKeyGroup;          MidiKeyBase* pKeyInfo = GetMidiKeyInfo(MIDIKey);
107    
108            pGroupEvents = iKeyGroup ? pEngineChannel->ActiveKeyGroups[iKeyGroup] : 0;
109    
110          SmplInfo   = GetSampleInfo();          SmplInfo   = GetSampleInfo();
111          RgnInfo    = GetRegionInfo();          RgnInfo    = GetRegionInfo();
112          InstrInfo  = GetInstrumentInfo();          InstrInfo  = GetInstrumentInfo();
113            
114            AboutToTrigger();
115    
116          // calculate volume          // calculate volume
117          const double velocityAttenuation = GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity);          const double velocityAttenuation = GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity);
118          float volume = CalculateVolume(velocityAttenuation);          float volume = CalculateVolume(velocityAttenuation) * pKeyInfo->Volume;
119          if (volume <= 0) return -1;          if (volume <= 0) return -1;
120    
121          // select channel mode (mono or stereo)          // select channel mode (mono or stereo)
# Line 123  namespace LinuxSampler { Line 126  namespace LinuxSampler {
126          // get starting crossfade volume level          // get starting crossfade volume level
127          float crossfadeVolume = CalculateCrossfadeVolume(itNoteOnEvent->Param.Note.Velocity);          float crossfadeVolume = CalculateCrossfadeVolume(itNoteOnEvent->Param.Note.Velocity);
128    
129          VolumeLeft  = volume * AbstractEngine::PanCurve[64 - RgnInfo.Pan];          VolumeLeft  = volume * pKeyInfo->PanLeft  * AbstractEngine::PanCurve[64 - RgnInfo.Pan];
130          VolumeRight = volume * AbstractEngine::PanCurve[64 + RgnInfo.Pan];          VolumeRight = volume * pKeyInfo->PanRight * AbstractEngine::PanCurve[64 + RgnInfo.Pan];
131    
132          float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;          float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;
133          CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);          CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);
# Line 132  namespace LinuxSampler { Line 135  namespace LinuxSampler {
135          PanLeftSmoother.trigger(pEngineChannel->GlobalPanLeft, subfragmentRate);          PanLeftSmoother.trigger(pEngineChannel->GlobalPanLeft, subfragmentRate);
136          PanRightSmoother.trigger(pEngineChannel->GlobalPanRight, subfragmentRate);          PanRightSmoother.trigger(pEngineChannel->GlobalPanRight, subfragmentRate);
137    
         finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)  
         Pos = RgnInfo.SampleStartOffset;  
   
138          // 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
139          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;
140          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;
141    
142            SetSampleStartOffset();
143    
144          if (DiskVoice) { // voice to be streamed from disk          if (DiskVoice) { // voice to be streamed from disk
145              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {
146                  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 177  namespace LinuxSampler {
177          // 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
178          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);
179    
180          // setup EG 1 (VCA EG)          if (GetSignalUnitRack() == NULL) { // setup EG 1 (VCA EG)
         {  
181              // get current value of EG1 controller              // get current value of EG1 controller
182              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);
183    
184              // calculate influence of EG1 controller on EG1's parameters              // calculate influence of EG1 controller on EG1's parameters
185              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);
186    
187              EG1.trigger (              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
188                  RgnInfo.EG1PreAttack,          } else {
189                  RgnInfo.EG1Attack * egInfo.Attack,              GetSignalUnitRack()->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  
             );  
190          }          }
191    
192  #ifdef CONFIG_INTERPOLATE_VOLUME  #ifdef CONFIG_INTERPOLATE_VOLUME
# Line 207  namespace LinuxSampler { Line 199  namespace LinuxSampler {
199          else          else
200      #else      #else
201          {          {
202              float finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * EG1.getLevel();              float finalVolume;
203                if (GetSignalUnitRack() == NULL) {
204                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();
205                } else {
206                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * GetSignalUnitRack()->GetEndpointUnit()->GetVolume();
207                }
208    
209              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * pEngineChannel->GlobalPanLeft;              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * pEngineChannel->GlobalPanLeft;
210              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight;              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight;
# Line 215  namespace LinuxSampler { Line 212  namespace LinuxSampler {
212      #endif      #endif
213  #endif  #endif
214    
215          // setup EG 2 (VCF Cutoff EG)          if (GetSignalUnitRack() == NULL) {
216          {              // setup EG 2 (VCF Cutoff EG)
217              // get current value of EG2 controller              {
218              double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);                  // get current value of EG2 controller
219                    double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);
220    
221                    // calculate influence of EG2 controller on EG2's parameters
222                    EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);
223    
224                    TriggerEG2(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
225                }
226    
             // calculate influence of EG2 controller on EG2's parameters  
             EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);  
227    
228              EG2.trigger (              // setup EG 3 (VCO EG)
229                  RgnInfo.EG2PreAttack,              {
230                  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
231                  false,                  bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;
232                  RgnInfo.EG2Decay1 * egInfo.Decay * velrelease,                  float eg3depth = (bPortamento)
233                  RgnInfo.EG2Decay2 * egInfo.Decay * velrelease,                               ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100)
234                  RgnInfo.EG2InfiniteSustain,                               : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);
235                  RgnInfo.EG2Sustain,                  float eg3time = (bPortamento)
236                  RgnInfo.EG2Release * egInfo.Release * velrelease,                              ? pEngineChannel->PortamentoTime
237                  velocityAttenuation,                              : RgnInfo.EG3Attack;
238                  GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE                  EG3.trigger(eg3depth, eg3time, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
239              );                  dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time));
240          }              }
241    
242    
243          // setup EG 3 (VCO EG)              // setup LFO 1 (VCA LFO)
244          {              InitLFO1();
245              // 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)
246              bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;              InitLFO2();
247              float eg3depth = (bPortamento)              // setup LFO 3 (VCO LFO)
248                           ? 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));  
249          }          }
250    
251    
         // setup LFO 1 (VCA LFO)  
         InitLFO1();  
         // setup LFO 2 (VCF Cutoff LFO)  
         InitLFO2();  
         // setup LFO 3 (VCO LFO)  
         InitLFO3();  
   
   
252          #if CONFIG_FORCE_FILTER          #if CONFIG_FORCE_FILTER
253          const bool bUseFilter = true;          const bool bUseFilter = true;
254          #else // use filter only if instrument file told so          #else // use filter only if instrument file told so
# Line 306  namespace LinuxSampler { Line 294  namespace LinuxSampler {
294    
295          return 0; // success          return 0; // success
296      }      }
297        
298        void AbstractVoice::SetSampleStartOffset() {
299            finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
300            Pos = RgnInfo.SampleStartOffset;
301        }
302    
303      /**      /**
304       *  Synthesizes the current audio fragment for this voice.       *  Synthesizes the current audio fragment for this voice.
# Line 317  namespace LinuxSampler { Line 310  namespace LinuxSampler {
310       */       */
311      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
312          AbstractEngineChannel* pChannel = pEngineChannel;          AbstractEngineChannel* pChannel = pEngineChannel;
313          finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];          MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey);
314          finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];  
315          finalSynthesisParameters.pSrc      = pSrc;          const bool bVoiceRequiresDedicatedRouting =
316                pEngineChannel->GetFxSendCount() > 0 &&
317                (pMidiKeyInfo->ReverbSend || pMidiKeyInfo->ChorusSend);
318    
319            if (bVoiceRequiresDedicatedRouting) {
320                finalSynthesisParameters.pOutLeft  = &GetEngine()->pDedicatedVoiceChannelLeft->Buffer()[Skip];
321                finalSynthesisParameters.pOutRight = &GetEngine()->pDedicatedVoiceChannelRight->Buffer()[Skip];
322            } else {
323                finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];
324                finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];
325            }
326            finalSynthesisParameters.pSrc = pSrc;
327    
328          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();
329          RTList<Event>::Iterator itNoteEvent;          RTList<Event>::Iterator itNoteEvent;
330          GetFirstEventOnKey(MIDIKey, itNoteEvent);          GetFirstEventOnKey(MIDIKey, itNoteEvent);
331    
332            RTList<Event>::Iterator itGroupEvent;
333            if (pGroupEvents) itGroupEvent = pGroupEvents->first();
334    
335          if (itTriggerEvent) { // skip events that happened before this voice was triggered          if (itTriggerEvent) { // skip events that happened before this voice was triggered
336              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;
337                while (itGroupEvent && itGroupEvent->FragmentPos() <= Skip) ++itGroupEvent;
338    
339              // we can't simply compare the timestamp here, because note events              // we can't simply compare the timestamp here, because note events
340              // 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
341              // 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 356  namespace LinuxSampler {
356                  // drivers that use Samples < MaxSamplesPerCycle).                  // drivers that use Samples < MaxSamplesPerCycle).
357                  // End the EG1 here, at pos 0, with a shorter max fade                  // End the EG1 here, at pos 0, with a shorter max fade
358                  // out time.                  // out time.
359                  EG1.enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (GetSignalUnitRack() == NULL) {
360                        pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
361                    } else {
362                        // TODO:
363                    }
364                  itKillEvent = Pool<Event>::Iterator();                  itKillEvent = Pool<Event>::Iterator();
365              } else {              } else {
366                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);
# Line 373  namespace LinuxSampler { Line 386  namespace LinuxSampler {
386    
387              // process transition events (note on, note off & sustain pedal)              // process transition events (note on, note off & sustain pedal)
388              processTransitionEvents(itNoteEvent, iSubFragmentEnd);              processTransitionEvents(itNoteEvent, iSubFragmentEnd);
389                processGroupEvents(itGroupEvent, iSubFragmentEnd);
390    
391              // if the voice was killed in this subfragment, or if the              if (GetSignalUnitRack() == NULL) {
392              // filter EG is finished, switch EG1 to fade out stage                  // if the voice was killed in this subfragment, or if the
393              if ((itKillEvent && killPos <= iSubFragmentEnd) ||                  // filter EG is finished, switch EG1 to fade out stage
394                  (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&                  if ((itKillEvent && killPos <= iSubFragmentEnd) ||
395                   EG2.getSegmentType() == gig::EGADSR::segment_end)) {                      (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
396                  EG1.enterFadeOutStage();                      pEG2->getSegmentType() == EG::segment_end)) {
397                  itKillEvent = Pool<Event>::Iterator();                      pEG1->enterFadeOutStage();
398              }                      itKillEvent = Pool<Event>::Iterator();
399                    }
400    
401              // process envelope generators                  // process envelope generators
402              switch (EG1.getSegmentType()) {                  switch (pEG1->getSegmentType()) {
403                  case gig::EGADSR::segment_lin:                      case EG::segment_lin:
404                      fFinalVolume *= EG1.processLin();                          fFinalVolume *= pEG1->processLin();
405                      break;                          break;
406                  case gig::EGADSR::segment_exp:                      case EG::segment_exp:
407                      fFinalVolume *= EG1.processExp();                          fFinalVolume *= pEG1->processExp();
408                      break;                          break;
409                  case gig::EGADSR::segment_end:                      case EG::segment_end:
410                      fFinalVolume *= EG1.getLevel();                          fFinalVolume *= pEG1->getLevel();
411                      break; // noop                          break; // noop
412              }                      case EG::segment_pow:
413              switch (EG2.getSegmentType()) {                          fFinalVolume *= pEG1->processPow();
414                  case gig::EGADSR::segment_lin:                          break;
415                      fFinalCutoff *= EG2.processLin();                  }
416                      break;                  switch (pEG2->getSegmentType()) {
417                  case gig::EGADSR::segment_exp:                      case EG::segment_lin:
418                      fFinalCutoff *= EG2.processExp();                          fFinalCutoff *= pEG2->processLin();
419                      break;                          break;
420                  case gig::EGADSR::segment_end:                      case EG::segment_exp:
421                      fFinalCutoff *= EG2.getLevel();                          fFinalCutoff *= pEG2->processExp();
422                      break; // noop                          break;
423              }                      case EG::segment_end:
424              if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();                          fFinalCutoff *= pEG2->getLevel();
425                            break; // noop
426              // process low frequency oscillators                      case EG::segment_pow:
427              if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());                          fFinalCutoff *= pEG2->processPow();
428              if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();                          break;
429              if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());                  }
430                    if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();
431    
432                    // process low frequency oscillators
433                    if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());
434                    if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();
435                    if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
436                } else {
437                    // if the voice was killed in this subfragment, or if the
438                    // filter EG is finished, switch EG1 to fade out stage
439                    /*if ((itKillEvent && killPos <= iSubFragmentEnd) ||
440                        (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
441                        pEG2->getSegmentType() == EG::segment_end)) {
442                        pEG1->enterFadeOutStage();
443                        itKillEvent = Pool<Event>::Iterator();
444                    }*/
445                    // TODO: ^^^
446    
447                    fFinalVolume   *= GetSignalUnitRack()->GetEndpointUnit()->GetVolume();
448                    fFinalCutoff    = GetSignalUnitRack()->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff);
449                    fFinalResonance = GetSignalUnitRack()->GetEndpointUnit()->CalculateResonance(fFinalResonance);
450                    
451                    finalSynthesisParameters.fFinalPitch =
452                        GetSignalUnitRack()->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);
453                        
454                }
455                
456              // limit the pitch so we don't read outside the buffer              // limit the pitch so we don't read outside the buffer
457              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));
458    
# Line 447  namespace LinuxSampler { Line 487  namespace LinuxSampler {
487              // render audio for one subfragment              // render audio for one subfragment
488              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
489    
490              // stop the rendering if volume EG is finished              if (GetSignalUnitRack() == NULL) {
491              if (EG1.getSegmentType() == gig::EGADSR::segment_end) break;                  // stop the rendering if volume EG is finished
492                    if (pEG1->getSegmentType() == EG::segment_end) break;
493                } else {
494                    // stop the rendering if the endpoint unit is not active
495                    if (!GetSignalUnitRack()->GetEndpointUnit()->Active()) break;
496                }
497    
498              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
499    
500              // increment envelopes' positions              if (GetSignalUnitRack() == NULL) {
501              if (EG1.active()) {                  // increment envelopes' positions
502                    if (pEG1->active()) {
503    
504                        // 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
505                        if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
506                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
507                        }
508    
509                  // 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);
510                  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);  
511                  }                  }
512                    if (pEG2->active()) {
513                  EG1.increment(1);                      pEG2->increment(1);
514                  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);
515              }                  }
516              if (EG2.active()) {                  EG3.increment(1);
517                  EG2.increment(1);                  if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
518                  if (!EG2.toStageEndLeft()) EG2.update(gig::EGADSR::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              } else {
519                        // 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
520                        /*if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
521                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
522                        }*/
523                    // TODO: ^^^
524                    
525                    GetSignalUnitRack()->Increment();
526              }              }
             EG3.increment(1);  
             if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached  
527    
528              Pos = newPos;              Pos = newPos;
529              i = iSubFragmentEnd;              i = iSubFragmentEnd;
530          }          }
531    
532            if (bVoiceRequiresDedicatedRouting) {
533                optional<float> effectSendLevels[2] = {
534                    pMidiKeyInfo->ReverbSend,
535                    pMidiKeyInfo->ChorusSend
536                };
537                GetEngine()->RouteDedicatedVoiceChannels(pEngineChannel, effectSendLevels, Samples);
538            }
539      }      }
540        
541      /**      /**
542       * Process given list of MIDI control change and pitch bend events for       * Process given list of MIDI control change and pitch bend events for
543       * the given time.       * the given time.
# Line 491  namespace LinuxSampler { Line 554  namespace LinuxSampler {
554                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
555                      processResonanceEvent(itEvent);                      processResonanceEvent(itEvent);
556                  }                  }
557                  if (itEvent->Param.CC.Controller == pLFO1->ExtController) {                  if (GetSignalUnitRack() == NULL) {
558                      pLFO1->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
559                  }                          pLFO1->update(itEvent->Param.CC.Value);
560                  if (itEvent->Param.CC.Controller == pLFO2->ExtController) {                      }
561                      pLFO2->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO2->ExtController) {
562                  }                          pLFO2->update(itEvent->Param.CC.Value);
563                  if (itEvent->Param.CC.Controller == pLFO3->ExtController) {                      }
564                      pLFO3->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO3->ExtController) {
565                            pLFO3->update(itEvent->Param.CC.Value);
566                        }
567                  }                  }
568                  if (itEvent->Param.CC.Controller == 7) { // volume                  if (itEvent->Param.CC.Controller == 7) { // volume
569                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);
# Line 511  namespace LinuxSampler { Line 576  namespace LinuxSampler {
576              }              }
577    
578              ProcessCCEvent(itEvent);              ProcessCCEvent(itEvent);
579                if (GetSignalUnitRack() != NULL) {
580                    GetSignalUnitRack()->ProcessCCEvent(itEvent);
581                }
582          }          }
583      }      }
584    
# Line 537  namespace LinuxSampler { Line 605  namespace LinuxSampler {
605       */       */
606      void AbstractVoice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {      void AbstractVoice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {
607          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
608              if (itEvent->Type == Event::type_release) {              // some voice types ignore note off
609                  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))) {
610                  EG2.update(gig::EGADSR::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (itEvent->Type == Event::type_release) {
611              } else if (itEvent->Type == Event::type_cancel_release) {                      EnterReleaseStage();
612                  EG1.update(gig::EGADSR::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  } else if (itEvent->Type == Event::type_cancel_release) {
613                  EG2.update(gig::EGADSR::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                      if (GetSignalUnitRack() == NULL) {
614                            pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
615                            pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
616                        } else {
617                            GetSignalUnitRack()->CancelRelease();
618                        }
619                    }
620              }              }
621          }          }
622      }      }
623    
624        /**
625         * Process given list of events aimed at all voices in a key group.
626         *
627         * @param itEvent - iterator pointing to the next event to be processed
628         * @param End     - youngest time stamp where processing should be stopped
629         */
630        void AbstractVoice::processGroupEvents(RTList<Event>::Iterator& itEvent, uint End) {
631            for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
632                ProcessGroupEvent(itEvent);
633            }
634        }
635    
636      /** @brief Update current portamento position.      /** @brief Update current portamento position.
637       *       *
638       * 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 642  namespace LinuxSampler {
642       * @param itNoteOffEvent - event which causes this voice to die soon       * @param itNoteOffEvent - event which causes this voice to die soon
643       */       */
644      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
645          const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());          if (GetSignalUnitRack() == NULL) {
646          pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;              const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
647                pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
648            } else {
649                // TODO:
650            }
651      }      }
652    
653      /**      /**
# Line 604  namespace LinuxSampler { Line 694  namespace LinuxSampler {
694          volume *= GetSampleAttenuation() * pEngineChannel->GlobalVolume * GLOBAL_VOLUME;          volume *= GetSampleAttenuation() * pEngineChannel->GlobalVolume * GLOBAL_VOLUME;
695    
696          // the volume of release triggered samples depends on note length          // the volume of release triggered samples depends on note length
697          if (Type == Voice::type_release_trigger) {          if (Type & Voice::type_release_trigger) {
698              float noteLength = float(GetEngine()->FrameTime + Delay -              float noteLength = float(GetEngine()->FrameTime + Delay -
699                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;
700    
701              float attenuation = 1 - 0.01053 * (256 >> RgnInfo.ReleaseTriggerDecay) * noteLength;              volume *= GetReleaseTriggerAttenuation(noteLength);
             volume *= attenuation;  
702          }          }
703    
704          return volume;          return volume;
705      }      }
706    
707        float AbstractVoice::GetReleaseTriggerAttenuation(float noteLength) {
708            return 1 - RgnInfo.ReleaseTriggerDecay * noteLength;
709        }
710    
711        void AbstractVoice::EnterReleaseStage() {
712            if (GetSignalUnitRack() == NULL) {
713                pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
714                pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
715            } else {
716                GetSignalUnitRack()->EnterReleaseStage();
717            }
718        }
719    
720        bool AbstractVoice::EG1Finished() {
721            if (GetSignalUnitRack() == NULL) {
722                return pEG1->getSegmentType() == EG::segment_end;
723            } else {
724                return !GetSignalUnitRack()->GetEndpointUnit()->Active();
725            }
726        }
727    
728  } // namespace LinuxSampler  } // namespace LinuxSampler

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

  ViewVC Help
Powered by ViewVC