/[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 614 by persson, Mon Jun 6 16:54:20 2005 UTC revision 770 by schoenebeck, Sun Sep 11 15:56:29 2005 UTC
# 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))
48          #if ARCH_X86          #if CONFIG_ASM && ARCH_X86
49          SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, Features::supportsMMX() && Features::supportsSSE());          SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, Features::supportsMMX() && Features::supportsSSE());
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 117  namespace LinuxSampler { namespace gig { Line 72  namespace LinuxSampler { namespace gig {
72       *  Initializes and triggers the voice, a disk stream will be launched if       *  Initializes and triggers the voice, a disk stream will be launched if
73       *  needed.       *  needed.
74       *       *
75       *  @param pEngineChannel       - engine channel on which this voice was ordered       *  @param pEngineChannel - engine channel on which this voice was ordered
76       *  @param itNoteOnEvent        - event that caused triggering of this voice       *  @param itNoteOnEvent  - event that caused triggering of this voice
77       *  @param PitchBend            - MIDI detune factor (-8192 ... +8191)       *  @param PitchBend      - MIDI detune factor (-8192 ... +8191)
78       *  @param pInstrument          - points to the loaded instrument which provides sample wave(s) and articulation data       *  @param pDimRgn        - points to the dimension region which provides sample wave(s) and articulation data
79       *  @param iLayer               - layer number this voice refers to (only if this is a layered sound of course)       *  @param VoiceType      - type of this voice
80       *  @param ReleaseTriggerVoice  - if this new voice is a release trigger voice (optional, default = false)       *  @param iKeyGroup      - a value > 0 defines a key group in which this voice is member of
      *  @param VoiceStealingAllowed - wether the voice is allowed to steal voices for further subvoices  
81       *  @returns 0 on success, a value < 0 if the voice wasn't triggered       *  @returns 0 on success, a value < 0 if the voice wasn't triggered
82       *           (either due to an error or e.g. because no region is       *           (either due to an error or e.g. because no region is
83       *           defined for the given key)       *           defined for the given key)
84       */       */
85      int Voice::Trigger(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealingAllowed) {      int Voice::Trigger(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent, int PitchBend, ::gig::DimensionRegion* pDimRgn, type_t VoiceType, int iKeyGroup) {
86          this->pEngineChannel = pEngineChannel;          this->pEngineChannel = pEngineChannel;
87          if (!pInstrument) {          this->pDimRgn        = pDimRgn;
88             dmsg(1,("voice::trigger: !pInstrument\n"));  
            exit(EXIT_FAILURE);  
         }  
89          #if CONFIG_DEVMODE          #if CONFIG_DEVMODE
90          if (itNoteOnEvent->FragmentPos() > pEngine->MaxSamplesPerCycle) { // just a sanity check for debugging          if (itNoteOnEvent->FragmentPos() > pEngine->MaxSamplesPerCycle) { // just a sanity check for debugging
91              dmsg(1,("Voice::Trigger(): ERROR, TriggerDelay > Totalsamples\n"));              dmsg(1,("Voice::Trigger(): ERROR, TriggerDelay > Totalsamples\n"));
92          }          }
93          #endif // CONFIG_DEVMODE          #endif // CONFIG_DEVMODE
94    
95          Type            = type_normal;          Type            = VoiceType;
96          MIDIKey         = itNoteOnEvent->Param.Note.Key;          MIDIKey         = itNoteOnEvent->Param.Note.Key;
         pRegion         = pInstrument->GetRegion(MIDIKey);  
97          PlaybackState   = playback_state_init; // mark voice as triggered, but no audio rendered yet          PlaybackState   = playback_state_init; // mark voice as triggered, but no audio rendered yet
98          Delay           = itNoteOnEvent->FragmentPos();          Delay           = itNoteOnEvent->FragmentPos();
99          itTriggerEvent  = itNoteOnEvent;          itTriggerEvent  = itNoteOnEvent;
100          itKillEvent     = Pool<Event>::Iterator();          itKillEvent     = Pool<Event>::Iterator();
101            KeyGroup        = iKeyGroup;
102            pSample         = pDimRgn->pSample; // sample won't change until the voice is finished
103    
104          if (!pRegion) {          // calculate volume
105              dmsg(4, ("gig::Voice: No Region defined for MIDI key %d\n", MIDIKey));          const double velocityAttenuation = pDimRgn->GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity);
             return -1;  
         }  
106    
107          // only mark the first voice of a layered voice (group) to be in a          Volume = velocityAttenuation / 32768.0f; // we downscale by 32768 to convert from int16 value range to DSP value range (which is -1.0..1.0)
         // key group, so the layered voices won't kill each other  
         KeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0;  
108    
109          // get current dimension values to select the right dimension region          Volume *= pDimRgn->SampleAttenuation;
         //FIXME: controller values for selecting the dimension region here are currently not sample accurate  
         uint DimValues[8] = { 0 };  
         for (int i = pRegion->Dimensions - 1; i >= 0; i--) {  
             switch (pRegion->pDimensionDefinitions[i].dimension) {  
                 case ::gig::dimension_samplechannel:  
                     DimValues[i] = 0; //TODO: we currently ignore this dimension  
                     break;  
                 case ::gig::dimension_layer:  
                     DimValues[i] = iLayer;  
                     break;  
                 case ::gig::dimension_velocity:  
                     DimValues[i] = itNoteOnEvent->Param.Note.Velocity;  
                     break;  
                 case ::gig::dimension_channelaftertouch:  
                     DimValues[i] = 0; //TODO: we currently ignore this dimension  
                     break;  
                 case ::gig::dimension_releasetrigger:  
                     Type = (ReleaseTriggerVoice) ? type_release_trigger : (!iLayer) ? type_release_trigger_required : type_normal;  
                     DimValues[i] = (uint) ReleaseTriggerVoice;  
                     break;  
                 case ::gig::dimension_keyboard:  
                     DimValues[i] = (uint) pEngineChannel->CurrentKeyDimension;  
                     break;  
                 case ::gig::dimension_roundrobin:  
                     DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on  
                     break;  
                 case ::gig::dimension_random:  
                     pEngine->RandomSeed = pEngine->RandomSeed * 1103515245 + 12345; // classic pseudo random number generator  
                     DimValues[i] = (uint) pEngine->RandomSeed >> (32 - pRegion->pDimensionDefinitions[i].bits); // highest bits are most random  
                     break;  
                 case ::gig::dimension_modwheel:  
                     DimValues[i] = pEngineChannel->ControllerTable[1];  
                     break;  
                 case ::gig::dimension_breath:  
                     DimValues[i] = pEngineChannel->ControllerTable[2];  
                     break;  
                 case ::gig::dimension_foot:  
                     DimValues[i] = pEngineChannel->ControllerTable[4];  
                     break;  
                 case ::gig::dimension_portamentotime:  
                     DimValues[i] = pEngineChannel->ControllerTable[5];  
                     break;  
                 case ::gig::dimension_effect1:  
                     DimValues[i] = pEngineChannel->ControllerTable[12];  
                     break;  
                 case ::gig::dimension_effect2:  
                     DimValues[i] = pEngineChannel->ControllerTable[13];  
                     break;  
                 case ::gig::dimension_genpurpose1:  
                     DimValues[i] = pEngineChannel->ControllerTable[16];  
                     break;  
                 case ::gig::dimension_genpurpose2:  
                     DimValues[i] = pEngineChannel->ControllerTable[17];  
                     break;  
                 case ::gig::dimension_genpurpose3:  
                     DimValues[i] = pEngineChannel->ControllerTable[18];  
                     break;  
                 case ::gig::dimension_genpurpose4:  
                     DimValues[i] = pEngineChannel->ControllerTable[19];  
                     break;  
                 case ::gig::dimension_sustainpedal:  
                     DimValues[i] = pEngineChannel->ControllerTable[64];  
                     break;  
                 case ::gig::dimension_portamento:  
                     DimValues[i] = pEngineChannel->ControllerTable[65];  
                     break;  
                 case ::gig::dimension_sostenutopedal:  
                     DimValues[i] = pEngineChannel->ControllerTable[66];  
                     break;  
                 case ::gig::dimension_softpedal:  
                     DimValues[i] = pEngineChannel->ControllerTable[67];  
                     break;  
                 case ::gig::dimension_genpurpose5:  
                     DimValues[i] = pEngineChannel->ControllerTable[80];  
                     break;  
                 case ::gig::dimension_genpurpose6:  
                     DimValues[i] = pEngineChannel->ControllerTable[81];  
                     break;  
                 case ::gig::dimension_genpurpose7:  
                     DimValues[i] = pEngineChannel->ControllerTable[82];  
                     break;  
                 case ::gig::dimension_genpurpose8:  
                     DimValues[i] = pEngineChannel->ControllerTable[83];  
                     break;  
                 case ::gig::dimension_effect1depth:  
                     DimValues[i] = pEngineChannel->ControllerTable[91];  
                     break;  
                 case ::gig::dimension_effect2depth:  
                     DimValues[i] = pEngineChannel->ControllerTable[92];  
                     break;  
                 case ::gig::dimension_effect3depth:  
                     DimValues[i] = pEngineChannel->ControllerTable[93];  
                     break;  
                 case ::gig::dimension_effect4depth:  
                     DimValues[i] = pEngineChannel->ControllerTable[94];  
                     break;  
                 case ::gig::dimension_effect5depth:  
                     DimValues[i] = pEngineChannel->ControllerTable[95];  
                     break;  
                 case ::gig::dimension_none:  
                     std::cerr << "gig::Voice::Trigger() Error: dimension=none\n" << std::flush;  
                     break;  
                 default:  
                     std::cerr << "gig::Voice::Trigger() Error: Unknown dimension\n" << std::flush;  
             }  
         }  
         pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);  
110    
111          pSample = pDimRgn->pSample; // sample won't change until the voice is finished          // the volume of release triggered samples depends on note length
112          if (!pSample || !pSample->SamplesTotal) return -1; // no need to continue if sample is silent          if (Type == type_release_trigger) {
113                float noteLength = float(pEngine->FrameTime + Delay -
114                                         pEngineChannel->pMIDIKeyInfo[MIDIKey].NoteOnTime) / pEngine->SampleRate;
115                float attenuation = 1 - 0.01053 * (256 >> pDimRgn->ReleaseTriggerDecay) * noteLength;
116                if (attenuation <= 0) return -1;
117                Volume *= attenuation;
118            }
119    
120          // select channel mode (mono or stereo)          // select channel mode (mono or stereo)
121          SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2);          SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2);
# Line 291  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    
144          // 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
145          long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;          long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;
# Line 302  namespace LinuxSampler { namespace gig { Line 150  namespace LinuxSampler { namespace gig {
150    
151              // 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
152              if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {              if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {
153                  RAMLoop        = true;                  RAMLoop            = true;
154                  LoopCyclesLeft = pSample->LoopPlayCount;                  loop.uiTotalCycles = pSample->LoopPlayCount;
155                    loop.uiCyclesLeft  = pSample->LoopPlayCount;
156                    loop.uiStart       = pSample->LoopStart;
157                    loop.uiEnd         = pSample->LoopEnd;
158                    loop.uiSize        = pSample->LoopSize;
159              }              }
160              else RAMLoop = false;              else RAMLoop = false;
161    
# Line 317  namespace LinuxSampler { namespace gig { Line 169  namespace LinuxSampler { namespace gig {
169          else { // RAM only voice          else { // RAM only voice
170              MaxRAMPos = cachedsamples;              MaxRAMPos = cachedsamples;
171              if (pSample->Loops) {              if (pSample->Loops) {
172                  RAMLoop        = true;                  RAMLoop           = true;
173                  LoopCyclesLeft = pSample->LoopPlayCount;                  loop.uiCyclesLeft = pSample->LoopPlayCount;
174              }              }
175              else RAMLoop = false;              else RAMLoop = false;
176              dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));              dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));
# Line 329  namespace LinuxSampler { namespace gig { Line 181  namespace LinuxSampler { namespace gig {
181          {          {
182              double pitchbasecents = pDimRgn->FineTune + (int) pEngine->ScaleTuning[MIDIKey % 12];              double pitchbasecents = pDimRgn->FineTune + (int) pEngine->ScaleTuning[MIDIKey % 12];
183              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;
184              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate()));              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->SampleRate));
185              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
186          }          }
187    
         const double velocityAttenuation = pDimRgn->GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity);  
   
         Volume = velocityAttenuation / 32768.0f; // we downscale by 32768 to convert from int16 value range to DSP value range (which is -1.0..1.0)  
   
         Volume *= pDimRgn->SampleAttenuation;  
   
188          // the length of the decay and release curves are dependent on the velocity          // the length of the decay and release curves are dependent on the velocity
189          const double velrelease = 1 / pDimRgn->GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);          const double velrelease = 1 / pDimRgn->GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);
190    
# Line 362  namespace LinuxSampler { namespace gig { Line 208  namespace LinuxSampler { namespace gig {
208              }              }
209              if (pDimRgn->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue;              if (pDimRgn->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue;
210    
211              // calculate influence of EG1 controller on EG1's parameters (TODO: needs to be fine tuned)              // calculate influence of EG1 controller on EG1's parameters
212              double eg1attack  = (pDimRgn->EG1ControllerAttackInfluence)  ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerAttackInfluence)  * eg1controllervalue : 0.0;              // (eg1attack is different from the others)
213              double eg1decay   = (pDimRgn->EG1ControllerDecayInfluence)   ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence)   * eg1controllervalue : 0.0;              double eg1attack  = (pDimRgn->EG1ControllerAttackInfluence)  ?
214              double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 0.0;                  1 + 0.031 * (double) (pDimRgn->EG1ControllerAttackInfluence == 1 ?
215                                          1 : 1 << pDimRgn->EG1ControllerAttackInfluence) * eg1controllervalue : 1.0;
216              pEG1->Trigger(pDimRgn->EG1PreAttack,              double eg1decay   = (pDimRgn->EG1ControllerDecayInfluence)   ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence)   * eg1controllervalue : 1.0;
217                            pDimRgn->EG1Attack + eg1attack,              double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 1.0;
218                            pDimRgn->EG1Hold,  
219                            pSample->LoopStart,              EG1.trigger(pDimRgn->EG1PreAttack,
220                            (pDimRgn->EG1Decay1 + eg1decay) * velrelease,                          pDimRgn->EG1Attack * eg1attack,
221                            (pDimRgn->EG1Decay2 + eg1decay) * velrelease,                          pDimRgn->EG1Hold,
222                            pDimRgn->EG1InfiniteSustain,                          pSample->LoopStart,
223                            pDimRgn->EG1Sustain,                          pDimRgn->EG1Decay1 * eg1decay * velrelease,
224                            (pDimRgn->EG1Release + eg1release) * velrelease,                          pDimRgn->EG1Decay2 * eg1decay * velrelease,
225                            // the SSE synthesis implementation requires                          pDimRgn->EG1InfiniteSustain,
226                            // the vca start to be 16 byte aligned                          pDimRgn->EG1Sustain,
227                            SYNTHESIS_MODE_GET_IMPLEMENTATION(SynthesisMode) ?                          pDimRgn->EG1Release * eg1release * velrelease,
228                            Delay & 0xfffffffc : Delay,                          velocityAttenuation,
229                            velocityAttenuation);                          pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
230          }          }
231    
232    
# Line 404  namespace LinuxSampler { namespace gig { Line 250  namespace LinuxSampler { namespace gig {
250              }              }
251              if (pDimRgn->EG2ControllerInvert) eg2controllervalue = 127 - eg2controllervalue;              if (pDimRgn->EG2ControllerInvert) eg2controllervalue = 127 - eg2controllervalue;
252    
253              // calculate influence of EG2 controller on EG2's parameters (TODO: needs to be fine tuned)              // calculate influence of EG2 controller on EG2's parameters
254              double eg2attack  = (pDimRgn->EG2ControllerAttackInfluence)  ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerAttackInfluence)  * eg2controllervalue : 0.0;              double eg2attack  = (pDimRgn->EG2ControllerAttackInfluence)  ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerAttackInfluence)  * eg2controllervalue : 1.0;
255              double eg2decay   = (pDimRgn->EG2ControllerDecayInfluence)   ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerDecayInfluence)   * eg2controllervalue : 0.0;              double eg2decay   = (pDimRgn->EG2ControllerDecayInfluence)   ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerDecayInfluence)   * eg2controllervalue : 1.0;
256              double eg2release = (pDimRgn->EG2ControllerReleaseInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerReleaseInfluence) * eg2controllervalue : 0.0;              double eg2release = (pDimRgn->EG2ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerReleaseInfluence) * eg2controllervalue : 1.0;
257    
258              pEG2->Trigger(pDimRgn->EG2PreAttack,              EG2.trigger(pDimRgn->EG2PreAttack,
259                            pDimRgn->EG2Attack + eg2attack,                          pDimRgn->EG2Attack * eg2attack,
260                            false,                          false,
261                            pSample->LoopStart,                          pSample->LoopStart,
262                            (pDimRgn->EG2Decay1 + eg2decay) * velrelease,                          pDimRgn->EG2Decay1 * eg2decay * velrelease,
263                            (pDimRgn->EG2Decay2 + eg2decay) * velrelease,                          pDimRgn->EG2Decay2 * eg2decay * velrelease,
264                            pDimRgn->EG2InfiniteSustain,                          pDimRgn->EG2InfiniteSustain,
265                            pDimRgn->EG2Sustain,                          pDimRgn->EG2Sustain,
266                            (pDimRgn->EG2Release + eg2release) * velrelease,                          pDimRgn->EG2Release * eg2release * velrelease,
267                            Delay,                          velocityAttenuation,
268                            velocityAttenuation);                          pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
269          }          }
270    
271    
272          // setup EG 3 (VCO EG)          // setup EG 3 (VCO EG)
273          {          {
274            double eg3depth = RTMath::CentsToFreqRatio(pDimRgn->EG3Depth);            double eg3depth = RTMath::CentsToFreqRatio(pDimRgn->EG3Depth);
275            pEG3->Trigger(eg3depth, pDimRgn->EG3Attack, Delay);            EG3.trigger(eg3depth, pDimRgn->EG3Attack, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
276          }          }
277    
278    
# Line 437  namespace LinuxSampler { namespace gig { Line 283  namespace LinuxSampler { namespace gig {
283                  case ::gig::lfo1_ctrl_internal:                  case ::gig::lfo1_ctrl_internal:
284                      lfo1_internal_depth  = pDimRgn->LFO1InternalDepth;                      lfo1_internal_depth  = pDimRgn->LFO1InternalDepth;
285                      pLFO1->ExtController = 0; // no external controller                      pLFO1->ExtController = 0; // no external controller
286                        bLFO1Enabled         = (lfo1_internal_depth > 0);
287                      break;                      break;
288                  case ::gig::lfo1_ctrl_modwheel:                  case ::gig::lfo1_ctrl_modwheel:
289                      lfo1_internal_depth  = 0;                      lfo1_internal_depth  = 0;
290                      pLFO1->ExtController = 1; // MIDI controller 1                      pLFO1->ExtController = 1; // MIDI controller 1
291                        bLFO1Enabled         = (pDimRgn->LFO1ControlDepth > 0);
292                      break;                      break;
293                  case ::gig::lfo1_ctrl_breath:                  case ::gig::lfo1_ctrl_breath:
294                      lfo1_internal_depth  = 0;                      lfo1_internal_depth  = 0;
295                      pLFO1->ExtController = 2; // MIDI controller 2                      pLFO1->ExtController = 2; // MIDI controller 2
296                        bLFO1Enabled         = (pDimRgn->LFO1ControlDepth > 0);
297                      break;                      break;
298                  case ::gig::lfo1_ctrl_internal_modwheel:                  case ::gig::lfo1_ctrl_internal_modwheel:
299                      lfo1_internal_depth  = pDimRgn->LFO1InternalDepth;                      lfo1_internal_depth  = pDimRgn->LFO1InternalDepth;
300                      pLFO1->ExtController = 1; // MIDI controller 1                      pLFO1->ExtController = 1; // MIDI controller 1
301                        bLFO1Enabled         = (lfo1_internal_depth > 0 || pDimRgn->LFO1ControlDepth > 0);
302                      break;                      break;
303                  case ::gig::lfo1_ctrl_internal_breath:                  case ::gig::lfo1_ctrl_internal_breath:
304                      lfo1_internal_depth  = pDimRgn->LFO1InternalDepth;                      lfo1_internal_depth  = pDimRgn->LFO1InternalDepth;
305                      pLFO1->ExtController = 2; // MIDI controller 2                      pLFO1->ExtController = 2; // MIDI controller 2
306                        bLFO1Enabled         = (lfo1_internal_depth > 0 || pDimRgn->LFO1ControlDepth > 0);
307                      break;                      break;
308                  default:                  default:
309                      lfo1_internal_depth  = 0;                      lfo1_internal_depth  = 0;
310                      pLFO1->ExtController = 0; // no external controller                      pLFO1->ExtController = 0; // no external controller
311                        bLFO1Enabled         = false;
312              }              }
313              pLFO1->Trigger(pDimRgn->LFO1Frequency,              if (bLFO1Enabled) pLFO1->trigger(pDimRgn->LFO1Frequency,
314                            lfo1_internal_depth,                                               start_level_max,
315                            pDimRgn->LFO1ControlDepth,                                               lfo1_internal_depth,
316                            pEngineChannel->ControllerTable[pLFO1->ExtController],                                               pDimRgn->LFO1ControlDepth,
317                            pDimRgn->LFO1FlipPhase,                                               pDimRgn->LFO1FlipPhase,
318                            pEngine->SampleRate,                                               pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
                           Delay);  
319          }          }
320    
321    
# Line 475  namespace LinuxSampler { namespace gig { Line 326  namespace LinuxSampler { namespace gig {
326                  case ::gig::lfo2_ctrl_internal:                  case ::gig::lfo2_ctrl_internal:
327                      lfo2_internal_depth  = pDimRgn->LFO2InternalDepth;                      lfo2_internal_depth  = pDimRgn->LFO2InternalDepth;
328                      pLFO2->ExtController = 0; // no external controller                      pLFO2->ExtController = 0; // no external controller
329                        bLFO2Enabled         = (lfo2_internal_depth > 0);
330                      break;                      break;
331                  case ::gig::lfo2_ctrl_modwheel:                  case ::gig::lfo2_ctrl_modwheel:
332                      lfo2_internal_depth  = 0;                      lfo2_internal_depth  = 0;
333                      pLFO2->ExtController = 1; // MIDI controller 1                      pLFO2->ExtController = 1; // MIDI controller 1
334                        bLFO2Enabled         = (pDimRgn->LFO2ControlDepth > 0);
335                      break;                      break;
336                  case ::gig::lfo2_ctrl_foot:                  case ::gig::lfo2_ctrl_foot:
337                      lfo2_internal_depth  = 0;                      lfo2_internal_depth  = 0;
338                      pLFO2->ExtController = 4; // MIDI controller 4                      pLFO2->ExtController = 4; // MIDI controller 4
339                        bLFO2Enabled         = (pDimRgn->LFO2ControlDepth > 0);
340                      break;                      break;
341                  case ::gig::lfo2_ctrl_internal_modwheel:                  case ::gig::lfo2_ctrl_internal_modwheel:
342                      lfo2_internal_depth  = pDimRgn->LFO2InternalDepth;                      lfo2_internal_depth  = pDimRgn->LFO2InternalDepth;
343                      pLFO2->ExtController = 1; // MIDI controller 1                      pLFO2->ExtController = 1; // MIDI controller 1
344                        bLFO2Enabled         = (lfo2_internal_depth > 0 || pDimRgn->LFO2ControlDepth > 0);
345                      break;                      break;
346                  case ::gig::lfo2_ctrl_internal_foot:                  case ::gig::lfo2_ctrl_internal_foot:
347                      lfo2_internal_depth  = pDimRgn->LFO2InternalDepth;                      lfo2_internal_depth  = pDimRgn->LFO2InternalDepth;
348                      pLFO2->ExtController = 4; // MIDI controller 4                      pLFO2->ExtController = 4; // MIDI controller 4
349                        bLFO2Enabled         = (lfo2_internal_depth > 0 || pDimRgn->LFO2ControlDepth > 0);
350                      break;                      break;
351                  default:                  default:
352                      lfo2_internal_depth  = 0;                      lfo2_internal_depth  = 0;
353                      pLFO2->ExtController = 0; // no external controller                      pLFO2->ExtController = 0; // no external controller
354                        bLFO2Enabled         = false;
355              }              }
356              pLFO2->Trigger(pDimRgn->LFO2Frequency,              if (bLFO2Enabled) pLFO2->trigger(pDimRgn->LFO2Frequency,
357                            lfo2_internal_depth,                                               start_level_max,
358                            pDimRgn->LFO2ControlDepth,                                               lfo2_internal_depth,
359                            pEngineChannel->ControllerTable[pLFO2->ExtController],                                               pDimRgn->LFO2ControlDepth,
360                            pDimRgn->LFO2FlipPhase,                                               pDimRgn->LFO2FlipPhase,
361                            pEngine->SampleRate,                                               pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
                           Delay);  
362          }          }
363    
364    
# Line 513  namespace LinuxSampler { namespace gig { Line 369  namespace LinuxSampler { namespace gig {
369                  case ::gig::lfo3_ctrl_internal:                  case ::gig::lfo3_ctrl_internal:
370                      lfo3_internal_depth  = pDimRgn->LFO3InternalDepth;                      lfo3_internal_depth  = pDimRgn->LFO3InternalDepth;
371                      pLFO3->ExtController = 0; // no external controller                      pLFO3->ExtController = 0; // no external controller
372                        bLFO3Enabled         = (lfo3_internal_depth > 0);
373                      break;                      break;
374                  case ::gig::lfo3_ctrl_modwheel:                  case ::gig::lfo3_ctrl_modwheel:
375                      lfo3_internal_depth  = 0;                      lfo3_internal_depth  = 0;
376                      pLFO3->ExtController = 1; // MIDI controller 1                      pLFO3->ExtController = 1; // MIDI controller 1
377                        bLFO3Enabled         = (pDimRgn->LFO3ControlDepth > 0);
378                      break;                      break;
379                  case ::gig::lfo3_ctrl_aftertouch:                  case ::gig::lfo3_ctrl_aftertouch:
380                      lfo3_internal_depth  = 0;                      lfo3_internal_depth  = 0;
381                      pLFO3->ExtController = 0; // TODO: aftertouch not implemented yet                      pLFO3->ExtController = 0; // TODO: aftertouch not implemented yet
382                        bLFO3Enabled         = false; // see TODO comment in line above
383                      break;                      break;
384                  case ::gig::lfo3_ctrl_internal_modwheel:                  case ::gig::lfo3_ctrl_internal_modwheel:
385                      lfo3_internal_depth  = pDimRgn->LFO3InternalDepth;                      lfo3_internal_depth  = pDimRgn->LFO3InternalDepth;
386                      pLFO3->ExtController = 1; // MIDI controller 1                      pLFO3->ExtController = 1; // MIDI controller 1
387                        bLFO3Enabled         = (lfo3_internal_depth > 0 || pDimRgn->LFO3ControlDepth > 0);
388                      break;                      break;
389                  case ::gig::lfo3_ctrl_internal_aftertouch:                  case ::gig::lfo3_ctrl_internal_aftertouch:
390                      lfo3_internal_depth  = pDimRgn->LFO3InternalDepth;                      lfo3_internal_depth  = pDimRgn->LFO3InternalDepth;
391                      pLFO1->ExtController = 0; // TODO: aftertouch not implemented yet                      pLFO1->ExtController = 0; // TODO: aftertouch not implemented yet
392                        bLFO3Enabled         = (lfo3_internal_depth > 0 /*|| pDimRgn->LFO3ControlDepth > 0*/); // see TODO comment in line above
393                      break;                      break;
394                  default:                  default:
395                      lfo3_internal_depth  = 0;                      lfo3_internal_depth  = 0;
396                      pLFO3->ExtController = 0; // no external controller                      pLFO3->ExtController = 0; // no external controller
397                        bLFO3Enabled         = false;
398              }              }
399              pLFO3->Trigger(pDimRgn->LFO3Frequency,              if (bLFO3Enabled) pLFO3->trigger(pDimRgn->LFO3Frequency,
400                            lfo3_internal_depth,                                               start_level_mid,
401                            pDimRgn->LFO3ControlDepth,                                               lfo3_internal_depth,
402                            pEngineChannel->ControllerTable[pLFO3->ExtController],                                               pDimRgn->LFO3ControlDepth,
403                            false,                                               false,
404                            pEngine->SampleRate,                                               pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
                           Delay);  
405          }          }
406    
407    
# Line 613  namespace LinuxSampler { namespace gig { Line 474  namespace LinuxSampler { namespace gig {
474              #endif // CONFIG_OVERRIDE_RESONANCE_CTRL              #endif // CONFIG_OVERRIDE_RESONANCE_CTRL
475    
476              #ifndef CONFIG_OVERRIDE_FILTER_TYPE              #ifndef CONFIG_OVERRIDE_FILTER_TYPE
477              FilterLeft.SetType(pDimRgn->VCFType);              finalSynthesisParameters.filterLeft.SetType(pDimRgn->VCFType);
478              FilterRight.SetType(pDimRgn->VCFType);              finalSynthesisParameters.filterRight.SetType(pDimRgn->VCFType);
479              #else // override filter type              #else // override filter type
480              FilterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE);              FilterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE);
481              FilterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE);              FilterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE);
# Line 624  namespace LinuxSampler { namespace gig { Line 485  namespace LinuxSampler { namespace gig {
485              VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller];              VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller];
486    
487              // calculate cutoff frequency              // calculate cutoff frequency
488              float cutoff = (!VCFCutoffCtrl.controller)              float cutoff = pDimRgn->GetVelocityCutoff(itNoteOnEvent->Param.Note.Velocity);
489                  ? exp((float) (127 - itNoteOnEvent->Param.Note.Velocity) * (float) pDimRgn->VCFVelocityScale * 6.2E-5f * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MAX              if (pDimRgn->VCFKeyboardTracking) {
490                  : exp((float) VCFCutoffCtrl.value * 0.00787402f * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MAX;                  cutoff *= exp((itNoteOnEvent->Param.Note.Key - pDimRgn->VCFKeyboardTrackingBreakpoint) * 0.057762265f); // (ln(2) / 12)
491                }
492                CutoffBase = cutoff;
493    
494                int cvalue;
495                if (VCFCutoffCtrl.controller) {
496                    cvalue = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller];
497                    if (pDimRgn->VCFCutoffControllerInvert) cvalue = 127 - cvalue;
498                    if (cvalue < pDimRgn->VCFVelocityScale) cvalue = pDimRgn->VCFVelocityScale;
499                }
500                else {
501                    cvalue = pDimRgn->VCFCutoff;
502                }
503                cutoff *= float(cvalue) * 0.00787402f; // (1 / 127)
504                if (cutoff > 1.0) cutoff = 1.0;
505                cutoff = exp(cutoff * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MIN;
506    
507              // calculate resonance              // calculate resonance
508              float resonance = (float) VCFResonanceCtrl.value * 0.00787f;   // 0.0..1.0              float resonance = (float) VCFResonanceCtrl.value * 0.00787f;   // 0.0..1.0
# Line 637  namespace LinuxSampler { namespace gig { Line 513  namespace LinuxSampler { namespace gig {
513    
514              VCFCutoffCtrl.fvalue    = cutoff - CONFIG_FILTER_CUTOFF_MIN;              VCFCutoffCtrl.fvalue    = cutoff - CONFIG_FILTER_CUTOFF_MIN;
515              VCFResonanceCtrl.fvalue = resonance;              VCFResonanceCtrl.fvalue = resonance;
   
             FilterUpdateCounter = -1;  
516          }          }
517          else {          else {
518              VCFCutoffCtrl.controller    = 0;              VCFCutoffCtrl.controller    = 0;
# Line 662  namespace LinuxSampler { namespace gig { Line 536  namespace LinuxSampler { namespace gig {
536      void Voice::Render(uint Samples) {      void Voice::Render(uint Samples) {
537    
538          // 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);  
539          SYNTHESIS_MODE_SET_LOOP(SynthesisMode, false);          SYNTHESIS_MODE_SET_LOOP(SynthesisMode, false);
540    
         // Reset the synthesis parameter matrix  
   
         pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngineChannel->GlobalVolume);  
         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);  
         }  
         pLFO1->Process(Samples);  
         pLFO2->Process(Samples);  
         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  
   
541          switch (this->PlaybackState) {          switch (this->PlaybackState) {
542    
543              case playback_state_init:              case playback_state_init:
# Line 707  namespace LinuxSampler { namespace gig { Line 552  namespace LinuxSampler { namespace gig {
552    
553                      if (DiskVoice) {                      if (DiskVoice) {
554                          // check if we reached the allowed limit of the sample RAM cache                          // check if we reached the allowed limit of the sample RAM cache
555                          if (Pos > MaxRAMPos) {                          if (finalSynthesisParameters.dPos > MaxRAMPos) {
556                              dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos));                              dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", finalSynthesisParameters.dPos));
557                              this->PlaybackState = playback_state_disk;                              this->PlaybackState = playback_state_disk;
558                          }                          }
559                      }                      } else if (finalSynthesisParameters.dPos >= pSample->GetCache().Size / pSample->FrameSize) {
                     else if (Pos >= pSample->GetCache().Size / pSample->FrameSize) {  
560                          this->PlaybackState = playback_state_end;                          this->PlaybackState = playback_state_end;
561                      }                      }
562                  }                  }
# Line 727  namespace LinuxSampler { namespace gig { Line 571  namespace LinuxSampler { namespace gig {
571                              KillImmediately();                              KillImmediately();
572                              return;                              return;
573                          }                          }
574                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(Pos) - MaxRAMPos));                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(finalSynthesisParameters.dPos) - MaxRAMPos));
575                          Pos -= int(Pos);                          finalSynthesisParameters.dPos -= int(finalSynthesisParameters.dPos);
576                          RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet                          RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet
577                      }                      }
578    
# Line 749  namespace LinuxSampler { namespace gig { Line 593  namespace LinuxSampler { namespace gig {
593                      // render current audio fragment                      // render current audio fragment
594                      Synthesize(Samples, ptr, Delay);                      Synthesize(Samples, ptr, Delay);
595    
596                      const int iPos = (int) Pos;                      const int iPos = (int) finalSynthesisParameters.dPos;
597                      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
598                      DiskStreamRef.pStream->IncrementReadPos(readSampleWords);                      DiskStreamRef.pStream->IncrementReadPos(readSampleWords);
599                      Pos -= iPos; // just keep fractional part of Pos                      finalSynthesisParameters.dPos -= iPos; // just keep fractional part of playback position
600    
601                      // 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
602                      if (RealSampleWordsLeftToRead >= 0) {                      if (RealSampleWordsLeftToRead >= 0) {
# Line 767  namespace LinuxSampler { namespace gig { Line 611  namespace LinuxSampler { namespace gig {
611                  break;                  break;
612          }          }
613    
614          // Reset synthesis event lists (except VCO, as VCO events apply channel wide currently)          // Reset synthesis event lists
615          pEngineChannel->pSynthesisEvents[Event::destination_vca]->clear();          pEngineChannel->pEvents->clear();
         pEngineChannel->pSynthesisEvents[Event::destination_vcfc]->clear();  
         pEngineChannel->pSynthesisEvents[Event::destination_vcfr]->clear();  
616    
617          // Reset delay          // Reset delay
618          Delay = 0;          Delay = 0;
# Line 778  namespace LinuxSampler { namespace gig { Line 620  namespace LinuxSampler { namespace gig {
620          itTriggerEvent = Pool<Event>::Iterator();          itTriggerEvent = Pool<Event>::Iterator();
621    
622          // If sample stream or release stage finished, kill the voice          // If sample stream or release stage finished, kill the voice
623          if (PlaybackState == playback_state_end || pEG1->GetStage() == EGADSR::stage_end) KillImmediately();          if (PlaybackState == playback_state_end || EG1.getSegmentType() == EGADSR::segment_end) KillImmediately();
624      }      }
625    
626      /**      /**
# Line 786  namespace LinuxSampler { namespace gig { Line 628  namespace LinuxSampler { namespace gig {
628       *  suspended / not running.       *  suspended / not running.
629       */       */
630      void Voice::Reset() {      void Voice::Reset() {
631          pLFO1->Reset();          finalSynthesisParameters.filterLeft.Reset();
632          pLFO2->Reset();          finalSynthesisParameters.filterRight.Reset();
         pLFO3->Reset();  
         FilterLeft.Reset();  
         FilterRight.Reset();  
633          DiskStreamRef.pStream = NULL;          DiskStreamRef.pStream = NULL;
634          DiskStreamRef.hStream = 0;          DiskStreamRef.hStream = 0;
635          DiskStreamRef.State   = Stream::state_unused;          DiskStreamRef.State   = Stream::state_unused;
# Line 801  namespace LinuxSampler { namespace gig { Line 640  namespace LinuxSampler { namespace gig {
640      }      }
641    
642      /**      /**
643       *  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
644       *  audio fragment. Event values will be applied to the synthesis parameter       * for the given time.
      *  matrix.  
645       *       *
646       *  @param Samples - number of samples to be rendered in this audio fragment cycle       * @param itEvent - iterator pointing to the next event to be processed
647         * @param End     - youngest time stamp where processing should be stopped
648       */       */
649      void Voice::ProcessEvents(uint Samples) {      void Voice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) {
650            for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
651          // dispatch control change events              if (itEvent->Type == Event::type_release) {
652          RTList<Event>::Iterator itCCEvent = pEngineChannel->pCCEvents->first();                  EG1.update(EGADSR::event_release, finalSynthesisParameters.dPos, finalSynthesisParameters.fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
653          if (Delay) { // skip events that happened before this voice was triggered                  EG2.update(EGADSR::event_release, finalSynthesisParameters.dPos, finalSynthesisParameters.fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
654              while (itCCEvent && itCCEvent->FragmentPos() <= Delay) ++itCCEvent;              } else if (itEvent->Type == Event::type_cancel_release) {
655          }                  EG1.update(EGADSR::event_cancel_release, finalSynthesisParameters.dPos, finalSynthesisParameters.fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
656          while (itCCEvent) {                  EG2.update(EGADSR::event_cancel_release, finalSynthesisParameters.dPos, finalSynthesisParameters.fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
             if (itCCEvent->Param.CC.Controller) { // if valid MIDI controller  
                 if (itCCEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {  
                     *pEngineChannel->pSynthesisEvents[Event::destination_vcfc]->allocAppend() = *itCCEvent;  
                 }  
                 if (itCCEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {  
                     *pEngineChannel->pSynthesisEvents[Event::destination_vcfr]->allocAppend() = *itCCEvent;  
                 }  
                 if (itCCEvent->Param.CC.Controller == pLFO1->ExtController) {  
                     pLFO1->SendEvent(itCCEvent);  
                 }  
                 if (itCCEvent->Param.CC.Controller == pLFO2->ExtController) {  
                     pLFO2->SendEvent(itCCEvent);  
                 }  
                 if (itCCEvent->Param.CC.Controller == pLFO3->ExtController) {  
                     pLFO3->SendEvent(itCCEvent);  
                 }  
                 if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange &&  
                     itCCEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) { // if crossfade event  
                     *pEngineChannel->pSynthesisEvents[Event::destination_vca]->allocAppend() = *itCCEvent;  
                 }  
657              }              }
   
             ++itCCEvent;  
658          }          }
659        }
660    
661        /**
662          // process pitch events       * Process given list of MIDI control change and pitch bend events for
663          {       * the given time.
664              RTList<Event>* pVCOEventList = pEngineChannel->pSynthesisEvents[Event::destination_vco];       *
665              RTList<Event>::Iterator itVCOEvent = pVCOEventList->first();       * @param itEvent - iterator pointing to the next event to be processed
666              if (Delay) { // skip events that happened before this voice was triggered       * @param End     - youngest time stamp where processing should be stopped
667                  while (itVCOEvent && itVCOEvent->FragmentPos() <= Delay) ++itVCOEvent;       */
668              }      void Voice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) {
669              // apply old pitchbend value until first pitch event occurs          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
670              if (this->PitchBend != 1.0) {              if (itEvent->Type == Event::type_control_change &&
671                  uint end = (itVCOEvent) ? itVCOEvent->FragmentPos() : Samples;                  itEvent->Param.CC.Controller) { // if (valid) MIDI control change event
672                  for (uint i = Delay; i < end; i++) {                  if (itEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {
673                      pEngine->pSynthesisParameters[Event::destination_vco][i] *= this->PitchBend;                      processCutoffEvent(itEvent);
674                    }
675                    if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
676                        processResonanceEvent(itEvent);
677                  }                  }
678              }                  if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
679              float pitch;                      pLFO1->update(itEvent->Param.CC.Value);
             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;  
680                  }                  }
681                    if (itEvent->Param.CC.Controller == pLFO2->ExtController) {
682                  itVCOEvent = itNextVCOEvent;                      pLFO2->update(itEvent->Param.CC.Value);
             }  
             if (!pVCOEventList->isEmpty()) {  
                 this->PitchBend = pitch;  
                 SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true);  
                 SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false);  
             }  
         }  
   
         // process volume / attenuation events (TODO: we only handle and _expect_ crossfade events here ATM !)  
         {  
             RTList<Event>* pVCAEventList = pEngineChannel->pSynthesisEvents[Event::destination_vca];  
             RTList<Event>::Iterator itVCAEvent = pVCAEventList->first();  
             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);  
   
                 float effective_volume = crossfadevolume * this->Volume * pEngineChannel->GlobalVolume;  
   
                 // apply volume value to the volume parameter sequence  
                 for (uint i = itVCAEvent->FragmentPos(); i < end; i++) {  
                     pEngine->pSynthesisParameters[Event::destination_vca][i] = effective_volume;  
683                  }                  }
684                    if (itEvent->Param.CC.Controller == pLFO3->ExtController) {
685                  itVCAEvent = itNextVCAEvent;                      pLFO3->update(itEvent->Param.CC.Value);
             }  
             if (!pVCAEventList->isEmpty()) this->CrossfadeVolume = crossfadevolume;  
         }  
   
         // process filter cutoff events  
         {  
             RTList<Event>* pCutoffEventList = pEngineChannel->pSynthesisEvents[Event::destination_vcfc];  
             RTList<Event>::Iterator itCutoffEvent = pCutoffEventList->first();  
             if (Delay) { // skip events that happened before this voice was triggered  
                 while (itCutoffEvent && itCutoffEvent->FragmentPos() <= Delay) ++itCutoffEvent;  
             }  
             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;  
686                  }                  }
687                    if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange &&
688                  itCutoffEvent = itNextCutoffEvent;                      itEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) {
689              }                      processCrossFadeEvent(itEvent);
             if (!pCutoffEventList->isEmpty()) VCFCutoffCtrl.fvalue = cutoff; // needed for initialization of parameter matrix next time  
         }  
   
         // process filter resonance events  
         {  
             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;  
690                  }                  }
691                } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event
692                  itResonanceEvent = itNextResonanceEvent;                  processPitchEvent(itEvent);
693              }              }
             if (!pResonanceEventList->isEmpty()) VCFResonanceCtrl.fvalue = pResonanceEventList->last()->Param.CC.Value * 0.00787f; // needed for initialization of parameter matrix next time  
694          }          }
695      }      }
696    
697      /**      void Voice::processPitchEvent(RTList<Event>::Iterator& itEvent) {
698       * Calculate all necessary, final biquad filter parameters.          const float pitch = RTMath::CentsToFreqRatio(((double) itEvent->Param.Pitch.Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents
699       *          finalSynthesisParameters.fFinalPitch *= pitch;
700       * @param Samples - number of samples to be rendered in this audio fragment cycle          PitchBend = pitch;
701       */      }
     void Voice::CalculateBiquadParameters(uint Samples) {  
         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);  
                 }  
             }  
702    
703              //same as 'pEngine->pBasicFilterParameters[i] = bqbase;'      void Voice::processCrossFadeEvent(RTList<Event>::Iterator& itEvent) {
704              bq    = (float*) &pEngine->pBasicFilterParameters[i];          CrossfadeVolume = CrossfadeAttenuation(itEvent->Param.CC.Value);
705              bq[0] = bqbase.b0;          #if CONFIG_PROCESS_MUTED_CHANNELS
706              bq[1] = bqbase.b1;          const float effectiveVolume = CrossfadeVolume * Volume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume);
707              bq[2] = bqbase.b2;          #else
708              bq[3] = bqbase.a1;          const float effectiveVolume = CrossfadeVolume * Volume * pEngineChannel->GlobalVolume;
709              bq[4] = bqbase.a2;          #endif
710            fFinalVolume = effectiveVolume;
711              // same as 'pEngine->pMainFilterParameters[i] = bqmain;'      }
712              bq    = (float*) &pEngine->pMainFilterParameters[i];  
713              bq[0] = bqmain.b0;      void Voice::processCutoffEvent(RTList<Event>::Iterator& itEvent) {
714              bq[1] = bqmain.b1;          int ccvalue = itEvent->Param.CC.Value;
715              bq[2] = bqmain.b2;          if (VCFCutoffCtrl.value == ccvalue) return;
716              bq[3] = bqmain.a1;          VCFCutoffCtrl.value == ccvalue;
717              bq[4] = bqmain.a2;          if (pDimRgn->VCFCutoffControllerInvert)  ccvalue = 127 - ccvalue;
718          }          if (ccvalue < pDimRgn->VCFVelocityScale) ccvalue = pDimRgn->VCFVelocityScale;
719            float cutoff = CutoffBase * float(ccvalue) * 0.00787402f; // (1 / 127)
720            if (cutoff > 1.0) cutoff = 1.0;
721            cutoff = exp(cutoff * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MIN - CONFIG_FILTER_CUTOFF_MIN;
722            VCFCutoffCtrl.fvalue = cutoff; // needed for initialization of fFinalCutoff next time
723            fFinalCutoff = cutoff;
724        }
725    
726        void Voice::processResonanceEvent(RTList<Event>::Iterator& itEvent) {
727            // convert absolute controller value to differential
728            const int ctrldelta = itEvent->Param.CC.Value - VCFResonanceCtrl.value;
729            VCFResonanceCtrl.value = itEvent->Param.CC.Value;
730            const float resonancedelta = (float) ctrldelta * 0.00787f; // 0.0..1.0
731            fFinalResonance += resonancedelta;
732            // needed for initialization of parameter
733            VCFResonanceCtrl.fvalue = itEvent->Param.CC.Value * 0.00787f;
734      }      }
735    
736      /**      /**
# Line 1022  namespace LinuxSampler { namespace gig { Line 742  namespace LinuxSampler { namespace gig {
742       *  @param Skip    - number of sample points to skip in output buffer       *  @param Skip    - number of sample points to skip in output buffer
743       */       */
744      void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {      void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
745          RunSynthesisFunction(SynthesisMode, *this, Samples, pSrc, Skip);          finalSynthesisParameters.pOutLeft  = &pEngineChannel->pOutputLeft[Skip];
746            finalSynthesisParameters.pOutRight = &pEngineChannel->pOutputRight[Skip];
747            finalSynthesisParameters.pSrc      = pSrc;
748    
749            RTList<Event>::Iterator itCCEvent = pEngineChannel->pEvents->first();
750            RTList<Event>::Iterator itNoteEvent = pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents->first();
751    
752            if (Skip) { // skip events that happened before this voice was triggered
753                while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;
754                while (itNoteEvent && itNoteEvent->FragmentPos() <= Skip) ++itNoteEvent;
755            }
756    
757            uint i = Skip;
758            while (i < Samples) {
759                int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples);
760    
761                // initialize all final synthesis parameters
762                finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend;
763                #if CONFIG_PROCESS_MUTED_CHANNELS
764                fFinalVolume = this->Volume * this->CrossfadeVolume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume);
765                #else
766                fFinalVolume = this->Volume * this->CrossfadeVolume * pEngineChannel->GlobalVolume;
767                #endif
768                fFinalCutoff    = VCFCutoffCtrl.fvalue;
769                fFinalResonance = VCFResonanceCtrl.fvalue;
770    
771                // process MIDI control change and pitchbend events for this subfragment
772                processCCEvents(itCCEvent, iSubFragmentEnd);
773    
774                // process transition events (note on, note off & sustain pedal)
775                processTransitionEvents(itNoteEvent, iSubFragmentEnd);
776    
777                // process envelope generators
778                switch (EG1.getSegmentType()) {
779                    case EGADSR::segment_lin:
780                        fFinalVolume *= EG1.processLin();
781                        break;
782                    case EGADSR::segment_exp:
783                        fFinalVolume *= EG1.processExp();
784                        break;
785                    case EGADSR::segment_end:
786                        fFinalVolume *= EG1.getLevel();
787                        break; // noop
788                }
789                switch (EG2.getSegmentType()) {
790                    case EGADSR::segment_lin:
791                        fFinalCutoff *= EG2.processLin();
792                        break;
793                    case EGADSR::segment_exp:
794                        fFinalCutoff *= EG2.processExp();
795                        break;
796                    case EGADSR::segment_end:
797                        fFinalCutoff *= EG2.getLevel();
798                        break; // noop
799                }
800                if (EG3.active()) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(EG3.render());
801    
802                // process low frequency oscillators
803                if (bLFO1Enabled) fFinalVolume *= pLFO1->render();
804                if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();
805                if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
806    
807                // if filter enabled then update filter coefficients
808                if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) {
809                    finalSynthesisParameters.filterLeft.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate);
810                    finalSynthesisParameters.filterRight.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate);
811                }
812    
813                // do we need resampling?
814                const float __PLUS_ONE_CENT  = 1.000577789506554859250142541782224725466f;
815                const float __MINUS_ONE_CENT = 0.9994225441413807496009516495583113737666f;
816                const bool bResamplingRequired = !(finalSynthesisParameters.fFinalPitch <= __PLUS_ONE_CENT &&
817                                                   finalSynthesisParameters.fFinalPitch >= __MINUS_ONE_CENT);
818                SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, bResamplingRequired);
819    
820                // prepare final synthesis parameters structure
821                finalSynthesisParameters.fFinalVolumeLeft  = fFinalVolume * PanLeft;
822                finalSynthesisParameters.fFinalVolumeRight = fFinalVolume * PanRight;
823                finalSynthesisParameters.uiToGo            = iSubFragmentEnd - i;
824    
825                // render audio for one subfragment
826                RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop);
827    
828                // increment envelopes' positions
829                if (EG1.active()) {
830                    EG1.increment(1);
831                    if (!EG1.toStageEndLeft()) EG1.update(EGADSR::event_stage_end, finalSynthesisParameters.dPos, finalSynthesisParameters.fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
832                }
833                if (EG2.active()) {
834                    EG2.increment(1);
835                    if (!EG2.toStageEndLeft()) EG2.update(EGADSR::event_stage_end, finalSynthesisParameters.dPos, finalSynthesisParameters.fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
836                }
837                EG3.increment(1);
838                if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached
839    
840                i = iSubFragmentEnd;
841            }
842      }      }
843    
844      /**      /**

Legend:
Removed from v.614  
changed lines
  Added in v.770

  ViewVC Help
Powered by ViewVC