--- linuxsampler/trunk/src/engines/gig/Engine.cpp 2004/10/14 21:31:26 285 +++ linuxsampler/trunk/src/engines/gig/Engine.cpp 2005/01/29 15:17:59 354 @@ -26,6 +26,7 @@ #include "EGADSR.h" #include "Engine.h" +#include namespace LinuxSampler { namespace gig { @@ -76,9 +77,14 @@ Engine::~Engine() { if (pDiskThread) { + dmsg(1,("Stopping disk thread...")); pDiskThread->StopThread(); delete pDiskThread; + dmsg(1,("OK\n")); } + + if (pInstrument) Instruments.HandBack(pInstrument, this); + if (pGig) delete pGig; if (pRIFF) delete pRIFF; for (uint i = 0; i < 128; i++) { @@ -88,18 +94,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; } @@ -158,6 +166,7 @@ ActiveVoiceCount = 0; ActiveVoiceCountMax = 0; GlobalVolume = 1.0; + CurrentKeyDimension = 0; // reset voice stealing parameters itLastStolenVoice = RTList::Iterator(); @@ -321,8 +330,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 +352,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 +409,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 +427,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 +523,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 +532,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; @@ -611,7 +663,15 @@ * @param itNoteOnEvent - key, velocity and time stamp of the event */ void Engine::ProcessNoteOn(Pool::Iterator& itNoteOnEvent) { - midi_key_info_t* pKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key]; + + const int key = itNoteOnEvent->Param.Note.Key; + + // Change key dimension value if key is in keyswitching area + if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high) + CurrentKeyDimension = ((key - pInstrument->DimensionKeyRange.low) * 128) / + (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1); + + midi_key_info_t* pKey = &pMIDIKeyInfo[key]; pKey->KeyPressed = true; // the MIDI key was now pressed down @@ -629,7 +689,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 +715,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; } } @@ -685,7 +745,8 @@ * when there is no free voice * (optional, default = true) * @returns pointer to new voice or NULL if there was no free voice or - * if an error occured while trying to trigger the new voice + * if the voice wasn't triggered (for example when no region is + * defined for the given key). */ Pool::Iterator Engine::LaunchVoice(Pool::Iterator& itNoteOnEvent, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing) { midi_key_info_t* pKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key]; @@ -694,8 +755,8 @@ Pool::Iterator itNewVoice = pKey->pActiveVoices->allocAppend(); if (itNewVoice) { // launch the new voice - if (itNewVoice->Trigger(itNoteOnEvent, this->Pitch, this->pInstrument, iLayer, ReleaseTriggerVoice) < 0) { - dmsg(1,("Triggering new voice failed!\n")); + if (itNewVoice->Trigger(itNoteOnEvent, this->Pitch, this->pInstrument, iLayer, ReleaseTriggerVoice, VoiceStealing) < 0) { + dmsg(4,("Voice not triggered\n")); pKey->pActiveVoices->free(itNewVoice); } else { // on success @@ -820,6 +881,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 +910,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 +1184,7 @@ } String Engine::Version() { - String s = "$Revision: 1.16 $"; + String s = "$Revision: 1.22 $"; return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword }