/[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 2298 by iliev, Fri Dec 9 17:04:24 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 44  namespace LinuxSampler { Line 43  namespace LinuxSampler {
43    
44          finalSynthesisParameters.filterLeft.Reset();          finalSynthesisParameters.filterLeft.Reset();
45          finalSynthesisParameters.filterRight.Reset();          finalSynthesisParameters.filterRight.Reset();
46            
47            pEq          = NULL;
48            bEqSupport   = false;
49      }      }
50    
51      AbstractVoice::~AbstractVoice() {      AbstractVoice::~AbstractVoice() {
52          if (pLFO1) delete pLFO1;          if (pLFO1) delete pLFO1;
53          if (pLFO2) delete pLFO2;          if (pLFO2) delete pLFO2;
54          if (pLFO3) delete pLFO3;          if (pLFO3) delete pLFO3;
55            
56            if(pEq != NULL) delete pEq;
57      }      }
58                    
59        void AbstractVoice::CreateEq() {
60            if(!bEqSupport) return;
61            if(pEq != NULL) delete pEq;
62            pEq = new EqSupport;
63            pEq->InitEffect(GetEngine()->pAudioOutputDevice);
64        }
65    
66      /**      /**
67       *  Resets voice variables. Should only be called if rendering process is       *  Resets voice variables. Should only be called if rendering process is
68       *  suspended / not running.       *  suspended / not running.
# Line 100  namespace LinuxSampler { Line 111  namespace LinuxSampler {
111    
112          Type            = VoiceType;          Type            = VoiceType;
113          MIDIKey         = itNoteOnEvent->Param.Note.Key;          MIDIKey         = itNoteOnEvent->Param.Note.Key;
114            MIDIVelocity    = itNoteOnEvent->Param.Note.Velocity;
115            MIDIPan         = pEngineChannel->ControllerTable[10];
116            if (MIDIPan == 0 && pEngineChannel->GlobalPanRight == 1) MIDIPan = 64; // workaround used to determine whether the MIDI pan has not been set
117          PlaybackState   = playback_state_init; // mark voice as triggered, but no audio rendered yet          PlaybackState   = playback_state_init; // mark voice as triggered, but no audio rendered yet
118          Delay           = itNoteOnEvent->FragmentPos();          Delay           = itNoteOnEvent->FragmentPos();
119          itTriggerEvent  = itNoteOnEvent;          itTriggerEvent  = itNoteOnEvent;
120          itKillEvent     = Pool<Event>::Iterator();          itKillEvent     = Pool<Event>::Iterator();
121          KeyGroup        = iKeyGroup;          MidiKeyBase* pKeyInfo = GetMidiKeyInfo(MIDIKey);
122    
123            pGroupEvents = iKeyGroup ? pEngineChannel->ActiveKeyGroups[iKeyGroup] : 0;
124    
125          SmplInfo   = GetSampleInfo();          SmplInfo   = GetSampleInfo();
126          RgnInfo    = GetRegionInfo();          RgnInfo    = GetRegionInfo();
127          InstrInfo  = GetInstrumentInfo();          InstrInfo  = GetInstrumentInfo();
128            
129            AboutToTrigger();
130    
131          // calculate volume          // calculate volume
132          const double velocityAttenuation = GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity);          const double velocityAttenuation = GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity);
133          float volume = CalculateVolume(velocityAttenuation);          float volume = CalculateVolume(velocityAttenuation) * pKeyInfo->Volume;
134          if (volume <= 0) return -1;          if (volume <= 0) return -1;
135    
136          // select channel mode (mono or stereo)          // select channel mode (mono or stereo)
# Line 123  namespace LinuxSampler { Line 141  namespace LinuxSampler {
141          // get starting crossfade volume level          // get starting crossfade volume level
142          float crossfadeVolume = CalculateCrossfadeVolume(itNoteOnEvent->Param.Note.Velocity);          float crossfadeVolume = CalculateCrossfadeVolume(itNoteOnEvent->Param.Note.Velocity);
143    
144          VolumeLeft  = volume * AbstractEngine::PanCurve[64 - RgnInfo.Pan];          VolumeLeft  = volume * pKeyInfo->PanLeft  * AbstractEngine::PanCurve[64 - RgnInfo.Pan];
145          VolumeRight = volume * AbstractEngine::PanCurve[64 + RgnInfo.Pan];          VolumeRight = volume * pKeyInfo->PanRight * AbstractEngine::PanCurve[64 + RgnInfo.Pan];
146    
147          float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;          float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;
148          CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);          CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);
# Line 132  namespace LinuxSampler { Line 150  namespace LinuxSampler {
150          PanLeftSmoother.trigger(pEngineChannel->GlobalPanLeft, subfragmentRate);          PanLeftSmoother.trigger(pEngineChannel->GlobalPanLeft, subfragmentRate);
151          PanRightSmoother.trigger(pEngineChannel->GlobalPanRight, subfragmentRate);          PanRightSmoother.trigger(pEngineChannel->GlobalPanRight, subfragmentRate);
152    
         finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)  
         Pos = RgnInfo.SampleStartOffset;  
   
153          // Check if the sample needs disk streaming or is too short for that          // Check if the sample needs disk streaming or is too short for that
154          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;
155          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;
156    
157            SetSampleStartOffset();
158    
159          if (DiskVoice) { // voice to be streamed from disk          if (DiskVoice) { // voice to be streamed from disk
160              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {
161                  MaxRAMPos = cachedsamples - (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH) / SmplInfo.ChannelCount; //TODO: this calculation is too pessimistic and may better be moved to Render() method, so it calculates MaxRAMPos dependent to the current demand of sample points to be rendered (e.g. in case of JACK)                  MaxRAMPos = cachedsamples - (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH) / SmplInfo.ChannelCount; //TODO: this calculation is too pessimistic and may better be moved to Render() method, so it calculates MaxRAMPos dependent to the current demand of sample points to be rendered (e.g. in case of JACK)
# Line 175  namespace LinuxSampler { Line 192  namespace LinuxSampler {
192          // the length of the decay and release curves are dependent on the velocity          // the length of the decay and release curves are dependent on the velocity
193          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);
194    
195          // setup EG 1 (VCA EG)          if (pSignalUnitRack == NULL) { // setup EG 1 (VCA EG)
         {  
196              // get current value of EG1 controller              // get current value of EG1 controller
197              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);
198    
199              // calculate influence of EG1 controller on EG1's parameters              // calculate influence of EG1 controller on EG1's parameters
200              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);
201    
202              EG1.trigger (              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
203                  RgnInfo.EG1PreAttack,          } else {
204                  RgnInfo.EG1Attack * egInfo.Attack,              pSignalUnitRack->Trigger();
                 RgnInfo.EG1Hold,  
                 RgnInfo.EG1Decay1 * egInfo.Decay * velrelease,  
                 RgnInfo.EG1Decay2 * egInfo.Decay * velrelease,  
                 RgnInfo.EG1InfiniteSustain,  
                 RgnInfo.EG1Sustain,  
                 RgnInfo.EG1Release * egInfo.Release * velrelease,  
                 velocityAttenuation,  
                 GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE  
             );  
205          }          }
206    
207  #ifdef CONFIG_INTERPOLATE_VOLUME  #ifdef CONFIG_INTERPOLATE_VOLUME
# Line 207  namespace LinuxSampler { Line 214  namespace LinuxSampler {
214          else          else
215      #else      #else
216          {          {
217              float finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * EG1.getLevel();              float finalVolume;
218                if (pSignalUnitRack == NULL) {
219                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();
220                } else {
221                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pSignalUnitRack->GetEndpointUnit()->GetVolume();
222                }
223    
224              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * pEngineChannel->GlobalPanLeft;              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * pEngineChannel->GlobalPanLeft;
225              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight;              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight;
# Line 215  namespace LinuxSampler { Line 227  namespace LinuxSampler {
227      #endif      #endif
228  #endif  #endif
229    
230          // setup EG 2 (VCF Cutoff EG)          if (pSignalUnitRack == NULL) {
231          {              // setup EG 2 (VCF Cutoff EG)
232              // get current value of EG2 controller              {
233              double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);                  // get current value of EG2 controller
234                    double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);
235    
236                    // calculate influence of EG2 controller on EG2's parameters
237                    EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);
238    
239                    TriggerEG2(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
240                }
241    
             // calculate influence of EG2 controller on EG2's parameters  
             EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);  
242    
243              EG2.trigger (              // setup EG 3 (VCO EG)
244                  RgnInfo.EG2PreAttack,              {
245                  RgnInfo.EG2Attack * egInfo.Attack,                  // if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch
246                  false,                  bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;
247                  RgnInfo.EG2Decay1 * egInfo.Decay * velrelease,                  float eg3depth = (bPortamento)
248                  RgnInfo.EG2Decay2 * egInfo.Decay * velrelease,                               ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100)
249                  RgnInfo.EG2InfiniteSustain,                               : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);
250                  RgnInfo.EG2Sustain,                  float eg3time = (bPortamento)
251                  RgnInfo.EG2Release * egInfo.Release * velrelease,                              ? pEngineChannel->PortamentoTime
252                  velocityAttenuation,                              : RgnInfo.EG3Attack;
253                  GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE                  EG3.trigger(eg3depth, eg3time, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
254              );                  dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time));
255          }              }
256    
257    
258          // setup EG 3 (VCO EG)              // setup LFO 1 (VCA LFO)
259          {              InitLFO1();
260              // if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch              // setup LFO 2 (VCF Cutoff LFO)
261              bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;              InitLFO2();
262              float eg3depth = (bPortamento)              // setup LFO 3 (VCO LFO)
263                           ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100)              InitLFO3();
                          : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);  
             float eg3time = (bPortamento)  
                         ? pEngineChannel->PortamentoTime  
                         : RgnInfo.EG3Attack;  
             EG3.trigger(eg3depth, eg3time, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);  
             dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time));  
264          }          }
265    
266    
         // setup LFO 1 (VCA LFO)  
         InitLFO1();  
         // setup LFO 2 (VCF Cutoff LFO)  
         InitLFO2();  
         // setup LFO 3 (VCO LFO)  
         InitLFO3();  
   
   
267          #if CONFIG_FORCE_FILTER          #if CONFIG_FORCE_FILTER
268          const bool bUseFilter = true;          const bool bUseFilter = true;
269          #else // use filter only if instrument file told so          #else // use filter only if instrument file told so
# Line 306  namespace LinuxSampler { Line 309  namespace LinuxSampler {
309    
310          return 0; // success          return 0; // success
311      }      }
312        
313        void AbstractVoice::SetSampleStartOffset() {
314            finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
315            Pos = RgnInfo.SampleStartOffset;
316        }
317    
318      /**      /**
319       *  Synthesizes the current audio fragment for this voice.       *  Synthesizes the current audio fragment for this voice.
# Line 316  namespace LinuxSampler { Line 324  namespace LinuxSampler {
324       *  @param Skip    - number of sample points to skip in output buffer       *  @param Skip    - number of sample points to skip in output buffer
325       */       */
326      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {      void AbstractVoice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
327            bool delay = false; // Whether the voice playback should be delayed for this call
328            
329            if (pSignalUnitRack != NULL) {
330                uint delaySteps = pSignalUnitRack->GetEndpointUnit()->DelayTrigger();
331                if (delaySteps > 0) { // delay on the endpoint unit means delay of the voice playback
332                    if (delaySteps >= Samples) {
333                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(Samples);
334                        delay = true;
335                    } else {
336                        pSignalUnitRack->GetEndpointUnit()->DecreaseDelay(delaySteps);
337                        Samples -= delaySteps;
338                        Skip += delaySteps;
339                    }
340                }
341            }
342            
343          AbstractEngineChannel* pChannel = pEngineChannel;          AbstractEngineChannel* pChannel = pEngineChannel;
344          finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];          MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey);
345          finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];  
346          finalSynthesisParameters.pSrc      = pSrc;          const bool bVoiceRequiresDedicatedRouting =
347                pEngineChannel->GetFxSendCount() > 0 &&
348                (pMidiKeyInfo->ReverbSend || pMidiKeyInfo->ChorusSend);
349            
350            const bool bEq =
351                pSignalUnitRack != NULL && pSignalUnitRack->HasEq() && pEq->HasSupport();
352    
353            if (bEq) {
354                pEq->GetInChannelLeft()->Clear();
355                pEq->GetInChannelRight()->Clear();
356                finalSynthesisParameters.pOutLeft  = &pEq->GetInChannelLeft()->Buffer()[Skip];
357                finalSynthesisParameters.pOutRight = &pEq->GetInChannelRight()->Buffer()[Skip];
358                pSignalUnitRack->UpdateEqSettings(pEq);
359            } else if (bVoiceRequiresDedicatedRouting) {
360                finalSynthesisParameters.pOutLeft  = &GetEngine()->pDedicatedVoiceChannelLeft->Buffer()[Skip];
361                finalSynthesisParameters.pOutRight = &GetEngine()->pDedicatedVoiceChannelRight->Buffer()[Skip];
362            } else {
363                finalSynthesisParameters.pOutLeft  = &pChannel->pChannelLeft->Buffer()[Skip];
364                finalSynthesisParameters.pOutRight = &pChannel->pChannelRight->Buffer()[Skip];
365            }
366            finalSynthesisParameters.pSrc = pSrc;
367    
368          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();
369          RTList<Event>::Iterator itNoteEvent;          RTList<Event>::Iterator itNoteEvent;
370          GetFirstEventOnKey(MIDIKey, itNoteEvent);          GetFirstEventOnKey(MIDIKey, itNoteEvent);
371    
372            RTList<Event>::Iterator itGroupEvent;
373            if (pGroupEvents) itGroupEvent = pGroupEvents->first();
374    
375          if (itTriggerEvent) { // skip events that happened before this voice was triggered          if (itTriggerEvent) { // skip events that happened before this voice was triggered
376              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;
377                while (itGroupEvent && itGroupEvent->FragmentPos() <= Skip) ++itGroupEvent;
378    
379              // we can't simply compare the timestamp here, because note events              // we can't simply compare the timestamp here, because note events
380              // 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
381              // 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 396  namespace LinuxSampler {
396                  // drivers that use Samples < MaxSamplesPerCycle).                  // drivers that use Samples < MaxSamplesPerCycle).
397                  // End the EG1 here, at pos 0, with a shorter max fade                  // End the EG1 here, at pos 0, with a shorter max fade
398                  // out time.                  // out time.
399                  EG1.enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (pSignalUnitRack == NULL) {
400                        pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
401                    } else {
402                        // TODO:
403                    }
404                  itKillEvent = Pool<Event>::Iterator();                  itKillEvent = Pool<Event>::Iterator();
405              } else {              } else {
406                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);
# Line 364  namespace LinuxSampler { Line 417  namespace LinuxSampler {
417    
418              // process MIDI control change and pitchbend events for this subfragment              // process MIDI control change and pitchbend events for this subfragment
419              processCCEvents(itCCEvent, iSubFragmentEnd);              processCCEvents(itCCEvent, iSubFragmentEnd);
420                uint8_t pan = MIDIPan;
421                if (pSignalUnitRack != NULL) pan = pSignalUnitRack->GetEndpointUnit()->CaluclatePan(pan);
422                
423                PanLeftSmoother.update(AbstractEngine::PanCurve[128 - pan]);
424                PanRightSmoother.update(AbstractEngine::PanCurve[pan]);
425    
426              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend;              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend;
427              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();
# Line 373  namespace LinuxSampler { Line 431  namespace LinuxSampler {
431    
432              // process transition events (note on, note off & sustain pedal)              // process transition events (note on, note off & sustain pedal)
433              processTransitionEvents(itNoteEvent, iSubFragmentEnd);              processTransitionEvents(itNoteEvent, iSubFragmentEnd);
434                processGroupEvents(itGroupEvent, iSubFragmentEnd);
435                
436                if (pSignalUnitRack == NULL) {
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    
446              // if the voice was killed in this subfragment, or if the                  // process envelope generators
447              // filter EG is finished, switch EG1 to fade out stage                  switch (pEG1->getSegmentType()) {
448              if ((itKillEvent && killPos <= iSubFragmentEnd) ||                      case EG::segment_lin:
449                  (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&                          fFinalVolume *= pEG1->processLin();
450                   EG2.getSegmentType() == gig::EGADSR::segment_end)) {                          break;
451                  EG1.enterFadeOutStage();                      case EG::segment_exp:
452                  itKillEvent = Pool<Event>::Iterator();                          fFinalVolume *= pEG1->processExp();
453              }                          break;
454                        case EG::segment_end:
455              // process envelope generators                          fFinalVolume *= pEG1->getLevel();
456              switch (EG1.getSegmentType()) {                          break; // noop
457                  case gig::EGADSR::segment_lin:                      case EG::segment_pow:
458                      fFinalVolume *= EG1.processLin();                          fFinalVolume *= pEG1->processPow();
459                      break;                          break;
460                  case gig::EGADSR::segment_exp:                  }
461                      fFinalVolume *= EG1.processExp();                  switch (pEG2->getSegmentType()) {
462                      break;                      case EG::segment_lin:
463                  case gig::EGADSR::segment_end:                          fFinalCutoff *= pEG2->processLin();
464                      fFinalVolume *= EG1.getLevel();                          break;
465                      break; // noop                      case EG::segment_exp:
466              }                          fFinalCutoff *= pEG2->processExp();
467              switch (EG2.getSegmentType()) {                          break;
468                  case gig::EGADSR::segment_lin:                      case EG::segment_end:
469                      fFinalCutoff *= EG2.processLin();                          fFinalCutoff *= pEG2->getLevel();
470                      break;                          break; // noop
471                  case gig::EGADSR::segment_exp:                      case EG::segment_pow:
472                      fFinalCutoff *= EG2.processExp();                          fFinalCutoff *= pEG2->processPow();
473                      break;                          break;
474                  case gig::EGADSR::segment_end:                  }
475                      fFinalCutoff *= EG2.getLevel();                  if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();
                     break; // noop  
             }  
             if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();  
   
             // process low frequency oscillators  
             if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());  
             if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();  
             if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());  
476    
477                    // process low frequency oscillators
478                    if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());
479                    if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();
480                    if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
481                } else {
482                    // if the voice was killed in this subfragment, or if the
483                    // filter EG is finished, switch EG1 to fade out stage
484                    /*if ((itKillEvent && killPos <= iSubFragmentEnd) ||
485                        (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
486                        pEG2->getSegmentType() == EG::segment_end)) {
487                        pEG1->enterFadeOutStage();
488                        itKillEvent = Pool<Event>::Iterator();
489                    }*/
490                    // TODO: ^^^
491    
492                    fFinalVolume   *= pSignalUnitRack->GetEndpointUnit()->GetVolume();
493                    fFinalCutoff    = pSignalUnitRack->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff);
494                    fFinalResonance = pSignalUnitRack->GetEndpointUnit()->CalculateResonance(fFinalResonance);
495                    
496                    finalSynthesisParameters.fFinalPitch =
497                        pSignalUnitRack->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);
498                        
499                }
500                
501              // limit the pitch so we don't read outside the buffer              // limit the pitch so we don't read outside the buffer
502              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));
503    
# Line 445  namespace LinuxSampler { Line 530  namespace LinuxSampler {
530                  fFinalVolume * VolumeRight * PanRightSmoother.render();                  fFinalVolume * VolumeRight * PanRightSmoother.render();
531  #endif  #endif
532              // render audio for one subfragment              // render audio for one subfragment
533              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);              if (!delay) RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
534    
535              // stop the rendering if volume EG is finished              if (pSignalUnitRack == NULL) {
536              if (EG1.getSegmentType() == gig::EGADSR::segment_end) break;                  // stop the rendering if volume EG is finished
537                    if (pEG1->getSegmentType() == EG::segment_end) break;
538                } else {
539                    // stop the rendering if the endpoint unit is not active
540                    if (!pSignalUnitRack->GetEndpointUnit()->Active()) break;
541                }
542    
543              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
544    
545              // increment envelopes' positions              if (pSignalUnitRack == NULL) {
546              if (EG1.active()) {                  // increment envelopes' positions
547                    if (pEG1->active()) {
548    
549                        // 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
550                        if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
551                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
552                        }
553    
554                  // 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);
555                  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);  
556                  }                  }
557                    if (pEG2->active()) {
558                  EG1.increment(1);                      pEG2->increment(1);
559                  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);
560              }                  }
561              if (EG2.active()) {                  EG3.increment(1);
562                  EG2.increment(1);                  if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
563                  if (!EG2.toStageEndLeft()) EG2.update(gig::EGADSR::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              } else {
564                        // 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
565                        /*if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
566                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
567                        }*/
568                    // TODO: ^^^
569                    
570                    if (!delay) pSignalUnitRack->Increment();
571              }              }
             EG3.increment(1);  
             if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached  
572    
573              Pos = newPos;              Pos = newPos;
574              i = iSubFragmentEnd;              i = iSubFragmentEnd;
575          }          }
576            
577            if (delay) return;
578    
579            if (bVoiceRequiresDedicatedRouting) {
580                if (bEq) {
581                    pEq->RenderAudio(Samples);
582                    pEq->GetOutChannelLeft()->CopyTo(GetEngine()->pDedicatedVoiceChannelLeft, Samples);
583                    pEq->GetOutChannelRight()->CopyTo(GetEngine()->pDedicatedVoiceChannelRight, Samples);
584                }
585                optional<float> effectSendLevels[2] = {
586                    pMidiKeyInfo->ReverbSend,
587                    pMidiKeyInfo->ChorusSend
588                };
589                GetEngine()->RouteDedicatedVoiceChannels(pEngineChannel, effectSendLevels, Samples);
590            } else if (bEq) {
591                pEq->RenderAudio(Samples);
592                pEq->GetOutChannelLeft()->MixTo(pChannel->pChannelLeft, Samples);
593                pEq->GetOutChannelRight()->MixTo(pChannel->pChannelRight, Samples);
594            }
595      }      }
596        
597      /**      /**
598       * Process given list of MIDI control change and pitch bend events for       * Process given list of MIDI control change and pitch bend events for
599       * the given time.       * the given time.
# Line 491  namespace LinuxSampler { Line 610  namespace LinuxSampler {
610                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
611                      processResonanceEvent(itEvent);                      processResonanceEvent(itEvent);
612                  }                  }
613                  if (itEvent->Param.CC.Controller == pLFO1->ExtController) {                  if (pSignalUnitRack == NULL) {
614                      pLFO1->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
615                  }                          pLFO1->update(itEvent->Param.CC.Value);
616                  if (itEvent->Param.CC.Controller == pLFO2->ExtController) {                      }
617                      pLFO2->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO2->ExtController) {
618                  }                          pLFO2->update(itEvent->Param.CC.Value);
619                  if (itEvent->Param.CC.Controller == pLFO3->ExtController) {                      }
620                      pLFO3->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO3->ExtController) {
621                            pLFO3->update(itEvent->Param.CC.Value);
622                        }
623                  }                  }
624                  if (itEvent->Param.CC.Controller == 7) { // volume                  if (itEvent->Param.CC.Controller == 7) { // volume
625                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);
626                  } else if (itEvent->Param.CC.Controller == 10) { // panpot                  } else if (itEvent->Param.CC.Controller == 10) { // panpot
627                      PanLeftSmoother.update(AbstractEngine::PanCurve[128 - itEvent->Param.CC.Value]);                      MIDIPan = itEvent->Param.CC.Value;
                     PanRightSmoother.update(AbstractEngine::PanCurve[itEvent->Param.CC.Value]);  
628                  }                  }
629              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event
630                  processPitchEvent(itEvent);                  processPitchEvent(itEvent);
631              }              }
632    
633              ProcessCCEvent(itEvent);              ProcessCCEvent(itEvent);
634                if (pSignalUnitRack != NULL) {
635                    pSignalUnitRack->ProcessCCEvent(itEvent);
636                }
637          }          }
638      }      }
639    
# Line 537  namespace LinuxSampler { Line 660  namespace LinuxSampler {
660       */       */
661      void AbstractVoice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {      void AbstractVoice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {
662          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
663              if (itEvent->Type == Event::type_release) {              // some voice types ignore note off
664                  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))) {
665                  EG2.update(gig::EGADSR::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (itEvent->Type == Event::type_release) {
666              } else if (itEvent->Type == Event::type_cancel_release) {                      EnterReleaseStage();
667                  EG1.update(gig::EGADSR::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  } else if (itEvent->Type == Event::type_cancel_release) {
668                  EG2.update(gig::EGADSR::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                      if (pSignalUnitRack == NULL) {
669                            pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
670                            pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
671                        } else {
672                            pSignalUnitRack->CancelRelease();
673                        }
674                    }
675              }              }
676          }          }
677      }      }
678    
679        /**
680         * Process given list of events aimed at all voices in a key group.
681         *
682         * @param itEvent - iterator pointing to the next event to be processed
683         * @param End     - youngest time stamp where processing should be stopped
684         */
685        void AbstractVoice::processGroupEvents(RTList<Event>::Iterator& itEvent, uint End) {
686            for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
687                ProcessGroupEvent(itEvent);
688            }
689        }
690    
691      /** @brief Update current portamento position.      /** @brief Update current portamento position.
692       *       *
693       * 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 697  namespace LinuxSampler {
697       * @param itNoteOffEvent - event which causes this voice to die soon       * @param itNoteOffEvent - event which causes this voice to die soon
698       */       */
699      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
700          const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());          if (pSignalUnitRack == NULL) {
701          pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;              const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
702                pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
703            } else {
704                // TODO:
705            }
706      }      }
707    
708      /**      /**
# Line 604  namespace LinuxSampler { Line 749  namespace LinuxSampler {
749          volume *= GetSampleAttenuation() * pEngineChannel->GlobalVolume * GLOBAL_VOLUME;          volume *= GetSampleAttenuation() * pEngineChannel->GlobalVolume * GLOBAL_VOLUME;
750    
751          // the volume of release triggered samples depends on note length          // the volume of release triggered samples depends on note length
752          if (Type == Voice::type_release_trigger) {          if (Type & Voice::type_release_trigger) {
753              float noteLength = float(GetEngine()->FrameTime + Delay -              float noteLength = float(GetEngine()->FrameTime + Delay -
754                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;
755    
756              float attenuation = 1 - 0.01053 * (256 >> RgnInfo.ReleaseTriggerDecay) * noteLength;              volume *= GetReleaseTriggerAttenuation(noteLength);
             volume *= attenuation;  
757          }          }
758    
759          return volume;          return volume;
760      }      }
761    
762        float AbstractVoice::GetReleaseTriggerAttenuation(float noteLength) {
763            return 1 - RgnInfo.ReleaseTriggerDecay * noteLength;
764        }
765    
766        void AbstractVoice::EnterReleaseStage() {
767            if (pSignalUnitRack == NULL) {
768                pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
769                pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
770            } else {
771                pSignalUnitRack->EnterReleaseStage();
772            }
773        }
774    
775        bool AbstractVoice::EG1Finished() {
776            if (pSignalUnitRack == NULL) {
777                return pEG1->getSegmentType() == EG::segment_end;
778            } else {
779                return !pSignalUnitRack->GetEndpointUnit()->Active();
780            }
781        }
782    
783  } // namespace LinuxSampler  } // namespace LinuxSampler

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

  ViewVC Help
Powered by ViewVC