/[svn]/linuxsampler/trunk/src/engines/gig/InstrumentResourceManager.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/engines/gig/InstrumentResourceManager.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3733 - (hide annotations) (download)
Sat Feb 1 18:11:20 2020 UTC (4 years, 2 months ago) by schoenebeck
File size: 48348 byte(s)
NKSP: Added support for 'patch' variables.

* NKSP language: Added support for 'patch' variable qualifier
  (as new dedicated keyword 'patch').

* NKSP parser: capture locations of 'patch' variable declarations
  in script's source code.

* ScriptVM: Allow patching 'patch' script variables by replacing
  their default assignment expression with a supplied replacement
  variable initialization expression by optional 2nd argument when
  calling loadScript().

* ScriptVM: Allow retrieval of default initialization expressions
  of all 'patch' variables by optional 3rd argument when calling
  loadScript() (i.e. for instrument editors).

* gig engine: Implemented support for loading real-time instrument
  scripts with 'patch' variables bundled with gig instruments.

* Bumped version (2.1.1.svn46).


1 schoenebeck 3719
2 schoenebeck 53 /***************************************************************************
3     * *
4     * LinuxSampler - modular, streaming capable sampler *
5     * *
6 schoenebeck 56 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
7 schoenebeck 3719 * Copyright (C) 2005 - 2020 Christian Schoenebeck *
8 schoenebeck 53 * *
9     * 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 *
11     * the Free Software Foundation; either version 2 of the License, or *
12     * (at your option) any later version. *
13     * *
14     * This program is distributed in the hope that it will be useful, *
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17     * GNU General Public License for more details. *
18     * *
19     * You should have received a copy of the GNU General Public License *
20     * along with this program; if not, write to the Free Software *
21     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
22     * MA 02111-1307 USA *
23     ***************************************************************************/
24    
25     #include <sstream>
26    
27     #include "InstrumentResourceManager.h"
28 iliev 2012 #include "EngineChannel.h"
29     #include "Engine.h"
30 schoenebeck 53
31 schoenebeck 1424 #include "../../common/global_private.h"
32 schoenebeck 1375 #include "../../plugins/InstrumentEditorFactory.h"
33 schoenebeck 1212
34 schoenebeck 53 namespace LinuxSampler { namespace gig {
35    
36 schoenebeck 517 // some data needed for the libgig callback function
37     struct progress_callback_arg_t {
38 schoenebeck 947 InstrumentResourceManager* pManager;
39     InstrumentManager::instrument_id_t* pInstrumentKey;
40 schoenebeck 517 };
41    
42 schoenebeck 1212 // we use this to react on events concerning an instrument on behalf of an instrument editor
43     class InstrumentEditorProxy : public InstrumentConsumer {
44     public:
45 schoenebeck 3034 virtual ~InstrumentEditorProxy() {}
46    
47 schoenebeck 1212 virtual void ResourceToBeUpdated(::gig::Instrument* pResource, void*& pUpdateArg) {
48     //TODO: inform the instrument editor about the pending update
49     }
50    
51     virtual void ResourceUpdated(::gig::Instrument* pOldResource, ::gig::Instrument* pNewResource, void* pUpdateArg) {
52     //TODO:: inform the instrument editor about finished update
53     }
54    
55     virtual void OnResourceProgress(float fProgress) {
56     //TODO: inform the instrument editor about the progress of an update
57     }
58    
59     // the instrument we borrowed on behalf of the editor
60     ::gig::Instrument* pInstrument;
61 schoenebeck 1653 // the instrument editor we work on behalf
62     InstrumentEditor* pEditor;
63 schoenebeck 1212 };
64    
65 schoenebeck 517 /**
66     * Callback function which will be called by libgig during loading of
67     * instruments to inform about the current progress. Or to be more
68     * specific; it will be called during the GetInstrument() call.
69     *
70     * @param pProgress - contains current progress value, pointer to the
71     * InstrumentResourceManager instance and
72     * instrument ID
73     */
74     void InstrumentResourceManager::OnInstrumentLoadingProgress(::gig::progress_t* pProgress) {
75 persson 2837 dmsg(7,("gig::InstrumentResourceManager: progress %f%%", pProgress->factor));
76 schoenebeck 517 progress_callback_arg_t* pArg = static_cast<progress_callback_arg_t*>(pProgress->custom);
77     // we randomly schedule 90% for the .gig file loading and the remaining 10% later for sample caching
78     const float localProgress = 0.9f * pProgress->factor;
79     pArg->pManager->DispatchResourceProgressEvent(*pArg->pInstrumentKey, localProgress);
80     }
81    
82 schoenebeck 947 String InstrumentResourceManager::GetInstrumentName(instrument_id_t ID) {
83 schoenebeck 970 Lock();
84     ::gig::Instrument* pInstrument = Resource(ID, false);
85     String res = (pInstrument) ? pInstrument->pInfo->Name : "";
86     Unlock();
87     return res;
88 schoenebeck 947 }
89    
90 schoenebeck 1321 String InstrumentResourceManager::GetInstrumentDataStructureName(instrument_id_t ID) {
91 schoenebeck 1212 return ::gig::libraryName();
92     }
93    
94 schoenebeck 1321 String InstrumentResourceManager::GetInstrumentDataStructureVersion(instrument_id_t ID) {
95 schoenebeck 1212 return ::gig::libraryVersion();
96     }
97    
98 schoenebeck 1525 std::vector<InstrumentResourceManager::instrument_id_t> InstrumentResourceManager::GetInstrumentFileContent(String File) throw (InstrumentManagerException) {
99     ::RIFF::File* riff = NULL;
100     ::gig::File* gig = NULL;
101     try {
102     std::vector<instrument_id_t> result;
103     riff = new ::RIFF::File(File);
104     gig = new ::gig::File(riff);
105     gig->SetAutoLoad(false); // avoid time consuming samples scanning
106     for (int i = 0; gig->GetInstrument(i); i++) {
107     instrument_id_t id;
108     id.FileName = File;
109     id.Index = i;
110     result.push_back(id);
111     }
112     if (gig) delete gig;
113     if (riff) delete riff;
114     return result;
115     } catch (::RIFF::Exception e) {
116     if (gig) delete gig;
117     if (riff) delete riff;
118     throw InstrumentManagerException(e.Message);
119     } catch (...) {
120     if (gig) delete gig;
121     if (riff) delete riff;
122     throw InstrumentManagerException("Unknown exception while trying to parse '" + File + "'");
123     }
124     }
125    
126     InstrumentResourceManager::instrument_info_t InstrumentResourceManager::GetInstrumentInfo(instrument_id_t ID) throw (InstrumentManagerException) {
127 iliev 1771 Lock();
128     ::gig::Instrument* pInstrument = Resource(ID, false);
129     bool loaded = (pInstrument != NULL);
130     if (!loaded) Unlock();
131    
132 schoenebeck 1525 ::RIFF::File* riff = NULL;
133     ::gig::File* gig = NULL;
134     try {
135 persson 2326 if (!loaded) {
136 iliev 1771 riff = new ::RIFF::File(ID.FileName);
137     gig = new ::gig::File(riff);
138     gig->SetAutoLoad(false); // avoid time consuming samples scanning
139     pInstrument = gig->GetInstrument(ID.Index);
140     }
141 schoenebeck 1852
142 schoenebeck 1525 if (!pInstrument) throw InstrumentManagerException("There is no instrument " + ToString(ID.Index) + " in " + ID.FileName);
143 iliev 1771
144 schoenebeck 1525 instrument_info_t info;
145 iliev 1771 for (int i = 0; i < 128; i++) { info.KeyBindings[i] = info.KeySwitchBindings[i] = 0; }
146    
147     ::gig::File* pFile = (::gig::File*) pInstrument->GetParent();
148    
149     if (pFile->pVersion) {
150     info.FormatVersion = ToString(pFile->pVersion->major);
151     info.Product = pFile->pInfo->Product;
152     info.Artists = pFile->pInfo->Artists;
153 schoenebeck 1525 }
154 iliev 1771
155 schoenebeck 1525 info.InstrumentName = pInstrument->pInfo->Name;
156 iliev 1771
157     ::gig::Region* pRegion = pInstrument->GetFirstRegion();
158     while (pRegion) {
159     int low = pRegion->KeyRange.low;
160     int high = pRegion->KeyRange.high;
161     if (low < 0 || low > 127 || high < 0 || high > 127 || low > high) {
162     std::cerr << "Invalid key range: " << low << " - " << high << std::endl;
163     } else {
164     for (int i = low; i <= high; i++) info.KeyBindings[i] = 1;
165     }
166 persson 1797
167 iliev 1771 pRegion = pInstrument->GetNextRegion();
168     }
169 persson 1797
170 iliev 1774 if (loaded) { // retrieve keyswitching only if the instrument is fully loaded.
171 persson 1797
172     // only return keyswitch range if keyswitching is used
173     bool hasKeyswitches = false;
174     for (::gig::Region* pRegion = pInstrument->GetFirstRegion() ;
175     pRegion && !hasKeyswitches ;
176     pRegion = pInstrument->GetNextRegion()) {
177     for (int i = 0 ; i < pRegion->Dimensions ; i++) {
178     if (pRegion->pDimensionDefinitions[i].dimension == ::gig::dimension_keyboard) {
179     hasKeyswitches = true;
180     break;
181     }
182     }
183 iliev 1774 }
184 persson 1797
185     if (hasKeyswitches) {
186     int low = pInstrument->DimensionKeyRange.low;
187     int high = pInstrument->DimensionKeyRange.high;
188     if (low < 0 || low > 127 || high < 0 || high > 127 || low > high) {
189     std::cerr << "Invalid keyswitch range: " << low << " - " << high << std::endl;
190     } else {
191     for (int i = low; i <= high; i++) info.KeySwitchBindings[i] = 1;
192     }
193     }
194 iliev 1771 }
195    
196     if (loaded) Unlock();
197    
198 schoenebeck 1525 if (gig) delete gig;
199     if (riff) delete riff;
200     return info;
201     } catch (::RIFF::Exception e) {
202 iliev 1771 if (loaded) Unlock();
203 schoenebeck 1525 if (gig) delete gig;
204     if (riff) delete riff;
205     throw InstrumentManagerException(e.Message);
206     } catch (...) {
207 iliev 1771 if (loaded) Unlock();
208 schoenebeck 1525 if (gig) delete gig;
209     if (riff) delete riff;
210     throw InstrumentManagerException("Unknown exception while trying to parse '" + ID.FileName + "'");
211     }
212     }
213    
214 schoenebeck 2687 InstrumentEditor* InstrumentResourceManager::LaunchInstrumentEditor(LinuxSampler::EngineChannel* pEngineChannel, instrument_id_t ID, void* pUserData) throw (InstrumentManagerException) {
215 schoenebeck 1321 const String sDataType = GetInstrumentDataStructureName(ID);
216     const String sDataVersion = GetInstrumentDataStructureVersion(ID);
217 schoenebeck 1212 // find instrument editors capable to handle given instrument
218     std::vector<String> vEditors =
219     InstrumentEditorFactory::MatchingEditors(sDataType, sDataVersion);
220     if (!vEditors.size())
221     throw InstrumentManagerException(
222     "There is no instrument editor capable to handle this instrument"
223     );
224     // simply use the first editor in the result set
225     dmsg(1,("Found matching editor '%s' for instrument ('%s', %d) having data structure ('%s','%s')\n",
226     vEditors[0].c_str(), ID.FileName.c_str(), ID.Index, sDataType.c_str(), sDataVersion.c_str()));
227     InstrumentEditor* pEditor = InstrumentEditorFactory::Create(vEditors[0]);
228 schoenebeck 1321 // register for receiving notifications from the instrument editor
229 schoenebeck 1212 pEditor->AddListener(this);
230     // create a proxy that reacts on notification on behalf of the editor
231     InstrumentEditorProxy* pProxy = new InstrumentEditorProxy;
232     // borrow the instrument on behalf of the instrument editor
233     ::gig::Instrument* pInstrument = Borrow(ID, pProxy);
234     // remember the proxy and instrument for this instrument editor
235     pProxy->pInstrument = pInstrument;
236 schoenebeck 1653 pProxy->pEditor = pEditor;
237 schoenebeck 1212 InstrumentEditorProxiesMutex.Lock();
238 schoenebeck 1653 InstrumentEditorProxies.add(pProxy);
239 schoenebeck 1212 InstrumentEditorProxiesMutex.Unlock();
240     // launch the instrument editor for the given instrument
241 schoenebeck 2687 pEditor->Launch(pEngineChannel, pInstrument, sDataType, sDataVersion, pUserData);
242 schoenebeck 1659
243     // register the instrument editor as virtual MIDI device as well ...
244     VirtualMidiDevice* pVirtualMidiDevice =
245     dynamic_cast<VirtualMidiDevice*>(pEditor);
246     if (!pVirtualMidiDevice) {
247     std::cerr << "Instrument editor not a virtual MIDI device\n" << std::flush;
248 schoenebeck 1868 return pEditor;
249 schoenebeck 1659 }
250     // NOTE: for now connect the virtual MIDI keyboard of the instrument editor (if any) with all engine channels that have the same instrument as the editor was opened for ( other ideas ? )
251     Lock();
252 iliev 2012 std::set<EngineChannel*> engineChannels =
253 schoenebeck 1659 GetEngineChannelsUsing(pInstrument, false/*don't lock again*/);
254 iliev 2012 std::set<EngineChannel*>::iterator iter = engineChannels.begin();
255     std::set<EngineChannel*>::iterator end = engineChannels.end();
256     for (; iter != end; ++iter) (static_cast<AbstractEngineChannel*>(*iter))->Connect(pVirtualMidiDevice);
257 schoenebeck 1659 Unlock();
258 schoenebeck 1868
259     return pEditor;
260 schoenebeck 1212 }
261    
262     /**
263     * Will be called by the respective instrument editor once it left its
264     * Main() loop. That way we can handle cleanup before its thread finally
265     * dies.
266     *
267     * @param pSender - instrument editor that stops execution
268     */
269     void InstrumentResourceManager::OnInstrumentEditorQuit(InstrumentEditor* pSender) {
270     dmsg(1,("InstrumentResourceManager: instrument editor quit, doing cleanup\n"));
271 schoenebeck 1659
272     ::gig::Instrument* pInstrument = NULL;
273     InstrumentEditorProxy* pProxy = NULL;
274     int iProxyIndex = -1;
275    
276     // first find the editor proxy entry for this editor
277 persson 2427 {
278     LockGuard lock(InstrumentEditorProxiesMutex);
279     for (int i = 0; i < InstrumentEditorProxies.size(); i++) {
280     InstrumentEditorProxy* pCurProxy =
281     dynamic_cast<InstrumentEditorProxy*>(
282     InstrumentEditorProxies[i]
283     );
284     if (pCurProxy->pEditor == pSender) {
285     pProxy = pCurProxy;
286     iProxyIndex = i;
287     pInstrument = pCurProxy->pInstrument;
288     }
289 schoenebeck 1653 }
290 schoenebeck 1212 }
291 persson 1455
292 schoenebeck 1659 if (!pProxy) {
293     std::cerr << "Eeeek, could not find instrument editor proxy, "
294     "this is a bug!\n" << std::flush;
295     return;
296     }
297    
298     // now unregister editor as not being available as a virtual MIDI device anymore
299     VirtualMidiDevice* pVirtualMidiDevice =
300     dynamic_cast<VirtualMidiDevice*>(pSender);
301     if (pVirtualMidiDevice) {
302     Lock();
303     // NOTE: see note in LaunchInstrumentEditor()
304 iliev 2012 std::set<EngineChannel*> engineChannels =
305 schoenebeck 1659 GetEngineChannelsUsing(pInstrument, false/*don't lock again*/);
306 iliev 2012 std::set<EngineChannel*>::iterator iter = engineChannels.begin();
307     std::set<EngineChannel*>::iterator end = engineChannels.end();
308 schoenebeck 1659 for (; iter != end; ++iter) (*iter)->Disconnect(pVirtualMidiDevice);
309     Unlock();
310     } else {
311     std::cerr << "Could not unregister editor as not longer acting as "
312     "virtual MIDI device. Wasn't it registered?\n"
313     << std::flush;
314     }
315    
316     // finally delete proxy entry and hand back instrument
317     if (pInstrument) {
318 persson 2427 {
319     LockGuard lock(InstrumentEditorProxiesMutex);
320     InstrumentEditorProxies.remove(iProxyIndex);
321     }
322 schoenebeck 1659
323     HandBack(pInstrument, pProxy);
324     delete pProxy;
325     }
326    
327 persson 1455 // Note that we don't need to free the editor here. As it
328     // derives from Thread, it will delete itself when the thread
329     // dies.
330 schoenebeck 1212 }
331    
332 schoenebeck 1662 #if 0 // currently unused :
333 schoenebeck 1653 /**
334     * Try to inform the respective instrument editor(s), that a note on
335     * event just occured. This method is called by the MIDI thread. If any
336     * obstacles are in the way (e.g. if a wait for an unlock would be
337     * required) we give up immediately, since the RT safeness of the MIDI
338     * thread has absolute priority.
339     */
340     void InstrumentResourceManager::TrySendNoteOnToEditors(uint8_t Key, uint8_t Velocity, ::gig::Instrument* pInstrument) {
341     const bool bGotLock = InstrumentEditorProxiesMutex.Trylock(); // naively assumes RT safe implementation
342     if (!bGotLock) return; // hell, forget it, not worth the hassle
343     for (int i = 0; i < InstrumentEditorProxies.size(); i++) {
344     InstrumentEditorProxy* pProxy =
345     dynamic_cast<InstrumentEditorProxy*>(
346     InstrumentEditorProxies[i]
347     );
348     if (pProxy->pInstrument == pInstrument)
349 schoenebeck 1659 pProxy->pEditor->SendNoteOnToDevice(Key, Velocity);
350 schoenebeck 1653 }
351     InstrumentEditorProxiesMutex.Unlock(); // naively assumes RT safe implementation
352     }
353    
354     /**
355     * Try to inform the respective instrument editor(s), that a note off
356     * event just occured. This method is called by the MIDI thread. If any
357     * obstacles are in the way (e.g. if a wait for an unlock would be
358     * required) we give up immediately, since the RT safeness of the MIDI
359     * thread has absolute priority.
360     */
361     void InstrumentResourceManager::TrySendNoteOffToEditors(uint8_t Key, uint8_t Velocity, ::gig::Instrument* pInstrument) {
362     const bool bGotLock = InstrumentEditorProxiesMutex.Trylock(); // naively assumes RT safe implementation
363     if (!bGotLock) return; // hell, forget it, not worth the hassle
364     for (int i = 0; i < InstrumentEditorProxies.size(); i++) {
365     InstrumentEditorProxy* pProxy =
366     dynamic_cast<InstrumentEditorProxy*>(
367     InstrumentEditorProxies[i]
368     );
369     if (pProxy->pInstrument == pInstrument)
370 schoenebeck 1659 pProxy->pEditor->SendNoteOffToDevice(Key, Velocity);
371 schoenebeck 1653 }
372     InstrumentEditorProxiesMutex.Unlock(); // naively assumes RT safe implementation
373     }
374 schoenebeck 1662 #endif // unused
375 schoenebeck 1653
376 schoenebeck 1321 void InstrumentResourceManager::OnSamplesToBeRemoved(std::set<void*> Samples, InstrumentEditor* pSender) {
377     if (Samples.empty()) {
378     std::cerr << "gig::InstrumentResourceManager: WARNING, "
379     "OnSamplesToBeRemoved() called with empty list, this "
380     "is a bug!\n" << std::flush;
381     return;
382     }
383     // TODO: ATM we assume here that all samples are from the same file
384     ::gig::Sample* pFirstSample = (::gig::Sample*) *Samples.begin();
385     ::gig::File* pCriticalFile = dynamic_cast< ::gig::File*>(pFirstSample->GetParent());
386     // completely suspend all engines that use that same file
387     SuspendEnginesUsing(pCriticalFile);
388     }
389    
390     void InstrumentResourceManager::OnSamplesRemoved(InstrumentEditor* pSender) {
391     // resume all previously, completely suspended engines
392     // (we don't have to un-cache the removed samples here, since that is
393     // automatically done by the gig::Sample destructor)
394     ResumeAllEngines();
395     }
396    
397     void InstrumentResourceManager::OnDataStructureToBeChanged(void* pStruct, String sStructType, InstrumentEditor* pSender) {
398 schoenebeck 2902 dmsg(5,("gig::InstrumentResourceManager::OnDataStructureToBeChanged(%s)\n", sStructType.c_str()));
399 schoenebeck 1321 //TODO: remove code duplication
400     if (sStructType == "gig::File") {
401     // completely suspend all engines that use that file
402     ::gig::File* pFile = (::gig::File*) pStruct;
403     SuspendEnginesUsing(pFile);
404     } else if (sStructType == "gig::Instrument") {
405     // completely suspend all engines that use that instrument
406     ::gig::Instrument* pInstrument = (::gig::Instrument*) pStruct;
407     SuspendEnginesUsing(pInstrument);
408     } else if (sStructType == "gig::Region") {
409     // only advice the engines to suspend the given region, so they'll
410     // only ignore that region (and probably already other suspended
411     // ones), but beside that continue normal playback
412     ::gig::Region* pRegion = (::gig::Region*) pStruct;
413     ::gig::Instrument* pInstrument =
414     (::gig::Instrument*) pRegion->GetParent();
415     Lock();
416 iliev 2012 std::set<Engine*> engines =
417 schoenebeck 1321 GetEnginesUsing(pInstrument, false/*don't lock again*/);
418 iliev 2012 std::set<Engine*>::iterator iter = engines.begin();
419     std::set<Engine*>::iterator end = engines.end();
420 schoenebeck 1321 for (; iter != end; ++iter) (*iter)->Suspend(pRegion);
421     Unlock();
422     } else if (sStructType == "gig::DimensionRegion") {
423     // only advice the engines to suspend the given DimensionRegions's
424     // parent region, so they'll only ignore that region (and probably
425     // already other suspended ones), but beside that continue normal
426     // playback
427     ::gig::DimensionRegion* pDimReg =
428     (::gig::DimensionRegion*) pStruct;
429     ::gig::Region* pRegion = pDimReg->GetParent();
430     ::gig::Instrument* pInstrument =
431     (::gig::Instrument*) pRegion->GetParent();
432     Lock();
433 iliev 2012 std::set<Engine*> engines =
434 schoenebeck 1321 GetEnginesUsing(pInstrument, false/*don't lock again*/);
435 iliev 2012 std::set<Engine*>::iterator iter = engines.begin();
436     std::set<Engine*>::iterator end = engines.end();
437 schoenebeck 1321 for (; iter != end; ++iter) (*iter)->Suspend(pRegion);
438     Unlock();
439 schoenebeck 2902 } else if (sStructType == "gig::Script") {
440     // no need to suspend anything here, since the sampler is
441     // processing a translated VM representation of the original script
442     // source code, not accessing the source code itself during playback
443     ::gig::Script* pScript = (::gig::Script*) pStruct;
444     // remember the original source code of the script, since the script
445     // resource manager uses the source code as key
446     pendingScriptUpdatesMutex.Lock();
447     pendingScriptUpdates[pScript] = pScript->GetScriptAsText();
448     pendingScriptUpdatesMutex.Unlock();
449 schoenebeck 1321 } else {
450     std::cerr << "gig::InstrumentResourceManager: ERROR, unknown data "
451     "structure '" << sStructType << "' requested to be "
452     "suspended by instrument editor. This is a bug!\n"
453     << std::flush;
454     //TODO: we should inform the instrument editor that something seriously went wrong
455     }
456     }
457    
458     void InstrumentResourceManager::OnDataStructureChanged(void* pStruct, String sStructType, InstrumentEditor* pSender) {
459 schoenebeck 2902 dmsg(5,("gig::InstrumentResourceManager::OnDataStructureChanged(%s)\n", sStructType.c_str()));
460 schoenebeck 1321 //TODO: remove code duplication
461     if (sStructType == "gig::File") {
462     // resume all previously suspended engines
463     ResumeAllEngines();
464     } else if (sStructType == "gig::Instrument") {
465     // resume all previously suspended engines
466     ResumeAllEngines();
467 schoenebeck 1852 } else if (sStructType == "gig::Sample") {
468     // we're assuming here, that OnDataStructureToBeChanged() with
469     // "gig::File" was called previously, so we won't resume anything
470     // here, but just re-cache the given sample
471     Lock();
472     ::gig::Sample* pSample = (::gig::Sample*) pStruct;
473     ::gig::File* pFile = (::gig::File*) pSample->GetParent();
474     UncacheInitialSamples(pSample);
475     // now re-cache ...
476     std::vector< ::gig::Instrument*> instruments =
477     GetInstrumentsCurrentlyUsedOf(pFile, false/*don't lock again*/);
478     for (int i = 0; i < instruments.size(); i++) {
479     if (SampleReferencedByInstrument(pSample, instruments[i])) {
480 iliev 2012 std::set<EngineChannel*> engineChannels =
481 schoenebeck 1852 GetEngineChannelsUsing(instruments[i], false/*don't lock again*/);
482 iliev 2012 std::set<EngineChannel*>::iterator iter = engineChannels.begin();
483     std::set<EngineChannel*>::iterator end = engineChannels.end();
484 schoenebeck 1852 for (; iter != end; ++iter)
485     CacheInitialSamples(pSample, *iter);
486     }
487     }
488     Unlock();
489 schoenebeck 1321 } else if (sStructType == "gig::Region") {
490     // advice the engines to resume the given region, that is to
491     // using it for playback again
492     ::gig::Region* pRegion = (::gig::Region*) pStruct;
493     ::gig::Instrument* pInstrument =
494     (::gig::Instrument*) pRegion->GetParent();
495     Lock();
496 iliev 2012 std::set<Engine*> engines =
497 schoenebeck 1321 GetEnginesUsing(pInstrument, false/*don't lock again*/);
498 iliev 2012 std::set<Engine*>::iterator iter = engines.begin();
499     std::set<Engine*>::iterator end = engines.end();
500 schoenebeck 1321 for (; iter != end; ++iter) (*iter)->Resume(pRegion);
501     Unlock();
502     } else if (sStructType == "gig::DimensionRegion") {
503     // advice the engines to resume the given DimensionRegion's parent
504     // region, that is to using it for playback again
505     ::gig::DimensionRegion* pDimReg =
506     (::gig::DimensionRegion*) pStruct;
507     ::gig::Region* pRegion = pDimReg->GetParent();
508     ::gig::Instrument* pInstrument =
509     (::gig::Instrument*) pRegion->GetParent();
510     Lock();
511 iliev 2012 std::set<Engine*> engines =
512 schoenebeck 1321 GetEnginesUsing(pInstrument, false/*don't lock again*/);
513 iliev 2012 std::set<Engine*>::iterator iter = engines.begin();
514     std::set<Engine*>::iterator end = engines.end();
515 schoenebeck 1321 for (; iter != end; ++iter) (*iter)->Resume(pRegion);
516     Unlock();
517 schoenebeck 2902 } else if (sStructType == "gig::Script") {
518     // inform all engine channels which are using this script, that
519     // they need to reload (parse) the script's source code text
520     ::gig::Script* pScript = (::gig::Script*) pStruct;
521     pendingScriptUpdatesMutex.Lock();
522     if (pendingScriptUpdates.count(pScript)) {
523     const String& code = pendingScriptUpdates[pScript];
524     std::set<EngineChannel*> channels = GetEngineChannelsUsingScriptSourceCode(code, true/*lock*/);
525     pendingScriptUpdates.erase(pScript);
526     std::set<EngineChannel*>::iterator iter = channels.begin();
527     std::set<EngineChannel*>::iterator end = channels.end();
528     for (; iter != end; ++iter) (*iter)->reloadScript(pScript);
529     }
530     pendingScriptUpdatesMutex.Unlock();
531 schoenebeck 1321 } else {
532     std::cerr << "gig::InstrumentResourceManager: ERROR, unknown data "
533     "structure '" << sStructType << "' requested to be "
534     "resumed by instrument editor. This is a bug!\n"
535     << std::flush;
536     //TODO: we should inform the instrument editor that something seriously went wrong
537     }
538     }
539    
540     void InstrumentResourceManager::OnSampleReferenceChanged(void* pOldSample, void* pNewSample, InstrumentEditor* pSender) {
541     // uncache old sample in case it's not used by anybody anymore
542     if (pOldSample) {
543     Lock();
544     ::gig::Sample* pSample = (::gig::Sample*) pOldSample;
545     ::gig::File* pFile = (::gig::File*) pSample->GetParent();
546 schoenebeck 1852 bool bSampleStillInUse = false;
547 schoenebeck 1321 std::vector< ::gig::Instrument*> instruments =
548     GetInstrumentsCurrentlyUsedOf(pFile, false/*don't lock again*/);
549 schoenebeck 1852 for (int i = 0; i < instruments.size(); i++) {
550     if (SampleReferencedByInstrument(pSample, instruments[i])) {
551     bSampleStillInUse = true;
552     break;
553     }
554     }
555     if (!bSampleStillInUse) UncacheInitialSamples(pSample);
556 schoenebeck 1321 Unlock();
557     }
558     // make sure new sample reference is cached
559     if (pNewSample) {
560     Lock();
561     ::gig::Sample* pSample = (::gig::Sample*) pNewSample;
562     ::gig::File* pFile = (::gig::File*) pSample->GetParent();
563     // get all engines that use that same gig::File
564 iliev 2012 std::set<Engine*> engines = GetEnginesUsing(pFile, false/*don't lock again*/);
565     std::set<Engine*>::iterator iter = engines.begin();
566     std::set<Engine*>::iterator end = engines.end();
567 schoenebeck 1321 for (; iter != end; ++iter)
568     CacheInitialSamples(pSample, *iter);
569     Unlock();
570     }
571     }
572    
573 schoenebeck 53 ::gig::Instrument* InstrumentResourceManager::Create(instrument_id_t Key, InstrumentConsumer* pConsumer, void*& pArg) {
574 schoenebeck 1321 // get gig file from internal gig file manager
575 persson 2185 ::gig::File* pGig = Gigs.Borrow(Key.FileName, reinterpret_cast<GigConsumer*>(Key.Index)); // conversion kinda hackish :/
576 schoenebeck 53
577 schoenebeck 517 // we pass this to the progress callback mechanism of libgig
578     progress_callback_arg_t callbackArg;
579     callbackArg.pManager = this;
580     callbackArg.pInstrumentKey = &Key;
581    
582     ::gig::progress_t progress;
583     progress.callback = OnInstrumentLoadingProgress;
584     progress.custom = &callbackArg;
585    
586 schoenebeck 947 dmsg(1,("Loading gig instrument ('%s',%d)...",Key.FileName.c_str(),Key.Index));
587     ::gig::Instrument* pInstrument = pGig->GetInstrument(Key.Index, &progress);
588 schoenebeck 53 if (!pInstrument) {
589     std::stringstream msg;
590 schoenebeck 947 msg << "There's no instrument with index " << Key.Index << ".";
591 schoenebeck 1212 throw InstrumentManagerException(msg.str());
592 schoenebeck 53 }
593     pGig->GetFirstSample(); // just to force complete instrument loading
594     dmsg(1,("OK\n"));
595    
596 persson 2326 uint maxSamplesPerCycle = GetMaxSamplesPerCycle(pConsumer);
597    
598 schoenebeck 53 // cache initial samples points (for actually needed samples)
599     dmsg(1,("Caching initial samples..."));
600 schoenebeck 517 uint iRegion = 0; // just for progress calculation
601 schoenebeck 53 ::gig::Region* pRgn = pInstrument->GetFirstRegion();
602     while (pRgn) {
603 schoenebeck 517 // we randomly schedule 90% for the .gig file loading and the remaining 10% now for sample caching
604     const float localProgress = 0.9f + 0.1f * (float) iRegion / (float) pInstrument->Regions;
605 schoenebeck 947 DispatchResourceProgressEvent(Key, localProgress);
606    
607 schoenebeck 354 if (pRgn->GetSample() && !pRgn->GetSample()->GetCache().Size) {
608 schoenebeck 53 dmsg(2,("C"));
609 persson 2326 CacheInitialSamples(pRgn->GetSample(), maxSamplesPerCycle);
610 schoenebeck 53 }
611     for (uint i = 0; i < pRgn->DimensionRegions; i++) {
612 persson 2326 CacheInitialSamples(pRgn->pDimensionRegions[i]->pSample, maxSamplesPerCycle);
613 schoenebeck 53 }
614    
615     pRgn = pInstrument->GetNextRegion();
616 schoenebeck 517 iRegion++;
617 schoenebeck 53 }
618     dmsg(1,("OK\n"));
619 schoenebeck 517 DispatchResourceProgressEvent(Key, 1.0f); // done; notify all consumers about progress 100%
620 schoenebeck 53
621     // we need the following for destruction later
622     instr_entry_t* pEntry = new instr_entry_t;
623 schoenebeck 947 pEntry->ID.FileName = Key.FileName;
624     pEntry->ID.Index = Key.Index;
625 persson 2326 pEntry->pFile = pGig;
626 persson 438
627 persson 2326 // and we save this to check if we need to reallocate for an engine with higher value of 'MaxSamplesPerSecond'
628     pEntry->MaxSamplesPerCycle = maxSamplesPerCycle;
629 schoenebeck 2275
630 schoenebeck 53 pArg = pEntry;
631    
632     return pInstrument;
633     }
634    
635 persson 2326 void InstrumentResourceManager::Destroy(::gig::Instrument* pResource, void* pArg) {
636 schoenebeck 53 instr_entry_t* pEntry = (instr_entry_t*) pArg;
637 schoenebeck 947 // we don't need the .gig file here anymore
638 persson 2326 Gigs.HandBack(pEntry->pFile, reinterpret_cast<GigConsumer*>(pEntry->ID.Index)); // conversion kinda hackish :/
639 schoenebeck 53 delete pEntry;
640     }
641    
642 iliev 2012 void InstrumentResourceManager::DeleteRegionIfNotUsed(::gig::DimensionRegion* pRegion, region_info_t* pRegInfo) {
643     // TODO: we could delete Region and Instrument here if they have become unused
644 persson 1038 }
645 schoenebeck 2275
646 iliev 2012 void InstrumentResourceManager::DeleteSampleIfNotUsed(::gig::Sample* pSample, region_info_t* pRegInfo) {
647     ::gig::File* gig = pRegInfo->file;
648     ::RIFF::File* riff = static_cast< ::RIFF::File*>(pRegInfo->pArg);
649     if (gig) {
650     gig->DeleteSample(pSample);
651     if (!gig->GetFirstSample()) {
652     dmsg(2,("No more samples in use - freeing gig\n"));
653     delete gig;
654     delete riff;
655 persson 1038 }
656     }
657     }
658    
659     /**
660 schoenebeck 1321 * Just a wrapper around the other @c CacheInitialSamples() method.
661     *
662     * @param pSample - points to the sample to be cached
663     * @param pEngine - pointer to Gig Engine Channel which caused this call
664     * (may be NULL, in this case default amount of samples
665     * will be cached)
666     */
667 iliev 2012 void InstrumentResourceManager::CacheInitialSamples(::gig::Sample* pSample, EngineChannel* pEngineChannel) {
668     Engine* pEngine =
669 schoenebeck 1321 (pEngineChannel && pEngineChannel->GetEngine()) ?
670 iliev 2012 dynamic_cast<Engine*>(pEngineChannel->GetEngine()) : NULL;
671 schoenebeck 1321 CacheInitialSamples(pSample, pEngine);
672     }
673    
674     /**
675 schoenebeck 53 * Caches a certain size at the beginning of the given sample in RAM. If the
676     * sample is very short, the whole sample will be loaded into RAM and thus
677     * no disk streaming is needed for this sample. Caching an initial part of
678     * samples is needed to compensate disk reading latency.
679     *
680     * @param pSample - points to the sample to be cached
681 schoenebeck 1321 * @param pEngine - pointer to Gig Engine which caused this call
682     * (may be NULL, in this case default amount of samples
683     * will be cached)
684 schoenebeck 53 */
685 iliev 2012 void InstrumentResourceManager::CacheInitialSamples(::gig::Sample* pSample, AbstractEngine* pEngine) {
686 persson 2326 uint maxSamplesPerCycle =
687     (pEngine) ? pEngine->pAudioOutputDevice->MaxSamplesPerCycle() :
688     DefaultMaxSamplesPerCycle();
689     CacheInitialSamples(pSample, maxSamplesPerCycle);
690     }
691    
692     void InstrumentResourceManager::CacheInitialSamples(::gig::Sample* pSample, uint maxSamplesPerCycle) {
693 schoenebeck 420 if (!pSample) {
694 persson 438 dmsg(4,("gig::InstrumentResourceManager: Skipping sample (pSample == NULL)\n"));
695 schoenebeck 420 return;
696     }
697     if (!pSample->SamplesTotal) return; // skip zero size samples
698 persson 438
699 schoenebeck 554 if (pSample->SamplesTotal <= CONFIG_PRELOAD_SAMPLES) {
700 schoenebeck 53 // Sample is too short for disk streaming, so we load the whole
701 schoenebeck 554 // sample into RAM and place 'pAudioIO->FragmentSize << CONFIG_MAX_PITCH'
702 schoenebeck 53 // number of '0' samples (silence samples) behind the official buffer
703     // border, to allow the interpolator do it's work even at the end of
704 persson 438 // the sample.
705 schoenebeck 3719 const uint neededSilenceSamples = uint((maxSamplesPerCycle << CONFIG_MAX_PITCH) + 6);
706 schoenebeck 3054 const uint currentlyCachedSilenceSamples = uint(pSample->GetCache().NullExtensionSize / pSample->FrameSize);
707 schoenebeck 420 if (currentlyCachedSilenceSamples < neededSilenceSamples) {
708 schoenebeck 3054 dmsg(3,("Caching whole sample (sample name: \"%s\", sample size: %llu)\n", pSample->pInfo->Name.c_str(), (long long)pSample->SamplesTotal));
709 schoenebeck 420 ::gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(neededSilenceSamples);
710 schoenebeck 3054 dmsg(4,("Cached %llu Bytes, %llu silence bytes.\n", (long long)buf.Size, (long long)buf.NullExtensionSize));
711 schoenebeck 420 }
712 schoenebeck 53 }
713 schoenebeck 554 else { // we only cache CONFIG_PRELOAD_SAMPLES and stream the other sample points from disk
714     if (!pSample->GetCache().Size) pSample->LoadSampleData(CONFIG_PRELOAD_SAMPLES);
715 schoenebeck 53 }
716    
717     if (!pSample->GetCache().Size) std::cerr << "Unable to cache sample - maybe memory full!" << std::endl << std::flush;
718     }
719    
720 schoenebeck 1321 void InstrumentResourceManager::UncacheInitialSamples(::gig::Sample* pSample) {
721 persson 2837 dmsg(1,("Uncaching sample %p\n",(void*)pSample));
722 schoenebeck 1321 if (pSample->GetCache().Size) pSample->ReleaseSampleData();
723     }
724 schoenebeck 53
725 schoenebeck 1321 /**
726     * Returns a list with all instruments currently in use, that are part of
727     * the given file.
728     *
729     * @param pFile - search criteria
730     * @param bLock - whether we should lock (mutex) the instrument manager
731     * during this call and unlock at the end of this call
732     */
733     std::vector< ::gig::Instrument*> InstrumentResourceManager::GetInstrumentsCurrentlyUsedOf(::gig::File* pFile, bool bLock) {
734     if (bLock) Lock();
735     std::vector< ::gig::Instrument*> result;
736     std::vector< ::gig::Instrument*> allInstruments = Resources(false/*don't lock again*/);
737     for (int i = 0; i < allInstruments.size(); i++)
738     if (
739     (::gig::File*) allInstruments[i]->GetParent()
740     == pFile
741     ) result.push_back(allInstruments[i]);
742     if (bLock) Unlock();
743     return result;
744     }
745 schoenebeck 53
746 schoenebeck 1321 /**
747 schoenebeck 1659 * Returns a list with all gig engine channels that are currently using
748 schoenebeck 2902 * the given real-time instrument script (provided as source code).
749     *
750     * @param pScript - search criteria
751     * @param bLock - whether we should lock (mutex) the instrument manager
752     * during this call and unlock at the end of this call
753     */
754     std::set<EngineChannel*> InstrumentResourceManager::GetEngineChannelsUsingScriptSourceCode(const String& code, bool bLock) {
755     if (bLock) Lock();
756     std::set<EngineChannel*> result;
757 schoenebeck 3733 std::set<InstrumentScriptConsumer*> consumers = scripts.ConsumersOf({
758     .code = code, .wildcardPatchVars = true
759     });
760 schoenebeck 2902 std::set<InstrumentScriptConsumer*>::iterator iter = consumers.begin();
761     std::set<InstrumentScriptConsumer*>::iterator end = consumers.end();
762     for (; iter != end; ++iter) {
763     EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(*iter);
764     if (!pEngineChannel) continue;
765     result.insert(pEngineChannel);
766     }
767     if (bLock) Unlock();
768     return result;
769     }
770    
771     /**
772     * Returns a list with all gig engine channels that are currently using
773 schoenebeck 1659 * the given instrument.
774     *
775     * @param pInstrument - search criteria
776     * @param bLock - whether we should lock (mutex) the instrument manager
777     * during this call and unlock at the end of this call
778     */
779 iliev 2012 std::set<EngineChannel*> InstrumentResourceManager::GetEngineChannelsUsing(::gig::Instrument* pInstrument, bool bLock) {
780 schoenebeck 1659 if (bLock) Lock();
781 iliev 2012 std::set<EngineChannel*> result;
782 schoenebeck 1659 std::set<ResourceConsumer< ::gig::Instrument>*> consumers = ConsumersOf(pInstrument);
783     std::set<ResourceConsumer< ::gig::Instrument>*>::iterator iter = consumers.begin();
784     std::set<ResourceConsumer< ::gig::Instrument>*>::iterator end = consumers.end();
785     for (; iter != end; ++iter) {
786 iliev 2012 EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(*iter);
787 schoenebeck 1659 if (!pEngineChannel) continue;
788     result.insert(pEngineChannel);
789     }
790     if (bLock) Unlock();
791     return result;
792     }
793    
794     /**
795 schoenebeck 1321 * Returns a list with all gig Engines that are currently using the given
796     * instrument.
797     *
798     * @param pInstrument - search criteria
799     * @param bLock - whether we should lock (mutex) the instrument manager
800     * during this call and unlock at the end of this call
801     */
802 iliev 2012 std::set<Engine*> InstrumentResourceManager::GetEnginesUsing(::gig::Instrument* pInstrument, bool bLock) {
803 schoenebeck 1321 if (bLock) Lock();
804 iliev 2012 std::set<Engine*> result;
805 schoenebeck 1321 std::set<ResourceConsumer< ::gig::Instrument>*> consumers = ConsumersOf(pInstrument);
806     std::set<ResourceConsumer< ::gig::Instrument>*>::iterator iter = consumers.begin();
807     std::set<ResourceConsumer< ::gig::Instrument>*>::iterator end = consumers.end();
808     for (; iter != end; ++iter) {
809 iliev 2012 EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(*iter);
810 schoenebeck 1321 if (!pEngineChannel) continue;
811 iliev 2012 Engine* pEngine = dynamic_cast<Engine*>(pEngineChannel->GetEngine());
812 schoenebeck 1321 if (!pEngine) continue;
813     result.insert(pEngine);
814     }
815     if (bLock) Unlock();
816     return result;
817     }
818    
819     /**
820     * Returns a list with all gig Engines that are currently using an
821     * instrument that is part of the given instrument file.
822     *
823     * @param pFile - search criteria
824     * @param bLock - whether we should lock (mutex) the instrument manager
825     * during this call and unlock at the end of this call
826     */
827 iliev 2012 std::set<Engine*> InstrumentResourceManager::GetEnginesUsing(::gig::File* pFile, bool bLock) {
828 schoenebeck 1321 if (bLock) Lock();
829     // get all instruments (currently in usage) that use that same gig::File
830     std::vector< ::gig::Instrument*> instrumentsOfInterest =
831     GetInstrumentsCurrentlyUsedOf(pFile, false/*don't lock again*/);
832    
833     // get all engines that use that same gig::File
834 iliev 2012 std::set<Engine*> result;
835 schoenebeck 1321 {
836     for (int i = 0; i < instrumentsOfInterest.size(); i++) {
837     std::set<ResourceConsumer< ::gig::Instrument>*> consumers = ConsumersOf(instrumentsOfInterest[i]);
838     std::set<ResourceConsumer< ::gig::Instrument>*>::iterator iter = consumers.begin();
839     std::set<ResourceConsumer< ::gig::Instrument>*>::iterator end = consumers.end();
840     for (; iter != end; ++iter) {
841 iliev 2012 EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(*iter);
842 schoenebeck 1321 if (!pEngineChannel) continue;
843 iliev 2012 Engine* pEngine = dynamic_cast<Engine*>(pEngineChannel->GetEngine());
844 schoenebeck 1321 if (!pEngine) continue;
845     // the unique, sorted container std::set makes
846     // sure we won't have duplicates
847     result.insert(pEngine);
848     }
849     }
850     }
851     if (bLock) Unlock();
852     return result;
853     }
854    
855     /**
856     * Returns @c true in case the given sample is referenced somewhere by the
857     * given instrument, @c false otherwise.
858     *
859     * @param pSample - sample reference
860     * @param pInstrument - instrument that might use that sample
861     */
862     bool InstrumentResourceManager::SampleReferencedByInstrument(::gig::Sample* pSample, ::gig::Instrument* pInstrument) {
863     for (
864     ::gig::Region* pRegion = pInstrument->GetFirstRegion();
865     pRegion; pRegion = pInstrument->GetNextRegion()
866     ) {
867     for (
868     int i = 0; i < pRegion->DimensionRegions &&
869     pRegion->pDimensionRegions[i]; i++
870     ) {
871     if (pRegion->pDimensionRegions[i]->pSample == pSample)
872     return true;
873     }
874     }
875     return false;
876     }
877    
878     /**
879     * Suspend all gig engines that use the given instrument. This means
880     * completely stopping playback on those engines and killing all their
881     * voices and disk streams. This method will block until all voices AND
882     * their disk streams are finally deleted and the engine turned into a
883     * complete idle loop.
884     *
885     * All @c SuspendEnginesUsing() methods only serve one thread by one and
886     * block all other threads until the current active thread called
887     * @c ResumeAllEngines() .
888     *
889     * @param pInstrument - search criteria
890     */
891     void InstrumentResourceManager::SuspendEnginesUsing(::gig::Instrument* pInstrument) {
892     // make sure no other thread suspends whole engines at the same time
893     suspendedEnginesMutex.Lock();
894     // get all engines that use that same gig::Instrument
895     suspendedEngines = GetEnginesUsing(pInstrument, true/*lock*/);
896     // finally, completely suspend all engines that use that same gig::Instrument
897 iliev 2012 std::set<Engine*>::iterator iter = suspendedEngines.begin();
898     std::set<Engine*>::iterator end = suspendedEngines.end();
899 schoenebeck 1321 for (; iter != end; ++iter) (*iter)->SuspendAll();
900     }
901    
902     /**
903     * Suspend all gig engines that use the given instrument file. This means
904     * completely stopping playback on those engines and killing all their
905     * voices and disk streams. This method will block until all voices AND
906     * their disk streams are finally deleted and the engine turned into a
907     * complete idle loop.
908     *
909     * All @c SuspendEnginesUsing() methods only serve one thread by one and
910     * block all other threads until the current active thread called
911     * @c ResumeAllEngines() .
912     *
913     * @param pFile - search criteria
914     */
915     void InstrumentResourceManager::SuspendEnginesUsing(::gig::File* pFile) {
916     // make sure no other thread suspends whole engines at the same time
917     suspendedEnginesMutex.Lock();
918     // get all engines that use that same gig::File
919     suspendedEngines = GetEnginesUsing(pFile, true/*lock*/);
920     // finally, completely suspend all engines that use that same gig::File
921 iliev 2012 std::set<Engine*>::iterator iter = suspendedEngines.begin();
922     std::set<Engine*>::iterator end = suspendedEngines.end();
923 schoenebeck 1321 for (; iter != end; ++iter) (*iter)->SuspendAll();
924     }
925    
926     /**
927     * MUST be called after one called one of the @c SuspendEnginesUsing()
928     * methods, to resume normal playback on all previously suspended engines.
929     * As it's only possible for one thread to suspend whole engines at the
930     * same time, this method doesn't take any arguments.
931     */
932     void InstrumentResourceManager::ResumeAllEngines() {
933     // resume all previously completely suspended engines
934     std::set<Engine*>::iterator iter = suspendedEngines.begin();
935     std::set<Engine*>::iterator end = suspendedEngines.end();
936     for (; iter != end; ++iter) (*iter)->ResumeAll();
937     // no more suspended engines ...
938     suspendedEngines.clear();
939     // allow another thread to suspend whole engines
940     suspendedEnginesMutex.Unlock();
941     }
942    
943    
944    
945 schoenebeck 53 // internal gig file manager
946    
947     ::gig::File* InstrumentResourceManager::GigResourceManager::Create(String Key, GigConsumer* pConsumer, void*& pArg) {
948     dmsg(1,("Loading gig file \'%s\'...", Key.c_str()));
949     ::RIFF::File* pRIFF = new ::RIFF::File(Key);
950     ::gig::File* pGig = new ::gig::File(pRIFF);
951     pArg = pRIFF;
952     dmsg(1,("OK\n"));
953     return pGig;
954     }
955    
956     void InstrumentResourceManager::GigResourceManager::Destroy(::gig::File* pResource, void* pArg) {
957 schoenebeck 2275 dmsg(1,("Freeing gig file '%s' from memory ...", pResource->GetFileName().c_str()));
958 persson 1038
959     // Delete as much as possible of the gig file. Some of the
960     // dimension regions and samples may still be in use - these
961     // will be deleted later by the HandBackDimReg function.
962     bool deleteFile = true;
963     ::gig::Instrument* nextInstrument;
964     for (::gig::Instrument* instrument = pResource->GetFirstInstrument() ;
965     instrument ;
966     instrument = nextInstrument) {
967     nextInstrument = pResource->GetNextInstrument();
968     bool deleteInstrument = true;
969     ::gig::Region* nextRegion;
970     for (::gig::Region *region = instrument->GetFirstRegion() ;
971     region ;
972     region = nextRegion) {
973     nextRegion = instrument->GetNextRegion();
974     bool deleteRegion = true;
975     for (int i = 0 ; i < region->DimensionRegions ; i++)
976     {
977     ::gig::DimensionRegion *d = region->pDimensionRegions[i];
978 iliev 2012 std::map< ::gig::DimensionRegion*, region_info_t>::iterator iter = parent->RegionInfo.find(d);
979     if (iter != parent->RegionInfo.end()) {
980     region_info_t& dimRegInfo = (*iter).second;
981 persson 1038 dimRegInfo.file = pResource;
982 iliev 2012 dimRegInfo.pArg = (::RIFF::File*)pArg;
983 persson 1038 deleteFile = deleteInstrument = deleteRegion = false;
984     }
985     }
986     if (deleteRegion) instrument->DeleteRegion(region);
987     }
988     if (deleteInstrument) pResource->DeleteInstrument(instrument);
989     }
990     if (deleteFile) {
991     delete pResource;
992     delete (::RIFF::File*) pArg;
993     } else {
994     dmsg(2,("keeping some samples that are in use..."));
995     ::gig::Sample* nextSample;
996     for (::gig::Sample* sample = pResource->GetFirstSample() ;
997     sample ;
998     sample = nextSample) {
999     nextSample = pResource->GetNextSample();
1000     if (parent->SampleRefCount.find(sample) == parent->SampleRefCount.end()) {
1001     pResource->DeleteSample(sample);
1002     }
1003     }
1004     }
1005 schoenebeck 53 dmsg(1,("OK\n"));
1006     }
1007    
1008     }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC