/[svn]/linuxsampler/trunk/src/voice.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/voice.cpp

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

revision 13 by schoenebeck, Fri Nov 21 15:07:23 2003 UTC revision 33 by schoenebeck, Mon Feb 16 19:30:42 2004 UTC
# Line 24  Line 24 
24    
25  // FIXME: no support for layers (nor crossfades) yet  // FIXME: no support for layers (nor crossfades) yet
26    
27  DiskThread* Voice::pDiskThread = NULL;  DiskThread*  Voice::pDiskThread = NULL;
28    AudioThread* Voice::pEngine     = NULL;
29    
30  Voice::Voice(DiskThread* pDiskThread) {  Voice::Voice() {
31      Active             = false;      Active = false;
     Voice::pDiskThread = pDiskThread;  
32  }  }
33    
34  Voice::~Voice() {  Voice::~Voice() {
35  }  }
36    
37  void Voice::Trigger(int MIDIKey, uint8_t Velocity, gig::Instrument* Instrument) {  /**
38      Active        = true;   *  Initializes and triggers the voice, a disk stream will be launched if
39      this->MIDIKey = MIDIKey;   *  needed.
40      pRegion       = Instrument->GetRegion(MIDIKey);   *
41      PlaybackState = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed   *  @param pNoteOnEvent - event that caused triggering of this voice
42      Pos           = 0;   *  @param Pitch        - MIDI detune factor (-8192 ... +8191)
43     *  @param pInstrument  - points to the loaded instrument which provides sample wave(s) and articulation data
44     *  @returns            0 on success, a value < 0 if something failed
45     */
46    int Voice::Trigger(ModulationSystem::Event* pNoteOnEvent, int Pitch, gig::Instrument* pInstrument) {
47        Active          = true;
48        MIDIKey         = pNoteOnEvent->Key;
49        pRegion         = pInstrument->GetRegion(MIDIKey);
50        PlaybackState   = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed
51        Pos             = 0;
52        ReleaseVelocity = 127; // default release velocity value
53        Delay           = pNoteOnEvent->FragmentPos();
54        pTriggerEvent   = pNoteOnEvent;
55    
56      if (!pRegion) {      if (!pRegion) {
57          std::cerr << "Audio Thread: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush;          std::cerr << "Audio Thread: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush;
58          Active = false;          Kill();
59          return;          return -1;
60      }      }
61    
62      //TODO: current MIDI controller values are not taken into account yet      //TODO: current MIDI controller values are not taken into account yet
# Line 52  void Voice::Trigger(int MIDIKey, uint8_t Line 64  void Voice::Trigger(int MIDIKey, uint8_t
64      for (int i = pRegion->Dimensions - 1; i >= 0; i--) { // Check if instrument has a velocity split      for (int i = pRegion->Dimensions - 1; i >= 0; i--) { // Check if instrument has a velocity split
65          if (pRegion->pDimensionDefinitions[i].dimension == gig::dimension_velocity) {          if (pRegion->pDimensionDefinitions[i].dimension == gig::dimension_velocity) {
66              uint DimValues[5] = {0,0,0,0,0};              uint DimValues[5] = {0,0,0,0,0};
67                   DimValues[i] = Velocity;                   DimValues[i] = pNoteOnEvent->Velocity;
68              pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);              pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);
69              break;              break;
70          }          }
# Line 67  void Voice::Trigger(int MIDIKey, uint8_t Line 79  void Voice::Trigger(int MIDIKey, uint8_t
79      long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;      long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;
80      DiskVoice          = cachedsamples < pSample->SamplesTotal;      DiskVoice          = cachedsamples < pSample->SamplesTotal;
81    
82      if (DiskVoice) {      if (DiskVoice) { // voice to be streamed from disk
83          MaxRAMPos = cachedsamples - (OutputBufferSize << MAX_PITCH) / pSample->Channels;          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)
84          pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos);  
85          dmsg(5,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d\n", cachedsamples, pSample->SamplesTotal, MaxRAMPos));          // check if there's a loop defined which completely fits into the cached (RAM) part of the sample
86            if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {
87                RAMLoop        = true;
88                LoopCyclesLeft = pSample->LoopPlayCount;
89            }
90            else RAMLoop = false;
91    
92            if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {
93                dmsg(1,("Disk stream order failed!\n"));
94                Kill();
95                return -1;
96            }
97            dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s)\n", cachedsamples, pSample->SamplesTotal, MaxRAMPos, (RAMLoop) ? "yes" : "no"));
98      }      }
99      else {      else { // RAM only voice
100          MaxRAMPos = cachedsamples;          MaxRAMPos = cachedsamples;
101          dmsg(5,("RAM only voice launched\n"));          if (pSample->Loops) {
102                RAMLoop        = true;
103                LoopCyclesLeft = pSample->LoopPlayCount;
104            }
105            else RAMLoop = false;
106            dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));
107      }      }
108    
109      CurrentPitch = pow(2, (double) (MIDIKey - (int) pSample->MIDIUnityNote) / (double) 12);  
110        // Pitch according to keyboard position (if 'PitchTrack' is set) and given detune factor
111        this->Pitch = ((double) Pitch / 8192.0) / 12.0 + (pDimRgn->PitchTrack) ? pow(2, ((double) (MIDIKey - (int) pDimRgn->UnityNote) + (double) pDimRgn->FineTune / 100.0) / 12.0)
112                                                                               : pow(2, ((double) pDimRgn->FineTune / 100.0) / 12.0);
113    
114        Volume = pDimRgn->GetVelocityAttenuation(pNoteOnEvent->Velocity);
115    
116        EG1.Trigger(pDimRgn->EG1PreAttack,
117                    pDimRgn->EG1Attack,
118                    pDimRgn->EG1Hold,
119                    pSample->LoopStart,
120                    pDimRgn->EG1Decay1,
121                    pDimRgn->EG1Decay2,
122                    pDimRgn->EG1InfiniteSustain,
123                    pDimRgn->EG1Sustain,
124                    pDimRgn->EG1Release,
125                    Delay);
126    
127      // ************************************************      // ************************************************
128      // TODO: ARTICULATION DATA HANDLING IS MISSING HERE      // TODO: ARTICULATION DATA HANDLING IS MISSING HERE
129      // ************************************************      // ************************************************
130    
131        return 0; // success
132  }  }
133    
134  void Voice::RenderAudio() {  /**
135     *  Renders the audio data for this voice for the current audio fragment.
136     *  The sample input data can either come from RAM (cached sample or sample
137     *  part) or directly from disk. The output signal will be rendered by
138     *  resampling / interpolation. If this voice is a disk streaming voice and
139     *  the voice completely played back the cached RAM part of the sample, it
140     *  will automatically switch to disk playback for the next RenderAudio()
141     *  call.
142     *
143     *  @param Samples - number of samples to be rendered in this audio fragment cycle
144     */
145    void Voice::Render(uint Samples) {
146    
147        // Reset the synthesis parameter matrix
148        ModulationSystem::ResetDestinationParameter(ModulationSystem::destination_vca, this->Volume);
149        ModulationSystem::ResetDestinationParameter(ModulationSystem::destination_vco, this->Pitch);
150    
151    
152        // Apply events to the synthesis parameter matrix
153        ProcessEvents(Samples);
154    
155    
156        // Let all modulators throw their parameter changes for the current audio fragment
157        EG1.Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->Pitch);
158    
159    
160      switch (this->PlaybackState) {      switch (this->PlaybackState) {
161    
162          case playback_state_ram: {          case playback_state_ram: {
163                  Interpolate((sample_t*) pSample->GetCache().pStart);                  if (RAMLoop) InterpolateAndLoop(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
164                    else         Interpolate(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
165                  if (DiskVoice) {                  if (DiskVoice) {
166                      // check if we reached the allowed limit of the sample RAM cache                      // check if we reached the allowed limit of the sample RAM cache
167                      if (Pos > MaxRAMPos) {                      if (Pos > MaxRAMPos) {
# Line 109  void Voice::RenderAudio() { Line 181  void Voice::RenderAudio() {
181                      DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);                      DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);
182                      if (!DiskStreamRef.pStream) {                      if (!DiskStreamRef.pStream) {
183                          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;
184                          pDiskThread->OrderDeletionOfStream(&DiskStreamRef);                          Kill();
                         this->Active = false;  
185                          return;                          return;
186                      }                      }
187                      DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (double_to_int(Pos) - MaxRAMPos));                      DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (double_to_int(Pos) - MaxRAMPos));
# Line 118  void Voice::RenderAudio() { Line 189  void Voice::RenderAudio() {
189                  }                  }
190    
191                  // 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)
192                  if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (OutputBufferSize << MAX_PITCH) / pSample->Channels) {                  if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels) {
193                      DiskStreamRef.pStream->WriteSilence((OutputBufferSize << MAX_PITCH) / pSample->Channels);                      DiskStreamRef.pStream->WriteSilence((MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels);
194                      this->PlaybackState = playback_state_end;                      this->PlaybackState = playback_state_end;
195                  }                  }
196    
197                  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
198                  Interpolate(ptr);                  Interpolate(Samples, ptr, Delay);
199                  DiskStreamRef.pStream->IncrementReadPos(double_to_int(Pos) * pSample->Channels);                  DiskStreamRef.pStream->IncrementReadPos(double_to_int(Pos) * pSample->Channels);
200                  Pos -= double_to_int(Pos);                  Pos -= double_to_int(Pos);
201              }              }
# Line 134  void Voice::RenderAudio() { Line 205  void Voice::RenderAudio() {
205              Kill(); // free voice              Kill(); // free voice
206              break;              break;
207      }      }
208    
209    
210        // Reset delay
211        Delay = 0;
212    
213        pTriggerEvent = NULL;
214    
215        // If release stage finished, let the voice be killed
216        if (EG1.GetStage() == EG_VCA::stage_end) this->PlaybackState = playback_state_end;
217  }  }
218    
219  void Voice::Interpolate(sample_t* pSrc) {  /**
220      float effective_volume = 1;  // TODO: use the art. data instead   *  Process the control change event lists of the engine for the current
221      int   i = 0;   *  audio fragment. Event values will be applied to the synthesis parameter
222     *  matrix.
223     *
224     *  @param Samples - number of samples to be rendered in this audio fragment cycle
225     */
226    void Voice::ProcessEvents(uint Samples) {
227        // process pitch events
228        RTEList<ModulationSystem::Event>* pEventList = pEngine->pCCEvents[ModulationSystem::destination_vco];
229        ModulationSystem::Event* pEvent = pEventList->first();;
230        while (pEvent) {
231            ModulationSystem::Event* pNextEvent = pEventList->next();
232    
233            // calculate the influence length of this event (in sample points)
234            uint duration = (pNextEvent) ? pNextEvent->FragmentPos() - pEvent->FragmentPos()
235                                         : Samples                   - pEvent->FragmentPos();
236    
237            // calculate actual pitch value
238            switch (pEvent->Type) {
239                case ModulationSystem::event_type_pitchbend:
240                    this->Pitch += ((double) pEvent->Pitch / 8192.0) / 12.0; // +- one semitone
241                    break;
242            }
243    
244      // ************************************************          // apply pitch value to the pitch parameter sequence
245      // TODO: ARTICULATION DATA HANDLING IS MISSING HERE          for (uint i = pEvent->FragmentPos(); i < duration; i++) {
246      // ************************************************              ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i] = this->Pitch;
247            }
248    
249            pEvent = pNextEvent;
250        }
251    }
252    
253    /**
254     *  Interpolates the input audio data (no loop).
255     *
256     *  @param Samples - number of sample points to be rendered in this audio
257     *                   fragment cycle
258     *  @param pSrc    - pointer to input sample data
259     *  @param Skip    - number of sample points to skip in output buffer
260     */
261    void Voice::Interpolate(uint Samples, sample_t* pSrc, uint Skip) {
262        int i = Skip;
263    
264      // FIXME: assuming either mono or stereo      // FIXME: assuming either mono or stereo
265      if (this->pSample->Channels == 2) { // Stereo Sample      if (this->pSample->Channels == 2) { // Stereo Sample
266          while (i < this->OutputBufferSize) {          while (i < Samples) {
267              #ifdef USE_LINEAR_INTERPOLATION              InterpolateOneStep_Stereo(pSrc, i,
268                  int   pos_int   = double_to_int(this->Pos);  // integer position                                        ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
269                  float pos_fract = this->Pos - pos_int;       // fractional part of position                                        ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
                 pos_int <<= 1;  
                 // left channel  
                 this->pOutput[i++] += effective_volume * (pSrc[pos_int]   + pos_fract * (pSrc[pos_int+2] - pSrc[pos_int]));  
                 // right channel  
                 this->pOutput[i++] += effective_volume * (pSrc[pos_int+1] + pos_fract * (pSrc[pos_int+3] - pSrc[pos_int+1]));  
             #else // polynomial interpolation  
                 //FIXME: !!!THIS WON'T WORK!!! needs to be adjusted for stereo, use linear interpolation meanwhile  
                 xm1 = pSrc[pos_int];  
                 x0  = pSrc[pos_int+1];  
                 x1  = pSrc[pos_int+2];  
                 x2  = pSrc[pos_int+3];  
                 a   = (3 * (x0-x1) - xm1 + x2) / 2;  
                 b   = 2 * x1 + xm1 - (5 * x0 + x2) / 2;  
                 c   = (x1 - xm1) / 2;  
                 this->pOutput[u] += effective_volume*((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0);  
             #endif // USE_LINEAR_INTERPOLATION  
   
             this->Pos += this->CurrentPitch;  
270          }          }
271      }      }
272      else { // Mono Sample      else { // Mono Sample
273          while (i < this->OutputBufferSize) {          while (i < Samples) {
274              #ifdef USE_LINEAR_INTERPOLATION              InterpolateOneStep_Mono(pSrc, i,
275                  int   pos_int       = double_to_int(this->Pos);  // integer position                                      ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
276                  float pos_fract     = this->Pos - pos_int;       // fractional part of position                                      ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
277                  float sample_point  = effective_volume * (pSrc[pos_int] + pos_fract * (pSrc[pos_int+1] - pSrc[pos_int]));          }
278                  this->pOutput[i]   += sample_point;      }
279                  this->pOutput[i+1] += sample_point;  }
                 i += 2;  
             #else // polynomial interpolation  
                 //FIXME: !!!THIS WON'T WORK!!! needs to be adjusted for stereo, use linear interpolation meanwhile  
                 xm1 = pSrc[pos_int];  
                 x0  = pSrc[pos_int+1];  
                 x1  = pSrc[pos_int+2];  
                 x2  = pSrc[pos_int+3];  
                 a   = (3 * (x0-x1) - xm1 + x2) / 2;  
                 b   = 2 * x1 + xm1 - (5 * x0 + x2) / 2;  
                 c   = (x1 - xm1) / 2;  
                this->pOutput[u] += effective_volume*((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0);  
             #endif  
280    
281              this->Pos += this->CurrentPitch;  /**
282     *  Interpolates the input audio data, this method honors looping.
283     *
284     *  @param Samples - number of sample points to be rendered in this audio
285     *                   fragment cycle
286     *  @param pSrc    - pointer to input sample data
287     *  @param Skip    - number of sample points to skip in output buffer
288     */
289    void Voice::InterpolateAndLoop(uint Samples, sample_t* pSrc, uint Skip) {
290        int i = Skip;
291    
292        // FIXME: assuming either mono or stereo
293        if (pSample->Channels == 2) { // Stereo Sample
294            if (pSample->LoopPlayCount) {
295                // render loop (loop count limited)
296                while (i < Samples && LoopCyclesLeft) {
297                    InterpolateOneStep_Stereo(pSrc, i,
298                                              ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
299                                              ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
300                    if (Pos > pSample->LoopEnd) {
301                        Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
302                        LoopCyclesLeft--;
303                    }
304                }
305                // render on without loop
306                while (i < Samples) {
307                    InterpolateOneStep_Stereo(pSrc, i,
308                                              ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
309                                              ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
310                }
311            }
312            else { // render loop (endless loop)
313                while (i < Samples) {
314                    InterpolateOneStep_Stereo(pSrc, i,
315                                              ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
316                                              ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
317                    if (Pos > pSample->LoopEnd) {
318                        Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);
319                    }
320                }
321            }
322        }
323        else { // Mono Sample
324            if (pSample->LoopPlayCount) {
325                // render loop (loop count limited)
326                while (i < Samples && LoopCyclesLeft) {
327                    InterpolateOneStep_Mono(pSrc, i,
328                                            ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
329                                            ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
330                    if (Pos > pSample->LoopEnd) {
331                        Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
332                        LoopCyclesLeft--;
333                    }
334                }
335                // render on without loop
336                while (i < Samples) {
337                    InterpolateOneStep_Mono(pSrc, i,
338                                            ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
339                                            ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
340                }
341            }
342            else { // render loop (endless loop)
343                while (i < Samples) {
344                    InterpolateOneStep_Mono(pSrc, i,
345                                            ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
346                                            ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
347                    if (Pos > pSample->LoopEnd) {
348                        Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
349                    }
350                }
351          }          }
352      }      }
353  }  }
354    
355    /**
356     *  Immediately kill the voice.
357     */
358  void Voice::Kill() {  void Voice::Kill() {
359      if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {      if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
360          pDiskThread->OrderDeletionOfStream(&DiskStreamRef);          pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
361      }      }
362        DiskStreamRef.pStream = NULL;
363        DiskStreamRef.hStream = 0;
364        DiskStreamRef.State   = Stream::state_unused;
365        DiskStreamRef.OrderID = 0;
366      Active = false;      Active = false;
367  }  }

Legend:
Removed from v.13  
changed lines
  Added in v.33

  ViewVC Help
Powered by ViewVC