/[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 13 by schoenebeck, Fri Nov 21 15:07:23 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          pActiveVoices[i] = new RTEList<Voice*>;          pMIDIKeyInfo[i].pActiveVoices    = new RTEList<Voice*>;
39            pMIDIKeyInfo[i].hSustainPtr      = NULL;
40            pMIDIKeyInfo[i].Sustained        = false;
41            pMIDIKeyInfo[i].KeyPressed       = false;
42            pMIDIKeyInfo[i].pSustainPoolNode = NULL;
43      }      }
44      SustainedKeyPool = new RTELMemoryPool<sustained_key_t>(200);      SustainedKeyPool = new RTELMemoryPool<uint>(128);
45    
46      pAudioSumBuffer = new float[pAudioIO->FragmentSize * pAudioIO->Channels];      pAudioSumBuffer = new float[pAudioIO->FragmentSize * pAudioIO->Channels];
47    
# Line 86  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 146  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          pVoices[i]->Trigger(MIDIKey, Velocity, this->pInstrument);  
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(pActiveVoices[MIDIKey]);          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
200    
201            // update key info
202            if (!pMIDIKeyInfo[MIDIKey].hSustainPtr) {
203                dmsg(4,("ActivateVoice(uint,uint): hSustainPtr == null, setting release pointer to the last voice on the key...\n"));
204                pMIDIKeyInfo[MIDIKey].pActiveVoices->last();
205                pMIDIKeyInfo[MIDIKey].hSustainPtr = pMIDIKeyInfo[MIDIKey].pActiveVoices->current();
206            }
207          return;          return;
208      }      }
209      std::cerr << "No free voice!" << std::endl << std::flush;      std::cerr << "No free voice!" << std::endl << std::flush;
210  }  }
211    
212  void AudioThread::ReleaseVoice(uint8_t MIDIKey, uint8_t Velocity) {  /**
213      // if sustain pedal is pressed postpone the Note-Off   *  Releases the voices on the given key if sustain pedal is not pressed.
214      if (SustainPedal) {   *  If sustain is pressed, the release of the note will be postponed until
215          // alloc an element in the SustainedKeyPool and add the current midikey to it   *  sustain pedal will be released or voice turned inactive by itself (e.g.
216          sustained_key_t* key = SustainedKeyPool->alloc();   *  due to completion of sample playback).
217          if (key == NULL) printf("ERROR: SustainedKeyPool FULL ! exiting\n"); // FIXME   */
218          key->midikey  = MIDIKey;  void AudioThread::ProcessNoteOff(uint8_t MIDIKey, uint8_t Velocity) {
219          key->velocity = Velocity;      pMIDIKeyInfo[MIDIKey].KeyPressed = false; // the MIDI key was currently released
220        midi_key_info_t* pmidikey = &pMIDIKeyInfo[MIDIKey];
221        if (SustainPedal) { // if sustain pedal is pressed postpone the Note-Off
222            if (pmidikey->hSustainPtr) {
223                // stick the note-off information to the respective voice
224                Voice** pVoiceToRelease = pmidikey->pActiveVoices->set_current(pmidikey->hSustainPtr);
225                if (pVoiceToRelease) {
226                    (*pVoiceToRelease)->ReleaseVelocity = Velocity;
227                    // now increment the sustain pointer
228                    pmidikey->pActiveVoices->next();
229                    pmidikey->hSustainPtr = pmidikey->pActiveVoices->current();
230                    // if the key was not sustained yet, add it's MIDI key number to the sustained key pool
231                    if (!pmidikey->Sustained) {
232                        uint* sustainedmidikey     = SustainedKeyPool->alloc();
233                        *sustainedmidikey          = MIDIKey;
234                        pmidikey->pSustainPoolNode = sustainedmidikey;
235                        pmidikey->Sustained        = true;
236                    }
237                }
238                else dmsg(3,("Ignoring NOTE OFF --> pVoiceToRelease == null!\n"));
239            }
240            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 = pActiveVoices[MIDIKey]->first();          Voice** pVoicePtr = pmidikey->pActiveVoices->first();
245          if (pVoicePtr) ReleaseVoice(*pVoicePtr);          while (pVoicePtr) {
246          else std::cerr << "Couldn't find active voice for note off command!" << std::endl << std::flush;              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
255     *  not). This method will e.g. be directly called if a voice went inactive
256     *  by itself. If sustain pedal is pressed the method takes care to free
257     *  those sustain informations of the voice.
258     */
259  void AudioThread::ReleaseVoice(Voice* pVoice) {  void AudioThread::ReleaseVoice(Voice* pVoice) {
260      if (pVoice) {      if (pVoice) {
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          // remove the voice from the list associated to this MIDI key          if (pMIDIKeyInfo[pVoice->MIDIKey].Sustained) {
264                // check if the sustain pointer has to be moved, now that we release the voice
265                RTEList<Voice*>::NodeHandle hSustainPtr = pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr;
266                if (hSustainPtr) {
267                    Voice** pVoicePtr = pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->set_current(hSustainPtr);
268                    if (pVoicePtr) {
269                        if (*pVoicePtr == pVoice) { // move sustain pointer to the next sustained voice
270                            dmsg(3,("Correcting sustain pointer\n"));
271                            pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->next();
272                            pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr = pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->current();
273                        }
274                        else dmsg(4,("ReleaseVoice(Voice*): *hSustain != pVoice\n"));
275                    }
276                    else dmsg(3,("ReleaseVoice(Voice*): pVoicePtr == null\n"));
277                }
278                else dmsg(3,("ReleaseVoice(Voice*): hSustainPtr == null\n"));
279            }
280    
281            // 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 voices left on the MIDI key and update the key info if so
285            if (pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->is_empty()) {
286                pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr = NULL;
287                if (pMIDIKeyInfo[pVoice->MIDIKey].Sustained) {
288                    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"));
293            }
294      }      }
295      else std::cerr << "Couldn't find active voice to release!" << std::endl << 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 223  void AudioThread::ContinuousController(u Line 305  void AudioThread::ContinuousController(u
305          if (Value < 64 && PrevHoldCCValue >= 64) {          if (Value < 64 && PrevHoldCCValue >= 64) {
306              dmsg(4,("PEDAL UP\n"));              dmsg(4,("PEDAL UP\n"));
307              SustainPedal = false;              SustainPedal = false;
308              for (sustained_key_t* key = SustainedKeyPool->first(); key; key = SustainedKeyPool->next()) {              // iterate through all keys that are currently sustained
309                  ReleaseVoice(key->midikey, key->velocity);              for (uint* key = SustainedKeyPool->first(); key; key = SustainedKeyPool->next()) {
310                    if (!pMIDIKeyInfo[*key].KeyPressed) { // release the voices on the key, if the key is not pressed anymore
311                        // release all active voices on the midi key
312                        Voice** pVoicePtr = pMIDIKeyInfo[*key].pActiveVoices->first();
313                        while (pVoicePtr) {
314                            Voice** pVoicePtrNext = pMIDIKeyInfo[*key].pActiveVoices->next();
315                            dmsg(3,("Sustain CC: releasing voice on midi key %d\n", *key));
316                            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 241  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.13  
changed lines
  Added in v.18

  ViewVC Help
Powered by ViewVC