/[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 716 by iliev, Sun Jul 24 06:57:30 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 21  Line 21 
21   *   MA  02111-1307  USA                                                   *   *   MA  02111-1307  USA                                                   *
22   ***************************************************************************/   ***************************************************************************/
23    
 #include "EGADSR.h"  
 #include "Manipulator.h"  
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 32  namespace LinuxSampler { namespace gig { Line 31  namespace LinuxSampler { namespace gig {
31    
32      const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff());      const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff());
33    
     const int Voice::FILTER_UPDATE_MASK(CalculateFilterUpdateMask());  
   
34      float Voice::CalculateFilterCutoffCoeff() {      float Voice::CalculateFilterCutoffCoeff() {
35          return log(CONFIG_FILTER_CUTOFF_MIN / CONFIG_FILTER_CUTOFF_MAX);          return log(CONFIG_FILTER_CUTOFF_MAX / CONFIG_FILTER_CUTOFF_MIN);
     }  
   
     int Voice::CalculateFilterUpdateMask() {  
         if (CONFIG_FILTER_UPDATE_STEPS <= 0) return 0;  
         int power_of_two;  
         for (power_of_two = 0; 1<<power_of_two < CONFIG_FILTER_UPDATE_STEPS; power_of_two++);  
         return (1 << power_of_two) - 1;  
36      }      }
37    
38      Voice::Voice() {      Voice::Voice() {
39          pEngine     = NULL;          pEngine     = NULL;
40          pDiskThread = NULL;          pDiskThread = NULL;
41          PlaybackState = playback_state_end;          PlaybackState = playback_state_end;
42          pEG1   = NULL;          pLFO1 = new LFOUnsigned(1.0f);  // amplitude EG (0..1 range)
43          pEG2   = NULL;          pLFO2 = new LFOUnsigned(1.0f);  // filter EG (0..1 range)
44          pEG3   = NULL;          pLFO3 = new LFOSigned(1200.0f); // pitch EG (-1200..+1200 range)
         pVCAManipulator  = NULL;  
         pVCFCManipulator = NULL;  
         pVCOManipulator  = NULL;  
         pLFO1  = NULL;  
         pLFO2  = NULL;  
         pLFO3  = NULL;  
45          KeyGroup = 0;          KeyGroup = 0;
46          SynthesisMode = 0; // set all mode bits to 0 first          SynthesisMode = 0; // set all mode bits to 0 first
47          // select synthesis implementation (currently either pure C++ or MMX+SSE(1))          // select synthesis implementation (currently either pure C++ or MMX+SSE(1))
# Line 66  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() {
         if (pEG1)  delete pEG1;  
         if (pEG2)  delete pEG2;  
         if (pEG3)  delete pEG3;  
60          if (pLFO1) delete pLFO1;          if (pLFO1) delete pLFO1;
61          if (pLFO2) delete pLFO2;          if (pLFO2) delete pLFO2;
62          if (pLFO3) delete pLFO3;          if (pLFO3) delete pLFO3;
         if (pVCAManipulator)  delete pVCAManipulator;  
         if (pVCFCManipulator) delete pVCFCManipulator;  
         if (pVCOManipulator)  delete pVCOManipulator;  
63      }      }
64    
65      void Voice::SetEngine(Engine* pEngine) {      void Voice::SetEngine(Engine* pEngine) {
66          this->pEngine = pEngine;          this->pEngine     = pEngine;
   
         // delete old objects  
         if (pEG1) delete pEG1;  
         if (pEG2) delete pEG2;  
         if (pEG3) delete pEG3;  
         if (pVCAManipulator)  delete pVCAManipulator;  
         if (pVCFCManipulator) delete pVCFCManipulator;  
         if (pVCOManipulator)  delete pVCOManipulator;  
         if (pLFO1) delete pLFO1;  
         if (pLFO2) delete pLFO2;  
         if (pLFO3) delete pLFO3;  
   
         // create new ones  
         pEG1   = new EGADSR(pEngine, Event::destination_vca);  
         pEG2   = new EGADSR(pEngine, Event::destination_vcfc);  
         pEG3   = new EGDecay(pEngine, Event::destination_vco);  
         pVCAManipulator  = new VCAManipulator(pEngine);  
         pVCFCManipulator = new VCFCManipulator(pEngine);  
         pVCOManipulator  = new VCOManipulator(pEngine);  
         pLFO1  = new LFO<gig::VCAManipulator>(0.0f, 1.0f, LFO<VCAManipulator>::propagation_top_down, pVCAManipulator, pEngine->pEventPool);  
         pLFO2  = new LFO<gig::VCFCManipulator>(0.0f, 1.0f, LFO<VCFCManipulator>::propagation_top_down, pVCFCManipulator, pEngine->pEventPool);  
         pLFO3  = new LFO<gig::VCOManipulator>(-1200.0f, 1200.0f, LFO<VCOManipulator>::propagation_middle_balanced, pVCOManipulator, pEngine->pEventPool); // +-1 octave (+-1200 cents) max.  
   
67          this->pDiskThread = pEngine->pDiskThread;          this->pDiskThread = pEngine->pDiskThread;
68          dmsg(6,("Voice::SetEngine()\n"));          dmsg(6,("Voice::SetEngine()\n"));
69      }      }
# Line 184  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 194  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 209  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          {          {
177              double pitchbasecents = pDimRgn->FineTune + (int) pEngine->ScaleTuning[MIDIKey % 12];              double pitchbasecents = pDimRgn->FineTune + (int) pEngine->ScaleTuning[MIDIKey % 12];
178              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;
179              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate()));              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->SampleRate));
180              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
181          }          }
182    
# Line 257  namespace LinuxSampler { namespace gig { Line 211  namespace LinuxSampler { namespace gig {
211              double eg1decay   = (pDimRgn->EG1ControllerDecayInfluence)   ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence)   * eg1controllervalue : 1.0;              double eg1decay   = (pDimRgn->EG1ControllerDecayInfluence)   ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence)   * eg1controllervalue : 1.0;
212              double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 1.0;              double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 1.0;
213    
214              pEG1->Trigger(pDimRgn->EG1PreAttack,              EG1.trigger(pDimRgn->EG1PreAttack,
215                            pDimRgn->EG1Attack * eg1attack,                          pDimRgn->EG1Attack * eg1attack,
216                            pDimRgn->EG1Hold,                          pDimRgn->EG1Hold,
217                            pSample->LoopStart,                          pDimRgn->EG1Decay1 * eg1decay * velrelease,
218                            pDimRgn->EG1Decay1 * eg1decay * velrelease,                          pDimRgn->EG1Decay2 * eg1decay * velrelease,
219                            pDimRgn->EG1Decay2 * eg1decay * velrelease,                          pDimRgn->EG1InfiniteSustain,
220                            pDimRgn->EG1InfiniteSustain,                          pDimRgn->EG1Sustain,
221                            pDimRgn->EG1Sustain,                          pDimRgn->EG1Release * eg1release * velrelease,
222                            pDimRgn->EG1Release * eg1release * velrelease,                          velocityAttenuation,
223                            // the SSE synthesis implementation requires                          pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
224                            // the vca start to be 16 byte aligned          }
225                            SYNTHESIS_MODE_GET_IMPLEMENTATION(SynthesisMode) ?  
226                            Delay & 0xfffffffc : Delay,          // setup initial volume in synthesis parameters
227                            velocityAttenuation);          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)
# Line 299  namespace LinuxSampler { namespace gig { Line 254  namespace LinuxSampler { namespace gig {
254              double eg2decay   = (pDimRgn->EG2ControllerDecayInfluence)   ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerDecayInfluence)   * eg2controllervalue : 1.0;              double eg2decay   = (pDimRgn->EG2ControllerDecayInfluence)   ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerDecayInfluence)   * eg2controllervalue : 1.0;
255              double eg2release = (pDimRgn->EG2ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerReleaseInfluence) * eg2controllervalue : 1.0;              double eg2release = (pDimRgn->EG2ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerReleaseInfluence) * eg2controllervalue : 1.0;
256    
257              pEG2->Trigger(pDimRgn->EG2PreAttack,              EG2.trigger(pDimRgn->EG2PreAttack,
258                            pDimRgn->EG2Attack * eg2attack,                          pDimRgn->EG2Attack * eg2attack,
259                            false,                          false,
260                            pSample->LoopStart,                          pDimRgn->EG2Decay1 * eg2decay * velrelease,
261                            pDimRgn->EG2Decay1 * eg2decay * velrelease,                          pDimRgn->EG2Decay2 * eg2decay * velrelease,
262                            pDimRgn->EG2Decay2 * eg2decay * velrelease,                          pDimRgn->EG2InfiniteSustain,
263                            pDimRgn->EG2InfiniteSustain,                          pDimRgn->EG2Sustain,
264                            pDimRgn->EG2Sustain,                          pDimRgn->EG2Release * eg2release * velrelease,
265                            pDimRgn->EG2Release * eg2release * velrelease,                          velocityAttenuation,
266                            Delay,                          pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
                           velocityAttenuation);  
267          }          }
268    
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            pEG3->Trigger(eg3depth, pDimRgn->EG3Attack, Delay);              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 354  namespace LinuxSampler { namespace gig { Line 316  namespace LinuxSampler { namespace gig {
316                      pLFO1->ExtController = 0; // no external controller                      pLFO1->ExtController = 0; // no external controller
317                      bLFO1Enabled         = false;                      bLFO1Enabled         = false;
318              }              }
319              if (bLFO1Enabled) pLFO1->Trigger(pDimRgn->LFO1Frequency,              if (bLFO1Enabled) pLFO1->trigger(pDimRgn->LFO1Frequency,
320                                                 start_level_max,
321                                               lfo1_internal_depth,                                               lfo1_internal_depth,
322                                               pDimRgn->LFO1ControlDepth,                                               pDimRgn->LFO1ControlDepth,
                                              pEngineChannel->ControllerTable[pLFO1->ExtController],  
323                                               pDimRgn->LFO1FlipPhase,                                               pDimRgn->LFO1FlipPhase,
324                                               pEngine->SampleRate,                                               pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
                                              Delay);  
325          }          }
326    
327    
# Line 398  namespace LinuxSampler { namespace gig { Line 359  namespace LinuxSampler { namespace gig {
359                      pLFO2->ExtController = 0; // no external controller                      pLFO2->ExtController = 0; // no external controller
360                      bLFO2Enabled         = false;                      bLFO2Enabled         = false;
361              }              }
362              if (bLFO2Enabled) pLFO2->Trigger(pDimRgn->LFO2Frequency,              if (bLFO2Enabled) pLFO2->trigger(pDimRgn->LFO2Frequency,
363                                                 start_level_max,
364                                               lfo2_internal_depth,                                               lfo2_internal_depth,
365                                               pDimRgn->LFO2ControlDepth,                                               pDimRgn->LFO2ControlDepth,
                                              pEngineChannel->ControllerTable[pLFO2->ExtController],  
366                                               pDimRgn->LFO2FlipPhase,                                               pDimRgn->LFO2FlipPhase,
367                                               pEngine->SampleRate,                                               pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
                                              Delay);  
368          }          }
369    
370    
# Line 442  namespace LinuxSampler { namespace gig { Line 402  namespace LinuxSampler { namespace gig {
402                      pLFO3->ExtController = 0; // no external controller                      pLFO3->ExtController = 0; // no external controller
403                      bLFO3Enabled         = false;                      bLFO3Enabled         = false;
404              }              }
405              if (bLFO3Enabled) pLFO3->Trigger(pDimRgn->LFO3Frequency,              if (bLFO3Enabled) pLFO3->trigger(pDimRgn->LFO3Frequency,
406                                                 start_level_mid,
407                                               lfo3_internal_depth,                                               lfo3_internal_depth,
408                                               pDimRgn->LFO3ControlDepth,                                               pDimRgn->LFO3ControlDepth,
                                              pEngineChannel->ControllerTable[pLFO3->ExtController],  
409                                               false,                                               false,
410                                               pEngine->SampleRate,                                               pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
                                              Delay);  
411          }          }
412    
413    
# Line 521  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 532  namespace LinuxSampler { namespace gig { Line 491  namespace LinuxSampler { namespace gig {
491              VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller];              VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller];
492    
493              // calculate cutoff frequency              // calculate cutoff frequency
494              float cutoff = (!VCFCutoffCtrl.controller)              float cutoff = pDimRgn->GetVelocityCutoff(itNoteOnEvent->Param.Note.Velocity);
                 ? exp((float) (127 - itNoteOnEvent->Param.Note.Velocity) * (float) pDimRgn->VCFVelocityScale * 6.2E-5f * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MAX  
                 : exp((float) VCFCutoffCtrl.value * 0.00787402f * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MAX;  
   
             // calculate resonance  
             float resonance = (float) VCFResonanceCtrl.value * 0.00787f;   // 0.0..1.0  
495              if (pDimRgn->VCFKeyboardTracking) {              if (pDimRgn->VCFKeyboardTracking) {
496                  resonance += (float) (itNoteOnEvent->Param.Note.Key - pDimRgn->VCFKeyboardTrackingBreakpoint) * 0.00787f;                  cutoff *= exp((itNoteOnEvent->Param.Note.Key - pDimRgn->VCFKeyboardTrackingBreakpoint) * 0.057762265f); // (ln(2) / 12)
497              }              }
498              Constrain(resonance, 0.0, 1.0); // correct resonance if outside allowed value range (0.0..1.0)              CutoffBase = cutoff;
499    
500              VCFCutoffCtrl.fvalue    = cutoff - CONFIG_FILTER_CUTOFF_MIN;              int cvalue;
501              VCFResonanceCtrl.fvalue = resonance;              if (VCFCutoffCtrl.controller) {
502                    cvalue = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller];
503                    if (pDimRgn->VCFCutoffControllerInvert) cvalue = 127 - cvalue;
504                    // VCFVelocityScale in this case means Minimum cutoff
505                    if (cvalue < pDimRgn->VCFVelocityScale) cvalue = pDimRgn->VCFVelocityScale;
506                }
507                else {
508                    cvalue = pDimRgn->VCFCutoff;
509                }
510                cutoff *= float(cvalue) * 0.00787402f; // (1 / 127)
511                if (cutoff > 1.0) cutoff = 1.0;
512                cutoff = (cutoff < 0.5 ? cutoff * 4826 - 1 : cutoff * 5715 - 449);
513                if (cutoff < 1.0) cutoff = 1.0;
514    
515                // calculate resonance
516                float resonance = (float) (VCFResonanceCtrl.controller ? VCFResonanceCtrl.value : pDimRgn->VCFResonance) * 0.00787f; // 0.0..1.0
517    
518              FilterUpdateCounter = -1;              VCFCutoffCtrl.fvalue    = cutoff - 1.0;
519                VCFResonanceCtrl.fvalue = resonance;
520          }          }
521          else {          else {
522              VCFCutoffCtrl.controller    = 0;              VCFCutoffCtrl.controller    = 0;
# Line 570  namespace LinuxSampler { namespace gig { Line 540  namespace LinuxSampler { namespace gig {
540      void Voice::Render(uint Samples) {      void Voice::Render(uint Samples) {
541    
542          // select default values for synthesis mode bits          // select default values for synthesis mode bits
         SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, (PitchBase * PitchBend) != 1.0f);  
         SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, true);  
543          SYNTHESIS_MODE_SET_LOOP(SynthesisMode, false);          SYNTHESIS_MODE_SET_LOOP(SynthesisMode, false);
544    
         // Reset the synthesis parameter matrix  
   
         #if CONFIG_PROCESS_MUTED_CHANNELS  
         pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume));  
         #else  
         pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngineChannel->GlobalVolume);  
         #endif  
         pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase);  
         pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue);  
         pEngine->ResetSynthesisParameters(Event::destination_vcfr, VCFResonanceCtrl.fvalue);  
   
         // Apply events to the synthesis parameter matrix  
         ProcessEvents(Samples);  
   
         // Let all modulators write their parameter changes to the synthesis parameter matrix for the current audio fragment  
         pEG1->Process(Samples, pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend, itKillEvent);  
         pEG2->Process(Samples, pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);  
         if (pEG3->Process(Samples)) { // if pitch EG is active  
             SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true);  
             SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false);  
         }  
         if (bLFO1Enabled) pLFO1->Process(Samples);  
         if (bLFO2Enabled) pLFO2->Process(Samples);  
         if (bLFO3Enabled) {  
             if (pLFO3->Process(Samples)) { // if pitch LFO modulation is active  
                 SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true);  
                 SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false);  
             }  
         }  
   
         if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode))  
             CalculateBiquadParameters(Samples); // calculate the final biquad filter parameters  
   
545          switch (this->PlaybackState) {          switch (this->PlaybackState) {
546    
547              case playback_state_init:              case playback_state_init:
# Line 621  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 641  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 663  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 681  namespace LinuxSampler { namespace gig { Line 615  namespace LinuxSampler { namespace gig {
615                  break;                  break;
616          }          }
617    
         // Reset synthesis event lists (except VCO, as VCO events apply channel wide currently)  
         pEngineChannel->pSynthesisEvents[Event::destination_vca]->clear();  
         pEngineChannel->pSynthesisEvents[Event::destination_vcfc]->clear();  
         pEngineChannel->pSynthesisEvents[Event::destination_vcfr]->clear();  
   
618          // Reset delay          // Reset delay
619          Delay = 0;          Delay = 0;
620    
621          itTriggerEvent = Pool<Event>::Iterator();          itTriggerEvent = Pool<Event>::Iterator();
622    
623          // If sample stream or release stage finished, kill the voice          // If sample stream or release stage finished, kill the voice
624          if (PlaybackState == playback_state_end || pEG1->GetStage() == EGADSR::stage_end) KillImmediately();          if (PlaybackState == playback_state_end || EG1.getSegmentType() == EGADSR::segment_end) KillImmediately();
625      }      }
626    
627      /**      /**
# Line 700  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          pLFO1->Reset();          finalSynthesisParameters.filterLeft.Reset();
633          pLFO2->Reset();          finalSynthesisParameters.filterRight.Reset();
         pLFO3->Reset();  
         FilterLeft.Reset();  
         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 715  namespace LinuxSampler { namespace gig { Line 641  namespace LinuxSampler { namespace gig {
641      }      }
642    
643      /**      /**
644       *  Process the control change event lists of the engine for the current       * Process given list of MIDI note on, note off and sustain pedal events
645       *  audio fragment. Event values will be applied to the synthesis parameter       * for the given time.
      *  matrix.  
646       *       *
647       *  @param Samples - number of samples to be rendered in this audio fragment cycle       * @param itEvent - iterator pointing to the next event to be processed
648         * @param End     - youngest time stamp where processing should be stopped
649       */       */
650      void Voice::ProcessEvents(uint Samples) {      void Voice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {
651            for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
652                if (itEvent->Type == Event::type_release) {
653                    EG1.update(EGADSR::event_release, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
654                    EG2.update(EGADSR::event_release, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
655                } else if (itEvent->Type == Event::type_cancel_release) {
656                    EG1.update(EGADSR::event_cancel_release, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
657                    EG2.update(EGADSR::event_cancel_release, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
658                }
659            }
660        }
661    
662          // dispatch control change events      /**
663          RTList<Event>::Iterator itCCEvent = pEngineChannel->pCCEvents->first();       * Process given list of MIDI control change and pitch bend events for
664          if (Delay) { // skip events that happened before this voice was triggered       * the given time.
665              while (itCCEvent && itCCEvent->FragmentPos() <= Delay) ++itCCEvent;       *
666          }       * @param itEvent - iterator pointing to the next event to be processed
667          while (itCCEvent) {       * @param End     - youngest time stamp where processing should be stopped
668              if (itCCEvent->Param.CC.Controller) { // if valid MIDI controller       */
669                  if (itCCEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {      void Voice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) {
670                      *pEngineChannel->pSynthesisEvents[Event::destination_vcfc]->allocAppend() = *itCCEvent;          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
671                  }              if (itEvent->Type == Event::type_control_change &&
672                  if (itCCEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {                  itEvent->Param.CC.Controller) { // if (valid) MIDI control change event
673                      *pEngineChannel->pSynthesisEvents[Event::destination_vcfr]->allocAppend() = *itCCEvent;                  if (itEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {
674                        processCutoffEvent(itEvent);
675                    }
676                    if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
677                        processResonanceEvent(itEvent);
678                  }                  }
679                  if (itCCEvent->Param.CC.Controller == pLFO1->ExtController) {                  if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
680                      pLFO1->SendEvent(itCCEvent);                      pLFO1->update(itEvent->Param.CC.Value);
681                  }                  }
682                  if (itCCEvent->Param.CC.Controller == pLFO2->ExtController) {                  if (itEvent->Param.CC.Controller == pLFO2->ExtController) {
683                      pLFO2->SendEvent(itCCEvent);                      pLFO2->update(itEvent->Param.CC.Value);
684                  }                  }
685                  if (itCCEvent->Param.CC.Controller == pLFO3->ExtController) {                  if (itEvent->Param.CC.Controller == pLFO3->ExtController) {
686                      pLFO3->SendEvent(itCCEvent);                      pLFO3->update(itEvent->Param.CC.Value);
687                  }                  }
688                  if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange &&                  if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange &&
689                      itCCEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) { // if crossfade event                      itEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) {
690                      *pEngineChannel->pSynthesisEvents[Event::destination_vca]->allocAppend() = *itCCEvent;                      processCrossFadeEvent(itEvent);
691                  }                  }
692                } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event
693                    processPitchEvent(itEvent);
694              }              }
695            }
696        }
697    
698        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
700            finalSynthesisParameters.fFinalPitch *= pitch;
701            PitchBend = pitch;
702        }
703    
704        void Voice::processCrossFadeEvent(RTList<Event>::Iterator& itEvent) {
705            CrossfadeVolume = CrossfadeAttenuation(itEvent->Param.CC.Value);
706            fFinalVolume = getVolume();
707        }
708    
709        float Voice::getVolume() {
710            #if CONFIG_PROCESS_MUTED_CHANNELS
711            return pEngineChannel->GetMute() ? 0 : (Volume * CrossfadeVolume * pEngineChannel->GlobalVolume);
712            #else
713            return Volume * CrossfadeVolume * pEngineChannel->GlobalVolume;
714            #endif
715        }
716    
717        void Voice::processCutoffEvent(RTList<Event>::Iterator& itEvent) {
718            int ccvalue = itEvent->Param.CC.Value;
719            if (VCFCutoffCtrl.value == ccvalue) return;
720            VCFCutoffCtrl.value == ccvalue;
721            if (pDimRgn->VCFCutoffControllerInvert)  ccvalue = 127 - ccvalue;
722            if (ccvalue < pDimRgn->VCFVelocityScale) ccvalue = pDimRgn->VCFVelocityScale;
723            float cutoff = CutoffBase * float(ccvalue) * 0.00787402f; // (1 / 127)
724            if (cutoff > 1.0) cutoff = 1.0;
725            cutoff = (cutoff < 0.5 ? cutoff * 4826 - 1 : cutoff * 5715 - 449);
726            if (cutoff < 1.0) cutoff = 1.0;
727    
728            VCFCutoffCtrl.fvalue = cutoff - 1.0; // needed for initialization of fFinalCutoff next time
729            fFinalCutoff = cutoff;
730        }
731    
732        void Voice::processResonanceEvent(RTList<Event>::Iterator& itEvent) {
733            // convert absolute controller value to differential
734            const int ctrldelta = itEvent->Param.CC.Value - VCFResonanceCtrl.value;
735            VCFResonanceCtrl.value = itEvent->Param.CC.Value;
736            const float resonancedelta = (float) ctrldelta * 0.00787f; // 0.0..1.0
737            fFinalResonance += resonancedelta;
738            // needed for initialization of parameter
739            VCFResonanceCtrl.fvalue = itEvent->Param.CC.Value * 0.00787f;
740        }
741    
742              ++itCCEvent;      /**
743         *  Synthesizes the current audio fragment for this voice.
744         *
745         *  @param Samples - number of sample points to be rendered in this audio
746         *                   fragment cycle
747         *  @param pSrc    - pointer to input sample data
748         *  @param Skip    - number of sample points to skip in output buffer
749         */
750        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();
756            RTList<Event>::Iterator itNoteEvent = pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents->first();
757    
758            if (Skip) { // skip events that happened before this voice was triggered
759                while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;
760                while (itNoteEvent && itNoteEvent->FragmentPos() <= Skip) ++itNoteEvent;
761          }          }
762    
763            uint killPos;
764            if (itKillEvent) killPos = RTMath::Min(itKillEvent->FragmentPos(), pEngine->MaxFadeOutPos);
765    
766          // process pitch events          uint i = Skip;
767          {          while (i < Samples) {
768              RTList<Event>* pVCOEventList = pEngineChannel->pSynthesisEvents[Event::destination_vco];              int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples);
769              RTList<Event>::Iterator itVCOEvent = pVCOEventList->first();  
770              if (Delay) { // skip events that happened before this voice was triggered              // initialize all final synthesis parameters
771                  while (itVCOEvent && itVCOEvent->FragmentPos() <= Delay) ++itVCOEvent;              finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend;
772              }              fFinalVolume    = getVolume();
773              // apply old pitchbend value until first pitch event occurs              fFinalCutoff    = VCFCutoffCtrl.fvalue;
774              if (this->PitchBend != 1.0) {              fFinalResonance = VCFResonanceCtrl.fvalue;
775                  uint end = (itVCOEvent) ? itVCOEvent->FragmentPos() : Samples;  
776                  for (uint i = Delay; i < end; i++) {              // process MIDI control change and pitchbend events for this subfragment
777                      pEngine->pSynthesisParameters[Event::destination_vco][i] *= this->PitchBend;              processCCEvents(itCCEvent, iSubFragmentEnd);
778                  }  
779                // process transition events (note on, note off & sustain pedal)
780                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              }              }
             float pitch;  
             while (itVCOEvent) {  
                 RTList<Event>::Iterator itNextVCOEvent = itVCOEvent;  
                 ++itNextVCOEvent;  
   
                 // calculate the influence length of this event (in sample points)  
                 uint end = (itNextVCOEvent) ? itNextVCOEvent->FragmentPos() : Samples;  
   
                 pitch = RTMath::CentsToFreqRatio(((double) itVCOEvent->Param.Pitch.Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents  
   
                 // apply pitch value to the pitch parameter sequence  
                 for (uint i = itVCOEvent->FragmentPos(); i < end; i++) {  
                     pEngine->pSynthesisParameters[Event::destination_vco][i] *= pitch;  
                 }  
787    
788                  itVCOEvent = itNextVCOEvent;              // process envelope generators
789                switch (EG1.getSegmentType()) {
790                    case EGADSR::segment_lin:
791                        fFinalVolume *= EG1.processLin();
792                        break;
793                    case EGADSR::segment_exp:
794                        fFinalVolume *= EG1.processExp();
795                        break;
796                    case EGADSR::segment_end:
797                        fFinalVolume *= EG1.getLevel();
798                        break; // noop
799              }              }
800              if (!pVCOEventList->isEmpty()) {              switch (EG2.getSegmentType()) {
801                  this->PitchBend = pitch;                  case EGADSR::segment_lin:
802                  SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true);                      fFinalCutoff *= EG2.processLin();
803                  SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false);                      break;
804                    case EGADSR::segment_exp:
805                        fFinalCutoff *= EG2.processExp();
806                        break;
807                    case EGADSR::segment_end:
808                        fFinalCutoff *= EG2.getLevel();
809                        break; // noop
810              }              }
811          }              if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render();
812    
813          // process volume / attenuation events (TODO: we only handle and _expect_ crossfade events here ATM !)              // process low frequency oscillators
814          {              if (bLFO1Enabled) fFinalVolume *= pLFO1->render();
815              RTList<Event>* pVCAEventList = pEngineChannel->pSynthesisEvents[Event::destination_vca];              if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();
816              RTList<Event>::Iterator itVCAEvent = pVCAEventList->first();              if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
             if (Delay) { // skip events that happened before this voice was triggered  
                 while (itVCAEvent && itVCAEvent->FragmentPos() <= Delay) ++itVCAEvent;  
             }  
             float crossfadevolume;  
             while (itVCAEvent) {  
                 RTList<Event>::Iterator itNextVCAEvent = itVCAEvent;  
                 ++itNextVCAEvent;  
   
                 // calculate the influence length of this event (in sample points)  
                 uint end = (itNextVCAEvent) ? itNextVCAEvent->FragmentPos() : Samples;  
   
                 crossfadevolume = CrossfadeAttenuation(itVCAEvent->Param.CC.Value);  
   
                 #if CONFIG_PROCESS_MUTED_CHANNELS  
                 float effective_volume = crossfadevolume * this->Volume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume);  
                 #else  
                 float effective_volume = crossfadevolume * this->Volume * pEngineChannel->GlobalVolume;  
                 #endif  
   
                 // apply volume value to the volume parameter sequence  
                 for (uint i = itVCAEvent->FragmentPos(); i < end; i++) {  
                     pEngine->pSynthesisParameters[Event::destination_vca][i] = effective_volume;  
                 }  
817    
818                  itVCAEvent = itNextVCAEvent;              // if filter enabled then update filter coefficients
819                if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) {
820                    finalSynthesisParameters.filterLeft.SetParameters(fFinalCutoff + 1.0, fFinalResonance, pEngine->SampleRate);
821                    finalSynthesisParameters.filterRight.SetParameters(fFinalCutoff + 1.0, fFinalResonance, pEngine->SampleRate);
822              }              }
             if (!pVCAEventList->isEmpty()) this->CrossfadeVolume = crossfadevolume;  
         }  
823    
824          // process filter cutoff events              // do we need resampling?
825          {              const float __PLUS_ONE_CENT  = 1.000577789506554859250142541782224725466f;
826              RTList<Event>* pCutoffEventList = pEngineChannel->pSynthesisEvents[Event::destination_vcfc];              const float __MINUS_ONE_CENT = 0.9994225441413807496009516495583113737666f;
827              RTList<Event>::Iterator itCutoffEvent = pCutoffEventList->first();              const bool bResamplingRequired = !(finalSynthesisParameters.fFinalPitch <= __PLUS_ONE_CENT &&
828              if (Delay) { // skip events that happened before this voice was triggered                                                 finalSynthesisParameters.fFinalPitch >= __MINUS_ONE_CENT);
829                  while (itCutoffEvent && itCutoffEvent->FragmentPos() <= Delay) ++itCutoffEvent;              SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, bResamplingRequired);
             }  
             float cutoff;  
             while (itCutoffEvent) {  
                 RTList<Event>::Iterator itNextCutoffEvent = itCutoffEvent;  
                 ++itNextCutoffEvent;  
   
                 // calculate the influence length of this event (in sample points)  
                 uint end = (itNextCutoffEvent) ? itNextCutoffEvent->FragmentPos() : Samples;  
   
                 cutoff = exp((float) itCutoffEvent->Param.CC.Value * 0.00787402f * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MAX - CONFIG_FILTER_CUTOFF_MIN;  
   
                 // apply cutoff frequency to the cutoff parameter sequence  
                 for (uint i = itCutoffEvent->FragmentPos(); i < end; i++) {  
                     pEngine->pSynthesisParameters[Event::destination_vcfc][i] = cutoff;  
                 }  
830    
831                  itCutoffEvent = itNextCutoffEvent;              // prepare final synthesis parameters structure
832              }              finalSynthesisParameters.uiToGo            = iSubFragmentEnd - i;
833              if (!pCutoffEventList->isEmpty()) VCFCutoffCtrl.fvalue = cutoff; // needed for initialization of parameter matrix next time  #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;
840                finalSynthesisParameters.fFinalVolumeRight = fFinalVolume * PanRight;
841    #endif
842                // render audio for one subfragment
843                RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
844    
845          // process filter resonance events              // stop the rendering if volume EG is finished
846          {              if (EG1.getSegmentType() == EGADSR::segment_end) break;
             RTList<Event>* pResonanceEventList = pEngineChannel->pSynthesisEvents[Event::destination_vcfr];  
             RTList<Event>::Iterator itResonanceEvent = pResonanceEventList->first();  
             if (Delay) { // skip events that happened before this voice was triggered  
                 while (itResonanceEvent && itResonanceEvent->FragmentPos() <= Delay) ++itResonanceEvent;  
             }  
             while (itResonanceEvent) {  
                 RTList<Event>::Iterator itNextResonanceEvent = itResonanceEvent;  
                 ++itNextResonanceEvent;  
   
                 // calculate the influence length of this event (in sample points)  
                 uint end = (itNextResonanceEvent) ? itNextResonanceEvent->FragmentPos() : Samples;  
   
                 // convert absolute controller value to differential  
                 int ctrldelta = itResonanceEvent->Param.CC.Value - VCFResonanceCtrl.value;  
                 VCFResonanceCtrl.value = itResonanceEvent->Param.CC.Value;  
   
                 float resonancedelta = (float) ctrldelta * 0.00787f; // 0.0..1.0  
   
                 // apply cutoff frequency to the cutoff parameter sequence  
                 for (uint i = itResonanceEvent->FragmentPos(); i < end; i++) {  
                     pEngine->pSynthesisParameters[Event::destination_vcfr][i] += resonancedelta;  
                 }  
847    
848                  itResonanceEvent = itNextResonanceEvent;              const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch;
             }  
             if (!pResonanceEventList->isEmpty()) VCFResonanceCtrl.fvalue = pResonanceEventList->last()->Param.CC.Value * 0.00787f; // needed for initialization of parameter matrix next time  
         }  
     }  
849    
850      /**              // increment envelopes' positions
851       * Calculate all necessary, final biquad filter parameters.              if (EG1.active()) {
852       *  
853       * @param Samples - number of samples to be rendered in this audio fragment cycle                  // 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
854       */                  if (pSample->Loops && Pos <= pSample->LoopStart && pSample->LoopStart < newPos) {
855      void Voice::CalculateBiquadParameters(uint Samples) {                      EG1.update(EGADSR::event_hold_end, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
         biquad_param_t bqbase;  
         biquad_param_t bqmain;  
         float prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][0];  
         float prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][0];  
         FilterLeft.SetParameters( &bqbase, &bqmain, prev_cutoff + CONFIG_FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate);  
         FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff + CONFIG_FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate);  
         pEngine->pBasicFilterParameters[0] = bqbase;  
         pEngine->pMainFilterParameters[0]  = bqmain;  
   
         float* bq;  
         for (int i = 1; i < Samples; i++) {  
             // recalculate biquad parameters if cutoff or resonance differ from previous sample point  
             if (!(i & FILTER_UPDATE_MASK)) {  
                 if (pEngine->pSynthesisParameters[Event::destination_vcfr][i] != prev_res ||  
                     pEngine->pSynthesisParameters[Event::destination_vcfc][i] != prev_cutoff)  
                 {  
                     prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i];  
                     prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][i];  
                     FilterLeft.SetParameters( &bqbase, &bqmain, prev_cutoff + CONFIG_FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate);  
                     FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff + CONFIG_FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate);  
856                  }                  }
857    
858                    EG1.increment(1);
859                    if (!EG1.toStageEndLeft()) EG1.update(EGADSR::event_stage_end, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
860              }              }
861                if (EG2.active()) {
862                    EG2.increment(1);
863                    if (!EG2.toStageEndLeft()) EG2.update(EGADSR::event_stage_end, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
864                }
865                EG3.increment(1);
866                if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
867    
868              //same as 'pEngine->pBasicFilterParameters[i] = bqbase;'              Pos = newPos;
869              bq    = (float*) &pEngine->pBasicFilterParameters[i];              i = iSubFragmentEnd;
             bq[0] = bqbase.b0;  
             bq[1] = bqbase.b1;  
             bq[2] = bqbase.b2;  
             bq[3] = bqbase.a1;  
             bq[4] = bqbase.a2;  
   
             // same as 'pEngine->pMainFilterParameters[i] = bqmain;'  
             bq    = (float*) &pEngine->pMainFilterParameters[i];  
             bq[0] = bqmain.b0;  
             bq[1] = bqmain.b1;  
             bq[2] = bqmain.b2;  
             bq[3] = bqmain.a1;  
             bq[4] = bqmain.a2;  
870          }          }
871      }      }
872    
873      /**      /** @brief Update current portamento position.
      *  Synthesizes the current audio fragment for this voice.  
874       *       *
875       *  @param Samples - number of sample points to be rendered in this audio       * Will be called when portamento mode is enabled to get the final
876       *                   fragment cycle       * portamento position of this active voice from where the next voice(s)
877       *  @param pSrc    - pointer to input sample data       * might continue to slide on.
878       *  @param Skip    - number of sample points to skip in output buffer       *
879         * @param itNoteOffEvent - event which causes this voice to die soon
880       */       */
881      void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {      void Voice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
882          RunSynthesisFunction(SynthesisMode, *this, Samples, pSrc, Skip);          const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
883            pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
884      }      }
885    
886      /**      /**

Legend:
Removed from v.716  
changed lines
  Added in v.830

  ViewVC Help
Powered by ViewVC