/[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 30 by schoenebeck, Sun Jan 11 16:43:54 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 - (OutputBufferSize << 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    /**
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::RenderAudio() {  void Voice::RenderAudio() {
130    
131        // Let all modulators throw their parameter changes for the current audio fragment
132        ModulationSystem::ResetDestinationParameter(ModulationSystem::destination_vca, this->Volume);
133        EG1.ProcessFragment();
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((sample_t*) pSample->GetCache().pStart);
140                    else         Interpolate((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 134  void Voice::RenderAudio() { Line 181  void Voice::RenderAudio() {
181              Kill(); // free voice              Kill(); // free voice
182              break;              break;
183      }      }
184    
185        // If release stage finished, let the voice be killed
186        if (EG1.GetStage() == EG_VCA::stage_end) this->PlaybackState = playback_state_end;
187  }  }
188    
189    /**
190     *  Interpolates the input audio data (no loop).
191     *
192     *  @param pSrc - pointer to input sample data
193     */
194  void Voice::Interpolate(sample_t* pSrc) {  void Voice::Interpolate(sample_t* pSrc) {
195      float effective_volume = 1;  // TODO: use the art. data instead      int i = 0;
196      int   i = 0;      float e = 1.0;
   
     // ************************************************  
     // TODO: ARTICULATION DATA HANDLING IS MISSING HERE  
     // ************************************************  
197    
198      // FIXME: assuming either mono or stereo      // FIXME: assuming either mono or stereo
199      if (this->pSample->Channels == 2) { // Stereo Sample      if (this->pSample->Channels == 2) { // Stereo Sample
200          while (i < this->OutputBufferSize) {          while (i < this->OutputBufferSize) {
201              #ifdef USE_LINEAR_INTERPOLATION              InterpolateOneStep_Stereo(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i>>1]);
                 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;  
202          }          }
203      }      }
204      else { // Mono Sample      else { // Mono Sample
205          while (i < this->OutputBufferSize) {          while (i < this->OutputBufferSize) {
206              #ifdef USE_LINEAR_INTERPOLATION              InterpolateOneStep_Mono(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i>>1]);
207                  int   pos_int       = double_to_int(this->Pos);  // integer position          }
208                  float pos_fract     = this->Pos - pos_int;       // fractional part of position      }
209                  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  
210    
211              this->Pos += this->CurrentPitch;  /**
212     *  Interpolates the input audio data, this method honors looping.
213     *
214     *  @param pSrc - pointer to input sample data
215     */
216    void Voice::InterpolateAndLoop(sample_t* pSrc) {
217        int i = 0;
218    
219        // FIXME: assuming either mono or stereo
220        if (pSample->Channels == 2) { // Stereo Sample
221            if (pSample->LoopPlayCount) {
222                // render loop (loop count limited)
223                while (i < OutputBufferSize && LoopCyclesLeft) {
224                    InterpolateOneStep_Stereo(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i>>1]);
225                    if (Pos > pSample->LoopEnd) {
226                        Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
227                        LoopCyclesLeft--;
228                    }
229                }
230                // render on without loop
231                while (i < OutputBufferSize) {
232                    InterpolateOneStep_Stereo(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i>>1]);
233                }
234            }
235            else { // render loop (endless loop)
236                while (i < OutputBufferSize) {
237                    InterpolateOneStep_Stereo(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i>>1]);
238                    if (Pos > pSample->LoopEnd) {
239                        Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);
240                    }
241                }
242            }
243        }
244        else { // Mono Sample
245            if (pSample->LoopPlayCount) {
246                // render loop (loop count limited)
247                while (i < OutputBufferSize && LoopCyclesLeft) {
248                    InterpolateOneStep_Mono(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i>>1]);
249                    if (Pos > pSample->LoopEnd) {
250                        Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
251                        LoopCyclesLeft--;
252                    }
253                }
254                // render on without loop
255                while (i < OutputBufferSize) {
256                    InterpolateOneStep_Mono(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i>>1]);
257                }
258            }
259            else { // render loop (endless loop)
260                while (i < OutputBufferSize) {
261                    InterpolateOneStep_Mono(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i>>1]);
262                    if (Pos > pSample->LoopEnd) {
263                        Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
264                    }
265                }
266          }          }
267      }      }
268  }  }
269    
270    /**
271     *  Immediately kill the voice.
272     */
273  void Voice::Kill() {  void Voice::Kill() {
274      if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {      if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
275          pDiskThread->OrderDeletionOfStream(&DiskStreamRef);          pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
276      }      }
277        DiskStreamRef.pStream = NULL;
278        DiskStreamRef.hStream = 0;
279        DiskStreamRef.State   = Stream::state_unused;
280        DiskStreamRef.OrderID = 0;
281      Active = false;      Active = false;
282  }  }
283    
284    /**
285     *  Release the voice in an appropriate time range, the voice will go through
286     *  it's release stage before it will be killed.
287     */
288    void Voice::Release() {
289       EG1.Release();
290    }

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

  ViewVC Help
Powered by ViewVC