/[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 64 by schoenebeck, Thu May 6 20:06:20 2004 UTC revision 247 by senkov, Sun Sep 19 23:44:23 2004 UTC
# Line 27  Line 27 
27    
28  namespace LinuxSampler { namespace gig {  namespace LinuxSampler { namespace gig {
29    
     // FIXME: no support for layers (nor crossfades) yet  
   
30      const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff());      const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff());
31    
32        const int Voice::FILTER_UPDATE_MASK(CalculateFilterUpdateMask());
33    
34      float Voice::CalculateFilterCutoffCoeff() {      float Voice::CalculateFilterCutoffCoeff() {
35          return log(FILTER_CUTOFF_MIN / FILTER_CUTOFF_MAX);          return log(FILTER_CUTOFF_MIN / FILTER_CUTOFF_MAX);
36      }      }
37    
38        int Voice::CalculateFilterUpdateMask() {
39            if (FILTER_UPDATE_PERIOD <= 0) return 0;
40            int power_of_two;
41            for (power_of_two = 0; 1<<power_of_two < FILTER_UPDATE_PERIOD; power_of_two++);
42            return (1 << power_of_two) - 1;
43        }
44    
45      Voice::Voice() {      Voice::Voice() {
46          pEngine     = NULL;          pEngine     = NULL;
47          pDiskThread = NULL;          pDiskThread = NULL;
# Line 48  namespace LinuxSampler { namespace gig { Line 55  namespace LinuxSampler { namespace gig {
55          pLFO1  = NULL;          pLFO1  = NULL;
56          pLFO2  = NULL;          pLFO2  = NULL;
57          pLFO3  = NULL;          pLFO3  = NULL;
58            KeyGroup = 0;
59      }      }
60    
61      Voice::~Voice() {      Voice::~Voice() {
# Line 62  namespace LinuxSampler { namespace gig { Line 70  namespace LinuxSampler { namespace gig {
70          if (pVCOManipulator)  delete pVCOManipulator;          if (pVCOManipulator)  delete pVCOManipulator;
71      }      }
72    
     void Voice::SetOutput(AudioOutputDevice* pAudioOutputDevice) {  
         this->pOutputLeft        = pAudioOutputDevice->Channel(0)->Buffer();  
         this->pOutputRight       = pAudioOutputDevice->Channel(1)->Buffer();  
         this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();  
         this->SampleRate         = pAudioOutputDevice->SampleRate();  
     }  
   
73      void Voice::SetEngine(Engine* pEngine) {      void Voice::SetEngine(Engine* pEngine) {
74          this->pEngine = pEngine;          this->pEngine = pEngine;
75    
# Line 102  namespace LinuxSampler { namespace gig { Line 103  namespace LinuxSampler { namespace gig {
103       *  Initializes and triggers the voice, a disk stream will be launched if       *  Initializes and triggers the voice, a disk stream will be launched if
104       *  needed.       *  needed.
105       *       *
106       *  @param pNoteOnEvent - event that caused triggering of this voice       *  @param pNoteOnEvent        - event that caused triggering of this voice
107       *  @param PitchBend    - MIDI detune factor (-8192 ... +8191)       *  @param PitchBend           - MIDI detune factor (-8192 ... +8191)
108       *  @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
109       *  @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)
110         *  @param ReleaseTriggerVoice - if this new voice is a release trigger voice (optional, default = false)
111         *  @returns 0 on success, a value < 0 if something failed
112       */       */
113      int Voice::Trigger(Event* pNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument) {      int Voice::Trigger(Event* pNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument, int iLayer, bool ReleaseTriggerVoice) {
114          if (!pInstrument) {          if (!pInstrument) {
115             dmsg(1,("voice::trigger: !pInstrument\n"));             dmsg(1,("voice::trigger: !pInstrument\n"));
116             exit(EXIT_FAILURE);             exit(EXIT_FAILURE);
117          }          }
118    
119            Type            = type_normal;
120          Active          = true;          Active          = true;
121          MIDIKey         = pNoteOnEvent->Key;          MIDIKey         = pNoteOnEvent->Param.Note.Key;
122          pRegion         = pInstrument->GetRegion(MIDIKey);          pRegion         = pInstrument->GetRegion(MIDIKey);
123          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
         Pos             = 0;  
124          Delay           = pNoteOnEvent->FragmentPos();          Delay           = pNoteOnEvent->FragmentPos();
125          pTriggerEvent   = pNoteOnEvent;          pTriggerEvent   = pNoteOnEvent;
126            pKillEvent      = NULL;
127    
128          if (!pRegion) {          if (!pRegion) {
129              std::cerr << "Audio Thread: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush;              std::cerr << "gig::Voice: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush;
130              Kill();              KillImmediately();
131              return -1;              return -1;
132          }          }
133    
134          //TODO: current MIDI controller values are not taken into account yet          KeyGroup = pRegion->KeyGroup;
135          ::gig::DimensionRegion* pDimRgn = NULL;  
136          for (int i = pRegion->Dimensions - 1; i >= 0; i--) { // Check if instrument has a velocity split          // get current dimension values to select the right dimension region
137              if (pRegion->pDimensionDefinitions[i].dimension == ::gig::dimension_velocity) {          //FIXME: controller values for selecting the dimension region here are currently not sample accurate
138                  uint DimValues[5] = {0,0,0,0,0};          uint DimValues[5] = {0,0,0,0,0};
139                      DimValues[i] = pNoteOnEvent->Velocity;          for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
140                  pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);              switch (pRegion->pDimensionDefinitions[i].dimension) {
141                  break;                  case ::gig::dimension_samplechannel:
142                        DimValues[i] = 0; //TODO: we currently ignore this dimension
143                        break;
144                    case ::gig::dimension_layer:
145                        DimValues[i] = iLayer;
146                        // if this is the 1st layer then spawn further voices for all the other layers
147                        if (iLayer == 0)
148                            for (int iNewLayer = 1; iNewLayer < pRegion->pDimensionDefinitions[i].zones; iNewLayer++)
149                                pEngine->LaunchVoice(pNoteOnEvent, iNewLayer, ReleaseTriggerVoice);
150                        break;
151                    case ::gig::dimension_velocity:
152                        DimValues[i] = pNoteOnEvent->Param.Note.Velocity;
153                        break;
154                    case ::gig::dimension_channelaftertouch:
155                        DimValues[i] = 0; //TODO: we currently ignore this dimension
156                        break;
157                    case ::gig::dimension_releasetrigger:
158                        Type = (ReleaseTriggerVoice) ? type_release_trigger : (!iLayer) ? type_release_trigger_required : type_normal;
159                        DimValues[i] = (uint) ReleaseTriggerVoice;
160                        break;
161                    case ::gig::dimension_keyboard:
162                        DimValues[i] = (uint) pNoteOnEvent->Param.Note.Key;
163                        break;
164                    case ::gig::dimension_modwheel:
165                        DimValues[i] = pEngine->ControllerTable[1];
166                        break;
167                    case ::gig::dimension_breath:
168                        DimValues[i] = pEngine->ControllerTable[2];
169                        break;
170                    case ::gig::dimension_foot:
171                        DimValues[i] = pEngine->ControllerTable[4];
172                        break;
173                    case ::gig::dimension_portamentotime:
174                        DimValues[i] = pEngine->ControllerTable[5];
175                        break;
176                    case ::gig::dimension_effect1:
177                        DimValues[i] = pEngine->ControllerTable[12];
178                        break;
179                    case ::gig::dimension_effect2:
180                        DimValues[i] = pEngine->ControllerTable[13];
181                        break;
182                    case ::gig::dimension_genpurpose1:
183                        DimValues[i] = pEngine->ControllerTable[16];
184                        break;
185                    case ::gig::dimension_genpurpose2:
186                        DimValues[i] = pEngine->ControllerTable[17];
187                        break;
188                    case ::gig::dimension_genpurpose3:
189                        DimValues[i] = pEngine->ControllerTable[18];
190                        break;
191                    case ::gig::dimension_genpurpose4:
192                        DimValues[i] = pEngine->ControllerTable[19];
193                        break;
194                    case ::gig::dimension_sustainpedal:
195                        DimValues[i] = pEngine->ControllerTable[64];
196                        break;
197                    case ::gig::dimension_portamento:
198                        DimValues[i] = pEngine->ControllerTable[65];
199                        break;
200                    case ::gig::dimension_sostenutopedal:
201                        DimValues[i] = pEngine->ControllerTable[66];
202                        break;
203                    case ::gig::dimension_softpedal:
204                        DimValues[i] = pEngine->ControllerTable[67];
205                        break;
206                    case ::gig::dimension_genpurpose5:
207                        DimValues[i] = pEngine->ControllerTable[80];
208                        break;
209                    case ::gig::dimension_genpurpose6:
210                        DimValues[i] = pEngine->ControllerTable[81];
211                        break;
212                    case ::gig::dimension_genpurpose7:
213                        DimValues[i] = pEngine->ControllerTable[82];
214                        break;
215                    case ::gig::dimension_genpurpose8:
216                        DimValues[i] = pEngine->ControllerTable[83];
217                        break;
218                    case ::gig::dimension_effect1depth:
219                        DimValues[i] = pEngine->ControllerTable[91];
220                        break;
221                    case ::gig::dimension_effect2depth:
222                        DimValues[i] = pEngine->ControllerTable[92];
223                        break;
224                    case ::gig::dimension_effect3depth:
225                        DimValues[i] = pEngine->ControllerTable[93];
226                        break;
227                    case ::gig::dimension_effect4depth:
228                        DimValues[i] = pEngine->ControllerTable[94];
229                        break;
230                    case ::gig::dimension_effect5depth:
231                        DimValues[i] = pEngine->ControllerTable[95];
232                        break;
233                    case ::gig::dimension_none:
234                        std::cerr << "gig::Voice::Trigger() Error: dimension=none\n" << std::flush;
235                        break;
236                    default:
237                        std::cerr << "gig::Voice::Trigger() Error: Unknown dimension\n" << std::flush;
238              }              }
239          }          }
240          if (!pDimRgn) { // if there was no velocity split          pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);
241              pDimRgn = pRegion->GetDimensionRegionByValue(0,0,0,0,0);  
242            // get starting crossfade volume level
243            switch (pDimRgn->AttenuationController.type) {
244                case ::gig::attenuation_ctrl_t::type_channelaftertouch:
245                    CrossfadeVolume = 1.0f; //TODO: aftertouch not supported yet
246                    break;
247                case ::gig::attenuation_ctrl_t::type_velocity:
248                    CrossfadeVolume = CrossfadeAttenuation(pNoteOnEvent->Param.Note.Velocity);
249                    break;
250                case ::gig::attenuation_ctrl_t::type_controlchange: //FIXME: currently not sample accurate
251                    CrossfadeVolume = CrossfadeAttenuation(pEngine->ControllerTable[pDimRgn->AttenuationController.controller_number]);
252                    break;
253                case ::gig::attenuation_ctrl_t::type_none: // no crossfade defined
254                default:
255                    CrossfadeVolume = 1.0f;
256          }          }
257    
258            const float fpan = float(RTMath::Max(RTMath::Min(pDimRgn->Pan, 63), -64)) / 64.0f;
259            PanLeft  = 1.0f - fpan;
260            PanRight = 1.0f + fpan;
261    
262          pSample = pDimRgn->pSample; // sample won't change until the voice is finished          pSample = pDimRgn->pSample; // sample won't change until the voice is finished
263    
264            Pos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
265    
266          // 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
267          long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;          long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;
268          DiskVoice          = cachedsamples < pSample->SamplesTotal;          DiskVoice          = cachedsamples < pSample->SamplesTotal;
269    
270          if (DiskVoice) { // voice to be streamed from disk          if (DiskVoice) { // voice to be streamed from disk
271              MaxRAMPos = cachedsamples - (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 << 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)
272    
273              // 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
274              if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {              if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {
# Line 159  namespace LinuxSampler { namespace gig { Line 279  namespace LinuxSampler { namespace gig {
279    
280              if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {              if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {
281                  dmsg(1,("Disk stream order failed!\n"));                  dmsg(1,("Disk stream order failed!\n"));
282                  Kill();                  KillImmediately();
283                  return -1;                  return -1;
284              }              }
285              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 177  namespace LinuxSampler { namespace gig { Line 297  namespace LinuxSampler { namespace gig {
297    
298          // calculate initial pitch value          // calculate initial pitch value
299          {          {
300              double pitchbasecents = pDimRgn->FineTune * 10;              double pitchbasecents = pDimRgn->FineTune * 10 + (int) pEngine->ScaleTuning[MIDIKey % 12];
301              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;
302              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents);              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate()));
303              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
304          }          }
305    
306    
307          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->GetVelocityAttenuation(pNoteOnEvent->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)
308    
309    
310          // setup EG 1 (VCA EG)          // setup EG 1 (VCA EG)
# Line 199  namespace LinuxSampler { namespace gig { Line 319  namespace LinuxSampler { namespace gig {
319                      eg1controllervalue = 0; // TODO: aftertouch not yet supported                      eg1controllervalue = 0; // TODO: aftertouch not yet supported
320                      break;                      break;
321                  case ::gig::eg1_ctrl_t::type_velocity:                  case ::gig::eg1_ctrl_t::type_velocity:
322                      eg1controllervalue = pNoteOnEvent->Velocity;                      eg1controllervalue = pNoteOnEvent->Param.Note.Velocity;
323                      break;                      break;
324                  case ::gig::eg1_ctrl_t::type_controlchange: // MIDI control change controller                  case ::gig::eg1_ctrl_t::type_controlchange: // MIDI control change controller
325                      eg1controllervalue = pEngine->ControllerTable[pDimRgn->EG1Controller.controller_number];                      eg1controllervalue = pEngine->ControllerTable[pDimRgn->EG1Controller.controller_number];
# Line 238  namespace LinuxSampler { namespace gig { Line 358  namespace LinuxSampler { namespace gig {
358                      eg2controllervalue = 0; // TODO: aftertouch not yet supported                      eg2controllervalue = 0; // TODO: aftertouch not yet supported
359                      break;                      break;
360                  case ::gig::eg2_ctrl_t::type_velocity:                  case ::gig::eg2_ctrl_t::type_velocity:
361                      eg2controllervalue = pNoteOnEvent->Velocity;                      eg2controllervalue = pNoteOnEvent->Param.Note.Velocity;
362                      break;                      break;
363                  case ::gig::eg2_ctrl_t::type_controlchange: // MIDI control change controller                  case ::gig::eg2_ctrl_t::type_controlchange: // MIDI control change controller
364                      eg2controllervalue = pEngine->ControllerTable[pDimRgn->EG2Controller.controller_number];                      eg2controllervalue = pEngine->ControllerTable[pDimRgn->EG2Controller.controller_number];
# Line 305  namespace LinuxSampler { namespace gig { Line 425  namespace LinuxSampler { namespace gig {
425                            pDimRgn->LFO1ControlDepth,                            pDimRgn->LFO1ControlDepth,
426                            pEngine->ControllerTable[pLFO1->ExtController],                            pEngine->ControllerTable[pLFO1->ExtController],
427                            pDimRgn->LFO1FlipPhase,                            pDimRgn->LFO1FlipPhase,
428                            this->SampleRate,                            pEngine->SampleRate,
429                            Delay);                            Delay);
430          }          }
431    
# Line 343  namespace LinuxSampler { namespace gig { Line 463  namespace LinuxSampler { namespace gig {
463                            pDimRgn->LFO2ControlDepth,                            pDimRgn->LFO2ControlDepth,
464                            pEngine->ControllerTable[pLFO2->ExtController],                            pEngine->ControllerTable[pLFO2->ExtController],
465                            pDimRgn->LFO2FlipPhase,                            pDimRgn->LFO2FlipPhase,
466                              pEngine->SampleRate,
467                            Delay);                            Delay);
468          }          }
469      #endif // ENABLE_FILTER      #endif // ENABLE_FILTER
# Line 380  namespace LinuxSampler { namespace gig { Line 501  namespace LinuxSampler { namespace gig {
501                            pDimRgn->LFO3ControlDepth,                            pDimRgn->LFO3ControlDepth,
502                            pEngine->ControllerTable[pLFO3->ExtController],                            pEngine->ControllerTable[pLFO3->ExtController],
503                            false,                            false,
504                            this->SampleRate,                            pEngine->SampleRate,
505                            Delay);                            Delay);
506          }          }
507    
# Line 465  namespace LinuxSampler { namespace gig { Line 586  namespace LinuxSampler { namespace gig {
586    
587              // calculate cutoff frequency              // calculate cutoff frequency
588              float cutoff = (!VCFCutoffCtrl.controller)              float cutoff = (!VCFCutoffCtrl.controller)
589                  ? exp((float) (127 - pNoteOnEvent->Velocity) * (float) pDimRgn->VCFVelocityScale * 6.2E-5f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX                  ? exp((float) (127 - pNoteOnEvent->Param.Note.Velocity) * (float) pDimRgn->VCFVelocityScale * 6.2E-5f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX
590                  : exp((float) VCFCutoffCtrl.value * 0.00787402f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX;                  : exp((float) VCFCutoffCtrl.value * 0.00787402f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX;
591    
592              // calculate resonance              // calculate resonance
593              float resonance = (float) VCFResonanceCtrl.value * 0.00787f;   // 0.0..1.0              float resonance = (float) VCFResonanceCtrl.value * 0.00787f;   // 0.0..1.0
594              if (pDimRgn->VCFKeyboardTracking) {              if (pDimRgn->VCFKeyboardTracking) {
595                  resonance += (float) (pNoteOnEvent->Key - pDimRgn->VCFKeyboardTrackingBreakpoint) * 0.00787f;                  resonance += (float) (pNoteOnEvent->Param.Note.Key - pDimRgn->VCFKeyboardTrackingBreakpoint) * 0.00787f;
596              }              }
597              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)
598    
599              VCFCutoffCtrl.fvalue    = cutoff - FILTER_CUTOFF_MIN;              VCFCutoffCtrl.fvalue    = cutoff - FILTER_CUTOFF_MIN;
600              VCFResonanceCtrl.fvalue = resonance;              VCFResonanceCtrl.fvalue = resonance;
601    
602              FilterLeft.SetParameters(cutoff,  resonance, SampleRate);              FilterLeft.SetParameters(cutoff,  resonance, pEngine->SampleRate);
603              FilterRight.SetParameters(cutoff, resonance, SampleRate);              FilterRight.SetParameters(cutoff, resonance, pEngine->SampleRate);
604    
605              FilterUpdateCounter = -1;              FilterUpdateCounter = -1;
606          }          }
# Line 489  namespace LinuxSampler { namespace gig { Line 610  namespace LinuxSampler { namespace gig {
610          }          }
611      #endif // ENABLE_FILTER      #endif // ENABLE_FILTER
612    
         // ************************************************  
         // TODO: ARTICULATION DATA HANDLING IS MISSING HERE  
         // ************************************************  
   
613          return 0; // success          return 0; // success
614      }      }
615    
# Line 510  namespace LinuxSampler { namespace gig { Line 627  namespace LinuxSampler { namespace gig {
627      void Voice::Render(uint Samples) {      void Voice::Render(uint Samples) {
628    
629          // Reset the synthesis parameter matrix          // Reset the synthesis parameter matrix
630          pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume);          pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngine->GlobalVolume);
631          pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase);          pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase);
632      #if ENABLE_FILTER      #if ENABLE_FILTER
633          pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue);          pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue);
# Line 523  namespace LinuxSampler { namespace gig { Line 640  namespace LinuxSampler { namespace gig {
640    
641    
642          // 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
643          pEG1->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);          pEG1->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->PitchBase * this->PitchBend, pKillEvent);
644      #if ENABLE_FILTER      #if ENABLE_FILTER
645          pEG2->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);          pEG2->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);
646      #endif // ENABLE_FILTER      #endif // ENABLE_FILTER
# Line 535  namespace LinuxSampler { namespace gig { Line 652  namespace LinuxSampler { namespace gig {
652          pLFO3->Process(Samples);          pLFO3->Process(Samples);
653    
654    
655        #if ENABLE_FILTER
656            CalculateBiquadParameters(Samples); // calculate the final biquad filter parameters
657        #endif // ENABLE_FILTER
658    
659    
660          switch (this->PlaybackState) {          switch (this->PlaybackState) {
661    
662              case playback_state_ram: {              case playback_state_ram: {
663                      if (RAMLoop) InterpolateAndLoop(Samples, (sample_t*) pSample->GetCache().pStart, Delay);                      if (RAMLoop) InterpolateAndLoop(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
664                      else         Interpolate(Samples, (sample_t*) pSample->GetCache().pStart, Delay);                      else         InterpolateNoLoop(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
665                      if (DiskVoice) {                      if (DiskVoice) {
666                          // check if we reached the allowed limit of the sample RAM cache                          // check if we reached the allowed limit of the sample RAM cache
667                          if (Pos > MaxRAMPos) {                          if (Pos > MaxRAMPos) {
# Line 559  namespace LinuxSampler { namespace gig { Line 681  namespace LinuxSampler { namespace gig {
681                          DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);                          DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);
682                          if (!DiskStreamRef.pStream) {                          if (!DiskStreamRef.pStream) {
683                              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;
684                              Kill();                              KillImmediately();
685                              return;                              return;
686                          }                          }
687                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (RTMath::DoubleToInt(Pos) - MaxRAMPos));                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (RTMath::DoubleToInt(Pos) - MaxRAMPos));
# Line 567  namespace LinuxSampler { namespace gig { Line 689  namespace LinuxSampler { namespace gig {
689                      }                      }
690    
691                      // 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)
692                      if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels) {                      if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels) {
693                          DiskStreamRef.pStream->WriteSilence((MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels);                          DiskStreamRef.pStream->WriteSilence((pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels);
694                          this->PlaybackState = playback_state_end;                          this->PlaybackState = playback_state_end;
695                      }                      }
696    
697                      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
698                      Interpolate(Samples, ptr, Delay);                      InterpolateNoLoop(Samples, ptr, Delay);
699                      DiskStreamRef.pStream->IncrementReadPos(RTMath::DoubleToInt(Pos) * pSample->Channels);                      DiskStreamRef.pStream->IncrementReadPos(RTMath::DoubleToInt(Pos) * pSample->Channels);
700                      Pos -= RTMath::DoubleToInt(Pos);                      Pos -= RTMath::DoubleToInt(Pos);
701                  }                  }
702                  break;                  break;
703    
704              case playback_state_end:              case playback_state_end:
705                  Kill(); // free voice                  KillImmediately(); // free voice
706                  break;                  break;
707          }          }
708    
709    
     #if ENABLE_FILTER  
710          // 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)
711            pEngine->pSynthesisEvents[Event::destination_vca]->clear();
712        #if ENABLE_FILTER
713          pEngine->pSynthesisEvents[Event::destination_vcfc]->clear();          pEngine->pSynthesisEvents[Event::destination_vcfc]->clear();
714          pEngine->pSynthesisEvents[Event::destination_vcfr]->clear();          pEngine->pSynthesisEvents[Event::destination_vcfr]->clear();
715      #endif // ENABLE_FILTER      #endif // ENABLE_FILTER
# Line 630  namespace LinuxSampler { namespace gig { Line 753  namespace LinuxSampler { namespace gig {
753              while (pCCEvent && pCCEvent->FragmentPos() <= Delay) pCCEvent = pEngine->pCCEvents->next();              while (pCCEvent && pCCEvent->FragmentPos() <= Delay) pCCEvent = pEngine->pCCEvents->next();
754          }          }
755          while (pCCEvent) {          while (pCCEvent) {
756              if (pCCEvent->Controller) { // if valid MIDI controller              if (pCCEvent->Param.CC.Controller) { // if valid MIDI controller
757                  #if ENABLE_FILTER                  #if ENABLE_FILTER
758                  if (pCCEvent->Controller == VCFCutoffCtrl.controller) {                  if (pCCEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {
759                      pEngine->pSynthesisEvents[Event::destination_vcfc]->alloc_assign(*pCCEvent);                      pEngine->pSynthesisEvents[Event::destination_vcfc]->alloc_assign(*pCCEvent);
760                  }                  }
761                  if (pCCEvent->Controller == VCFResonanceCtrl.controller) {                  if (pCCEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
762                      pEngine->pSynthesisEvents[Event::destination_vcfr]->alloc_assign(*pCCEvent);                      pEngine->pSynthesisEvents[Event::destination_vcfr]->alloc_assign(*pCCEvent);
763                  }                  }
764                  #endif // ENABLE_FILTER                  #endif // ENABLE_FILTER
765                  if (pCCEvent->Controller == pLFO1->ExtController) {                  if (pCCEvent->Param.CC.Controller == pLFO1->ExtController) {
766                      pLFO1->SendEvent(pCCEvent);                      pLFO1->SendEvent(pCCEvent);
767                  }                  }
768                  #if ENABLE_FILTER                  #if ENABLE_FILTER
769                  if (pCCEvent->Controller == pLFO2->ExtController) {                  if (pCCEvent->Param.CC.Controller == pLFO2->ExtController) {
770                      pLFO2->SendEvent(pCCEvent);                      pLFO2->SendEvent(pCCEvent);
771                  }                  }
772                  #endif // ENABLE_FILTER                  #endif // ENABLE_FILTER
773                  if (pCCEvent->Controller == pLFO3->ExtController) {                  if (pCCEvent->Param.CC.Controller == pLFO3->ExtController) {
774                      pLFO3->SendEvent(pCCEvent);                      pLFO3->SendEvent(pCCEvent);
775                  }                  }
776                    if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange &&
777                        pCCEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) { // if crossfade event
778                        pEngine->pSynthesisEvents[Event::destination_vca]->alloc_assign(*pCCEvent);
779                    }
780              }              }
781    
782              pCCEvent = pEngine->pCCEvents->next();              pCCEvent = pEngine->pCCEvents->next();
# Line 677  namespace LinuxSampler { namespace gig { Line 804  namespace LinuxSampler { namespace gig {
804                  // calculate the influence length of this event (in sample points)                  // calculate the influence length of this event (in sample points)
805                  uint end = (pNextVCOEvent) ? pNextVCOEvent->FragmentPos() : Samples;                  uint end = (pNextVCOEvent) ? pNextVCOEvent->FragmentPos() : Samples;
806    
807                  pitch = RTMath::CentsToFreqRatio(((double) pVCOEvent->Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents                  pitch = RTMath::CentsToFreqRatio(((double) pVCOEvent->Param.Pitch.Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents
808    
809                  // apply pitch value to the pitch parameter sequence                  // apply pitch value to the pitch parameter sequence
810                  for (uint i = pVCOEvent->FragmentPos(); i < end; i++) {                  for (uint i = pVCOEvent->FragmentPos(); i < end; i++) {
# Line 689  namespace LinuxSampler { namespace gig { Line 816  namespace LinuxSampler { namespace gig {
816              if (pVCOEventList->last()) this->PitchBend = pitch;              if (pVCOEventList->last()) this->PitchBend = pitch;
817          }          }
818    
819            // process volume / attenuation events (TODO: we only handle and _expect_ crossfade events here ATM !)
820            {
821                RTEList<Event>* pVCAEventList = pEngine->pSynthesisEvents[Event::destination_vca];
822                Event* pVCAEvent = pVCAEventList->first();
823                if (Delay) { // skip events that happened before this voice was triggered
824                    while (pVCAEvent && pVCAEvent->FragmentPos() <= Delay) pVCAEvent = pVCAEventList->next();
825                }
826                float crossfadevolume;
827                while (pVCAEvent) {
828                    Event* pNextVCAEvent = pVCAEventList->next();
829    
830                    // calculate the influence length of this event (in sample points)
831                    uint end = (pNextVCAEvent) ? pNextVCAEvent->FragmentPos() : Samples;
832    
833                    crossfadevolume = CrossfadeAttenuation(pVCAEvent->Param.CC.Value);
834    
835                    float effective_volume = crossfadevolume * this->Volume * pEngine->GlobalVolume;
836    
837                    // apply volume value to the volume parameter sequence
838                    for (uint i = pVCAEvent->FragmentPos(); i < end; i++) {
839                        pEngine->pSynthesisParameters[Event::destination_vca][i] = effective_volume;
840                    }
841    
842                    pVCAEvent = pNextVCAEvent;
843                }
844                if (pVCAEventList->last()) this->CrossfadeVolume = crossfadevolume;
845            }
846    
847      #if ENABLE_FILTER      #if ENABLE_FILTER
848          // process filter cutoff events          // process filter cutoff events
# Line 705  namespace LinuxSampler { namespace gig { Line 859  namespace LinuxSampler { namespace gig {
859                  // calculate the influence length of this event (in sample points)                  // calculate the influence length of this event (in sample points)
860                  uint end = (pNextCutoffEvent) ? pNextCutoffEvent->FragmentPos() : Samples;                  uint end = (pNextCutoffEvent) ? pNextCutoffEvent->FragmentPos() : Samples;
861    
862                  cutoff = exp((float) pCutoffEvent->Value * 0.00787402f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX - FILTER_CUTOFF_MIN;                  cutoff = exp((float) pCutoffEvent->Param.CC.Value * 0.00787402f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX - FILTER_CUTOFF_MIN;
863    
864                  // apply cutoff frequency to the cutoff parameter sequence                  // apply cutoff frequency to the cutoff parameter sequence
865                  for (uint i = pCutoffEvent->FragmentPos(); i < end; i++) {                  for (uint i = pCutoffEvent->FragmentPos(); i < end; i++) {
# Line 731  namespace LinuxSampler { namespace gig { Line 885  namespace LinuxSampler { namespace gig {
885                  uint end = (pNextResonanceEvent) ? pNextResonanceEvent->FragmentPos() : Samples;                  uint end = (pNextResonanceEvent) ? pNextResonanceEvent->FragmentPos() : Samples;
886    
887                  // convert absolute controller value to differential                  // convert absolute controller value to differential
888                  int ctrldelta = pResonanceEvent->Value - VCFResonanceCtrl.value;                  int ctrldelta = pResonanceEvent->Param.CC.Value - VCFResonanceCtrl.value;
889                  VCFResonanceCtrl.value = pResonanceEvent->Value;                  VCFResonanceCtrl.value = pResonanceEvent->Param.CC.Value;
890    
891                  float resonancedelta = (float) ctrldelta * 0.00787f; // 0.0..1.0                  float resonancedelta = (float) ctrldelta * 0.00787f; // 0.0..1.0
892    
# Line 743  namespace LinuxSampler { namespace gig { Line 897  namespace LinuxSampler { namespace gig {
897    
898                  pResonanceEvent = pNextResonanceEvent;                  pResonanceEvent = pNextResonanceEvent;
899              }              }
900              if (pResonanceEventList->last()) VCFResonanceCtrl.fvalue = pResonanceEventList->last()->Value * 0.00787f; // needed for initialization of parameter matrix next time              if (pResonanceEventList->last()) VCFResonanceCtrl.fvalue = pResonanceEventList->last()->Param.CC.Value * 0.00787f; // needed for initialization of parameter matrix next time
901          }          }
902      #endif // ENABLE_FILTER      #endif // ENABLE_FILTER
903      }      }
904    
905        #if ENABLE_FILTER
906      /**      /**
907       *  Interpolates the input audio data (no loop).       * Calculate all necessary, final biquad filter parameters.
908         *
909         * @param Samples - number of samples to be rendered in this audio fragment cycle
910         */
911        void Voice::CalculateBiquadParameters(uint Samples) {
912            if (!FilterLeft.Enabled) return;
913    
914            biquad_param_t bqbase;
915            biquad_param_t bqmain;
916            float prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][0];
917            float prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][0];
918            FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
919            pEngine->pBasicFilterParameters[0] = bqbase;
920            pEngine->pMainFilterParameters[0]  = bqmain;
921    
922            float* bq;
923            for (int i = 1; i < Samples; i++) {
924                // recalculate biquad parameters if cutoff or resonance differ from previous sample point
925                if (!(i & FILTER_UPDATE_MASK)) if (pEngine->pSynthesisParameters[Event::destination_vcfr][i] != prev_res ||
926                                                   pEngine->pSynthesisParameters[Event::destination_vcfc][i] != prev_cutoff) {
927                    prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i];
928                    prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][i];
929                    FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
930                }
931    
932                //same as 'pEngine->pBasicFilterParameters[i] = bqbase;'
933                bq    = (float*) &pEngine->pBasicFilterParameters[i];
934                bq[0] = bqbase.a1;
935                bq[1] = bqbase.a2;
936                bq[2] = bqbase.b0;
937                bq[3] = bqbase.b1;
938                bq[4] = bqbase.b2;
939    
940                // same as 'pEngine->pMainFilterParameters[i] = bqmain;'
941                bq    = (float*) &pEngine->pMainFilterParameters[i];
942                bq[0] = bqmain.a1;
943                bq[1] = bqmain.a2;
944                bq[2] = bqmain.b0;
945                bq[3] = bqmain.b1;
946                bq[4] = bqmain.b2;
947            }
948        }
949        #endif // ENABLE_FILTER
950    
951        /**
952         *  Interpolates the input audio data (without looping).
953       *       *
954       *  @param Samples - number of sample points to be rendered in this audio       *  @param Samples - number of sample points to be rendered in this audio
955       *                   fragment cycle       *                   fragment cycle
956       *  @param pSrc    - pointer to input sample data       *  @param pSrc    - pointer to input sample data
957       *  @param Skip    - number of sample points to skip in output buffer       *  @param Skip    - number of sample points to skip in output buffer
958       */       */
959      void Voice::Interpolate(uint Samples, sample_t* pSrc, uint Skip) {      void Voice::InterpolateNoLoop(uint Samples, sample_t* pSrc, uint Skip) {
960          int i = Skip;          int i = Skip;
961    
962          // FIXME: assuming either mono or stereo          // FIXME: assuming either mono or stereo
963          if (this->pSample->Channels == 2) { // Stereo Sample          if (this->pSample->Channels == 2) { // Stereo Sample
964              while (i < Samples) {              while (i < Samples) InterpolateStereo(pSrc, i);
                 InterpolateOneStep_Stereo(pSrc, i,  
                                           pEngine->pSynthesisParameters[Event::destination_vca][i],  
                                           pEngine->pSynthesisParameters[Event::destination_vco][i],  
                                           pEngine->pSynthesisParameters[Event::destination_vcfc][i],  
                                           pEngine->pSynthesisParameters[Event::destination_vcfr][i]);  
             }  
965          }          }
966          else { // Mono Sample          else { // Mono Sample
967              while (i < Samples) {              while (i < Samples) InterpolateMono(pSrc, i);
                 InterpolateOneStep_Mono(pSrc, i,  
                                         pEngine->pSynthesisParameters[Event::destination_vca][i],  
                                         pEngine->pSynthesisParameters[Event::destination_vco][i],  
                                         pEngine->pSynthesisParameters[Event::destination_vcfc][i],  
                                         pEngine->pSynthesisParameters[Event::destination_vcfr][i]);  
             }  
968          }          }
969      }      }
970    
# Line 796  namespace LinuxSampler { namespace gig { Line 984  namespace LinuxSampler { namespace gig {
984              if (pSample->LoopPlayCount) {              if (pSample->LoopPlayCount) {
985                  // render loop (loop count limited)                  // render loop (loop count limited)
986                  while (i < Samples && LoopCyclesLeft) {                  while (i < Samples && LoopCyclesLeft) {
987                      InterpolateOneStep_Stereo(pSrc, i,                      InterpolateStereo(pSrc, i);
                                               pEngine->pSynthesisParameters[Event::destination_vca][i],  
                                               pEngine->pSynthesisParameters[Event::destination_vco][i],  
                                               pEngine->pSynthesisParameters[Event::destination_vcfc][i],  
                                               pEngine->pSynthesisParameters[Event::destination_vcfr][i]);  
988                      if (Pos > pSample->LoopEnd) {                      if (Pos > pSample->LoopEnd) {
989                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
990                          LoopCyclesLeft--;                          LoopCyclesLeft--;
991                      }                      }
992                  }                  }
993                  // render on without loop                  // render on without loop
994                  while (i < Samples) {                  while (i < Samples) InterpolateStereo(pSrc, i);
                     InterpolateOneStep_Stereo(pSrc, i,  
                                               pEngine->pSynthesisParameters[Event::destination_vca][i],  
                                               pEngine->pSynthesisParameters[Event::destination_vco][i],  
                                               pEngine->pSynthesisParameters[Event::destination_vcfc][i],  
                                               pEngine->pSynthesisParameters[Event::destination_vcfr][i]);  
                 }  
995              }              }
996              else { // render loop (endless loop)              else { // render loop (endless loop)
997                  while (i < Samples) {                  while (i < Samples) {
998                      InterpolateOneStep_Stereo(pSrc, i,                      InterpolateStereo(pSrc, i);
                                               pEngine->pSynthesisParameters[Event::destination_vca][i],  
                                               pEngine->pSynthesisParameters[Event::destination_vco][i],  
                                               pEngine->pSynthesisParameters[Event::destination_vcfc][i],  
                                               pEngine->pSynthesisParameters[Event::destination_vcfr][i]);  
999                      if (Pos > pSample->LoopEnd) {                      if (Pos > pSample->LoopEnd) {
1000                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);
1001                      }                      }
# Line 832  namespace LinuxSampler { namespace gig { Line 1006  namespace LinuxSampler { namespace gig {
1006              if (pSample->LoopPlayCount) {              if (pSample->LoopPlayCount) {
1007                  // render loop (loop count limited)                  // render loop (loop count limited)
1008                  while (i < Samples && LoopCyclesLeft) {                  while (i < Samples && LoopCyclesLeft) {
1009                      InterpolateOneStep_Mono(pSrc, i,                      InterpolateMono(pSrc, i);
                                             pEngine->pSynthesisParameters[Event::destination_vca][i],  
                                             pEngine->pSynthesisParameters[Event::destination_vco][i],  
                                             pEngine->pSynthesisParameters[Event::destination_vcfc][i],  
                                             pEngine->pSynthesisParameters[Event::destination_vcfr][i]);  
1010                      if (Pos > pSample->LoopEnd) {                      if (Pos > pSample->LoopEnd) {
1011                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
1012                          LoopCyclesLeft--;                          LoopCyclesLeft--;
1013                      }                      }
1014                  }                  }
1015                  // render on without loop                  // render on without loop
1016                  while (i < Samples) {                  while (i < Samples) InterpolateMono(pSrc, i);
                     InterpolateOneStep_Mono(pSrc, i,  
                                             pEngine->pSynthesisParameters[Event::destination_vca][i],  
                                             pEngine->pSynthesisParameters[Event::destination_vco][i],  
                                             pEngine->pSynthesisParameters[Event::destination_vcfc][i],  
                                             pEngine->pSynthesisParameters[Event::destination_vcfr][i]);  
                 }  
1017              }              }
1018              else { // render loop (endless loop)              else { // render loop (endless loop)
1019                  while (i < Samples) {                  while (i < Samples) {
1020                      InterpolateOneStep_Mono(pSrc, i,                      InterpolateMono(pSrc, i);
                                             pEngine->pSynthesisParameters[Event::destination_vca][i],  
                                             pEngine->pSynthesisParameters[Event::destination_vco][i],  
                                             pEngine->pSynthesisParameters[Event::destination_vcfc][i],  
                                             pEngine->pSynthesisParameters[Event::destination_vcfr][i]);  
1021                      if (Pos > pSample->LoopEnd) {                      if (Pos > pSample->LoopEnd) {
1022                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
1023                      }                      }
# Line 867  namespace LinuxSampler { namespace gig { Line 1027  namespace LinuxSampler { namespace gig {
1027      }      }
1028    
1029      /**      /**
1030       *  Immediately kill the voice.       *  Immediately kill the voice. This method should not be used to kill
1031         *  a normal, active voice, because it doesn't take care of things like
1032         *  fading down the volume level to avoid clicks and regular processing
1033         *  until the kill event actually occured!
1034         *
1035         *  @see Kill()
1036       */       */
1037      void Voice::Kill() {      void Voice::KillImmediately() {
1038          if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {          if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
1039              pDiskThread->OrderDeletionOfStream(&DiskStreamRef);              pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
1040          }          }
1041          Reset();          Reset();
1042      }      }
1043    
1044        /**
1045         *  Kill the voice in regular sense. Let the voice render audio until
1046         *  the kill event actually occured and then fade down the volume level
1047         *  very quickly and let the voice die finally. Unlike a normal release
1048         *  of a voice, a kill process cannot be cancalled and is therefore
1049         *  usually used for voice stealing and key group conflicts.
1050         *
1051         *  @param pKillEvent - event which caused the voice to be killed
1052         */
1053        void Voice::Kill(Event* pKillEvent) {
1054            if (pTriggerEvent && pKillEvent->FragmentPos() <= pTriggerEvent->FragmentPos()) return;
1055            this->pKillEvent = pKillEvent;
1056        }
1057    
1058  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

Legend:
Removed from v.64  
changed lines
  Added in v.247

  ViewVC Help
Powered by ViewVC