/[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 783 by persson, Sun Oct 2 14:40:52 2005 UTC revision 830 by persson, Sun Jan 15 18:23:11 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 150  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;  
                 loop.uiTotalCycles = pSample->LoopPlayCount;  
                 loop.uiCyclesLeft  = pSample->LoopPlayCount;  
                 loop.uiStart       = pSample->LoopStart;  
                 loop.uiEnd         = pSample->LoopEnd;  
                 loop.uiSize        = pSample->LoopSize;  
             }  
             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 169  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;  
                 loop.uiCyclesLeft = 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 229  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;
229            finalSynthesisParameters.fFinalVolumeRight = fFinalVolume * PanRight;
230    
231    
232          // setup EG 2 (VCF Cutoff EG)          // setup EG 2 (VCF Cutoff EG)
233          {          {
# Line 270  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 494  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 501  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 698  namespace LinuxSampler { namespace gig { Line 703  namespace LinuxSampler { namespace gig {
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 750  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          uint i = Skip;          uint i = Skip;
767          while (i < Samples) {          while (i < Samples) {
768              int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples);              int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples);
769    
770              // initialize all final synthesis parameters              // initialize all final synthesis parameters
771              finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend;              finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend;
772              #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  
773              fFinalCutoff    = VCFCutoffCtrl.fvalue;              fFinalCutoff    = VCFCutoffCtrl.fvalue;
774              fFinalResonance = VCFResonanceCtrl.fvalue;              fFinalResonance = VCFResonanceCtrl.fvalue;
775    
# Line 770  namespace LinuxSampler { namespace gig { Line 779  namespace LinuxSampler { namespace gig {
779              // process transition events (note on, note off & sustain pedal)              // process transition events (note on, note off & sustain pedal)
780              processTransitionEvents(itNoteEvent, iSubFragmentEnd);              processTransitionEvents(itNoteEvent, iSubFragmentEnd);
781    
782                // if the voice was killed in this subfragment switch EG1 to fade out stage
783                if (itKillEvent && killPos <= iSubFragmentEnd) {
784                    EG1.enterFadeOutStage();
785                    itKillEvent = Pool<Event>::Iterator();
786                }
787    
788              // process envelope generators              // process envelope generators
789              switch (EG1.getSegmentType()) {              switch (EG1.getSegmentType()) {
790                  case EGADSR::segment_lin:                  case EGADSR::segment_lin:
# Line 793  namespace LinuxSampler { namespace gig { Line 808  namespace LinuxSampler { namespace gig {
808                      fFinalCutoff *= EG2.getLevel();                      fFinalCutoff *= EG2.getLevel();
809                      break; // noop                      break; // noop
810              }              }
811              if (EG3.active()) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(EG3.render());              if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();
812    
813              // process low frequency oscillators              // process low frequency oscillators
814              if (bLFO1Enabled) fFinalVolume *= pLFO1->render();              if (bLFO1Enabled) fFinalVolume *= pLFO1->render();
# Line 802  namespace LinuxSampler { namespace gig { Line 817  namespace LinuxSampler { namespace gig {
817    
818              // if filter enabled then update filter coefficients              // if filter enabled then update filter coefficients
819              if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) {              if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) {
820                  finalSynthesisParameters.filterLeft.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate);                  finalSynthesisParameters.filterLeft.SetParameters(fFinalCutoff + 1.0, fFinalResonance, pEngine->SampleRate);
821                  finalSynthesisParameters.filterRight.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate);                  finalSynthesisParameters.filterRight.SetParameters(fFinalCutoff + 1.0, fFinalResonance, pEngine->SampleRate);
822              }              }
823    
824              // do we need resampling?              // do we need resampling?
# Line 814  namespace LinuxSampler { namespace gig { Line 829  namespace LinuxSampler { namespace gig {
829              SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, bResamplingRequired);              SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, bResamplingRequired);
830    
831              // prepare final synthesis parameters structure              // prepare final synthesis parameters structure
832                finalSynthesisParameters.uiToGo            = iSubFragmentEnd - i;
833    #ifdef CONFIG_INTERPOLATE_VOLUME
834                finalSynthesisParameters.fFinalVolumeDeltaLeft  =
835                    (fFinalVolume * PanLeft - finalSynthesisParameters.fFinalVolumeLeft) / finalSynthesisParameters.uiToGo;
836                finalSynthesisParameters.fFinalVolumeDeltaRight =
837                    (fFinalVolume * PanRight - finalSynthesisParameters.fFinalVolumeRight) / finalSynthesisParameters.uiToGo;
838    #else
839              finalSynthesisParameters.fFinalVolumeLeft  = fFinalVolume * PanLeft;              finalSynthesisParameters.fFinalVolumeLeft  = fFinalVolume * PanLeft;
840              finalSynthesisParameters.fFinalVolumeRight = fFinalVolume * PanRight;              finalSynthesisParameters.fFinalVolumeRight = fFinalVolume * PanRight;
841              finalSynthesisParameters.uiToGo            = iSubFragmentEnd - i;  #endif
   
842              // render audio for one subfragment              // render audio for one subfragment
843              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);              RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
844    
845                // stop the rendering if volume EG is finished
846                if (EG1.getSegmentType() == EGADSR::segment_end) break;
847    
848              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
849    
850              // increment envelopes' positions              // increment envelopes' positions
# Line 846  namespace LinuxSampler { namespace gig { Line 870  namespace LinuxSampler { namespace gig {
870          }          }
871      }      }
872    
873        /** @brief Update current portamento position.
874         *
875         * Will be called when portamento mode is enabled to get the final
876         * portamento position of this active voice from where the next voice(s)
877         * might continue to slide on.
878         *
879         * @param itNoteOffEvent - event which causes this voice to die soon
880         */
881        void Voice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
882            const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
883            pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
884        }
885    
886      /**      /**
887       *  Immediately kill the voice. This method should not be used to kill       *  Immediately kill the voice. This method should not be used to kill
888       *  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.783  
changed lines
  Added in v.830

  ViewVC Help
Powered by ViewVC