/[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 271 by schoenebeck, Fri Oct 8 20:51:39 2004 UTC revision 411 by schoenebeck, Sat Feb 26 02:01:14 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    
# Line 45  namespace LinuxSampler { namespace gig { Line 48  namespace LinuxSampler { namespace gig {
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 56  namespace LinuxSampler { namespace gig { Line 59  namespace LinuxSampler { namespace gig {
59          pLFO2  = NULL;          pLFO2  = NULL;
60          pLFO3  = NULL;          pLFO3  = NULL;
61          KeyGroup = 0;          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 103  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 pEngineChannel      - engine channel on which this voice was ordered
121       *  @param itNoteOnEvent       - event that caused triggering of this voice       *  @param itNoteOnEvent       - event that caused triggering of this voice
122       *  @param PitchBend           - MIDI detune factor (-8192 ... +8191)       *  @param PitchBend           - MIDI detune factor (-8192 ... +8191)
123       *  @param pInstrument         - points to the loaded instrument which provides sample wave(s) and articulation data       *  @param pInstrument         - points to the loaded instrument which provides sample wave(s) and articulation data
124       *  @param iLayer              - layer number this voice refers to (only if this is a layered sound of course)       *  @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)       *  @param ReleaseTriggerVoice - if this new voice is a release trigger voice (optional, default = false)
126       *  @returns 0 on success, a value < 0 if something failed       *  @param VoiceStealing       - 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(Pool<Event>::Iterator& itNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument, int iLayer, bool ReleaseTriggerVoice) {      int Voice::Trigger(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing) {
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 (itNoteOnEvent->FragmentPos() > pEngine->MaxSamplesPerCycle) { // FIXME: should be removed before the final release (purpose: just a sanity check for debugging)
138                dmsg(1,("Voice::Trigger(): ERROR, TriggerDelay > Totalsamples\n"));
139            }
140    
141          Type            = type_normal;          Type            = type_normal;
         Active          = true;  
142          MIDIKey         = itNoteOnEvent->Param.Note.Key;          MIDIKey         = itNoteOnEvent->Param.Note.Key;
143          pRegion         = pInstrument->GetRegion(MIDIKey);          pRegion         = pInstrument->GetRegion(MIDIKey);
144          PlaybackState   = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed          PlaybackState   = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed
145          Delay           = itNoteOnEvent->FragmentPos();          Delay           = itNoteOnEvent->FragmentPos();
146          itTriggerEvent  = itNoteOnEvent;          itTriggerEvent  = itNoteOnEvent;
147          itKillEvent     = Pool<Event>::Iterator();          itKillEvent     = Pool<Event>::Iterator();
148            itChildVoice    = Pool<Voice>::Iterator();
149    
150          if (!pRegion) {          if (!pRegion) {
151              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));
             KillImmediately();  
152              return -1;              return -1;
153          }          }
154    
# Line 135  namespace LinuxSampler { namespace gig { Line 156  namespace LinuxSampler { namespace gig {
156    
157          // get current dimension values to select the right dimension region          // get current dimension values to select the right dimension region
158          //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
159          uint DimValues[5] = {0,0,0,0,0};          uint DimValues[8] = { 0 };
160          for (int i = pRegion->Dimensions - 1; i >= 0; i--) {          for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
161              switch (pRegion->pDimensionDefinitions[i].dimension) {              switch (pRegion->pDimensionDefinitions[i].dimension) {
162                  case ::gig::dimension_samplechannel:                  case ::gig::dimension_samplechannel:
# Line 146  namespace LinuxSampler { namespace gig { Line 167  namespace LinuxSampler { namespace gig {
167                      // if this is the 1st layer then spawn further voices for all the other layers                      // if this is the 1st layer then spawn further voices for all the other layers
168                      if (iLayer == 0)                      if (iLayer == 0)
169                          for (int iNewLayer = 1; iNewLayer < pRegion->pDimensionDefinitions[i].zones; iNewLayer++)                          for (int iNewLayer = 1; iNewLayer < pRegion->pDimensionDefinitions[i].zones; iNewLayer++)
170                              pEngine->LaunchVoice(itNoteOnEvent, iNewLayer, ReleaseTriggerVoice);                              itChildVoice = pEngine->LaunchVoice(pEngineChannel, itNoteOnEvent, iNewLayer, ReleaseTriggerVoice, VoiceStealing);
171                      break;                      break;
172                  case ::gig::dimension_velocity:                  case ::gig::dimension_velocity:
173                      DimValues[i] = itNoteOnEvent->Param.Note.Velocity;                      DimValues[i] = itNoteOnEvent->Param.Note.Velocity;
# Line 159  namespace LinuxSampler { namespace gig { Line 180  namespace LinuxSampler { namespace gig {
180                      DimValues[i] = (uint) ReleaseTriggerVoice;                      DimValues[i] = (uint) ReleaseTriggerVoice;
181                      break;                      break;
182                  case ::gig::dimension_keyboard:                  case ::gig::dimension_keyboard:
183                      DimValues[i] = (uint) itNoteOnEvent->Param.Note.Key;                      DimValues[i] = (uint) pEngineChannel->CurrentKeyDimension;
184                      break;                      break;
185                  case ::gig::dimension_modwheel:                  case ::gig::dimension_modwheel:
186                      DimValues[i] = pEngine->ControllerTable[1];                      DimValues[i] = pEngineChannel->ControllerTable[1];
187                      break;                      break;
188                  case ::gig::dimension_breath:                  case ::gig::dimension_breath:
189                      DimValues[i] = pEngine->ControllerTable[2];                      DimValues[i] = pEngineChannel->ControllerTable[2];
190                      break;                      break;
191                  case ::gig::dimension_foot:                  case ::gig::dimension_foot:
192                      DimValues[i] = pEngine->ControllerTable[4];                      DimValues[i] = pEngineChannel->ControllerTable[4];
193                      break;                      break;
194                  case ::gig::dimension_portamentotime:                  case ::gig::dimension_portamentotime:
195                      DimValues[i] = pEngine->ControllerTable[5];                      DimValues[i] = pEngineChannel->ControllerTable[5];
196                      break;                      break;
197                  case ::gig::dimension_effect1:                  case ::gig::dimension_effect1:
198                      DimValues[i] = pEngine->ControllerTable[12];                      DimValues[i] = pEngineChannel->ControllerTable[12];
199                      break;                      break;
200                  case ::gig::dimension_effect2:                  case ::gig::dimension_effect2:
201                      DimValues[i] = pEngine->ControllerTable[13];                      DimValues[i] = pEngineChannel->ControllerTable[13];
202                      break;                      break;
203                  case ::gig::dimension_genpurpose1:                  case ::gig::dimension_genpurpose1:
204                      DimValues[i] = pEngine->ControllerTable[16];                      DimValues[i] = pEngineChannel->ControllerTable[16];
205                      break;                      break;
206                  case ::gig::dimension_genpurpose2:                  case ::gig::dimension_genpurpose2:
207                      DimValues[i] = pEngine->ControllerTable[17];                      DimValues[i] = pEngineChannel->ControllerTable[17];
208                      break;                      break;
209                  case ::gig::dimension_genpurpose3:                  case ::gig::dimension_genpurpose3:
210                      DimValues[i] = pEngine->ControllerTable[18];                      DimValues[i] = pEngineChannel->ControllerTable[18];
211                      break;                      break;
212                  case ::gig::dimension_genpurpose4:                  case ::gig::dimension_genpurpose4:
213                      DimValues[i] = pEngine->ControllerTable[19];                      DimValues[i] = pEngineChannel->ControllerTable[19];
214                      break;                      break;
215                  case ::gig::dimension_sustainpedal:                  case ::gig::dimension_sustainpedal:
216                      DimValues[i] = pEngine->ControllerTable[64];                      DimValues[i] = pEngineChannel->ControllerTable[64];
217                      break;                      break;
218                  case ::gig::dimension_portamento:                  case ::gig::dimension_portamento:
219                      DimValues[i] = pEngine->ControllerTable[65];                      DimValues[i] = pEngineChannel->ControllerTable[65];
220                      break;                      break;
221                  case ::gig::dimension_sostenutopedal:                  case ::gig::dimension_sostenutopedal:
222                      DimValues[i] = pEngine->ControllerTable[66];                      DimValues[i] = pEngineChannel->ControllerTable[66];
223                      break;                      break;
224                  case ::gig::dimension_softpedal:                  case ::gig::dimension_softpedal:
225                      DimValues[i] = pEngine->ControllerTable[67];                      DimValues[i] = pEngineChannel->ControllerTable[67];
226                      break;                      break;
227                  case ::gig::dimension_genpurpose5:                  case ::gig::dimension_genpurpose5:
228                      DimValues[i] = pEngine->ControllerTable[80];                      DimValues[i] = pEngineChannel->ControllerTable[80];
229                      break;                      break;
230                  case ::gig::dimension_genpurpose6:                  case ::gig::dimension_genpurpose6:
231                      DimValues[i] = pEngine->ControllerTable[81];                      DimValues[i] = pEngineChannel->ControllerTable[81];
232                      break;                      break;
233                  case ::gig::dimension_genpurpose7:                  case ::gig::dimension_genpurpose7:
234                      DimValues[i] = pEngine->ControllerTable[82];                      DimValues[i] = pEngineChannel->ControllerTable[82];
235                      break;                      break;
236                  case ::gig::dimension_genpurpose8:                  case ::gig::dimension_genpurpose8:
237                      DimValues[i] = pEngine->ControllerTable[83];                      DimValues[i] = pEngineChannel->ControllerTable[83];
238                      break;                      break;
239                  case ::gig::dimension_effect1depth:                  case ::gig::dimension_effect1depth:
240                      DimValues[i] = pEngine->ControllerTable[91];                      DimValues[i] = pEngineChannel->ControllerTable[91];
241                      break;                      break;
242                  case ::gig::dimension_effect2depth:                  case ::gig::dimension_effect2depth:
243                      DimValues[i] = pEngine->ControllerTable[92];                      DimValues[i] = pEngineChannel->ControllerTable[92];
244                      break;                      break;
245                  case ::gig::dimension_effect3depth:                  case ::gig::dimension_effect3depth:
246                      DimValues[i] = pEngine->ControllerTable[93];                      DimValues[i] = pEngineChannel->ControllerTable[93];
247                      break;                      break;
248                  case ::gig::dimension_effect4depth:                  case ::gig::dimension_effect4depth:
249                      DimValues[i] = pEngine->ControllerTable[94];                      DimValues[i] = pEngineChannel->ControllerTable[94];
250                      break;                      break;
251                  case ::gig::dimension_effect5depth:                  case ::gig::dimension_effect5depth:
252                      DimValues[i] = pEngine->ControllerTable[95];                      DimValues[i] = pEngineChannel->ControllerTable[95];
253                      break;                      break;
254                  case ::gig::dimension_none:                  case ::gig::dimension_none:
255                      std::cerr << "gig::Voice::Trigger() Error: dimension=none\n" << std::flush;                      std::cerr << "gig::Voice::Trigger() Error: dimension=none\n" << std::flush;
# Line 237  namespace LinuxSampler { namespace gig { Line 258  namespace LinuxSampler { namespace gig {
258                      std::cerr << "gig::Voice::Trigger() Error: Unknown dimension\n" << std::flush;                      std::cerr << "gig::Voice::Trigger() Error: Unknown dimension\n" << std::flush;
259              }              }
260          }          }
261          pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);          pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
262    
263            pSample = pDimRgn->pSample; // sample won't change until the voice is finished
264            if (!pSample || !pSample->SamplesTotal) return -1; // no need to continue if sample is silent
265    
266            // select channel mode (mono or stereo)
267            SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2);
268    
269          // get starting crossfade volume level          // get starting crossfade volume level
270          switch (pDimRgn->AttenuationController.type) {          switch (pDimRgn->AttenuationController.type) {
# Line 248  namespace LinuxSampler { namespace gig { Line 275  namespace LinuxSampler { namespace gig {
275                  CrossfadeVolume = CrossfadeAttenuation(itNoteOnEvent->Param.Note.Velocity);                  CrossfadeVolume = CrossfadeAttenuation(itNoteOnEvent->Param.Note.Velocity);
276                  break;                  break;
277              case ::gig::attenuation_ctrl_t::type_controlchange: //FIXME: currently not sample accurate              case ::gig::attenuation_ctrl_t::type_controlchange: //FIXME: currently not sample accurate
278                  CrossfadeVolume = CrossfadeAttenuation(pEngine->ControllerTable[pDimRgn->AttenuationController.controller_number]);                  CrossfadeVolume = CrossfadeAttenuation(pEngineChannel->ControllerTable[pDimRgn->AttenuationController.controller_number]);
279                  break;                  break;
280              case ::gig::attenuation_ctrl_t::type_none: // no crossfade defined              case ::gig::attenuation_ctrl_t::type_none: // no crossfade defined
281              default:              default:
# Line 258  namespace LinuxSampler { namespace gig { Line 285  namespace LinuxSampler { namespace gig {
285          PanLeft  = 1.0f - float(RTMath::Max(pDimRgn->Pan, 0)) /  63.0f;          PanLeft  = 1.0f - float(RTMath::Max(pDimRgn->Pan, 0)) /  63.0f;
286          PanRight = 1.0f - float(RTMath::Min(pDimRgn->Pan, 0)) / -64.0f;          PanRight = 1.0f - float(RTMath::Min(pDimRgn->Pan, 0)) / -64.0f;
287    
         pSample = pDimRgn->pSample; // sample won't change until the voice is finished  
   
288          Pos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)          Pos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
289    
290          // 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
# Line 296  namespace LinuxSampler { namespace gig { Line 321  namespace LinuxSampler { namespace gig {
321    
322          // calculate initial pitch value          // calculate initial pitch value
323          {          {
324              double pitchbasecents = pDimRgn->FineTune * 10 + (int) pEngine->ScaleTuning[MIDIKey % 12];              double pitchbasecents = pDimRgn->FineTune + (int) pEngine->ScaleTuning[MIDIKey % 12];
325              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;
326              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate()));              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate()));
327              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
328          }          }
329    
   
330          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)          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)
331    
332            Volume *= pDimRgn->SampleAttenuation;
333    
334          // setup EG 1 (VCA EG)          // setup EG 1 (VCA EG)
335          {          {
# Line 321  namespace LinuxSampler { namespace gig { Line 346  namespace LinuxSampler { namespace gig {
346                      eg1controllervalue = itNoteOnEvent->Param.Note.Velocity;                      eg1controllervalue = itNoteOnEvent->Param.Note.Velocity;
347                      break;                      break;
348                  case ::gig::eg1_ctrl_t::type_controlchange: // MIDI control change controller                  case ::gig::eg1_ctrl_t::type_controlchange: // MIDI control change controller
349                      eg1controllervalue = pEngine->ControllerTable[pDimRgn->EG1Controller.controller_number];                      eg1controllervalue = pEngineChannel->ControllerTable[pDimRgn->EG1Controller.controller_number];
350                      break;                      break;
351              }              }
352              if (pDimRgn->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue;              if (pDimRgn->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue;
# Line 344  namespace LinuxSampler { namespace gig { Line 369  namespace LinuxSampler { namespace gig {
369          }          }
370    
371    
     #if ENABLE_FILTER  
372          // setup EG 2 (VCF Cutoff EG)          // setup EG 2 (VCF Cutoff EG)
373          {          {
374              // get current value of EG2 controller              // get current value of EG2 controller
# Line 360  namespace LinuxSampler { namespace gig { Line 384  namespace LinuxSampler { namespace gig {
384                      eg2controllervalue = itNoteOnEvent->Param.Note.Velocity;                      eg2controllervalue = itNoteOnEvent->Param.Note.Velocity;
385                      break;                      break;
386                  case ::gig::eg2_ctrl_t::type_controlchange: // MIDI control change controller                  case ::gig::eg2_ctrl_t::type_controlchange: // MIDI control change controller
387                      eg2controllervalue = pEngine->ControllerTable[pDimRgn->EG2Controller.controller_number];                      eg2controllervalue = pEngineChannel->ControllerTable[pDimRgn->EG2Controller.controller_number];
388                      break;                      break;
389              }              }
390              if (pDimRgn->EG2ControllerInvert) eg2controllervalue = 127 - eg2controllervalue;              if (pDimRgn->EG2ControllerInvert) eg2controllervalue = 127 - eg2controllervalue;
# Line 381  namespace LinuxSampler { namespace gig { Line 405  namespace LinuxSampler { namespace gig {
405                            pDimRgn->EG2Release + eg2release,                            pDimRgn->EG2Release + eg2release,
406                            Delay);                            Delay);
407          }          }
     #endif // ENABLE_FILTER  
408    
409    
410          // setup EG 3 (VCO EG)          // setup EG 3 (VCO EG)
# Line 422  namespace LinuxSampler { namespace gig { Line 445  namespace LinuxSampler { namespace gig {
445              pLFO1->Trigger(pDimRgn->LFO1Frequency,              pLFO1->Trigger(pDimRgn->LFO1Frequency,
446                            lfo1_internal_depth,                            lfo1_internal_depth,
447                            pDimRgn->LFO1ControlDepth,                            pDimRgn->LFO1ControlDepth,
448                            pEngine->ControllerTable[pLFO1->ExtController],                            pEngineChannel->ControllerTable[pLFO1->ExtController],
449                            pDimRgn->LFO1FlipPhase,                            pDimRgn->LFO1FlipPhase,
450                            pEngine->SampleRate,                            pEngine->SampleRate,
451                            Delay);                            Delay);
452          }          }
453    
454      #if ENABLE_FILTER  
455          // setup LFO 2 (VCF Cutoff LFO)          // setup LFO 2 (VCF Cutoff LFO)
456          {          {
457              uint16_t lfo2_internal_depth;              uint16_t lfo2_internal_depth;
# Line 460  namespace LinuxSampler { namespace gig { Line 483  namespace LinuxSampler { namespace gig {
483              pLFO2->Trigger(pDimRgn->LFO2Frequency,              pLFO2->Trigger(pDimRgn->LFO2Frequency,
484                            lfo2_internal_depth,                            lfo2_internal_depth,
485                            pDimRgn->LFO2ControlDepth,                            pDimRgn->LFO2ControlDepth,
486                            pEngine->ControllerTable[pLFO2->ExtController],                            pEngineChannel->ControllerTable[pLFO2->ExtController],
487                            pDimRgn->LFO2FlipPhase,                            pDimRgn->LFO2FlipPhase,
488                            pEngine->SampleRate,                            pEngine->SampleRate,
489                            Delay);                            Delay);
490          }          }
491      #endif // ENABLE_FILTER  
492    
493          // setup LFO 3 (VCO LFO)          // setup LFO 3 (VCO LFO)
494          {          {
# Line 498  namespace LinuxSampler { namespace gig { Line 521  namespace LinuxSampler { namespace gig {
521              pLFO3->Trigger(pDimRgn->LFO3Frequency,              pLFO3->Trigger(pDimRgn->LFO3Frequency,
522                            lfo3_internal_depth,                            lfo3_internal_depth,
523                            pDimRgn->LFO3ControlDepth,                            pDimRgn->LFO3ControlDepth,
524                            pEngine->ControllerTable[pLFO3->ExtController],                            pEngineChannel->ControllerTable[pLFO3->ExtController],
525                            false,                            false,
526                            pEngine->SampleRate,                            pEngine->SampleRate,
527                            Delay);                            Delay);
528          }          }
529    
530      #if ENABLE_FILTER  
531          #if FORCE_FILTER_USAGE          #if FORCE_FILTER_USAGE
532          FilterLeft.Enabled = FilterRight.Enabled = true;          const bool bUseFilter = true;
533          #else // use filter only if instrument file told so          #else // use filter only if instrument file told so
534          FilterLeft.Enabled = FilterRight.Enabled = pDimRgn->VCFEnabled;          const bool bUseFilter = pDimRgn->VCFEnabled;
535          #endif // FORCE_FILTER_USAGE          #endif // FORCE_FILTER_USAGE
536          if (pDimRgn->VCFEnabled) {          SYNTHESIS_MODE_SET_FILTER(SynthesisMode, bUseFilter);
537            if (bUseFilter) {
538              #ifdef OVERRIDE_FILTER_CUTOFF_CTRL              #ifdef OVERRIDE_FILTER_CUTOFF_CTRL
539              VCFCutoffCtrl.controller = OVERRIDE_FILTER_CUTOFF_CTRL;              VCFCutoffCtrl.controller = OVERRIDE_FILTER_CUTOFF_CTRL;
540              #else // use the one defined in the instrument file              #else // use the one defined in the instrument file
# Line 580  namespace LinuxSampler { namespace gig { Line 604  namespace LinuxSampler { namespace gig {
604              FilterRight.SetType(OVERRIDE_FILTER_TYPE);              FilterRight.SetType(OVERRIDE_FILTER_TYPE);
605              #endif // OVERRIDE_FILTER_TYPE              #endif // OVERRIDE_FILTER_TYPE
606    
607              VCFCutoffCtrl.value    = pEngine->ControllerTable[VCFCutoffCtrl.controller];              VCFCutoffCtrl.value    = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller];
608              VCFResonanceCtrl.value = pEngine->ControllerTable[VCFResonanceCtrl.controller];              VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller];
609    
610              // calculate cutoff frequency              // calculate cutoff frequency
611              float cutoff = (!VCFCutoffCtrl.controller)              float cutoff = (!VCFCutoffCtrl.controller)
# Line 598  namespace LinuxSampler { namespace gig { Line 622  namespace LinuxSampler { namespace gig {
622              VCFCutoffCtrl.fvalue    = cutoff - FILTER_CUTOFF_MIN;              VCFCutoffCtrl.fvalue    = cutoff - FILTER_CUTOFF_MIN;
623              VCFResonanceCtrl.fvalue = resonance;              VCFResonanceCtrl.fvalue = resonance;
624    
             FilterLeft.SetParameters(cutoff,  resonance, pEngine->SampleRate);  
             FilterRight.SetParameters(cutoff, resonance, pEngine->SampleRate);  
   
625              FilterUpdateCounter = -1;              FilterUpdateCounter = -1;
626          }          }
627          else {          else {
628              VCFCutoffCtrl.controller    = 0;              VCFCutoffCtrl.controller    = 0;
629              VCFResonanceCtrl.controller = 0;              VCFResonanceCtrl.controller = 0;
630          }          }
     #endif // ENABLE_FILTER  
631    
632          return 0; // success          return 0; // success
633      }      }
# Line 625  namespace LinuxSampler { namespace gig { Line 645  namespace LinuxSampler { namespace gig {
645       */       */
646      void Voice::Render(uint Samples) {      void Voice::Render(uint Samples) {
647    
648            // select default values for synthesis mode bits
649            SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, (PitchBase * PitchBend) != 1.0f);
650            SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, true);
651            SYNTHESIS_MODE_SET_LOOP(SynthesisMode, false);
652    
653          // Reset the synthesis parameter matrix          // Reset the synthesis parameter matrix
654          pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngine->GlobalVolume);  
655            pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngineChannel->GlobalVolume);
656          pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase);          pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase);
     #if ENABLE_FILTER  
657          pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue);          pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue);
658          pEngine->ResetSynthesisParameters(Event::destination_vcfr, VCFResonanceCtrl.fvalue);          pEngine->ResetSynthesisParameters(Event::destination_vcfr, VCFResonanceCtrl.fvalue);
     #endif // ENABLE_FILTER  
   
659    
660          // Apply events to the synthesis parameter matrix          // Apply events to the synthesis parameter matrix
661          ProcessEvents(Samples);          ProcessEvents(Samples);
662    
   
663          // 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
664          pEG1->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend, itKillEvent);          pEG1->Process(Samples, pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend, itKillEvent);
665      #if ENABLE_FILTER          pEG2->Process(Samples, pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);
666          pEG2->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);          if (pEG3->Process(Samples)) { // if pitch EG is active
667      #endif // ENABLE_FILTER              SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true);
668          pEG3->Process(Samples);              SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false);
669            }
670          pLFO1->Process(Samples);          pLFO1->Process(Samples);
     #if ENABLE_FILTER  
671          pLFO2->Process(Samples);          pLFO2->Process(Samples);
672      #endif // ENABLE_FILTER          if (pLFO3->Process(Samples)) { // if pitch LFO modulation is active
673          pLFO3->Process(Samples);              SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true);
674                SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false);
675            }
     #if ENABLE_FILTER  
         CalculateBiquadParameters(Samples); // calculate the final biquad filter parameters  
     #endif // ENABLE_FILTER  
676    
677            if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode))
678                    CalculateBiquadParameters(Samples); // calculate the final biquad filter parameters
679    
680          switch (this->PlaybackState) {          switch (this->PlaybackState) {
681    
682              case playback_state_ram: {              case playback_state_ram: {
683                      if (RAMLoop) InterpolateAndLoop(Samples, (sample_t*) pSample->GetCache().pStart, Delay);                      if (RAMLoop) SYNTHESIS_MODE_SET_LOOP(SynthesisMode, true); // enable looping
684                      else         InterpolateNoLoop(Samples, (sample_t*) pSample->GetCache().pStart, Delay);  
685                        // render current fragment
686                        Synthesize(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
687    
688                      if (DiskVoice) {                      if (DiskVoice) {
689                          // check if we reached the allowed limit of the sample RAM cache                          // check if we reached the allowed limit of the sample RAM cache
690                          if (Pos > MaxRAMPos) {                          if (Pos > MaxRAMPos) {
# Line 683  namespace LinuxSampler { namespace gig { Line 707  namespace LinuxSampler { namespace gig {
707                              KillImmediately();                              KillImmediately();
708                              return;                              return;
709                          }                          }
710                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (RTMath::DoubleToInt(Pos) - MaxRAMPos));                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(Pos) - MaxRAMPos));
711                          Pos -= RTMath::DoubleToInt(Pos);                          Pos -= int(Pos);
712                            RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet
713                      }                      }
714    
715                        const int sampleWordsLeftToRead = DiskStreamRef.pStream->GetReadSpace();
716    
717                      // 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)
718                      if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels) {                      if (DiskStreamRef.State == Stream::state_end) {
719                          DiskStreamRef.pStream->WriteSilence((pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels);                          const int maxSampleWordsPerCycle = (pEngine->MaxSamplesPerCycle << MAX_PITCH) * pSample->Channels + 6; // +6 for the interpolator algorithm
720                          this->PlaybackState = playback_state_end;                          if (sampleWordsLeftToRead <= maxSampleWordsPerCycle) {
721                                // remember how many sample words there are before any silence has been added
722                                if (RealSampleWordsLeftToRead < 0) RealSampleWordsLeftToRead = sampleWordsLeftToRead;
723                                DiskStreamRef.pStream->WriteSilence(maxSampleWordsPerCycle - sampleWordsLeftToRead);
724                            }
725                      }                      }
726    
727                      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
728                      InterpolateNoLoop(Samples, ptr, Delay);  
729                      DiskStreamRef.pStream->IncrementReadPos(RTMath::DoubleToInt(Pos) * pSample->Channels);                      // render current audio fragment
730                      Pos -= RTMath::DoubleToInt(Pos);                      Synthesize(Samples, ptr, Delay);
731    
732                        const int iPos = (int) Pos;
733                        const int readSampleWords = iPos * pSample->Channels; // amount of sample words actually been read
734                        DiskStreamRef.pStream->IncrementReadPos(readSampleWords);
735                        Pos -= iPos; // just keep fractional part of Pos
736    
737                        // change state of voice to 'end' if we really reached the end of the sample data
738                        if (RealSampleWordsLeftToRead >= 0) {
739                            RealSampleWordsLeftToRead -= readSampleWords;
740                            if (RealSampleWordsLeftToRead <= 0) this->PlaybackState = playback_state_end;
741                        }
742                  }                  }
743                  break;                  break;
744    
745              case playback_state_end:              case playback_state_end:
746                  KillImmediately(); // free voice                  std::cerr << "gig::Voice::Render(): entered with playback_state_end, this is a bug!\n" << std::flush;
747                  break;                  break;
748          }          }
749    
   
750          // 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)
751          pEngine->pSynthesisEvents[Event::destination_vca]->clear();          pEngine->pSynthesisEvents[Event::destination_vca]->clear();
     #if ENABLE_FILTER  
752          pEngine->pSynthesisEvents[Event::destination_vcfc]->clear();          pEngine->pSynthesisEvents[Event::destination_vcfc]->clear();
753          pEngine->pSynthesisEvents[Event::destination_vcfr]->clear();          pEngine->pSynthesisEvents[Event::destination_vcfr]->clear();
     #endif // ENABLE_FILTER  
754    
755          // Reset delay          // Reset delay
756          Delay = 0;          Delay = 0;
757    
758          itTriggerEvent = Pool<Event>::Iterator();          itTriggerEvent = Pool<Event>::Iterator();
759    
760          // If release stage finished, let the voice be killed          // If sample stream or release stage finished, kill the voice
761          if (pEG1->GetStage() == EGADSR::stage_end) this->PlaybackState = playback_state_end;          if (PlaybackState == playback_state_end || pEG1->GetStage() == EGADSR::stage_end) KillImmediately();
762      }      }
763    
764      /**      /**
# Line 730  namespace LinuxSampler { namespace gig { Line 769  namespace LinuxSampler { namespace gig {
769          pLFO1->Reset();          pLFO1->Reset();
770          pLFO2->Reset();          pLFO2->Reset();
771          pLFO3->Reset();          pLFO3->Reset();
772            FilterLeft.Reset();
773            FilterRight.Reset();
774          DiskStreamRef.pStream = NULL;          DiskStreamRef.pStream = NULL;
775          DiskStreamRef.hStream = 0;          DiskStreamRef.hStream = 0;
776          DiskStreamRef.State   = Stream::state_unused;          DiskStreamRef.State   = Stream::state_unused;
777          DiskStreamRef.OrderID = 0;          DiskStreamRef.OrderID = 0;
778          Active = false;          PlaybackState = playback_state_end;
779            itTriggerEvent = Pool<Event>::Iterator();
780            itKillEvent    = Pool<Event>::Iterator();
781      }      }
782    
783      /**      /**
# Line 753  namespace LinuxSampler { namespace gig { Line 796  namespace LinuxSampler { namespace gig {
796          }          }
797          while (itCCEvent) {          while (itCCEvent) {
798              if (itCCEvent->Param.CC.Controller) { // if valid MIDI controller              if (itCCEvent->Param.CC.Controller) { // if valid MIDI controller
                 #if ENABLE_FILTER  
799                  if (itCCEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {                  if (itCCEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {
800                      *pEngine->pSynthesisEvents[Event::destination_vcfc]->allocAppend() = *itCCEvent;                      *pEngine->pSynthesisEvents[Event::destination_vcfc]->allocAppend() = *itCCEvent;
801                  }                  }
802                  if (itCCEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {                  if (itCCEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
803                      *pEngine->pSynthesisEvents[Event::destination_vcfr]->allocAppend() = *itCCEvent;                      *pEngine->pSynthesisEvents[Event::destination_vcfr]->allocAppend() = *itCCEvent;
804                  }                  }
                 #endif // ENABLE_FILTER  
805                  if (itCCEvent->Param.CC.Controller == pLFO1->ExtController) {                  if (itCCEvent->Param.CC.Controller == pLFO1->ExtController) {
806                      pLFO1->SendEvent(itCCEvent);                      pLFO1->SendEvent(itCCEvent);
807                  }                  }
                 #if ENABLE_FILTER  
808                  if (itCCEvent->Param.CC.Controller == pLFO2->ExtController) {                  if (itCCEvent->Param.CC.Controller == pLFO2->ExtController) {
809                      pLFO2->SendEvent(itCCEvent);                      pLFO2->SendEvent(itCCEvent);
810                  }                  }
                 #endif // ENABLE_FILTER  
811                  if (itCCEvent->Param.CC.Controller == pLFO3->ExtController) {                  if (itCCEvent->Param.CC.Controller == pLFO3->ExtController) {
812                      pLFO3->SendEvent(itCCEvent);                      pLFO3->SendEvent(itCCEvent);
813                  }                  }
# Line 813  namespace LinuxSampler { namespace gig { Line 852  namespace LinuxSampler { namespace gig {
852    
853                  itVCOEvent = itNextVCOEvent;                  itVCOEvent = itNextVCOEvent;
854              }              }
855              if (!pVCOEventList->isEmpty()) this->PitchBend = pitch;              if (!pVCOEventList->isEmpty()) {
856                    this->PitchBend = pitch;
857                    SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true);
858                    SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false);
859                }
860          }          }
861    
862          // process volume / attenuation events (TODO: we only handle and _expect_ crossfade events here ATM !)          // process volume / attenuation events (TODO: we only handle and _expect_ crossfade events here ATM !)
# Line 833  namespace LinuxSampler { namespace gig { Line 876  namespace LinuxSampler { namespace gig {
876    
877                  crossfadevolume = CrossfadeAttenuation(itVCAEvent->Param.CC.Value);                  crossfadevolume = CrossfadeAttenuation(itVCAEvent->Param.CC.Value);
878    
879                  float effective_volume = crossfadevolume * this->Volume * pEngine->GlobalVolume;                  float effective_volume = crossfadevolume * this->Volume * pEngineChannel->GlobalVolume;
880    
881                  // apply volume value to the volume parameter sequence                  // apply volume value to the volume parameter sequence
882                  for (uint i = itVCAEvent->FragmentPos(); i < end; i++) {                  for (uint i = itVCAEvent->FragmentPos(); i < end; i++) {
# Line 845  namespace LinuxSampler { namespace gig { Line 888  namespace LinuxSampler { namespace gig {
888              if (!pVCAEventList->isEmpty()) this->CrossfadeVolume = crossfadevolume;              if (!pVCAEventList->isEmpty()) this->CrossfadeVolume = crossfadevolume;
889          }          }
890    
     #if ENABLE_FILTER  
891          // process filter cutoff events          // process filter cutoff events
892          {          {
893              RTList<Event>* pCutoffEventList = pEngine->pSynthesisEvents[Event::destination_vcfc];              RTList<Event>* pCutoffEventList = pEngine->pSynthesisEvents[Event::destination_vcfc];
# Line 902  namespace LinuxSampler { namespace gig { Line 944  namespace LinuxSampler { namespace gig {
944              }              }
945              if (!pResonanceEventList->isEmpty()) VCFResonanceCtrl.fvalue = pResonanceEventList->last()->Param.CC.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
946          }          }
     #endif // ENABLE_FILTER  
947      }      }
948    
     #if ENABLE_FILTER  
949      /**      /**
950       * Calculate all necessary, final biquad filter parameters.       * Calculate all necessary, final biquad filter parameters.
951       *       *
952       * @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
953       */       */
954      void Voice::CalculateBiquadParameters(uint Samples) {      void Voice::CalculateBiquadParameters(uint Samples) {
         if (!FilterLeft.Enabled) return;  
   
955          biquad_param_t bqbase;          biquad_param_t bqbase;
956          biquad_param_t bqmain;          biquad_param_t bqmain;
957          float prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][0];          float prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][0];
958          float prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][0];          float prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][0];
959          FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);          FilterLeft.SetParameters( &bqbase, &bqmain, prev_cutoff + FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate);
960            FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff + FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate);
961          pEngine->pBasicFilterParameters[0] = bqbase;          pEngine->pBasicFilterParameters[0] = bqbase;
962          pEngine->pMainFilterParameters[0]  = bqmain;          pEngine->pMainFilterParameters[0]  = bqmain;
963    
964          float* bq;          float* bq;
965          for (int i = 1; i < Samples; i++) {          for (int i = 1; i < Samples; i++) {
966              // recalculate biquad parameters if cutoff or resonance differ from previous sample point              // recalculate biquad parameters if cutoff or resonance differ from previous sample point
967              if (!(i & FILTER_UPDATE_MASK)) if (pEngine->pSynthesisParameters[Event::destination_vcfr][i] != prev_res ||              if (!(i & FILTER_UPDATE_MASK)) {
968                                                 pEngine->pSynthesisParameters[Event::destination_vcfc][i] != prev_cutoff) {                  if (pEngine->pSynthesisParameters[Event::destination_vcfr][i] != prev_res ||
969                  prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i];                      pEngine->pSynthesisParameters[Event::destination_vcfc][i] != prev_cutoff)
970                  prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][i];                  {
971                  FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);                      prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i];
972                        prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][i];
973                        FilterLeft.SetParameters( &bqbase, &bqmain, prev_cutoff + FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate);
974                        FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff + FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate);
975                    }
976              }              }
977    
978              //same as 'pEngine->pBasicFilterParameters[i] = bqbase;'              //same as 'pEngine->pBasicFilterParameters[i] = bqbase;'
979              bq    = (float*) &pEngine->pBasicFilterParameters[i];              bq    = (float*) &pEngine->pBasicFilterParameters[i];
980              bq[0] = bqbase.a1;              bq[0] = bqbase.b0;
981              bq[1] = bqbase.a2;              bq[1] = bqbase.b1;
982              bq[2] = bqbase.b0;              bq[2] = bqbase.b2;
983              bq[3] = bqbase.b1;              bq[3] = bqbase.a1;
984              bq[4] = bqbase.b2;              bq[4] = bqbase.a2;
985    
986              // same as 'pEngine->pMainFilterParameters[i] = bqmain;'              // same as 'pEngine->pMainFilterParameters[i] = bqmain;'
987              bq    = (float*) &pEngine->pMainFilterParameters[i];              bq    = (float*) &pEngine->pMainFilterParameters[i];
988              bq[0] = bqmain.a1;              bq[0] = bqmain.b0;
989              bq[1] = bqmain.a2;              bq[1] = bqmain.b1;
990              bq[2] = bqmain.b0;              bq[2] = bqmain.b2;
991              bq[3] = bqmain.b1;              bq[3] = bqmain.a1;
992              bq[4] = bqmain.b2;              bq[4] = bqmain.a2;
993          }          }
994      }      }
     #endif // ENABLE_FILTER  
995    
996      /**      /**
997       *  Interpolates the input audio data (without looping).       *  Synthesizes the current audio fragment for this voice.
998       *       *
999       *  @param Samples - number of sample points to be rendered in this audio       *  @param Samples - number of sample points to be rendered in this audio
1000       *                   fragment cycle       *                   fragment cycle
1001       *  @param pSrc    - pointer to input sample data       *  @param pSrc    - pointer to input sample data
1002       *  @param Skip    - number of sample points to skip in output buffer       *  @param Skip    - number of sample points to skip in output buffer
1003       */       */
1004      void Voice::InterpolateNoLoop(uint Samples, sample_t* pSrc, uint Skip) {      void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) {
1005          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) InterpolateStereo(pSrc, i);  
         }  
         else { // Mono Sample  
             while (i < Samples) InterpolateMono(pSrc, i);  
         }  
     }  
   
     /**  
      *  Interpolates the input audio data, this method honors looping.  
      *  
      *  @param Samples - number of sample points to be rendered in this audio  
      *                   fragment cycle  
      *  @param pSrc    - pointer to input sample data  
      *  @param Skip    - number of sample points to skip in output buffer  
      */  
     void Voice::InterpolateAndLoop(uint Samples, sample_t* pSrc, uint Skip) {  
         int i = Skip;  
   
         // FIXME: assuming either mono or stereo  
         if (pSample->Channels == 2) { // Stereo Sample  
             if (pSample->LoopPlayCount) {  
                 // render loop (loop count limited)  
                 while (i < Samples && LoopCyclesLeft) {  
                     InterpolateStereo(pSrc, i);  
                     if (Pos > pSample->LoopEnd) {  
                         Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;  
                         LoopCyclesLeft--;  
                     }  
                 }  
                 // render on without loop  
                 while (i < Samples) InterpolateStereo(pSrc, i);  
             }  
             else { // render loop (endless loop)  
                 while (i < Samples) {  
                     InterpolateStereo(pSrc, 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) {  
                     InterpolateMono(pSrc, i);  
                     if (Pos > pSample->LoopEnd) {  
                         Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;  
                         LoopCyclesLeft--;  
                     }  
                 }  
                 // render on without loop  
                 while (i < Samples) InterpolateMono(pSrc, i);  
             }  
             else { // render loop (endless loop)  
                 while (i < Samples) {  
                     InterpolateMono(pSrc, i);  
                     if (Pos > pSample->LoopEnd) {  
                         Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;  
                     }  
                 }  
             }  
         }  
1006      }      }
1007    
1008      /**      /**
# Line 1054  namespace LinuxSampler { namespace gig { Line 1030  namespace LinuxSampler { namespace gig {
1030       *  @param itKillEvent - event which caused the voice to be killed       *  @param itKillEvent - event which caused the voice to be killed
1031       */       */
1032      void Voice::Kill(Pool<Event>::Iterator& itKillEvent) {      void Voice::Kill(Pool<Event>::Iterator& itKillEvent) {
1033            //FIXME: just two sanity checks for debugging, can be removed
1034            if (!itKillEvent) dmsg(1,("gig::Voice::Kill(): ERROR, !itKillEvent !!!\n"));
1035            if (itKillEvent && !itKillEvent.isValid()) dmsg(1,("gig::Voice::Kill(): ERROR, itKillEvent invalid !!!\n"));
1036    
1037          if (itTriggerEvent && itKillEvent->FragmentPos() <= itTriggerEvent->FragmentPos()) return;          if (itTriggerEvent && itKillEvent->FragmentPos() <= itTriggerEvent->FragmentPos()) return;
1038          this->itKillEvent = itKillEvent;          this->itKillEvent = itKillEvent;
1039      }      }

Legend:
Removed from v.271  
changed lines
  Added in v.411

  ViewVC Help
Powered by ViewVC