/[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 10 by senoner, Tue Nov 11 23:30:47 2003 UTC revision 18 by schoenebeck, Sun Dec 7 05:03:43 2003 UTC
# Line 29  AudioThread::AudioThread(AudioIO* pAudio Line 29  AudioThread::AudioThread(AudioIO* pAudio
29      pCommandQueue     = new RingBuffer<command_t>(1024);      pCommandQueue     = new RingBuffer<command_t>(1024);
30      pVoices           = new Voice*[MAX_AUDIO_VOICES];      pVoices           = new Voice*[MAX_AUDIO_VOICES];
31      // allocate the ActiveVoicePool (for each midi key there is a variable size linked list      // allocate the ActiveVoicePool (for each midi key there is a variable size linked list
32      // of pointers to Voice classes)      // of pointers to Voice objects)
33      ActiveVoicePool=new RTELMemoryPool<Voice *>(MAX_AUDIO_VOICES);      ActiveVoicePool = new RTELMemoryPool<Voice*>(MAX_AUDIO_VOICES);
34      for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {      for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {
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<uint>(128);
     SustainedKeyPool=new RTELMemoryPool<sustained_key_t>(200);  
   
   
45    
46      pAudioSumBuffer = new float[pAudioIO->FragmentSize * pAudioIO->Channels];      pAudioSumBuffer = new float[pAudioIO->FragmentSize * pAudioIO->Channels];
47    
# Line 50  AudioThread::AudioThread(AudioIO* pAudio Line 51  AudioThread::AudioThread(AudioIO* pAudio
51      }      }
52    
53      // cache initial samples points (for actually needed samples)      // cache initial samples points (for actually needed samples)
54      dmsg(("Caching initial samples..."));      dmsg(1,("Caching initial samples..."));
55      gig::Region* pRgn = this->pInstrument->GetFirstRegion();      gig::Region* pRgn = this->pInstrument->GetFirstRegion();
56      while (pRgn) {      while (pRgn) {
57          if (!pRgn->GetSample()->GetCache().Size) {          if (!pRgn->GetSample()->GetCache().Size) {
58  //printf("C");              dmsg(2,("C"));
59              CacheInitialSamples(pRgn->GetSample());              CacheInitialSamples(pRgn->GetSample());
60          }          }
61          for (uint i = 0; i < pRgn->DimensionRegions; i++) {          for (uint i = 0; i < pRgn->DimensionRegions; i++) {
# Line 65  AudioThread::AudioThread(AudioIO* pAudio Line 66  AudioThread::AudioThread(AudioIO* pAudio
66      }      }
67    
68      // sustain pedal value      // sustain pedal value
69      PrevHoldCCValue=0;      PrevHoldCCValue = 0;
70      SustainPedal=0;      SustainPedal    = 0;
71    
72      dmsg(("OK\n"));      dmsg(1,("OK\n"));
73  }  }
74    
75  AudioThread::~AudioThread() {  AudioThread::~AudioThread() {
# Line 82  AudioThread::~AudioThread() { Line 83  AudioThread::~AudioThread() {
83  }  }
84    
85  int AudioThread::Main() {  int AudioThread::Main() {
86      dmsg(("Audio thread running\n"));      dmsg(2,("Audio thread running\n"));
     //int fifofd=open("/tmp/fifo1",O_WRONLY);  
87    
88      while (true) {      while (true) {
89    
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(("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(("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(("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 116  int AudioThread::Main() { Line 116  int AudioThread::Main() {
116    
117    
118          // render audio from all active voices          // render audio from all active voices
119          int act_voices=0;          int active_voices = 0;
120          for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {          for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {
121              if (pVoices[i]->IsActive()) {              if (pVoices[i]->IsActive()) {
122                  pVoices[i]->RenderAudio();                  pVoices[i]->RenderAudio();
123                  act_voices++;                  if (pVoices[i]->IsActive()) active_voices++; // still active
124                    else { // voice reached end, is now inactive
125                        ReleaseVoice(pVoices[i]); // remove voice from the list of active voices
126                    }
127              }              }
128          }          }
129          // write that to the disk thread class so that it can print it          // write that to the disk thread class so that it can print it
130          // on the console for debugging purposes          // on the console for debugging purposes
131          ActiveVoiceCount=act_voices;          ActiveVoiceCount = active_voices;
132            if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;
133    
134    
135          // check clipping in the audio sum, convert to sample_type          // check clipping in the audio sum, convert to sample_type
# Line 142  int AudioThread::Main() { Line 146  int AudioThread::Main() {
146          // call audio driver to output sound          // call audio driver to output sound
147          int res = this->pAudioIO->Output();          int res = this->pAudioIO->Output();
148          if (res < 0) exit(EXIT_FAILURE);          if (res < 0) exit(EXIT_FAILURE);
   
         // FIXME remove because we use it only to write to a fifo to save the audio  
         //write(fifofd, pAudioIO->pOutputBuffer, pAudioIO->FragmentSize * pAudioIO->Channels * sizeof(short));  
           
149      }      }
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    /**
184  void AudioThread::ActivateVoice(uint8_t MIDIKey, uint8_t Velocity) {   *  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
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     *  Releases the voices on the given key if sustain pedal is not pressed.
214     *  If sustain is pressed, the release of the note will be postponed until
215     *  sustain pedal will be released or voice turned inactive by itself (e.g.
216     *  due to completion of sample playback).
217     */
218    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];
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 {
243            // release all active voices on the midi key
244            Voice** pVoicePtr = pmidikey->pActiveVoices->first();
245            while (pVoicePtr) {
246                Voice** pVoicePtrNext = pMIDIKeyInfo[MIDIKey].pActiveVoices->next();
247                ReleaseVoice(*pVoicePtr);
248                pVoicePtr = pVoicePtrNext;
249            }
250        }
251    }
252    
253      // get the first voice in the list of active voices on the MIDI Key  /**
254      Voice** pVoicePtr = pActiveVoices[MIDIKey]->first();   *  Releases the voice given with pVoice (no matter if sustain is pressed or
255      Voice *pVoice=*pVoicePtr;   *  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) {
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
262    
263          // if sustain pedal is pressed postpone the Note-Off          if (pMIDIKeyInfo[pVoice->MIDIKey].Sustained) {
264          if(SustainPedal) {              // check if the sustain pointer has to be moved, now that we release the voice
265              // alloc an element in the SustainedKeyPool and add the current midikey to it              RTEList<Voice*>::NodeHandle hSustainPtr = pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr;
266              sustained_key_t *key=SustainedKeyPool->alloc();              if (hSustainPtr) {
267              if(key == NULL) { /* FIXME */ printf("ERROR: SustainedKeyPool FULL ! exiting\n"); exit(0); }                  Voice** pVoicePtr = pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->set_current(hSustainPtr);
268              key->midikey=MIDIKey;                  if (pVoicePtr) {
269              key->velocity=Velocity;                      if (*pVoicePtr == pVoice) { // move sustain pointer to the next sustained voice
270            return;                          dmsg(3,("Correcting sustain pointer\n"));
271          }                          pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->next();
272                            pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr = pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->current();
273          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                      }
274                        else dmsg(4,("ReleaseVoice(Voice*): *hSustain != pVoice\n"));
275          // remove the voice from the list associated to this MIDI key                  }
276          ActiveVoicePool->free(pVoicePtr);                  else dmsg(3,("ReleaseVoice(Voice*): pVoicePtr == null\n"));
277      }              }
278      else std::cerr << "Couldn't find active voice for note off command!" << std::endl << std::flush;              else dmsg(3,("ReleaseVoice(Voice*): hSustainPtr == null\n"));
279  }          }
   
 void AudioThread::ContinuousController(uint8_t Channel, uint8_t Number, uint8_t Value) {  
 //printf("AudioThread::ContinuousController c=%d n=%d v=%d\n",Channel, Number, Value);  
   if(Number == 64) {  
     if(Value >=64 && PrevHoldCCValue < 64) {  
       //printf("PEDAL DOWN\n");  
       SustainPedal=1;  
     }  
     if(Value < 64 && PrevHoldCCValue >=64) {  
       //printf("PEDAL UP\n");  
       SustainPedal=0;  
       sustained_key_t *key;  
       for(key = SustainedKeyPool->first(); key ; key=SustainedKeyPool->next() ) {  
         ReleaseVoice(key->midikey, key->velocity);  
       }  
       // empty the SustainedKeyPool (free all the elements)  
       SustainedKeyPool->empty();  
280    
281                  // remove the voice from the list associated with this MIDI key
282      }          ActiveVoicePool->free(pVoice->pSelfPtr);
     PrevHoldCCValue=Value;  
   }  
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 release voice! (pVoice == NULL)\n" << std::flush;
296  }  }
297    
298    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));
300        if (Number == 64) {
301            if (Value >= 64 && PrevHoldCCValue < 64) {
302                dmsg(4,("PEDAL DOWN\n"));
303                SustainPedal = true;
304            }
305            if (Value < 64 && PrevHoldCCValue >= 64) {
306                dmsg(4,("PEDAL UP\n"));
307                SustainPedal = false;
308                // iterate through all keys that are currently sustained
309                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                }
321            }
322            PrevHoldCCValue = Value;
323        }
324    }
325    
326  void AudioThread::CacheInitialSamples(gig::Sample* pSample) {  void AudioThread::CacheInitialSamples(gig::Sample* pSample) {
327      if (!pSample || pSample->GetCache().Size) return;      if (!pSample || pSample->GetCache().Size) return;
# Line 250  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(("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
338          pSample->LoadSampleData(NUM_RAM_PRELOAD_SAMPLES);          pSample->LoadSampleData(NUM_RAM_PRELOAD_SAMPLES);

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

  ViewVC Help
Powered by ViewVC