/[svn]/linuxsampler/trunk/src/audiothread.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/audiothread.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 15 by schoenebeck, Sun Nov 23 21:16:49 2003 UTC revision 18 by schoenebeck, Sun Dec 7 05:03:43 2003 UTC
# Line 35  AudioThread::AudioThread(AudioIO* pAudio Line 35  AudioThread::AudioThread(AudioIO* pAudio
35          pVoices[i] = new Voice(pDiskThread);          pVoices[i] = new Voice(pDiskThread);
36      }      }
37      for (uint i = 0; i < 128; i++) {      for (uint i = 0; i < 128; i++) {
38          pMIDIKeyInfo[i].pActiveVoices = new RTEList<Voice*>;          pMIDIKeyInfo[i].pActiveVoices    = new RTEList<Voice*>;
39          pMIDIKeyInfo[i].hSustainPtr   = NULL;          pMIDIKeyInfo[i].hSustainPtr      = NULL;
40          pMIDIKeyInfo[i].Sustained     = false;          pMIDIKeyInfo[i].Sustained        = false;
41            pMIDIKeyInfo[i].KeyPressed       = false;
42            pMIDIKeyInfo[i].pSustainPoolNode = NULL;
43      }      }
44      SustainedKeyPool = new RTELMemoryPool<uint>(128);      SustainedKeyPool = new RTELMemoryPool<uint>(128);
45    
# Line 88  int AudioThread::Main() { Line 90  int AudioThread::Main() {
90          // read and process commands from the queue          // read and process commands from the queue
91          while (true) {          while (true) {
92              command_t command;              command_t command;
93              if (pCommandQueue->read(&command, 1) == 0) break;              if (!pCommandQueue->pop(&command)) break;
94    
95              switch (command.type) {              switch (command.type) {
96                  case command_type_note_on:                  case command_type_note_on:
97                      dmsg(5,("Audio Thread: Note on received\n"));                      dmsg(5,("Audio Thread: Note on received\n"));
98                      ActivateVoice(command.pitch, command.velocity);                      ProcessNoteOn(command.pitch, command.velocity);
99                      break;                      break;
100                  case command_type_note_off:                  case command_type_note_off:
101                      dmsg(5,("Audio Thread: Note off received\n"));                      dmsg(5,("Audio Thread: Note off received\n"));
102                      ReleaseVoice(command.pitch, command.velocity);                      ProcessNoteOff(command.pitch, command.velocity);
103                      break;                      break;
104                  case command_type_continuous_controller:                  case command_type_continuous_controller:
105                      dmsg(5,("Audio Thread: MIDI CC received\n"));                      dmsg(5,("Audio Thread: MIDI CC received\n"));
106                      ContinuousController(command.channel, command.number, command.value);                      ProcessControlChange(command.channel, command.number, command.value);
107                      break;                      break;
108              }              }
109          }          }
# Line 148  int AudioThread::Main() { Line 150  int AudioThread::Main() {
150  }  }
151    
152  /// Will be called by the MIDIIn Thread to let the audio thread trigger a new voice.  /// Will be called by the MIDIIn Thread to let the audio thread trigger a new voice.
153  void AudioThread::ProcessNoteOn(uint8_t Pitch, uint8_t Velocity) {  void AudioThread::SendNoteOn(uint8_t Pitch, uint8_t Velocity) {
154      command_t cmd;      command_t cmd;
155      cmd.type     = command_type_note_on;      cmd.type     = command_type_note_on;
156      cmd.pitch    = Pitch;      cmd.pitch    = Pitch;
157      cmd.velocity = Velocity;      cmd.velocity = Velocity;
158      this->pCommandQueue->write(&cmd, 1);      if (this->pCommandQueue->write_space() > 0) this->pCommandQueue->push(&cmd);
159        else dmsg(1,("AudioThread: Command queue full!"));
160  }  }
161    
162  /// Will be called by the MIDIIn Thread to signal the audio thread to release a voice.  /// Will be called by the MIDIIn Thread to signal the audio thread to release voice(s).
163  void AudioThread::ProcessNoteOff(uint8_t Pitch, uint8_t Velocity) {  void AudioThread::SendNoteOff(uint8_t Pitch, uint8_t Velocity) {
164      command_t cmd;      command_t cmd;
165      cmd.type     = command_type_note_off;      cmd.type     = command_type_note_off;
166      cmd.pitch    = Pitch;      cmd.pitch    = Pitch;
167      cmd.velocity = Velocity;      cmd.velocity = Velocity;
168      this->pCommandQueue->write(&cmd, 1);      if (this->pCommandQueue->write_space() > 0) this->pCommandQueue->push(&cmd);
169        else dmsg(1,("AudioThread: Command queue full!"));
170  }  }
171    
172  // Will be called by the MIDIIn Thead to send MIDI continuos controller events  // Will be called by the MIDIIn Thread to signal the audio thread that a continuous controller value has changed.
173  void AudioThread::ProcessContinuousController(uint8_t Channel, uint8_t Number, uint8_t Value) {  void AudioThread::SendControlChange(uint8_t Channel, uint8_t Number, uint8_t Value) {
174      command_t cmd;      command_t cmd;
175      cmd.type     = command_type_continuous_controller;      cmd.type     = command_type_continuous_controller;
176      cmd.channel  = Channel;      cmd.channel  = Channel;
177      cmd.number   = Number;      cmd.number   = Number;
178      cmd.value    = Value;      cmd.value    = Value;
179      this->pCommandQueue->write(&cmd, 1);      if (this->pCommandQueue->write_space() > 0) this->pCommandQueue->push(&cmd);
180        else dmsg(1,("AudioThread: Command queue full!"));
181  }  }
182    
183  void AudioThread::ActivateVoice(uint8_t MIDIKey, uint8_t Velocity) {  /**
184     *  Assigns and triggers a new voice for the respective MIDI key.
185     */
186    void AudioThread::ProcessNoteOn(uint8_t MIDIKey, uint8_t Velocity) {
187        pMIDIKeyInfo[MIDIKey].KeyPressed = true; // the MIDI key was currently pressed down
188      for (int i = 0; i < MAX_AUDIO_VOICES; i++) {      for (int i = 0; i < MAX_AUDIO_VOICES; i++) {
189          if (pVoices[i]->IsActive()) continue;          if (pVoices[i]->IsActive()) continue; // search for a free voice
190    
191            // launch the new voice
192            if (pVoices[i]->Trigger(MIDIKey, Velocity, this->pInstrument) < 0) {
193                return; // failed to trigger the new voice
194            }
195    
196          // add (append) a new voice to the corresponding MIDIKey active voices list          // add (append) a new voice to the corresponding MIDIKey active voices list
197          Voice** new_voice_ptr = ActiveVoicePool->alloc_append(pMIDIKeyInfo[MIDIKey].pActiveVoices);          Voice** new_voice_ptr = ActiveVoicePool->alloc_append(pMIDIKeyInfo[MIDIKey].pActiveVoices);
198          *new_voice_ptr = pVoices[i];          *new_voice_ptr = pVoices[i];
199          pVoices[i]->pSelfPtr = new_voice_ptr; // FIXME: hack to allow fast deallocation          pVoices[i]->pSelfPtr = new_voice_ptr; // FIXME: hack to allow fast deallocation
         pVoices[i]->Trigger(MIDIKey, Velocity, this->pInstrument);  
200    
201            // update key info
202          if (!pMIDIKeyInfo[MIDIKey].hSustainPtr) {          if (!pMIDIKeyInfo[MIDIKey].hSustainPtr) {
203              dmsg(4,("ActivateVoice(uint,uint): hSustainPtr == null, setting release pointer to the last voice on the key...\n"));              dmsg(4,("ActivateVoice(uint,uint): hSustainPtr == null, setting release pointer to the last voice on the key...\n"));
204              pMIDIKeyInfo[MIDIKey].pActiveVoices->last();              pMIDIKeyInfo[MIDIKey].pActiveVoices->last();
# Line 201  void AudioThread::ActivateVoice(uint8_t Line 215  void AudioThread::ActivateVoice(uint8_t
215   *  sustain pedal will be released or voice turned inactive by itself (e.g.   *  sustain pedal will be released or voice turned inactive by itself (e.g.
216   *  due to completion of sample playback).   *  due to completion of sample playback).
217   */   */
218  void AudioThread::ReleaseVoice(uint8_t MIDIKey, uint8_t Velocity) {  void AudioThread::ProcessNoteOff(uint8_t MIDIKey, uint8_t Velocity) {
219        pMIDIKeyInfo[MIDIKey].KeyPressed = false; // the MIDI key was currently released
220      midi_key_info_t* pmidikey = &pMIDIKeyInfo[MIDIKey];      midi_key_info_t* pmidikey = &pMIDIKeyInfo[MIDIKey];
221      if (SustainPedal) { // if sustain pedal is pressed postpone the Note-Off      if (SustainPedal) { // if sustain pedal is pressed postpone the Note-Off
222          if (pmidikey->hSustainPtr) {          if (pmidikey->hSustainPtr) {
# Line 214  void AudioThread::ReleaseVoice(uint8_t M Line 229  void AudioThread::ReleaseVoice(uint8_t M
229                  pmidikey->hSustainPtr = pmidikey->pActiveVoices->current();                  pmidikey->hSustainPtr = pmidikey->pActiveVoices->current();
230                  // if the key was not sustained yet, add it's MIDI key number to the sustained key pool                  // if the key was not sustained yet, add it's MIDI key number to the sustained key pool
231                  if (!pmidikey->Sustained) {                  if (!pmidikey->Sustained) {
232                      uint* sustainedmidikey = SustainedKeyPool->alloc();                      uint* sustainedmidikey     = SustainedKeyPool->alloc();
233                      *sustainedmidikey      = MIDIKey;                      *sustainedmidikey          = MIDIKey;
234                      pmidikey->Sustained    = true;                      pmidikey->pSustainPoolNode = sustainedmidikey;
235                        pmidikey->Sustained        = true;
236                  }                  }
237              }              }
238              else dmsg(3,("Ignoring NOTE OFF --> pVoiceToRelease == null!\n"));              else dmsg(3,("Ignoring NOTE OFF --> pVoiceToRelease == null!\n"));
# Line 224  void AudioThread::ReleaseVoice(uint8_t M Line 240  void AudioThread::ReleaseVoice(uint8_t M
240          else dmsg(3,("Ignoring NOTE OFF, seems like more Note-Offs than Note-Ons or no free voices available?\n"));          else dmsg(3,("Ignoring NOTE OFF, seems like more Note-Offs than Note-Ons or no free voices available?\n"));
241      }      }
242      else {      else {
243          // get the first voice in the list of active voices on the MIDI Key          // release all active voices on the midi key
244          Voice** pVoicePtr = pmidikey->pActiveVoices->first();          Voice** pVoicePtr = pmidikey->pActiveVoices->first();
245          if (pVoicePtr) ReleaseVoice(*pVoicePtr);          while (pVoicePtr) {
246          else dmsg(2,("Couldn't find active voice for note off command, maybe already released.\n"));              Voice** pVoicePtrNext = pMIDIKeyInfo[MIDIKey].pActiveVoices->next();
247                ReleaseVoice(*pVoicePtr);
248                pVoicePtr = pVoicePtrNext;
249            }
250      }      }
251  }  }
252    
253  /**  /**
254   *  Releases the voice given with pVoice (no matter if sustain is pressed or   *  Releases the voice given with pVoice (no matter if sustain is pressed or
255   *  not). This method will e.g. be directly called if a voice went inactive   *  not). This method will e.g. be directly called if a voice went inactive
256   *  by itself. If susatain pedal is pressed the method takes care to free   *  by itself. If sustain pedal is pressed the method takes care to free
257   *  those sustain informations of the voice.   *  those sustain informations of the voice.
258   */   */
259  void AudioThread::ReleaseVoice(Voice* pVoice) {  void AudioThread::ReleaseVoice(Voice* pVoice) {
# Line 242  void AudioThread::ReleaseVoice(Voice* pV Line 261  void AudioThread::ReleaseVoice(Voice* pV
261          if (pVoice->IsActive()) pVoice->Kill(); //TODO: for now we're rude and just kill the poor, poor voice immediately :), later we add a Release() method to the Voice class and call it here to let the voice go through it's release phase          if (pVoice->IsActive()) pVoice->Kill(); //TODO: for now we're rude and just kill the poor, poor voice immediately :), later we add a Release() method to the Voice class and call it here to let the voice go through it's release phase
262    
263          if (pMIDIKeyInfo[pVoice->MIDIKey].Sustained) {          if (pMIDIKeyInfo[pVoice->MIDIKey].Sustained) {
   
264              // check if the sustain pointer has to be moved, now that we release the voice              // check if the sustain pointer has to be moved, now that we release the voice
265              RTEList<Voice*>::NodeHandle hSustainPtr = pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr;              RTEList<Voice*>::NodeHandle hSustainPtr = pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr;
266              if (hSustainPtr) {              if (hSustainPtr) {
# Line 258  void AudioThread::ReleaseVoice(Voice* pV Line 276  void AudioThread::ReleaseVoice(Voice* pV
276                  else dmsg(3,("ReleaseVoice(Voice*): pVoicePtr == null\n"));                  else dmsg(3,("ReleaseVoice(Voice*): pVoicePtr == null\n"));
277              }              }
278              else dmsg(3,("ReleaseVoice(Voice*): hSustainPtr == null\n"));              else dmsg(3,("ReleaseVoice(Voice*): hSustainPtr == null\n"));
279            }
280    
281              // remove the voice from the list associated with this MIDI key          // remove the voice from the list associated with this MIDI key
282              ActiveVoicePool->free(pVoice->pSelfPtr);          ActiveVoicePool->free(pVoice->pSelfPtr);
283    
284              // check if there are no sustained voices left on the MIDI key and update the key info if so          // check if there are no voices left on the MIDI key and update the key info if so
285              if (pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->is_empty()) {          if (pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->is_empty()) {
286                  pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr = NULL;              pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr = NULL;
287                  pMIDIKeyInfo[pVoice->MIDIKey].Sustained   = false;              if (pMIDIKeyInfo[pVoice->MIDIKey].Sustained) {
288                  dmsg(3,("Key now not sustained\n"));                  SustainedKeyPool->free(pMIDIKeyInfo[pVoice->MIDIKey].pSustainPoolNode);
289                    pMIDIKeyInfo[pVoice->MIDIKey].pSustainPoolNode = NULL;
290                    pMIDIKeyInfo[pVoice->MIDIKey].Sustained        = false;
291              }              }
292          }              dmsg(3,("Key has no more voices now\n"));
         else {  
             // remove the voice from the list associated with this MIDI key  
             ActiveVoicePool->free(pVoice->pSelfPtr);  
             dmsg(4,("Key was not sustained\n"));  
293          }          }
294      }      }
295      else std::cerr << "Couldn't release voice! (pVoice == NULL)\n" << std::flush;      else std::cerr << "Couldn't release voice! (pVoice == NULL)\n" << std::flush;
296  }  }
297    
298  void AudioThread::ContinuousController(uint8_t Channel, uint8_t Number, uint8_t Value) {  void AudioThread::ProcessControlChange(uint8_t Channel, uint8_t Number, uint8_t Value) {
299      dmsg(4,("AudioThread::ContinuousController c=%d n=%d v=%d\n", Channel, Number, Value));      dmsg(4,("AudioThread::ContinuousController c=%d n=%d v=%d\n", Channel, Number, Value));
300      if (Number == 64) {      if (Number == 64) {
301          if (Value >= 64 && PrevHoldCCValue < 64) {          if (Value >= 64 && PrevHoldCCValue < 64) {
# Line 290  void AudioThread::ContinuousController(u Line 307  void AudioThread::ContinuousController(u
307              SustainPedal = false;              SustainPedal = false;
308              // iterate through all keys that are currently sustained              // iterate through all keys that are currently sustained
309              for (uint* key = SustainedKeyPool->first(); key; key = SustainedKeyPool->next()) {              for (uint* key = SustainedKeyPool->first(); key; key = SustainedKeyPool->next()) {
310                  // release all active voices on the midi key                  if (!pMIDIKeyInfo[*key].KeyPressed) { // release the voices on the key, if the key is not pressed anymore
311                  Voice** pVoicePtr = pMIDIKeyInfo[*key].pActiveVoices->first();                      // release all active voices on the midi key
312                  while (pVoicePtr) {                      Voice** pVoicePtr = pMIDIKeyInfo[*key].pActiveVoices->first();
313                      Voice** pVoicePtrNext = pMIDIKeyInfo[*key].pActiveVoices->next();                      while (pVoicePtr) {
314                      dmsg(3,("Sustain CC: releasing voice on midi key %d\n", *key));                          Voice** pVoicePtrNext = pMIDIKeyInfo[*key].pActiveVoices->next();
315                      ReleaseVoice(*pVoicePtr);                          dmsg(3,("Sustain CC: releasing voice on midi key %d\n", *key));
316                      pVoicePtr = pVoicePtrNext;                          ReleaseVoice(*pVoicePtr);
317                            pVoicePtr = pVoicePtrNext;
318                        }
319                  }                  }
320              }              }
             // empty the SustainedKeyPool (free all the elements)  
             SustainedKeyPool->empty();  
321          }          }
322          PrevHoldCCValue = Value;          PrevHoldCCValue = Value;
323      }      }
# Line 314  void AudioThread::CacheInitialSamples(gi Line 331  void AudioThread::CacheInitialSamples(gi
331          // number of '0' samples (silence samples) behind the official buffer          // number of '0' samples (silence samples) behind the official buffer
332          // border, to allow the interpolator do it's work even at the end of          // border, to allow the interpolator do it's work even at the end of
333          // the sample.          // the sample.
334          gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(pAudioIO->FragmentSize << MAX_PITCH);          gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension((pAudioIO->FragmentSize << MAX_PITCH) + 3);
335          dmsg(4,("Cached %d Bytes, %d silence bytes.\n", buf.Size, buf.NullExtensionSize));          dmsg(4,("Cached %d Bytes, %d silence bytes.\n", buf.Size, buf.NullExtensionSize));
336      }      }
337      else { // we only cache NUM_RAM_PRELOAD_SAMPLES and stream the other sample points from disk      else { // we only cache NUM_RAM_PRELOAD_SAMPLES and stream the other sample points from disk

Legend:
Removed from v.15  
changed lines
  Added in v.18

  ViewVC Help
Powered by ViewVC