/[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 2309 - (hide annotations) (download)
Mon Jan 30 10:40:19 2012 UTC (12 years, 2 months ago) by iliev
File size: 46798 byte(s)
* fixed bug #162

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 capela 2291 Engine* pEngine = dynamic_cast<Engine*>(pEngineChannel->GetEngine());
608     AudioOutputDevice* pDevice = (pEngine) ? pEngine->pAudioOutputDevice : NULL;
609 schoenebeck 411 // and we save this to check if we need to reallocate for a engine with higher value of 'MaxSamplesPerSecond'
610     pEntry->MaxSamplesPerCycle =
611 schoenebeck 2275 (pDevice) ? pDevice->MaxSamplesPerCycle() : DefaultMaxSamplesPerCycle();
612    
613 schoenebeck 53 pArg = pEntry;
614    
615     return pInstrument;
616     }
617    
618     void InstrumentResourceManager::Destroy( ::gig::Instrument* pResource, void* pArg) {
619     instr_entry_t* pEntry = (instr_entry_t*) pArg;
620 schoenebeck 947 // we don't need the .gig file here anymore
621 persson 2185 Gigs.HandBack(pEntry->pGig, reinterpret_cast<GigConsumer*>(pEntry->ID.Index)); // conversion kinda hackish :/
622 schoenebeck 53 delete pEntry;
623     }
624    
625     void InstrumentResourceManager::OnBorrow(::gig::Instrument* pResource, InstrumentConsumer* pConsumer, void*& pArg) {
626     instr_entry_t* pEntry = (instr_entry_t*) pArg;
627 schoenebeck 2275
628     // (try to resolve the audio device context)
629 iliev 2012 EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(pConsumer);
630 iliev 2309 Engine* pEngine = pEngineChannel ? dynamic_cast<Engine*>(pEngineChannel->GetEngine()) : NULL;
631 capela 2291 AudioOutputDevice* pDevice = (pEngine) ? pEngine->pAudioOutputDevice : NULL;
632 schoenebeck 2275
633 schoenebeck 411 uint maxSamplesPerCycle =
634 schoenebeck 2275 (pDevice) ? pDevice->MaxSamplesPerCycle() : DefaultMaxSamplesPerCycle();
635    
636 schoenebeck 411 if (pEntry->MaxSamplesPerCycle < maxSamplesPerCycle) {
637 schoenebeck 2275 dmsg(1,("Completely reloading instrument due to insufficient precached samples ...\n"));
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 schoenebeck 2275
646 iliev 2012 void InstrumentResourceManager::DeleteSampleIfNotUsed(::gig::Sample* pSample, region_info_t* pRegInfo) {
647     ::gig::File* gig = pRegInfo->file;
648     ::RIFF::File* riff = static_cast< ::RIFF::File*>(pRegInfo->pArg);
649     if (gig) {
650     gig->DeleteSample(pSample);
651     if (!gig->GetFirstSample()) {
652     dmsg(2,("No more samples in use - freeing gig\n"));
653     delete gig;
654     delete riff;
655 persson 1038 }
656     }
657     }
658    
659     /**
660 schoenebeck 1321 * Just a wrapper around the other @c CacheInitialSamples() method.
661     *
662     * @param pSample - points to the sample to be cached
663     * @param pEngine - pointer to Gig Engine Channel which caused this call
664     * (may be NULL, in this case default amount of samples
665     * will be cached)
666     */
667 iliev 2012 void InstrumentResourceManager::CacheInitialSamples(::gig::Sample* pSample, EngineChannel* pEngineChannel) {
668     Engine* pEngine =
669 schoenebeck 1321 (pEngineChannel && pEngineChannel->GetEngine()) ?
670 iliev 2012 dynamic_cast<Engine*>(pEngineChannel->GetEngine()) : NULL;
671 schoenebeck 1321 CacheInitialSamples(pSample, pEngine);
672     }
673    
674     /**
675 schoenebeck 53 * Caches a certain size at the beginning of the given sample in RAM. If the
676     * sample is very short, the whole sample will be loaded into RAM and thus
677     * no disk streaming is needed for this sample. Caching an initial part of
678     * samples is needed to compensate disk reading latency.
679     *
680     * @param pSample - points to the sample to be cached
681 schoenebeck 1321 * @param pEngine - pointer to Gig Engine which caused this call
682     * (may be NULL, in this case default amount of samples
683     * will be cached)
684 schoenebeck 53 */
685 iliev 2012 void InstrumentResourceManager::CacheInitialSamples(::gig::Sample* pSample, AbstractEngine* pEngine) {
686 schoenebeck 420 if (!pSample) {
687 persson 438 dmsg(4,("gig::InstrumentResourceManager: Skipping sample (pSample == NULL)\n"));
688 schoenebeck 420 return;
689     }
690     if (!pSample->SamplesTotal) return; // skip zero size samples
691 persson 438
692 schoenebeck 554 if (pSample->SamplesTotal <= CONFIG_PRELOAD_SAMPLES) {
693 schoenebeck 53 // Sample is too short for disk streaming, so we load the whole
694 schoenebeck 554 // sample into RAM and place 'pAudioIO->FragmentSize << CONFIG_MAX_PITCH'
695 schoenebeck 53 // number of '0' samples (silence samples) behind the official buffer
696     // border, to allow the interpolator do it's work even at the end of
697 persson 438 // the sample.
698 schoenebeck 411 const uint maxSamplesPerCycle =
699 schoenebeck 1321 (pEngine) ? pEngine->pAudioOutputDevice->MaxSamplesPerCycle()
700 schoenebeck 2275 : DefaultMaxSamplesPerCycle();
701 schoenebeck 554 const uint neededSilenceSamples = (maxSamplesPerCycle << CONFIG_MAX_PITCH) + 3;
702 schoenebeck 420 const uint currentlyCachedSilenceSamples = pSample->GetCache().NullExtensionSize / pSample->FrameSize;
703     if (currentlyCachedSilenceSamples < neededSilenceSamples) {
704     dmsg(3,("Caching whole sample (sample name: \"%s\", sample size: %d)\n", pSample->pInfo->Name.c_str(), pSample->SamplesTotal));
705     ::gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(neededSilenceSamples);
706     dmsg(4,("Cached %d Bytes, %d silence bytes.\n", buf.Size, buf.NullExtensionSize));
707     }
708 schoenebeck 53 }
709 schoenebeck 554 else { // we only cache CONFIG_PRELOAD_SAMPLES and stream the other sample points from disk
710     if (!pSample->GetCache().Size) pSample->LoadSampleData(CONFIG_PRELOAD_SAMPLES);
711 schoenebeck 53 }
712    
713     if (!pSample->GetCache().Size) std::cerr << "Unable to cache sample - maybe memory full!" << std::endl << std::flush;
714     }
715    
716 schoenebeck 1321 void InstrumentResourceManager::UncacheInitialSamples(::gig::Sample* pSample) {
717     dmsg(1,("Uncaching sample %x\n",pSample));
718     if (pSample->GetCache().Size) pSample->ReleaseSampleData();
719     }
720 schoenebeck 53
721 schoenebeck 1321 /**
722     * Returns a list with all instruments currently in use, that are part of
723     * the given file.
724     *
725     * @param pFile - search criteria
726     * @param bLock - whether we should lock (mutex) the instrument manager
727     * during this call and unlock at the end of this call
728     */
729     std::vector< ::gig::Instrument*> InstrumentResourceManager::GetInstrumentsCurrentlyUsedOf(::gig::File* pFile, bool bLock) {
730     if (bLock) Lock();
731     std::vector< ::gig::Instrument*> result;
732     std::vector< ::gig::Instrument*> allInstruments = Resources(false/*don't lock again*/);
733     for (int i = 0; i < allInstruments.size(); i++)
734     if (
735     (::gig::File*) allInstruments[i]->GetParent()
736     == pFile
737     ) result.push_back(allInstruments[i]);
738     if (bLock) Unlock();
739     return result;
740     }
741 schoenebeck 53
742 schoenebeck 1321 /**
743 schoenebeck 1659 * Returns a list with all gig engine channels that are currently using
744     * the given instrument.
745     *
746     * @param pInstrument - search criteria
747     * @param bLock - whether we should lock (mutex) the instrument manager
748     * during this call and unlock at the end of this call
749     */
750 iliev 2012 std::set<EngineChannel*> InstrumentResourceManager::GetEngineChannelsUsing(::gig::Instrument* pInstrument, bool bLock) {
751 schoenebeck 1659 if (bLock) Lock();
752 iliev 2012 std::set<EngineChannel*> result;
753 schoenebeck 1659 std::set<ResourceConsumer< ::gig::Instrument>*> consumers = ConsumersOf(pInstrument);
754     std::set<ResourceConsumer< ::gig::Instrument>*>::iterator iter = consumers.begin();
755     std::set<ResourceConsumer< ::gig::Instrument>*>::iterator end = consumers.end();
756     for (; iter != end; ++iter) {
757 iliev 2012 EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(*iter);
758 schoenebeck 1659 if (!pEngineChannel) continue;
759     result.insert(pEngineChannel);
760     }
761     if (bLock) Unlock();
762     return result;
763     }
764    
765     /**
766 schoenebeck 1321 * Returns a list with all gig Engines that are currently using the given
767     * instrument.
768     *
769     * @param pInstrument - search criteria
770     * @param bLock - whether we should lock (mutex) the instrument manager
771     * during this call and unlock at the end of this call
772     */
773 iliev 2012 std::set<Engine*> InstrumentResourceManager::GetEnginesUsing(::gig::Instrument* pInstrument, bool bLock) {
774 schoenebeck 1321 if (bLock) Lock();
775 iliev 2012 std::set<Engine*> result;
776 schoenebeck 1321 std::set<ResourceConsumer< ::gig::Instrument>*> consumers = ConsumersOf(pInstrument);
777     std::set<ResourceConsumer< ::gig::Instrument>*>::iterator iter = consumers.begin();
778     std::set<ResourceConsumer< ::gig::Instrument>*>::iterator end = consumers.end();
779     for (; iter != end; ++iter) {
780 iliev 2012 EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(*iter);
781 schoenebeck 1321 if (!pEngineChannel) continue;
782 iliev 2012 Engine* pEngine = dynamic_cast<Engine*>(pEngineChannel->GetEngine());
783 schoenebeck 1321 if (!pEngine) continue;
784     result.insert(pEngine);
785     }
786     if (bLock) Unlock();
787     return result;
788     }
789    
790     /**
791     * Returns a list with all gig Engines that are currently using an
792     * instrument that is part of the given instrument file.
793     *
794     * @param pFile - search criteria
795     * @param bLock - whether we should lock (mutex) the instrument manager
796     * during this call and unlock at the end of this call
797     */
798 iliev 2012 std::set<Engine*> InstrumentResourceManager::GetEnginesUsing(::gig::File* pFile, bool bLock) {
799 schoenebeck 1321 if (bLock) Lock();
800     // get all instruments (currently in usage) that use that same gig::File
801     std::vector< ::gig::Instrument*> instrumentsOfInterest =
802     GetInstrumentsCurrentlyUsedOf(pFile, false/*don't lock again*/);
803    
804     // get all engines that use that same gig::File
805 iliev 2012 std::set<Engine*> result;
806 schoenebeck 1321 {
807     for (int i = 0; i < instrumentsOfInterest.size(); i++) {
808     std::set<ResourceConsumer< ::gig::Instrument>*> consumers = ConsumersOf(instrumentsOfInterest[i]);
809     std::set<ResourceConsumer< ::gig::Instrument>*>::iterator iter = consumers.begin();
810     std::set<ResourceConsumer< ::gig::Instrument>*>::iterator end = consumers.end();
811     for (; iter != end; ++iter) {
812 iliev 2012 EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(*iter);
813 schoenebeck 1321 if (!pEngineChannel) continue;
814 iliev 2012 Engine* pEngine = dynamic_cast<Engine*>(pEngineChannel->GetEngine());
815 schoenebeck 1321 if (!pEngine) continue;
816     // the unique, sorted container std::set makes
817     // sure we won't have duplicates
818     result.insert(pEngine);
819     }
820     }
821     }
822     if (bLock) Unlock();
823     return result;
824     }
825    
826     /**
827     * Returns @c true in case the given sample is referenced somewhere by the
828     * given instrument, @c false otherwise.
829     *
830     * @param pSample - sample reference
831     * @param pInstrument - instrument that might use that sample
832     */
833     bool InstrumentResourceManager::SampleReferencedByInstrument(::gig::Sample* pSample, ::gig::Instrument* pInstrument) {
834     for (
835     ::gig::Region* pRegion = pInstrument->GetFirstRegion();
836     pRegion; pRegion = pInstrument->GetNextRegion()
837     ) {
838     for (
839     int i = 0; i < pRegion->DimensionRegions &&
840     pRegion->pDimensionRegions[i]; i++
841     ) {
842     if (pRegion->pDimensionRegions[i]->pSample == pSample)
843     return true;
844     }
845     }
846     return false;
847     }
848    
849     /**
850     * Suspend all gig engines that use the given instrument. This means
851     * completely stopping playback on those engines and killing all their
852     * voices and disk streams. This method will block until all voices AND
853     * their disk streams are finally deleted and the engine turned into a
854     * complete idle loop.
855     *
856     * All @c SuspendEnginesUsing() methods only serve one thread by one and
857     * block all other threads until the current active thread called
858     * @c ResumeAllEngines() .
859     *
860     * @param pInstrument - search criteria
861     */
862     void InstrumentResourceManager::SuspendEnginesUsing(::gig::Instrument* pInstrument) {
863     // make sure no other thread suspends whole engines at the same time
864     suspendedEnginesMutex.Lock();
865     // get all engines that use that same gig::Instrument
866     suspendedEngines = GetEnginesUsing(pInstrument, true/*lock*/);
867     // finally, completely suspend all engines that use that same gig::Instrument
868 iliev 2012 std::set<Engine*>::iterator iter = suspendedEngines.begin();
869     std::set<Engine*>::iterator end = suspendedEngines.end();
870 schoenebeck 1321 for (; iter != end; ++iter) (*iter)->SuspendAll();
871     }
872    
873     /**
874     * Suspend all gig engines that use the given instrument file. This means
875     * completely stopping playback on those engines and killing all their
876     * voices and disk streams. This method will block until all voices AND
877     * their disk streams are finally deleted and the engine turned into a
878     * complete idle loop.
879     *
880     * All @c SuspendEnginesUsing() methods only serve one thread by one and
881     * block all other threads until the current active thread called
882     * @c ResumeAllEngines() .
883     *
884     * @param pFile - search criteria
885     */
886     void InstrumentResourceManager::SuspendEnginesUsing(::gig::File* pFile) {
887     // make sure no other thread suspends whole engines at the same time
888     suspendedEnginesMutex.Lock();
889     // get all engines that use that same gig::File
890     suspendedEngines = GetEnginesUsing(pFile, true/*lock*/);
891     // finally, completely suspend all engines that use that same gig::File
892 iliev 2012 std::set<Engine*>::iterator iter = suspendedEngines.begin();
893     std::set<Engine*>::iterator end = suspendedEngines.end();
894 schoenebeck 1321 for (; iter != end; ++iter) (*iter)->SuspendAll();
895     }
896    
897     /**
898     * MUST be called after one called one of the @c SuspendEnginesUsing()
899     * methods, to resume normal playback on all previously suspended engines.
900     * As it's only possible for one thread to suspend whole engines at the
901     * same time, this method doesn't take any arguments.
902     */
903     void InstrumentResourceManager::ResumeAllEngines() {
904     // resume all previously completely suspended engines
905     std::set<Engine*>::iterator iter = suspendedEngines.begin();
906     std::set<Engine*>::iterator end = suspendedEngines.end();
907     for (; iter != end; ++iter) (*iter)->ResumeAll();
908     // no more suspended engines ...
909     suspendedEngines.clear();
910     // allow another thread to suspend whole engines
911     suspendedEnginesMutex.Unlock();
912     }
913    
914    
915    
916 schoenebeck 53 // internal gig file manager
917    
918     ::gig::File* InstrumentResourceManager::GigResourceManager::Create(String Key, GigConsumer* pConsumer, void*& pArg) {
919     dmsg(1,("Loading gig file \'%s\'...", Key.c_str()));
920     ::RIFF::File* pRIFF = new ::RIFF::File(Key);
921     ::gig::File* pGig = new ::gig::File(pRIFF);
922     pArg = pRIFF;
923     dmsg(1,("OK\n"));
924     return pGig;
925     }
926    
927     void InstrumentResourceManager::GigResourceManager::Destroy(::gig::File* pResource, void* pArg) {
928 schoenebeck 2275 dmsg(1,("Freeing gig file '%s' from memory ...", pResource->GetFileName().c_str()));
929 persson 1038
930     // Delete as much as possible of the gig file. Some of the
931     // dimension regions and samples may still be in use - these
932     // will be deleted later by the HandBackDimReg function.
933     bool deleteFile = true;
934     ::gig::Instrument* nextInstrument;
935     for (::gig::Instrument* instrument = pResource->GetFirstInstrument() ;
936     instrument ;
937     instrument = nextInstrument) {
938     nextInstrument = pResource->GetNextInstrument();
939     bool deleteInstrument = true;
940     ::gig::Region* nextRegion;
941     for (::gig::Region *region = instrument->GetFirstRegion() ;
942     region ;
943     region = nextRegion) {
944     nextRegion = instrument->GetNextRegion();
945     bool deleteRegion = true;
946     for (int i = 0 ; i < region->DimensionRegions ; i++)
947     {
948     ::gig::DimensionRegion *d = region->pDimensionRegions[i];
949 iliev 2012 std::map< ::gig::DimensionRegion*, region_info_t>::iterator iter = parent->RegionInfo.find(d);
950     if (iter != parent->RegionInfo.end()) {
951     region_info_t& dimRegInfo = (*iter).second;
952 persson 1038 dimRegInfo.file = pResource;
953 iliev 2012 dimRegInfo.pArg = (::RIFF::File*)pArg;
954 persson 1038 deleteFile = deleteInstrument = deleteRegion = false;
955     }
956     }
957     if (deleteRegion) instrument->DeleteRegion(region);
958     }
959     if (deleteInstrument) pResource->DeleteInstrument(instrument);
960     }
961     if (deleteFile) {
962     delete pResource;
963     delete (::RIFF::File*) pArg;
964     } else {
965     dmsg(2,("keeping some samples that are in use..."));
966     ::gig::Sample* nextSample;
967     for (::gig::Sample* sample = pResource->GetFirstSample() ;
968     sample ;
969     sample = nextSample) {
970     nextSample = pResource->GetNextSample();
971     if (parent->SampleRefCount.find(sample) == parent->SampleRefCount.end()) {
972     pResource->DeleteSample(sample);
973     }
974     }
975     }
976 schoenebeck 53 dmsg(1,("OK\n"));
977     }
978    
979     }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC