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

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

  ViewVC Help
Powered by ViewVC