/[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 11 by senoner, Tue Nov 11 23:30:47 2003 UTC revision 12 by schoenebeck, Sun Nov 16 19:01:50 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 *>;          pActiveVoices[i] = new RTEList<Voice*>;
39      }      }
40        SustainedKeyPool = new RTELMemoryPool<sustained_key_t>(200);
     SustainedKeyPool=new RTELMemoryPool<sustained_key_t>(200);  
   
   
41    
42      pAudioSumBuffer = new float[pAudioIO->FragmentSize * pAudioIO->Channels];      pAudioSumBuffer = new float[pAudioIO->FragmentSize * pAudioIO->Channels];
43    
# Line 50  AudioThread::AudioThread(AudioIO* pAudio Line 47  AudioThread::AudioThread(AudioIO* pAudio
47      }      }
48    
49      // cache initial samples points (for actually needed samples)      // cache initial samples points (for actually needed samples)
50      dmsg(("Caching initial samples..."));      dmsg(1,("Caching initial samples..."));
51      gig::Region* pRgn = this->pInstrument->GetFirstRegion();      gig::Region* pRgn = this->pInstrument->GetFirstRegion();
52      while (pRgn) {      while (pRgn) {
53          if (!pRgn->GetSample()->GetCache().Size) {          if (!pRgn->GetSample()->GetCache().Size) {
54  //printf("C");              dmsg(2,("C"));
55              CacheInitialSamples(pRgn->GetSample());              CacheInitialSamples(pRgn->GetSample());
56          }          }
57          for (uint i = 0; i < pRgn->DimensionRegions; i++) {          for (uint i = 0; i < pRgn->DimensionRegions; i++) {
# Line 65  AudioThread::AudioThread(AudioIO* pAudio Line 62  AudioThread::AudioThread(AudioIO* pAudio
62      }      }
63    
64      // sustain pedal value      // sustain pedal value
65      PrevHoldCCValue=0;      PrevHoldCCValue = 0;
66      SustainPedal=0;      SustainPedal    = 0;
67    
68      dmsg(("OK\n"));      dmsg(1,("OK\n"));
69  }  }
70    
71  AudioThread::~AudioThread() {  AudioThread::~AudioThread() {
# Line 82  AudioThread::~AudioThread() { Line 79  AudioThread::~AudioThread() {
79  }  }
80    
81  int AudioThread::Main() {  int AudioThread::Main() {
82      dmsg(("Audio thread running\n"));      dmsg(2,("Audio thread running\n"));
     //int fifofd=open("/tmp/fifo1",O_WRONLY);  
83    
84      while (true) {      while (true) {
85    
# Line 94  int AudioThread::Main() { Line 90  int AudioThread::Main() {
90    
91              switch (command.type) {              switch (command.type) {
92                  case command_type_note_on:                  case command_type_note_on:
93                      dmsg(("Audio Thread: Note on received\n"));                      dmsg(5,("Audio Thread: Note on received\n"));
94                      ActivateVoice(command.pitch, command.velocity);                      ActivateVoice(command.pitch, command.velocity);
95                      break;                      break;
96                  case command_type_note_off:                  case command_type_note_off:
97                      dmsg(("Audio Thread: Note off received\n"));                      dmsg(5,("Audio Thread: Note off received\n"));
98                      ReleaseVoice(command.pitch, command.velocity);                      ReleaseVoice(command.pitch, command.velocity);
99                      break;                      break;
100                  case command_type_continuous_controller:                  case command_type_continuous_controller:
101                      dmsg(("Audio Thread: MIDI CC received\n"));                      dmsg(5,("Audio Thread: MIDI CC received\n"));
102                      ContinuousController(command.channel, command.number, command.value);                      ContinuousController(command.channel, command.number, command.value);
103                      break;                      break;
104              }              }
# Line 116  int AudioThread::Main() { Line 112  int AudioThread::Main() {
112    
113    
114          // render audio from all active voices          // render audio from all active voices
115          int act_voices=0;          int active_voices = 0;
116          for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {          for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {
117              if (pVoices[i]->IsActive()) {              if (pVoices[i]->IsActive()) {
118                  pVoices[i]->RenderAudio();                  pVoices[i]->RenderAudio();
119                  act_voices++;                  if (pVoices[i]->IsActive()) active_voices++; // still active
120                    else { // voice reached end, is now inactive
121                        ReleaseVoice(pVoices[i]); // remove voice from the list of active voices
122                    }
123              }              }
124          }          }
125          // 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
126          // on the console for debugging purposes          // on the console for debugging purposes
127          ActiveVoiceCount=act_voices;          ActiveVoiceCount = active_voices;
128    
129    
130          // 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 141  int AudioThread::Main() {
141          // call audio driver to output sound          // call audio driver to output sound
142          int res = this->pAudioIO->Output();          int res = this->pAudioIO->Output();
143          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));  
           
144      }      }
145  }  }
146    
# Line 177  void AudioThread::ProcessContinuousContr Line 172  void AudioThread::ProcessContinuousContr
172      this->pCommandQueue->write(&cmd, 1);      this->pCommandQueue->write(&cmd, 1);
173  }  }
174    
   
175  void AudioThread::ActivateVoice(uint8_t MIDIKey, uint8_t Velocity) {  void AudioThread::ActivateVoice(uint8_t MIDIKey, uint8_t Velocity) {
176      for (int i = 0; i < MAX_AUDIO_VOICES; i++) {      for (int i = 0; i < MAX_AUDIO_VOICES; i++) {
177          if (pVoices[i]->IsActive()) continue;          if (pVoices[i]->IsActive()) continue;
178          pVoices[i]->Trigger(MIDIKey, Velocity, this->pInstrument);          pVoices[i]->Trigger(MIDIKey, Velocity, this->pInstrument);
179          // add (append) a new voice to the corresponding MIDIKey active voices list          // add (append) a new voice to the corresponding MIDIKey active voices list
180          Voice **new_voice_ptr=ActiveVoicePool->alloc_append(pActiveVoices[MIDIKey]);          Voice** new_voice_ptr = ActiveVoicePool->alloc_append(pActiveVoices[MIDIKey]);
181          *new_voice_ptr=pVoices[i];          *new_voice_ptr = pVoices[i];
182            pVoices[i]->pSelfPtr = new_voice_ptr; // FIXME: hack to allow fast deallocation
183          return;          return;
184      }      }
185      std::cerr << "No free voice!" << std::endl << std::flush;      std::cerr << "No free voice!" << std::endl << std::flush;
186  }  }
187    
188  void AudioThread::ReleaseVoice(uint8_t MIDIKey, uint8_t Velocity) {  void AudioThread::ReleaseVoice(uint8_t MIDIKey, uint8_t Velocity) {
189        // if sustain pedal is pressed postpone the Note-Off
190        if (SustainPedal) {
191            // alloc an element in the SustainedKeyPool and add the current midikey to it
192            sustained_key_t* key = SustainedKeyPool->alloc();
193            if (key == NULL) printf("ERROR: SustainedKeyPool FULL ! exiting\n"); // FIXME
194            key->midikey  = MIDIKey;
195            key->velocity = Velocity;
196        }
197        else {
198            // get the first voice in the list of active voices on the MIDI Key
199            Voice** pVoicePtr = pActiveVoices[MIDIKey]->first();
200            if (pVoicePtr) ReleaseVoice(*pVoicePtr);
201            else std::cerr << "Couldn't find active voice for note off command!" << std::endl << std::flush;
202        }
203    }
204    
205    void AudioThread::ReleaseVoice(Voice* pVoice) {
     // get the first voice in the list of active voices on the MIDI Key  
     Voice** pVoicePtr = pActiveVoices[MIDIKey]->first();  
     Voice *pVoice=*pVoicePtr;  
       
206      if (pVoice) {      if (pVoice) {
207            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 sustain pedal is pressed postpone the Note-Off  
         if(SustainPedal) {  
             // alloc an element in the SustainedKeyPool and add the current midikey to it  
             sustained_key_t *key=SustainedKeyPool->alloc();  
             if(key == NULL) { /* FIXME */ printf("ERROR: SustainedKeyPool FULL ! exiting\n"); exit(0); }  
             key->midikey=MIDIKey;  
             key->velocity=Velocity;  
           return;  
         }  
   
         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  
208    
209          // remove the voice from the list associated to this MIDI key          // remove the voice from the list associated to this MIDI key
210          ActiveVoicePool->free(pVoicePtr);          ActiveVoicePool->free(pVoice->pSelfPtr);
211      }      }
212      else std::cerr << "Couldn't find active voice for note off command!" << std::endl << std::flush;      else std::cerr << "Couldn't find active voice to release!" << std::endl << std::flush;
213  }  }
214    
215  void AudioThread::ContinuousController(uint8_t Channel, uint8_t Number, uint8_t Value) {  void AudioThread::ContinuousController(uint8_t Channel, uint8_t Number, uint8_t Value) {
216  //printf("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));
217    if(Number == 64) {      if (Number == 64) {
218      if(Value >=64 && PrevHoldCCValue < 64) {          if (Value >= 64 && PrevHoldCCValue < 64) {
219        //printf("PEDAL DOWN\n");              dmsg(4,("PEDAL DOWN\n"));
220        SustainPedal=1;              SustainPedal = true;
221      }          }
222      if(Value < 64 && PrevHoldCCValue >=64) {          if (Value < 64 && PrevHoldCCValue >= 64) {
223        //printf("PEDAL UP\n");              dmsg(4,("PEDAL UP\n"));
224        SustainPedal=0;              SustainPedal = false;
225        sustained_key_t *key;              for (sustained_key_t* key = SustainedKeyPool->first(); key; key = SustainedKeyPool->next()) {
226        for(key = SustainedKeyPool->first(); key ; key=SustainedKeyPool->next() ) {                  ReleaseVoice(key->midikey, key->velocity);
227          ReleaseVoice(key->midikey, key->velocity);              }
228        }              // empty the SustainedKeyPool (free all the elements)
229        // empty the SustainedKeyPool (free all the elements)              SustainedKeyPool->empty();
230        SustainedKeyPool->empty();          }
231            PrevHoldCCValue = Value;
         
232      }      }
     PrevHoldCCValue=Value;  
   }  
   
233  }  }
234    
   
235  void AudioThread::CacheInitialSamples(gig::Sample* pSample) {  void AudioThread::CacheInitialSamples(gig::Sample* pSample) {
236      if (!pSample || pSample->GetCache().Size) return;      if (!pSample || pSample->GetCache().Size) return;
237      if (pSample->SamplesTotal <= NUM_RAM_PRELOAD_SAMPLES) {      if (pSample->SamplesTotal <= NUM_RAM_PRELOAD_SAMPLES) {
# Line 251  void AudioThread::CacheInitialSamples(gi Line 241  void AudioThread::CacheInitialSamples(gi
241          // 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
242          // the sample.          // the sample.
243          gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(pAudioIO->FragmentSize << MAX_PITCH);          gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(pAudioIO->FragmentSize << MAX_PITCH);
244          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));
245      }      }
246      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
247          pSample->LoadSampleData(NUM_RAM_PRELOAD_SAMPLES);          pSample->LoadSampleData(NUM_RAM_PRELOAD_SAMPLES);

Legend:
Removed from v.11  
changed lines
  Added in v.12

  ViewVC Help
Powered by ViewVC