/[svn]/linuxsampler/trunk/src/engines/gig/Voice.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/gig/Voice.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 769 by schoenebeck, Sat Sep 3 11:14:30 2005 UTC revision 796 by persson, Sun Oct 30 08:35:13 2005 UTC
# Line 23  Line 23 
23    
24  #include "../../common/Features.h"  #include "../../common/Features.h"
25  #include "Synthesizer.h"  #include "Synthesizer.h"
26    #include "Profiler.h"
27    
28  #include "Voice.h"  #include "Voice.h"
29    
# Line 49  namespace LinuxSampler { namespace gig { Line 50  namespace LinuxSampler { namespace gig {
50          #else          #else
51          SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false);          SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false);
52          #endif          #endif
53          SYNTHESIS_MODE_SET_PROFILING(SynthesisMode, true);          SYNTHESIS_MODE_SET_PROFILING(SynthesisMode, Profiler::isEnabled());
54    
55          FilterLeft.Reset();          finalSynthesisParameters.filterLeft.Reset();
56          FilterRight.Reset();          finalSynthesisParameters.filterRight.Reset();
57      }      }
58    
59      Voice::~Voice() {      Voice::~Voice() {
# Line 138  namespace LinuxSampler { namespace gig { Line 139  namespace LinuxSampler { namespace gig {
139          PanLeft  = 1.0f - float(RTMath::Max(pDimRgn->Pan, 0)) /  63.0f;          PanLeft  = 1.0f - float(RTMath::Max(pDimRgn->Pan, 0)) /  63.0f;
140          PanRight = 1.0f - float(RTMath::Min(pDimRgn->Pan, 0)) / -64.0f;          PanRight = 1.0f - float(RTMath::Min(pDimRgn->Pan, 0)) / -64.0f;
141    
142          Pos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)          finalSynthesisParameters.dPos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
143            Pos = pDimRgn->SampleStartOffset;
144    
145          // 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
146          long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;          long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;
# Line 149  namespace LinuxSampler { namespace gig { Line 151  namespace LinuxSampler { namespace gig {
151    
152              // check if there's a loop defined which completely fits into the cached (RAM) part of the sample              // check if there's a loop defined which completely fits into the cached (RAM) part of the sample
153              if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {              if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {
154                  RAMLoop        = true;                  RAMLoop            = true;
155                  LoopCyclesLeft = pSample->LoopPlayCount;                  loop.uiTotalCycles = pSample->LoopPlayCount;
156                    loop.uiCyclesLeft  = pSample->LoopPlayCount;
157                    loop.uiStart       = pSample->LoopStart;
158                    loop.uiEnd         = pSample->LoopEnd;
159                    loop.uiSize        = pSample->LoopSize;
160              }              }
161              else RAMLoop = false;              else RAMLoop = false;
162    
# Line 164  namespace LinuxSampler { namespace gig { Line 170  namespace LinuxSampler { namespace gig {
170          else { // RAM only voice          else { // RAM only voice
171              MaxRAMPos = cachedsamples;              MaxRAMPos = cachedsamples;
172              if (pSample->Loops) {              if (pSample->Loops) {
173                  RAMLoop        = true;                  RAMLoop           = true;
174                  LoopCyclesLeft = pSample->LoopPlayCount;                  loop.uiCyclesLeft = pSample->LoopPlayCount;
175              }              }
176              else RAMLoop = false;              else RAMLoop = false;
177              dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));              dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));
# Line 214  namespace LinuxSampler { namespace gig { Line 220  namespace LinuxSampler { namespace gig {
220              EG1.trigger(pDimRgn->EG1PreAttack,              EG1.trigger(pDimRgn->EG1PreAttack,
221                          pDimRgn->EG1Attack * eg1attack,                          pDimRgn->EG1Attack * eg1attack,
222                          pDimRgn->EG1Hold,                          pDimRgn->EG1Hold,
                         pSample->LoopStart,  
223                          pDimRgn->EG1Decay1 * eg1decay * velrelease,                          pDimRgn->EG1Decay1 * eg1decay * velrelease,
224                          pDimRgn->EG1Decay2 * eg1decay * velrelease,                          pDimRgn->EG1Decay2 * eg1decay * velrelease,
225                          pDimRgn->EG1InfiniteSustain,                          pDimRgn->EG1InfiniteSustain,
# Line 253  namespace LinuxSampler { namespace gig { Line 258  namespace LinuxSampler { namespace gig {
258              EG2.trigger(pDimRgn->EG2PreAttack,              EG2.trigger(pDimRgn->EG2PreAttack,
259                          pDimRgn->EG2Attack * eg2attack,                          pDimRgn->EG2Attack * eg2attack,
260                          false,                          false,
                         pSample->LoopStart,  
261                          pDimRgn->EG2Decay1 * eg2decay * velrelease,                          pDimRgn->EG2Decay1 * eg2decay * velrelease,
262                          pDimRgn->EG2Decay2 * eg2decay * velrelease,                          pDimRgn->EG2Decay2 * eg2decay * velrelease,
263                          pDimRgn->EG2InfiniteSustain,                          pDimRgn->EG2InfiniteSustain,
# Line 469  namespace LinuxSampler { namespace gig { Line 473  namespace LinuxSampler { namespace gig {
473              #endif // CONFIG_OVERRIDE_RESONANCE_CTRL              #endif // CONFIG_OVERRIDE_RESONANCE_CTRL
474    
475              #ifndef CONFIG_OVERRIDE_FILTER_TYPE              #ifndef CONFIG_OVERRIDE_FILTER_TYPE
476              FilterLeft.SetType(pDimRgn->VCFType);              finalSynthesisParameters.filterLeft.SetType(pDimRgn->VCFType);
477              FilterRight.SetType(pDimRgn->VCFType);              finalSynthesisParameters.filterRight.SetType(pDimRgn->VCFType);
478              #else // override filter type              #else // override filter type
479              FilterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE);              FilterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE);
480              FilterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE);              FilterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE);
# Line 490  namespace LinuxSampler { namespace gig { Line 494  namespace LinuxSampler { namespace gig {
494              if (VCFCutoffCtrl.controller) {              if (VCFCutoffCtrl.controller) {
495                  cvalue = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller];                  cvalue = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller];
496                  if (pDimRgn->VCFCutoffControllerInvert) cvalue = 127 - cvalue;                  if (pDimRgn->VCFCutoffControllerInvert) cvalue = 127 - cvalue;
497                    // VCFVelocityScale in this case means Minimum cutoff
498                  if (cvalue < pDimRgn->VCFVelocityScale) cvalue = pDimRgn->VCFVelocityScale;                  if (cvalue < pDimRgn->VCFVelocityScale) cvalue = pDimRgn->VCFVelocityScale;
499              }              }
500              else {              else {
# Line 497  namespace LinuxSampler { namespace gig { Line 502  namespace LinuxSampler { namespace gig {
502              }              }
503              cutoff *= float(cvalue) * 0.00787402f; // (1 / 127)              cutoff *= float(cvalue) * 0.00787402f; // (1 / 127)
504              if (cutoff > 1.0) cutoff = 1.0;              if (cutoff > 1.0) cutoff = 1.0;
505              cutoff = exp(cutoff * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MIN;              cutoff = (cutoff < 0.5 ? cutoff * 4826 - 1 : cutoff * 5715 - 449);
506                if (cutoff < 1.0) cutoff = 1.0;
507    
508              // calculate resonance              // calculate resonance
509              float resonance = (float) VCFResonanceCtrl.value * 0.00787f;   // 0.0..1.0              float resonance = (float) (VCFResonanceCtrl.controller ? VCFResonanceCtrl.value : pDimRgn->VCFResonance) * 0.00787f; // 0.0..1.0
             if (pDimRgn->VCFKeyboardTracking) {  
                 resonance += (float) (itNoteOnEvent->Param.Note.Key - pDimRgn->VCFKeyboardTrackingBreakpoint) * 0.00787f;  
             }  
             Constrain(resonance, 0.0, 1.0); // correct resonance if outside allowed value range (0.0..1.0)  
510    
511              VCFCutoffCtrl.fvalue    = cutoff - CONFIG_FILTER_CUTOFF_MIN;              VCFCutoffCtrl.fvalue    = cutoff - 1.0;
512              VCFResonanceCtrl.fvalue = resonance;              VCFResonanceCtrl.fvalue = resonance;
513          }          }
514          else {          else {
# Line 547  namespace LinuxSampler { namespace gig { Line 549  namespace LinuxSampler { namespace gig {
549    
550                      if (DiskVoice) {                      if (DiskVoice) {
551                          // check if we reached the allowed limit of the sample RAM cache                          // check if we reached the allowed limit of the sample RAM cache
552                          if (Pos > MaxRAMPos) {                          if (finalSynthesisParameters.dPos > MaxRAMPos) {
553                              dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos));                              dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", finalSynthesisParameters.dPos));
554                              this->PlaybackState = playback_state_disk;                              this->PlaybackState = playback_state_disk;
555                          }                          }
556                      }                      } else if (finalSynthesisParameters.dPos >= pSample->GetCache().Size / pSample->FrameSize) {
                     else if (Pos >= pSample->GetCache().Size / pSample->FrameSize) {  
557                          this->PlaybackState = playback_state_end;                          this->PlaybackState = playback_state_end;
558                      }                      }
559                  }                  }
# Line 567  namespace LinuxSampler { namespace gig { Line 568  namespace LinuxSampler { namespace gig {
568                              KillImmediately();                              KillImmediately();
569                              return;                              return;
570                          }                          }
571                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(Pos) - MaxRAMPos));                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(finalSynthesisParameters.dPos) - MaxRAMPos));
572                          Pos -= int(Pos);                          finalSynthesisParameters.dPos -= int(finalSynthesisParameters.dPos);
573                          RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet                          RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet
574                      }                      }
575    
# Line 589  namespace LinuxSampler { namespace gig { Line 590  namespace LinuxSampler { namespace gig {
590                      // render current audio fragment                      // render current audio fragment
591                      Synthesize(Samples, ptr, Delay);                      Synthesize(Samples, ptr, Delay);
592    
593                      const int iPos = (int) Pos;                      const int iPos = (int) finalSynthesisParameters.dPos;
594                      const int readSampleWords = iPos * pSample->Channels; // amount of sample words actually been read                      const int readSampleWords = iPos * pSample->Channels; // amount of sample words actually been read
595                      DiskStreamRef.pStream->IncrementReadPos(readSampleWords);                      DiskStreamRef.pStream->IncrementReadPos(readSampleWords);
596                      Pos -= iPos; // just keep fractional part of Pos                      finalSynthesisParameters.dPos -= iPos; // just keep fractional part of playback position
597    
598                      // change state of voice to 'end' if we really reached the end of the sample data                      // change state of voice to 'end' if we really reached the end of the sample data
599                      if (RealSampleWordsLeftToRead >= 0) {                      if (RealSampleWordsLeftToRead >= 0) {
# Line 607  namespace LinuxSampler { namespace gig { Line 608  namespace LinuxSampler { namespace gig {
608                  break;                  break;
609          }          }
610    
         // Reset synthesis event lists  
         pEngineChannel->pEvents->clear();  
   
611          // Reset delay          // Reset delay
612          Delay = 0;          Delay = 0;
613    
# Line 624  namespace LinuxSampler { namespace gig { Line 622  namespace LinuxSampler { namespace gig {
622       *  suspended / not running.       *  suspended / not running.
623       */       */
624      void Voice::Reset() {      void Voice::Reset() {
625          FilterLeft.Reset();          finalSynthesisParameters.filterLeft.Reset();
626          FilterRight.Reset();          finalSynthesisParameters.filterRight.Reset();
627          DiskStreamRef.pStream = NULL;          DiskStreamRef.pStream = NULL;
628          DiskStreamRef.hStream = 0;          DiskStreamRef.hStream = 0;
629          DiskStreamRef.State   = Stream::state_unused;          DiskStreamRef.State   = Stream::state_unused;
# Line 645  namespace LinuxSampler { namespace gig { Line 643  namespace LinuxSampler { namespace gig {
643      void Voice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {      void Voice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {
644          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
645              if (itEvent->Type == Event::type_release) {              if (itEvent->Type == Event::type_release) {
646                  EG1.update(EGADSR::event_release, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  EG1.update(EGADSR::event_release, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
647                  EG2.update(EGADSR::event_release, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  EG2.update(EGADSR::event_release, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
648              } else if (itEvent->Type == Event::type_cancel_release) {              } else if (itEvent->Type == Event::type_cancel_release) {
649                  EG1.update(EGADSR::event_cancel_release, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  EG1.update(EGADSR::event_cancel_release, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
650                  EG2.update(EGADSR::event_cancel_release, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  EG2.update(EGADSR::event_cancel_release, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
651              }              }
652          }          }
653      }      }
# Line 692  namespace LinuxSampler { namespace gig { Line 690  namespace LinuxSampler { namespace gig {
690    
691      void Voice::processPitchEvent(RTList<Event>::Iterator& itEvent) {      void Voice::processPitchEvent(RTList<Event>::Iterator& itEvent) {
692          const float pitch = RTMath::CentsToFreqRatio(((double) itEvent->Param.Pitch.Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents          const float pitch = RTMath::CentsToFreqRatio(((double) itEvent->Param.Pitch.Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents
693          fFinalPitch *= pitch;          finalSynthesisParameters.fFinalPitch *= pitch;
694          PitchBend = pitch;          PitchBend = pitch;
695      }      }
696    
# Line 714  namespace LinuxSampler { namespace gig { Line 712  namespace LinuxSampler { namespace gig {
712          if (ccvalue < pDimRgn->VCFVelocityScale) ccvalue = pDimRgn->VCFVelocityScale;          if (ccvalue < pDimRgn->VCFVelocityScale) ccvalue = pDimRgn->VCFVelocityScale;
713          float cutoff = CutoffBase * float(ccvalue) * 0.00787402f; // (1 / 127)          float cutoff = CutoffBase * float(ccvalue) * 0.00787402f; // (1 / 127)
714          if (cutoff > 1.0) cutoff = 1.0;          if (cutoff > 1.0) cutoff = 1.0;
715          cutoff = exp(cutoff * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MIN - CONFIG_FILTER_CUTOFF_MIN;          cutoff = (cutoff < 0.5 ? cutoff * 4826 - 1 : cutoff * 5715 - 449);
716          VCFCutoffCtrl.fvalue = cutoff; // needed for initialization of fFinalCutoff next time          if (cutoff < 1.0) cutoff = 1.0;
717    
718            VCFCutoffCtrl.fvalue = cutoff - 1.0; // needed for initialization of fFinalCutoff next time
719          fFinalCutoff = cutoff;          fFinalCutoff = cutoff;
720      }      }
721    
# Line 738  namespace LinuxSampler { namespace gig { Line 738  namespace LinuxSampler { namespace gig {
738       *  @param Skip    - number of sample points to skip in output buffer       *  @param Skip    - number of sample points to skip in output buffer
739       */       */
740      void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {      void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
741            finalSynthesisParameters.pOutLeft  = &pEngineChannel->pOutputLeft[Skip];
742            finalSynthesisParameters.pOutRight = &pEngineChannel->pOutputRight[Skip];
743            finalSynthesisParameters.pSrc      = pSrc;
744    
745          RTList<Event>::Iterator itCCEvent = pEngineChannel->pEvents->first();          RTList<Event>::Iterator itCCEvent = pEngineChannel->pEvents->first();
746          RTList<Event>::Iterator itNoteEvent = pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents->first();          RTList<Event>::Iterator itNoteEvent = pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents->first();
747    
# Line 746  namespace LinuxSampler { namespace gig { Line 750  namespace LinuxSampler { namespace gig {
750              while (itNoteEvent && itNoteEvent->FragmentPos() <= Skip) ++itNoteEvent;              while (itNoteEvent && itNoteEvent->FragmentPos() <= Skip) ++itNoteEvent;
751          }          }
752    
753            uint killPos;
754            if (itKillEvent) killPos = RTMath::Min(itKillEvent->FragmentPos(), pEngine->MaxFadeOutPos);
755    
756          uint i = Skip;          uint i = Skip;
757          while (i < Samples) {          while (i < Samples) {
758              int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples);              int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples);
759    
760              // initialize all final synthesis parameters              // initialize all final synthesis parameters
761              fFinalPitch = PitchBase * PitchBend;              finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend;
762              #if CONFIG_PROCESS_MUTED_CHANNELS              #if CONFIG_PROCESS_MUTED_CHANNELS
763              fFinalVolume = this->Volume * this->CrossfadeVolume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume);              fFinalVolume = this->Volume * this->CrossfadeVolume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume);
764              #else              #else
# Line 766  namespace LinuxSampler { namespace gig { Line 773  namespace LinuxSampler { namespace gig {
773              // process transition events (note on, note off & sustain pedal)              // process transition events (note on, note off & sustain pedal)
774              processTransitionEvents(itNoteEvent, iSubFragmentEnd);              processTransitionEvents(itNoteEvent, iSubFragmentEnd);
775    
776                // if the voice was killed in this subfragment switch EG1 to fade out stage
777                if (itKillEvent && killPos <= iSubFragmentEnd) {
778                    EG1.enterFadeOutStage();
779                    itKillEvent = Pool<Event>::Iterator();
780                }
781    
782              // process envelope generators              // process envelope generators
783              switch (EG1.getSegmentType()) {              switch (EG1.getSegmentType()) {
784                  case EGADSR::segment_lin:                  case EGADSR::segment_lin:
# Line 789  namespace LinuxSampler { namespace gig { Line 802  namespace LinuxSampler { namespace gig {
802                      fFinalCutoff *= EG2.getLevel();                      fFinalCutoff *= EG2.getLevel();
803                      break; // noop                      break; // noop
804              }              }
805              fFinalPitch *= RTMath::CentsToFreqRatio(EG3.render());              if (EG3.active()) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(EG3.render());
806    
807              // process low frequency oscillators              // process low frequency oscillators
808              if (bLFO1Enabled) fFinalVolume *= pLFO1->render();              if (bLFO1Enabled) fFinalVolume *= pLFO1->render();
809              if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();              if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();
810              if (bLFO3Enabled) fFinalPitch  *= RTMath::CentsToFreqRatio(pLFO3->render());              if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
811    
812              // if filter enabled then update filter coefficients              // if filter enabled then update filter coefficients
813              if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) {              if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) {
814                  FilterLeft.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate);                  finalSynthesisParameters.filterLeft.SetParameters(fFinalCutoff + 1.0, fFinalResonance, pEngine->SampleRate);
815                  FilterRight.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate);                  finalSynthesisParameters.filterRight.SetParameters(fFinalCutoff + 1.0, fFinalResonance, pEngine->SampleRate);
816              }              }
817    
818              // how many steps do we calculate for this next subfragment              // do we need resampling?
819              const int steps = iSubFragmentEnd - i;              const float __PLUS_ONE_CENT  = 1.000577789506554859250142541782224725466f;
820                const float __MINUS_ONE_CENT = 0.9994225441413807496009516495583113737666f;
821              // select the appropriate synthesis mode              const bool bResamplingRequired = !(finalSynthesisParameters.fFinalPitch <= __PLUS_ONE_CENT &&
822              SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, fFinalPitch != 1.0f);                                                 finalSynthesisParameters.fFinalPitch >= __MINUS_ONE_CENT);
823                SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, bResamplingRequired);
824    
825                // prepare final synthesis parameters structure
826                finalSynthesisParameters.fFinalVolumeLeft  = fFinalVolume * PanLeft;
827                finalSynthesisParameters.fFinalVolumeRight = fFinalVolume * PanRight;
828                finalSynthesisParameters.uiToGo            = iSubFragmentEnd - i;
829    
830              // render audio for one subfragment              // render audio for one subfragment
831              RunSynthesisFunction(SynthesisMode, *this, iSubFragmentEnd, pSrc, i);              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
832    
833                const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
834    
835              // increment envelopes' positions              // increment envelopes' positions
836              if (EG1.active()) {              if (EG1.active()) {
837    
838                    // 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
839                    if (pSample->Loops && Pos <= pSample->LoopStart && pSample->LoopStart < newPos) {
840                        EG1.update(EGADSR::event_hold_end, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
841                    }
842    
843                  EG1.increment(1);                  EG1.increment(1);
844                  if (!EG1.toStageEndLeft()) EG1.update(EGADSR::event_stage_end, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (!EG1.toStageEndLeft()) EG1.update(EGADSR::event_stage_end, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
845              }              }
846              if (EG2.active()) {              if (EG2.active()) {
847                  EG2.increment(1);                  EG2.increment(1);
848                  if (!EG2.toStageEndLeft()) EG2.update(EGADSR::event_stage_end, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                  if (!EG2.toStageEndLeft()) EG2.update(EGADSR::event_stage_end, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
849              }              }
850              EG3.increment(1);              EG3.increment(1);
851              if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached              if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
852    
853                Pos = newPos;
854              i = iSubFragmentEnd;              i = iSubFragmentEnd;
855          }          }
856      }      }

Legend:
Removed from v.769  
changed lines
  Added in v.796

  ViewVC Help
Powered by ViewVC