/[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 2055 by persson, Sat Jan 30 10:30:02 2010 UTC revision 2219 by iliev, Thu Jul 28 12:35:49 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;
         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 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            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          KeyGroup        = iKeyGroup;          MidiKeyBase* pKeyInfo = GetMidiKeyInfo(MIDIKey);
110    
111            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 306  namespace LinuxSampler { Line 313  namespace LinuxSampler {
313       */       */
314      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
315          AbstractEngineChannel* pChannel = pEngineChannel;          AbstractEngineChannel* pChannel = pEngineChannel;
316          finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];          MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey);
317          finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];  
318          finalSynthesisParameters.pSrc      = pSrc;          const bool bVoiceRequiresDedicatedRouting =
319                pEngineChannel->GetFxSendCount() > 0 &&
320                (pMidiKeyInfo->ReverbSend || pMidiKeyInfo->ChorusSend);
321    
322            if (bVoiceRequiresDedicatedRouting) {
323                finalSynthesisParameters.pOutLeft  = &GetEngine()->pDedicatedVoiceChannelLeft->Buffer()[Skip];
324                finalSynthesisParameters.pOutRight = &GetEngine()->pDedicatedVoiceChannelRight->Buffer()[Skip];
325            } else {
326                finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];
327                finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];
328            }
329            finalSynthesisParameters.pSrc = pSrc;
330    
331          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();
332          RTList<Event>::Iterator itNoteEvent;          RTList<Event>::Iterator itNoteEvent;
333          GetFirstEventOnKey(MIDIKey, itNoteEvent);          GetFirstEventOnKey(MIDIKey, itNoteEvent);
334    
335            RTList<Event>::Iterator itGroupEvent;
336            if (pGroupEvents) itGroupEvent = pGroupEvents->first();
337    
338          if (itTriggerEvent) { // skip events that happened before this voice was triggered          if (itTriggerEvent) { // skip events that happened before this voice was triggered
339              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;
340                while (itGroupEvent && itGroupEvent->FragmentPos() <= Skip) ++itGroupEvent;
341    
342              // we can't simply compare the timestamp here, because note events              // we can't simply compare the timestamp here, because note events
343              // 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
344              // actual sequence the note events arrived instead (see bug #112)              // actual sequence the note events arrived instead (see bug #112)
# Line 336  namespace LinuxSampler { Line 359  namespace LinuxSampler {
359                  // drivers that use Samples < MaxSamplesPerCycle).                  // drivers that use Samples < MaxSamplesPerCycle).
360                  // End the EG1 here, at pos 0, with a shorter max fade                  // End the EG1 here, at pos 0, with a shorter max fade
361                  // out time.                  // out time.
362                  pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (pSignalUnitRack == NULL) {
363                        pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
364                    } else {
365                        // TODO:
366                    }
367                  itKillEvent = Pool<Event>::Iterator();                  itKillEvent = Pool<Event>::Iterator();
368              } else {              } else {
369                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);
# Line 353  namespace LinuxSampler { Line 380  namespace LinuxSampler {
380    
381              // process MIDI control change and pitchbend events for this subfragment              // process MIDI control change and pitchbend events for this subfragment
382              processCCEvents(itCCEvent, iSubFragmentEnd);              processCCEvents(itCCEvent, iSubFragmentEnd);
383                uint8_t pan = MIDIPan;
384                if (pSignalUnitRack != NULL) pan = pSignalUnitRack->GetEndpointUnit()->CaluclatePan(pan);
385                
386                PanLeftSmoother.update(AbstractEngine::PanCurve[128 - pan]);
387                PanRightSmoother.update(AbstractEngine::PanCurve[pan]);
388    
389              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend;              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend;
390              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();
# Line 362  namespace LinuxSampler { Line 394  namespace LinuxSampler {
394    
395              // process transition events (note on, note off & sustain pedal)              // process transition events (note on, note off & sustain pedal)
396              processTransitionEvents(itNoteEvent, iSubFragmentEnd);              processTransitionEvents(itNoteEvent, iSubFragmentEnd);
397                processGroupEvents(itGroupEvent, iSubFragmentEnd);
398    
399              // if the voice was killed in this subfragment, or if the              if (pSignalUnitRack == NULL) {
400              // filter EG is finished, switch EG1 to fade out stage                  // if the voice was killed in this subfragment, or if the
401              if ((itKillEvent && killPos <= iSubFragmentEnd) ||                  // filter EG is finished, switch EG1 to fade out stage
402                  (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&                  if ((itKillEvent && killPos <= iSubFragmentEnd) ||
403                   EG2.getSegmentType() == gig::EGADSR::segment_end)) {                      (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
404                  pEG1->enterFadeOutStage();                      pEG2->getSegmentType() == EG::segment_end)) {
405                  itKillEvent = Pool<Event>::Iterator();                      pEG1->enterFadeOutStage();
406              }                      itKillEvent = Pool<Event>::Iterator();
407                    }
408    
409              // process envelope generators                  // process envelope generators
410              switch (pEG1->getSegmentType()) {                  switch (pEG1->getSegmentType()) {
411                  case EG::segment_lin:                      case EG::segment_lin:
412                      fFinalVolume *= pEG1->processLin();                          fFinalVolume *= pEG1->processLin();
413                      break;                          break;
414                  case EG::segment_exp:                      case EG::segment_exp:
415                      fFinalVolume *= pEG1->processExp();                          fFinalVolume *= pEG1->processExp();
416                      break;                          break;
417                  case EG::segment_end:                      case EG::segment_end:
418                      fFinalVolume *= pEG1->getLevel();                          fFinalVolume *= pEG1->getLevel();
419                      break; // noop                          break; // noop
420                  case EG::segment_pow:                      case EG::segment_pow:
421                      fFinalVolume *= pEG1->processPow();                          fFinalVolume *= pEG1->processPow();
422                      break;                          break;
423              }                  }
424              switch (EG2.getSegmentType()) {                  switch (pEG2->getSegmentType()) {
425                  case gig::EGADSR::segment_lin:                      case EG::segment_lin:
426                      fFinalCutoff *= EG2.processLin();                          fFinalCutoff *= pEG2->processLin();
427                      break;                          break;
428                  case gig::EGADSR::segment_exp:                      case EG::segment_exp:
429                      fFinalCutoff *= EG2.processExp();                          fFinalCutoff *= pEG2->processExp();
430                      break;                          break;
431                  case gig::EGADSR::segment_end:                      case EG::segment_end:
432                      fFinalCutoff *= EG2.getLevel();                          fFinalCutoff *= pEG2->getLevel();
433                      break; // noop                          break; // noop
434              }                      case EG::segment_pow:
435              if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();                          fFinalCutoff *= pEG2->processPow();
436                            break;
437              // process low frequency oscillators                  }
438              if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());                  if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();
             if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();  
             if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());  
439    
440                    // process low frequency oscillators
441                    if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());
442                    if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();
443                    if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
444                } else {
445                    // if the voice was killed in this subfragment, or if the
446                    // filter EG is finished, switch EG1 to fade out stage
447                    /*if ((itKillEvent && killPos <= iSubFragmentEnd) ||
448                        (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
449                        pEG2->getSegmentType() == EG::segment_end)) {
450                        pEG1->enterFadeOutStage();
451                        itKillEvent = Pool<Event>::Iterator();
452                    }*/
453                    // TODO: ^^^
454    
455                    fFinalVolume   *= pSignalUnitRack->GetEndpointUnit()->GetVolume();
456                    fFinalCutoff    = pSignalUnitRack->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff);
457                    fFinalResonance = pSignalUnitRack->GetEndpointUnit()->CalculateResonance(fFinalResonance);
458                    
459                    finalSynthesisParameters.fFinalPitch =
460                        pSignalUnitRack->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);
461                        
462                }
463                
464              // limit the pitch so we don't read outside the buffer              // limit the pitch so we don't read outside the buffer
465              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));
466    
# Line 439  namespace LinuxSampler { Line 495  namespace LinuxSampler {
495              // render audio for one subfragment              // render audio for one subfragment
496              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
497    
498              // stop the rendering if volume EG is finished              if (pSignalUnitRack == NULL) {
499              if (pEG1->getSegmentType() == EG::segment_end) break;                  // stop the rendering if volume EG is finished
500                    if (pEG1->getSegmentType() == EG::segment_end) break;
501                } else {
502                    // stop the rendering if the endpoint unit is not active
503                    if (!pSignalUnitRack->GetEndpointUnit()->Active()) break;
504                }
505    
506              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
507    
508              // increment envelopes' positions              if (pSignalUnitRack == NULL) {
509              if (pEG1->active()) {                  // increment envelopes' positions
510                    if (pEG1->active()) {
511    
512                        // 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
513                        if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
514                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
515                        }
516    
517                  // 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);
518                  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);  
519                  }                  }
520                    if (pEG2->active()) {
521                  pEG1->increment(1);                      pEG2->increment(1);
522                  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);
523              }                  }
524              if (EG2.active()) {                  EG3.increment(1);
525                  EG2.increment(1);                  if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
526                  if (!EG2.toStageEndLeft()) EG2.update(gig::EGADSR::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              } else {
527                        // 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
528                        /*if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
529                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
530                        }*/
531                    // TODO: ^^^
532                    
533                    pSignalUnitRack->Increment();
534              }              }
             EG3.increment(1);  
             if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached  
535    
536              Pos = newPos;              Pos = newPos;
537              i = iSubFragmentEnd;              i = iSubFragmentEnd;
538          }          }
539    
540            if (bVoiceRequiresDedicatedRouting) {
541                optional<float> effectSendLevels[2] = {
542                    pMidiKeyInfo->ReverbSend,
543                    pMidiKeyInfo->ChorusSend
544                };
545                GetEngine()->RouteDedicatedVoiceChannels(pEngineChannel, effectSendLevels, Samples);
546            }
547      }      }
548    
549      /**      /**
# Line 483  namespace LinuxSampler { Line 562  namespace LinuxSampler {
562                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
563                      processResonanceEvent(itEvent);                      processResonanceEvent(itEvent);
564                  }                  }
565                  if (itEvent->Param.CC.Controller == pLFO1->ExtController) {                  if (pSignalUnitRack == NULL) {
566                      pLFO1->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
567                  }                          pLFO1->update(itEvent->Param.CC.Value);
568                  if (itEvent->Param.CC.Controller == pLFO2->ExtController) {                      }
569                      pLFO2->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO2->ExtController) {
570                  }                          pLFO2->update(itEvent->Param.CC.Value);
571                  if (itEvent->Param.CC.Controller == pLFO3->ExtController) {                      }
572                      pLFO3->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO3->ExtController) {
573                            pLFO3->update(itEvent->Param.CC.Value);
574                        }
575                  }                  }
576                  if (itEvent->Param.CC.Controller == 7) { // volume                  if (itEvent->Param.CC.Controller == 7) { // volume
577                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);
578                  } else if (itEvent->Param.CC.Controller == 10) { // panpot                  } else if (itEvent->Param.CC.Controller == 10) { // panpot
579                      PanLeftSmoother.update(AbstractEngine::PanCurve[128 - itEvent->Param.CC.Value]);                      MIDIPan = itEvent->Param.CC.Value;
                     PanRightSmoother.update(AbstractEngine::PanCurve[itEvent->Param.CC.Value]);  
580                  }                  }
581              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event
582                  processPitchEvent(itEvent);                  processPitchEvent(itEvent);
583              }              }
584    
585              ProcessCCEvent(itEvent);              ProcessCCEvent(itEvent);
586                if (pSignalUnitRack != NULL) {
587                    pSignalUnitRack->ProcessCCEvent(itEvent);
588                }
589          }          }
590      }      }
591    
# Line 529  namespace LinuxSampler { Line 612  namespace LinuxSampler {
612       */       */
613      void AbstractVoice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {      void AbstractVoice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {
614          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
615              if (itEvent->Type == Event::type_release) {              // some voice types ignore note off
616                  pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              if (!(Type & (Voice::type_one_shot | Voice::type_release_trigger | Voice::type_controller_triggered))) {
617                  EG2.update(gig::EGADSR::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (itEvent->Type == Event::type_release) {
618              } else if (itEvent->Type == Event::type_cancel_release) {                      EnterReleaseStage();
619                  pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  } else if (itEvent->Type == Event::type_cancel_release) {
620                  EG2.update(gig::EGADSR::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                      if (pSignalUnitRack == NULL) {
621                            pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
622                            pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
623                        } else {
624                            pSignalUnitRack->CancelRelease();
625                        }
626                    }
627              }              }
628          }          }
629      }      }
630    
631        /**
632         * Process given list of events aimed at all voices in a key group.
633         *
634         * @param itEvent - iterator pointing to the next event to be processed
635         * @param End     - youngest time stamp where processing should be stopped
636         */
637        void AbstractVoice::processGroupEvents(RTList<Event>::Iterator& itEvent, uint End) {
638            for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
639                ProcessGroupEvent(itEvent);
640            }
641        }
642    
643      /** @brief Update current portamento position.      /** @brief Update current portamento position.
644       *       *
645       * 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 548  namespace LinuxSampler { Line 649  namespace LinuxSampler {
649       * @param itNoteOffEvent - event which causes this voice to die soon       * @param itNoteOffEvent - event which causes this voice to die soon
650       */       */
651      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
652          const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());          if (pSignalUnitRack == NULL) {
653          pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;              const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
654                pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
655            } else {
656                // TODO:
657            }
658      }      }
659    
660      /**      /**
# Line 596  namespace LinuxSampler { Line 701  namespace LinuxSampler {
701          volume *= GetSampleAttenuation() * pEngineChannel->GlobalVolume * GLOBAL_VOLUME;          volume *= GetSampleAttenuation() * pEngineChannel->GlobalVolume * GLOBAL_VOLUME;
702    
703          // the volume of release triggered samples depends on note length          // the volume of release triggered samples depends on note length
704          if (Type == Voice::type_release_trigger) {          if (Type & Voice::type_release_trigger) {
705              float noteLength = float(GetEngine()->FrameTime + Delay -              float noteLength = float(GetEngine()->FrameTime + Delay -
706                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;
707    
708              float attenuation = 1 - 0.01053 * (256 >> RgnInfo.ReleaseTriggerDecay) * noteLength;              volume *= GetReleaseTriggerAttenuation(noteLength);
             volume *= attenuation;  
709          }          }
710    
711          return volume;          return volume;
712      }      }
713    
714        float AbstractVoice::GetReleaseTriggerAttenuation(float noteLength) {
715            return 1 - RgnInfo.ReleaseTriggerDecay * noteLength;
716        }
717    
718        void AbstractVoice::EnterReleaseStage() {
719            if (pSignalUnitRack == NULL) {
720                pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
721                pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
722            } else {
723                pSignalUnitRack->EnterReleaseStage();
724            }
725        }
726    
727        bool AbstractVoice::EG1Finished() {
728            if (pSignalUnitRack == NULL) {
729                return pEG1->getSegmentType() == EG::segment_end;
730            } else {
731                return !pSignalUnitRack->GetEndpointUnit()->Active();
732            }
733        }
734    
735  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.2055  
changed lines
  Added in v.2219

  ViewVC Help
Powered by ViewVC