/[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 287 by schoenebeck, Sat Oct 16 17:38:03 2004 UTC revision 354 by schoenebeck, Sat Jan 29 15:17:59 2005 UTC
# Line 22  Line 22 
22    
23  #include "EGADSR.h"  #include "EGADSR.h"
24  #include "Manipulator.h"  #include "Manipulator.h"
25    #include "../../common/Features.h"
26    #include "Synthesizer.h"
27    
28  #include "Voice.h"  #include "Voice.h"
29    
# Line 56  namespace LinuxSampler { namespace gig { Line 58  namespace LinuxSampler { namespace gig {
58          pLFO2  = NULL;          pLFO2  = NULL;
59          pLFO3  = NULL;          pLFO3  = NULL;
60          KeyGroup = 0;          KeyGroup = 0;
61            SynthesisMode = 0; //Set all mode bits to 0 first
62    
63            // select synthesis implementation (currently either pure C++ or MMX+SSE(1))
64            SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, Features::supportsMMX() && Features::supportsSSE());
65            SYNTHESIS_MODE_SET_PROFILING(SynthesisMode, true);
66      }      }
67    
68      Voice::~Voice() {      Voice::~Voice() {
# Line 109  namespace LinuxSampler { namespace gig { Line 116  namespace LinuxSampler { namespace gig {
116       *  @param iLayer              - layer number this voice refers to (only if this is a layered sound of course)       *  @param iLayer              - layer number this voice refers to (only if this is a layered sound of course)
117       *  @param ReleaseTriggerVoice - if this new voice is a release trigger voice (optional, default = false)       *  @param ReleaseTriggerVoice - if this new voice is a release trigger voice (optional, default = false)
118       *  @param VoiceStealing       - wether the voice is allowed to steal voices for further subvoices       *  @param VoiceStealing       - wether the voice is allowed to steal voices for further subvoices
119       *  @returns 0 on success, a value < 0 if something failed       *  @returns 0 on success, a value < 0 if the voice wasn't triggered
120         *           (either due to an error or e.g. because no region is
121         *           defined for the given key)
122       */       */
123      int Voice::Trigger(Pool<Event>::Iterator& itNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing) {      int Voice::Trigger(Pool<Event>::Iterator& itNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing) {
124          if (!pInstrument) {          if (!pInstrument) {
125             dmsg(1,("voice::trigger: !pInstrument\n"));             dmsg(1,("voice::trigger: !pInstrument\n"));
126             exit(EXIT_FAILURE);             exit(EXIT_FAILURE);
127          }          }
128            if (itNoteOnEvent->FragmentPos() > pEngine->MaxSamplesPerCycle) { // FIXME: should be removed before the final release (purpose: just a sanity check for debugging)
129                dmsg(1,("Voice::Trigger(): ERROR, TriggerDelay > Totalsamples\n"));
130            }
131    
132          Type            = type_normal;          Type            = type_normal;
133          MIDIKey         = itNoteOnEvent->Param.Note.Key;          MIDIKey         = itNoteOnEvent->Param.Note.Key;
# Line 127  namespace LinuxSampler { namespace gig { Line 139  namespace LinuxSampler { namespace gig {
139          itChildVoice    = Pool<Voice>::Iterator();          itChildVoice    = Pool<Voice>::Iterator();
140    
141          if (!pRegion) {          if (!pRegion) {
142              std::cerr << "gig::Voice: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush;              dmsg(4, ("gig::Voice: No Region defined for MIDI key %d\n", MIDIKey));
             KillImmediately();  
143              return -1;              return -1;
144          }          }
145    
# Line 136  namespace LinuxSampler { namespace gig { Line 147  namespace LinuxSampler { namespace gig {
147    
148          // get current dimension values to select the right dimension region          // get current dimension values to select the right dimension region
149          //FIXME: controller values for selecting the dimension region here are currently not sample accurate          //FIXME: controller values for selecting the dimension region here are currently not sample accurate
150          uint DimValues[5] = {0,0,0,0,0};          uint DimValues[8] = { 0 };
151          for (int i = pRegion->Dimensions - 1; i >= 0; i--) {          for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
152              switch (pRegion->pDimensionDefinitions[i].dimension) {              switch (pRegion->pDimensionDefinitions[i].dimension) {
153                  case ::gig::dimension_samplechannel:                  case ::gig::dimension_samplechannel:
# Line 160  namespace LinuxSampler { namespace gig { Line 171  namespace LinuxSampler { namespace gig {
171                      DimValues[i] = (uint) ReleaseTriggerVoice;                      DimValues[i] = (uint) ReleaseTriggerVoice;
172                      break;                      break;
173                  case ::gig::dimension_keyboard:                  case ::gig::dimension_keyboard:
174                      DimValues[i] = (uint) itNoteOnEvent->Param.Note.Key;                      DimValues[i] = (uint) pEngine->CurrentKeyDimension;
175                      break;                      break;
176                  case ::gig::dimension_modwheel:                  case ::gig::dimension_modwheel:
177                      DimValues[i] = pEngine->ControllerTable[1];                      DimValues[i] = pEngine->ControllerTable[1];
# Line 238  namespace LinuxSampler { namespace gig { Line 249  namespace LinuxSampler { namespace gig {
249                      std::cerr << "gig::Voice::Trigger() Error: Unknown dimension\n" << std::flush;                      std::cerr << "gig::Voice::Trigger() Error: Unknown dimension\n" << std::flush;
250              }              }
251          }          }
252          pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);          pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
253    
254            pSample = pDimRgn->pSample; // sample won't change until the voice is finished
255            if (!pSample || !pSample->SamplesTotal) return -1; // no need to continue if sample is silent
256    
257            // select channel mode (mono or stereo)
258            SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2);
259    
260          // get starting crossfade volume level          // get starting crossfade volume level
261          switch (pDimRgn->AttenuationController.type) {          switch (pDimRgn->AttenuationController.type) {
# Line 259  namespace LinuxSampler { namespace gig { Line 276  namespace LinuxSampler { namespace gig {
276          PanLeft  = 1.0f - float(RTMath::Max(pDimRgn->Pan, 0)) /  63.0f;          PanLeft  = 1.0f - float(RTMath::Max(pDimRgn->Pan, 0)) /  63.0f;
277          PanRight = 1.0f - float(RTMath::Min(pDimRgn->Pan, 0)) / -64.0f;          PanRight = 1.0f - float(RTMath::Min(pDimRgn->Pan, 0)) / -64.0f;
278    
         pSample = pDimRgn->pSample; // sample won't change until the voice is finished  
   
279          Pos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)          Pos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
280    
281          // 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
# Line 297  namespace LinuxSampler { namespace gig { Line 312  namespace LinuxSampler { namespace gig {
312    
313          // calculate initial pitch value          // calculate initial pitch value
314          {          {
315              double pitchbasecents = pDimRgn->FineTune * 10 + (int) pEngine->ScaleTuning[MIDIKey % 12];              double pitchbasecents = pDimRgn->FineTune + (int) pEngine->ScaleTuning[MIDIKey % 12];
316              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;
317              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate()));              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate()));
318              this->PitchBend = RTMath::CentsToFreqRatio(((double) PitchBend / 8192.0) * 200.0); // pitchbend wheel +-2 semitones = 200 cents              this->PitchBend = RTMath::CentsToFreqRatio(((double) PitchBend / 8192.0) * 200.0); // pitchbend wheel +-2 semitones = 200 cents
319          }          }
320    
   
321          Volume = pDimRgn->GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity) / 32768.0f; // we downscale by 32768 to convert from int16 value range to DSP value range (which is -1.0..1.0)          Volume = pDimRgn->GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity) / 32768.0f; // we downscale by 32768 to convert from int16 value range to DSP value range (which is -1.0..1.0)
322    
   
323          // setup EG 1 (VCA EG)          // setup EG 1 (VCA EG)
324          {          {
325              // get current value of EG1 controller              // get current value of EG1 controller
# Line 345  namespace LinuxSampler { namespace gig { Line 358  namespace LinuxSampler { namespace gig {
358          }          }
359    
360    
     #if ENABLE_FILTER  
361          // setup EG 2 (VCF Cutoff EG)          // setup EG 2 (VCF Cutoff EG)
362          {          {
363              // get current value of EG2 controller              // get current value of EG2 controller
# Line 382  namespace LinuxSampler { namespace gig { Line 394  namespace LinuxSampler { namespace gig {
394                            pDimRgn->EG2Release + eg2release,                            pDimRgn->EG2Release + eg2release,
395                            Delay);                            Delay);
396          }          }
     #endif // ENABLE_FILTER  
397    
398    
399          // setup EG 3 (VCO EG)          // setup EG 3 (VCO EG)
# Line 429  namespace LinuxSampler { namespace gig { Line 440  namespace LinuxSampler { namespace gig {
440                            Delay);                            Delay);
441          }          }
442    
443      #if ENABLE_FILTER  
444          // setup LFO 2 (VCF Cutoff LFO)          // setup LFO 2 (VCF Cutoff LFO)
445          {          {
446              uint16_t lfo2_internal_depth;              uint16_t lfo2_internal_depth;
# Line 466  namespace LinuxSampler { namespace gig { Line 477  namespace LinuxSampler { namespace gig {
477                            pEngine->SampleRate,                            pEngine->SampleRate,
478                            Delay);                            Delay);
479          }          }
480      #endif // ENABLE_FILTER  
481    
482          // setup LFO 3 (VCO LFO)          // setup LFO 3 (VCO LFO)
483          {          {
# Line 505  namespace LinuxSampler { namespace gig { Line 516  namespace LinuxSampler { namespace gig {
516                            Delay);                            Delay);
517          }          }
518    
519      #if ENABLE_FILTER  
520          #if FORCE_FILTER_USAGE          #if FORCE_FILTER_USAGE
521          FilterLeft.Enabled = FilterRight.Enabled = true;          SYNTHESIS_MODE_SET_FILTER(SynthesisMode, true);
522          #else // use filter only if instrument file told so          #else // use filter only if instrument file told so
523          FilterLeft.Enabled = FilterRight.Enabled = pDimRgn->VCFEnabled;          SYNTHESIS_MODE_SET_FILTER(SynthesisMode, pDimRgn->VCFEnabled);
524          #endif // FORCE_FILTER_USAGE          #endif // FORCE_FILTER_USAGE
525          if (pDimRgn->VCFEnabled) {          if (pDimRgn->VCFEnabled) {
526              #ifdef OVERRIDE_FILTER_CUTOFF_CTRL              #ifdef OVERRIDE_FILTER_CUTOFF_CTRL
# Line 599  namespace LinuxSampler { namespace gig { Line 610  namespace LinuxSampler { namespace gig {
610              VCFCutoffCtrl.fvalue    = cutoff - FILTER_CUTOFF_MIN;              VCFCutoffCtrl.fvalue    = cutoff - FILTER_CUTOFF_MIN;
611              VCFResonanceCtrl.fvalue = resonance;              VCFResonanceCtrl.fvalue = resonance;
612    
             FilterLeft.SetParameters(cutoff,  resonance, pEngine->SampleRate);  
             FilterRight.SetParameters(cutoff, resonance, pEngine->SampleRate);  
   
613              FilterUpdateCounter = -1;              FilterUpdateCounter = -1;
614          }          }
615          else {          else {
616              VCFCutoffCtrl.controller    = 0;              VCFCutoffCtrl.controller    = 0;
617              VCFResonanceCtrl.controller = 0;              VCFResonanceCtrl.controller = 0;
618          }          }
     #endif // ENABLE_FILTER  
619    
620          return 0; // success          return 0; // success
621      }      }
# Line 626  namespace LinuxSampler { namespace gig { Line 633  namespace LinuxSampler { namespace gig {
633       */       */
634      void Voice::Render(uint Samples) {      void Voice::Render(uint Samples) {
635    
636            // select default values for synthesis mode bits
637            SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, (PitchBase * PitchBend) != 1.0f);
638            SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, true);
639            SYNTHESIS_MODE_SET_LOOP(SynthesisMode, false);
640    
641          // Reset the synthesis parameter matrix          // Reset the synthesis parameter matrix
642    
643          pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngine->GlobalVolume);          pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngine->GlobalVolume);
644          pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase);          pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase);
     #if ENABLE_FILTER  
645          pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue);          pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue);
646          pEngine->ResetSynthesisParameters(Event::destination_vcfr, VCFResonanceCtrl.fvalue);          pEngine->ResetSynthesisParameters(Event::destination_vcfr, VCFResonanceCtrl.fvalue);
     #endif // ENABLE_FILTER  
   
647    
648          // Apply events to the synthesis parameter matrix          // Apply events to the synthesis parameter matrix
649          ProcessEvents(Samples);          ProcessEvents(Samples);
650    
   
651          // Let all modulators write their parameter changes to the synthesis parameter matrix for the current audio fragment          // Let all modulators write their parameter changes to the synthesis parameter matrix for the current audio fragment
652          pEG1->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend, itKillEvent);          pEG1->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend, itKillEvent);
     #if ENABLE_FILTER  
653          pEG2->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);          pEG2->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);
654      #endif // ENABLE_FILTER          if (pEG3->Process(Samples)) { // if pitch EG is active
655          pEG3->Process(Samples);              SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true);
656                SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false);
657            }
658          pLFO1->Process(Samples);          pLFO1->Process(Samples);
     #if ENABLE_FILTER  
659          pLFO2->Process(Samples);          pLFO2->Process(Samples);
660      #endif // ENABLE_FILTER          if (pLFO3->Process(Samples)) { // if pitch LFO modulation is active
661          pLFO3->Process(Samples);              SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true);
662                SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false);
663            }
     #if ENABLE_FILTER  
         CalculateBiquadParameters(Samples); // calculate the final biquad filter parameters  
     #endif // ENABLE_FILTER  
664    
665            if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode))
666                    CalculateBiquadParameters(Samples); // calculate the final biquad filter parameters
667    
668          switch (this->PlaybackState) {          switch (this->PlaybackState) {
669    
670              case playback_state_ram: {              case playback_state_ram: {
671                      if (RAMLoop) InterpolateAndLoop(Samples, (sample_t*) pSample->GetCache().pStart, Delay);                      if (RAMLoop) SYNTHESIS_MODE_SET_LOOP(SynthesisMode, true); // enable looping
672                      else         InterpolateNoLoop(Samples, (sample_t*) pSample->GetCache().pStart, Delay);  
673                        // render current fragment
674                        Synthesize(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
675    
676                      if (DiskVoice) {                      if (DiskVoice) {
677                          // check if we reached the allowed limit of the sample RAM cache                          // check if we reached the allowed limit of the sample RAM cache
678                          if (Pos > MaxRAMPos) {                          if (Pos > MaxRAMPos) {
# Line 684  namespace LinuxSampler { namespace gig { Line 695  namespace LinuxSampler { namespace gig {
695                              KillImmediately();                              KillImmediately();
696                              return;                              return;
697                          }                          }
698                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (RTMath::DoubleToInt(Pos) - MaxRAMPos));                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(Pos) - MaxRAMPos));
699                          Pos -= RTMath::DoubleToInt(Pos);                          Pos -= int(Pos);
700                            RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet
701                      }                      }
702    
703                        const int sampleWordsLeftToRead = DiskStreamRef.pStream->GetReadSpace();
704    
705                      // add silence sample at the end if we reached the end of the stream (for the interpolator)                      // add silence sample at the end if we reached the end of the stream (for the interpolator)
706                      if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels) {                      if (DiskStreamRef.State == Stream::state_end) {
707                          DiskStreamRef.pStream->WriteSilence((pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels);                          const int maxSampleWordsPerCycle = (pEngine->MaxSamplesPerCycle << MAX_PITCH) * pSample->Channels + 6; // +6 for the interpolator algorithm
708                          this->PlaybackState = playback_state_end;                          if (sampleWordsLeftToRead <= maxSampleWordsPerCycle) {
709                                // remember how many sample words there are before any silence has been added
710                                if (RealSampleWordsLeftToRead < 0) RealSampleWordsLeftToRead = sampleWordsLeftToRead;
711                                DiskStreamRef.pStream->WriteSilence(maxSampleWordsPerCycle - sampleWordsLeftToRead);
712                            }
713                      }                      }
714    
715                      sample_t* ptr = DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from                      sample_t* ptr = DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from
716                      InterpolateNoLoop(Samples, ptr, Delay);  
717                      DiskStreamRef.pStream->IncrementReadPos(RTMath::DoubleToInt(Pos) * pSample->Channels);                      // render current audio fragment
718                      Pos -= RTMath::DoubleToInt(Pos);                      Synthesize(Samples, ptr, Delay);
719    
720                        const int iPos = (int) Pos;
721                        const int readSampleWords = iPos * pSample->Channels; // amount of sample words actually been read
722                        DiskStreamRef.pStream->IncrementReadPos(readSampleWords);
723                        Pos -= iPos; // just keep fractional part of Pos
724    
725                        // change state of voice to 'end' if we really reached the end of the sample data
726                        if (RealSampleWordsLeftToRead >= 0) {
727                            RealSampleWordsLeftToRead -= readSampleWords;
728                            if (RealSampleWordsLeftToRead <= 0) this->PlaybackState = playback_state_end;
729                        }
730                  }                  }
731                  break;                  break;
732    
# Line 706  namespace LinuxSampler { namespace gig { Line 735  namespace LinuxSampler { namespace gig {
735                  break;                  break;
736          }          }
737    
   
738          // Reset synthesis event lists (except VCO, as VCO events apply channel wide currently)          // Reset synthesis event lists (except VCO, as VCO events apply channel wide currently)
739          pEngine->pSynthesisEvents[Event::destination_vca]->clear();          pEngine->pSynthesisEvents[Event::destination_vca]->clear();
     #if ENABLE_FILTER  
740          pEngine->pSynthesisEvents[Event::destination_vcfc]->clear();          pEngine->pSynthesisEvents[Event::destination_vcfc]->clear();
741          pEngine->pSynthesisEvents[Event::destination_vcfr]->clear();          pEngine->pSynthesisEvents[Event::destination_vcfr]->clear();
     #endif // ENABLE_FILTER  
742    
743          // Reset delay          // Reset delay
744          Delay = 0;          Delay = 0;
# Line 731  namespace LinuxSampler { namespace gig { Line 757  namespace LinuxSampler { namespace gig {
757          pLFO1->Reset();          pLFO1->Reset();
758          pLFO2->Reset();          pLFO2->Reset();
759          pLFO3->Reset();          pLFO3->Reset();
760            FilterLeft.Reset();
761            FilterRight.Reset();
762          DiskStreamRef.pStream = NULL;          DiskStreamRef.pStream = NULL;
763          DiskStreamRef.hStream = 0;          DiskStreamRef.hStream = 0;
764          DiskStreamRef.State   = Stream::state_unused;          DiskStreamRef.State   = Stream::state_unused;
# Line 756  namespace LinuxSampler { namespace gig { Line 784  namespace LinuxSampler { namespace gig {
784          }          }
785          while (itCCEvent) {          while (itCCEvent) {
786              if (itCCEvent->Param.CC.Controller) { // if valid MIDI controller              if (itCCEvent->Param.CC.Controller) { // if valid MIDI controller
                 #if ENABLE_FILTER  
787                  if (itCCEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {                  if (itCCEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {
788                      *pEngine->pSynthesisEvents[Event::destination_vcfc]->allocAppend() = *itCCEvent;                      *pEngine->pSynthesisEvents[Event::destination_vcfc]->allocAppend() = *itCCEvent;
789                  }                  }
790                  if (itCCEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {                  if (itCCEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
791                      *pEngine->pSynthesisEvents[Event::destination_vcfr]->allocAppend() = *itCCEvent;                      *pEngine->pSynthesisEvents[Event::destination_vcfr]->allocAppend() = *itCCEvent;
792                  }                  }
                 #endif // ENABLE_FILTER  
793                  if (itCCEvent->Param.CC.Controller == pLFO1->ExtController) {                  if (itCCEvent->Param.CC.Controller == pLFO1->ExtController) {
794                      pLFO1->SendEvent(itCCEvent);                      pLFO1->SendEvent(itCCEvent);
795                  }                  }
                 #if ENABLE_FILTER  
796                  if (itCCEvent->Param.CC.Controller == pLFO2->ExtController) {                  if (itCCEvent->Param.CC.Controller == pLFO2->ExtController) {
797                      pLFO2->SendEvent(itCCEvent);                      pLFO2->SendEvent(itCCEvent);
798                  }                  }
                 #endif // ENABLE_FILTER  
799                  if (itCCEvent->Param.CC.Controller == pLFO3->ExtController) {                  if (itCCEvent->Param.CC.Controller == pLFO3->ExtController) {
800                      pLFO3->SendEvent(itCCEvent);                      pLFO3->SendEvent(itCCEvent);
801                  }                  }
# Line 816  namespace LinuxSampler { namespace gig { Line 840  namespace LinuxSampler { namespace gig {
840    
841                  itVCOEvent = itNextVCOEvent;                  itVCOEvent = itNextVCOEvent;
842              }              }
843              if (!pVCOEventList->isEmpty()) this->PitchBend = pitch;              if (!pVCOEventList->isEmpty()) {
844                    this->PitchBend = pitch;
845                    SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true);
846                    SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false);
847                }
848          }          }
849    
850          // process volume / attenuation events (TODO: we only handle and _expect_ crossfade events here ATM !)          // process volume / attenuation events (TODO: we only handle and _expect_ crossfade events here ATM !)
# Line 848  namespace LinuxSampler { namespace gig { Line 876  namespace LinuxSampler { namespace gig {
876              if (!pVCAEventList->isEmpty()) this->CrossfadeVolume = crossfadevolume;              if (!pVCAEventList->isEmpty()) this->CrossfadeVolume = crossfadevolume;
877          }          }
878    
     #if ENABLE_FILTER  
879          // process filter cutoff events          // process filter cutoff events
880          {          {
881              RTList<Event>* pCutoffEventList = pEngine->pSynthesisEvents[Event::destination_vcfc];              RTList<Event>* pCutoffEventList = pEngine->pSynthesisEvents[Event::destination_vcfc];
# Line 905  namespace LinuxSampler { namespace gig { Line 932  namespace LinuxSampler { namespace gig {
932              }              }
933              if (!pResonanceEventList->isEmpty()) VCFResonanceCtrl.fvalue = pResonanceEventList->last()->Param.CC.Value * 0.00787f; // needed for initialization of parameter matrix next time              if (!pResonanceEventList->isEmpty()) VCFResonanceCtrl.fvalue = pResonanceEventList->last()->Param.CC.Value * 0.00787f; // needed for initialization of parameter matrix next time
934          }          }
     #endif // ENABLE_FILTER  
935      }      }
936    
     #if ENABLE_FILTER  
937      /**      /**
938       * Calculate all necessary, final biquad filter parameters.       * Calculate all necessary, final biquad filter parameters.
939       *       *
940       * @param Samples - number of samples to be rendered in this audio fragment cycle       * @param Samples - number of samples to be rendered in this audio fragment cycle
941       */       */
942      void Voice::CalculateBiquadParameters(uint Samples) {      void Voice::CalculateBiquadParameters(uint Samples) {
         if (!FilterLeft.Enabled) return;  
   
943          biquad_param_t bqbase;          biquad_param_t bqbase;
944          biquad_param_t bqmain;          biquad_param_t bqmain;
945          float prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][0];          float prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][0];
946          float prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][0];          float prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][0];
947          FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);          FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
948            FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
949          pEngine->pBasicFilterParameters[0] = bqbase;          pEngine->pBasicFilterParameters[0] = bqbase;
950          pEngine->pMainFilterParameters[0]  = bqmain;          pEngine->pMainFilterParameters[0]  = bqmain;
951    
952          float* bq;          float* bq;
953          for (int i = 1; i < Samples; i++) {          for (int i = 1; i < Samples; i++) {
954              // recalculate biquad parameters if cutoff or resonance differ from previous sample point              // recalculate biquad parameters if cutoff or resonance differ from previous sample point
955              if (!(i & FILTER_UPDATE_MASK)) if (pEngine->pSynthesisParameters[Event::destination_vcfr][i] != prev_res ||              if (!(i & FILTER_UPDATE_MASK)) {
956                                                 pEngine->pSynthesisParameters[Event::destination_vcfc][i] != prev_cutoff) {                  if (pEngine->pSynthesisParameters[Event::destination_vcfr][i] != prev_res ||
957                  prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i];                      pEngine->pSynthesisParameters[Event::destination_vcfc][i] != prev_cutoff)
958                  prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][i];                  {
959                  FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);                      prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i];
960                        prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][i];
961                        FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
962                        FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
963                    }
964              }              }
965    
966              //same as 'pEngine->pBasicFilterParameters[i] = bqbase;'              //same as 'pEngine->pBasicFilterParameters[i] = bqbase;'
967              bq    = (float*) &pEngine->pBasicFilterParameters[i];              bq    = (float*) &pEngine->pBasicFilterParameters[i];
968              bq[0] = bqbase.a1;              bq[0] = bqbase.b0;
969              bq[1] = bqbase.a2;              bq[1] = bqbase.b1;
970              bq[2] = bqbase.b0;              bq[2] = bqbase.b2;
971              bq[3] = bqbase.b1;              bq[3] = bqbase.a1;
972              bq[4] = bqbase.b2;              bq[4] = bqbase.a2;
973    
974              // same as 'pEngine->pMainFilterParameters[i] = bqmain;'              // same as 'pEngine->pMainFilterParameters[i] = bqmain;'
975              bq    = (float*) &pEngine->pMainFilterParameters[i];              bq    = (float*) &pEngine->pMainFilterParameters[i];
976              bq[0] = bqmain.a1;              bq[0] = bqmain.b0;
977              bq[1] = bqmain.a2;              bq[1] = bqmain.b1;
978              bq[2] = bqmain.b0;              bq[2] = bqmain.b2;
979              bq[3] = bqmain.b1;              bq[3] = bqmain.a1;
980              bq[4] = bqmain.b2;              bq[4] = bqmain.a2;
         }  
     }  
     #endif // ENABLE_FILTER  
   
     /**  
      *  Interpolates the input audio data (without looping).  
      *  
      *  @param Samples - number of sample points to be rendered in this audio  
      *                   fragment cycle  
      *  @param pSrc    - pointer to input sample data  
      *  @param Skip    - number of sample points to skip in output buffer  
      */  
     void Voice::InterpolateNoLoop(uint Samples, sample_t* pSrc, uint Skip) {  
         int i = Skip;  
   
         // FIXME: assuming either mono or stereo  
         if (this->pSample->Channels == 2) { // Stereo Sample  
             while (i < Samples) InterpolateStereo(pSrc, i);  
         }  
         else { // Mono Sample  
             while (i < Samples) InterpolateMono(pSrc, i);  
981          }          }
982      }      }
983    
984      /**      /**
985       *  Interpolates the input audio data, this method honors looping.       *  Synthesizes the current audio fragment for this voice.
986       *       *
987       *  @param Samples - number of sample points to be rendered in this audio       *  @param Samples - number of sample points to be rendered in this audio
988       *                   fragment cycle       *                   fragment cycle
989       *  @param pSrc    - pointer to input sample data       *  @param pSrc    - pointer to input sample data
990       *  @param Skip    - number of sample points to skip in output buffer       *  @param Skip    - number of sample points to skip in output buffer
991       */       */
992      void Voice::InterpolateAndLoop(uint Samples, sample_t* pSrc, uint Skip) {      void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
993          int i = Skip;          RunSynthesisFunction(SynthesisMode, *this, Samples, pSrc, Skip);
   
         // FIXME: assuming either mono or stereo  
         if (pSample->Channels == 2) { // Stereo Sample  
             if (pSample->LoopPlayCount) {  
                 // render loop (loop count limited)  
                 while (i < Samples && LoopCyclesLeft) {  
                     InterpolateStereo(pSrc, i);  
                     if (Pos > pSample->LoopEnd) {  
                         Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;  
                         LoopCyclesLeft--;  
                     }  
                 }  
                 // render on without loop  
                 while (i < Samples) InterpolateStereo(pSrc, i);  
             }  
             else { // render loop (endless loop)  
                 while (i < Samples) {  
                     InterpolateStereo(pSrc, i);  
                     if (Pos > pSample->LoopEnd) {  
                         Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);  
                     }  
                 }  
             }  
         }  
         else { // Mono Sample  
             if (pSample->LoopPlayCount) {  
                 // render loop (loop count limited)  
                 while (i < Samples && LoopCyclesLeft) {  
                     InterpolateMono(pSrc, i);  
                     if (Pos > pSample->LoopEnd) {  
                         Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;  
                         LoopCyclesLeft--;  
                     }  
                 }  
                 // render on without loop  
                 while (i < Samples) InterpolateMono(pSrc, i);  
             }  
             else { // render loop (endless loop)  
                 while (i < Samples) {  
                     InterpolateMono(pSrc, i);  
                     if (Pos > pSample->LoopEnd) {  
                         Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;  
                     }  
                 }  
             }  
         }  
994      }      }
995    
996      /**      /**

Legend:
Removed from v.287  
changed lines
  Added in v.354

  ViewVC Help
Powered by ViewVC