/[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 829 by schoenebeck, Sat Jan 14 14:07:47 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 270  namespace LinuxSampler { namespace gig { Line 264  namespace LinuxSampler { namespace gig {
264    
265          // setup EG 3 (VCO EG)          // setup EG 3 (VCO EG)
266          {          {
267            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
268            EG3.trigger(eg3depth, pDimRgn->EG3Attack, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);              bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;
269                float eg3depth = (bPortamento)
270                                     ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100)
271                                     : RTMath::CentsToFreqRatio(pDimRgn->EG3Depth);
272                float eg3time = (bPortamento)
273                                    ? pEngineChannel->PortamentoTime
274                                    : pDimRgn->EG3Attack;
275                EG3.trigger(eg3depth, eg3time, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
276                dmsg(5,("PortamentoPos=%f, depth=%f, time=%f\n", pEngineChannel->PortamentoPos, eg3depth, eg3time));
277          }          }
278    
279    
# Line 494  namespace LinuxSampler { namespace gig { Line 496  namespace LinuxSampler { namespace gig {
496              if (VCFCutoffCtrl.controller) {              if (VCFCutoffCtrl.controller) {
497                  cvalue = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller];                  cvalue = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller];
498                  if (pDimRgn->VCFCutoffControllerInvert) cvalue = 127 - cvalue;                  if (pDimRgn->VCFCutoffControllerInvert) cvalue = 127 - cvalue;
499                    // VCFVelocityScale in this case means Minimum cutoff
500                  if (cvalue < pDimRgn->VCFVelocityScale) cvalue = pDimRgn->VCFVelocityScale;                  if (cvalue < pDimRgn->VCFVelocityScale) cvalue = pDimRgn->VCFVelocityScale;
501              }              }
502              else {              else {
# Line 501  namespace LinuxSampler { namespace gig { Line 504  namespace LinuxSampler { namespace gig {
504              }              }
505              cutoff *= float(cvalue) * 0.00787402f; // (1 / 127)              cutoff *= float(cvalue) * 0.00787402f; // (1 / 127)
506              if (cutoff > 1.0) cutoff = 1.0;              if (cutoff > 1.0) cutoff = 1.0;
507              cutoff = exp(cutoff * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MIN;              cutoff = (cutoff < 0.5 ? cutoff * 4826 - 1 : cutoff * 5715 - 449);
508                if (cutoff < 1.0) cutoff = 1.0;
509    
510              // calculate resonance              // calculate resonance
511              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)  
512    
513              VCFCutoffCtrl.fvalue    = cutoff - CONFIG_FILTER_CUTOFF_MIN;              VCFCutoffCtrl.fvalue    = cutoff - 1.0;
514              VCFResonanceCtrl.fvalue = resonance;              VCFResonanceCtrl.fvalue = resonance;
515          }          }
516          else {          else {
# Line 714  namespace LinuxSampler { namespace gig { Line 714  namespace LinuxSampler { namespace gig {
714          if (ccvalue < pDimRgn->VCFVelocityScale) ccvalue = pDimRgn->VCFVelocityScale;          if (ccvalue < pDimRgn->VCFVelocityScale) ccvalue = pDimRgn->VCFVelocityScale;
715          float cutoff = CutoffBase * float(ccvalue) * 0.00787402f; // (1 / 127)          float cutoff = CutoffBase * float(ccvalue) * 0.00787402f; // (1 / 127)
716          if (cutoff > 1.0) cutoff = 1.0;          if (cutoff > 1.0) cutoff = 1.0;
717          cutoff = exp(cutoff * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MIN - CONFIG_FILTER_CUTOFF_MIN;          cutoff = (cutoff < 0.5 ? cutoff * 4826 - 1 : cutoff * 5715 - 449);
718          VCFCutoffCtrl.fvalue = cutoff; // needed for initialization of fFinalCutoff next time          if (cutoff < 1.0) cutoff = 1.0;
719    
720            VCFCutoffCtrl.fvalue = cutoff - 1.0; // needed for initialization of fFinalCutoff next time
721          fFinalCutoff = cutoff;          fFinalCutoff = cutoff;
722      }      }
723    
# Line 750  namespace LinuxSampler { namespace gig { Line 752  namespace LinuxSampler { namespace gig {
752              while (itNoteEvent && itNoteEvent->FragmentPos() <= Skip) ++itNoteEvent;              while (itNoteEvent && itNoteEvent->FragmentPos() <= Skip) ++itNoteEvent;
753          }          }
754    
755            uint killPos;
756            if (itKillEvent) killPos = RTMath::Min(itKillEvent->FragmentPos(), pEngine->MaxFadeOutPos);
757    
758          uint i = Skip;          uint i = Skip;
759          while (i < Samples) {          while (i < Samples) {
760              int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples);              int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples);
# Line 770  namespace LinuxSampler { namespace gig { Line 775  namespace LinuxSampler { namespace gig {
775              // process transition events (note on, note off & sustain pedal)              // process transition events (note on, note off & sustain pedal)
776              processTransitionEvents(itNoteEvent, iSubFragmentEnd);              processTransitionEvents(itNoteEvent, iSubFragmentEnd);
777    
778                // if the voice was killed in this subfragment switch EG1 to fade out stage
779                if (itKillEvent && killPos <= iSubFragmentEnd) {
780                    EG1.enterFadeOutStage();
781                    itKillEvent = Pool<Event>::Iterator();
782                }
783    
784              // process envelope generators              // process envelope generators
785              switch (EG1.getSegmentType()) {              switch (EG1.getSegmentType()) {
786                  case EGADSR::segment_lin:                  case EGADSR::segment_lin:
# Line 793  namespace LinuxSampler { namespace gig { Line 804  namespace LinuxSampler { namespace gig {
804                      fFinalCutoff *= EG2.getLevel();                      fFinalCutoff *= EG2.getLevel();
805                      break; // noop                      break; // noop
806              }              }
807              if (EG3.active()) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(EG3.render());              if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();
808    
809              // process low frequency oscillators              // process low frequency oscillators
810              if (bLFO1Enabled) fFinalVolume *= pLFO1->render();              if (bLFO1Enabled) fFinalVolume *= pLFO1->render();
# Line 802  namespace LinuxSampler { namespace gig { Line 813  namespace LinuxSampler { namespace gig {
813    
814              // if filter enabled then update filter coefficients              // if filter enabled then update filter coefficients
815              if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) {              if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) {
816                  finalSynthesisParameters.filterLeft.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate);                  finalSynthesisParameters.filterLeft.SetParameters(fFinalCutoff + 1.0, fFinalResonance, pEngine->SampleRate);
817                  finalSynthesisParameters.filterRight.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate);                  finalSynthesisParameters.filterRight.SetParameters(fFinalCutoff + 1.0, fFinalResonance, pEngine->SampleRate);
818              }              }
819    
820              // do we need resampling?              // do we need resampling?
# Line 846  namespace LinuxSampler { namespace gig { Line 857  namespace LinuxSampler { namespace gig {
857          }          }
858      }      }
859    
860        /** @brief Update current portamento position.
861         *
862         * Will be called when portamento mode is enabled to get the final
863         * portamento position of this active voice from where the next voice(s)
864         * might continue to slide on.
865         *
866         * @param itNoteOffEvent - event which causes this voice to die soon
867         */
868        void Voice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
869            const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
870            pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
871        }
872    
873      /**      /**
874       *  Immediately kill the voice. This method should not be used to kill       *  Immediately kill the voice. This method should not be used to kill
875       *  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.829

  ViewVC Help
Powered by ViewVC