/[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 28 by schoenebeck, Fri Jan 2 00:02:56 2004 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() {
# 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 pNoteOnEvent - event that caused triggering of this voice
42     *  @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(int MIDIKey, uint8_t Velocity, gig::Instrument* Instrument) {  int Voice::Trigger(ModulationSystem::Event* pNoteOnEvent, int Pitch, gig::Instrument* pInstrument) {
47      Active          = true;      Active          = true;
48      this->MIDIKey   = MIDIKey;      MIDIKey         = pNoteOnEvent->Key;
49      pRegion         = Instrument->GetRegion(MIDIKey);      pRegion         = pInstrument->GetRegion(MIDIKey);
50      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
51      Pos             = 0;      Pos             = 0;
52      ReleaseVelocity = 127; // default release velocity value      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;
# Line 59  int Voice::Trigger(int MIDIKey, uint8_t Line 64  int 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 75  int Voice::Trigger(int MIDIKey, uint8_t Line 80  int Voice::Trigger(int MIDIKey, uint8_t
80      DiskVoice          = cachedsamples < pSample->SamplesTotal;      DiskVoice          = cachedsamples < pSample->SamplesTotal;
81    
82      if (DiskVoice) { // voice to be streamed from disk      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    
85          // 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
86          if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {          if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {
# Line 89  int Voice::Trigger(int MIDIKey, uint8_t Line 94  int Voice::Trigger(int MIDIKey, uint8_t
94              Kill();              Kill();
95              return -1;              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"));          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 { // RAM only voice      else { // RAM only voice
100          MaxRAMPos = cachedsamples;          MaxRAMPos = cachedsamples;
# Line 101  int Voice::Trigger(int MIDIKey, uint8_t Line 106  int Voice::Trigger(int MIDIKey, uint8_t
106          dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));          dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));
107      }      }
108    
109      // Pitch according to keyboard position (if keyrange > 1 key)  
110      CurrentPitch = (pRegion->KeyRange.high != pRegion->KeyRange.low) ?      // Pitch according to keyboard position (if 'PitchTrack' is set) and given detune factor
111                             pow(2, (double) (MIDIKey - (int) pSample->MIDIUnityNote) / (double) 12) : 1.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)
112      Volume       = pDimRgn->GetVelocityAttenuation(Velocity);                                                                             : 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
# Line 121  int Voice::Trigger(int MIDIKey, uint8_t Line 139  int Voice::Trigger(int MIDIKey, uint8_t
139   *  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
140   *  will automatically switch to disk playback for the next RenderAudio()   *  will automatically switch to disk playback for the next RenderAudio()
141   *  call.   *  call.
142     *
143     *  @param Samples - number of samples to be rendered in this audio fragment cycle
144   */   */
145  void Voice::RenderAudio() {  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                  if (RAMLoop) InterpolateAndLoop((sample_t*) pSample->GetCache().pStart);                  if (RAMLoop) InterpolateAndLoop(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
164                  else         Interpolate((sample_t*) pSample->GetCache().pStart);                  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 156  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 172  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  /**  /**
220   *  Interpolates the input audio data (no loop).   *  Process the control change event lists of the engine for the current
221     *  audio fragment. Event values will be applied to the synthesis parameter
222     *  matrix.
223   *   *
224   *  @param pSrc - pointer to input sample data   *  @param Samples - number of samples to be rendered in this audio fragment cycle
225   */   */
226  void Voice::Interpolate(sample_t* pSrc) {  void Voice::ProcessEvents(uint Samples) {
227      float effective_volume = this->Volume;      // process pitch events
228      int   i = 0;      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              InterpolateOneStep_Stereo(pSrc, i, effective_volume);              InterpolateOneStep_Stereo(pSrc, i,
268                                          ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
269                                          ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
270          }          }
271      }      }
272      else { // Mono Sample      else { // Mono Sample
273          while (i < this->OutputBufferSize) {          while (i < Samples) {
274              InterpolateOneStep_Mono(pSrc, i, effective_volume);              InterpolateOneStep_Mono(pSrc, i,
275                                        ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
276                                        ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
277          }          }
278      }      }
279  }  }
# Line 203  void Voice::Interpolate(sample_t* pSrc) Line 281  void Voice::Interpolate(sample_t* pSrc)
281  /**  /**
282   *  Interpolates the input audio data, this method honors looping.   *  Interpolates the input audio data, this method honors looping.
283   *   *
284   *  @param pSrc - pointer to input sample data   *  @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(sample_t* pSrc) {  void Voice::InterpolateAndLoop(uint Samples, sample_t* pSrc, uint Skip) {
290      float effective_volume = this->Volume;      int i = Skip;
     int   i = 0;  
   
     // ************************************************  
     // TODO: ARTICULATION DATA HANDLING IS MISSING HERE  
     // ************************************************  
291    
292      // FIXME: assuming either mono or stereo      // FIXME: assuming either mono or stereo
293      if (pSample->Channels == 2) { // Stereo Sample      if (pSample->Channels == 2) { // Stereo Sample
294          if (pSample->LoopPlayCount) {          if (pSample->LoopPlayCount) {
295              // render loop (loop count limited)              // render loop (loop count limited)
296              while (i < OutputBufferSize && LoopCyclesLeft) {              while (i < Samples && LoopCyclesLeft) {
297                  InterpolateOneStep_Stereo(pSrc, i, effective_volume);                  InterpolateOneStep_Stereo(pSrc, i,
298                                              ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
299                                              ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
300                  if (Pos > pSample->LoopEnd) {                  if (Pos > pSample->LoopEnd) {
301                      Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;                      Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
302                      LoopCyclesLeft--;                      LoopCyclesLeft--;
303                  }                  }
304              }              }
305              // render on without loop              // render on without loop
306              while (i < OutputBufferSize) {              while (i < Samples) {
307                  InterpolateOneStep_Stereo(pSrc, i, effective_volume);                  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)          else { // render loop (endless loop)
313              while (i < OutputBufferSize) {              while (i < Samples) {
314                  InterpolateOneStep_Stereo(pSrc, i, effective_volume);                  InterpolateOneStep_Stereo(pSrc, i,
315                                              ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
316                                              ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
317                  if (Pos > pSample->LoopEnd) {                  if (Pos > pSample->LoopEnd) {
318                      Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);                      Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);
319                  }                  }
# Line 241  void Voice::InterpolateAndLoop(sample_t* Line 323  void Voice::InterpolateAndLoop(sample_t*
323      else { // Mono Sample      else { // Mono Sample
324          if (pSample->LoopPlayCount) {          if (pSample->LoopPlayCount) {
325              // render loop (loop count limited)              // render loop (loop count limited)
326              while (i < OutputBufferSize && LoopCyclesLeft) {              while (i < Samples && LoopCyclesLeft) {
327                  InterpolateOneStep_Mono(pSrc, i, effective_volume);                  InterpolateOneStep_Mono(pSrc, i,
328                                            ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
329                                            ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
330                  if (Pos > pSample->LoopEnd) {                  if (Pos > pSample->LoopEnd) {
331                      Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;                      Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
332                      LoopCyclesLeft--;                      LoopCyclesLeft--;
333                  }                  }
334              }              }
335              // render on without loop              // render on without loop
336              while (i < OutputBufferSize) {              while (i < Samples) {
337                  InterpolateOneStep_Mono(pSrc, i, effective_volume);                  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)          else { // render loop (endless loop)
343              while (i < OutputBufferSize) {              while (i < Samples) {
344                  InterpolateOneStep_Mono(pSrc, i, effective_volume);                  InterpolateOneStep_Mono(pSrc, i,
345                                            ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
346                                            ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
347                  if (Pos > pSample->LoopEnd) {                  if (Pos > pSample->LoopEnd) {
348                      Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;                      Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
349                  }                  }

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

  ViewVC Help
Powered by ViewVC