/[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 31 by schoenebeck, Sun Jan 18 20:31:31 2004 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() {
# Line 38  Voice::~Voice() { Line 38  Voice::~Voice() {
38   *  Initializes and triggers the voice, a disk stream will be launched if   *  Initializes and triggers the voice, a disk stream will be launched if
39   *  needed.   *  needed.
40   *   *
41   *  @returns  0 on success, a value < 0 if something failed   *  @param MIDIKey     - MIDI key number of the triggered key
42     *  @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, gig::Instrument* Instrument) {  int Voice::Trigger(int MIDIKey, uint8_t Velocity, int Pitch, gig::Instrument* pInstrument, uint Delay) {
49      Active          = true;      Active                = true;
50      this->MIDIKey   = MIDIKey;      this->MIDIKey         = MIDIKey;
51      pRegion         = Instrument->GetRegion(MIDIKey);      pRegion               = pInstrument->GetRegion(MIDIKey);
52      PlaybackState   = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed      PlaybackState         = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed
53      Pos             = 0;      Pos                   = 0;
54      ReleaseVelocity = 127; // default release velocity value      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;
# Line 75  int Voice::Trigger(int MIDIKey, uint8_t Line 82  int Voice::Trigger(int MIDIKey, uint8_t
82      DiskVoice          = cachedsamples < pSample->SamplesTotal;      DiskVoice          = cachedsamples < pSample->SamplesTotal;
83    
84      if (DiskVoice) { // voice to be streamed from disk      if (DiskVoice) { // voice to be streamed from disk
85          MaxRAMPos = cachedsamples - (MaxSamplesPerCycle << 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    
87          // check if there's a loop defined which completely fits into the cached (RAM) part of the sample          // check if there's a loop defined which completely fits into the cached (RAM) part of the sample
88          if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {          if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {
# Line 102  int Voice::Trigger(int MIDIKey, uint8_t Line 109  int Voice::Trigger(int MIDIKey, uint8_t
109      }      }
110    
111    
112      // Pitch according to keyboard position (if 'PitchTrack' is set)      // Pitch according to keyboard position (if 'PitchTrack' is set) and given detune factor
113      CurrentPitch = (pDimRgn->PitchTrack) ? pow(2, ((double) (MIDIKey - (int) pDimRgn->UnityNote) + (double) pDimRgn->FineTune / 100.0) / 12.0)      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);                                                                             : pow(2, ((double) pDimRgn->FineTune / 100.0) / 12.0);
115    
116      Volume = pDimRgn->GetVelocityAttenuation(Velocity);      Volume = pDimRgn->GetVelocityAttenuation(Velocity);
117    
118      EG1.Trigger(pDimRgn->EG1PreAttack, pDimRgn->EG1Attack, pDimRgn->EG1Release);      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
# Line 125  int Voice::Trigger(int MIDIKey, uint8_t Line 132  int Voice::Trigger(int MIDIKey, uint8_t
132   *  the voice completely played back the cached RAM part of the sample, it   *  the voice completely played back the cached RAM part of the sample, it
133   *  will automatically switch to disk playback for the next RenderAudio()   *  will automatically switch to disk playback for the next RenderAudio()
134   *  call.   *  call.
135     *
136     *  @param Samples - number of samples to be rendered in this audio fragment cycle
137   */   */
138  void Voice::Render(uint Samples) {  void Voice::Render(uint Samples) {
139    
140      // Let all modulators throw their parameter changes for the current audio fragment      // Reset the synthesis parameter matrix
141      ModulationSystem::ResetDestinationParameter(ModulationSystem::destination_vca, this->Volume);      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);      EG1.Process(Samples);
151    
152    
153      switch (this->PlaybackState) {      switch (this->PlaybackState) {
154    
155          case playback_state_ram: {          case playback_state_ram: {
156                  if (RAMLoop) InterpolateAndLoop(Samples, (sample_t*) pSample->GetCache().pStart);                  if (RAMLoop) InterpolateAndLoop(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
157                  else         Interpolate(Samples, (sample_t*) pSample->GetCache().pStart);                  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 171  void Voice::Render(uint Samples) { Line 188  void Voice::Render(uint Samples) {
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(Samples, 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 182  void Voice::Render(uint Samples) { Line 199  void Voice::Render(uint Samples) {
199              break;              break;
200      }      }
201    
202    
203        // Reset delay
204        Delay = 0;
205    
206    
207      // If release stage finished, let the voice be killed      // If release stage finished, let the voice be killed
208      if (EG1.GetStage() == EG_VCA::stage_end) this->PlaybackState = playback_state_end;      if (EG1.GetStage() == EG_VCA::stage_end) this->PlaybackState = playback_state_end;
209  }  }
210    
211  /**  /**
212     *  Process the control change event lists of the engine for the current
213     *  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            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).   *  Interpolates the input audio data (no loop).
247   *   *
248   *  @param pSrc - pointer to input sample data   *  @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) {  void Voice::Interpolate(uint Samples, sample_t* pSrc, uint Skip) {
254      int i = 0;      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 < Samples) {          while (i < Samples) {
259              InterpolateOneStep_Stereo(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i]);              InterpolateOneStep_Stereo(pSrc, i,
260                                          ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
261                                          ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
262          }          }
263      }      }
264      else { // Mono Sample      else { // Mono Sample
265          while (i < Samples) {          while (i < Samples) {
266              InterpolateOneStep_Mono(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i]);              InterpolateOneStep_Mono(pSrc, i,
267                                        ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
268                                        ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
269          }          }
270      }      }
271  }  }
# Line 210  void Voice::Interpolate(uint Samples, sa Line 273  void Voice::Interpolate(uint Samples, sa
273  /**  /**
274   *  Interpolates the input audio data, this method honors looping.   *  Interpolates the input audio data, this method honors looping.
275   *   *
276   *  @param pSrc - pointer to input sample data   *  @param Samples - number of sample points to be rendered in this audio
277     *                   fragment cycle
278     *  @param pSrc    - pointer to input sample data
279     *  @param Skip    - number of sample points to skip in output buffer
280   */   */
281  void Voice::InterpolateAndLoop(uint Samples, sample_t* pSrc) {  void Voice::InterpolateAndLoop(uint Samples, sample_t* pSrc, uint Skip) {
282      int i = 0;      int i = Skip;
283    
284      // FIXME: assuming either mono or stereo      // FIXME: assuming either mono or stereo
285      if (pSample->Channels == 2) { // Stereo Sample      if (pSample->Channels == 2) { // Stereo Sample
286          if (pSample->LoopPlayCount) {          if (pSample->LoopPlayCount) {
287              // render loop (loop count limited)              // render loop (loop count limited)
288              while (i < Samples && LoopCyclesLeft) {              while (i < Samples && LoopCyclesLeft) {
289                  InterpolateOneStep_Stereo(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i]);                  InterpolateOneStep_Stereo(pSrc, i,
290                                              ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
291                                              ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
292                  if (Pos > pSample->LoopEnd) {                  if (Pos > pSample->LoopEnd) {
293                      Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;                      Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
294                      LoopCyclesLeft--;                      LoopCyclesLeft--;
# Line 228  void Voice::InterpolateAndLoop(uint Samp Line 296  void Voice::InterpolateAndLoop(uint Samp
296              }              }
297              // render on without loop              // render on without loop
298              while (i < Samples) {              while (i < Samples) {
299                  InterpolateOneStep_Stereo(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i]);                  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)          else { // render loop (endless loop)
305              while (i < Samples) {              while (i < Samples) {
306                  InterpolateOneStep_Stereo(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i]);                  InterpolateOneStep_Stereo(pSrc, i,
307                                              ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
308                                              ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
309                  if (Pos > pSample->LoopEnd) {                  if (Pos > pSample->LoopEnd) {
310                      Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);                      Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);
311                  }                  }
# Line 244  void Voice::InterpolateAndLoop(uint Samp Line 316  void Voice::InterpolateAndLoop(uint Samp
316          if (pSample->LoopPlayCount) {          if (pSample->LoopPlayCount) {
317              // render loop (loop count limited)              // render loop (loop count limited)
318              while (i < Samples && LoopCyclesLeft) {              while (i < Samples && LoopCyclesLeft) {
319                  InterpolateOneStep_Mono(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i]);                  InterpolateOneStep_Mono(pSrc, i,
320                                            ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
321                                            ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
322                  if (Pos > pSample->LoopEnd) {                  if (Pos > pSample->LoopEnd) {
323                      Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;                      Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
324                      LoopCyclesLeft--;                      LoopCyclesLeft--;
# Line 252  void Voice::InterpolateAndLoop(uint Samp Line 326  void Voice::InterpolateAndLoop(uint Samp
326              }              }
327              // render on without loop              // render on without loop
328              while (i < Samples) {              while (i < Samples) {
329                  InterpolateOneStep_Mono(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i]);                  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)          else { // render loop (endless loop)
335              while (i < Samples) {              while (i < Samples) {
336                  InterpolateOneStep_Mono(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i]);                  InterpolateOneStep_Mono(pSrc, i,
337                                            ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
338                                            ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
339                  if (Pos > pSample->LoopEnd) {                  if (Pos > pSample->LoopEnd) {
340                      Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;                      Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
341                  }                  }
# Line 283  void Voice::Kill() { Line 361  void Voice::Kill() {
361  /**  /**
362   *  Release the voice in an appropriate time range, the voice will go through   *  Release the voice in an appropriate time range, the voice will go through
363   *  it's release stage before it will be killed.   *  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() {  void Voice::Release(uint Delay) {
368     EG1.Release();     if (!ReleaseSignalReceived) {
369           EG1.Release(Delay);
370           ReleaseSignalReceived = true;
371       }
372  }  }

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

  ViewVC Help
Powered by ViewVC