/[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 2275 - (hide annotations) (download)
Mon Sep 19 21:48:45 2011 UTC (12 years, 7 months ago) by schoenebeck
File size: 46753 byte(s)
* Bugfix: When creating MIDI instrument map entries with "PERSISTENT"
  type, the instruments were uselessly precached with zero samples,
  however it still took the full preloading time and on 1st program
  change the respective instrument was completely reloaded again.
* Bumped version to 1.0.0.svn15

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

  ViewVC Help
Powered by ViewVC