/[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 20 by schoenebeck, Thu Dec 25 00:02:45 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          }          }
110    
111    
112          // zero out the sum buffer          // zero out the output sum buffer
113          for (uint u = 0; u < pAudioIO->FragmentSize * pAudioIO->Channels; u++) {          memset(pAudioSumBuffer, 0, pAudioIO->FragmentSize * pAudioIO->Channels * sizeof(float));
             pAudioSumBuffer[u] = 0.0;  
         }  
114    
115    
116          // render audio from all active voices          // render audio from all active voices
117          int act_voices=0;          int active_voices = 0;
118          for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {          for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {
119              if (pVoices[i]->IsActive()) {              if (pVoices[i]->IsActive()) {
120                  pVoices[i]->RenderAudio();                  pVoices[i]->RenderAudio();
121                  act_voices++;                  if (pVoices[i]->IsActive()) active_voices++; // still active
122                    else { // voice reached end, is now inactive
123                        ReleaseVoice(pVoices[i]); // remove voice from the list of active voices
124                    }
125              }              }
126          }          }
127          // 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
128          // on the console for debugging purposes          // on the console for debugging purposes
129          ActiveVoiceCount=act_voices;          ActiveVoiceCount = active_voices;
130            if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;
131    
132    
133          // check clipping in the audio sum, convert to sample_type          // check clipping in the audio sum, convert to sample_type
134          // (from 32bit to 16bit sample) and copy to output buffer          // (from 32bit to 16bit sample) and copy to output buffer
135          float sample_point;          float sample_point;
136          for (uint u = 0; u < pAudioIO->FragmentSize * pAudioIO->Channels; u++) {          for (uint u = 0; u < pAudioIO->FragmentSize * pAudioIO->Channels; u++) {
137              sample_point = this->pAudioSumBuffer[u] / 4; // FIXME division by 4 just for testing purposes (to give a bit of head room when mixing multiple voices together)              sample_point = this->pAudioSumBuffer[u] * this->Volume;
138              if (sample_point < -32768.0) sample_point = -32768.0;              if (sample_point < -32768.0) sample_point = -32768.0;
139              if (sample_point > 32767.0)  sample_point = 32767.0;              if (sample_point > 32767.0)  sample_point = 32767.0;
140              this->pAudioIO->pOutputBuffer[u] = (sample_t) sample_point;              this->pAudioIO->pOutputBuffer[u] = (sample_t) sample_point;
# Line 142  int AudioThread::Main() { Line 144  int AudioThread::Main() {
144          // call audio driver to output sound          // call audio driver to output sound
145          int res = this->pAudioIO->Output();          int res = this->pAudioIO->Output();
146          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));  
           
147      }      }
148  }  }
149    
150  /// 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.
151  void AudioThread::ProcessNoteOn(uint8_t Pitch, uint8_t Velocity) {  void AudioThread::SendNoteOn(uint8_t Pitch, uint8_t Velocity) {
152      command_t cmd;      command_t cmd;
153      cmd.type     = command_type_note_on;      cmd.type     = command_type_note_on;
154      cmd.pitch    = Pitch;      cmd.pitch    = Pitch;
155      cmd.velocity = Velocity;      cmd.velocity = Velocity;
156      this->pCommandQueue->write(&cmd, 1);      if (this->pCommandQueue->write_space() > 0) this->pCommandQueue->push(&cmd);
157        else dmsg(1,("AudioThread: Command queue full!"));
158  }  }
159    
160  /// 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).
161  void AudioThread::ProcessNoteOff(uint8_t Pitch, uint8_t Velocity) {  void AudioThread::SendNoteOff(uint8_t Pitch, uint8_t Velocity) {
162      command_t cmd;      command_t cmd;
163      cmd.type     = command_type_note_off;      cmd.type     = command_type_note_off;
164      cmd.pitch    = Pitch;      cmd.pitch    = Pitch;
165      cmd.velocity = Velocity;      cmd.velocity = Velocity;
166      this->pCommandQueue->write(&cmd, 1);      if (this->pCommandQueue->write_space() > 0) this->pCommandQueue->push(&cmd);
167        else dmsg(1,("AudioThread: Command queue full!"));
168  }  }
169    
170  // 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.
171  void AudioThread::ProcessContinuousController(uint8_t Channel, uint8_t Number, uint8_t Value) {  void AudioThread::SendControlChange(uint8_t Channel, uint8_t Number, uint8_t Value) {
172      command_t cmd;      command_t cmd;
173      cmd.type     = command_type_continuous_controller;      cmd.type     = command_type_continuous_controller;
174      cmd.channel  = Channel;      cmd.channel  = Channel;
175      cmd.number   = Number;      cmd.number   = Number;
176      cmd.value    = Value;      cmd.value    = Value;
177      this->pCommandQueue->write(&cmd, 1);      if (this->pCommandQueue->write_space() > 0) this->pCommandQueue->push(&cmd);
178        else dmsg(1,("AudioThread: Command queue full!"));
179  }  }
180    
181    /**
182  void AudioThread::ActivateVoice(uint8_t MIDIKey, uint8_t Velocity) {   *  Assigns and triggers a new voice for the respective MIDI key.
183     */
184    void AudioThread::ProcessNoteOn(uint8_t MIDIKey, uint8_t Velocity) {
185        pMIDIKeyInfo[MIDIKey].KeyPressed = true; // the MIDI key was currently pressed down
186      for (int i = 0; i < MAX_AUDIO_VOICES; i++) {      for (int i = 0; i < MAX_AUDIO_VOICES; i++) {
187          if (pVoices[i]->IsActive()) continue;          if (pVoices[i]->IsActive()) continue; // search for a free voice
188          pVoices[i]->Trigger(MIDIKey, Velocity, this->pInstrument);  
189            // launch the new voice
190            if (pVoices[i]->Trigger(MIDIKey, Velocity, this->pInstrument) < 0) {
191                return; // failed to trigger the new voice
192            }
193    
194          // add (append) a new voice to the corresponding MIDIKey active voices list          // add (append) a new voice to the corresponding MIDIKey active voices list
195          Voice **new_voice_ptr=ActiveVoicePool->alloc_append(pActiveVoices[MIDIKey]);          Voice** new_voice_ptr = ActiveVoicePool->alloc_append(pMIDIKeyInfo[MIDIKey].pActiveVoices);
196          *new_voice_ptr=pVoices[i];          *new_voice_ptr = pVoices[i];
197            pVoices[i]->pSelfPtr = new_voice_ptr; // FIXME: hack to allow fast deallocation
198    
199            // update key info
200            if (!pMIDIKeyInfo[MIDIKey].hSustainPtr) {
201                dmsg(4,("ActivateVoice(uint,uint): hSustainPtr == null, setting release pointer to the last voice on the key...\n"));
202                pMIDIKeyInfo[MIDIKey].pActiveVoices->last();
203                pMIDIKeyInfo[MIDIKey].hSustainPtr = pMIDIKeyInfo[MIDIKey].pActiveVoices->current();
204            }
205          return;          return;
206      }      }
207      std::cerr << "No free voice!" << std::endl << std::flush;      std::cerr << "No free voice!" << std::endl << std::flush;
208  }  }
209    
210  void AudioThread::ReleaseVoice(uint8_t MIDIKey, uint8_t Velocity) {  /**
211     *  Releases the voices on the given key if sustain pedal is not pressed.
212     *  If sustain is pressed, the release of the note will be postponed until
213     *  sustain pedal will be released or voice turned inactive by itself (e.g.
214     *  due to completion of sample playback).
215     */
216    void AudioThread::ProcessNoteOff(uint8_t MIDIKey, uint8_t Velocity) {
217        pMIDIKeyInfo[MIDIKey].KeyPressed = false; // the MIDI key was currently released
218        midi_key_info_t* pmidikey = &pMIDIKeyInfo[MIDIKey];
219        if (SustainPedal) { // if sustain pedal is pressed postpone the Note-Off
220            if (pmidikey->hSustainPtr) {
221                // stick the note-off information to the respective voice
222                Voice** pVoiceToRelease = pmidikey->pActiveVoices->set_current(pmidikey->hSustainPtr);
223                if (pVoiceToRelease) {
224                    (*pVoiceToRelease)->ReleaseVelocity = Velocity;
225                    // now increment the sustain pointer
226                    pmidikey->pActiveVoices->next();
227                    pmidikey->hSustainPtr = pmidikey->pActiveVoices->current();
228                    // if the key was not sustained yet, add it's MIDI key number to the sustained key pool
229                    if (!pmidikey->Sustained) {
230                        uint* sustainedmidikey     = SustainedKeyPool->alloc();
231                        *sustainedmidikey          = MIDIKey;
232                        pmidikey->pSustainPoolNode = sustainedmidikey;
233                        pmidikey->Sustained        = true;
234                    }
235                }
236                else dmsg(3,("Ignoring NOTE OFF --> pVoiceToRelease == null!\n"));
237            }
238            else dmsg(3,("Ignoring NOTE OFF, seems like more Note-Offs than Note-Ons or no free voices available?\n"));
239        }
240        else {
241            // release all active voices on the midi key
242            Voice** pVoicePtr = pmidikey->pActiveVoices->first();
243            while (pVoicePtr) {
244                Voice** pVoicePtrNext = pMIDIKeyInfo[MIDIKey].pActiveVoices->next();
245                ReleaseVoice(*pVoicePtr);
246                pVoicePtr = pVoicePtrNext;
247            }
248        }
249    }
250    
251      // get the first voice in the list of active voices on the MIDI Key  /**
252      Voice** pVoicePtr = pActiveVoices[MIDIKey]->first();   *  Releases the voice given with pVoice (no matter if sustain is pressed or
253      Voice *pVoice=*pVoicePtr;   *  not). This method will e.g. be directly called if a voice went inactive
254         *  by itself. If sustain pedal is pressed the method takes care to free
255     *  those sustain informations of the voice.
256     */
257    void AudioThread::ReleaseVoice(Voice* pVoice) {
258      if (pVoice) {      if (pVoice) {
259            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
260    
261          // if sustain pedal is pressed postpone the Note-Off          if (pMIDIKeyInfo[pVoice->MIDIKey].Sustained) {
262          if(SustainPedal) {              // check if the sustain pointer has to be moved, now that we release the voice
263              // alloc an element in the SustainedKeyPool and add the current midikey to it              RTEList<Voice*>::NodeHandle hSustainPtr = pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr;
264              sustained_key_t *key=SustainedKeyPool->alloc();              if (hSustainPtr) {
265              if(key == NULL) { /* FIXME */ printf("ERROR: SustainedKeyPool FULL ! exiting\n"); exit(0); }                  Voice** pVoicePtr = pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->set_current(hSustainPtr);
266              key->midikey=MIDIKey;                  if (pVoicePtr) {
267              key->velocity=Velocity;                      if (*pVoicePtr == pVoice) { // move sustain pointer to the next sustained voice
268            return;                          dmsg(3,("Correcting sustain pointer\n"));
269          }                          pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->next();
270                            pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr = pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->current();
271          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                      }
272                        else dmsg(4,("ReleaseVoice(Voice*): *hSustain != pVoice\n"));
273          // remove the voice from the list associated to this MIDI key                  }
274          ActiveVoicePool->free(pVoicePtr);                  else dmsg(3,("ReleaseVoice(Voice*): pVoicePtr == null\n"));
275      }              }
276      else std::cerr << "Couldn't find active voice for note off command!" << std::endl << std::flush;              else dmsg(3,("ReleaseVoice(Voice*): hSustainPtr == null\n"));
277  }          }
   
 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();  
278    
279                  // remove the voice from the list associated with this MIDI key
280      }          ActiveVoicePool->free(pVoice->pSelfPtr);
     PrevHoldCCValue=Value;  
   }  
281    
282            // check if there are no voices left on the MIDI key and update the key info if so
283            if (pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->is_empty()) {
284                pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr = NULL;
285                if (pMIDIKeyInfo[pVoice->MIDIKey].Sustained) {
286                    SustainedKeyPool->free(pMIDIKeyInfo[pVoice->MIDIKey].pSustainPoolNode);
287                    pMIDIKeyInfo[pVoice->MIDIKey].pSustainPoolNode = NULL;
288                    pMIDIKeyInfo[pVoice->MIDIKey].Sustained        = false;
289                }
290                dmsg(3,("Key has no more voices now\n"));
291            }
292        }
293        else std::cerr << "Couldn't release voice! (pVoice == NULL)\n" << std::flush;
294  }  }
295    
296    void AudioThread::ProcessControlChange(uint8_t Channel, uint8_t Number, uint8_t Value) {
297        dmsg(4,("AudioThread::ContinuousController c=%d n=%d v=%d\n", Channel, Number, Value));
298        if (Number == 64) {
299            if (Value >= 64 && PrevHoldCCValue < 64) {
300                dmsg(4,("PEDAL DOWN\n"));
301                SustainPedal = true;
302            }
303            if (Value < 64 && PrevHoldCCValue >= 64) {
304                dmsg(4,("PEDAL UP\n"));
305                SustainPedal = false;
306                // iterate through all keys that are currently sustained
307                for (uint* key = SustainedKeyPool->first(); key; key = SustainedKeyPool->next()) {
308                    if (!pMIDIKeyInfo[*key].KeyPressed) { // release the voices on the key, if the key is not pressed anymore
309                        // release all active voices on the midi key
310                        Voice** pVoicePtr = pMIDIKeyInfo[*key].pActiveVoices->first();
311                        while (pVoicePtr) {
312                            Voice** pVoicePtrNext = pMIDIKeyInfo[*key].pActiveVoices->next();
313                            dmsg(3,("Sustain CC: releasing voice on midi key %d\n", *key));
314                            ReleaseVoice(*pVoicePtr);
315                            pVoicePtr = pVoicePtrNext;
316                        }
317                    }
318                }
319            }
320            PrevHoldCCValue = Value;
321        }
322    }
323    
324  void AudioThread::CacheInitialSamples(gig::Sample* pSample) {  void AudioThread::CacheInitialSamples(gig::Sample* pSample) {
325      if (!pSample || pSample->GetCache().Size) return;      if (!pSample || pSample->GetCache().Size) return;
# Line 250  void AudioThread::CacheInitialSamples(gi Line 329  void AudioThread::CacheInitialSamples(gi
329          // number of '0' samples (silence samples) behind the official buffer          // number of '0' samples (silence samples) behind the official buffer
330          // 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
331          // the sample.          // the sample.
332          gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(pAudioIO->FragmentSize << MAX_PITCH);          gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension((pAudioIO->FragmentSize << MAX_PITCH) + 3);
333          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));
334      }      }
335      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
336          pSample->LoadSampleData(NUM_RAM_PRELOAD_SAMPLES);          pSample->LoadSampleData(NUM_RAM_PRELOAD_SAMPLES);

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

  ViewVC Help
Powered by ViewVC