/[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 31 by schoenebeck, Sun Jan 18 20:31:31 2004 UTC revision 32 by schoenebeck, Tue Feb 3 13:21:19 2004 UTC
# Line 23  Line 23 
23  #include "audiothread.h"  #include "audiothread.h"
24    
25  AudioThread::AudioThread(AudioIO* pAudioIO, DiskThread* pDiskThread, gig::Instrument* pInstrument) {  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;
29      pCommandQueue     = new RingBuffer<command_t>(1024);      this->Pitch        = 0;
30      pVoices           = new Voice*[MAX_AUDIO_VOICES];      Voice::pDiskThread = pDiskThread;
31      // allocate the ActiveVoicePool (for each midi key there is a variable size linked list      Voice::pEngine     = this;
32      // of pointers to Voice objects)      pEventQueue        = new RingBuffer<ModulationSystem::Event>(MAX_EVENTS_PER_FRAGMENT);
33      ActiveVoicePool = new RTELMemoryPool<Voice*>(MAX_AUDIO_VOICES);      pEventPool         = new RTELMemoryPool<ModulationSystem::Event>(MAX_EVENTS_PER_FRAGMENT);
34      for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {      pVoicePool         = new RTELMemoryPool<Voice>(MAX_AUDIO_VOICES);
35          pVoices[i] = new Voice(pDiskThread);      pSustainedKeyPool  = new RTELMemoryPool<uint>(128);
36        pEvents            = new RTEList<ModulationSystem::Event>(pEventPool);
37        for (uint i = 0; i < ModulationSystem::destination_count; i++) {
38            pCCEvents[i] = new RTEList<ModulationSystem::Event>(pEventPool);
39      }      }
40      for (uint i = 0; i < 128; i++) {      for (uint i = 0; i < 128; i++) {
41          pMIDIKeyInfo[i].pActiveVoices    = new RTEList<Voice*>;          pMIDIKeyInfo[i].pActiveVoices    = new RTEList<Voice>(pVoicePool);
42          pMIDIKeyInfo[i].hSustainPtr      = NULL;          pMIDIKeyInfo[i].pSustainPtr      = NULL;
43          pMIDIKeyInfo[i].Sustained        = false;          pMIDIKeyInfo[i].Sustained        = false;
44          pMIDIKeyInfo[i].KeyPressed       = false;          pMIDIKeyInfo[i].KeyPressed       = false;
45          pMIDIKeyInfo[i].pSustainPoolNode = NULL;          pMIDIKeyInfo[i].pSustainPoolNode = NULL;
46      }      }
     SustainedKeyPool = new RTELMemoryPool<uint>(128);  
47    
48      // FIXME: assuming stereo output      // FIXME: assuming stereo output
49      pAudioSumBuffer[0] = new float[pAudioIO->MaxSamplesPerCycle() * pAudioIO->Channels()];      pAudioSumBuffer[0] = new float[pAudioIO->MaxSamplesPerCycle() * pAudioIO->Channels()];
50      pAudioSumBuffer[1] = &pAudioSumBuffer[0][pAudioIO->MaxSamplesPerCycle()];      pAudioSumBuffer[1] = &pAudioSumBuffer[0][pAudioIO->MaxSamplesPerCycle()];
51    
52      // set all voice outputs to the AudioSumBuffer      // set all voice outputs to the AudioSumBuffer
53      for (int i = 0; i < MAX_AUDIO_VOICES; i++) { //FIXME: assuming stereo      for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) { //FIXME: assuming stereo
54          pVoices[i]->SetOutputLeft(pAudioSumBuffer[0],  pAudioIO->MaxSamplesPerCycle());          pVoice->SetOutputLeft(pAudioSumBuffer[0],  pAudioIO->MaxSamplesPerCycle());
55          pVoices[i]->SetOutputRight(pAudioSumBuffer[1], pAudioIO->MaxSamplesPerCycle());          pVoice->SetOutputRight(pAudioSumBuffer[1], pAudioIO->MaxSamplesPerCycle());
56      }      }
57        pVoicePool->clear();
58    
59      // cache initial samples points (for actually needed samples)      // cache initial samples points (for actually needed samples)
60      dmsg(1,("Caching initial samples..."));      dmsg(1,("Caching initial samples..."));
# Line 80  AudioThread::AudioThread(AudioIO* pAudio Line 83  AudioThread::AudioThread(AudioIO* pAudio
83    
84  AudioThread::~AudioThread() {  AudioThread::~AudioThread() {
85      ModulationSystem::Close();      ModulationSystem::Close();
86      if (pCommandQueue) delete pCommandQueue;      for (uint i = 0; i < 128; i++) {
87      if (pVoices) {          if (pMIDIKeyInfo[i].pActiveVoices) delete pMIDIKeyInfo[i].pActiveVoices;
88          for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {      }
89              if (pVoices[i]) delete pVoices[i];      for (uint i = 0; i < ModulationSystem::destination_count; i++) {
90          }          if (pCCEvents[i]) delete pCCEvents[i];
91      }      }
92      delete[] pVoices;      delete[] pCCEvents;
93        if (pEvents)           delete pEvents;
94        if (pEventQueue)       delete pEventQueue;
95        if (pEventPool)        delete pEventPool;
96        if (pVoicePool)        delete pVoicePool;
97        if (pSustainedKeyPool) delete pSustainedKeyPool;
98      delete[] pAudioSumBuffer[0]; // this also frees the right channel buffer      delete[] pAudioSumBuffer[0]; // this also frees the right channel buffer
99  }  }
100    
101    /**
102     *  Let this engine proceed to render the given amount of sample points. The
103     *  calculated audio data of all voices of this engine will be placed into
104     *  the engine's audio sum buffer which has to be copied and eventually be
105     *  converted to the appropriate value range by the audio output class (e.g.
106     *  AlsaIO or JackIO) right after.
107     *
108     *  @param Samples - number of sample points to be rendered
109     *  @returns       0 on success
110     */
111  int AudioThread::RenderAudio(uint Samples) {  int AudioThread::RenderAudio(uint Samples) {
112    
113      // read and process commands from the queue      // empty the event lists for the new fragment
114        pEvents->clear();
115        for (uint i = 0; i < ModulationSystem::destination_count; i++) {
116            pCCEvents[i]->clear();
117        }
118    
119        // read and copy events from input queue
120        ModulationSystem::Event Event;
121      while (true) {      while (true) {
122          command_t command;          if (!pEventQueue->pop(&Event)) break;
123          if (!pCommandQueue->pop(&command)) break;          pEvents->alloc_assign(Event);
124        }
125    
126    
127        // update time of start and end of this audio fragment (as events' time stamps relate to this)
128        ModulationSystem::UpdateFragmentTime();
129    
130    
131          switch (command.type) {      // process events
132              case command_type_note_on:      ModulationSystem::Event* pNextEvent = pEvents->first();
133        while (pNextEvent) {
134            ModulationSystem::Event* pEvent = pNextEvent;
135            pEvents->set_current(pEvent);
136            pNextEvent = pEvents->next();
137            switch (pEvent->Type) {
138                case ModulationSystem::event_type_note_on:
139                  dmsg(5,("Audio Thread: Note on received\n"));                  dmsg(5,("Audio Thread: Note on received\n"));
140                  ProcessNoteOn(command.pitch, command.velocity);                  ProcessNoteOn(pEvent);
141                  break;                  break;
142              case command_type_note_off:              case ModulationSystem::event_type_note_off:
143                  dmsg(5,("Audio Thread: Note off received\n"));                  dmsg(5,("Audio Thread: Note off received\n"));
144                  ProcessNoteOff(command.pitch, command.velocity);                  ProcessNoteOff(pEvent);
145                  break;                  break;
146              case command_type_continuous_controller:              case ModulationSystem::event_type_control_change:
147                  dmsg(5,("Audio Thread: MIDI CC received\n"));                  dmsg(5,("Audio Thread: MIDI CC received\n"));
148                  ProcessControlChange(command.channel, command.number, command.value);                  ProcessControlChange(pEvent);
149                    break;
150                case ModulationSystem::event_type_pitchbend:
151                    dmsg(5,("Audio Thread: Pitchbend received\n"));
152                    ProcessPitchbend(pEvent);
153                  break;                  break;
154          }          }
155      }      }
# Line 120  int AudioThread::RenderAudio(uint Sample Line 161  int AudioThread::RenderAudio(uint Sample
161    
162      // render audio from all active voices      // render audio from all active voices
163      int active_voices = 0;      int active_voices = 0;
164      for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {      for (uint i = 0; i < 128; i++) {
165          if (pVoices[i]->IsActive()) {          midi_key_info_t* pKey = &pMIDIKeyInfo[i];
166              pVoices[i]->Render(Samples);          Voice* pVoiceNext = pKey->pActiveVoices->first();
167              if (pVoices[i]->IsActive()) active_voices++; // still active          while (pVoiceNext) {
168                // already get next voice on key
169                Voice* pVoice = pVoiceNext;
170                pKey->pActiveVoices->set_current(pVoice);
171                pVoiceNext = pKey->pActiveVoices->next();
172    
173                // now render current voice
174                pVoice->Render(Samples);
175                if (pVoice->IsActive()) active_voices++; // still active
176              else { // voice reached end, is now inactive              else { // voice reached end, is now inactive
177                  KillVoice(pVoices[i]); // remove voice from the list of active voices                  KillVoice(pVoice); // remove voice from the list of active voices
178              }              }
179          }          }
180      }      }
181    
182      // 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
183      // on the console for debugging purposes      // on the console for debugging purposes
184      ActiveVoiceCount = active_voices;      ActiveVoiceCount = active_voices;
# Line 138  int AudioThread::RenderAudio(uint Sample Line 188  int AudioThread::RenderAudio(uint Sample
188      return 0;      return 0;
189  }  }
190    
191  /// Will be called by the MIDIIn Thread to let the audio thread trigger a new voice.  /**
192  void AudioThread::SendNoteOn(uint8_t Pitch, uint8_t Velocity) {   *  Will be called by the MIDIIn Thread to let the audio thread trigger a new
193      command_t cmd;   *  voice for the given key.
194      cmd.type     = command_type_note_on;   *
195      cmd.pitch    = Pitch;   *  @param Key      - MIDI key number of the triggered key
196      cmd.velocity = Velocity;   *  @param Velocity - MIDI velocity value of the triggered key
197      if (this->pCommandQueue->write_space() > 0) this->pCommandQueue->push(&cmd);   */
198      else dmsg(1,("AudioThread: Command queue full!"));  void AudioThread::SendNoteOn(uint8_t Key, uint8_t Velocity) {
199  }      ModulationSystem::Event Event;
200        Event.Type       = ModulationSystem::event_type_note_on;
201  /// Will be called by the MIDIIn Thread to signal the audio thread to release voice(s).      Event.Key        = Key;
202  void AudioThread::SendNoteOff(uint8_t Pitch, uint8_t Velocity) {      Event.Velocity   = Velocity;
203      command_t cmd;      if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&Event);
204      cmd.type     = command_type_note_off;      else dmsg(1,("AudioThread: Input event queue full!"));
205      cmd.pitch    = Pitch;  }
206      cmd.velocity = Velocity;  
207      if (this->pCommandQueue->write_space() > 0) this->pCommandQueue->push(&cmd);  /**
208      else dmsg(1,("AudioThread: Command queue full!"));   *  Will be called by the MIDIIn Thread to signal the audio thread to release
209  }   *  voice(s) on the given key.
210     *
211  // Will be called by the MIDIIn Thread to signal the audio thread that a continuous controller value has changed.   *  @param Key      - MIDI key number of the released key
212  void AudioThread::SendControlChange(uint8_t Channel, uint8_t Number, uint8_t Value) {   *  @param Velocity - MIDI release velocity value of the released key
213      command_t cmd;   */
214      cmd.type     = command_type_continuous_controller;  void AudioThread::SendNoteOff(uint8_t Key, uint8_t Velocity) {
215      cmd.channel  = Channel;      ModulationSystem::Event Event;
216      cmd.number   = Number;      Event.Type       = ModulationSystem::event_type_note_off;
217      cmd.value    = Value;      Event.Key        = Key;
218      if (this->pCommandQueue->write_space() > 0) this->pCommandQueue->push(&cmd);      Event.Velocity   = Velocity;
219      else dmsg(1,("AudioThread: Command queue full!"));      if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&Event);
220        else dmsg(1,("AudioThread: Input event queue full!"));
221    }
222    
223    /**
224     *  Will be called by the MIDIIn Thread to signal the audio thread to change
225     *  the pitch value for all voices.
226     *
227     *  @param Pitch - MIDI pitch value (-8192 ... +8191)
228     */
229    void AudioThread::SendPitchbend(int Pitch) {
230        ModulationSystem::Event Event;
231        Event.Type  = ModulationSystem::event_type_pitchbend;
232        Event.Pitch = Pitch;
233        if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&Event);
234        else dmsg(1,("AudioThread: Input event queue full!"));
235    }
236    
237    /**
238     *  Will be called by the MIDIIn Thread to signal the audio thread that a
239     *  continuous controller value has changed.
240     *
241     *  @param Controller - MIDI controller number of the occured control change
242     *  @param Value      - value of the control change
243     */
244    void AudioThread::SendControlChange(uint8_t Controller, uint8_t Value) {
245        ModulationSystem::Event Event;
246        Event.Type       = ModulationSystem::event_type_control_change;
247        Event.Controller = Controller;
248        Event.Value      = Value;
249        if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&Event);
250        else dmsg(1,("AudioThread: Input event queue full!"));
251  }  }
252    
253  /**  /**
254   *  Assigns and triggers a new voice for the respective MIDI key.   *  Assigns and triggers a new voice for the respective MIDI key.
255     *
256     *  @param pNoteOnEvent - key, velocity and time stamp of the event
257   */   */
258  void AudioThread::ProcessNoteOn(uint8_t MIDIKey, uint8_t Velocity) {  void AudioThread::ProcessNoteOn(ModulationSystem::Event* pNoteOnEvent) {
259      pMIDIKeyInfo[MIDIKey].KeyPressed = true; // the MIDI key was currently pressed down      midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOnEvent->Key];
     for (int i = 0; i < MAX_AUDIO_VOICES; i++) {  
         if (pVoices[i]->IsActive()) continue; // search for a free voice  
260    
261        pKey->KeyPressed = true; // the MIDI key was now pressed down
262        Voice* pNewVoice = pKey->pActiveVoices->alloc(); // allocate a new voice for the key
263        if (pNewVoice) {
264          // launch the new voice          // launch the new voice
265          if (pVoices[i]->Trigger(MIDIKey, Velocity, this->pInstrument) < 0) {          if (pNewVoice->Trigger(pNoteOnEvent->Key, pNoteOnEvent->Velocity, this->Pitch, this->pInstrument, pNoteOnEvent->FragmentPos()) < 0) {
266              return; // failed to trigger the new voice              return; // failed to trigger the new voice
267          }          }
268    
         // add (append) a new voice to the corresponding MIDIKey active voices list  
         Voice** new_voice_ptr = ActiveVoicePool->alloc_append(pMIDIKeyInfo[MIDIKey].pActiveVoices);  
         *new_voice_ptr = pVoices[i];  
         pVoices[i]->pSelfPtr = new_voice_ptr; // FIXME: hack to allow fast deallocation  
   
269          // update key info          // update key info
270          if (!pMIDIKeyInfo[MIDIKey].hSustainPtr) {          if (!pKey->pSustainPtr) {
271              dmsg(4,("ActivateVoice(uint,uint): hSustainPtr == null, setting release pointer to the last voice on the key...\n"));              dmsg(4,("ProcessNoteOn(): pSustainPtr == null, setting release pointer to the last voice on the key...\n"));
272              pMIDIKeyInfo[MIDIKey].pActiveVoices->last();              pKey->pSustainPtr = pKey->pActiveVoices->last();
             pMIDIKeyInfo[MIDIKey].hSustainPtr = pMIDIKeyInfo[MIDIKey].pActiveVoices->current();  
273          }          }
         return;  
274      }      }
275      std::cerr << "No free voice!" << std::endl << std::flush;      else std::cerr << "No free voice!" << std::endl << std::flush;
276  }  }
277    
278  /**  /**
# Line 203  void AudioThread::ProcessNoteOn(uint8_t Line 280  void AudioThread::ProcessNoteOn(uint8_t
280   *  If sustain is pressed, the release of the note will be postponed until   *  If sustain is pressed, the release of the note will be postponed until
281   *  sustain pedal will be released or voice turned inactive by itself (e.g.   *  sustain pedal will be released or voice turned inactive by itself (e.g.
282   *  due to completion of sample playback).   *  due to completion of sample playback).
283     *
284     *  @param pNoteOffEvent - key, velocity and time stamp of the event
285   */   */
286  void AudioThread::ProcessNoteOff(uint8_t MIDIKey, uint8_t Velocity) {  void AudioThread::ProcessNoteOff(ModulationSystem::Event* pNoteOffEvent) {
287      pMIDIKeyInfo[MIDIKey].KeyPressed = false; // the MIDI key was currently released      midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOffEvent->Key];
288      midi_key_info_t* pmidikey = &pMIDIKeyInfo[MIDIKey];  
289        pKey->KeyPressed = false; // the MIDI key was now released
290      if (SustainPedal) { // if sustain pedal is pressed postpone the Note-Off      if (SustainPedal) { // if sustain pedal is pressed postpone the Note-Off
291          if (pmidikey->hSustainPtr) {          if (pKey->pSustainPtr) {
292              // stick the note-off information to the respective voice              // stick the note-off information to the respective voice
293              Voice** pVoiceToRelease = pmidikey->pActiveVoices->set_current(pmidikey->hSustainPtr);              Voice* pVoiceToRelease = pKey->pSustainPtr;
294              if (pVoiceToRelease) {              pVoiceToRelease->ReleaseVelocity = pNoteOffEvent->Velocity;
295                  (*pVoiceToRelease)->ReleaseVelocity = Velocity;  
296                  // now increment the sustain pointer              // now increment the sustain pointer
297                  pmidikey->pActiveVoices->next();              pKey->pActiveVoices->set_current(pVoiceToRelease);
298                  pmidikey->hSustainPtr = pmidikey->pActiveVoices->current();              pKey->pSustainPtr = pKey->pActiveVoices->next();
299                  // if the key was not sustained yet, add it's MIDI key number to the sustained key pool  
300                  if (!pmidikey->Sustained) {              // if the key was not marked as sustained yet, add it's MIDI key number to the sustained key pool
301                      uint* sustainedmidikey     = SustainedKeyPool->alloc();              if (!pKey->Sustained) {
302                      *sustainedmidikey          = MIDIKey;                  uint* puiSustainedKey  = pSustainedKeyPool->alloc();
303                      pmidikey->pSustainPoolNode = sustainedmidikey;                  *puiSustainedKey       = pNoteOffEvent->Key;
304                      pmidikey->Sustained        = true;                  pKey->pSustainPoolNode = puiSustainedKey;
305                  }                  pKey->Sustained        = true;
306              }              }
             else dmsg(3,("Ignoring NOTE OFF --> pVoiceToRelease == null!\n"));  
307          }          }
308          else dmsg(3,("Ignoring NOTE OFF, seems like more Note-Offs than Note-Ons or no free voices available?\n"));          else dmsg(3,("Ignoring NOTE OFF, seems like more Note-Offs than Note-Ons or no free voices available?\n"));
309      }      }
310      else {      else {
311          // release all active voices on the midi key          // release all active voices on the midi key
312          Voice** pVoicePtr = pmidikey->pActiveVoices->first();          Voice* pVoiceNext = pKey->pActiveVoices->first();
313          while (pVoicePtr) {          while (pVoiceNext) {
314              Voice** pVoicePtrNext = pMIDIKeyInfo[MIDIKey].pActiveVoices->next();              Voice* pVoiceToRelease = pVoiceNext;
315              (*pVoicePtr)->Release();              pKey->pActiveVoices->set_current(pVoiceToRelease);
316              pVoicePtr = pVoicePtrNext;              pVoiceNext = pKey->pActiveVoices->next();
317                pVoiceToRelease->Release(pNoteOffEvent->FragmentPos());
318          }          }
319      }      }
320  }  }
321    
322  /**  /**
323     *  Moves pitchbend event from the general (input) event list to the pitch
324     *  event list and converts absolute pitch value to delta pitch value.
325     *
326     *  @param pPitchbendEvent - absolute pitch value and time stamp of the event
327     */
328    void AudioThread::ProcessPitchbend(ModulationSystem::Event* pPitchbendEvent) {
329        int currentPitch        = pPitchbendEvent->Pitch;
330        pPitchbendEvent->Pitch -= this->Pitch;  // convert to delta
331        this->Pitch             = currentPitch; // store current absolute pitch value
332        pEvents->move(pPitchbendEvent, pCCEvents[ModulationSystem::destination_vco]);
333    }
334    
335    /**
336   *  Immediately kills the voice given with pVoice (no matter if sustain is   *  Immediately kills the voice given with pVoice (no matter if sustain is
337   *  pressed or not) and removes it from the MIDI key's list of active voice.   *  pressed or not) and removes it from the MIDI key's list of active voice.
338   *  This method will e.g. be called if a voice went inactive by itself. If   *  This method will e.g. be called if a voice went inactive by itself. If
339   *  sustain pedal is pressed the method takes care to free those sustain   *  sustain pedal is pressed the method takes care to free those sustain
340   *  informations of the voice.   *  informations of the voice.
341     *
342     *  @param pVoice - points to the voice to be killed
343   */   */
344  void AudioThread::KillVoice(Voice* pVoice) {  void AudioThread::KillVoice(Voice* pVoice) {
345      if (pVoice) {      if (pVoice) {
346          if (pVoice->IsActive()) pVoice->Kill();          if (pVoice->IsActive()) pVoice->Kill();
347    
348          if (pMIDIKeyInfo[pVoice->MIDIKey].Sustained) {          midi_key_info_t* pKey = &pMIDIKeyInfo[pVoice->MIDIKey];
349    
350            if (pKey->Sustained) {
351              // check if the sustain pointer has to be moved, now that we kill the voice              // check if the sustain pointer has to be moved, now that we kill the voice
352              RTEList<Voice*>::NodeHandle hSustainPtr = pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr;              if (pKey->pSustainPtr) {
353              if (hSustainPtr) {                  if (pKey->pSustainPtr == pVoice) {
354                  Voice** pVoicePtr = pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->set_current(hSustainPtr);                      // move sustain pointer to the next sustained voice
355                  if (pVoicePtr) {                      dmsg(3,("Correcting sustain pointer\n"));
356                      if (*pVoicePtr == pVoice) { // move sustain pointer to the next sustained voice                      pKey->pActiveVoices->set_current(pVoice);
357                          dmsg(3,("Correcting sustain pointer\n"));                      pKey->pSustainPtr = pKey->pActiveVoices->next();
                         pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->next();  
                         pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr = pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->current();  
                     }  
                     else dmsg(4,("ReleaseVoice(Voice*): *hSustain != pVoice\n"));  
358                  }                  }
359                  else dmsg(3,("ReleaseVoice(Voice*): pVoicePtr == null\n"));                  else dmsg(4,("KillVoice(Voice*): pSustainPtr != pVoice\n"));
360              }              }
361              else dmsg(3,("ReleaseVoice(Voice*): hSustainPtr == null\n"));              else dmsg(3,("KillVoice(Voice*): pSustainPtr == null\n"));
362          }          }
363    
364          // remove the voice from the list associated with this MIDI key          // free the voice object
365          ActiveVoicePool->free(pVoice->pSelfPtr);          pVoicePool->free(pVoice);
366    
367          // check if there are no voices left on the MIDI key and update the key info if so          // check if there are no voices left on the MIDI key and update the key info if so
368          if (pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->is_empty()) {          if (pKey->pActiveVoices->is_empty()) {
369              pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr = NULL;              pKey->pSustainPtr = NULL;
370              if (pMIDIKeyInfo[pVoice->MIDIKey].Sustained) {              if (pKey->Sustained) {
371                  SustainedKeyPool->free(pMIDIKeyInfo[pVoice->MIDIKey].pSustainPoolNode);                  pSustainedKeyPool->free(pKey->pSustainPoolNode);
372                  pMIDIKeyInfo[pVoice->MIDIKey].pSustainPoolNode = NULL;                  pKey->pSustainPoolNode = NULL;
373                  pMIDIKeyInfo[pVoice->MIDIKey].Sustained        = false;                  pKey->Sustained        = false;
374              }              }
375              dmsg(3,("Key has no more voices now\n"));              dmsg(3,("Key has no more voices now\n"));
376          }          }
# Line 285  void AudioThread::KillVoice(Voice* pVoic Line 378  void AudioThread::KillVoice(Voice* pVoic
378      else std::cerr << "Couldn't release voice! (pVoice == NULL)\n" << std::flush;      else std::cerr << "Couldn't release voice! (pVoice == NULL)\n" << std::flush;
379  }  }
380    
381  void AudioThread::ProcessControlChange(uint8_t Channel, uint8_t Number, uint8_t Value) {  /**
382      dmsg(4,("AudioThread::ContinuousController c=%d n=%d v=%d\n", Channel, Number, Value));   *  Reacts on supported control change commands (e.g. pitch bend wheel,
383      if (Number == 64) {   *  modulation wheel, aftertouch).
384          if (Value >= 64 && PrevHoldCCValue < 64) {   *
385              dmsg(4,("PEDAL DOWN\n"));   *  @param pControlChangeEvent - controller, value and time stamp of the event
386              SustainPedal = true;   */
387          }  void AudioThread::ProcessControlChange(ModulationSystem::Event* pControlChangeEvent) {
388          if (Value < 64 && PrevHoldCCValue >= 64) {      dmsg(4,("AudioThread::ContinuousController cc=%d v=%d\n", pControlChangeEvent->Controller, pControlChangeEvent->Value));
389              dmsg(4,("PEDAL UP\n"));  
390              SustainPedal = false;      switch (pControlChangeEvent->Controller) {
391              // iterate through all keys that are currently sustained          case 64: {
392              for (uint* key = SustainedKeyPool->first(); key; key = SustainedKeyPool->next()) {              if (pControlChangeEvent->Value >= 64 && PrevHoldCCValue < 64) {
393                  if (!pMIDIKeyInfo[*key].KeyPressed) { // release the voices on the key, if the key is not pressed anymore                  dmsg(4,("PEDAL DOWN\n"));
394                      // release all active voices on the midi key                  SustainPedal = true;
395                      Voice** pVoicePtr = pMIDIKeyInfo[*key].pActiveVoices->first();              }
396                      while (pVoicePtr) {              if (pControlChangeEvent->Value < 64 && PrevHoldCCValue >= 64) {
397                          Voice** pVoicePtrNext = pMIDIKeyInfo[*key].pActiveVoices->next();                  dmsg(4,("PEDAL UP\n"));
398                          dmsg(3,("Sustain CC: releasing voice on midi key %d\n", *key));                  SustainPedal = false;
399                          (*pVoicePtr)->Release();                  // iterate through all keys that are currently sustained
400                          pVoicePtr = pVoicePtrNext;                  for (uint* key = pSustainedKeyPool->first(); key; key = pSustainedKeyPool->next()) {
401                        if (!pMIDIKeyInfo[*key].KeyPressed) { // release the voices on the key, if the key is not pressed anymore
402                            // release all active voices on the midi key
403                            Voice* pNextVoice = pMIDIKeyInfo[*key].pActiveVoices->first();
404                            while (pNextVoice) {
405                                Voice* pVoiceToRelease = pNextVoice;
406                                pMIDIKeyInfo[*key].pActiveVoices->set_current(pVoiceToRelease);
407                                pNextVoice = pMIDIKeyInfo[*key].pActiveVoices->next();
408                                dmsg(3,("Sustain CC: releasing voice on midi key %d\n", *key));
409                                pVoiceToRelease->Release(pControlChangeEvent->FragmentPos());
410                            }
411                            pSustainedKeyPool->free(pMIDIKeyInfo[*key].pSustainPoolNode);
412                            pMIDIKeyInfo[*key].pSustainPoolNode = NULL;
413                            pMIDIKeyInfo[*key].Sustained        = false;
414                            pMIDIKeyInfo[*key].pSustainPtr      = NULL;
415                      }                      }
                     SustainedKeyPool->free(pMIDIKeyInfo[*key].pSustainPoolNode);  
                     pMIDIKeyInfo[*key].pSustainPoolNode = NULL;  
                     pMIDIKeyInfo[*key].Sustained        = false;  
                     pMIDIKeyInfo[*key].hSustainPtr      = NULL;  
416                  }                  }
417                    //SustainedKeyPool->empty();
418              }              }
419              //SustainedKeyPool->empty();              PrevHoldCCValue = pControlChangeEvent->Value;
420                break;
421          }          }
         PrevHoldCCValue = Value;  
422      }      }
423  }  }
424    
425    /**
426     *  Caches a certain size at the beginning of the given sample in RAM. If the
427     *  sample is very short, the whole sample will be loaded into RAM and thus
428     *  no disk streaming is needed for this sample. Caching an initial part of
429     *  samples is needed to compensate disk reading latency.
430     *
431     *  @param pSample - points to the sample to be cached
432     */
433  void AudioThread::CacheInitialSamples(gig::Sample* pSample) {  void AudioThread::CacheInitialSamples(gig::Sample* pSample) {
434      if (!pSample || pSample->GetCache().Size) return;      if (!pSample || pSample->GetCache().Size) return;
435      if (pSample->SamplesTotal <= NUM_RAM_PRELOAD_SAMPLES) {      if (pSample->SamplesTotal <= NUM_RAM_PRELOAD_SAMPLES) {

Legend:
Removed from v.31  
changed lines
  Added in v.32

  ViewVC Help
Powered by ViewVC