/[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 233 by schoenebeck, Tue Sep 7 09:32:21 2004 UTC revision 563 by schoenebeck, Sun May 22 20:43:32 2005 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                              *
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 22  Line 23 
23    
24  #include "EGADSR.h"  #include "EGADSR.h"
25  #include "Manipulator.h"  #include "Manipulator.h"
26    #include "../../common/Features.h"
27    #include "Synthesizer.h"
28    
29  #include "Voice.h"  #include "Voice.h"
30    
31  namespace LinuxSampler { namespace gig {  namespace LinuxSampler { namespace gig {
32    
     // TODO: no support for crossfades yet  
   
33      const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff());      const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff());
34    
35      const int Voice::FILTER_UPDATE_MASK(CalculateFilterUpdateMask());      const int Voice::FILTER_UPDATE_MASK(CalculateFilterUpdateMask());
36    
37      float Voice::CalculateFilterCutoffCoeff() {      float Voice::CalculateFilterCutoffCoeff() {
38          return log(FILTER_CUTOFF_MIN / FILTER_CUTOFF_MAX);          return log(CONFIG_FILTER_CUTOFF_MIN / CONFIG_FILTER_CUTOFF_MAX);
39      }      }
40    
41      int Voice::CalculateFilterUpdateMask() {      int Voice::CalculateFilterUpdateMask() {
42          if (FILTER_UPDATE_PERIOD <= 0) return 0;          if (CONFIG_FILTER_UPDATE_STEPS <= 0) return 0;
43          int power_of_two;          int power_of_two;
44          for (power_of_two = 0; 1<<power_of_two < FILTER_UPDATE_PERIOD; power_of_two++);          for (power_of_two = 0; 1<<power_of_two < CONFIG_FILTER_UPDATE_STEPS; power_of_two++);
45          return (1 << power_of_two) - 1;          return (1 << power_of_two) - 1;
46      }      }
47    
48      Voice::Voice() {      Voice::Voice() {
49          pEngine     = NULL;          pEngine     = NULL;
50          pDiskThread = NULL;          pDiskThread = NULL;
51          Active = false;          PlaybackState = playback_state_end;
52          pEG1   = NULL;          pEG1   = NULL;
53          pEG2   = NULL;          pEG2   = NULL;
54          pEG3   = NULL;          pEG3   = NULL;
# Line 57  namespace LinuxSampler { namespace gig { Line 58  namespace LinuxSampler { namespace gig {
58          pLFO1  = NULL;          pLFO1  = NULL;
59          pLFO2  = NULL;          pLFO2  = NULL;
60          pLFO3  = NULL;          pLFO3  = NULL;
61            KeyGroup = 0;
62            SynthesisMode = 0; // set all mode bits to 0 first
63            // select synthesis implementation (currently either pure C++ or MMX+SSE(1))
64            #if ARCH_X86
65            SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, Features::supportsMMX() && Features::supportsSSE());
66            #else
67            SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false);
68            #endif
69            SYNTHESIS_MODE_SET_PROFILING(SynthesisMode, true);
70    
71            FilterLeft.Reset();
72            FilterRight.Reset();
73      }      }
74    
75      Voice::~Voice() {      Voice::~Voice() {
# Line 104  namespace LinuxSampler { namespace gig { Line 117  namespace LinuxSampler { namespace gig {
117       *  Initializes and triggers the voice, a disk stream will be launched if       *  Initializes and triggers the voice, a disk stream will be launched if
118       *  needed.       *  needed.
119       *       *
120       *  @param pNoteOnEvent - event that caused triggering of this voice       *  @param pEngineChannel       - engine channel on which this voice was ordered
121       *  @param PitchBend    - MIDI detune factor (-8192 ... +8191)       *  @param itNoteOnEvent        - event that caused triggering of this voice
122       *  @param pInstrument  - points to the loaded instrument which provides sample wave(s) and articulation data       *  @param PitchBend            - MIDI detune factor (-8192 ... +8191)
123       *  @param iLayer       - layer number this voice refers to (only if this is a layered sound of course)       *  @param pInstrument          - points to the loaded instrument which provides sample wave(s) and articulation data
124       *  @returns            0 on success, a value < 0 if something failed       *  @param iLayer               - layer number this voice refers to (only if this is a layered sound of course)
125         *  @param ReleaseTriggerVoice  - if this new voice is a release trigger voice (optional, default = false)
126         *  @param VoiceStealingAllowed - wether the voice is allowed to steal voices for further subvoices
127         *  @returns 0 on success, a value < 0 if the voice wasn't triggered
128         *           (either due to an error or e.g. because no region is
129         *           defined for the given key)
130       */       */
131      int Voice::Trigger(Event* pNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument, int iLayer) {      int Voice::Trigger(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealingAllowed) {
132            this->pEngineChannel = pEngineChannel;
133          if (!pInstrument) {          if (!pInstrument) {
134             dmsg(1,("voice::trigger: !pInstrument\n"));             dmsg(1,("voice::trigger: !pInstrument\n"));
135             exit(EXIT_FAILURE);             exit(EXIT_FAILURE);
136          }          }
137            #if CONFIG_DEVMODE
138            if (itNoteOnEvent->FragmentPos() > pEngine->MaxSamplesPerCycle) { // just a sanity check for debugging
139                dmsg(1,("Voice::Trigger(): ERROR, TriggerDelay > Totalsamples\n"));
140            }
141            #endif // CONFIG_DEVMODE
142    
143          Active          = true;          Type            = type_normal;
144          MIDIKey         = pNoteOnEvent->Key;          MIDIKey         = itNoteOnEvent->Param.Note.Key;
145          pRegion         = pInstrument->GetRegion(MIDIKey);          pRegion         = pInstrument->GetRegion(MIDIKey);
146          PlaybackState   = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed          PlaybackState   = playback_state_init; // mark voice as triggered, but no audio rendered yet
147          Pos             = 0;          Delay           = itNoteOnEvent->FragmentPos();
148          Delay           = pNoteOnEvent->FragmentPos();          itTriggerEvent  = itNoteOnEvent;
149          pTriggerEvent   = pNoteOnEvent;          itKillEvent     = Pool<Event>::Iterator();
150    
151          if (!pRegion) {          if (!pRegion) {
152              std::cerr << "gig::Voice: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush;              dmsg(4, ("gig::Voice: No Region defined for MIDI key %d\n", MIDIKey));
             Kill();  
153              return -1;              return -1;
154          }          }
155    
156            // only mark the first voice of a layered voice (group) to be in a
157            // key group, so the layered voices won't kill each other
158            KeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0;
159    
160          // get current dimension values to select the right dimension region          // get current dimension values to select the right dimension region
161          //FIXME: controller values for selecting the dimension region here are currently not sample accurate          //FIXME: controller values for selecting the dimension region here are currently not sample accurate
162          uint DimValues[5] = {0,0,0,0,0};          uint DimValues[8] = { 0 };
163          for (int i = pRegion->Dimensions - 1; i >= 0; i--) {          for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
164              switch (pRegion->pDimensionDefinitions[i].dimension) {              switch (pRegion->pDimensionDefinitions[i].dimension) {
165                  case ::gig::dimension_samplechannel:                  case ::gig::dimension_samplechannel:
# Line 140  namespace LinuxSampler { namespace gig { Line 167  namespace LinuxSampler { namespace gig {
167                      break;                      break;
168                  case ::gig::dimension_layer:                  case ::gig::dimension_layer:
169                      DimValues[i] = iLayer;                      DimValues[i] = iLayer;
                     // if this is the 1st layer then spawn further voices for all the other layers  
                     if (iLayer == 0)  
                         for (int iNewLayer = 1; iNewLayer < pRegion->pDimensionDefinitions[i].zones; iNewLayer++)  
                             pEngine->LaunchVoice(pNoteOnEvent, iNewLayer);  
170                      break;                      break;
171                  case ::gig::dimension_velocity:                  case ::gig::dimension_velocity:
172                      DimValues[i] = pNoteOnEvent->Velocity;                      DimValues[i] = itNoteOnEvent->Param.Note.Velocity;
173                      break;                      break;
174                  case ::gig::dimension_channelaftertouch:                  case ::gig::dimension_channelaftertouch:
175                      DimValues[i] = 0; //TODO: we currently ignore this dimension                      DimValues[i] = 0; //TODO: we currently ignore this dimension
176                      break;                      break;
177                  case ::gig::dimension_releasetrigger:                  case ::gig::dimension_releasetrigger:
178                      DimValues[i] = 0; //TODO: we currently ignore this dimension                      Type = (ReleaseTriggerVoice) ? type_release_trigger : (!iLayer) ? type_release_trigger_required : type_normal;
179                        DimValues[i] = (uint) ReleaseTriggerVoice;
180                      break;                      break;
181                  case ::gig::dimension_keyboard:                  case ::gig::dimension_keyboard:
182                      DimValues[i] = (uint) pNoteOnEvent->Key;                      DimValues[i] = (uint) pEngineChannel->CurrentKeyDimension;
183                        break;
184                    case ::gig::dimension_roundrobin:
185                        DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on
186                        break;
187                    case ::gig::dimension_random:
188                        pEngine->RandomSeed = pEngine->RandomSeed * 1103515245 + 12345; // classic pseudo random number generator
189                        DimValues[i] = (uint) pEngine->RandomSeed >> (32 - pRegion->pDimensionDefinitions[i].bits); // highest bits are most random
190                      break;                      break;
191                  case ::gig::dimension_modwheel:                  case ::gig::dimension_modwheel:
192                      DimValues[i] = pEngine->ControllerTable[1];                      DimValues[i] = pEngineChannel->ControllerTable[1];
193                      break;                      break;
194                  case ::gig::dimension_breath:                  case ::gig::dimension_breath:
195                      DimValues[i] = pEngine->ControllerTable[2];                      DimValues[i] = pEngineChannel->ControllerTable[2];
196                      break;                      break;
197                  case ::gig::dimension_foot:                  case ::gig::dimension_foot:
198                      DimValues[i] = pEngine->ControllerTable[4];                      DimValues[i] = pEngineChannel->ControllerTable[4];
199                      break;                      break;
200                  case ::gig::dimension_portamentotime:                  case ::gig::dimension_portamentotime:
201                      DimValues[i] = pEngine->ControllerTable[5];                      DimValues[i] = pEngineChannel->ControllerTable[5];
202                      break;                      break;
203                  case ::gig::dimension_effect1:                  case ::gig::dimension_effect1:
204                      DimValues[i] = pEngine->ControllerTable[12];                      DimValues[i] = pEngineChannel->ControllerTable[12];
205                      break;                      break;
206                  case ::gig::dimension_effect2:                  case ::gig::dimension_effect2:
207                      DimValues[i] = pEngine->ControllerTable[13];                      DimValues[i] = pEngineChannel->ControllerTable[13];
208                      break;                      break;
209                  case ::gig::dimension_genpurpose1:                  case ::gig::dimension_genpurpose1:
210                      DimValues[i] = pEngine->ControllerTable[16];                      DimValues[i] = pEngineChannel->ControllerTable[16];
211                      break;                      break;
212                  case ::gig::dimension_genpurpose2:                  case ::gig::dimension_genpurpose2:
213                      DimValues[i] = pEngine->ControllerTable[17];                      DimValues[i] = pEngineChannel->ControllerTable[17];
214                      break;                      break;
215                  case ::gig::dimension_genpurpose3:                  case ::gig::dimension_genpurpose3:
216                      DimValues[i] = pEngine->ControllerTable[18];                      DimValues[i] = pEngineChannel->ControllerTable[18];
217                      break;                      break;
218                  case ::gig::dimension_genpurpose4:                  case ::gig::dimension_genpurpose4:
219                      DimValues[i] = pEngine->ControllerTable[19];                      DimValues[i] = pEngineChannel->ControllerTable[19];
220                      break;                      break;
221                  case ::gig::dimension_sustainpedal:                  case ::gig::dimension_sustainpedal:
222                      DimValues[i] = pEngine->ControllerTable[64];                      DimValues[i] = pEngineChannel->ControllerTable[64];
223                      break;                      break;
224                  case ::gig::dimension_portamento:                  case ::gig::dimension_portamento:
225                      DimValues[i] = pEngine->ControllerTable[65];                      DimValues[i] = pEngineChannel->ControllerTable[65];
226                      break;                      break;
227                  case ::gig::dimension_sostenutopedal:                  case ::gig::dimension_sostenutopedal:
228                      DimValues[i] = pEngine->ControllerTable[66];                      DimValues[i] = pEngineChannel->ControllerTable[66];
229                      break;                      break;
230                  case ::gig::dimension_softpedal:                  case ::gig::dimension_softpedal:
231                      DimValues[i] = pEngine->ControllerTable[67];                      DimValues[i] = pEngineChannel->ControllerTable[67];
232                      break;                      break;
233                  case ::gig::dimension_genpurpose5:                  case ::gig::dimension_genpurpose5:
234                      DimValues[i] = pEngine->ControllerTable[80];                      DimValues[i] = pEngineChannel->ControllerTable[80];
235                      break;                      break;
236                  case ::gig::dimension_genpurpose6:                  case ::gig::dimension_genpurpose6:
237                      DimValues[i] = pEngine->ControllerTable[81];                      DimValues[i] = pEngineChannel->ControllerTable[81];
238                      break;                      break;
239                  case ::gig::dimension_genpurpose7:                  case ::gig::dimension_genpurpose7:
240                      DimValues[i] = pEngine->ControllerTable[82];                      DimValues[i] = pEngineChannel->ControllerTable[82];
241                      break;                      break;
242                  case ::gig::dimension_genpurpose8:                  case ::gig::dimension_genpurpose8:
243                      DimValues[i] = pEngine->ControllerTable[83];                      DimValues[i] = pEngineChannel->ControllerTable[83];
244                      break;                      break;
245                  case ::gig::dimension_effect1depth:                  case ::gig::dimension_effect1depth:
246                      DimValues[i] = pEngine->ControllerTable[91];                      DimValues[i] = pEngineChannel->ControllerTable[91];
247                      break;                      break;
248                  case ::gig::dimension_effect2depth:                  case ::gig::dimension_effect2depth:
249                      DimValues[i] = pEngine->ControllerTable[92];                      DimValues[i] = pEngineChannel->ControllerTable[92];
250                      break;                      break;
251                  case ::gig::dimension_effect3depth:                  case ::gig::dimension_effect3depth:
252                      DimValues[i] = pEngine->ControllerTable[93];                      DimValues[i] = pEngineChannel->ControllerTable[93];
253                      break;                      break;
254                  case ::gig::dimension_effect4depth:                  case ::gig::dimension_effect4depth:
255                      DimValues[i] = pEngine->ControllerTable[94];                      DimValues[i] = pEngineChannel->ControllerTable[94];
256                      break;                      break;
257                  case ::gig::dimension_effect5depth:                  case ::gig::dimension_effect5depth:
258                      DimValues[i] = pEngine->ControllerTable[95];                      DimValues[i] = pEngineChannel->ControllerTable[95];
259                      break;                      break;
260                  case ::gig::dimension_none:                  case ::gig::dimension_none:
261                      std::cerr << "gig::Voice::Trigger() Error: dimension=none\n" << std::flush;                      std::cerr << "gig::Voice::Trigger() Error: dimension=none\n" << std::flush;
# Line 233  namespace LinuxSampler { namespace gig { Line 264  namespace LinuxSampler { namespace gig {
264                      std::cerr << "gig::Voice::Trigger() Error: Unknown dimension\n" << std::flush;                      std::cerr << "gig::Voice::Trigger() Error: Unknown dimension\n" << std::flush;
265              }              }
266          }          }
267          ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);          pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
268    
269          pSample = pDimRgn->pSample; // sample won't change until the voice is finished          pSample = pDimRgn->pSample; // sample won't change until the voice is finished
270            if (!pSample || !pSample->SamplesTotal) return -1; // no need to continue if sample is silent
271    
272            // select channel mode (mono or stereo)
273            SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2);
274    
275            // get starting crossfade volume level
276            switch (pDimRgn->AttenuationController.type) {
277                case ::gig::attenuation_ctrl_t::type_channelaftertouch:
278                    CrossfadeVolume = 1.0f; //TODO: aftertouch not supported yet
279                    break;
280                case ::gig::attenuation_ctrl_t::type_velocity:
281                    CrossfadeVolume = CrossfadeAttenuation(itNoteOnEvent->Param.Note.Velocity);
282                    break;
283                case ::gig::attenuation_ctrl_t::type_controlchange: //FIXME: currently not sample accurate
284                    CrossfadeVolume = CrossfadeAttenuation(pEngineChannel->ControllerTable[pDimRgn->AttenuationController.controller_number]);
285                    break;
286                case ::gig::attenuation_ctrl_t::type_none: // no crossfade defined
287                default:
288                    CrossfadeVolume = 1.0f;
289            }
290    
291            PanLeft  = 1.0f - float(RTMath::Max(pDimRgn->Pan, 0)) /  63.0f;
292            PanRight = 1.0f - float(RTMath::Min(pDimRgn->Pan, 0)) / -64.0f;
293    
294            Pos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
295    
296          // 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
297          long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;          long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;
298          DiskVoice          = cachedsamples < pSample->SamplesTotal;          DiskVoice          = cachedsamples < pSample->SamplesTotal;
299    
300          if (DiskVoice) { // voice to be streamed from disk          if (DiskVoice) { // voice to be streamed from disk
301              MaxRAMPos = cachedsamples - (pEngine->MaxSamplesPerCycle << 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)
302    
303              // 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
304              if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {              if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {
# Line 253  namespace LinuxSampler { namespace gig { Line 309  namespace LinuxSampler { namespace gig {
309    
310              if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {              if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {
311                  dmsg(1,("Disk stream order failed!\n"));                  dmsg(1,("Disk stream order failed!\n"));
312                  Kill();                  KillImmediately();
313                  return -1;                  return -1;
314              }              }
315              dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s)\n", cachedsamples, pSample->SamplesTotal, MaxRAMPos, (RAMLoop) ? "yes" : "no"));              dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s)\n", cachedsamples, pSample->SamplesTotal, MaxRAMPos, (RAMLoop) ? "yes" : "no"));
# Line 271  namespace LinuxSampler { namespace gig { Line 327  namespace LinuxSampler { namespace gig {
327    
328          // calculate initial pitch value          // calculate initial pitch value
329          {          {
330              double pitchbasecents = pDimRgn->FineTune * 10;              double pitchbasecents = pDimRgn->FineTune + (int) pEngine->ScaleTuning[MIDIKey % 12];
331              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;
332              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate()));              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate()));
333              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
334          }          }
335    
336            Volume = pDimRgn->GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity) / 32768.0f; // we downscale by 32768 to convert from int16 value range to DSP value range (which is -1.0..1.0)
337    
338          Volume = pDimRgn->GetVelocityAttenuation(pNoteOnEvent->Velocity) / 32768.0f; // we downscale by 32768 to convert from int16 value range to DSP value range (which is -1.0..1.0)          Volume *= pDimRgn->SampleAttenuation;
   
339    
340          // setup EG 1 (VCA EG)          // setup EG 1 (VCA EG)
341          {          {
# Line 293  namespace LinuxSampler { namespace gig { Line 349  namespace LinuxSampler { namespace gig {
349                      eg1controllervalue = 0; // TODO: aftertouch not yet supported                      eg1controllervalue = 0; // TODO: aftertouch not yet supported
350                      break;                      break;
351                  case ::gig::eg1_ctrl_t::type_velocity:                  case ::gig::eg1_ctrl_t::type_velocity:
352                      eg1controllervalue = pNoteOnEvent->Velocity;                      eg1controllervalue = itNoteOnEvent->Param.Note.Velocity;
353                      break;                      break;
354                  case ::gig::eg1_ctrl_t::type_controlchange: // MIDI control change controller                  case ::gig::eg1_ctrl_t::type_controlchange: // MIDI control change controller
355                      eg1controllervalue = pEngine->ControllerTable[pDimRgn->EG1Controller.controller_number];                      eg1controllervalue = pEngineChannel->ControllerTable[pDimRgn->EG1Controller.controller_number];
356                      break;                      break;
357              }              }
358              if (pDimRgn->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue;              if (pDimRgn->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue;
# Line 315  namespace LinuxSampler { namespace gig { Line 371  namespace LinuxSampler { namespace gig {
371                            pDimRgn->EG1InfiniteSustain,                            pDimRgn->EG1InfiniteSustain,
372                            pDimRgn->EG1Sustain,                            pDimRgn->EG1Sustain,
373                            pDimRgn->EG1Release + eg1release,                            pDimRgn->EG1Release + eg1release,
374                            Delay);                            // the SSE synthesis implementation requires
375                              // the vca start to be 16 byte aligned
376                              SYNTHESIS_MODE_GET_IMPLEMENTATION(SynthesisMode) ?
377                              Delay & 0xfffffffc : Delay);
378          }          }
379    
380    
     #if ENABLE_FILTER  
381          // setup EG 2 (VCF Cutoff EG)          // setup EG 2 (VCF Cutoff EG)
382          {          {
383              // get current value of EG2 controller              // get current value of EG2 controller
# Line 332  namespace LinuxSampler { namespace gig { Line 390  namespace LinuxSampler { namespace gig {
390                      eg2controllervalue = 0; // TODO: aftertouch not yet supported                      eg2controllervalue = 0; // TODO: aftertouch not yet supported
391                      break;                      break;
392                  case ::gig::eg2_ctrl_t::type_velocity:                  case ::gig::eg2_ctrl_t::type_velocity:
393                      eg2controllervalue = pNoteOnEvent->Velocity;                      eg2controllervalue = itNoteOnEvent->Param.Note.Velocity;
394                      break;                      break;
395                  case ::gig::eg2_ctrl_t::type_controlchange: // MIDI control change controller                  case ::gig::eg2_ctrl_t::type_controlchange: // MIDI control change controller
396                      eg2controllervalue = pEngine->ControllerTable[pDimRgn->EG2Controller.controller_number];                      eg2controllervalue = pEngineChannel->ControllerTable[pDimRgn->EG2Controller.controller_number];
397                      break;                      break;
398              }              }
399              if (pDimRgn->EG2ControllerInvert) eg2controllervalue = 127 - eg2controllervalue;              if (pDimRgn->EG2ControllerInvert) eg2controllervalue = 127 - eg2controllervalue;
# Line 356  namespace LinuxSampler { namespace gig { Line 414  namespace LinuxSampler { namespace gig {
414                            pDimRgn->EG2Release + eg2release,                            pDimRgn->EG2Release + eg2release,
415                            Delay);                            Delay);
416          }          }
     #endif // ENABLE_FILTER  
417    
418    
419          // setup EG 3 (VCO EG)          // setup EG 3 (VCO EG)
# Line 397  namespace LinuxSampler { namespace gig { Line 454  namespace LinuxSampler { namespace gig {
454              pLFO1->Trigger(pDimRgn->LFO1Frequency,              pLFO1->Trigger(pDimRgn->LFO1Frequency,
455                            lfo1_internal_depth,                            lfo1_internal_depth,
456                            pDimRgn->LFO1ControlDepth,                            pDimRgn->LFO1ControlDepth,
457                            pEngine->ControllerTable[pLFO1->ExtController],                            pEngineChannel->ControllerTable[pLFO1->ExtController],
458                            pDimRgn->LFO1FlipPhase,                            pDimRgn->LFO1FlipPhase,
459                            pEngine->SampleRate,                            pEngine->SampleRate,
460                            Delay);                            Delay);
461          }          }
462    
463      #if ENABLE_FILTER  
464          // setup LFO 2 (VCF Cutoff LFO)          // setup LFO 2 (VCF Cutoff LFO)
465          {          {
466              uint16_t lfo2_internal_depth;              uint16_t lfo2_internal_depth;
# Line 435  namespace LinuxSampler { namespace gig { Line 492  namespace LinuxSampler { namespace gig {
492              pLFO2->Trigger(pDimRgn->LFO2Frequency,              pLFO2->Trigger(pDimRgn->LFO2Frequency,
493                            lfo2_internal_depth,                            lfo2_internal_depth,
494                            pDimRgn->LFO2ControlDepth,                            pDimRgn->LFO2ControlDepth,
495                            pEngine->ControllerTable[pLFO2->ExtController],                            pEngineChannel->ControllerTable[pLFO2->ExtController],
496                            pDimRgn->LFO2FlipPhase,                            pDimRgn->LFO2FlipPhase,
497                            pEngine->SampleRate,                            pEngine->SampleRate,
498                            Delay);                            Delay);
499          }          }
500      #endif // ENABLE_FILTER  
501    
502          // setup LFO 3 (VCO LFO)          // setup LFO 3 (VCO LFO)
503          {          {
# Line 473  namespace LinuxSampler { namespace gig { Line 530  namespace LinuxSampler { namespace gig {
530              pLFO3->Trigger(pDimRgn->LFO3Frequency,              pLFO3->Trigger(pDimRgn->LFO3Frequency,
531                            lfo3_internal_depth,                            lfo3_internal_depth,
532                            pDimRgn->LFO3ControlDepth,                            pDimRgn->LFO3ControlDepth,
533                            pEngine->ControllerTable[pLFO3->ExtController],                            pEngineChannel->ControllerTable[pLFO3->ExtController],
534                            false,                            false,
535                            pEngine->SampleRate,                            pEngine->SampleRate,
536                            Delay);                            Delay);
537          }          }
538    
539      #if ENABLE_FILTER  
540          #if FORCE_FILTER_USAGE          #if CONFIG_FORCE_FILTER
541          FilterLeft.Enabled = FilterRight.Enabled = true;          const bool bUseFilter = true;
542          #else // use filter only if instrument file told so          #else // use filter only if instrument file told so
543          FilterLeft.Enabled = FilterRight.Enabled = pDimRgn->VCFEnabled;          const bool bUseFilter = pDimRgn->VCFEnabled;
544          #endif // FORCE_FILTER_USAGE          #endif // CONFIG_FORCE_FILTER
545          if (pDimRgn->VCFEnabled) {          SYNTHESIS_MODE_SET_FILTER(SynthesisMode, bUseFilter);
546              #ifdef OVERRIDE_FILTER_CUTOFF_CTRL          if (bUseFilter) {
547              VCFCutoffCtrl.controller = OVERRIDE_FILTER_CUTOFF_CTRL;              #ifdef CONFIG_OVERRIDE_CUTOFF_CTRL
548                VCFCutoffCtrl.controller = CONFIG_OVERRIDE_CUTOFF_CTRL;
549              #else // use the one defined in the instrument file              #else // use the one defined in the instrument file
550              switch (pDimRgn->VCFCutoffController) {              switch (pDimRgn->VCFCutoffController) {
551                  case ::gig::vcf_cutoff_ctrl_modwheel:                  case ::gig::vcf_cutoff_ctrl_modwheel:
# Line 523  namespace LinuxSampler { namespace gig { Line 581  namespace LinuxSampler { namespace gig {
581                      VCFCutoffCtrl.controller = 0;                      VCFCutoffCtrl.controller = 0;
582                      break;                      break;
583              }              }
584              #endif // OVERRIDE_FILTER_CUTOFF_CTRL              #endif // CONFIG_OVERRIDE_CUTOFF_CTRL
585    
586              #ifdef OVERRIDE_FILTER_RES_CTRL              #ifdef CONFIG_OVERRIDE_RESONANCE_CTRL
587              VCFResonanceCtrl.controller = OVERRIDE_FILTER_RES_CTRL;              VCFResonanceCtrl.controller = CONFIG_OVERRIDE_RESONANCE_CTRL;
588              #else // use the one defined in the instrument file              #else // use the one defined in the instrument file
589              switch (pDimRgn->VCFResonanceController) {              switch (pDimRgn->VCFResonanceController) {
590                  case ::gig::vcf_res_ctrl_genpurpose3:                  case ::gig::vcf_res_ctrl_genpurpose3:
# Line 545  namespace LinuxSampler { namespace gig { Line 603  namespace LinuxSampler { namespace gig {
603                  default:                  default:
604                      VCFResonanceCtrl.controller = 0;                      VCFResonanceCtrl.controller = 0;
605              }              }
606              #endif // OVERRIDE_FILTER_RES_CTRL              #endif // CONFIG_OVERRIDE_RESONANCE_CTRL
607    
608              #ifndef OVERRIDE_FILTER_TYPE              #ifndef CONFIG_OVERRIDE_FILTER_TYPE
609              FilterLeft.SetType(pDimRgn->VCFType);              FilterLeft.SetType(pDimRgn->VCFType);
610              FilterRight.SetType(pDimRgn->VCFType);              FilterRight.SetType(pDimRgn->VCFType);
611              #else // override filter type              #else // override filter type
612              FilterLeft.SetType(OVERRIDE_FILTER_TYPE);              FilterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE);
613              FilterRight.SetType(OVERRIDE_FILTER_TYPE);              FilterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE);
614              #endif // OVERRIDE_FILTER_TYPE              #endif // CONFIG_OVERRIDE_FILTER_TYPE
615    
616              VCFCutoffCtrl.value    = pEngine->ControllerTable[VCFCutoffCtrl.controller];              VCFCutoffCtrl.value    = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller];
617              VCFResonanceCtrl.value = pEngine->ControllerTable[VCFResonanceCtrl.controller];              VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller];
618    
619              // calculate cutoff frequency              // calculate cutoff frequency
620              float cutoff = (!VCFCutoffCtrl.controller)              float cutoff = (!VCFCutoffCtrl.controller)
621                  ? exp((float) (127 - pNoteOnEvent->Velocity) * (float) pDimRgn->VCFVelocityScale * 6.2E-5f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX                  ? exp((float) (127 - itNoteOnEvent->Param.Note.Velocity) * (float) pDimRgn->VCFVelocityScale * 6.2E-5f * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MAX
622                  : exp((float) VCFCutoffCtrl.value * 0.00787402f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX;                  : exp((float) VCFCutoffCtrl.value * 0.00787402f * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MAX;
623    
624              // calculate resonance              // calculate resonance
625              float resonance = (float) VCFResonanceCtrl.value * 0.00787f;   // 0.0..1.0              float resonance = (float) VCFResonanceCtrl.value * 0.00787f;   // 0.0..1.0
626              if (pDimRgn->VCFKeyboardTracking) {              if (pDimRgn->VCFKeyboardTracking) {
627                  resonance += (float) (pNoteOnEvent->Key - pDimRgn->VCFKeyboardTrackingBreakpoint) * 0.00787f;                  resonance += (float) (itNoteOnEvent->Param.Note.Key - pDimRgn->VCFKeyboardTrackingBreakpoint) * 0.00787f;
628              }              }
629              Constrain(resonance, 0.0, 1.0); // correct resonance if outside allowed value range (0.0..1.0)              Constrain(resonance, 0.0, 1.0); // correct resonance if outside allowed value range (0.0..1.0)
630    
631              VCFCutoffCtrl.fvalue    = cutoff - FILTER_CUTOFF_MIN;              VCFCutoffCtrl.fvalue    = cutoff - CONFIG_FILTER_CUTOFF_MIN;
632              VCFResonanceCtrl.fvalue = resonance;              VCFResonanceCtrl.fvalue = resonance;
633    
             FilterLeft.SetParameters(cutoff,  resonance, pEngine->SampleRate);  
             FilterRight.SetParameters(cutoff, resonance, pEngine->SampleRate);  
   
634              FilterUpdateCounter = -1;              FilterUpdateCounter = -1;
635          }          }
636          else {          else {
637              VCFCutoffCtrl.controller    = 0;              VCFCutoffCtrl.controller    = 0;
638              VCFResonanceCtrl.controller = 0;              VCFResonanceCtrl.controller = 0;
639          }          }
     #endif // ENABLE_FILTER  
   
         // ************************************************  
         // TODO: ARTICULATION DATA HANDLING IS MISSING HERE  
         // ************************************************  
640    
641          return 0; // success          return 0; // success
642      }      }
# Line 604  namespace LinuxSampler { namespace gig { Line 654  namespace LinuxSampler { namespace gig {
654       */       */
655      void Voice::Render(uint Samples) {      void Voice::Render(uint Samples) {
656    
657            // select default values for synthesis mode bits
658            SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, (PitchBase * PitchBend) != 1.0f);
659            SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, true);
660            SYNTHESIS_MODE_SET_LOOP(SynthesisMode, false);
661    
662          // Reset the synthesis parameter matrix          // Reset the synthesis parameter matrix
663          pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * pEngine->GlobalVolume);  
664            pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngineChannel->GlobalVolume);
665          pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase);          pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase);
     #if ENABLE_FILTER  
666          pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue);          pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue);
667          pEngine->ResetSynthesisParameters(Event::destination_vcfr, VCFResonanceCtrl.fvalue);          pEngine->ResetSynthesisParameters(Event::destination_vcfr, VCFResonanceCtrl.fvalue);
     #endif // ENABLE_FILTER  
   
668    
669          // Apply events to the synthesis parameter matrix          // Apply events to the synthesis parameter matrix
670          ProcessEvents(Samples);          ProcessEvents(Samples);
671    
   
672          // Let all modulators write their parameter changes to the synthesis parameter matrix for the current audio fragment          // Let all modulators write their parameter changes to the synthesis parameter matrix for the current audio fragment
673          pEG1->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);          pEG1->Process(Samples, pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend, itKillEvent);
674      #if ENABLE_FILTER          pEG2->Process(Samples, pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);
675          pEG2->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);          if (pEG3->Process(Samples)) { // if pitch EG is active
676      #endif // ENABLE_FILTER              SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true);
677          pEG3->Process(Samples);              SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false);
678            }
679          pLFO1->Process(Samples);          pLFO1->Process(Samples);
     #if ENABLE_FILTER  
680          pLFO2->Process(Samples);          pLFO2->Process(Samples);
681      #endif // ENABLE_FILTER          if (pLFO3->Process(Samples)) { // if pitch LFO modulation is active
682          pLFO3->Process(Samples);              SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true);
683                SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false);
684            }
     #if ENABLE_FILTER  
         CalculateBiquadParameters(Samples); // calculate the final biquad filter parameters  
     #endif // ENABLE_FILTER  
685    
686            if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode))
687                CalculateBiquadParameters(Samples); // calculate the final biquad filter parameters
688    
689          switch (this->PlaybackState) {          switch (this->PlaybackState) {
690    
691                case playback_state_init:
692                    this->PlaybackState = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed
693                    // no break - continue with playback_state_ram
694    
695              case playback_state_ram: {              case playback_state_ram: {
696                      if (RAMLoop) InterpolateAndLoop(Samples, (sample_t*) pSample->GetCache().pStart, Delay);                      if (RAMLoop) SYNTHESIS_MODE_SET_LOOP(SynthesisMode, true); // enable looping
697                      else         Interpolate(Samples, (sample_t*) pSample->GetCache().pStart, Delay);  
698                        // render current fragment
699                        Synthesize(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
700    
701                      if (DiskVoice) {                      if (DiskVoice) {
702                          // check if we reached the allowed limit of the sample RAM cache                          // check if we reached the allowed limit of the sample RAM cache
703                          if (Pos > MaxRAMPos) {                          if (Pos > MaxRAMPos) {
# Line 659  namespace LinuxSampler { namespace gig { Line 717  namespace LinuxSampler { namespace gig {
717                          DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);                          DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);
718                          if (!DiskStreamRef.pStream) {                          if (!DiskStreamRef.pStream) {
719                              std::cout << stderr << "Disk stream not available in time!" << std::endl << std::flush;                              std::cout << stderr << "Disk stream not available in time!" << std::endl << std::flush;
720                              Kill();                              KillImmediately();
721                              return;                              return;
722                          }                          }
723                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (RTMath::DoubleToInt(Pos) - MaxRAMPos));                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(Pos) - MaxRAMPos));
724                          Pos -= RTMath::DoubleToInt(Pos);                          Pos -= int(Pos);
725                            RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet
726                      }                      }
727    
728                        const int sampleWordsLeftToRead = DiskStreamRef.pStream->GetReadSpace();
729    
730                      // add silence sample at the end if we reached the end of the stream (for the interpolator)                      // add silence sample at the end if we reached the end of the stream (for the interpolator)
731                      if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels) {                      if (DiskStreamRef.State == Stream::state_end) {
732                          DiskStreamRef.pStream->WriteSilence((pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels);                          const int maxSampleWordsPerCycle = (pEngine->MaxSamplesPerCycle << CONFIG_MAX_PITCH) * pSample->Channels + 6; // +6 for the interpolator algorithm
733                          this->PlaybackState = playback_state_end;                          if (sampleWordsLeftToRead <= maxSampleWordsPerCycle) {
734                                // remember how many sample words there are before any silence has been added
735                                if (RealSampleWordsLeftToRead < 0) RealSampleWordsLeftToRead = sampleWordsLeftToRead;
736                                DiskStreamRef.pStream->WriteSilence(maxSampleWordsPerCycle - sampleWordsLeftToRead);
737                            }
738                      }                      }
739    
740                      sample_t* ptr = DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from                      sample_t* ptr = DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from
741                      Interpolate(Samples, ptr, Delay);  
742                      DiskStreamRef.pStream->IncrementReadPos(RTMath::DoubleToInt(Pos) * pSample->Channels);                      // render current audio fragment
743                      Pos -= RTMath::DoubleToInt(Pos);                      Synthesize(Samples, ptr, Delay);
744    
745                        const int iPos = (int) Pos;
746                        const int readSampleWords = iPos * pSample->Channels; // amount of sample words actually been read
747                        DiskStreamRef.pStream->IncrementReadPos(readSampleWords);
748                        Pos -= iPos; // just keep fractional part of Pos
749    
750                        // change state of voice to 'end' if we really reached the end of the sample data
751                        if (RealSampleWordsLeftToRead >= 0) {
752                            RealSampleWordsLeftToRead -= readSampleWords;
753                            if (RealSampleWordsLeftToRead <= 0) this->PlaybackState = playback_state_end;
754                        }
755                  }                  }
756                  break;                  break;
757    
758              case playback_state_end:              case playback_state_end:
759                  Kill(); // free voice                  std::cerr << "gig::Voice::Render(): entered with playback_state_end, this is a bug!\n" << std::flush;
760                  break;                  break;
761          }          }
762    
   
     #if ENABLE_FILTER  
763          // Reset synthesis event lists (except VCO, as VCO events apply channel wide currently)          // Reset synthesis event lists (except VCO, as VCO events apply channel wide currently)
764          pEngine->pSynthesisEvents[Event::destination_vcfc]->clear();          pEngineChannel->pSynthesisEvents[Event::destination_vca]->clear();
765          pEngine->pSynthesisEvents[Event::destination_vcfr]->clear();          pEngineChannel->pSynthesisEvents[Event::destination_vcfc]->clear();
766      #endif // ENABLE_FILTER          pEngineChannel->pSynthesisEvents[Event::destination_vcfr]->clear();
767    
768          // Reset delay          // Reset delay
769          Delay = 0;          Delay = 0;
770    
771          pTriggerEvent = NULL;          itTriggerEvent = Pool<Event>::Iterator();
772    
773          // If release stage finished, let the voice be killed          // If sample stream or release stage finished, kill the voice
774          if (pEG1->GetStage() == EGADSR::stage_end) this->PlaybackState = playback_state_end;          if (PlaybackState == playback_state_end || pEG1->GetStage() == EGADSR::stage_end) KillImmediately();
775      }      }
776    
777      /**      /**
# Line 708  namespace LinuxSampler { namespace gig { Line 782  namespace LinuxSampler { namespace gig {
782          pLFO1->Reset();          pLFO1->Reset();
783          pLFO2->Reset();          pLFO2->Reset();
784          pLFO3->Reset();          pLFO3->Reset();
785            FilterLeft.Reset();
786            FilterRight.Reset();
787          DiskStreamRef.pStream = NULL;          DiskStreamRef.pStream = NULL;
788          DiskStreamRef.hStream = 0;          DiskStreamRef.hStream = 0;
789          DiskStreamRef.State   = Stream::state_unused;          DiskStreamRef.State   = Stream::state_unused;
790          DiskStreamRef.OrderID = 0;          DiskStreamRef.OrderID = 0;
791          Active = false;          PlaybackState = playback_state_end;
792            itTriggerEvent = Pool<Event>::Iterator();
793            itKillEvent    = Pool<Event>::Iterator();
794      }      }
795    
796      /**      /**
# Line 725  namespace LinuxSampler { namespace gig { Line 803  namespace LinuxSampler { namespace gig {
803      void Voice::ProcessEvents(uint Samples) {      void Voice::ProcessEvents(uint Samples) {
804    
805          // dispatch control change events          // dispatch control change events
806          Event* pCCEvent = pEngine->pCCEvents->first();          RTList<Event>::Iterator itCCEvent = pEngineChannel->pCCEvents->first();
807          if (Delay) { // skip events that happened before this voice was triggered          if (Delay) { // skip events that happened before this voice was triggered
808              while (pCCEvent && pCCEvent->FragmentPos() <= Delay) pCCEvent = pEngine->pCCEvents->next();              while (itCCEvent && itCCEvent->FragmentPos() <= Delay) ++itCCEvent;
809          }          }
810          while (pCCEvent) {          while (itCCEvent) {
811              if (pCCEvent->Controller) { // if valid MIDI controller              if (itCCEvent->Param.CC.Controller) { // if valid MIDI controller
812                  #if ENABLE_FILTER                  if (itCCEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {
813                  if (pCCEvent->Controller == VCFCutoffCtrl.controller) {                      *pEngineChannel->pSynthesisEvents[Event::destination_vcfc]->allocAppend() = *itCCEvent;
                     pEngine->pSynthesisEvents[Event::destination_vcfc]->alloc_assign(*pCCEvent);  
814                  }                  }
815                  if (pCCEvent->Controller == VCFResonanceCtrl.controller) {                  if (itCCEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
816                      pEngine->pSynthesisEvents[Event::destination_vcfr]->alloc_assign(*pCCEvent);                      *pEngineChannel->pSynthesisEvents[Event::destination_vcfr]->allocAppend() = *itCCEvent;
817                  }                  }
818                  #endif // ENABLE_FILTER                  if (itCCEvent->Param.CC.Controller == pLFO1->ExtController) {
819                  if (pCCEvent->Controller == pLFO1->ExtController) {                      pLFO1->SendEvent(itCCEvent);
                     pLFO1->SendEvent(pCCEvent);  
820                  }                  }
821                  #if ENABLE_FILTER                  if (itCCEvent->Param.CC.Controller == pLFO2->ExtController) {
822                  if (pCCEvent->Controller == pLFO2->ExtController) {                      pLFO2->SendEvent(itCCEvent);
                     pLFO2->SendEvent(pCCEvent);  
823                  }                  }
824                  #endif // ENABLE_FILTER                  if (itCCEvent->Param.CC.Controller == pLFO3->ExtController) {
825                  if (pCCEvent->Controller == pLFO3->ExtController) {                      pLFO3->SendEvent(itCCEvent);
826                      pLFO3->SendEvent(pCCEvent);                  }
827                    if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange &&
828                        itCCEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) { // if crossfade event
829                        *pEngineChannel->pSynthesisEvents[Event::destination_vca]->allocAppend() = *itCCEvent;
830                  }                  }
831              }              }
832    
833              pCCEvent = pEngine->pCCEvents->next();              ++itCCEvent;
834          }          }
835    
836    
837          // process pitch events          // process pitch events
838          {          {
839              RTEList<Event>* pVCOEventList = pEngine->pSynthesisEvents[Event::destination_vco];              RTList<Event>* pVCOEventList = pEngineChannel->pSynthesisEvents[Event::destination_vco];
840              Event* pVCOEvent = pVCOEventList->first();              RTList<Event>::Iterator itVCOEvent = pVCOEventList->first();
841              if (Delay) { // skip events that happened before this voice was triggered              if (Delay) { // skip events that happened before this voice was triggered
842                  while (pVCOEvent && pVCOEvent->FragmentPos() <= Delay) pVCOEvent = pVCOEventList->next();                  while (itVCOEvent && itVCOEvent->FragmentPos() <= Delay) ++itVCOEvent;
843              }              }
844              // apply old pitchbend value until first pitch event occurs              // apply old pitchbend value until first pitch event occurs
845              if (this->PitchBend != 1.0) {              if (this->PitchBend != 1.0) {
846                  uint end = (pVCOEvent) ? pVCOEvent->FragmentPos() : Samples;                  uint end = (itVCOEvent) ? itVCOEvent->FragmentPos() : Samples;
847                  for (uint i = Delay; i < end; i++) {                  for (uint i = Delay; i < end; i++) {
848                      pEngine->pSynthesisParameters[Event::destination_vco][i] *= this->PitchBend;                      pEngine->pSynthesisParameters[Event::destination_vco][i] *= this->PitchBend;
849                  }                  }
850              }              }
851              float pitch;              float pitch;
852              while (pVCOEvent) {              while (itVCOEvent) {
853                  Event* pNextVCOEvent = pVCOEventList->next();                  RTList<Event>::Iterator itNextVCOEvent = itVCOEvent;
854                    ++itNextVCOEvent;
855    
856                  // calculate the influence length of this event (in sample points)                  // calculate the influence length of this event (in sample points)
857                  uint end = (pNextVCOEvent) ? pNextVCOEvent->FragmentPos() : Samples;                  uint end = (itNextVCOEvent) ? itNextVCOEvent->FragmentPos() : Samples;
858    
859                  pitch = RTMath::CentsToFreqRatio(((double) pVCOEvent->Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents                  pitch = RTMath::CentsToFreqRatio(((double) itVCOEvent->Param.Pitch.Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents
860    
861                  // apply pitch value to the pitch parameter sequence                  // apply pitch value to the pitch parameter sequence
862                  for (uint i = pVCOEvent->FragmentPos(); i < end; i++) {                  for (uint i = itVCOEvent->FragmentPos(); i < end; i++) {
863                      pEngine->pSynthesisParameters[Event::destination_vco][i] *= pitch;                      pEngine->pSynthesisParameters[Event::destination_vco][i] *= pitch;
864                  }                  }
865    
866                  pVCOEvent = pNextVCOEvent;                  itVCOEvent = itNextVCOEvent;
867                }
868                if (!pVCOEventList->isEmpty()) {
869                    this->PitchBend = pitch;
870                    SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true);
871                    SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false);
872              }              }
             if (pVCOEventList->last()) this->PitchBend = pitch;  
873          }          }
874    
875            // process volume / attenuation events (TODO: we only handle and _expect_ crossfade events here ATM !)
876            {
877                RTList<Event>* pVCAEventList = pEngineChannel->pSynthesisEvents[Event::destination_vca];
878                RTList<Event>::Iterator itVCAEvent = pVCAEventList->first();
879                if (Delay) { // skip events that happened before this voice was triggered
880                    while (itVCAEvent && itVCAEvent->FragmentPos() <= Delay) ++itVCAEvent;
881                }
882                float crossfadevolume;
883                while (itVCAEvent) {
884                    RTList<Event>::Iterator itNextVCAEvent = itVCAEvent;
885                    ++itNextVCAEvent;
886    
887                    // calculate the influence length of this event (in sample points)
888                    uint end = (itNextVCAEvent) ? itNextVCAEvent->FragmentPos() : Samples;
889    
890                    crossfadevolume = CrossfadeAttenuation(itVCAEvent->Param.CC.Value);
891    
892                    float effective_volume = crossfadevolume * this->Volume * pEngineChannel->GlobalVolume;
893    
894                    // apply volume value to the volume parameter sequence
895                    for (uint i = itVCAEvent->FragmentPos(); i < end; i++) {
896                        pEngine->pSynthesisParameters[Event::destination_vca][i] = effective_volume;
897                    }
898    
899                    itVCAEvent = itNextVCAEvent;
900                }
901                if (!pVCAEventList->isEmpty()) this->CrossfadeVolume = crossfadevolume;
902            }
903    
     #if ENABLE_FILTER  
904          // process filter cutoff events          // process filter cutoff events
905          {          {
906              RTEList<Event>* pCutoffEventList = pEngine->pSynthesisEvents[Event::destination_vcfc];              RTList<Event>* pCutoffEventList = pEngineChannel->pSynthesisEvents[Event::destination_vcfc];
907              Event* pCutoffEvent = pCutoffEventList->first();              RTList<Event>::Iterator itCutoffEvent = pCutoffEventList->first();
908              if (Delay) { // skip events that happened before this voice was triggered              if (Delay) { // skip events that happened before this voice was triggered
909                  while (pCutoffEvent && pCutoffEvent->FragmentPos() <= Delay) pCutoffEvent = pCutoffEventList->next();                  while (itCutoffEvent && itCutoffEvent->FragmentPos() <= Delay) ++itCutoffEvent;
910              }              }
911              float cutoff;              float cutoff;
912              while (pCutoffEvent) {              while (itCutoffEvent) {
913                  Event* pNextCutoffEvent = pCutoffEventList->next();                  RTList<Event>::Iterator itNextCutoffEvent = itCutoffEvent;
914                    ++itNextCutoffEvent;
915    
916                  // calculate the influence length of this event (in sample points)                  // calculate the influence length of this event (in sample points)
917                  uint end = (pNextCutoffEvent) ? pNextCutoffEvent->FragmentPos() : Samples;                  uint end = (itNextCutoffEvent) ? itNextCutoffEvent->FragmentPos() : Samples;
918    
919                  cutoff = exp((float) pCutoffEvent->Value * 0.00787402f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX - FILTER_CUTOFF_MIN;                  cutoff = exp((float) itCutoffEvent->Param.CC.Value * 0.00787402f * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MAX - CONFIG_FILTER_CUTOFF_MIN;
920    
921                  // apply cutoff frequency to the cutoff parameter sequence                  // apply cutoff frequency to the cutoff parameter sequence
922                  for (uint i = pCutoffEvent->FragmentPos(); i < end; i++) {                  for (uint i = itCutoffEvent->FragmentPos(); i < end; i++) {
923                      pEngine->pSynthesisParameters[Event::destination_vcfc][i] = cutoff;                      pEngine->pSynthesisParameters[Event::destination_vcfc][i] = cutoff;
924                  }                  }
925    
926                  pCutoffEvent = pNextCutoffEvent;                  itCutoffEvent = itNextCutoffEvent;
927              }              }
928              if (pCutoffEventList->last()) VCFCutoffCtrl.fvalue = cutoff; // needed for initialization of parameter matrix next time              if (!pCutoffEventList->isEmpty()) VCFCutoffCtrl.fvalue = cutoff; // needed for initialization of parameter matrix next time
929          }          }
930    
931          // process filter resonance events          // process filter resonance events
932          {          {
933              RTEList<Event>* pResonanceEventList = pEngine->pSynthesisEvents[Event::destination_vcfr];              RTList<Event>* pResonanceEventList = pEngineChannel->pSynthesisEvents[Event::destination_vcfr];
934              Event* pResonanceEvent = pResonanceEventList->first();              RTList<Event>::Iterator itResonanceEvent = pResonanceEventList->first();
935              if (Delay) { // skip events that happened before this voice was triggered              if (Delay) { // skip events that happened before this voice was triggered
936                  while (pResonanceEvent && pResonanceEvent->FragmentPos() <= Delay) pResonanceEvent = pResonanceEventList->next();                  while (itResonanceEvent && itResonanceEvent->FragmentPos() <= Delay) ++itResonanceEvent;
937              }              }
938              while (pResonanceEvent) {              while (itResonanceEvent) {
939                  Event* pNextResonanceEvent = pResonanceEventList->next();                  RTList<Event>::Iterator itNextResonanceEvent = itResonanceEvent;
940                    ++itNextResonanceEvent;
941    
942                  // calculate the influence length of this event (in sample points)                  // calculate the influence length of this event (in sample points)
943                  uint end = (pNextResonanceEvent) ? pNextResonanceEvent->FragmentPos() : Samples;                  uint end = (itNextResonanceEvent) ? itNextResonanceEvent->FragmentPos() : Samples;
944    
945                  // convert absolute controller value to differential                  // convert absolute controller value to differential
946                  int ctrldelta = pResonanceEvent->Value - VCFResonanceCtrl.value;                  int ctrldelta = itResonanceEvent->Param.CC.Value - VCFResonanceCtrl.value;
947                  VCFResonanceCtrl.value = pResonanceEvent->Value;                  VCFResonanceCtrl.value = itResonanceEvent->Param.CC.Value;
948    
949                  float resonancedelta = (float) ctrldelta * 0.00787f; // 0.0..1.0                  float resonancedelta = (float) ctrldelta * 0.00787f; // 0.0..1.0
950    
951                  // apply cutoff frequency to the cutoff parameter sequence                  // apply cutoff frequency to the cutoff parameter sequence
952                  for (uint i = pResonanceEvent->FragmentPos(); i < end; i++) {                  for (uint i = itResonanceEvent->FragmentPos(); i < end; i++) {
953                      pEngine->pSynthesisParameters[Event::destination_vcfr][i] += resonancedelta;                      pEngine->pSynthesisParameters[Event::destination_vcfr][i] += resonancedelta;
954                  }                  }
955    
956                  pResonanceEvent = pNextResonanceEvent;                  itResonanceEvent = itNextResonanceEvent;
957              }              }
958              if (pResonanceEventList->last()) VCFResonanceCtrl.fvalue = pResonanceEventList->last()->Value * 0.00787f; // needed for initialization of parameter matrix next time              if (!pResonanceEventList->isEmpty()) VCFResonanceCtrl.fvalue = pResonanceEventList->last()->Param.CC.Value * 0.00787f; // needed for initialization of parameter matrix next time
959          }          }
     #endif // ENABLE_FILTER  
960      }      }
961    
     #if ENABLE_FILTER  
962      /**      /**
963       * Calculate all necessary, final biquad filter parameters.       * Calculate all necessary, final biquad filter parameters.
964       *       *
965       * @param Samples - number of samples to be rendered in this audio fragment cycle       * @param Samples - number of samples to be rendered in this audio fragment cycle
966       */       */
967      void Voice::CalculateBiquadParameters(uint Samples) {      void Voice::CalculateBiquadParameters(uint Samples) {
         if (!FilterLeft.Enabled) return;  
   
968          biquad_param_t bqbase;          biquad_param_t bqbase;
969          biquad_param_t bqmain;          biquad_param_t bqmain;
970          float prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][0];          float prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][0];
971          float prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][0];          float prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][0];
972          FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);          FilterLeft.SetParameters( &bqbase, &bqmain, prev_cutoff + CONFIG_FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate);
973            FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff + CONFIG_FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate);
974          pEngine->pBasicFilterParameters[0] = bqbase;          pEngine->pBasicFilterParameters[0] = bqbase;
975          pEngine->pMainFilterParameters[0]  = bqmain;          pEngine->pMainFilterParameters[0]  = bqmain;
976    
977          float* bq;          float* bq;
978          for (int i = 1; i < Samples; i++) {          for (int i = 1; i < Samples; i++) {
979              // recalculate biquad parameters if cutoff or resonance differ from previous sample point              // recalculate biquad parameters if cutoff or resonance differ from previous sample point
980              if (!(i & FILTER_UPDATE_MASK)) if (pEngine->pSynthesisParameters[Event::destination_vcfr][i] != prev_res ||              if (!(i & FILTER_UPDATE_MASK)) {
981                                                 pEngine->pSynthesisParameters[Event::destination_vcfc][i] != prev_cutoff) {                  if (pEngine->pSynthesisParameters[Event::destination_vcfr][i] != prev_res ||
982                  prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i];                      pEngine->pSynthesisParameters[Event::destination_vcfc][i] != prev_cutoff)
983                  prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][i];                  {
984                  FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);                      prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i];
985                        prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][i];
986                        FilterLeft.SetParameters( &bqbase, &bqmain, prev_cutoff + CONFIG_FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate);
987                        FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff + CONFIG_FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate);
988                    }
989              }              }
990    
991              //same as 'pEngine->pBasicFilterParameters[i] = bqbase;'              //same as 'pEngine->pBasicFilterParameters[i] = bqbase;'
992              bq    = (float*) &pEngine->pBasicFilterParameters[i];              bq    = (float*) &pEngine->pBasicFilterParameters[i];
993              bq[0] = bqbase.a1;              bq[0] = bqbase.b0;
994              bq[1] = bqbase.a2;              bq[1] = bqbase.b1;
995              bq[2] = bqbase.b0;              bq[2] = bqbase.b2;
996              bq[3] = bqbase.b1;              bq[3] = bqbase.a1;
997              bq[4] = bqbase.b2;              bq[4] = bqbase.a2;
998    
999              // same as 'pEngine->pMainFilterParameters[i] = bqmain;'              // same as 'pEngine->pMainFilterParameters[i] = bqmain;'
1000              bq    = (float*) &pEngine->pMainFilterParameters[i];              bq    = (float*) &pEngine->pMainFilterParameters[i];
1001              bq[0] = bqmain.a1;              bq[0] = bqmain.b0;
1002              bq[1] = bqmain.a2;              bq[1] = bqmain.b1;
1003              bq[2] = bqmain.b0;              bq[2] = bqmain.b2;
1004              bq[3] = bqmain.b1;              bq[3] = bqmain.a1;
1005              bq[4] = bqmain.b2;              bq[4] = bqmain.a2;
1006          }          }
1007      }      }
     #endif // ENABLE_FILTER  
1008    
1009      /**      /**
1010       *  Interpolates the input audio data (no loop).       *  Synthesizes the current audio fragment for this voice.
1011       *       *
1012       *  @param Samples - number of sample points to be rendered in this audio       *  @param Samples - number of sample points to be rendered in this audio
1013       *                   fragment cycle       *                   fragment cycle
1014       *  @param pSrc    - pointer to input sample data       *  @param pSrc    - pointer to input sample data
1015       *  @param Skip    - number of sample points to skip in output buffer       *  @param Skip    - number of sample points to skip in output buffer
1016       */       */
1017      void Voice::Interpolate(uint Samples, sample_t* pSrc, uint Skip) {      void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
1018          int i = Skip;          RunSynthesisFunction(SynthesisMode, *this, Samples, pSrc, Skip);
   
         // FIXME: assuming either mono or stereo  
         if (this->pSample->Channels == 2) { // Stereo Sample  
             while (i < Samples) {  
                 InterpolateOneStep_Stereo(pSrc, i,  
                                           pEngine->pSynthesisParameters[Event::destination_vca][i],  
                                           pEngine->pSynthesisParameters[Event::destination_vco][i],  
                                           pEngine->pBasicFilterParameters[i],  
                                           pEngine->pMainFilterParameters[i]);  
             }  
         }  
         else { // Mono Sample  
             while (i < Samples) {  
                 InterpolateOneStep_Mono(pSrc, i,  
                                         pEngine->pSynthesisParameters[Event::destination_vca][i],  
                                         pEngine->pSynthesisParameters[Event::destination_vco][i],  
                                         pEngine->pBasicFilterParameters[i],  
                                         pEngine->pMainFilterParameters[i]);  
             }  
         }  
1019      }      }
1020    
1021      /**      /**
1022       *  Interpolates the input audio data, this method honors looping.       *  Immediately kill the voice. This method should not be used to kill
1023         *  a normal, active voice, because it doesn't take care of things like
1024         *  fading down the volume level to avoid clicks and regular processing
1025         *  until the kill event actually occured!
1026       *       *
1027       *  @param Samples - number of sample points to be rendered in this audio       *  @see Kill()
      *                   fragment cycle  
      *  @param pSrc    - pointer to input sample data  
      *  @param Skip    - number of sample points to skip in output buffer  
1028       */       */
1029      void Voice::InterpolateAndLoop(uint Samples, sample_t* pSrc, uint Skip) {      void Voice::KillImmediately() {
1030          int i = Skip;          if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
1031                pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
         // FIXME: assuming either mono or stereo  
         if (pSample->Channels == 2) { // Stereo Sample  
             if (pSample->LoopPlayCount) {  
                 // render loop (loop count limited)  
                 while (i < Samples && LoopCyclesLeft) {  
                     InterpolateOneStep_Stereo(pSrc, i,  
                                               pEngine->pSynthesisParameters[Event::destination_vca][i],  
                                               pEngine->pSynthesisParameters[Event::destination_vco][i],  
                                               pEngine->pBasicFilterParameters[i],  
                                               pEngine->pMainFilterParameters[i]);  
                     if (Pos > pSample->LoopEnd) {  
                         Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;  
                         LoopCyclesLeft--;  
                     }  
                 }  
                 // render on without loop  
                 while (i < Samples) {  
                     InterpolateOneStep_Stereo(pSrc, i,  
                                               pEngine->pSynthesisParameters[Event::destination_vca][i],  
                                               pEngine->pSynthesisParameters[Event::destination_vco][i],  
                                               pEngine->pBasicFilterParameters[i],  
                                               pEngine->pMainFilterParameters[i]);  
                 }  
             }  
             else { // render loop (endless loop)  
                 while (i < Samples) {  
                     InterpolateOneStep_Stereo(pSrc, i,  
                                               pEngine->pSynthesisParameters[Event::destination_vca][i],  
                                               pEngine->pSynthesisParameters[Event::destination_vco][i],  
                                               pEngine->pBasicFilterParameters[i],  
                                               pEngine->pMainFilterParameters[i]);  
                     if (Pos > pSample->LoopEnd) {  
                         Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);  
                     }  
                 }  
             }  
         }  
         else { // Mono Sample  
             if (pSample->LoopPlayCount) {  
                 // render loop (loop count limited)  
                 while (i < Samples && LoopCyclesLeft) {  
                     InterpolateOneStep_Mono(pSrc, i,  
                                             pEngine->pSynthesisParameters[Event::destination_vca][i],  
                                             pEngine->pSynthesisParameters[Event::destination_vco][i],  
                                             pEngine->pBasicFilterParameters[i],  
                                             pEngine->pMainFilterParameters[i]);  
                     if (Pos > pSample->LoopEnd) {  
                         Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;  
                         LoopCyclesLeft--;  
                     }  
                 }  
                 // render on without loop  
                 while (i < Samples) {  
                     InterpolateOneStep_Mono(pSrc, i,  
                                             pEngine->pSynthesisParameters[Event::destination_vca][i],  
                                             pEngine->pSynthesisParameters[Event::destination_vco][i],  
                                             pEngine->pBasicFilterParameters[i],  
                                             pEngine->pMainFilterParameters[i]);  
                 }  
             }  
             else { // render loop (endless loop)  
                 while (i < Samples) {  
                     InterpolateOneStep_Mono(pSrc, i,  
                                             pEngine->pSynthesisParameters[Event::destination_vca][i],  
                                             pEngine->pSynthesisParameters[Event::destination_vco][i],  
                                             pEngine->pBasicFilterParameters[i],  
                                             pEngine->pMainFilterParameters[i]);  
                     if (Pos > pSample->LoopEnd) {  
                         Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;  
                     }  
                 }  
             }  
1032          }          }
1033            Reset();
1034      }      }
1035    
1036      /**      /**
1037       *  Immediately kill the voice.       *  Kill the voice in regular sense. Let the voice render audio until
1038         *  the kill event actually occured and then fade down the volume level
1039         *  very quickly and let the voice die finally. Unlike a normal release
1040         *  of a voice, a kill process cannot be cancalled and is therefore
1041         *  usually used for voice stealing and key group conflicts.
1042         *
1043         *  @param itKillEvent - event which caused the voice to be killed
1044       */       */
1045      void Voice::Kill() {      void Voice::Kill(Pool<Event>::Iterator& itKillEvent) {
1046          if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {          #if CONFIG_DEVMODE
1047              pDiskThread->OrderDeletionOfStream(&DiskStreamRef);          if (!itKillEvent) dmsg(1,("gig::Voice::Kill(): ERROR, !itKillEvent !!!\n"));
1048          }          if (itKillEvent && !itKillEvent.isValid()) dmsg(1,("gig::Voice::Kill(): ERROR, itKillEvent invalid !!!\n"));
1049          Reset();          #endif // CONFIG_DEVMODE
1050    
1051            if (itTriggerEvent && itKillEvent->FragmentPos() <= itTriggerEvent->FragmentPos()) return;
1052            this->itKillEvent = itKillEvent;
1053      }      }
1054    
1055  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

Legend:
Removed from v.233  
changed lines
  Added in v.563

  ViewVC Help
Powered by ViewVC