/[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 1646 by persson, Sun Jan 20 15:04:51 2008 UTC revision 2012 by iliev, Fri Oct 23 17:53:17 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 - 2008 Christian Schoenebeck                       *   *   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 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"  #include "../../common/global_private.h"
31  #include "../../plugins/InstrumentEditorFactory.h"  #include "../../plugins/InstrumentEditorFactory.h"
# Line 67  namespace LinuxSampler { namespace gig { Line 69  namespace LinuxSampler { namespace gig {
69    
70          // the instrument we borrowed on behalf of the editor          // the instrument we borrowed on behalf of the editor
71          ::gig::Instrument* pInstrument;          ::gig::Instrument* pInstrument;
72            // the instrument editor we work on behalf
73            InstrumentEditor* pEditor;
74      };      };
75    
76      /**      /**
# Line 90  namespace LinuxSampler { namespace gig { Line 94  namespace LinuxSampler { namespace gig {
94          return Entries();          return Entries();
95      }      }
96    
     InstrumentManager::mode_t InstrumentResourceManager::GetMode(const instrument_id_t& ID) {  
         return static_cast<InstrumentManager::mode_t>(AvailabilityMode(ID));  
     }  
   
     void InstrumentResourceManager::SetMode(const instrument_id_t& ID, InstrumentManager::mode_t Mode) {  
         dmsg(2,("gig::InstrumentResourceManager: setting mode for %s (Index=%d) to %d\n",ID.FileName.c_str(),ID.Index,Mode));  
         SetAvailabilityMode(ID, static_cast<ResourceManager<InstrumentManager::instrument_id_t, ::gig::Instrument>::mode_t>(Mode));  
     }  
   
97      String InstrumentResourceManager::GetInstrumentName(instrument_id_t ID) {      String InstrumentResourceManager::GetInstrumentName(instrument_id_t ID) {
98          Lock();          Lock();
99          ::gig::Instrument* pInstrument = Resource(ID, false);          ::gig::Instrument* pInstrument = Resource(ID, false);
# Line 144  namespace LinuxSampler { namespace gig { Line 139  namespace LinuxSampler { namespace gig {
139      }      }
140    
141      InstrumentResourceManager::instrument_info_t InstrumentResourceManager::GetInstrumentInfo(instrument_id_t ID) throw (InstrumentManagerException) {      InstrumentResourceManager::instrument_info_t InstrumentResourceManager::GetInstrumentInfo(instrument_id_t ID) throw (InstrumentManagerException) {
142          std::vector<instrument_id_t> result;          Lock();
143            ::gig::Instrument* pInstrument = Resource(ID, false);
144            bool loaded = (pInstrument != NULL);
145            if (!loaded) Unlock();
146    
147          ::RIFF::File* riff = NULL;          ::RIFF::File* riff = NULL;
148          ::gig::File*  gig  = NULL;          ::gig::File*  gig  = NULL;
149          try {          try {
150              riff = new ::RIFF::File(ID.FileName);              if(!loaded) {
151              gig  = new ::gig::File(riff);                  riff = new ::RIFF::File(ID.FileName);
152              gig->SetAutoLoad(false); // avoid time consuming samples scanning                  gig  = new ::gig::File(riff);
153              ::gig::Instrument* pInstrument = gig->GetInstrument(ID.Index);                  gig->SetAutoLoad(false); // avoid time consuming samples scanning
154                    pInstrument = gig->GetInstrument(ID.Index);
155                }
156    
157              if (!pInstrument) throw InstrumentManagerException("There is no instrument " + ToString(ID.Index) + " in " + ID.FileName);              if (!pInstrument) throw InstrumentManagerException("There is no instrument " + ToString(ID.Index) + " in " + ID.FileName);
158    
159              instrument_info_t info;              instrument_info_t info;
160              if (gig->pVersion) {              for (int i = 0; i < 128; i++) { info.KeyBindings[i] = info.KeySwitchBindings[i] = 0; }
161                  info.FormatVersion = ToString(gig->pVersion->major);  
162                  info.Product = gig->pInfo->Product;              ::gig::File* pFile = (::gig::File*) pInstrument->GetParent();
163                  info.Artists = gig->pInfo->Artists;  
164                if (pFile->pVersion) {
165                    info.FormatVersion = ToString(pFile->pVersion->major);
166                    info.Product = pFile->pInfo->Product;
167                    info.Artists = pFile->pInfo->Artists;
168              }              }
169    
170              info.InstrumentName = pInstrument->pInfo->Name;              info.InstrumentName = pInstrument->pInfo->Name;
171    
172                ::gig::Region* pRegion = pInstrument->GetFirstRegion();
173                while (pRegion) {
174                    int low = pRegion->KeyRange.low;
175                    int high = pRegion->KeyRange.high;
176                    if (low < 0 || low > 127 || high < 0 || high > 127 || low > high) {
177                        std::cerr << "Invalid key range: " << low << " - " << high << std::endl;
178                    } else {
179                        for (int i = low; i <= high; i++) info.KeyBindings[i] = 1;
180                    }
181    
182                    pRegion = pInstrument->GetNextRegion();
183                }
184    
185                if (loaded) { // retrieve keyswitching only if the instrument is fully loaded.
186    
187                    // only return keyswitch range if keyswitching is used
188                    bool hasKeyswitches = false;
189                    for (::gig::Region* pRegion = pInstrument->GetFirstRegion() ;
190                         pRegion && !hasKeyswitches ;
191                         pRegion = pInstrument->GetNextRegion()) {
192                        for (int i = 0 ; i < pRegion->Dimensions ; i++) {
193                            if (pRegion->pDimensionDefinitions[i].dimension == ::gig::dimension_keyboard) {
194                                hasKeyswitches = true;
195                                break;
196                            }
197                        }
198                    }
199    
200                    if (hasKeyswitches) {
201                        int low = pInstrument->DimensionKeyRange.low;
202                        int high = pInstrument->DimensionKeyRange.high;
203                        if (low < 0 || low > 127 || high < 0 || high > 127 || low > high) {
204                            std::cerr << "Invalid keyswitch range: " << low << " - " << high << std::endl;
205                        } else {
206                            for (int i = low; i <= high; i++) info.KeySwitchBindings[i] = 1;
207                        }
208                    }
209                }
210    
211                if (loaded) Unlock();
212    
213              if (gig)  delete gig;              if (gig)  delete gig;
214              if (riff) delete riff;              if (riff) delete riff;
215              return info;              return info;
216          } catch (::RIFF::Exception e) {          } catch (::RIFF::Exception e) {
217                if (loaded) Unlock();
218              if (gig)  delete gig;              if (gig)  delete gig;
219              if (riff) delete riff;              if (riff) delete riff;
220              throw InstrumentManagerException(e.Message);              throw InstrumentManagerException(e.Message);
221          } catch (...) {          } catch (...) {
222                if (loaded) Unlock();
223              if (gig)  delete gig;              if (gig)  delete gig;
224              if (riff) delete riff;              if (riff) delete riff;
225              throw InstrumentManagerException("Unknown exception while trying to parse '" + ID.FileName + "'");              throw InstrumentManagerException("Unknown exception while trying to parse '" + ID.FileName + "'");
226          }          }
227      }      }
228    
229      void InstrumentResourceManager::LaunchInstrumentEditor(instrument_id_t ID) throw (InstrumentManagerException) {      InstrumentEditor* InstrumentResourceManager::LaunchInstrumentEditor(instrument_id_t ID, void* pUserData) throw (InstrumentManagerException) {
230          const String sDataType    = GetInstrumentDataStructureName(ID);          const String sDataType    = GetInstrumentDataStructureName(ID);
231          const String sDataVersion = GetInstrumentDataStructureVersion(ID);          const String sDataVersion = GetInstrumentDataStructureVersion(ID);
232          // find instrument editors capable to handle given instrument          // find instrument editors capable to handle given instrument
# Line 196  namespace LinuxSampler { namespace gig { Line 248  namespace LinuxSampler { namespace gig {
248          ::gig::Instrument* pInstrument = Borrow(ID, pProxy);          ::gig::Instrument* pInstrument = Borrow(ID, pProxy);
249          // remember the proxy and instrument for this instrument editor          // remember the proxy and instrument for this instrument editor
250          pProxy->pInstrument = pInstrument;          pProxy->pInstrument = pInstrument;
251            pProxy->pEditor     = pEditor;
252          InstrumentEditorProxiesMutex.Lock();          InstrumentEditorProxiesMutex.Lock();
253          InstrumentEditorProxies[pEditor] = pProxy;          InstrumentEditorProxies.add(pProxy);
254          InstrumentEditorProxiesMutex.Unlock();          InstrumentEditorProxiesMutex.Unlock();
255          // launch the instrument editor for the given instrument          // launch the instrument editor for the given instrument
256          pEditor->Launch(pInstrument, sDataType, sDataVersion);          pEditor->Launch(pInstrument, sDataType, sDataVersion, pUserData);
257    
258            // register the instrument editor as virtual MIDI device as well ...
259            VirtualMidiDevice* pVirtualMidiDevice =
260                dynamic_cast<VirtualMidiDevice*>(pEditor);
261            if (!pVirtualMidiDevice) {
262                std::cerr << "Instrument editor not a virtual MIDI device\n" << std::flush;
263                return pEditor;
264            }
265            // NOTE: for now connect the virtual MIDI keyboard of the instrument editor (if any) with all engine channels that have the same instrument as the editor was opened for ( other ideas ? )
266            Lock();
267            std::set<EngineChannel*> engineChannels =
268                GetEngineChannelsUsing(pInstrument, false/*don't lock again*/);
269            std::set<EngineChannel*>::iterator iter = engineChannels.begin();
270            std::set<EngineChannel*>::iterator end  = engineChannels.end();
271            for (; iter != end; ++iter) (static_cast<AbstractEngineChannel*>(*iter))->Connect(pVirtualMidiDevice);
272            Unlock();
273    
274            return pEditor;
275      }      }
276    
277      /**      /**
# Line 212  namespace LinuxSampler { namespace gig { Line 283  namespace LinuxSampler { namespace gig {
283       */       */
284      void InstrumentResourceManager::OnInstrumentEditorQuit(InstrumentEditor* pSender) {      void InstrumentResourceManager::OnInstrumentEditorQuit(InstrumentEditor* pSender) {
285          dmsg(1,("InstrumentResourceManager: instrument editor quit, doing cleanup\n"));          dmsg(1,("InstrumentResourceManager: instrument editor quit, doing cleanup\n"));
286          // hand back instrument and free proxy  
287            ::gig::Instrument* pInstrument = NULL;
288            InstrumentEditorProxy* pProxy  = NULL;
289            int iProxyIndex                = -1;
290    
291            // first find the editor proxy entry for this editor
292          InstrumentEditorProxiesMutex.Lock();          InstrumentEditorProxiesMutex.Lock();
293          if (InstrumentEditorProxies.count(pSender)) {          for (int i = 0; i < InstrumentEditorProxies.size(); i++) {
294              InstrumentEditorProxy* pProxy =              InstrumentEditorProxy* pCurProxy =
295                  dynamic_cast<InstrumentEditorProxy*>(                  dynamic_cast<InstrumentEditorProxy*>(
296                      InstrumentEditorProxies[pSender]                      InstrumentEditorProxies[i]
297                  );                  );
298              InstrumentEditorProxies.erase(pSender);              if (pCurProxy->pEditor == pSender) {
299              InstrumentEditorProxiesMutex.Unlock();                  pProxy      = pCurProxy;
300              HandBack(pProxy->pInstrument, pProxy);                  iProxyIndex = i;
301              if (pProxy) delete pProxy;                  pInstrument = pCurProxy->pInstrument;
302                }
303            }
304            InstrumentEditorProxiesMutex.Unlock();
305    
306            if (!pProxy) {
307                std::cerr << "Eeeek, could not find instrument editor proxy, "
308                             "this is a bug!\n" << std::flush;
309                return;
310            }
311    
312            // now unregister editor as not being available as a virtual MIDI device anymore
313            VirtualMidiDevice* pVirtualMidiDevice =
314                dynamic_cast<VirtualMidiDevice*>(pSender);
315            if (pVirtualMidiDevice) {
316                Lock();
317                // NOTE: see note in LaunchInstrumentEditor()
318                std::set<EngineChannel*> engineChannels =
319                    GetEngineChannelsUsing(pInstrument, false/*don't lock again*/);
320                std::set<EngineChannel*>::iterator iter = engineChannels.begin();
321                std::set<EngineChannel*>::iterator end  = engineChannels.end();
322                for (; iter != end; ++iter) (*iter)->Disconnect(pVirtualMidiDevice);
323                Unlock();
324          } else {          } else {
325                std::cerr << "Could not unregister editor as not longer acting as "
326                             "virtual MIDI device. Wasn't it registered?\n"
327                          << std::flush;
328            }
329    
330            // finally delete proxy entry and hand back instrument
331            if (pInstrument) {
332                InstrumentEditorProxiesMutex.Lock();
333                InstrumentEditorProxies.remove(iProxyIndex);
334              InstrumentEditorProxiesMutex.Unlock();              InstrumentEditorProxiesMutex.Unlock();
335              std::cerr << "Eeeek, could not find instrument editor proxy, this is a bug!\n" << std::flush;  
336                HandBack(pInstrument, pProxy);
337                delete pProxy;
338          }          }
339    
340          // Note that we don't need to free the editor here. As it          // Note that we don't need to free the editor here. As it
# Line 233  namespace LinuxSampler { namespace gig { Line 342  namespace LinuxSampler { namespace gig {
342          // dies.          // dies.
343      }      }
344    
345    #if 0 // currently unused :
346        /**
347         * Try to inform the respective instrument editor(s), that a note on
348         * event just occured. This method is called by the MIDI thread. If any
349         * obstacles are in the way (e.g. if a wait for an unlock would be
350         * required) we give up immediately, since the RT safeness of the MIDI
351         * thread has absolute priority.
352         */
353        void InstrumentResourceManager::TrySendNoteOnToEditors(uint8_t Key, uint8_t Velocity, ::gig::Instrument* pInstrument) {
354            const bool bGotLock = InstrumentEditorProxiesMutex.Trylock(); // naively assumes RT safe implementation
355            if (!bGotLock) return; // hell, forget it, not worth the hassle
356            for (int i = 0; i < InstrumentEditorProxies.size(); i++) {
357                InstrumentEditorProxy* pProxy =
358                    dynamic_cast<InstrumentEditorProxy*>(
359                        InstrumentEditorProxies[i]
360                    );
361                if (pProxy->pInstrument == pInstrument)
362                    pProxy->pEditor->SendNoteOnToDevice(Key, Velocity);
363            }
364            InstrumentEditorProxiesMutex.Unlock(); // naively assumes RT safe implementation
365        }
366    
367        /**
368         * Try to inform the respective instrument editor(s), that a note off
369         * event just occured. This method is called by the MIDI thread. If any
370         * obstacles are in the way (e.g. if a wait for an unlock would be
371         * required) we give up immediately, since the RT safeness of the MIDI
372         * thread has absolute priority.
373         */
374        void InstrumentResourceManager::TrySendNoteOffToEditors(uint8_t Key, uint8_t Velocity, ::gig::Instrument* pInstrument) {
375            const bool bGotLock = InstrumentEditorProxiesMutex.Trylock(); // naively assumes RT safe implementation
376            if (!bGotLock) return; // hell, forget it, not worth the hassle
377            for (int i = 0; i < InstrumentEditorProxies.size(); i++) {
378                InstrumentEditorProxy* pProxy =
379                    dynamic_cast<InstrumentEditorProxy*>(
380                        InstrumentEditorProxies[i]
381                    );
382                if (pProxy->pInstrument == pInstrument)
383                    pProxy->pEditor->SendNoteOffToDevice(Key, Velocity);
384            }
385            InstrumentEditorProxiesMutex.Unlock(); // naively assumes RT safe implementation
386        }
387    #endif // unused
388    
389      void InstrumentResourceManager::OnSamplesToBeRemoved(std::set<void*> Samples, InstrumentEditor* pSender) {      void InstrumentResourceManager::OnSamplesToBeRemoved(std::set<void*> Samples, InstrumentEditor* pSender) {
390          if (Samples.empty()) {          if (Samples.empty()) {
391              std::cerr << "gig::InstrumentResourceManager: WARNING, "              std::cerr << "gig::InstrumentResourceManager: WARNING, "
# Line 272  namespace LinuxSampler { namespace gig { Line 425  namespace LinuxSampler { namespace gig {
425              ::gig::Instrument* pInstrument =              ::gig::Instrument* pInstrument =
426                  (::gig::Instrument*) pRegion->GetParent();                  (::gig::Instrument*) pRegion->GetParent();
427              Lock();              Lock();
428              std::set<gig::Engine*> engines =              std::set<Engine*> engines =
429                  GetEnginesUsing(pInstrument, false/*don't lock again*/);                  GetEnginesUsing(pInstrument, false/*don't lock again*/);
430              std::set<gig::Engine*>::iterator iter = engines.begin();              std::set<Engine*>::iterator iter = engines.begin();
431              std::set<gig::Engine*>::iterator end  = engines.end();              std::set<Engine*>::iterator end  = engines.end();
432              for (; iter != end; ++iter) (*iter)->Suspend(pRegion);              for (; iter != end; ++iter) (*iter)->Suspend(pRegion);
433              Unlock();              Unlock();
434          } else if (sStructType == "gig::DimensionRegion") {          } else if (sStructType == "gig::DimensionRegion") {
# Line 289  namespace LinuxSampler { namespace gig { Line 442  namespace LinuxSampler { namespace gig {
442              ::gig::Instrument* pInstrument =              ::gig::Instrument* pInstrument =
443                  (::gig::Instrument*) pRegion->GetParent();                  (::gig::Instrument*) pRegion->GetParent();
444              Lock();              Lock();
445              std::set<gig::Engine*> engines =              std::set<Engine*> engines =
446                  GetEnginesUsing(pInstrument, false/*don't lock again*/);                  GetEnginesUsing(pInstrument, false/*don't lock again*/);
447              std::set<gig::Engine*>::iterator iter = engines.begin();              std::set<Engine*>::iterator iter = engines.begin();
448              std::set<gig::Engine*>::iterator end  = engines.end();              std::set<Engine*>::iterator end  = engines.end();
449              for (; iter != end; ++iter) (*iter)->Suspend(pRegion);              for (; iter != end; ++iter) (*iter)->Suspend(pRegion);
450              Unlock();              Unlock();
451          } else {          } else {
# Line 312  namespace LinuxSampler { namespace gig { Line 465  namespace LinuxSampler { namespace gig {
465          } else if (sStructType == "gig::Instrument") {          } else if (sStructType == "gig::Instrument") {
466              // resume all previously suspended engines              // resume all previously suspended engines
467              ResumeAllEngines();              ResumeAllEngines();
468            } else if (sStructType == "gig::Sample") {
469                // we're assuming here, that OnDataStructureToBeChanged() with
470                // "gig::File" was called previously, so we won't resume anything
471                // here, but just re-cache the given sample
472                Lock();
473                ::gig::Sample* pSample = (::gig::Sample*) pStruct;
474                ::gig::File* pFile = (::gig::File*) pSample->GetParent();
475                UncacheInitialSamples(pSample);
476                // now re-cache ...
477                std::vector< ::gig::Instrument*> instruments =
478                    GetInstrumentsCurrentlyUsedOf(pFile, false/*don't lock again*/);
479                for (int i = 0; i < instruments.size(); i++) {
480                    if (SampleReferencedByInstrument(pSample, instruments[i])) {
481                        std::set<EngineChannel*> engineChannels =
482                            GetEngineChannelsUsing(instruments[i], false/*don't lock again*/);
483                        std::set<EngineChannel*>::iterator iter = engineChannels.begin();
484                        std::set<EngineChannel*>::iterator end  = engineChannels.end();
485                        for (; iter != end; ++iter)
486                            CacheInitialSamples(pSample, *iter);
487                    }
488                }
489                Unlock();
490          } else if (sStructType == "gig::Region") {          } else if (sStructType == "gig::Region") {
491              // advice the engines to resume the given region, that is to              // advice the engines to resume the given region, that is to
492              // using it for playback again              // using it for playback again
# Line 319  namespace LinuxSampler { namespace gig { Line 494  namespace LinuxSampler { namespace gig {
494              ::gig::Instrument* pInstrument =              ::gig::Instrument* pInstrument =
495                  (::gig::Instrument*) pRegion->GetParent();                  (::gig::Instrument*) pRegion->GetParent();
496              Lock();              Lock();
497              std::set<gig::Engine*> engines =              std::set<Engine*> engines =
498                  GetEnginesUsing(pInstrument, false/*don't lock again*/);                  GetEnginesUsing(pInstrument, false/*don't lock again*/);
499              std::set<gig::Engine*>::iterator iter = engines.begin();              std::set<Engine*>::iterator iter = engines.begin();
500              std::set<gig::Engine*>::iterator end  = engines.end();              std::set<Engine*>::iterator end  = engines.end();
501              for (; iter != end; ++iter) (*iter)->Resume(pRegion);              for (; iter != end; ++iter) (*iter)->Resume(pRegion);
502              Unlock();              Unlock();
503          } else if (sStructType == "gig::DimensionRegion") {          } else if (sStructType == "gig::DimensionRegion") {
# Line 334  namespace LinuxSampler { namespace gig { Line 509  namespace LinuxSampler { namespace gig {
509              ::gig::Instrument* pInstrument =              ::gig::Instrument* pInstrument =
510                  (::gig::Instrument*) pRegion->GetParent();                  (::gig::Instrument*) pRegion->GetParent();
511              Lock();              Lock();
512              std::set<gig::Engine*> engines =              std::set<Engine*> engines =
513                  GetEnginesUsing(pInstrument, false/*don't lock again*/);                  GetEnginesUsing(pInstrument, false/*don't lock again*/);
514              std::set<gig::Engine*>::iterator iter = engines.begin();              std::set<Engine*>::iterator iter = engines.begin();
515              std::set<gig::Engine*>::iterator end  = engines.end();              std::set<Engine*>::iterator end  = engines.end();
516              for (; iter != end; ++iter) (*iter)->Resume(pRegion);              for (; iter != end; ++iter) (*iter)->Resume(pRegion);
517              Unlock();              Unlock();
518          } else {          } else {
# Line 355  namespace LinuxSampler { namespace gig { Line 530  namespace LinuxSampler { namespace gig {
530              Lock();              Lock();
531              ::gig::Sample* pSample = (::gig::Sample*) pOldSample;              ::gig::Sample* pSample = (::gig::Sample*) pOldSample;
532              ::gig::File* pFile = (::gig::File*) pSample->GetParent();              ::gig::File* pFile = (::gig::File*) pSample->GetParent();
533                bool bSampleStillInUse = false;
534              std::vector< ::gig::Instrument*> instruments =              std::vector< ::gig::Instrument*> instruments =
535                  GetInstrumentsCurrentlyUsedOf(pFile, false/*don't lock again*/);                  GetInstrumentsCurrentlyUsedOf(pFile, false/*don't lock again*/);
536              for (int i = 0; i < instruments.size(); i++)              for (int i = 0; i < instruments.size(); i++) {
537                  if (!SampleReferencedByInstrument(pSample, instruments[i]))                  if (SampleReferencedByInstrument(pSample, instruments[i])) {
538                      UncacheInitialSamples(pSample);                      bSampleStillInUse = true;
539                        break;
540                    }
541                }
542                if (!bSampleStillInUse) UncacheInitialSamples(pSample);
543              Unlock();              Unlock();
544          }          }
545          // make sure new sample reference is cached          // make sure new sample reference is cached
# Line 368  namespace LinuxSampler { namespace gig { Line 548  namespace LinuxSampler { namespace gig {
548              ::gig::Sample* pSample = (::gig::Sample*) pNewSample;              ::gig::Sample* pSample = (::gig::Sample*) pNewSample;
549              ::gig::File* pFile = (::gig::File*) pSample->GetParent();              ::gig::File* pFile = (::gig::File*) pSample->GetParent();
550              // get all engines that use that same gig::File              // get all engines that use that same gig::File
551              std::set<gig::Engine*> engines = GetEnginesUsing(pFile, false/*don't lock again*/);              std::set<Engine*> engines = GetEnginesUsing(pFile, false/*don't lock again*/);
552              std::set<gig::Engine*>::iterator iter = engines.begin();              std::set<Engine*>::iterator iter = engines.begin();
553              std::set<gig::Engine*>::iterator end  = engines.end();              std::set<Engine*>::iterator end  = engines.end();
554              for (; iter != end; ++iter)              for (; iter != end; ++iter)
555                  CacheInitialSamples(pSample, *iter);                  CacheInitialSamples(pSample, *iter);
556              Unlock();              Unlock();
# Line 411  namespace LinuxSampler { namespace gig { Line 591  namespace LinuxSampler { namespace gig {
591    
592              if (pRgn->GetSample() && !pRgn->GetSample()->GetCache().Size) {              if (pRgn->GetSample() && !pRgn->GetSample()->GetCache().Size) {
593                  dmsg(2,("C"));                  dmsg(2,("C"));
594                  CacheInitialSamples(pRgn->GetSample(), (gig::EngineChannel*) pConsumer);                  CacheInitialSamples(pRgn->GetSample(), (EngineChannel*) pConsumer);
595              }              }
596              for (uint i = 0; i < pRgn->DimensionRegions; i++) {              for (uint i = 0; i < pRgn->DimensionRegions; i++) {
597                  CacheInitialSamples(pRgn->pDimensionRegions[i]->pSample, (gig::EngineChannel*) pConsumer);                  CacheInitialSamples(pRgn->pDimensionRegions[i]->pSample, (EngineChannel*) pConsumer);
598              }              }
599    
600              pRgn = pInstrument->GetNextRegion();              pRgn = pInstrument->GetNextRegion();
# Line 429  namespace LinuxSampler { namespace gig { Line 609  namespace LinuxSampler { namespace gig {
609          pEntry->ID.Index      = Key.Index;          pEntry->ID.Index      = Key.Index;
610          pEntry->pGig          = pGig;          pEntry->pGig          = pGig;
611    
612          gig::EngineChannel* pEngineChannel = dynamic_cast<gig::EngineChannel*>(pConsumer);          EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(pConsumer);
613          // and we save this to check if we need to reallocate for a engine with higher value of 'MaxSamplesPerSecond'          // and we save this to check if we need to reallocate for a engine with higher value of 'MaxSamplesPerSecond'
614          pEntry->MaxSamplesPerCycle =          pEntry->MaxSamplesPerCycle =
615              (!pEngineChannel) ? 0 /* don't care for instrument editors */ :              (!pEngineChannel) ? 0 /* don't care for instrument editors */ :
616                  (pEngineChannel->GetEngine()) ?                  (pEngineChannel->GetEngine()) ?
617                      dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle()                      dynamic_cast<Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle()
618                      : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;                      : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
619          pArg = pEntry;          pArg = pEntry;
620    
# Line 450  namespace LinuxSampler { namespace gig { Line 630  namespace LinuxSampler { namespace gig {
630    
631      void InstrumentResourceManager::OnBorrow(::gig::Instrument* pResource, InstrumentConsumer* pConsumer, void*& pArg) {      void InstrumentResourceManager::OnBorrow(::gig::Instrument* pResource, InstrumentConsumer* pConsumer, void*& pArg) {
632          instr_entry_t* pEntry = (instr_entry_t*) pArg;          instr_entry_t* pEntry = (instr_entry_t*) pArg;
633          gig::EngineChannel* pEngineChannel = dynamic_cast<gig::EngineChannel*>(pConsumer);          EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(pConsumer);
634          uint maxSamplesPerCycle =          uint maxSamplesPerCycle =
635              (pEngineChannel && pEngineChannel->GetEngine()) ? dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle()              (pEngineChannel && pEngineChannel->GetEngine()) ? dynamic_cast<Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle()
636                                            : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;                                            : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
637          if (pEntry->MaxSamplesPerCycle < maxSamplesPerCycle) {          if (pEntry->MaxSamplesPerCycle < maxSamplesPerCycle) {
638              Update(pResource, pConsumer);              Update(pResource, pConsumer);
639          }          }
640      }      }
641    
642      /**      void InstrumentResourceManager::DeleteRegionIfNotUsed(::gig::DimensionRegion* pRegion, region_info_t* pRegInfo) {
643       * Give back an instrument. This should be used instead of          // TODO: we could delete Region and Instrument here if they have become unused
      * HandBack if there are some dimension regions that are still in  
      * use. (When an instrument is changed, the voices currently  
      * playing are allowed to keep playing with the old instrument  
      * until note off arrives. New notes will use the new instrument.)  
      */  
     void InstrumentResourceManager::HandBackInstrument(::gig::Instrument* pResource, InstrumentConsumer* pConsumer,  
                                                        RTList< ::gig::DimensionRegion*>* pDimRegionsInUse) {  
         DimRegInfoMutex.Lock();  
         for (RTList< ::gig::DimensionRegion*>::Iterator i = pDimRegionsInUse->first() ; i != pDimRegionsInUse->end() ; i++) {  
             DimRegInfo[*i].refCount++;  
             SampleRefCount[(*i)->pSample]++;  
         }  
         HandBack(pResource, pConsumer, true);  
         DimRegInfoMutex.Unlock();  
644      }      }
645        void InstrumentResourceManager::DeleteSampleIfNotUsed(::gig::Sample* pSample, region_info_t* pRegInfo) {
646      /**          ::gig::File* gig = pRegInfo->file;
647       * Give back a dimension region that belongs to an instrument that          ::RIFF::File* riff = static_cast< ::RIFF::File*>(pRegInfo->pArg);
648       * was previously handed back.          if (gig) {
649       */              gig->DeleteSample(pSample);
650      void InstrumentResourceManager::HandBackDimReg(::gig::DimensionRegion* pDimReg) {              if (!gig->GetFirstSample()) {
651          DimRegInfoMutex.Lock();                  dmsg(2,("No more samples in use - freeing gig\n"));
652          dimreg_info_t& dimRegInfo = DimRegInfo[pDimReg];                  delete gig;
653          int dimRegRefCount = --dimRegInfo.refCount;                  delete riff;
         int sampleRefCount = --SampleRefCount[pDimReg->pSample];  
         if (dimRegRefCount == 0) {  
             ::gig::File* gig = dimRegInfo.file;  
             ::RIFF::File* riff = dimRegInfo.riff;  
             DimRegInfo.erase(pDimReg);  
             // TODO: we could delete Region and Instrument here if  
             // they have become unused  
   
             if (sampleRefCount == 0) {  
                 SampleRefCount.erase(pDimReg->pSample);  
   
                 if (gig) {  
                     gig->DeleteSample(pDimReg->pSample);  
                     if (!gig->GetFirstSample()) {  
                         dmsg(2,("No more samples in use - freeing gig\n"));  
                         delete gig;  
                         delete riff;  
                     }  
                 }  
654              }              }
655          }          }
         DimRegInfoMutex.Unlock();  
656      }      }
657    
658      /**      /**
# Line 517  namespace LinuxSampler { namespace gig { Line 663  namespace LinuxSampler { namespace gig {
663       *                   (may be NULL, in this case default amount of samples       *                   (may be NULL, in this case default amount of samples
664       *                   will be cached)       *                   will be cached)
665       */       */
666      void InstrumentResourceManager::CacheInitialSamples(::gig::Sample* pSample, gig::EngineChannel* pEngineChannel) {      void InstrumentResourceManager::CacheInitialSamples(::gig::Sample* pSample, EngineChannel* pEngineChannel) {
667          gig::Engine* pEngine =          Engine* pEngine =
668              (pEngineChannel && pEngineChannel->GetEngine()) ?              (pEngineChannel && pEngineChannel->GetEngine()) ?
669                  dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine()) : NULL;                  dynamic_cast<Engine*>(pEngineChannel->GetEngine()) : NULL;
670          CacheInitialSamples(pSample, pEngine);          CacheInitialSamples(pSample, pEngine);
671      }      }
672    
# Line 535  namespace LinuxSampler { namespace gig { Line 681  namespace LinuxSampler { namespace gig {
681       *                   (may be NULL, in this case default amount of samples       *                   (may be NULL, in this case default amount of samples
682       *                   will be cached)       *                   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) {          if (!pSample) {
686              dmsg(4,("gig::InstrumentResourceManager: Skipping sample (pSample == NULL)\n"));              dmsg(4,("gig::InstrumentResourceManager: Skipping sample (pSample == NULL)\n"));
687              return;              return;
# Line 593  namespace LinuxSampler { namespace gig { Line 739  namespace LinuxSampler { namespace gig {
739      }      }
740    
741      /**      /**
742         * Returns a list with all gig engine channels that are currently using
743         * the given instrument.
744         *
745         * @param pInstrument - search criteria
746         * @param bLock - whether we should lock (mutex) the instrument manager
747         *                during this call and unlock at the end of this call
748         */
749        std::set<EngineChannel*> InstrumentResourceManager::GetEngineChannelsUsing(::gig::Instrument* pInstrument, bool bLock) {
750            if (bLock) Lock();
751            std::set<EngineChannel*> result;
752            std::set<ResourceConsumer< ::gig::Instrument>*> consumers = ConsumersOf(pInstrument);
753            std::set<ResourceConsumer< ::gig::Instrument>*>::iterator iter = consumers.begin();
754            std::set<ResourceConsumer< ::gig::Instrument>*>::iterator end  = consumers.end();
755            for (; iter != end; ++iter) {
756                EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(*iter);
757                if (!pEngineChannel) continue;
758                result.insert(pEngineChannel);
759            }
760            if (bLock) Unlock();
761            return result;
762        }
763    
764        /**
765       * Returns a list with all gig Engines that are currently using the given       * Returns a list with all gig Engines that are currently using the given
766       * instrument.       * instrument.
767       *       *
# Line 600  namespace LinuxSampler { namespace gig { Line 769  namespace LinuxSampler { namespace gig {
769       * @param bLock - whether we should lock (mutex) the instrument manager       * @param bLock - whether we should lock (mutex) the instrument manager
770       *                during this call and unlock at the end of this call       *                during this call and unlock at the end of this call
771       */       */
772      std::set<gig::Engine*> InstrumentResourceManager::GetEnginesUsing(::gig::Instrument* pInstrument, bool bLock) {      std::set<Engine*> InstrumentResourceManager::GetEnginesUsing(::gig::Instrument* pInstrument, bool bLock) {
773          if (bLock) Lock();          if (bLock) Lock();
774          std::set<gig::Engine*> result;          std::set<Engine*> result;
775          std::set<ResourceConsumer< ::gig::Instrument>*> consumers = ConsumersOf(pInstrument);          std::set<ResourceConsumer< ::gig::Instrument>*> consumers = ConsumersOf(pInstrument);
776          std::set<ResourceConsumer< ::gig::Instrument>*>::iterator iter = consumers.begin();          std::set<ResourceConsumer< ::gig::Instrument>*>::iterator iter = consumers.begin();
777          std::set<ResourceConsumer< ::gig::Instrument>*>::iterator end  = consumers.end();          std::set<ResourceConsumer< ::gig::Instrument>*>::iterator end  = consumers.end();
778          for (; iter != end; ++iter) {          for (; iter != end; ++iter) {
779              gig::EngineChannel* pEngineChannel = dynamic_cast<gig::EngineChannel*>(*iter);              EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(*iter);
780              if (!pEngineChannel) continue;              if (!pEngineChannel) continue;
781              gig::Engine* pEngine = dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine());              Engine* pEngine = dynamic_cast<Engine*>(pEngineChannel->GetEngine());
782              if (!pEngine) continue;              if (!pEngine) continue;
783              result.insert(pEngine);              result.insert(pEngine);
784          }          }
# Line 625  namespace LinuxSampler { namespace gig { Line 794  namespace LinuxSampler { namespace gig {
794       * @param bLock - whether we should lock (mutex) the instrument manager       * @param bLock - whether we should lock (mutex) the instrument manager
795       *                during this call and unlock at the end of this call       *                during this call and unlock at the end of this call
796       */       */
797      std::set<gig::Engine*> InstrumentResourceManager::GetEnginesUsing(::gig::File* pFile, bool bLock) {      std::set<Engine*> InstrumentResourceManager::GetEnginesUsing(::gig::File* pFile, bool bLock) {
798          if (bLock) Lock();          if (bLock) Lock();
799          // get all instruments (currently in usage) that use that same gig::File          // get all instruments (currently in usage) that use that same gig::File
800          std::vector< ::gig::Instrument*> instrumentsOfInterest =          std::vector< ::gig::Instrument*> instrumentsOfInterest =
801              GetInstrumentsCurrentlyUsedOf(pFile, false/*don't lock again*/);              GetInstrumentsCurrentlyUsedOf(pFile, false/*don't lock again*/);
802    
803          // get all engines that use that same gig::File          // get all engines that use that same gig::File
804          std::set<gig::Engine*> result;          std::set<Engine*> result;
805          {          {
806              for (int i = 0; i < instrumentsOfInterest.size(); i++) {              for (int i = 0; i < instrumentsOfInterest.size(); i++) {
807                  std::set<ResourceConsumer< ::gig::Instrument>*> consumers = ConsumersOf(instrumentsOfInterest[i]);                  std::set<ResourceConsumer< ::gig::Instrument>*> consumers = ConsumersOf(instrumentsOfInterest[i]);
808                  std::set<ResourceConsumer< ::gig::Instrument>*>::iterator iter = consumers.begin();                  std::set<ResourceConsumer< ::gig::Instrument>*>::iterator iter = consumers.begin();
809                  std::set<ResourceConsumer< ::gig::Instrument>*>::iterator end  = consumers.end();                  std::set<ResourceConsumer< ::gig::Instrument>*>::iterator end  = consumers.end();
810                  for (; iter != end; ++iter) {                  for (; iter != end; ++iter) {
811                      gig::EngineChannel* pEngineChannel = dynamic_cast<gig::EngineChannel*>(*iter);                      EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(*iter);
812                      if (!pEngineChannel) continue;                      if (!pEngineChannel) continue;
813                      gig::Engine* pEngine = dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine());                      Engine* pEngine = dynamic_cast<Engine*>(pEngineChannel->GetEngine());
814                      if (!pEngine) continue;                      if (!pEngine) continue;
815                      // the unique, sorted container std::set makes                      // the unique, sorted container std::set makes
816                      // sure we won't have duplicates                      // sure we won't have duplicates
# Line 695  namespace LinuxSampler { namespace gig { Line 864  namespace LinuxSampler { namespace gig {
864          // get all engines that use that same gig::Instrument          // get all engines that use that same gig::Instrument
865          suspendedEngines = GetEnginesUsing(pInstrument, true/*lock*/);          suspendedEngines = GetEnginesUsing(pInstrument, true/*lock*/);
866          // finally, completely suspend all engines that use that same gig::Instrument          // finally, completely suspend all engines that use that same gig::Instrument
867          std::set<gig::Engine*>::iterator iter = suspendedEngines.begin();          std::set<Engine*>::iterator iter = suspendedEngines.begin();
868          std::set<gig::Engine*>::iterator end  = suspendedEngines.end();          std::set<Engine*>::iterator end  = suspendedEngines.end();
869          for (; iter != end; ++iter) (*iter)->SuspendAll();          for (; iter != end; ++iter) (*iter)->SuspendAll();
870      }      }
871    
# Line 719  namespace LinuxSampler { namespace gig { Line 888  namespace LinuxSampler { namespace gig {
888          // get all engines that use that same gig::File          // get all engines that use that same gig::File
889          suspendedEngines = GetEnginesUsing(pFile, true/*lock*/);          suspendedEngines = GetEnginesUsing(pFile, true/*lock*/);
890          // finally, completely suspend all engines that use that same gig::File          // finally, completely suspend all engines that use that same gig::File
891          std::set<gig::Engine*>::iterator iter = suspendedEngines.begin();          std::set<Engine*>::iterator iter = suspendedEngines.begin();
892          std::set<gig::Engine*>::iterator end  = suspendedEngines.end();          std::set<Engine*>::iterator end  = suspendedEngines.end();
893          for (; iter != end; ++iter) (*iter)->SuspendAll();          for (; iter != end; ++iter) (*iter)->SuspendAll();
894      }      }
895    
# Line 776  namespace LinuxSampler { namespace gig { Line 945  namespace LinuxSampler { namespace gig {
945                  for (int i = 0 ; i < region->DimensionRegions ; i++)                  for (int i = 0 ; i < region->DimensionRegions ; i++)
946                  {                  {
947                      ::gig::DimensionRegion *d = region->pDimensionRegions[i];                      ::gig::DimensionRegion *d = region->pDimensionRegions[i];
948                      std::map< ::gig::DimensionRegion*, dimreg_info_t>::iterator iter = parent->DimRegInfo.find(d);                      std::map< ::gig::DimensionRegion*, region_info_t>::iterator iter = parent->RegionInfo.find(d);
949                      if (iter != parent->DimRegInfo.end()) {                      if (iter != parent->RegionInfo.end()) {
950                          dimreg_info_t& dimRegInfo = (*iter).second;                          region_info_t& dimRegInfo = (*iter).second;
951                          dimRegInfo.file = pResource;                          dimRegInfo.file = pResource;
952                          dimRegInfo.riff = (::RIFF::File*)pArg;                          dimRegInfo.pArg = (::RIFF::File*)pArg;
953                          deleteFile = deleteInstrument = deleteRegion = false;                          deleteFile = deleteInstrument = deleteRegion = false;
954                      }                      }
955                  }                  }

Legend:
Removed from v.1646  
changed lines
  Added in v.2012

  ViewVC Help
Powered by ViewVC