/[svn]/linuxsampler/trunk/src/engines/gig/Voice.h
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/gig/Voice.h

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 53 by schoenebeck, Mon Apr 26 17:15:51 2004 UTC revision 287 by schoenebeck, Sat Oct 16 17:38:03 2004 UTC
# Line 2  Line 2 
2   *                                                                         *   *                                                                         *
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003 by Benno Senoner and Christian Schoenebeck         *   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6   *                                                                         *   *                                                                         *
7   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
8   *   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 31  Line 31 
31    
32  #include "../../common/RTMath.h"  #include "../../common/RTMath.h"
33  #include "../../common/RingBuffer.h"  #include "../../common/RingBuffer.h"
34  #include "../../common/RTELMemoryPool.h"  #include "../../common/Pool.h"
35  #include "../../audiodriver/AudioOutputDevice.h"  #include "../../drivers/audio/AudioOutputDevice.h"
36  #include "../../lib/fileloader/libgig/gig.h"  #include "../../lib/fileloader/libgig/gig.h"
37    #include "../common/BiquadFilter.h"
38  #include "Engine.h"  #include "Engine.h"
39  #include "Stream.h"  #include "Stream.h"
40  #include "DiskThread.h"  #include "DiskThread.h"
# Line 42  Line 43 
43  #include "Filter.h"  #include "Filter.h"
44  #include "../common/LFO.h"  #include "../common/LFO.h"
45    
46  #define USE_LINEAR_INTERPOLATION        1  ///< set to 0 if you prefer cubic interpolation (slower, better quality)  #define USE_LINEAR_INTERPOLATION        0  ///< set to 0 if you prefer cubic interpolation (slower, better quality)
47  #define ENABLE_FILTER                   0  ///< if set to 0 then filter (VCF) code is ignored on compile time  #define ENABLE_FILTER                   1  ///< if set to 0 then filter (VCF) code is ignored on compile time
48  #define FILTER_UPDATE_PERIOD            64 ///< amount of sample points after which filter parameters (cutoff, resonance) are going to be updated (higher value means less CPU load, but also worse parameter resolution)  #define FILTER_UPDATE_PERIOD            64 ///< amount of sample points after which filter parameters (cutoff, resonance) are going to be updated (higher value means less CPU load, but also worse parameter resolution, this value will be aligned to a power of two)
49  #define FORCE_FILTER_USAGE              0  ///< if set to 1 then filter is always used, if set to 0 filter is used only in case the instrument file defined one  #define FORCE_FILTER_USAGE              0  ///< if set to 1 then filter is always used, if set to 0 filter is used only in case the instrument file defined one
50  #define FILTER_CUTOFF_MAX               10000.0f ///< maximum cutoff frequency (10kHz)  #define FILTER_CUTOFF_MAX               10000.0f ///< maximum cutoff frequency (10kHz)
51  #define FILTER_CUTOFF_MIN               100.0f   ///< minimum cutoff frequency (100Hz)  #define FILTER_CUTOFF_MIN               100.0f   ///< minimum cutoff frequency (100Hz)
# Line 79  namespace LinuxSampler { namespace gig { Line 80  namespace LinuxSampler { namespace gig {
80       */       */
81      class Voice {      class Voice {
82          public:          public:
83                // Types
84                enum type_t {
85                    type_normal,
86                    type_release_trigger_required,  ///< If the key of this voice will be released, it causes a release triggered voice to be spawned
87                    type_release_trigger            ///< Release triggered voice which cannot be killed by releasing its key
88                };
89    
90              // Attributes              // Attributes
91                type_t       Type;         ///< Voice Type
92              int          MIDIKey;      ///< MIDI key number of the key that triggered the voice              int          MIDIKey;      ///< MIDI key number of the key that triggered the voice
93                uint         KeyGroup;
94              DiskThread*  pDiskThread;  ///< Pointer to the disk thread, to be able to order a disk stream and later to delete the stream again              DiskThread*  pDiskThread;  ///< Pointer to the disk thread, to be able to order a disk stream and later to delete the stream again
95                RTList<Voice>::Iterator itChildVoice; ///< Points to the next layer voice (if any). This field is currently only used by the voice stealing algorithm.
96    
97              // Methods              // Methods
98              Voice();              Voice();
99             ~Voice();             ~Voice();
100              void Kill();              void Kill(Pool<Event>::Iterator& itKillEvent);
101              void Render(uint Samples);              void Render(uint Samples);
102              void Reset();              void Reset();
103              void SetOutput(AudioOutputDevice* pAudioOutputDevice);              void SetOutput(AudioOutputDevice* pAudioOutputDevice);
104              void SetEngine(Engine* pEngine);              void SetEngine(Engine* pEngine);
105              int  Trigger(Event* pNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument);              int  Trigger(Pool<Event>::Iterator& itNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing);
106              inline bool IsActive() { return Active; }              inline bool IsActive() { return PlaybackState; }
107          private:          private:
108              // Types              // Types
109              enum playback_state_t {              enum playback_state_t {
110                  playback_state_ram,                  playback_state_end  = 0,
111                  playback_state_disk,                  playback_state_ram  = 1,
112                  playback_state_end                  playback_state_disk = 2
113              };              };
114    
115              // Attributes              // Attributes
116              gig::Engine*                pEngine;            ///< Pointer to the sampler engine, to be able to access the event lists.              gig::Engine*                pEngine;            ///< Pointer to the sampler engine, to be able to access the event lists.
117              float                       Volume;             ///< Volume level of the voice              float                       Volume;             ///< Volume level of the voice
118              float*                      pOutputLeft;        ///< Audio output channel buffer (left)              float                       PanLeft;
119              float*                      pOutputRight;       ///< Audio output channel buffer (right)              float                       PanRight;
120              uint                        SampleRate;         ///< Sample rate of the engines output audio signal (in Hz)              float                       CrossfadeVolume;    ///< Current attenuation level caused by a crossfade (only if a crossfade is defined of course)
             uint                        MaxSamplesPerCycle; ///< Size of each audio output buffer  
121              double                      Pos;                ///< Current playback position in sample              double                      Pos;                ///< Current playback position in sample
122              double                      PitchBase;          ///< Basic pitch depth, stays the same for the whole life time of the voice              double                      PitchBase;          ///< Basic pitch depth, stays the same for the whole life time of the voice
123              double                      PitchBend;          ///< Current pitch value of the pitchbend wheel              double                      PitchBend;          ///< Current pitch value of the pitchbend wheel
124              ::gig::Sample*              pSample;            ///< Pointer to the sample to be played back              ::gig::Sample*              pSample;            ///< Pointer to the sample to be played back
125              ::gig::Region*              pRegion;            ///< Pointer to the articulation information of the respective keyboard region of this voice              ::gig::Region*              pRegion;            ///< Pointer to the articulation information of the respective keyboard region of this voice
126              bool                        Active;             ///< If this voice object is currently in usage              ::gig::DimensionRegion*     pDimRgn;            ///< Pointer to the articulation information of current dimension region of this voice
127              playback_state_t            PlaybackState;      ///< When a sample will be triggered, it will be first played from RAM cache and after a couple of sample points it will switch to disk streaming and at the end of a disk stream we have to add null samples, so the interpolator can do it's work correctly              playback_state_t            PlaybackState;      ///< When a sample will be triggered, it will be first played from RAM cache and after a couple of sample points it will switch to disk streaming and at the end of a disk stream we have to add null samples, so the interpolator can do it's work correctly
128              bool                        DiskVoice;          ///< If the sample is very short it completely fits into the RAM cache and doesn't need to be streamed from disk, in that case this flag is set to false              bool                        DiskVoice;          ///< If the sample is very short it completely fits into the RAM cache and doesn't need to be streamed from disk, in that case this flag is set to false
129              Stream::reference_t         DiskStreamRef;      ///< Reference / link to the disk stream              Stream::reference_t         DiskStreamRef;      ///< Reference / link to the disk stream
# Line 130  namespace LinuxSampler { namespace gig { Line 140  namespace LinuxSampler { namespace gig {
140              midi_ctrl                   VCFResonanceCtrl;              midi_ctrl                   VCFResonanceCtrl;
141              int                         FilterUpdateCounter; ///< Used to update filter parameters all FILTER_UPDATE_PERIOD samples              int                         FilterUpdateCounter; ///< Used to update filter parameters all FILTER_UPDATE_PERIOD samples
142              static const float          FILTER_CUTOFF_COEFF;              static const float          FILTER_CUTOFF_COEFF;
143                static const int            FILTER_UPDATE_MASK;
144              VCAManipulator*             pVCAManipulator;              VCAManipulator*             pVCAManipulator;
145              VCFCManipulator*            pVCFCManipulator;              VCFCManipulator*            pVCFCManipulator;
146              VCOManipulator*             pVCOManipulator;              VCOManipulator*             pVCOManipulator;
147              LFO<gig::VCAManipulator>*   pLFO1;              ///< Low Frequency Oscillator 1 (Amplification)              LFO<gig::VCAManipulator>*   pLFO1;              ///< Low Frequency Oscillator 1 (Amplification)
148              LFO<gig::VCFCManipulator>*  pLFO2;             ///< Low Frequency Oscillator 2 (Filter cutoff frequency)              LFO<gig::VCFCManipulator>*  pLFO2;             ///< Low Frequency Oscillator 2 (Filter cutoff frequency)
149              LFO<gig::VCOManipulator>*   pLFO3;              ///< Low Frequency Oscillator 3 (Pitch)              LFO<gig::VCOManipulator>*   pLFO3;              ///< Low Frequency Oscillator 3 (Pitch)
150              Event*                      pTriggerEvent;      ///< First event on the key's list the voice should process (only needed for the first audio fragment in which voice was triggered, after that it will be set to NULL).              Pool<Event>::Iterator       itTriggerEvent;      ///< First event on the key's list the voice should process (only needed for the first audio fragment in which voice was triggered, after that it will be set to NULL).
151            public: // FIXME: just made public for debugging (sanity check in Engine::RenderAudio()), should be changed to private before the final release
152                Pool<Event>::Iterator       itKillEvent;         ///< Event which caused this voice to be killed
153            private:
154    
155    
156              // Static Methods              // Static Methods
157              static float CalculateFilterCutoffCoeff();              static float CalculateFilterCutoffCoeff();
158                static int   CalculateFilterUpdateMask();
159    
160              // Methods              // Methods
161                void        KillImmediately();
162              void        ProcessEvents(uint Samples);              void        ProcessEvents(uint Samples);
163              void        Interpolate(uint Samples, sample_t* pSrc, uint Skip);              #if ENABLE_FILTER
164                void        CalculateBiquadParameters(uint Samples);
165                #endif // ENABLE_FILTER
166                void        InterpolateNoLoop(uint Samples, sample_t* pSrc, uint Skip);
167              void        InterpolateAndLoop(uint Samples, sample_t* pSrc, uint Skip);              void        InterpolateAndLoop(uint Samples, sample_t* pSrc, uint Skip);
168              inline void InterpolateOneStep_Stereo(sample_t* pSrc, int& i, float& effective_volume, float& pitch, float& cutoff, float& resonance) {  
169                inline void InterpolateMono(sample_t* pSrc, int& i) {
170                    InterpolateOneStep_Mono(pSrc, i,
171                                            pEngine->pSynthesisParameters[Event::destination_vca][i] * PanLeft,
172                                            pEngine->pSynthesisParameters[Event::destination_vca][i] * PanRight,
173                                            pEngine->pSynthesisParameters[Event::destination_vco][i],
174                                            pEngine->pBasicFilterParameters[i],
175                                            pEngine->pMainFilterParameters[i]);
176                }
177    
178                inline void InterpolateStereo(sample_t* pSrc, int& i) {
179                    InterpolateOneStep_Stereo(pSrc, i,
180                                              pEngine->pSynthesisParameters[Event::destination_vca][i] * PanLeft,
181                                              pEngine->pSynthesisParameters[Event::destination_vca][i] * PanRight,
182                                              pEngine->pSynthesisParameters[Event::destination_vco][i],
183                                              pEngine->pBasicFilterParameters[i],
184                                              pEngine->pMainFilterParameters[i]);
185                }
186    
187                inline void InterpolateOneStep_Stereo(sample_t* pSrc, int& i, float volume_left, float volume_right, float& pitch, biquad_param_t& bq_base, biquad_param_t& bq_main) {
188                  int   pos_int   = RTMath::DoubleToInt(this->Pos);  // integer position                  int   pos_int   = RTMath::DoubleToInt(this->Pos);  // integer position
189                  float pos_fract = this->Pos - pos_int;             // fractional part of position                  float pos_fract = this->Pos - pos_int;             // fractional part of position
190                  pos_int <<= 1;                  pos_int <<= 1;
191    
                 #if ENABLE_FILTER  
                     UpdateFilter_Stereo(cutoff + FILTER_CUTOFF_MIN, resonance);  
                 #endif // ENABLE_FILTER  
   
192                  #if USE_LINEAR_INTERPOLATION                  #if USE_LINEAR_INTERPOLATION
193                      #if ENABLE_FILTER                      #if ENABLE_FILTER
194                          // left channel                          // left channel
195                          pOutputLeft[i]    += this->FilterLeft.Apply(effective_volume * (pSrc[pos_int]   + pos_fract * (pSrc[pos_int+2] - pSrc[pos_int])));                          pEngine->pOutputLeft[i]    += this->FilterLeft.Apply(&bq_base, &bq_main, volume_left * (pSrc[pos_int]   + pos_fract * (pSrc[pos_int+2] - pSrc[pos_int])));
196                          // right channel                          // right channel
197                          pOutputRight[i++] += this->FilterRight.Apply(effective_volume * (pSrc[pos_int+1] + pos_fract * (pSrc[pos_int+3] - pSrc[pos_int+1])));                          pEngine->pOutputRight[i++] += this->FilterRight.Apply(&bq_base, &bq_main, volume_right * (pSrc[pos_int+1] + pos_fract * (pSrc[pos_int+3] - pSrc[pos_int+1])));
198                      #else // no filter                      #else // no filter
199                          // left channel                          // left channel
200                          pOutputLeft[i]    += effective_volume * (pSrc[pos_int]   + pos_fract * (pSrc[pos_int+2] - pSrc[pos_int]));                          pEngine->pOutputLeft[i]    += volume_left * (pSrc[pos_int]   + pos_fract * (pSrc[pos_int+2] - pSrc[pos_int]));
201                          // right channel                          // right channel
202                          pOutputRight[i++] += effective_volume * (pSrc[pos_int+1] + pos_fract * (pSrc[pos_int+3] - pSrc[pos_int+1]));                          pEngine->pOutputRight[i++] += volume_right * (pSrc[pos_int+1] + pos_fract * (pSrc[pos_int+3] - pSrc[pos_int+1]));
203                      #endif // ENABLE_FILTER                      #endif // ENABLE_FILTER
204                  #else // polynomial interpolation                  #else // polynomial interpolation
205                      // calculate left channel                      // calculate left channel
# Line 172  namespace LinuxSampler { namespace gig { Line 207  namespace LinuxSampler { namespace gig {
207                      float x0  = pSrc[pos_int+2];                      float x0  = pSrc[pos_int+2];
208                      float x1  = pSrc[pos_int+4];                      float x1  = pSrc[pos_int+4];
209                      float x2  = pSrc[pos_int+6];                      float x2  = pSrc[pos_int+6];
210                      float a   = (3 * (x0 - x1) - xm1 + x2) / 2;                      float a   = (3.0f * (x0 - x1) - xm1 + x2) * 0.5f;
211                      float b   = 2 * x1 + xm1 - (5 * x0 + x2) / 2;                      float b   = 2.0f * x1 + xm1 - (5.0f * x0 + x2) * 0.5f;
212                      float c   = (x1 - xm1) / 2;                      float c   = (x1 - xm1) * 0.5f;
213                      #if ENABLE_FILTER                      #if ENABLE_FILTER
214                          pOutputLeft[i] += this->FilterLeft.Apply(effective_volume * ((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0));                          pEngine->pOutputLeft[i] += this->FilterLeft.Apply(&bq_base, &bq_main, volume_left * ((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0));
215                      #else // no filter                      #else // no filter
216                          pOutputRight[i] += effective_volume * ((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0);                          pEngine->pOutputLeft[i] += volume_left * ((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0);
217                      #endif // ENABLE_FILTER                      #endif // ENABLE_FILTER
218    
219                      //calculate right channel                      //calculate right channel
# Line 186  namespace LinuxSampler { namespace gig { Line 221  namespace LinuxSampler { namespace gig {
221                      x0  = pSrc[pos_int+3];                      x0  = pSrc[pos_int+3];
222                      x1  = pSrc[pos_int+5];                      x1  = pSrc[pos_int+5];
223                      x2  = pSrc[pos_int+7];                      x2  = pSrc[pos_int+7];
224                      a   = (3 * (x0 - x1) - xm1 + x2) / 2;                      a   = (3.0f * (x0 - x1) - xm1 + x2) * 0.5f;
225                      b   = 2 * x1 + xm1 - (5 * x0 + x2) / 2;                      b   = 2.0f * x1 + xm1 - (5.0f * x0 + x2) * 0.5f;
226                      c   = (x1 - xm1) / 2;                      c   = (x1 - xm1) * 0.5f;
227                      #if ENABLE_FILTER                      #if ENABLE_FILTER
228                          pOutputLeft[i++] += this->FilterRight.Apply(effective_volume * ((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0));                          pEngine->pOutputRight[i++] += this->FilterRight.Apply(&bq_base, &bq_main, volume_right * ((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0));
229                      #else // no filter                      #else // no filter
230                          pOutputRight[i++] += effective_volume * ((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0);                          pEngine->pOutputRight[i++] += volume_right * ((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0);
231                      #endif // ENABLE_FILTER                      #endif // ENABLE_FILTER
232                  #endif // USE_LINEAR_INTERPOLATION                  #endif // USE_LINEAR_INTERPOLATION
233    
234                  this->Pos += pitch;                  this->Pos += pitch;
235              }              }
236              inline void InterpolateOneStep_Mono(sample_t* pSrc, int& i, float& effective_volume, float& pitch, float& cutoff, float& resonance) {  
237                inline void InterpolateOneStep_Mono(sample_t* pSrc, int& i, float volume_left, float volume_right, float& pitch,  biquad_param_t& bq_base, biquad_param_t& bq_main) {
238                  int   pos_int   = RTMath::DoubleToInt(this->Pos);  // integer position                  int   pos_int   = RTMath::DoubleToInt(this->Pos);  // integer position
239                  float pos_fract = this->Pos - pos_int;             // fractional part of position                  float pos_fract = this->Pos - pos_int;             // fractional part of position
240    
                 #if ENABLE_FILTER  
                     UpdateFilter_Mono(cutoff + FILTER_CUTOFF_MIN, resonance);  
                 #endif // ENABLE_FILTER  
   
241                  #if USE_LINEAR_INTERPOLATION                  #if USE_LINEAR_INTERPOLATION
242                      float sample_point  = effective_volume * (pSrc[pos_int] + pos_fract * (pSrc[pos_int+1] - pSrc[pos_int]));                      float sample_point  = pSrc[pos_int] + pos_fract * (pSrc[pos_int+1] - pSrc[pos_int]);
243                  #else // polynomial interpolation                  #else // polynomial interpolation
244                      float xm1 = pSrc[pos_int];                      float xm1 = pSrc[pos_int];
245                      float x0  = pSrc[pos_int+1];                      float x0  = pSrc[pos_int+1];
246                      float x1  = pSrc[pos_int+2];                      float x1  = pSrc[pos_int+2];
247                      float x2  = pSrc[pos_int+3];                      float x2  = pSrc[pos_int+3];
248                      float a   = (3 * (x0 - x1) - xm1 + x2) / 2;                      float a   = (3.0f * (x0 - x1) - xm1 + x2) * 0.5f;
249                      float b   = 2 * x1 + xm1 - (5 * x0 + x2) / 2;                      float b   = 2.0f * x1 + xm1 - (5.0f * x0 + x2) * 0.5f;
250                      float c   = (x1 - xm1) / 2;                      float c   = (x1 - xm1) * 0.5f;
251                      float sample_point = effective_volume * ((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0);                      float sample_point =  (((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0;
252                  #endif // USE_LINEAR_INTERPOLATION                  #endif // USE_LINEAR_INTERPOLATION
253    
254                  #if ENABLE_FILTER                  #if ENABLE_FILTER
255                      sample_point = this->FilterLeft.Apply(sample_point);                      sample_point = this->FilterLeft.Apply(&bq_base, &bq_main, sample_point);
256                  #endif // ENABLE_FILTER                  #endif // ENABLE_FILTER
257    
258                  pOutputLeft[i]    += sample_point;                  pEngine->pOutputLeft[i]    += sample_point * volume_left;
259                  pOutputRight[i++] += sample_point;                  pEngine->pOutputRight[i++] += sample_point * volume_right;
260    
261                  this->Pos += pitch;                  this->Pos += pitch;
262              }              }
263              inline void UpdateFilter_Stereo(float cutoff, float& resonance) {  
264                  if (!(++FilterUpdateCounter % FILTER_UPDATE_PERIOD) && (cutoff != FilterLeft.Cutoff() || resonance != FilterLeft.Resonance())) {              inline float CrossfadeAttenuation(uint8_t& CrossfadeControllerValue) {
265                      FilterLeft.SetParameters(cutoff, resonance, SampleRate);                  return (CrossfadeControllerValue <= pDimRgn->Crossfade.in_start)  ? 0.0f
266                      FilterRight.SetParameters(cutoff, resonance, SampleRate);                       : (CrossfadeControllerValue < pDimRgn->Crossfade.in_end)     ? float(CrossfadeControllerValue - pDimRgn->Crossfade.in_start) / float(pDimRgn->Crossfade.in_end - pDimRgn->Crossfade.in_start)
267                  }                       : (CrossfadeControllerValue <= pDimRgn->Crossfade.out_start) ? 1.0f
268              }                       : (CrossfadeControllerValue < pDimRgn->Crossfade.out_end)    ? float(CrossfadeControllerValue - pDimRgn->Crossfade.out_start) / float(pDimRgn->Crossfade.out_end - pDimRgn->Crossfade.out_start)
269              inline void UpdateFilter_Mono(float cutoff, float& resonance) {                       : 0.0f;
                 if (!(++FilterUpdateCounter % FILTER_UPDATE_PERIOD) && (cutoff != FilterLeft.Cutoff() || resonance != FilterLeft.Resonance())) {  
                     FilterLeft.SetParameters(cutoff, resonance, SampleRate);  
                 }  
270              }              }
271    
272              inline float Constrain(float ValueToCheck, float Min, float Max) {              inline float Constrain(float ValueToCheck, float Min, float Max) {
273                  if      (ValueToCheck > Max) ValueToCheck = Max;                  if      (ValueToCheck > Max) ValueToCheck = Max;
274                  else if (ValueToCheck < Min) ValueToCheck = Min;                  else if (ValueToCheck < Min) ValueToCheck = Min;

Legend:
Removed from v.53  
changed lines
  Added in v.287

  ViewVC Help
Powered by ViewVC