/[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 2175 by persson, Mon Apr 25 08:12:36 2011 UTC revision 2217 by iliev, Tue Jul 26 15:51:30 2011 UTC
# 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 LFO (0..1 range)          pLFO1 = new LFOUnsigned(1.0f);  // amplitude LFO (0..1 range)
32          pLFO2 = new LFOUnsigned(1.0f);  // filter LFO (0..1 range)          pLFO2 = new LFOUnsigned(1.0f);  // filter LFO (0..1 range)
# Line 110  namespace LinuxSampler { Line 110  namespace LinuxSampler {
110          SmplInfo   = GetSampleInfo();          SmplInfo   = GetSampleInfo();
111          RgnInfo    = GetRegionInfo();          RgnInfo    = GetRegionInfo();
112          InstrInfo  = GetInstrumentInfo();          InstrInfo  = GetInstrumentInfo();
113            
114            AboutToTrigger();
115    
116          // calculate volume          // calculate volume
117          const double velocityAttenuation = GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity);          const double velocityAttenuation = GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity);
# Line 133  namespace LinuxSampler { Line 135  namespace LinuxSampler {
135          PanLeftSmoother.trigger(pEngineChannel->GlobalPanLeft, subfragmentRate);          PanLeftSmoother.trigger(pEngineChannel->GlobalPanLeft, subfragmentRate);
136          PanRightSmoother.trigger(pEngineChannel->GlobalPanRight, subfragmentRate);          PanRightSmoother.trigger(pEngineChannel->GlobalPanRight, subfragmentRate);
137    
         finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)  
         Pos = RgnInfo.SampleStartOffset;  
   
138          // Check if the sample needs disk streaming or is too short for that          // Check if the sample needs disk streaming or is too short for that
139          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;
140          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;          DiskVoice          = cachedsamples < SmplInfo.TotalFrameCount;
141    
142            SetSampleStartOffset();
143    
144          if (DiskVoice) { // voice to be streamed from disk          if (DiskVoice) { // voice to be streamed from disk
145              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {              if (cachedsamples > (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {
146                  MaxRAMPos = cachedsamples - (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH) / SmplInfo.ChannelCount; //TODO: this calculation is too pessimistic and may better be moved to Render() method, so it calculates MaxRAMPos dependent to the current demand of sample points to be rendered (e.g. in case of JACK)                  MaxRAMPos = cachedsamples - (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH) / SmplInfo.ChannelCount; //TODO: this calculation is too pessimistic and may better be moved to Render() method, so it calculates MaxRAMPos dependent to the current demand of sample points to be rendered (e.g. in case of JACK)
# Line 176  namespace LinuxSampler { Line 177  namespace LinuxSampler {
177          // the length of the decay and release curves are dependent on the velocity          // the length of the decay and release curves are dependent on the velocity
178          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);
179    
180          // setup EG 1 (VCA EG)          if (pSignalUnitRack == NULL) { // setup EG 1 (VCA EG)
         {  
181              // get current value of EG1 controller              // get current value of EG1 controller
182              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);              double eg1controllervalue = GetEG1ControllerValue(itNoteOnEvent->Param.Note.Velocity);
183    
# Line 185  namespace LinuxSampler { Line 185  namespace LinuxSampler {
185              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);
186    
187              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
188            } else {
189                pSignalUnitRack->Trigger();
190          }          }
191    
192  #ifdef CONFIG_INTERPOLATE_VOLUME  #ifdef CONFIG_INTERPOLATE_VOLUME
# Line 197  namespace LinuxSampler { Line 199  namespace LinuxSampler {
199          else          else
200      #else      #else
201          {          {
202              float finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();              float finalVolume;
203                if (pSignalUnitRack == NULL) {
204                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pEG1->getLevel();
205                } else {
206                    finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * pSignalUnitRack->GetEndpointUnit()->GetVolume();
207                }
208    
209              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * pEngineChannel->GlobalPanLeft;              finalSynthesisParameters.fFinalVolumeLeft  = finalVolume * VolumeLeft  * pEngineChannel->GlobalPanLeft;
210              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight;              finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight;
# Line 205  namespace LinuxSampler { Line 212  namespace LinuxSampler {
212      #endif      #endif
213  #endif  #endif
214    
215          // setup EG 2 (VCF Cutoff EG)          if (pSignalUnitRack == NULL) {
216          {              // setup EG 2 (VCF Cutoff EG)
217              // get current value of EG2 controller              {
218              double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);                  // get current value of EG2 controller
219                    double eg2controllervalue = GetEG2ControllerValue(itNoteOnEvent->Param.Note.Velocity);
220    
221                    // calculate influence of EG2 controller on EG2's parameters
222                    EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);
223    
224                    TriggerEG2(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
225                }
226    
             // calculate influence of EG2 controller on EG2's parameters  
             EGInfo egInfo = CalculateEG2ControllerInfluence(eg2controllervalue);  
227    
228              TriggerEG2(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);              // setup EG 3 (VCO EG)
229          }              {
230                    // if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch
231                    bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;
232                    float eg3depth = (bPortamento)
233                                 ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100)
234                                 : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);
235                    float eg3time = (bPortamento)
236                                ? pEngineChannel->PortamentoTime
237                                : RgnInfo.EG3Attack;
238                    EG3.trigger(eg3depth, eg3time, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
239                    dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time));
240                }
241    
242    
243          // setup EG 3 (VCO EG)              // setup LFO 1 (VCA LFO)
244          {              InitLFO1();
245              // if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch              // setup LFO 2 (VCF Cutoff LFO)
246              bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;              InitLFO2();
247              float eg3depth = (bPortamento)              // setup LFO 3 (VCO LFO)
248                           ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100)              InitLFO3();
                          : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);  
             float eg3time = (bPortamento)  
                         ? pEngineChannel->PortamentoTime  
                         : RgnInfo.EG3Attack;  
             EG3.trigger(eg3depth, eg3time, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);  
             dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time));  
249          }          }
250    
251    
         // setup LFO 1 (VCA LFO)  
         InitLFO1();  
         // setup LFO 2 (VCF Cutoff LFO)  
         InitLFO2();  
         // setup LFO 3 (VCO LFO)  
         InitLFO3();  
   
   
252          #if CONFIG_FORCE_FILTER          #if CONFIG_FORCE_FILTER
253          const bool bUseFilter = true;          const bool bUseFilter = true;
254          #else // use filter only if instrument file told so          #else // use filter only if instrument file told so
# Line 285  namespace LinuxSampler { Line 294  namespace LinuxSampler {
294    
295          return 0; // success          return 0; // success
296      }      }
297        
298        void AbstractVoice::SetSampleStartOffset() {
299            finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
300            Pos = RgnInfo.SampleStartOffset;
301        }
302    
303      /**      /**
304       *  Synthesizes the current audio fragment for this voice.       *  Synthesizes the current audio fragment for this voice.
# Line 342  namespace LinuxSampler { Line 356  namespace LinuxSampler {
356                  // drivers that use Samples < MaxSamplesPerCycle).                  // drivers that use Samples < MaxSamplesPerCycle).
357                  // End the EG1 here, at pos 0, with a shorter max fade                  // End the EG1 here, at pos 0, with a shorter max fade
358                  // out time.                  // out time.
359                  pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (pSignalUnitRack == NULL) {
360                        pEG1->enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
361                    } else {
362                        // TODO:
363                    }
364                  itKillEvent = Pool<Event>::Iterator();                  itKillEvent = Pool<Event>::Iterator();
365              } else {              } else {
366                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);                  killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);
# Line 370  namespace LinuxSampler { Line 388  namespace LinuxSampler {
388              processTransitionEvents(itNoteEvent, iSubFragmentEnd);              processTransitionEvents(itNoteEvent, iSubFragmentEnd);
389              processGroupEvents(itGroupEvent, iSubFragmentEnd);              processGroupEvents(itGroupEvent, iSubFragmentEnd);
390    
391              // if the voice was killed in this subfragment, or if the              if (pSignalUnitRack == NULL) {
392              // filter EG is finished, switch EG1 to fade out stage                  // if the voice was killed in this subfragment, or if the
393              if ((itKillEvent && killPos <= iSubFragmentEnd) ||                  // filter EG is finished, switch EG1 to fade out stage
394                  (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&                  if ((itKillEvent && killPos <= iSubFragmentEnd) ||
395                   pEG2->getSegmentType() == EG::segment_end)) {                      (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
396                  pEG1->enterFadeOutStage();                      pEG2->getSegmentType() == EG::segment_end)) {
397                  itKillEvent = Pool<Event>::Iterator();                      pEG1->enterFadeOutStage();
398              }                      itKillEvent = Pool<Event>::Iterator();
399                    }
             // process envelope generators  
             switch (pEG1->getSegmentType()) {  
                 case EG::segment_lin:  
                     fFinalVolume *= pEG1->processLin();  
                     break;  
                 case EG::segment_exp:  
                     fFinalVolume *= pEG1->processExp();  
                     break;  
                 case EG::segment_end:  
                     fFinalVolume *= pEG1->getLevel();  
                     break; // noop  
                 case EG::segment_pow:  
                     fFinalVolume *= pEG1->processPow();  
                     break;  
             }  
             switch (pEG2->getSegmentType()) {  
                 case EG::segment_lin:  
                     fFinalCutoff *= pEG2->processLin();  
                     break;  
                 case EG::segment_exp:  
                     fFinalCutoff *= pEG2->processExp();  
                     break;  
                 case EG::segment_end:  
                     fFinalCutoff *= pEG2->getLevel();  
                     break; // noop  
                 case EG::segment_pow:  
                     fFinalCutoff *= pEG2->processPow();  
                     break;  
             }  
             if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();  
400    
401              // process low frequency oscillators                  // process envelope generators
402              if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());                  switch (pEG1->getSegmentType()) {
403              if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();                      case EG::segment_lin:
404              if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());                          fFinalVolume *= pEG1->processLin();
405                            break;
406                        case EG::segment_exp:
407                            fFinalVolume *= pEG1->processExp();
408                            break;
409                        case EG::segment_end:
410                            fFinalVolume *= pEG1->getLevel();
411                            break; // noop
412                        case EG::segment_pow:
413                            fFinalVolume *= pEG1->processPow();
414                            break;
415                    }
416                    switch (pEG2->getSegmentType()) {
417                        case EG::segment_lin:
418                            fFinalCutoff *= pEG2->processLin();
419                            break;
420                        case EG::segment_exp:
421                            fFinalCutoff *= pEG2->processExp();
422                            break;
423                        case EG::segment_end:
424                            fFinalCutoff *= pEG2->getLevel();
425                            break; // noop
426                        case EG::segment_pow:
427                            fFinalCutoff *= pEG2->processPow();
428                            break;
429                    }
430                    if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();
431    
432                    // process low frequency oscillators
433                    if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());
434                    if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();
435                    if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
436                } else {
437                    // if the voice was killed in this subfragment, or if the
438                    // filter EG is finished, switch EG1 to fade out stage
439                    /*if ((itKillEvent && killPos <= iSubFragmentEnd) ||
440                        (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) &&
441                        pEG2->getSegmentType() == EG::segment_end)) {
442                        pEG1->enterFadeOutStage();
443                        itKillEvent = Pool<Event>::Iterator();
444                    }*/
445                    // TODO: ^^^
446    
447                    fFinalVolume   *= pSignalUnitRack->GetEndpointUnit()->GetVolume();
448                    fFinalCutoff    = pSignalUnitRack->GetEndpointUnit()->CalculateFilterCutoff(fFinalCutoff);
449                    fFinalResonance = pSignalUnitRack->GetEndpointUnit()->CalculateResonance(fFinalResonance);
450                    
451                    finalSynthesisParameters.fFinalPitch =
452                        pSignalUnitRack->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);
453                        
454                }
455                
456              // limit the pitch so we don't read outside the buffer              // limit the pitch so we don't read outside the buffer
457              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));
458    
# Line 449  namespace LinuxSampler { Line 487  namespace LinuxSampler {
487              // render audio for one subfragment              // render audio for one subfragment
488              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
489    
490              // stop the rendering if volume EG is finished              if (pSignalUnitRack == NULL) {
491              if (pEG1->getSegmentType() == EG::segment_end) break;                  // stop the rendering if volume EG is finished
492                    if (pEG1->getSegmentType() == EG::segment_end) break;
493                } else {
494                    // stop the rendering if the endpoint unit is not active
495                    if (!pSignalUnitRack->GetEndpointUnit()->Active()) break;
496                }
497    
498              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
499    
500              // increment envelopes' positions              if (pSignalUnitRack == NULL) {
501              if (pEG1->active()) {                  // increment envelopes' positions
502                    if (pEG1->active()) {
503    
504                        // if sample has a loop and loop start has been reached in this subfragment, send a special event to EG1 to let it finish the attack hold stage
505                        if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
506                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
507                        }
508    
509                  // if sample has a loop and loop start has been reached in this subfragment, send a special event to EG1 to let it finish the attack hold stage                      pEG1->increment(1);
510                  if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {                      if (!pEG1->toStageEndLeft()) pEG1->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
                     pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);  
511                  }                  }
512                    if (pEG2->active()) {
513                  pEG1->increment(1);                      pEG2->increment(1);
514                  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);
515              }                  }
516              if (pEG2->active()) {                  EG3.increment(1);
517                  pEG2->increment(1);                  if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
518                  if (!pEG2->toStageEndLeft()) pEG2->update(EG::event_stage_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              } else {
519                        // if sample has a loop and loop start has been reached in this subfragment, send a special event to EG1 to let it finish the attack hold stage
520                        /*if (SmplInfo.HasLoops && Pos <= SmplInfo.LoopStart && SmplInfo.LoopStart < newPos) {
521                            pEG1->update(EG::event_hold_end, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
522                        }*/
523                    // TODO: ^^^
524                    
525                    pSignalUnitRack->Increment();
526              }              }
             EG3.increment(1);  
             if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached  
527    
528              Pos = newPos;              Pos = newPos;
529              i = iSubFragmentEnd;              i = iSubFragmentEnd;
# Line 501  namespace LinuxSampler { Line 554  namespace LinuxSampler {
554                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
555                      processResonanceEvent(itEvent);                      processResonanceEvent(itEvent);
556                  }                  }
557                  if (itEvent->Param.CC.Controller == pLFO1->ExtController) {                  if (pSignalUnitRack == NULL) {
558                      pLFO1->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
559                  }                          pLFO1->update(itEvent->Param.CC.Value);
560                  if (itEvent->Param.CC.Controller == pLFO2->ExtController) {                      }
561                      pLFO2->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO2->ExtController) {
562                  }                          pLFO2->update(itEvent->Param.CC.Value);
563                  if (itEvent->Param.CC.Controller == pLFO3->ExtController) {                      }
564                      pLFO3->update(itEvent->Param.CC.Value);                      if (itEvent->Param.CC.Controller == pLFO3->ExtController) {
565                            pLFO3->update(itEvent->Param.CC.Value);
566                        }
567                  }                  }
568                  if (itEvent->Param.CC.Controller == 7) { // volume                  if (itEvent->Param.CC.Controller == 7) { // volume
569                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);                      VolumeSmoother.update(AbstractEngine::VolumeCurve[itEvent->Param.CC.Value]);
# Line 521  namespace LinuxSampler { Line 576  namespace LinuxSampler {
576              }              }
577    
578              ProcessCCEvent(itEvent);              ProcessCCEvent(itEvent);
579                if (pSignalUnitRack != NULL) {
580                    pSignalUnitRack->ProcessCCEvent(itEvent);
581                }
582          }          }
583      }      }
584    
# Line 552  namespace LinuxSampler { Line 610  namespace LinuxSampler {
610                  if (itEvent->Type == Event::type_release) {                  if (itEvent->Type == Event::type_release) {
611                      EnterReleaseStage();                      EnterReleaseStage();
612                  } else if (itEvent->Type == Event::type_cancel_release) {                  } else if (itEvent->Type == Event::type_cancel_release) {
613                      pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                      if (pSignalUnitRack == NULL) {
614                      pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                          pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
615                            pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
616                        } else {
617                            pSignalUnitRack->CancelRelease();
618                        }
619                  }                  }
620              }              }
621          }          }
# Line 580  namespace LinuxSampler { Line 642  namespace LinuxSampler {
642       * @param itNoteOffEvent - event which causes this voice to die soon       * @param itNoteOffEvent - event which causes this voice to die soon
643       */       */
644      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
645          const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());          if (pSignalUnitRack == NULL) {
646          pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;              const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
647                pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
648            } else {
649                // TODO:
650            }
651      }      }
652    
653      /**      /**
# Line 643  namespace LinuxSampler { Line 709  namespace LinuxSampler {
709      }      }
710    
711      void AbstractVoice::EnterReleaseStage() {      void AbstractVoice::EnterReleaseStage() {
712          pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);          if (pSignalUnitRack == NULL) {
713          pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              pEG1->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
714                pEG2->update(EG::event_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
715            } else {
716                pSignalUnitRack->EnterReleaseStage();
717            }
718        }
719    
720        bool AbstractVoice::EG1Finished() {
721            if (pSignalUnitRack == NULL) {
722                return pEG1->getSegmentType() == EG::segment_end;
723            } else {
724                return !pSignalUnitRack->GetEndpointUnit()->Active();
725            }
726      }      }
727    
728  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.2175  
changed lines
  Added in v.2217

  ViewVC Help
Powered by ViewVC