/[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 285 by schoenebeck, Thu Oct 14 21:31:26 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 = 0, bool ReleaseTriggerVoice = false);
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                Pool<Event>::Iterator       itKillEvent;         ///< Event which caused this voice to be killed
152    
153              // Static Methods              // Static Methods
154              static float CalculateFilterCutoffCoeff();              static float CalculateFilterCutoffCoeff();
155                static int   CalculateFilterUpdateMask();
156    
157              // Methods              // Methods
158                void        KillImmediately();
159              void        ProcessEvents(uint Samples);              void        ProcessEvents(uint Samples);
160              void        Interpolate(uint Samples, sample_t* pSrc, uint Skip);              #if ENABLE_FILTER
161                void        CalculateBiquadParameters(uint Samples);
162                #endif // ENABLE_FILTER
163                void        InterpolateNoLoop(uint Samples, sample_t* pSrc, uint Skip);
164              void        InterpolateAndLoop(uint Samples, sample_t* pSrc, uint Skip);              void        InterpolateAndLoop(uint Samples, sample_t* pSrc, uint Skip);
165              inline void InterpolateOneStep_Stereo(sample_t* pSrc, int& i, float& effective_volume, float& pitch, float& cutoff, float& resonance) {  
166                inline void InterpolateMono(sample_t* pSrc, int& i) {
167                    InterpolateOneStep_Mono(pSrc, i,
168                                            pEngine->pSynthesisParameters[Event::destination_vca][i] * PanLeft,
169                                            pEngine->pSynthesisParameters[Event::destination_vca][i] * PanRight,
170                                            pEngine->pSynthesisParameters[Event::destination_vco][i],
171                                            pEngine->pBasicFilterParameters[i],
172                                            pEngine->pMainFilterParameters[i]);
173                }
174    
175                inline void InterpolateStereo(sample_t* pSrc, int& i) {
176                    InterpolateOneStep_Stereo(pSrc, i,
177                                              pEngine->pSynthesisParameters[Event::destination_vca][i] * PanLeft,
178                                              pEngine->pSynthesisParameters[Event::destination_vca][i] * PanRight,
179                                              pEngine->pSynthesisParameters[Event::destination_vco][i],
180                                              pEngine->pBasicFilterParameters[i],
181                                              pEngine->pMainFilterParameters[i]);
182                }
183    
184                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) {
185                  int   pos_int   = RTMath::DoubleToInt(this->Pos);  // integer position                  int   pos_int   = RTMath::DoubleToInt(this->Pos);  // integer position
186                  float pos_fract = this->Pos - pos_int;             // fractional part of position                  float pos_fract = this->Pos - pos_int;             // fractional part of position
187                  pos_int <<= 1;                  pos_int <<= 1;
188    
                 #if ENABLE_FILTER  
                     UpdateFilter_Stereo(cutoff + FILTER_CUTOFF_MIN, resonance);  
                 #endif // ENABLE_FILTER  
   
189                  #if USE_LINEAR_INTERPOLATION                  #if USE_LINEAR_INTERPOLATION
190                      #if ENABLE_FILTER                      #if ENABLE_FILTER
191                          // left channel                          // left channel
192                          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])));
193                          // right channel                          // right channel
194                          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])));
195                      #else // no filter                      #else // no filter
196                          // left channel                          // left channel
197                          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]));
198                          // right channel                          // right channel
199                          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]));
200                      #endif // ENABLE_FILTER                      #endif // ENABLE_FILTER
201                  #else // polynomial interpolation                  #else // polynomial interpolation
202                      // calculate left channel                      // calculate left channel
# Line 172  namespace LinuxSampler { namespace gig { Line 204  namespace LinuxSampler { namespace gig {
204                      float x0  = pSrc[pos_int+2];                      float x0  = pSrc[pos_int+2];
205                      float x1  = pSrc[pos_int+4];                      float x1  = pSrc[pos_int+4];
206                      float x2  = pSrc[pos_int+6];                      float x2  = pSrc[pos_int+6];
207                      float a   = (3 * (x0 - x1) - xm1 + x2) / 2;                      float a   = (3.0f * (x0 - x1) - xm1 + x2) * 0.5f;
208                      float b   = 2 * x1 + xm1 - (5 * x0 + x2) / 2;                      float b   = 2.0f * x1 + xm1 - (5.0f * x0 + x2) * 0.5f;
209                      float c   = (x1 - xm1) / 2;                      float c   = (x1 - xm1) * 0.5f;
210                      #if ENABLE_FILTER                      #if ENABLE_FILTER
211                          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));
212                      #else // no filter                      #else // no filter
213                          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);
214                      #endif // ENABLE_FILTER                      #endif // ENABLE_FILTER
215    
216                      //calculate right channel                      //calculate right channel
# Line 186  namespace LinuxSampler { namespace gig { Line 218  namespace LinuxSampler { namespace gig {
218                      x0  = pSrc[pos_int+3];                      x0  = pSrc[pos_int+3];
219                      x1  = pSrc[pos_int+5];                      x1  = pSrc[pos_int+5];
220                      x2  = pSrc[pos_int+7];                      x2  = pSrc[pos_int+7];
221                      a   = (3 * (x0 - x1) - xm1 + x2) / 2;                      a   = (3.0f * (x0 - x1) - xm1 + x2) * 0.5f;
222                      b   = 2 * x1 + xm1 - (5 * x0 + x2) / 2;                      b   = 2.0f * x1 + xm1 - (5.0f * x0 + x2) * 0.5f;
223                      c   = (x1 - xm1) / 2;                      c   = (x1 - xm1) * 0.5f;
224                      #if ENABLE_FILTER                      #if ENABLE_FILTER
225                          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));
226                      #else // no filter                      #else // no filter
227                          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);
228                      #endif // ENABLE_FILTER                      #endif // ENABLE_FILTER
229                  #endif // USE_LINEAR_INTERPOLATION                  #endif // USE_LINEAR_INTERPOLATION
230    
231                  this->Pos += pitch;                  this->Pos += pitch;
232              }              }
233              inline void InterpolateOneStep_Mono(sample_t* pSrc, int& i, float& effective_volume, float& pitch, float& cutoff, float& resonance) {  
234                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) {
235                  int   pos_int   = RTMath::DoubleToInt(this->Pos);  // integer position                  int   pos_int   = RTMath::DoubleToInt(this->Pos);  // integer position
236                  float pos_fract = this->Pos - pos_int;             // fractional part of position                  float pos_fract = this->Pos - pos_int;             // fractional part of position
237    
                 #if ENABLE_FILTER  
                     UpdateFilter_Mono(cutoff + FILTER_CUTOFF_MIN, resonance);  
                 #endif // ENABLE_FILTER  
   
238                  #if USE_LINEAR_INTERPOLATION                  #if USE_LINEAR_INTERPOLATION
239                      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]);
240                  #else // polynomial interpolation                  #else // polynomial interpolation
241                      float xm1 = pSrc[pos_int];                      float xm1 = pSrc[pos_int];
242                      float x0  = pSrc[pos_int+1];                      float x0  = pSrc[pos_int+1];
243                      float x1  = pSrc[pos_int+2];                      float x1  = pSrc[pos_int+2];
244                      float x2  = pSrc[pos_int+3];                      float x2  = pSrc[pos_int+3];
245                      float a   = (3 * (x0 - x1) - xm1 + x2) / 2;                      float a   = (3.0f * (x0 - x1) - xm1 + x2) * 0.5f;
246                      float b   = 2 * x1 + xm1 - (5 * x0 + x2) / 2;                      float b   = 2.0f * x1 + xm1 - (5.0f * x0 + x2) * 0.5f;
247                      float c   = (x1 - xm1) / 2;                      float c   = (x1 - xm1) * 0.5f;
248                      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;
249                  #endif // USE_LINEAR_INTERPOLATION                  #endif // USE_LINEAR_INTERPOLATION
250    
251                  #if ENABLE_FILTER                  #if ENABLE_FILTER
252                      sample_point = this->FilterLeft.Apply(sample_point);                      sample_point = this->FilterLeft.Apply(&bq_base, &bq_main, sample_point);
253                  #endif // ENABLE_FILTER                  #endif // ENABLE_FILTER
254    
255                  pOutputLeft[i]    += sample_point;                  pEngine->pOutputLeft[i]    += sample_point * volume_left;
256                  pOutputRight[i++] += sample_point;                  pEngine->pOutputRight[i++] += sample_point * volume_right;
257    
258                  this->Pos += pitch;                  this->Pos += pitch;
259              }              }
260              inline void UpdateFilter_Stereo(float cutoff, float& resonance) {  
261                  if (!(++FilterUpdateCounter % FILTER_UPDATE_PERIOD) && (cutoff != FilterLeft.Cutoff() || resonance != FilterLeft.Resonance())) {              inline float CrossfadeAttenuation(uint8_t& CrossfadeControllerValue) {
262                      FilterLeft.SetParameters(cutoff, resonance, SampleRate);                  return (CrossfadeControllerValue <= pDimRgn->Crossfade.in_start)  ? 0.0f
263                      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)
264                  }                       : (CrossfadeControllerValue <= pDimRgn->Crossfade.out_start) ? 1.0f
265              }                       : (CrossfadeControllerValue < pDimRgn->Crossfade.out_end)    ? float(CrossfadeControllerValue - pDimRgn->Crossfade.out_start) / float(pDimRgn->Crossfade.out_end - pDimRgn->Crossfade.out_start)
266              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);  
                 }  
267              }              }
268    
269              inline float Constrain(float ValueToCheck, float Min, float Max) {              inline float Constrain(float ValueToCheck, float Min, float Max) {
270                  if      (ValueToCheck > Max) ValueToCheck = Max;                  if      (ValueToCheck > Max) ValueToCheck = Max;
271                  else if (ValueToCheck < Min) ValueToCheck = Min;                  else if (ValueToCheck < Min) ValueToCheck = Min;

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

  ViewVC Help
Powered by ViewVC