/[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 768 by persson, Fri Sep 2 20:11:55 2005 UTC revision 783 by persson, Sun Oct 2 14:40:52 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 547  namespace LinuxSampler { namespace gig { Line 551  namespace LinuxSampler { namespace gig {
551    
552                      if (DiskVoice) {                      if (DiskVoice) {
553                          // check if we reached the allowed limit of the sample RAM cache                          // check if we reached the allowed limit of the sample RAM cache
554                          if (Pos > MaxRAMPos) {                          if (finalSynthesisParameters.dPos > MaxRAMPos) {
555                              dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos));                              dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", finalSynthesisParameters.dPos));
556                              this->PlaybackState = playback_state_disk;                              this->PlaybackState = playback_state_disk;
557                          }                          }
558                      }                      } else if (finalSynthesisParameters.dPos >= pSample->GetCache().Size / pSample->FrameSize) {
                     else if (Pos >= pSample->GetCache().Size / pSample->FrameSize) {  
559                          this->PlaybackState = playback_state_end;                          this->PlaybackState = playback_state_end;
560                      }                      }
561                  }                  }
# Line 567  namespace LinuxSampler { namespace gig { Line 570  namespace LinuxSampler { namespace gig {
570                              KillImmediately();                              KillImmediately();
571                              return;                              return;
572                          }                          }
573                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(Pos) - MaxRAMPos));                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(finalSynthesisParameters.dPos) - MaxRAMPos));
574                          Pos -= int(Pos);                          finalSynthesisParameters.dPos -= int(finalSynthesisParameters.dPos);
575                          RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet                          RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet
576                      }                      }
577    
# Line 589  namespace LinuxSampler { namespace gig { Line 592  namespace LinuxSampler { namespace gig {
592                      // render current audio fragment                      // render current audio fragment
593                      Synthesize(Samples, ptr, Delay);                      Synthesize(Samples, ptr, Delay);
594    
595                      const int iPos = (int) Pos;                      const int iPos = (int) finalSynthesisParameters.dPos;
596                      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
597                      DiskStreamRef.pStream->IncrementReadPos(readSampleWords);                      DiskStreamRef.pStream->IncrementReadPos(readSampleWords);
598                      Pos -= iPos; // just keep fractional part of Pos                      finalSynthesisParameters.dPos -= iPos; // just keep fractional part of playback position
599    
600                      // 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
601                      if (RealSampleWordsLeftToRead >= 0) {                      if (RealSampleWordsLeftToRead >= 0) {
# Line 607  namespace LinuxSampler { namespace gig { Line 610  namespace LinuxSampler { namespace gig {
610                  break;                  break;
611          }          }
612    
         // Reset synthesis event lists  
         pEngineChannel->pEvents->clear();  
   
613          // Reset delay          // Reset delay
614          Delay = 0;          Delay = 0;
615    
# Line 624  namespace LinuxSampler { namespace gig { Line 624  namespace LinuxSampler { namespace gig {
624       *  suspended / not running.       *  suspended / not running.
625       */       */
626      void Voice::Reset() {      void Voice::Reset() {
627          FilterLeft.Reset();          finalSynthesisParameters.filterLeft.Reset();
628          FilterRight.Reset();          finalSynthesisParameters.filterRight.Reset();
629          DiskStreamRef.pStream = NULL;          DiskStreamRef.pStream = NULL;
630          DiskStreamRef.hStream = 0;          DiskStreamRef.hStream = 0;
631          DiskStreamRef.State   = Stream::state_unused;          DiskStreamRef.State   = Stream::state_unused;
# Line 645  namespace LinuxSampler { namespace gig { Line 645  namespace LinuxSampler { namespace gig {
645      void Voice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {      void Voice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {
646          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
647              if (itEvent->Type == Event::type_release) {              if (itEvent->Type == Event::type_release) {
648                  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);
649                  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);
650              } else if (itEvent->Type == Event::type_cancel_release) {              } else if (itEvent->Type == Event::type_cancel_release) {
651                  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);
652                  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);
653              }              }
654          }          }
655      }      }
# Line 692  namespace LinuxSampler { namespace gig { Line 692  namespace LinuxSampler { namespace gig {
692    
693      void Voice::processPitchEvent(RTList<Event>::Iterator& itEvent) {      void Voice::processPitchEvent(RTList<Event>::Iterator& itEvent) {
694          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
695          fFinalPitch *= pitch;          finalSynthesisParameters.fFinalPitch *= pitch;
696            PitchBend = pitch;
697      }      }
698    
699      void Voice::processCrossFadeEvent(RTList<Event>::Iterator& itEvent) {      void Voice::processCrossFadeEvent(RTList<Event>::Iterator& itEvent) {
# Line 737  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 750  namespace LinuxSampler { namespace gig { Line 755  namespace LinuxSampler { namespace gig {
755              int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples);              int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples);
756    
757              // initialize all final synthesis parameters              // initialize all final synthesis parameters
758              fFinalPitch = PitchBase * PitchBend;              finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend;
759              #if CONFIG_PROCESS_MUTED_CHANNELS              #if CONFIG_PROCESS_MUTED_CHANNELS
760              fFinalVolume = this->Volume * this->CrossfadeVolume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume);              fFinalVolume = this->Volume * this->CrossfadeVolume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume);
761              #else              #else
# Line 788  namespace LinuxSampler { namespace gig { Line 793  namespace LinuxSampler { namespace gig {
793                      fFinalCutoff *= EG2.getLevel();                      fFinalCutoff *= EG2.getLevel();
794                      break; // noop                      break; // noop
795              }              }
796              fFinalPitch *= RTMath::CentsToFreqRatio(EG3.render());              if (EG3.active()) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(EG3.render());
797    
798              // process low frequency oscillators              // process low frequency oscillators
799              if (bLFO1Enabled) fFinalVolume *= pLFO1->render();              if (bLFO1Enabled) fFinalVolume *= pLFO1->render();
800              if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();              if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();
801              if (bLFO3Enabled) fFinalPitch  *= RTMath::CentsToFreqRatio(pLFO3->render());              if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
802    
803              // if filter enabled then update filter coefficients              // if filter enabled then update filter coefficients
804              if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) {              if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) {
805                  FilterLeft.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate);                  finalSynthesisParameters.filterLeft.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate);
806                  FilterRight.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate);                  finalSynthesisParameters.filterRight.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate);
807              }              }
808    
809              // how many steps do we calculate for this next subfragment              // do we need resampling?
810              const int steps = iSubFragmentEnd - i;              const float __PLUS_ONE_CENT  = 1.000577789506554859250142541782224725466f;
811                const float __MINUS_ONE_CENT = 0.9994225441413807496009516495583113737666f;
812              // select the appropriate synthesis mode              const bool bResamplingRequired = !(finalSynthesisParameters.fFinalPitch <= __PLUS_ONE_CENT &&
813              SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, fFinalPitch != 1.0f);                                                 finalSynthesisParameters.fFinalPitch >= __MINUS_ONE_CENT);
814                SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, bResamplingRequired);
815    
816                // prepare final synthesis parameters structure
817                finalSynthesisParameters.fFinalVolumeLeft  = fFinalVolume * PanLeft;
818                finalSynthesisParameters.fFinalVolumeRight = fFinalVolume * PanRight;
819                finalSynthesisParameters.uiToGo            = iSubFragmentEnd - i;
820    
821              // render audio for one subfragment              // render audio for one subfragment
822              RunSynthesisFunction(SynthesisMode, *this, iSubFragmentEnd, pSrc, i);              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
823    
824                const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
825    
826              // increment envelopes' positions              // increment envelopes' positions
827              if (EG1.active()) {              if (EG1.active()) {
828    
829                    // 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
830                    if (pSample->Loops && Pos <= pSample->LoopStart && pSample->LoopStart < newPos) {
831                        EG1.update(EGADSR::event_hold_end, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
832                    }
833    
834                  EG1.increment(1);                  EG1.increment(1);
835                  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);
836              }              }
837              if (EG2.active()) {              if (EG2.active()) {
838                  EG2.increment(1);                  EG2.increment(1);
839                  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);
840              }              }
841              EG3.increment(1);              EG3.increment(1);
842              if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached              if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
843    
844                Pos = newPos;
845              i = iSubFragmentEnd;              i = iSubFragmentEnd;
846          }          }
847      }      }

Legend:
Removed from v.768  
changed lines
  Added in v.783

  ViewVC Help
Powered by ViewVC