/[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 9 by schoenebeck, Wed Nov 5 14:47:10 2003 UTC revision 26 by schoenebeck, Fri Dec 26 16:39:58 2003 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      pRegion       = Instrument->GetRegion(MIDIKey);   *  needed.
40      PlaybackState = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed   *
41      Pos           = 0;   *  @returns  0 on success, a value < 0 if something failed
42     */
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 66  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 - (OutputBufferSize << MAX_PITCH) / pSample->Channels;
79          pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos);  
80          dmsg(("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(("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);      CurrentPitch = pow(2, (double) (MIDIKey - (int) pSample->MIDIUnityNote) / (double) 12);
105        Volume       = pDimRgn->GetVelocityAttenuation(Velocity);
106    
107      // ************************************************      // ************************************************
108      // TODO: ARTICULATION DATA HANDLING IS MISSING HERE      // TODO: ARTICULATION DATA HANDLING IS MISSING HERE
109      // ************************************************      // ************************************************
110    
111        return 0; // success
112  }  }
113    
114    /**
115     *  Renders the audio data for this voice for the current audio fragment.
116     *  The sample input data can either come from RAM (cached sample or sample
117     *  part) or directly from disk. The output signal will be rendered by
118     *  resampling / interpolation. If this voice is a disk streaming voice and
119     *  the voice completely played back the cached RAM part of the sample, it
120     *  will automatically switch to disk playback for the next RenderAudio()
121     *  call.
122     */
123  void Voice::RenderAudio() {  void Voice::RenderAudio() {
124    
125      switch (this->PlaybackState) {      switch (this->PlaybackState) {
126    
127          case playback_state_ram: {          case playback_state_ram: {
128                  Interpolate((sample_t*) pSample->GetCache().pStart);                  if (RAMLoop) InterpolateAndLoop((sample_t*) pSample->GetCache().pStart);
129                    else         Interpolate((sample_t*) pSample->GetCache().pStart);
130                  if (DiskVoice) {                  if (DiskVoice) {
131                      // check if we reached the allowed limit of the sample RAM cache                      // check if we reached the allowed limit of the sample RAM cache
132                      if (Pos > MaxRAMPos) {                      if (Pos > MaxRAMPos) {
133                          dmsg(("Voice: switching to disk playback (Pos=%f)\n", Pos));                          dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos));
134                          this->PlaybackState = playback_state_disk;                          this->PlaybackState = playback_state_disk;
135                      }                      }
136                  }                  }
# Line 108  void Voice::RenderAudio() { Line 146  void Voice::RenderAudio() {
146                      DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);                      DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);
147                      if (!DiskStreamRef.pStream) {                      if (!DiskStreamRef.pStream) {
148                          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;
149                          pDiskThread->OrderDeletionOfStream(&DiskStreamRef);                          Kill();
                         this->Active = false;  
150                          return;                          return;
151                      }                      }
152                      DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (double_to_int(Pos) - MaxRAMPos));                      DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (double_to_int(Pos) - MaxRAMPos));
# Line 130  void Voice::RenderAudio() { Line 167  void Voice::RenderAudio() {
167              break;              break;
168    
169          case playback_state_end:          case playback_state_end:
170              this->Active = false; // free voice              Kill(); // free voice
171              break;              break;
172      }      }
173  }  }
174    
175    /**
176     *  Interpolates the input audio data (no loop).
177     *
178     *  @param pSrc - pointer to input sample data
179     */
180  void Voice::Interpolate(sample_t* pSrc) {  void Voice::Interpolate(sample_t* pSrc) {
181      float effective_volume = 1;  // TODO: use the art. data instead      float effective_volume = this->Volume;
182      int   i = 0;      int   i = 0;
183    
184      // ************************************************      // ************************************************
# Line 146  void Voice::Interpolate(sample_t* pSrc) Line 188  void Voice::Interpolate(sample_t* pSrc)
188      // FIXME: assuming either mono or stereo      // FIXME: assuming either mono or stereo
189      if (this->pSample->Channels == 2) { // Stereo Sample      if (this->pSample->Channels == 2) { // Stereo Sample
190          while (i < this->OutputBufferSize) {          while (i < this->OutputBufferSize) {
191              #ifdef USE_LINEAR_INTERPOLATION              InterpolateOneStep_Stereo(pSrc, i, effective_volume);
                 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;  
192          }          }
193      }      }
194      else { // Mono Sample      else { // Mono Sample
195          while (i < this->OutputBufferSize) {          while (i < this->OutputBufferSize) {
196              #ifdef USE_LINEAR_INTERPOLATION              InterpolateOneStep_Mono(pSrc, i, effective_volume);
197                  int   pos_int       = double_to_int(this->Pos);  // integer position          }
198                  float pos_fract     = this->Pos - pos_int;       // fractional part of position      }
199                  float sample_point  = effective_volume * (pSrc[pos_int] + pos_fract * (pSrc[pos_int+1] - pSrc[pos_int]));  }
200                  this->pOutput[i]   += sample_point;  
201                  this->pOutput[i+1] += sample_point;  /**
202                  i += 2;   *  Interpolates the input audio data, this method honors looping.
203              #else // polynomial interpolation   *
204                  //FIXME: !!!THIS WON'T WORK!!! needs to be adjusted for stereo, use linear interpolation meanwhile   *  @param pSrc - pointer to input sample data
205                  xm1 = pSrc[pos_int];   */
206                  x0  = pSrc[pos_int+1];  void Voice::InterpolateAndLoop(sample_t* pSrc) {
207                  x1  = pSrc[pos_int+2];      float effective_volume = this->Volume;
208                  x2  = pSrc[pos_int+3];      int   i = 0;
209                  a   = (3 * (x0-x1) - xm1 + x2) / 2;  
210                  b   = 2 * x1 + xm1 - (5 * x0 + x2) / 2;      // ************************************************
211                  c   = (x1 - xm1) / 2;      // TODO: ARTICULATION DATA HANDLING IS MISSING HERE
212                 this->pOutput[u] += effective_volume*((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0);      // ************************************************
             #endif  
213    
214              this->Pos += this->CurrentPitch;      // FIXME: assuming either mono or stereo
215        if (pSample->Channels == 2) { // Stereo Sample
216            if (pSample->LoopPlayCount) {
217                // render loop (loop count limited)
218                while (i < OutputBufferSize && LoopCyclesLeft) {
219                    InterpolateOneStep_Stereo(pSrc, i, effective_volume);
220                    if (Pos > pSample->LoopEnd) {
221                        Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
222                        LoopCyclesLeft--;
223                    }
224                }
225                // render on without loop
226                while (i < OutputBufferSize) {
227                    InterpolateOneStep_Stereo(pSrc, i, effective_volume);
228                }
229            }
230            else { // render loop (endless loop)
231                while (i < OutputBufferSize) {
232                    InterpolateOneStep_Stereo(pSrc, i, effective_volume);
233                    if (Pos > pSample->LoopEnd) {
234                        Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);
235                    }
236                }
237            }
238        }
239        else { // Mono Sample
240            if (pSample->LoopPlayCount) {
241                // render loop (loop count limited)
242                while (i < OutputBufferSize && LoopCyclesLeft) {
243                    InterpolateOneStep_Mono(pSrc, i, effective_volume);
244                    if (Pos > pSample->LoopEnd) {
245                        Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
246                        LoopCyclesLeft--;
247                    }
248                }
249                // render on without loop
250                while (i < OutputBufferSize) {
251                    InterpolateOneStep_Mono(pSrc, i, effective_volume);
252                }
253            }
254            else { // render loop (endless loop)
255                while (i < OutputBufferSize) {
256                    InterpolateOneStep_Mono(pSrc, i, effective_volume);
257                    if (Pos > pSample->LoopEnd) {
258                        Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
259                    }
260                }
261          }          }
262      }      }
263  }  }
264    
265    /**
266     *  Immediately kill the voice.
267     */
268  void Voice::Kill() {  void Voice::Kill() {
269      if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {      if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
270          pDiskThread->OrderDeletionOfStream(&DiskStreamRef);          pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
271      }      }
272        DiskStreamRef.pStream = NULL;
273        DiskStreamRef.hStream = 0;
274        DiskStreamRef.State   = Stream::state_unused;
275        DiskStreamRef.OrderID = 0;
276      Active = false;      Active = false;
277  }  }

Legend:
Removed from v.9  
changed lines
  Added in v.26

  ViewVC Help
Powered by ViewVC