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

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

  ViewVC Help
Powered by ViewVC