4 |
* * |
* * |
5 |
* Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck * |
* Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck * |
6 |
* Copyright (C) 2005-2008 Christian Schoenebeck * |
* Copyright (C) 2005-2008 Christian Schoenebeck * |
7 |
* Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev * |
* Copyright (C) 2009-2013 Christian Schoenebeck and Grigor Iliev * |
8 |
* * |
* * |
9 |
* This program is free software; you can redistribute it and/or modify * |
* This program is free software; you can redistribute it and/or modify * |
10 |
* it under the terms of the GNU General Public License as published by * |
* it under the terms of the GNU General Public License as published by * |
39 |
bool bChangeInstrument; ///< Set to true by the loader when the channel should change instrument. |
bool bChangeInstrument; ///< Set to true by the loader when the channel should change instrument. |
40 |
I* pInstrument; ///< The new instrument. Also used by the loader to read the previously loaded instrument. |
I* pInstrument; ///< The new instrument. Also used by the loader to read the previously loaded instrument. |
41 |
RTList<R*>* pRegionsInUse; ///< List of dimension regions in use by the currently loaded instrument. Continuously updated by the audio thread. |
RTList<R*>* pRegionsInUse; ///< List of dimension regions in use by the currently loaded instrument. Continuously updated by the audio thread. |
42 |
|
InstrumentScript* pScript; ///< Instrument script to be executed for this instrument, or NULL if instrument does not have a script. |
43 |
}; |
}; |
44 |
|
|
45 |
template<class R> |
template<class R> |
85 |
} |
} |
86 |
|
|
87 |
virtual void DeleteRegionsInUse() { |
virtual void DeleteRegionsInUse() { |
88 |
|
RTList<R*>* previous = NULL; // prevent double free |
89 |
{ |
{ |
90 |
InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate(); |
InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate(); |
91 |
if (cmd.pRegionsInUse) { |
if (cmd.pRegionsInUse) { |
92 |
|
previous = cmd.pRegionsInUse; |
93 |
delete cmd.pRegionsInUse; |
delete cmd.pRegionsInUse; |
94 |
cmd.pRegionsInUse = NULL; |
cmd.pRegionsInUse = NULL; |
95 |
} |
} |
98 |
{ |
{ |
99 |
InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.SwitchConfig(); |
InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.SwitchConfig(); |
100 |
if (cmd.pRegionsInUse) { |
if (cmd.pRegionsInUse) { |
101 |
delete cmd.pRegionsInUse; |
if (cmd.pRegionsInUse != previous) |
102 |
|
delete cmd.pRegionsInUse; |
103 |
cmd.pRegionsInUse = NULL; |
cmd.pRegionsInUse = NULL; |
104 |
} |
} |
105 |
cmd.bChangeInstrument = false; |
cmd.bChangeInstrument = false; |
125 |
DisconnectAudioOutputDevice(); |
DisconnectAudioOutputDevice(); |
126 |
} |
} |
127 |
AbstractEngine* newEngine = AbstractEngine::AcquireEngine(this, pAudioOut); |
AbstractEngine* newEngine = AbstractEngine::AcquireEngine(this, pAudioOut); |
128 |
EngineMutex.Lock(); |
{ |
129 |
pEngine = newEngine; |
LockGuard lock(EngineMutex); |
130 |
EngineMutex.Unlock(); |
pEngine = newEngine; |
131 |
|
} |
132 |
ResetInternal(); |
ResetInternal(); |
133 |
pEvents = new RTList<Event>(pEngine->pEventPool); |
pEvents = new RTList<Event>(pEngine->pEventPool); |
134 |
|
|
183 |
ResetInternal(); |
ResetInternal(); |
184 |
|
|
185 |
DeleteRegionsInUse(); |
DeleteRegionsInUse(); |
186 |
|
UnloadScriptInUse(); |
187 |
|
|
188 |
InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate(); |
InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate(); |
189 |
if (cmd.pInstrument) { |
if (cmd.pInstrument) { |
201 |
DeleteGroupEventLists(); |
DeleteGroupEventLists(); |
202 |
|
|
203 |
AudioOutputDevice* oldAudioDevice = pEngine->pAudioOutputDevice; |
AudioOutputDevice* oldAudioDevice = pEngine->pAudioOutputDevice; |
204 |
EngineMutex.Lock(); |
{ |
205 |
pEngine = NULL; |
LockGuard lock(EngineMutex); |
206 |
EngineMutex.Unlock(); |
pEngine = NULL; |
207 |
|
} |
208 |
AbstractEngine::FreeEngine(this, oldAudioDevice); |
AbstractEngine::FreeEngine(this, oldAudioDevice); |
209 |
AudioDeviceChannelLeft = -1; |
AudioDeviceChannelLeft = -1; |
210 |
AudioDeviceChannelRight = -1; |
AudioDeviceChannelRight = -1; |
226 |
pEvents->clear(); |
pEvents->clear(); |
227 |
// empty MIDI key specific event lists |
// empty MIDI key specific event lists |
228 |
ClearEventListsHandler handler; |
ClearEventListsHandler handler; |
229 |
ProcessActiveVoices(&handler); |
this->ProcessActiveVoices(&handler); |
230 |
|
|
231 |
// empty exclusive group specific event lists |
// empty exclusive group specific event lists |
232 |
ClearGroupEventLists(); |
// (pInstrument == 0 could mean that LoadInstrument is |
233 |
|
// building new group event lists, so we must check |
234 |
|
// for that) |
235 |
|
if (pInstrument) ClearGroupEventLists(); |
236 |
} |
} |
237 |
|
|
238 |
// implementation of abstract methods derived from interface class 'InstrumentConsumer' |
// implementation of abstract methods derived from interface class 'InstrumentConsumer' |
242 |
* we are currently using on this EngineChannel is going to be updated, |
* we are currently using on this EngineChannel is going to be updated, |
243 |
* so we can stop playback before that happens. |
* so we can stop playback before that happens. |
244 |
*/ |
*/ |
245 |
virtual void ResourceToBeUpdated(I* pResource, void*& pUpdateArg) { |
virtual void ResourceToBeUpdated(I* pResource, void*& pUpdateArg) OVERRIDE { |
246 |
dmsg(3,("EngineChannelBase: Received instrument update message.\n")); |
dmsg(3,("EngineChannelBase: Received instrument update message.\n")); |
247 |
if (pEngine) pEngine->DisableAndLock(); |
if (pEngine) pEngine->DisableAndLock(); |
248 |
ResetInternal(); |
ResetInternal(); |
253 |
* Will be called by the InstrumentResourceManager when the instrument |
* Will be called by the InstrumentResourceManager when the instrument |
254 |
* update process was completed, so we can continue with playback. |
* update process was completed, so we can continue with playback. |
255 |
*/ |
*/ |
256 |
virtual void ResourceUpdated(I* pOldResource, I* pNewResource, void* pUpdateArg) { |
virtual void ResourceUpdated(I* pOldResource, I* pNewResource, void* pUpdateArg) OVERRIDE { |
257 |
this->pInstrument = pNewResource; //TODO: there are couple of engine parameters we should update here as well if the instrument was updated (see LoadInstrument()) |
this->pInstrument = pNewResource; //TODO: there are couple of engine parameters we should update here as well if the instrument was updated (see LoadInstrument()) |
258 |
if (pEngine) pEngine->Enable(); |
if (pEngine) pEngine->Enable(); |
259 |
bStatusChanged = true; // status of engine has changed, so set notify flag |
bStatusChanged = true; // status of engine has changed, so set notify flag |
265 |
* |
* |
266 |
* @param fProgress - current progress as value between 0.0 and 1.0 |
* @param fProgress - current progress as value between 0.0 and 1.0 |
267 |
*/ |
*/ |
268 |
virtual void OnResourceProgress(float fProgress) { |
virtual void OnResourceProgress(float fProgress) OVERRIDE { |
269 |
this->InstrumentStat = int(fProgress * 100.0f); |
this->InstrumentStat = int(fProgress * 100.0f); |
270 |
dmsg(7,("EngineChannelBase: progress %d%", InstrumentStat)); |
dmsg(7,("EngineChannelBase: progress %d%", InstrumentStat)); |
271 |
bStatusChanged = true; // status of engine has changed, so set notify flag |
bStatusChanged = true; // status of engine has changed, so set notify flag |
273 |
|
|
274 |
void RenderActiveVoices(uint Samples) { |
void RenderActiveVoices(uint Samples) { |
275 |
RenderVoicesHandler handler(this, Samples); |
RenderVoicesHandler handler(this, Samples); |
276 |
ProcessActiveVoices(&handler); |
this->ProcessActiveVoices(&handler); |
277 |
|
|
278 |
SetVoiceCount(handler.VoiceCount); |
SetVoiceCount(handler.VoiceCount); |
279 |
SetDiskStreamCount(handler.StreamCount); |
SetDiskStreamCount(handler.StreamCount); |
294 |
InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate(); |
InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate(); |
295 |
cmd.pRegionsInUse = NULL; |
cmd.pRegionsInUse = NULL; |
296 |
cmd.pInstrument = NULL; |
cmd.pInstrument = NULL; |
297 |
|
cmd.pScript = new InstrumentScript(this); |
298 |
cmd.bChangeInstrument = false; |
cmd.bChangeInstrument = false; |
299 |
} |
} |
300 |
{ |
{ |
301 |
InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.SwitchConfig(); |
InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.SwitchConfig(); |
302 |
cmd.pRegionsInUse = NULL; |
cmd.pRegionsInUse = NULL; |
303 |
cmd.pInstrument = NULL; |
cmd.pInstrument = NULL; |
304 |
|
cmd.pScript = new InstrumentScript(this); |
305 |
cmd.bChangeInstrument = false; |
cmd.bChangeInstrument = false; |
306 |
} |
} |
307 |
} |
} |
308 |
|
|
309 |
virtual ~EngineChannelBase() { } |
virtual ~EngineChannelBase() { |
310 |
|
InstrumentScript* previous = NULL; // prevent double free |
311 |
|
{ |
312 |
|
InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate(); |
313 |
|
if (cmd.pScript) { |
314 |
|
previous = cmd.pScript; |
315 |
|
delete cmd.pScript; |
316 |
|
cmd.pScript = NULL; |
317 |
|
} |
318 |
|
} |
319 |
|
{ |
320 |
|
InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.SwitchConfig(); |
321 |
|
if (cmd.pScript) { |
322 |
|
if (previous != cmd.pScript) |
323 |
|
delete cmd.pScript; |
324 |
|
cmd.pScript = NULL; |
325 |
|
} |
326 |
|
} |
327 |
|
} |
328 |
|
|
329 |
typedef typename RTList<V>::Iterator RTListVoiceIterator; |
typedef typename RTList<V>::Iterator RTListVoiceIterator; |
330 |
|
|
377 |
} |
} |
378 |
|
|
379 |
/** |
/** |
380 |
|
* Unload the currently used and loaded real-time instrument script. |
381 |
|
* The source code of the script is retained, so that it can still |
382 |
|
* be reloaded. |
383 |
|
*/ |
384 |
|
void UnloadScriptInUse() { |
385 |
|
{ |
386 |
|
InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate(); |
387 |
|
if (cmd.pScript) pScript->unload(); |
388 |
|
} |
389 |
|
{ |
390 |
|
InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.SwitchConfig(); |
391 |
|
if (cmd.pScript) pScript->unload(); |
392 |
|
} |
393 |
|
} |
394 |
|
|
395 |
|
/** |
396 |
|
* Load real-time instrument script and all its resources required |
397 |
|
* for the upcoming instrument change. |
398 |
|
* |
399 |
|
* @param text - source code of script |
400 |
|
*/ |
401 |
|
void LoadInstrumentScript(const String& text) { |
402 |
|
InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate(); |
403 |
|
// load the new script |
404 |
|
cmd.pScript->load(text); |
405 |
|
} |
406 |
|
|
407 |
|
/** |
408 |
* Changes the instrument for an engine channel. |
* Changes the instrument for an engine channel. |
409 |
* |
* |
410 |
* @param pInstrument - new instrument |
* @param pInstrument - new instrument |