--- linuxsampler/trunk/src/engines/gig/Engine.cpp 2008/11/01 19:01:27 1789 +++ linuxsampler/trunk/src/engines/gig/Engine.cpp 2009/07/09 17:37:41 1933 @@ -3,7 +3,7 @@ * LinuxSampler - modular, streaming capable sampler * * * * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck * - * Copyright (C) 2005-2008 Christian Schoenebeck * + * Copyright (C) 2005-2009 Christian Schoenebeck * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -107,11 +107,13 @@ pSysexBuffer = new RingBuffer(CONFIG_SYSEX_BUFFER_SIZE, 0); pEventQueue = new RingBuffer(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0); pEventPool = new Pool(CONFIG_MAX_EVENTS_PER_FRAGMENT); - pVoicePool = new Pool(CONFIG_MAX_VOICES); - pDimRegionPool[0] = new Pool< ::gig::DimensionRegion*>(CONFIG_MAX_VOICES); - pDimRegionPool[1] = new Pool< ::gig::DimensionRegion*>(CONFIG_MAX_VOICES); + pVoicePool = new Pool(GLOBAL_MAX_VOICES); + pDimRegionPool[0] = new Pool< ::gig::DimensionRegion*>(GLOBAL_MAX_VOICES); + pDimRegionPool[1] = new Pool< ::gig::DimensionRegion*>(GLOBAL_MAX_VOICES); pVoiceStealingQueue = new RTList(pEventPool); pGlobalEvents = new RTList(pEventPool); + iMaxDiskStreams = GLOBAL_MAX_STREAMS; + FrameTime = 0; for (RTList::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) { iterVoice->SetEngine(this); @@ -152,7 +154,7 @@ void Engine::Enable() { dmsg(3,("gig::Engine: enabling\n")); - EngineDisabled.PushAndUnlock(false, 2); // set condition object 'EngineDisabled' to false (wait max. 2s) + EngineDisabled.PushAndUnlock(false, 2, 0, true); // set condition object 'EngineDisabled' to false (wait max. 2s) dmsg(3,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe())); } @@ -211,6 +213,8 @@ if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream iPendingStreamDeletions++; } + // free the voice to the voice pool and update key info + FreeVoice(pEngineChannel, itVoice); } } } @@ -342,6 +346,9 @@ * @param pAudioOut - audio output device to connect to */ void Engine::Connect(AudioOutputDevice* pAudioOut) { + // caution: don't ignore if connecting to the same device here, + // because otherwise SetMaxDiskStreams() implementation won't work anymore! + pAudioOutputDevice = pAudioOut; ResetInternal(); @@ -380,8 +387,13 @@ delete this->pDiskThread; dmsg(1,("OK\n")); } - this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo - &instruments); + this->pDiskThread = + new DiskThread( + iMaxDiskStreams, + ((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo + &instruments + ); + if (!pDiskThread) { dmsg(0,("gig::Engine new diskthread = NULL\n")); exit(EXIT_FAILURE); @@ -407,6 +419,7 @@ exit(EXIT_FAILURE); } } + pVoicePool->clear(); } /** @@ -433,6 +446,7 @@ if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream iPendingStreamDeletions++; } + //NOTE: maybe we should call FreeVoice() here, shouldn't cause a harm though I think, since the voices should be freed by RenderActiveVoices() in the render loop, they are probably just freed a bit later than they could/should be } } } @@ -584,10 +598,10 @@ // update time of start and end of this audio fragment (as events' time stamps relate to this) pEventGenerator->UpdateFragmentTime(Samples); - // We only allow a maximum of CONFIG_MAX_VOICES voices to be spawned + // We only allow the given maximum number of voices to be spawned // in each audio fragment. All subsequent request for spawning new // voices in the same audio fragment will be ignored. - VoiceSpawnsLeft = CONFIG_MAX_VOICES; + VoiceSpawnsLeft = MaxVoices(); // get all events from the engine's global input event queue which belong to the current fragment // (these are usually just SysEx messages) @@ -1947,6 +1961,15 @@ if (reader.read(&addr[0], 3) != 3) goto free_sysex_data; if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters dmsg(3,("\tSystem Parameter\n")); + if (addr[2] == 0x7f) { // GS reset + for (int i = 0; i < engineChannels.size(); ++i) { + EngineChannel* pEngineChannel = engineChannels[i]; + if (pEngineChannel->GetMidiInputPort() == itSysexEvent->pMidiInputPort) { + KillAllVoices(pEngineChannel, itSysexEvent); + pEngineChannel->ResetControllers(); + } + } + } } else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters dmsg(3,("\tCommon Parameter\n")); @@ -2111,6 +2134,47 @@ return ActiveVoiceCountMax; } + int Engine::MaxVoices() { + return pVoicePool->poolSize(); + } + + void Engine::SetMaxVoices(int iVoices) throw (Exception) { + if (iVoices < 1) + throw Exception("Maximum voices for an engine cannot be set lower than 1"); + + SuspendAll(); + + // NOTE: we need to clear pDimRegionsInUse before deleting pDimRegionPool, + // otherwise memory corruption will occur if there are active voices (see bug #118) + for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) { + engineChannels[iChannel]->ClearDimRegionsInUse(); + } + + if (pDimRegionPool[0]) delete pDimRegionPool[0]; + if (pDimRegionPool[1]) delete pDimRegionPool[1]; + + pDimRegionPool[0] = new Pool< ::gig::DimensionRegion*>(iVoices); + pDimRegionPool[1] = new Pool< ::gig::DimensionRegion*>(iVoices); + + for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) { + engineChannels[iChannel]->ResetDimRegionsInUse(); + } + + try { + pVoicePool->resizePool(iVoices); + } catch (...) { + throw Exception("FATAL: Could not resize voice pool!"); + } + + for (RTList::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) { + iterVoice->SetEngine(this); + iterVoice->pDiskThread = this->pDiskThread; + } + pVoicePool->clear(); + + ResumeAll(); + } + bool Engine::DiskStreamSupported() { return true; } @@ -2123,6 +2187,25 @@ return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; } + int Engine::MaxDiskStreams() { + return iMaxDiskStreams; + } + + void Engine::SetMaxDiskStreams(int iStreams) throw (Exception) { + if (iStreams < 0) + throw Exception("Maximum disk streams for an engine cannot be set lower than 0"); + + SuspendAll(); + + iMaxDiskStreams = iStreams; + + // reconnect to audio output device, because that will automatically + // recreate the disk thread with the required amount of streams + if (pAudioOutputDevice) Connect(pAudioOutputDevice); + + ResumeAll(); + } + String Engine::DiskStreamBufferFillBytes() { return pDiskThread->GetBufferFillBytes(); } @@ -2140,7 +2223,7 @@ } String Engine::Version() { - String s = "$Revision: 1.98 $"; + String s = "$Revision: 1.104 $"; return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword }