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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.56  
changed lines
  Added in v.1876

  ViewVC Help
Powered by ViewVC