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

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

  ViewVC Help
Powered by ViewVC