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

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

  ViewVC Help
Powered by ViewVC