/[svn]/linuxsampler/tags/v0_1_0/src/audiothread.cpp
ViewVC logotype

Diff of /linuxsampler/tags/v0_1_0/src/audiothread.cpp

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

revision 18 by schoenebeck, Sun Dec 7 05:03:43 2003 UTC revision 31 by schoenebeck, Sun Jan 18 20:31:31 2004 UTC
# Line 22  Line 22 
22    
23  #include "audiothread.h"  #include "audiothread.h"
24    
25  AudioThread::AudioThread(AudioIO* pAudioIO, DiskThread* pDiskThread, gig::Instrument* pInstrument) : Thread(true, 1, 0) {  AudioThread::AudioThread(AudioIO* pAudioIO, DiskThread* pDiskThread, gig::Instrument* pInstrument) {
26      this->pAudioIO    = pAudioIO;      this->pAudioIO    = pAudioIO;
27      this->pDiskThread = pDiskThread;      this->pDiskThread = pDiskThread;
28      this->pInstrument = pInstrument;      this->pInstrument = pInstrument;
# Line 43  AudioThread::AudioThread(AudioIO* pAudio Line 43  AudioThread::AudioThread(AudioIO* pAudio
43      }      }
44      SustainedKeyPool = new RTELMemoryPool<uint>(128);      SustainedKeyPool = new RTELMemoryPool<uint>(128);
45    
46      pAudioSumBuffer = new float[pAudioIO->FragmentSize * pAudioIO->Channels];      // FIXME: assuming stereo output
47        pAudioSumBuffer[0] = new float[pAudioIO->MaxSamplesPerCycle() * pAudioIO->Channels()];
48        pAudioSumBuffer[1] = &pAudioSumBuffer[0][pAudioIO->MaxSamplesPerCycle()];
49    
50      // set all voice outputs to the AudioSumBuffer      // set all voice outputs to the AudioSumBuffer
51      for (int i = 0; i < MAX_AUDIO_VOICES; i++) {      for (int i = 0; i < MAX_AUDIO_VOICES; i++) { //FIXME: assuming stereo
52          pVoices[i]->SetOutput(pAudioSumBuffer, pAudioIO->FragmentSize * 2);  //FIXME: assuming stereo          pVoices[i]->SetOutputLeft(pAudioSumBuffer[0],  pAudioIO->MaxSamplesPerCycle());
53            pVoices[i]->SetOutputRight(pAudioSumBuffer[1], pAudioIO->MaxSamplesPerCycle());
54      }      }
55    
56      // cache initial samples points (for actually needed samples)      // cache initial samples points (for actually needed samples)
# Line 65  AudioThread::AudioThread(AudioIO* pAudio Line 68  AudioThread::AudioThread(AudioIO* pAudio
68          pRgn = this->pInstrument->GetNextRegion();          pRgn = this->pInstrument->GetNextRegion();
69      }      }
70    
71        // initialize modulation system
72        ModulationSystem::Initialize(pAudioIO->SampleRate(), pAudioIO->MaxSamplesPerCycle());
73    
74      // sustain pedal value      // sustain pedal value
75      PrevHoldCCValue = 0;      PrevHoldCCValue = 0;
76      SustainPedal    = 0;      SustainPedal    = 0;
# Line 73  AudioThread::AudioThread(AudioIO* pAudio Line 79  AudioThread::AudioThread(AudioIO* pAudio
79  }  }
80    
81  AudioThread::~AudioThread() {  AudioThread::~AudioThread() {
82        ModulationSystem::Close();
83      if (pCommandQueue) delete pCommandQueue;      if (pCommandQueue) delete pCommandQueue;
84      if (pVoices) {      if (pVoices) {
85          for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {          for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {
# Line 80  AudioThread::~AudioThread() { Line 87  AudioThread::~AudioThread() {
87          }          }
88      }      }
89      delete[] pVoices;      delete[] pVoices;
90        delete[] pAudioSumBuffer[0]; // this also frees the right channel buffer
91  }  }
92    
93  int AudioThread::Main() {  int AudioThread::RenderAudio(uint Samples) {
     dmsg(2,("Audio thread running\n"));  
94    
95        // read and process commands from the queue
96      while (true) {      while (true) {
97            command_t command;
98            if (!pCommandQueue->pop(&command)) break;
99    
100          // read and process commands from the queue          switch (command.type) {
101          while (true) {              case command_type_note_on:
102              command_t command;                  dmsg(5,("Audio Thread: Note on received\n"));
103              if (!pCommandQueue->pop(&command)) break;                  ProcessNoteOn(command.pitch, command.velocity);
104                    break;
105              switch (command.type) {              case command_type_note_off:
106                  case command_type_note_on:                  dmsg(5,("Audio Thread: Note off received\n"));
107                      dmsg(5,("Audio Thread: Note on received\n"));                  ProcessNoteOff(command.pitch, command.velocity);
108                      ProcessNoteOn(command.pitch, command.velocity);                  break;
109                      break;              case command_type_continuous_controller:
110                  case command_type_note_off:                  dmsg(5,("Audio Thread: MIDI CC received\n"));
111                      dmsg(5,("Audio Thread: Note off received\n"));                  ProcessControlChange(command.channel, command.number, command.value);
112                      ProcessNoteOff(command.pitch, command.velocity);                  break;
                     break;  
                 case command_type_continuous_controller:  
                     dmsg(5,("Audio Thread: MIDI CC received\n"));  
                     ProcessControlChange(command.channel, command.number, command.value);  
                     break;  
             }  
113          }          }
114        }
115    
116    
117          // zero out the sum buffer      // zero out the output sum buffer (left and right channel)
118          for (uint u = 0; u < pAudioIO->FragmentSize * pAudioIO->Channels; u++) {      memset(pAudioSumBuffer[0], 0, Samples * pAudioIO->Channels() * sizeof(float));
             pAudioSumBuffer[u] = 0.0;  
         }  
119    
120    
121          // render audio from all active voices      // render audio from all active voices
122          int active_voices = 0;      int active_voices = 0;
123          for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {      for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {
124              if (pVoices[i]->IsActive()) {          if (pVoices[i]->IsActive()) {
125                  pVoices[i]->RenderAudio();              pVoices[i]->Render(Samples);
126                  if (pVoices[i]->IsActive()) active_voices++; // still active              if (pVoices[i]->IsActive()) active_voices++; // still active
127                  else { // voice reached end, is now inactive              else { // voice reached end, is now inactive
128                      ReleaseVoice(pVoices[i]); // remove voice from the list of active voices                  KillVoice(pVoices[i]); // remove voice from the list of active voices
                 }  
129              }              }
130          }          }
131          // write that to the disk thread class so that it can print it      }
132          // on the console for debugging purposes      // write that to the disk thread class so that it can print it
133          ActiveVoiceCount = active_voices;      // on the console for debugging purposes
134          if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;      ActiveVoiceCount = active_voices;
135        if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;
   
         // check clipping in the audio sum, convert to sample_type  
         // (from 32bit to 16bit sample) and copy to output buffer  
         float sample_point;  
         for (uint u = 0; u < pAudioIO->FragmentSize * pAudioIO->Channels; u++) {  
             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)  
             if (sample_point < -32768.0) sample_point = -32768.0;  
             if (sample_point > 32767.0)  sample_point = 32767.0;  
             this->pAudioIO->pOutputBuffer[u] = (sample_t) sample_point;  
         }  
136    
137    
138          // call audio driver to output sound      return 0;
         int res = this->pAudioIO->Output();  
         if (res < 0) exit(EXIT_FAILURE);  
     }  
139  }  }
140    
141  /// 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.
# Line 244  void AudioThread::ProcessNoteOff(uint8_t Line 233  void AudioThread::ProcessNoteOff(uint8_t
233          Voice** pVoicePtr = pmidikey->pActiveVoices->first();          Voice** pVoicePtr = pmidikey->pActiveVoices->first();
234          while (pVoicePtr) {          while (pVoicePtr) {
235              Voice** pVoicePtrNext = pMIDIKeyInfo[MIDIKey].pActiveVoices->next();              Voice** pVoicePtrNext = pMIDIKeyInfo[MIDIKey].pActiveVoices->next();
236              ReleaseVoice(*pVoicePtr);              (*pVoicePtr)->Release();
237              pVoicePtr = pVoicePtrNext;              pVoicePtr = pVoicePtrNext;
238          }          }
239      }      }
240  }  }
241    
242  /**  /**
243   *  Releases the voice given with pVoice (no matter if sustain is pressed or   *  Immediately kills the voice given with pVoice (no matter if sustain is
244   *  not). This method will e.g. be directly called if a voice went inactive   *  pressed or not) and removes it from the MIDI key's list of active voice.
245   *  by itself. If sustain pedal is pressed the method takes care to free   *  This method will e.g. be called if a voice went inactive by itself. If
246   *  those sustain informations of the voice.   *  sustain pedal is pressed the method takes care to free those sustain
247     *  informations of the voice.
248   */   */
249  void AudioThread::ReleaseVoice(Voice* pVoice) {  void AudioThread::KillVoice(Voice* pVoice) {
250      if (pVoice) {      if (pVoice) {
251          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();
252    
253          if (pMIDIKeyInfo[pVoice->MIDIKey].Sustained) {          if (pMIDIKeyInfo[pVoice->MIDIKey].Sustained) {
254              // 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 kill the voice
255              RTEList<Voice*>::NodeHandle hSustainPtr = pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr;              RTEList<Voice*>::NodeHandle hSustainPtr = pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr;
256              if (hSustainPtr) {              if (hSustainPtr) {
257                  Voice** pVoicePtr = pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->set_current(hSustainPtr);                  Voice** pVoicePtr = pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->set_current(hSustainPtr);
# Line 313  void AudioThread::ProcessControlChange(u Line 303  void AudioThread::ProcessControlChange(u
303                      while (pVoicePtr) {                      while (pVoicePtr) {
304                          Voice** pVoicePtrNext = pMIDIKeyInfo[*key].pActiveVoices->next();                          Voice** pVoicePtrNext = pMIDIKeyInfo[*key].pActiveVoices->next();
305                          dmsg(3,("Sustain CC: releasing voice on midi key %d\n", *key));                          dmsg(3,("Sustain CC: releasing voice on midi key %d\n", *key));
306                          ReleaseVoice(*pVoicePtr);                          (*pVoicePtr)->Release();
307                          pVoicePtr = pVoicePtrNext;                          pVoicePtr = pVoicePtrNext;
308                      }                      }
309                        SustainedKeyPool->free(pMIDIKeyInfo[*key].pSustainPoolNode);
310                        pMIDIKeyInfo[*key].pSustainPoolNode = NULL;
311                        pMIDIKeyInfo[*key].Sustained        = false;
312                        pMIDIKeyInfo[*key].hSustainPtr      = NULL;
313                  }                  }
314              }              }
315                //SustainedKeyPool->empty();
316          }          }
317          PrevHoldCCValue = Value;          PrevHoldCCValue = Value;
318      }      }
# Line 331  void AudioThread::CacheInitialSamples(gi Line 326  void AudioThread::CacheInitialSamples(gi
326          // number of '0' samples (silence samples) behind the official buffer          // number of '0' samples (silence samples) behind the official buffer
327          // 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
328          // the sample.          // the sample.
329          gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension((pAudioIO->FragmentSize << MAX_PITCH) + 3);          gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension((pAudioIO->MaxSamplesPerCycle() << MAX_PITCH) + 3);
330          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));
331      }      }
332      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.18  
changed lines
  Added in v.31

  ViewVC Help
Powered by ViewVC