--- linuxsampler/trunk/src/engines/gig/Engine.cpp 2004/10/14 21:31:26 285 +++ linuxsampler/trunk/src/engines/gig/Engine.cpp 2004/12/28 09:43:04 329 @@ -26,6 +26,7 @@ #include "EGADSR.h" #include "Engine.h" +#include namespace LinuxSampler { namespace gig { @@ -76,8 +77,10 @@ Engine::~Engine() { if (pDiskThread) { + dmsg(1,("Stopping disk thread...")); pDiskThread->StopThread(); delete pDiskThread; + dmsg(1,("OK\n")); } if (pGig) delete pGig; if (pRIFF) delete pRIFF; @@ -88,18 +91,20 @@ for (uint i = 0; i < Event::destination_count; i++) { if (pSynthesisEvents[i]) delete pSynthesisEvents[i]; } - delete[] pSynthesisEvents; if (pEvents) delete pEvents; if (pCCEvents) delete pCCEvents; if (pEventQueue) delete pEventQueue; if (pEventPool) delete pEventPool; - if (pVoicePool) delete pVoicePool; + if (pVoicePool) { + pVoicePool->clear(); + delete pVoicePool; + } if (pActiveKeys) delete pActiveKeys; if (pSysexBuffer) delete pSysexBuffer; if (pEventGenerator) delete pEventGenerator; if (pMainFilterParameters) delete[] pMainFilterParameters; if (pBasicFilterParameters) delete[] pBasicFilterParameters; - if (pSynthesisParameters[0]) delete[] pSynthesisParameters[0]; + if (pSynthesisParameters[0]) free(pSynthesisParameters[0]); if (pVoiceStealingQueue) delete pVoiceStealingQueue; } @@ -321,8 +326,10 @@ // (re)create disk thread if (this->pDiskThread) { + dmsg(1,("Stopping disk thread...")); this->pDiskThread->StopThread(); delete this->pDiskThread; + dmsg(1,("OK\n")); } this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << MAX_PITCH) << 1) + 6); //FIXME: assuming stereo if (!pDiskThread) { @@ -341,8 +348,8 @@ pEventGenerator = new EventGenerator(pAudioOut->SampleRate()); // (re)allocate synthesis parameter matrix - if (pSynthesisParameters[0]) delete[] pSynthesisParameters[0]; - pSynthesisParameters[0] = new float[Event::destination_count * pAudioOut->MaxSamplesPerCycle()]; + if (pSynthesisParameters[0]) free(pSynthesisParameters[0]); + pSynthesisParameters[0] = (float *) memalign(16,(Event::destination_count * sizeof(float) * pAudioOut->MaxSamplesPerCycle())); for (int dst = 1; dst < Event::destination_count; dst++) pSynthesisParameters[dst] = pSynthesisParameters[dst - 1] + pAudioOut->MaxSamplesPerCycle(); @@ -398,6 +405,10 @@ } + // update time of start and end of this audio fragment (as events' time stamps relate to this) + pEventGenerator->UpdateFragmentTime(Samples); + + // empty the event lists for the new fragment pEvents->clear(); pCCEvents->clear(); @@ -412,16 +423,30 @@ } } - // read and copy events from input queue - Event event = pEventGenerator->CreateEvent(); - while (true) { - if (!pEventQueue->pop(&event) || pEvents->poolIsEmpty()) break; - *pEvents->allocAppend() = event; - } - - // update time of start and end of this audio fragment (as events' time stamps relate to this) - pEventGenerator->UpdateFragmentTime(Samples); + // get all events from the input event queue which belong to the current fragment + { + RingBuffer::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader(); + Event* pEvent; + while (true) { + // get next event from input event queue + if (!(pEvent = eventQueueReader.pop())) break; + // if younger event reached, ignore that and all subsequent ones for now + if (pEvent->FragmentPos() >= Samples) { + eventQueueReader--; + dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples)); + pEvent->ResetFragmentPos(); + break; + } + // copy event to internal event list + if (pEvents->poolIsEmpty()) { + dmsg(1,("Event pool emtpy!\n")); + break; + } + *pEvents->allocAppend() = *pEvent; + } + eventQueueReader.free(); // free all copied events from input queue + } // process events @@ -494,7 +519,7 @@ } } } - else dmsg(1,("Ouch, voice stealing didn't work out!\n")); + else dmsg(1,("gig::Engine: ERROR, voice stealing didn't work out!\n")); } } // reset voice stealing for the new fragment @@ -503,6 +528,29 @@ iuiLastStolenKey = RTList::Iterator(); + // free all keys which have no active voices left + { + RTList::Iterator iuiKey = pActiveKeys->first(); + RTList::Iterator end = pActiveKeys->end(); + while (iuiKey != end) { // iterate through all active keys + midi_key_info_t* pKey = &pMIDIKeyInfo[*iuiKey]; + ++iuiKey; + if (pKey->pActiveVoices->isEmpty()) FreeKey(pKey); + #if DEVMODE + else { // FIXME: should be removed before the final release (purpose: just a sanity check for debugging) + RTList::Iterator itVoice = pKey->pActiveVoices->first(); + RTList::Iterator itVoicesEnd = pKey->pActiveVoices->end(); + for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key + if (itVoice->itKillEvent) { + dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n")); + } + } + } + #endif // DEVMODE + } + } + + // write that to the disk thread class so that it can print it // on the console for debugging purposes ActiveVoiceCount = active_voices; @@ -629,7 +677,7 @@ RTList::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents); // allocate and trigger a new voice for the key - LaunchVoice(itNoteOnEventOnKeyList); + LaunchVoice(itNoteOnEventOnKeyList, 0, false, true); } /** @@ -655,7 +703,7 @@ // spawn release triggered voice(s) if needed if (pKey->ReleaseTrigger) { - LaunchVoice(itNoteOffEventOnKeyList, 0, true); + LaunchVoice(itNoteOffEventOnKeyList, 0, true, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples pKey->ReleaseTrigger = false; } } @@ -694,7 +742,7 @@ Pool::Iterator itNewVoice = pKey->pActiveVoices->allocAppend(); if (itNewVoice) { // launch the new voice - if (itNewVoice->Trigger(itNoteOnEvent, this->Pitch, this->pInstrument, iLayer, ReleaseTriggerVoice) < 0) { + if (itNewVoice->Trigger(itNoteOnEvent, this->Pitch, this->pInstrument, iLayer, ReleaseTriggerVoice, VoiceStealing) < 0) { dmsg(1,("Triggering new voice failed!\n")); pKey->pActiveVoices->free(itNewVoice); } @@ -820,6 +868,9 @@ } } + //FIXME: can be removed, just a sanity check for debugging + if (!itOldestVoice->IsActive()) dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n")); + // now kill the selected voice itOldestVoice->Kill(itNoteOnEvent); // remember which voice on which key we stole, so we can simply proceed for the next voice stealing @@ -846,24 +897,34 @@ // free the voice object pVoicePool->free(itVoice); - // check if there are no voices left on the MIDI key and update the key info if so - if (pKey->pActiveVoices->isEmpty()) { - if (keygroup) { // if voice / key belongs to a key group - uint** ppKeyGroup = &ActiveKeyGroups[keygroup]; - if (*ppKeyGroup == &*pKey->itSelf) *ppKeyGroup = NULL; // remove key from key group - } - pKey->Active = false; - pActiveKeys->free(pKey->itSelf); // remove key from list of active keys - pKey->itSelf = RTList::Iterator(); - pKey->ReleaseTrigger = false; - pKey->pEvents->clear(); - dmsg(3,("Key has no more voices now\n")); + // if no other voices left and member of a key group, remove from key group + if (pKey->pActiveVoices->isEmpty() && keygroup) { + uint** ppKeyGroup = &ActiveKeyGroups[keygroup]; + if (*ppKeyGroup == &*pKey->itSelf) *ppKeyGroup = NULL; // remove key from key group } } else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush; } /** + * Called when there's no more voice left on a key, this call will + * update the key info respectively. + * + * @param pKey - key which is now inactive + */ + void Engine::FreeKey(midi_key_info_t* pKey) { + if (pKey->pActiveVoices->isEmpty()) { + pKey->Active = false; + pActiveKeys->free(pKey->itSelf); // remove key from list of active keys + pKey->itSelf = RTList::Iterator(); + pKey->ReleaseTrigger = false; + pKey->pEvents->clear(); + dmsg(3,("Key has no more voices now\n")); + } + else dmsg(1,("gig::Engine: Oops, tried to free a key which contains voices.\n")); + } + + /** * Reacts on supported control change commands (e.g. pitch bend wheel, * modulation wheel, aftertouch). * @@ -1110,7 +1171,7 @@ } String Engine::Version() { - String s = "$Revision: 1.16 $"; + String s = "$Revision: 1.20 $"; return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword }