/[svn]/linuxsampler/tags/v0_1_0/src/voice.cpp
ViewVC logotype

Diff of /linuxsampler/tags/v0_1_0/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 31 by schoenebeck, Sun Jan 18 20:31:31 2004 UTC
# Line 34  Voice::Voice(DiskThread* pDiskThread) { Line 34  Voice::Voice(DiskThread* pDiskThread) {
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   *  @returns  0 on success, a value < 0 if something failed
42      Pos           = 0;   */
43    int Voice::Trigger(int MIDIKey, uint8_t Velocity, gig::Instrument* Instrument) {
44        Active          = true;
45        this->MIDIKey   = MIDIKey;
46        pRegion         = Instrument->GetRegion(MIDIKey);
47        PlaybackState   = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed
48        Pos             = 0;
49        ReleaseVelocity = 127; // default release velocity value
50    
51      if (!pRegion) {      if (!pRegion) {
52          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;
53          Active = false;          Kill();
54          return;          return -1;
55      }      }
56    
57      //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 74  void Voice::Trigger(int MIDIKey, uint8_t
74      long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;      long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;
75      DiskVoice          = cachedsamples < pSample->SamplesTotal;      DiskVoice          = cachedsamples < pSample->SamplesTotal;
76    
77      if (DiskVoice) {      if (DiskVoice) { // voice to be streamed from disk
78          MaxRAMPos = cachedsamples - (OutputBufferSize << MAX_PITCH) / pSample->Channels;          MaxRAMPos = cachedsamples - (MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels;
79          pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos);  
80          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
81            if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {
82                RAMLoop        = true;
83                LoopCyclesLeft = pSample->LoopPlayCount;
84            }
85            else RAMLoop = false;
86    
87            if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {
88                dmsg(1,("Disk stream order failed!\n"));
89                Kill();
90                return -1;
91            }
92            dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s)\n", cachedsamples, pSample->SamplesTotal, MaxRAMPos, (RAMLoop) ? "yes" : "no"));
93      }      }
94      else {      else { // RAM only voice
95          MaxRAMPos = cachedsamples;          MaxRAMPos = cachedsamples;
96          dmsg(5,("RAM only voice launched\n"));          if (pSample->Loops) {
97                RAMLoop        = true;
98                LoopCyclesLeft = pSample->LoopPlayCount;
99            }
100            else RAMLoop = false;
101            dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));
102      }      }
103    
104      CurrentPitch = pow(2, (double) (MIDIKey - (int) pSample->MIDIUnityNote) / (double) 12);  
105        // Pitch according to keyboard position (if 'PitchTrack' is set)
106        CurrentPitch = (pDimRgn->PitchTrack) ? pow(2, ((double) (MIDIKey - (int) pDimRgn->UnityNote) + (double) pDimRgn->FineTune / 100.0) / 12.0)
107                                             : pow(2, ((double) pDimRgn->FineTune / 100.0) / 12.0);
108    
109        Volume = pDimRgn->GetVelocityAttenuation(Velocity);
110    
111        EG1.Trigger(pDimRgn->EG1PreAttack, pDimRgn->EG1Attack, pDimRgn->EG1Release);
112    
113      // ************************************************      // ************************************************
114      // TODO: ARTICULATION DATA HANDLING IS MISSING HERE      // TODO: ARTICULATION DATA HANDLING IS MISSING HERE
115      // ************************************************      // ************************************************
116    
117        return 0; // success
118  }  }
119    
120  void Voice::RenderAudio() {  /**
121     *  Renders the audio data for this voice for the current audio fragment.
122     *  The sample input data can either come from RAM (cached sample or sample
123     *  part) or directly from disk. The output signal will be rendered by
124     *  resampling / interpolation. If this voice is a disk streaming voice and
125     *  the voice completely played back the cached RAM part of the sample, it
126     *  will automatically switch to disk playback for the next RenderAudio()
127     *  call.
128     */
129    void Voice::Render(uint Samples) {
130    
131        // Let all modulators throw their parameter changes for the current audio fragment
132        ModulationSystem::ResetDestinationParameter(ModulationSystem::destination_vca, this->Volume);
133        EG1.Process(Samples);
134    
135    
136      switch (this->PlaybackState) {      switch (this->PlaybackState) {
137    
138          case playback_state_ram: {          case playback_state_ram: {
139                  Interpolate((sample_t*) pSample->GetCache().pStart);                  if (RAMLoop) InterpolateAndLoop(Samples, (sample_t*) pSample->GetCache().pStart);
140                    else         Interpolate(Samples, (sample_t*) pSample->GetCache().pStart);
141                  if (DiskVoice) {                  if (DiskVoice) {
142                      // check if we reached the allowed limit of the sample RAM cache                      // check if we reached the allowed limit of the sample RAM cache
143                      if (Pos > MaxRAMPos) {                      if (Pos > MaxRAMPos) {
# Line 109  void Voice::RenderAudio() { Line 157  void Voice::RenderAudio() {
157                      DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);                      DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);
158                      if (!DiskStreamRef.pStream) {                      if (!DiskStreamRef.pStream) {
159                          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;
160                          pDiskThread->OrderDeletionOfStream(&DiskStreamRef);                          Kill();
                         this->Active = false;  
161                          return;                          return;
162                      }                      }
163                      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 165  void Voice::RenderAudio() {
165                  }                  }
166    
167                  // 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)
168                  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) {
169                      DiskStreamRef.pStream->WriteSilence((OutputBufferSize << MAX_PITCH) / pSample->Channels);                      DiskStreamRef.pStream->WriteSilence((MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels);
170                      this->PlaybackState = playback_state_end;                      this->PlaybackState = playback_state_end;
171                  }                  }
172    
173                  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
174                  Interpolate(ptr);                  Interpolate(Samples, ptr);
175                  DiskStreamRef.pStream->IncrementReadPos(double_to_int(Pos) * pSample->Channels);                  DiskStreamRef.pStream->IncrementReadPos(double_to_int(Pos) * pSample->Channels);
176                  Pos -= double_to_int(Pos);                  Pos -= double_to_int(Pos);
177              }              }
# Line 134  void Voice::RenderAudio() { Line 181  void Voice::RenderAudio() {
181              Kill(); // free voice              Kill(); // free voice
182              break;              break;
183      }      }
 }  
184    
185  void Voice::Interpolate(sample_t* pSrc) {      // If release stage finished, let the voice be killed
186      float effective_volume = 1;  // TODO: use the art. data instead      if (EG1.GetStage() == EG_VCA::stage_end) this->PlaybackState = playback_state_end;
187      int   i = 0;  }
188    
189      // ************************************************  /**
190      // TODO: ARTICULATION DATA HANDLING IS MISSING HERE   *  Interpolates the input audio data (no loop).
191      // ************************************************   *
192     *  @param pSrc - pointer to input sample data
193     */
194    void Voice::Interpolate(uint Samples, sample_t* pSrc) {
195        int i = 0;
196    
197      // FIXME: assuming either mono or stereo      // FIXME: assuming either mono or stereo
198      if (this->pSample->Channels == 2) { // Stereo Sample      if (this->pSample->Channels == 2) { // Stereo Sample
199          while (i < this->OutputBufferSize) {          while (i < Samples) {
200              #ifdef USE_LINEAR_INTERPOLATION              InterpolateOneStep_Stereo(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i]);
                 int   pos_int   = double_to_int(this->Pos);  // integer position  
                 float pos_fract = this->Pos - pos_int;       // fractional part of position  
                 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;  
201          }          }
202      }      }
203      else { // Mono Sample      else { // Mono Sample
204          while (i < this->OutputBufferSize) {          while (i < Samples) {
205              #ifdef USE_LINEAR_INTERPOLATION              InterpolateOneStep_Mono(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i]);
206                  int   pos_int       = double_to_int(this->Pos);  // integer position          }
207                  float pos_fract     = this->Pos - pos_int;       // fractional part of position      }
208                  float sample_point  = effective_volume * (pSrc[pos_int] + pos_fract * (pSrc[pos_int+1] - pSrc[pos_int]));  }
                 this->pOutput[i]   += sample_point;  
                 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  
209    
210              this->Pos += this->CurrentPitch;  /**
211     *  Interpolates the input audio data, this method honors looping.
212     *
213     *  @param pSrc - pointer to input sample data
214     */
215    void Voice::InterpolateAndLoop(uint Samples, sample_t* pSrc) {
216        int i = 0;
217    
218        // FIXME: assuming either mono or stereo
219        if (pSample->Channels == 2) { // Stereo Sample
220            if (pSample->LoopPlayCount) {
221                // render loop (loop count limited)
222                while (i < Samples && LoopCyclesLeft) {
223                    InterpolateOneStep_Stereo(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i]);
224                    if (Pos > pSample->LoopEnd) {
225                        Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
226                        LoopCyclesLeft--;
227                    }
228                }
229                // render on without loop
230                while (i < Samples) {
231                    InterpolateOneStep_Stereo(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i]);
232                }
233            }
234            else { // render loop (endless loop)
235                while (i < Samples) {
236                    InterpolateOneStep_Stereo(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i]);
237                    if (Pos > pSample->LoopEnd) {
238                        Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);
239                    }
240                }
241            }
242        }
243        else { // Mono Sample
244            if (pSample->LoopPlayCount) {
245                // render loop (loop count limited)
246                while (i < Samples && LoopCyclesLeft) {
247                    InterpolateOneStep_Mono(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i]);
248                    if (Pos > pSample->LoopEnd) {
249                        Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
250                        LoopCyclesLeft--;
251                    }
252                }
253                // render on without loop
254                while (i < Samples) {
255                    InterpolateOneStep_Mono(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i]);
256                }
257            }
258            else { // render loop (endless loop)
259                while (i < Samples) {
260                    InterpolateOneStep_Mono(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i]);
261                    if (Pos > pSample->LoopEnd) {
262                        Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
263                    }
264                }
265          }          }
266      }      }
267  }  }
268    
269    /**
270     *  Immediately kill the voice.
271     */
272  void Voice::Kill() {  void Voice::Kill() {
273      if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {      if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
274          pDiskThread->OrderDeletionOfStream(&DiskStreamRef);          pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
275      }      }
276        DiskStreamRef.pStream = NULL;
277        DiskStreamRef.hStream = 0;
278        DiskStreamRef.State   = Stream::state_unused;
279        DiskStreamRef.OrderID = 0;
280      Active = false;      Active = false;
281  }  }
282    
283    /**
284     *  Release the voice in an appropriate time range, the voice will go through
285     *  it's release stage before it will be killed.
286     */
287    void Voice::Release() {
288       EG1.Release();
289    }

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

  ViewVC Help
Powered by ViewVC