/[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 2012 - (hide annotations) (download)
Fri Oct 23 17:53:17 2009 UTC (14 years, 6 months ago) by iliev
File size: 46964 byte(s)
* Refactoring: moved the independent code from
  the Gigasampler format engine to base classes
* SFZ format engine: experimental code (not usable yet)
* SoundFont format engine: experimental code (not usable yet)
* Fixed crash which may occur when MIDI key + transpose is out of range

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

  ViewVC Help
Powered by ViewVC