--- linuxsampler/trunk/src/engines/EngineChannelBase.h 2012/03/17 06:19:01 2335 +++ linuxsampler/trunk/src/engines/EngineChannelBase.h 2014/06/10 13:32:16 2612 @@ -4,7 +4,7 @@ * * * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck * * Copyright (C) 2005-2008 Christian Schoenebeck * - * Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev * + * Copyright (C) 2009-2013 Christian Schoenebeck and Grigor Iliev * * * * 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 * @@ -39,6 +39,7 @@ bool bChangeInstrument; ///< Set to true by the loader when the channel should change instrument. I* pInstrument; ///< The new instrument. Also used by the loader to read the previously loaded instrument. RTList* pRegionsInUse; ///< List of dimension regions in use by the currently loaded instrument. Continuously updated by the audio thread. + InstrumentScript* pScript; ///< Instrument script to be executed for this instrument, or NULL if instrument does not have a script. }; template @@ -84,9 +85,11 @@ } virtual void DeleteRegionsInUse() { + RTList* previous = NULL; // prevent double free { InstrumentChangeCmd& cmd = InstrumentChangeCommand.GetConfigForUpdate(); if (cmd.pRegionsInUse) { + previous = cmd.pRegionsInUse; delete cmd.pRegionsInUse; cmd.pRegionsInUse = NULL; } @@ -95,7 +98,8 @@ { InstrumentChangeCmd& cmd = InstrumentChangeCommand.SwitchConfig(); if (cmd.pRegionsInUse) { - delete cmd.pRegionsInUse; + if (cmd.pRegionsInUse != previous) + delete cmd.pRegionsInUse; cmd.pRegionsInUse = NULL; } cmd.bChangeInstrument = false; @@ -121,9 +125,10 @@ DisconnectAudioOutputDevice(); } AbstractEngine* newEngine = AbstractEngine::AcquireEngine(this, pAudioOut); - EngineMutex.Lock(); - pEngine = newEngine; - EngineMutex.Unlock(); + { + LockGuard lock(EngineMutex); + pEngine = newEngine; + } ResetInternal(); pEvents = new RTList(pEngine->pEventPool); @@ -178,6 +183,7 @@ ResetInternal(); DeleteRegionsInUse(); + UnloadScriptInUse(); InstrumentChangeCmd& cmd = InstrumentChangeCommand.GetConfigForUpdate(); if (cmd.pInstrument) { @@ -195,9 +201,10 @@ DeleteGroupEventLists(); AudioOutputDevice* oldAudioDevice = pEngine->pAudioOutputDevice; - EngineMutex.Lock(); - pEngine = NULL; - EngineMutex.Unlock(); + { + LockGuard lock(EngineMutex); + pEngine = NULL; + } AbstractEngine::FreeEngine(this, oldAudioDevice); AudioDeviceChannelLeft = -1; AudioDeviceChannelRight = -1; @@ -222,7 +229,10 @@ this->ProcessActiveVoices(&handler); // empty exclusive group specific event lists - ClearGroupEventLists(); + // (pInstrument == 0 could mean that LoadInstrument is + // building new group event lists, so we must check + // for that) + if (pInstrument) ClearGroupEventLists(); } // implementation of abstract methods derived from interface class 'InstrumentConsumer' @@ -232,7 +242,7 @@ * we are currently using on this EngineChannel is going to be updated, * so we can stop playback before that happens. */ - virtual void ResourceToBeUpdated(I* pResource, void*& pUpdateArg) { + virtual void ResourceToBeUpdated(I* pResource, void*& pUpdateArg) OVERRIDE { dmsg(3,("EngineChannelBase: Received instrument update message.\n")); if (pEngine) pEngine->DisableAndLock(); ResetInternal(); @@ -243,7 +253,7 @@ * Will be called by the InstrumentResourceManager when the instrument * update process was completed, so we can continue with playback. */ - virtual void ResourceUpdated(I* pOldResource, I* pNewResource, void* pUpdateArg) { + virtual void ResourceUpdated(I* pOldResource, I* pNewResource, void* pUpdateArg) OVERRIDE { this->pInstrument = pNewResource; //TODO: there are couple of engine parameters we should update here as well if the instrument was updated (see LoadInstrument()) if (pEngine) pEngine->Enable(); bStatusChanged = true; // status of engine has changed, so set notify flag @@ -255,7 +265,7 @@ * * @param fProgress - current progress as value between 0.0 and 1.0 */ - virtual void OnResourceProgress(float fProgress) { + virtual void OnResourceProgress(float fProgress) OVERRIDE { this->InstrumentStat = int(fProgress * 100.0f); dmsg(7,("EngineChannelBase: progress %d%", InstrumentStat)); bStatusChanged = true; // status of engine has changed, so set notify flag @@ -284,17 +294,37 @@ InstrumentChangeCmd& cmd = InstrumentChangeCommand.GetConfigForUpdate(); cmd.pRegionsInUse = NULL; cmd.pInstrument = NULL; + cmd.pScript = new InstrumentScript(this); cmd.bChangeInstrument = false; } { InstrumentChangeCmd& cmd = InstrumentChangeCommand.SwitchConfig(); cmd.pRegionsInUse = NULL; cmd.pInstrument = NULL; + cmd.pScript = new InstrumentScript(this); cmd.bChangeInstrument = false; } } - virtual ~EngineChannelBase() { } + virtual ~EngineChannelBase() { + InstrumentScript* previous = NULL; // prevent double free + { + InstrumentChangeCmd& cmd = InstrumentChangeCommand.GetConfigForUpdate(); + if (cmd.pScript) { + previous = cmd.pScript; + delete cmd.pScript; + cmd.pScript = NULL; + } + } + { + InstrumentChangeCmd& cmd = InstrumentChangeCommand.SwitchConfig(); + if (cmd.pScript) { + if (previous != cmd.pScript) + delete cmd.pScript; + cmd.pScript = NULL; + } + } + } typedef typename RTList::Iterator RTListVoiceIterator; @@ -347,6 +377,34 @@ } /** + * Unload the currently used and loaded real-time instrument script. + * The source code of the script is retained, so that it can still + * be reloaded. + */ + void UnloadScriptInUse() { + { + InstrumentChangeCmd& cmd = InstrumentChangeCommand.GetConfigForUpdate(); + if (cmd.pScript) pScript->unload(); + } + { + InstrumentChangeCmd& cmd = InstrumentChangeCommand.SwitchConfig(); + if (cmd.pScript) pScript->unload(); + } + } + + /** + * Load real-time instrument script and all its resources required + * for the upcoming instrument change. + * + * @param text - source code of script + */ + void LoadInstrumentScript(const String& text) { + InstrumentChangeCmd& cmd = InstrumentChangeCommand.GetConfigForUpdate(); + // load the new script + cmd.pScript->load(text); + } + + /** * Changes the instrument for an engine channel. * * @param pInstrument - new instrument