/[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 831 by persson, Sat Jan 28 16:55:30 2006 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 Christian Schoenebeck                              *   *   Copyright (C) 2005, 2006 Christian Schoenebeck                        *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
9   *   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 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 135  namespace LinuxSampler { namespace gig { Line 136  namespace LinuxSampler { namespace gig {
136                  CrossfadeVolume = 1.0f;                  CrossfadeVolume = 1.0f;
137          }          }
138    
139          PanLeft  = 1.0f - float(RTMath::Max(pDimRgn->Pan, 0)) /  63.0f;          PanLeft  = Engine::PanCurve[64 - pDimRgn->Pan];
140          PanRight = 1.0f - float(RTMath::Min(pDimRgn->Pan, 0)) / -64.0f;          PanRight = Engine::PanCurve[64 + pDimRgn->Pan];
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 148  namespace LinuxSampler { namespace gig { Line 150  namespace LinuxSampler { namespace gig {
150              MaxRAMPos = cachedsamples - (pEngine->MaxSamplesPerCycle << CONFIG_MAX_PITCH) / pSample->Channels; //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 - (pEngine->MaxSamplesPerCycle << CONFIG_MAX_PITCH) / pSample->Channels; //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)
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) {              RAMLoop = (pSample->Loops && pSample->LoopEnd <= MaxRAMPos);
                 RAMLoop        = true;  
                 LoopCyclesLeft = pSample->LoopPlayCount;  
             }  
             else RAMLoop = false;  
154    
155              if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {              if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {
156                  dmsg(1,("Disk stream order failed!\n"));                  dmsg(1,("Disk stream order failed!\n"));
# Line 163  namespace LinuxSampler { namespace gig { Line 161  namespace LinuxSampler { namespace gig {
161          }          }
162          else { // RAM only voice          else { // RAM only voice
163              MaxRAMPos = cachedsamples;              MaxRAMPos = cachedsamples;
164              if (pSample->Loops) {              RAMLoop = (pSample->Loops != 0);
                 RAMLoop        = true;  
                 LoopCyclesLeft = pSample->LoopPlayCount;  
             }  
             else RAMLoop = false;  
165              dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));              dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));
166          }          }
167            if (RAMLoop) {
168                loop.uiTotalCycles = pSample->LoopPlayCount;
169                loop.uiCyclesLeft  = pSample->LoopPlayCount;
170                loop.uiStart       = pSample->LoopStart;
171                loop.uiEnd         = pSample->LoopEnd;
172                loop.uiSize        = pSample->LoopSize;
173            }
174    
175          // calculate initial pitch value          // calculate initial pitch value
176          {          {
# Line 214  namespace LinuxSampler { namespace gig { Line 214  namespace LinuxSampler { namespace gig {
214              EG1.trigger(pDimRgn->EG1PreAttack,              EG1.trigger(pDimRgn->EG1PreAttack,
215                          pDimRgn->EG1Attack * eg1attack,                          pDimRgn->EG1Attack * eg1attack,
216                          pDimRgn->EG1Hold,                          pDimRgn->EG1Hold,
                         pSample->LoopStart,  
217                          pDimRgn->EG1Decay1 * eg1decay * velrelease,                          pDimRgn->EG1Decay1 * eg1decay * velrelease,
218                          pDimRgn->EG1Decay2 * eg1decay * velrelease,                          pDimRgn->EG1Decay2 * eg1decay * velrelease,
219                          pDimRgn->EG1InfiniteSustain,                          pDimRgn->EG1InfiniteSustain,
# Line 224  namespace LinuxSampler { namespace gig { Line 223  namespace LinuxSampler { namespace gig {
223                          pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                          pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
224          }          }
225    
226            // setup initial volume in synthesis parameters
227            fFinalVolume = getVolume() * EG1.getLevel();
228            finalSynthesisParameters.fFinalVolumeLeft  = fFinalVolume * PanLeft * pEngineChannel->GlobalPanLeft;
229            finalSynthesisParameters.fFinalVolumeRight = fFinalVolume * PanRight * pEngineChannel->GlobalPanRight;
230    
231    
232          // setup EG 2 (VCF Cutoff EG)          // setup EG 2 (VCF Cutoff EG)
233          {          {
# Line 253  namespace LinuxSampler { namespace gig { Line 257  namespace LinuxSampler { namespace gig {
257              EG2.trigger(pDimRgn->EG2PreAttack,              EG2.trigger(pDimRgn->EG2PreAttack,
258                          pDimRgn->EG2Attack * eg2attack,                          pDimRgn->EG2Attack * eg2attack,
259                          false,                          false,
                         pSample->LoopStart,  
260                          pDimRgn->EG2Decay1 * eg2decay * velrelease,                          pDimRgn->EG2Decay1 * eg2decay * velrelease,
261                          pDimRgn->EG2Decay2 * eg2decay * velrelease,                          pDimRgn->EG2Decay2 * eg2decay * velrelease,
262                          pDimRgn->EG2InfiniteSustain,                          pDimRgn->EG2InfiniteSustain,
# Line 266  namespace LinuxSampler { namespace gig { Line 269  namespace LinuxSampler { namespace gig {
269    
270          // setup EG 3 (VCO EG)          // setup EG 3 (VCO EG)
271          {          {
272            double eg3depth = RTMath::CentsToFreqRatio(pDimRgn->EG3Depth);              // if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch
273            EG3.trigger(eg3depth, pDimRgn->EG3Attack, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;
274                float eg3depth = (bPortamento)
275                                     ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100)
276                                     : RTMath::CentsToFreqRatio(pDimRgn->EG3Depth);
277                float eg3time = (bPortamento)
278                                    ? pEngineChannel->PortamentoTime
279                                    : pDimRgn->EG3Attack;
280                EG3.trigger(eg3depth, eg3time, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
281                dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time));
282          }          }
283    
284    
# Line 469  namespace LinuxSampler { namespace gig { Line 480  namespace LinuxSampler { namespace gig {
480              #endif // CONFIG_OVERRIDE_RESONANCE_CTRL              #endif // CONFIG_OVERRIDE_RESONANCE_CTRL
481    
482              #ifndef CONFIG_OVERRIDE_FILTER_TYPE              #ifndef CONFIG_OVERRIDE_FILTER_TYPE
483              FilterLeft.SetType(pDimRgn->VCFType);              finalSynthesisParameters.filterLeft.SetType(pDimRgn->VCFType);
484              FilterRight.SetType(pDimRgn->VCFType);              finalSynthesisParameters.filterRight.SetType(pDimRgn->VCFType);
485              #else // override filter type              #else // override filter type
486              FilterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE);              FilterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE);
487              FilterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE);              FilterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE);
# Line 490  namespace LinuxSampler { namespace gig { Line 501  namespace LinuxSampler { namespace gig {
501              if (VCFCutoffCtrl.controller) {              if (VCFCutoffCtrl.controller) {
502                  cvalue = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller];                  cvalue = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller];
503                  if (pDimRgn->VCFCutoffControllerInvert) cvalue = 127 - cvalue;                  if (pDimRgn->VCFCutoffControllerInvert) cvalue = 127 - cvalue;
504                    // VCFVelocityScale in this case means Minimum cutoff
505                  if (cvalue < pDimRgn->VCFVelocityScale) cvalue = pDimRgn->VCFVelocityScale;                  if (cvalue < pDimRgn->VCFVelocityScale) cvalue = pDimRgn->VCFVelocityScale;
506              }              }
507              else {              else {
# Line 497  namespace LinuxSampler { namespace gig { Line 509  namespace LinuxSampler { namespace gig {
509              }              }
510              cutoff *= float(cvalue) * 0.00787402f; // (1 / 127)              cutoff *= float(cvalue) * 0.00787402f; // (1 / 127)
511              if (cutoff > 1.0) cutoff = 1.0;              if (cutoff > 1.0) cutoff = 1.0;
512              cutoff = exp(cutoff * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MIN;              cutoff = (cutoff < 0.5 ? cutoff * 4826 - 1 : cutoff * 5715 - 449);
513                if (cutoff < 1.0) cutoff = 1.0;
514    
515              // calculate resonance              // calculate resonance
516              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)  
517    
518              VCFCutoffCtrl.fvalue    = cutoff - CONFIG_FILTER_CUTOFF_MIN;              VCFCutoffCtrl.fvalue    = cutoff - 1.0;
519              VCFResonanceCtrl.fvalue = resonance;              VCFResonanceCtrl.fvalue = resonance;
520          }          }
521          else {          else {
# Line 547  namespace LinuxSampler { namespace gig { Line 556  namespace LinuxSampler { namespace gig {
556    
557                      if (DiskVoice) {                      if (DiskVoice) {
558                          // check if we reached the allowed limit of the sample RAM cache                          // check if we reached the allowed limit of the sample RAM cache
559                          if (Pos > MaxRAMPos) {                          if (finalSynthesisParameters.dPos > MaxRAMPos) {
560                              dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos));                              dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", finalSynthesisParameters.dPos));
561                              this->PlaybackState = playback_state_disk;                              this->PlaybackState = playback_state_disk;
562                          }                          }
563                      }                      } else if (finalSynthesisParameters.dPos >= pSample->GetCache().Size / pSample->FrameSize) {
                     else if (Pos >= pSample->GetCache().Size / pSample->FrameSize) {  
564                          this->PlaybackState = playback_state_end;                          this->PlaybackState = playback_state_end;
565                      }                      }
566                  }                  }
# Line 567  namespace LinuxSampler { namespace gig { Line 575  namespace LinuxSampler { namespace gig {
575                              KillImmediately();                              KillImmediately();
576                              return;                              return;
577                          }                          }
578                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(Pos) - MaxRAMPos));                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(finalSynthesisParameters.dPos) - MaxRAMPos));
579                          Pos -= int(Pos);                          finalSynthesisParameters.dPos -= int(finalSynthesisParameters.dPos);
580                          RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet                          RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet
581                      }                      }
582    
# Line 589  namespace LinuxSampler { namespace gig { Line 597  namespace LinuxSampler { namespace gig {
597                      // render current audio fragment                      // render current audio fragment
598                      Synthesize(Samples, ptr, Delay);                      Synthesize(Samples, ptr, Delay);
599    
600                      const int iPos = (int) Pos;                      const int iPos = (int) finalSynthesisParameters.dPos;
601                      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
602                      DiskStreamRef.pStream->IncrementReadPos(readSampleWords);                      DiskStreamRef.pStream->IncrementReadPos(readSampleWords);
603                      Pos -= iPos; // just keep fractional part of Pos                      finalSynthesisParameters.dPos -= iPos; // just keep fractional part of playback position
604    
605                      // 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
606                      if (RealSampleWordsLeftToRead >= 0) {                      if (RealSampleWordsLeftToRead >= 0) {
# Line 607  namespace LinuxSampler { namespace gig { Line 615  namespace LinuxSampler { namespace gig {
615                  break;                  break;
616          }          }
617    
         // Reset synthesis event lists  
         pEngineChannel->pEvents->clear();  
   
618          // Reset delay          // Reset delay
619          Delay = 0;          Delay = 0;
620    
# Line 624  namespace LinuxSampler { namespace gig { Line 629  namespace LinuxSampler { namespace gig {
629       *  suspended / not running.       *  suspended / not running.
630       */       */
631      void Voice::Reset() {      void Voice::Reset() {
632          FilterLeft.Reset();          finalSynthesisParameters.filterLeft.Reset();
633          FilterRight.Reset();          finalSynthesisParameters.filterRight.Reset();
634          DiskStreamRef.pStream = NULL;          DiskStreamRef.pStream = NULL;
635          DiskStreamRef.hStream = 0;          DiskStreamRef.hStream = 0;
636          DiskStreamRef.State   = Stream::state_unused;          DiskStreamRef.State   = Stream::state_unused;
# Line 645  namespace LinuxSampler { namespace gig { Line 650  namespace LinuxSampler { namespace gig {
650      void Voice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {      void Voice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {
651          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
652              if (itEvent->Type == Event::type_release) {              if (itEvent->Type == Event::type_release) {
653                  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);
654                  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);
655              } else if (itEvent->Type == Event::type_cancel_release) {              } else if (itEvent->Type == Event::type_cancel_release) {
656                  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);
657                  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);
658              }              }
659          }          }
660      }      }
# Line 692  namespace LinuxSampler { namespace gig { Line 697  namespace LinuxSampler { namespace gig {
697    
698      void Voice::processPitchEvent(RTList<Event>::Iterator& itEvent) {      void Voice::processPitchEvent(RTList<Event>::Iterator& itEvent) {
699          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
700          fFinalPitch *= pitch;          finalSynthesisParameters.fFinalPitch *= pitch;
701          PitchBend = pitch;          PitchBend = pitch;
702      }      }
703    
704      void Voice::processCrossFadeEvent(RTList<Event>::Iterator& itEvent) {      void Voice::processCrossFadeEvent(RTList<Event>::Iterator& itEvent) {
705          CrossfadeVolume = CrossfadeAttenuation(itEvent->Param.CC.Value);          CrossfadeVolume = CrossfadeAttenuation(itEvent->Param.CC.Value);
706            fFinalVolume = getVolume();
707        }
708    
709        float Voice::getVolume() {
710          #if CONFIG_PROCESS_MUTED_CHANNELS          #if CONFIG_PROCESS_MUTED_CHANNELS
711          const float effectiveVolume = CrossfadeVolume * Volume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume);          return pEngineChannel->GetMute() ? 0 : (Volume * CrossfadeVolume * pEngineChannel->GlobalVolume);
712          #else          #else
713          const float effectiveVolume = CrossfadeVolume * Volume * pEngineChannel->GlobalVolume;          return Volume * CrossfadeVolume * pEngineChannel->GlobalVolume;
714          #endif          #endif
         fFinalVolume = effectiveVolume;  
715      }      }
716    
717      void Voice::processCutoffEvent(RTList<Event>::Iterator& itEvent) {      void Voice::processCutoffEvent(RTList<Event>::Iterator& itEvent) {
# Line 714  namespace LinuxSampler { namespace gig { Line 722  namespace LinuxSampler { namespace gig {
722          if (ccvalue < pDimRgn->VCFVelocityScale) ccvalue = pDimRgn->VCFVelocityScale;          if (ccvalue < pDimRgn->VCFVelocityScale) ccvalue = pDimRgn->VCFVelocityScale;
723          float cutoff = CutoffBase * float(ccvalue) * 0.00787402f; // (1 / 127)          float cutoff = CutoffBase * float(ccvalue) * 0.00787402f; // (1 / 127)
724          if (cutoff > 1.0) cutoff = 1.0;          if (cutoff > 1.0) cutoff = 1.0;
725          cutoff = exp(cutoff * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MIN - CONFIG_FILTER_CUTOFF_MIN;          cutoff = (cutoff < 0.5 ? cutoff * 4826 - 1 : cutoff * 5715 - 449);
726          VCFCutoffCtrl.fvalue = cutoff; // needed for initialization of fFinalCutoff next time          if (cutoff < 1.0) cutoff = 1.0;
727    
728            VCFCutoffCtrl.fvalue = cutoff - 1.0; // needed for initialization of fFinalCutoff next time
729          fFinalCutoff = cutoff;          fFinalCutoff = cutoff;
730      }      }
731    
# Line 738  namespace LinuxSampler { namespace gig { Line 748  namespace LinuxSampler { namespace gig {
748       *  @param Skip    - number of sample points to skip in output buffer       *  @param Skip    - number of sample points to skip in output buffer
749       */       */
750      void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {      void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
751            finalSynthesisParameters.pOutLeft  = &pEngineChannel->pOutputLeft[Skip];
752            finalSynthesisParameters.pOutRight = &pEngineChannel->pOutputRight[Skip];
753            finalSynthesisParameters.pSrc      = pSrc;
754    
755          RTList<Event>::Iterator itCCEvent = pEngineChannel->pEvents->first();          RTList<Event>::Iterator itCCEvent = pEngineChannel->pEvents->first();
756          RTList<Event>::Iterator itNoteEvent = pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents->first();          RTList<Event>::Iterator itNoteEvent = pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents->first();
757    
# Line 746  namespace LinuxSampler { namespace gig { Line 760  namespace LinuxSampler { namespace gig {
760              while (itNoteEvent && itNoteEvent->FragmentPos() <= Skip) ++itNoteEvent;              while (itNoteEvent && itNoteEvent->FragmentPos() <= Skip) ++itNoteEvent;
761          }          }
762    
763            uint killPos;
764            if (itKillEvent) killPos = RTMath::Min(itKillEvent->FragmentPos(), pEngine->MaxFadeOutPos);
765    
766            float fFinalPanLeft = PanLeft * pEngineChannel->GlobalPanLeft;
767            float fFinalPanRight = PanRight * pEngineChannel->GlobalPanRight;
768    
769          uint i = Skip;          uint i = Skip;
770          while (i < Samples) {          while (i < Samples) {
771              int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples);              int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples);
772    
773              // initialize all final synthesis parameters              // initialize all final synthesis parameters
774              fFinalPitch = PitchBase * PitchBend;              finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend;
775              #if CONFIG_PROCESS_MUTED_CHANNELS              fFinalVolume    = getVolume();
             fFinalVolume = this->Volume * this->CrossfadeVolume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume);  
             #else  
             fFinalVolume = this->Volume * this->CrossfadeVolume * pEngineChannel->GlobalVolume;  
             #endif  
776              fFinalCutoff    = VCFCutoffCtrl.fvalue;              fFinalCutoff    = VCFCutoffCtrl.fvalue;
777              fFinalResonance = VCFResonanceCtrl.fvalue;              fFinalResonance = VCFResonanceCtrl.fvalue;
778    
# Line 766  namespace LinuxSampler { namespace gig { Line 782  namespace LinuxSampler { namespace gig {
782              // process transition events (note on, note off & sustain pedal)              // process transition events (note on, note off & sustain pedal)
783              processTransitionEvents(itNoteEvent, iSubFragmentEnd);              processTransitionEvents(itNoteEvent, iSubFragmentEnd);
784    
785                // if the voice was killed in this subfragment switch EG1 to fade out stage
786                if (itKillEvent && killPos <= iSubFragmentEnd) {
787                    EG1.enterFadeOutStage();
788                    itKillEvent = Pool<Event>::Iterator();
789                }
790    
791              // process envelope generators              // process envelope generators
792              switch (EG1.getSegmentType()) {              switch (EG1.getSegmentType()) {
793                  case EGADSR::segment_lin:                  case EGADSR::segment_lin:
# Line 789  namespace LinuxSampler { namespace gig { Line 811  namespace LinuxSampler { namespace gig {
811                      fFinalCutoff *= EG2.getLevel();                      fFinalCutoff *= EG2.getLevel();
812                      break; // noop                      break; // noop
813              }              }
814              fFinalPitch *= RTMath::CentsToFreqRatio(EG3.render());              if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();
815    
816              // process low frequency oscillators              // process low frequency oscillators
817              if (bLFO1Enabled) fFinalVolume *= pLFO1->render();              if (bLFO1Enabled) fFinalVolume *= pLFO1->render();
818              if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();              if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();
819              if (bLFO3Enabled) fFinalPitch  *= RTMath::CentsToFreqRatio(pLFO3->render());              if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
820    
821              // if filter enabled then update filter coefficients              // if filter enabled then update filter coefficients
822              if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) {              if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) {
823                  FilterLeft.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate);                  finalSynthesisParameters.filterLeft.SetParameters(fFinalCutoff + 1.0, fFinalResonance, pEngine->SampleRate);
824                  FilterRight.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate);                  finalSynthesisParameters.filterRight.SetParameters(fFinalCutoff + 1.0, fFinalResonance, pEngine->SampleRate);
825              }              }
826    
827              // how many steps do we calculate for this next subfragment              // do we need resampling?
828              const int steps = iSubFragmentEnd - i;              const float __PLUS_ONE_CENT  = 1.000577789506554859250142541782224725466f;
829                const float __MINUS_ONE_CENT = 0.9994225441413807496009516495583113737666f;
830                const bool bResamplingRequired = !(finalSynthesisParameters.fFinalPitch <= __PLUS_ONE_CENT &&
831                                                   finalSynthesisParameters.fFinalPitch >= __MINUS_ONE_CENT);
832                SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, bResamplingRequired);
833    
834                // prepare final synthesis parameters structure
835                finalSynthesisParameters.uiToGo            = iSubFragmentEnd - i;
836    #ifdef CONFIG_INTERPOLATE_VOLUME
837                finalSynthesisParameters.fFinalVolumeDeltaLeft  =
838                    (fFinalVolume * fFinalPanLeft - finalSynthesisParameters.fFinalVolumeLeft) / finalSynthesisParameters.uiToGo;
839                finalSynthesisParameters.fFinalVolumeDeltaRight =
840                    (fFinalVolume * fFinalPanRight - finalSynthesisParameters.fFinalVolumeRight) / finalSynthesisParameters.uiToGo;
841    #else
842                finalSynthesisParameters.fFinalVolumeLeft  = fFinalVolume * fFinalPanLeft;
843                finalSynthesisParameters.fFinalVolumeRight = fFinalVolume * fFinalPanRight;
844    #endif
845                // render audio for one subfragment
846                RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
847    
848              // select the appropriate synthesis mode              // stop the rendering if volume EG is finished
849              SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, fFinalPitch != 1.0f);              if (EG1.getSegmentType() == EGADSR::segment_end) break;
850    
851              // render audio for one subfragment              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
             RunSynthesisFunction(SynthesisMode, *this, iSubFragmentEnd, pSrc, i);  
852    
853              // increment envelopes' positions              // increment envelopes' positions
854              if (EG1.active()) {              if (EG1.active()) {
855    
856                    // 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
857                    if (pSample->Loops && Pos <= pSample->LoopStart && pSample->LoopStart < newPos) {
858                        EG1.update(EGADSR::event_hold_end, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
859                    }
860    
861                  EG1.increment(1);                  EG1.increment(1);
862                  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);
863              }              }
864              if (EG2.active()) {              if (EG2.active()) {
865                  EG2.increment(1);                  EG2.increment(1);
866                  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);
867              }              }
868              EG3.increment(1);              EG3.increment(1);
869              if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached              if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
870    
871                Pos = newPos;
872              i = iSubFragmentEnd;              i = iSubFragmentEnd;
873          }          }
874      }      }
875    
876        /** @brief Update current portamento position.
877         *
878         * Will be called when portamento mode is enabled to get the final
879         * portamento position of this active voice from where the next voice(s)
880         * might continue to slide on.
881         *
882         * @param itNoteOffEvent - event which causes this voice to die soon
883         */
884        void Voice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
885            const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
886            pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
887        }
888    
889      /**      /**
890       *  Immediately kill the voice. This method should not be used to kill       *  Immediately kill the voice. This method should not be used to kill
891       *  a normal, active voice, because it doesn't take care of things like       *  a normal, active voice, because it doesn't take care of things like

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

  ViewVC Help
Powered by ViewVC