/[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 554 by schoenebeck, Thu May 19 19:25:14 2005 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 Christian Schoenebeck                              *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
9   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 24  Line 25 
25    
26  #include "InstrumentResourceManager.h"  #include "InstrumentResourceManager.h"
27    
28    // We need to know the maximum number of sample points which are going to
29    // be processed for each render cycle of the audio output driver, to know
30    // how much initial sample points we need to cache into RAM. If the given
31    // sampler channel does not have an audio output device assigned yet
32    // though, we simply use this default value.
33    #define GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE     128
34    
35  namespace LinuxSampler { namespace gig {  namespace LinuxSampler { namespace gig {
36    
37        // some data needed for the libgig callback function
38        struct progress_callback_arg_t {
39            InstrumentResourceManager* pManager;
40            instrument_id_t*           pInstrumentKey;
41        };
42    
43        /**
44         * Callback function which will be called by libgig during loading of
45         * instruments to inform about the current progress. Or to be more
46         * specific; it will be called during the GetInstrument() call.
47         *
48         * @param pProgress - contains current progress value, pointer to the
49         *                    InstrumentResourceManager instance and
50         *                    instrument ID
51         */
52        void InstrumentResourceManager::OnInstrumentLoadingProgress(::gig::progress_t* pProgress) {
53            dmsg(7,("gig::InstrumentResourceManager: progress %f%", pProgress->factor));
54            progress_callback_arg_t* pArg = static_cast<progress_callback_arg_t*>(pProgress->custom);
55            // we randomly schedule 90% for the .gig file loading and the remaining 10% later for sample caching
56            const float localProgress = 0.9f * pProgress->factor;
57            pArg->pManager->DispatchResourceProgressEvent(*pArg->pInstrumentKey, localProgress);
58        }
59    
60      ::gig::Instrument* InstrumentResourceManager::Create(instrument_id_t Key, InstrumentConsumer* pConsumer, void*& pArg) {      ::gig::Instrument* InstrumentResourceManager::Create(instrument_id_t Key, InstrumentConsumer* pConsumer, void*& pArg) {
61          // get gig file from inernal gig file manager          // get gig file from inernal gig file manager
62          ::gig::File* pGig = Gigs.Borrow(Key.FileName, (GigConsumer*) Key.iInstrument); // conversion kinda hackish :/          ::gig::File* pGig = Gigs.Borrow(Key.FileName, (GigConsumer*) Key.iInstrument); // conversion kinda hackish :/
63    
64            // we pass this to the progress callback mechanism of libgig
65            progress_callback_arg_t callbackArg;
66            callbackArg.pManager       = this;
67            callbackArg.pInstrumentKey = &Key;
68    
69            ::gig::progress_t progress;
70            progress.callback = OnInstrumentLoadingProgress;
71            progress.custom   = &callbackArg;
72    
73          dmsg(1,("Loading gig instrument..."));          dmsg(1,("Loading gig instrument..."));
74          ::gig::Instrument* pInstrument = pGig->GetInstrument(Key.iInstrument);          ::gig::Instrument* pInstrument = pGig->GetInstrument(Key.iInstrument, &progress);
75          if (!pInstrument) {          if (!pInstrument) {
76              std::stringstream msg;              std::stringstream msg;
77              msg << "There's no instrument with index " << Key.iInstrument << ".";              msg << "There's no instrument with index " << Key.iInstrument << ".";
# Line 42  namespace LinuxSampler { namespace gig { Line 82  namespace LinuxSampler { namespace gig {
82    
83          // cache initial samples points (for actually needed samples)          // cache initial samples points (for actually needed samples)
84          dmsg(1,("Caching initial samples..."));          dmsg(1,("Caching initial samples..."));
85            uint iRegion = 0; // just for progress calculation
86          ::gig::Region* pRgn = pInstrument->GetFirstRegion();          ::gig::Region* pRgn = pInstrument->GetFirstRegion();
87          while (pRgn) {          while (pRgn) {
88              if (!pRgn->GetSample()->GetCache().Size) {              // we randomly schedule 90% for the .gig file loading and the remaining 10% now for sample caching
89                const float localProgress = 0.9f + 0.1f * (float) iRegion / (float) pInstrument->Regions;
90                DispatchResourceProgressEvent(Key, localProgress);            
91                
92                if (pRgn->GetSample() && !pRgn->GetSample()->GetCache().Size) {
93                  dmsg(2,("C"));                  dmsg(2,("C"));
94                  CacheInitialSamples(pRgn->GetSample(), dynamic_cast<gig::Engine*>(pConsumer));                  CacheInitialSamples(pRgn->GetSample(), dynamic_cast<gig::EngineChannel*>(pConsumer));
95              }              }
96              for (uint i = 0; i < pRgn->DimensionRegions; i++) {              for (uint i = 0; i < pRgn->DimensionRegions; i++) {
97                  CacheInitialSamples(pRgn->pDimensionRegions[i]->pSample, dynamic_cast<gig::Engine*>(pConsumer));                  CacheInitialSamples(pRgn->pDimensionRegions[i]->pSample, dynamic_cast<gig::EngineChannel*>(pConsumer));
98              }              }
99    
100              pRgn = pInstrument->GetNextRegion();              pRgn = pInstrument->GetNextRegion();
101                iRegion++;
102          }          }
103          dmsg(1,("OK\n"));          dmsg(1,("OK\n"));
104            DispatchResourceProgressEvent(Key, 1.0f); // done; notify all consumers about progress 100%
105    
106          // we need the following for destruction later          // we need the following for destruction later
107          instr_entry_t* pEntry = new instr_entry_t;          instr_entry_t* pEntry = new instr_entry_t;
108          pEntry->iInstrument   = Key.iInstrument;          pEntry->iInstrument   = Key.iInstrument;
109          pEntry->pGig          = pGig;          pEntry->pGig          = pGig;
110          // and this to check if we need to reallocate for a engine with higher value of 'MaxSamplesPerSecond'  
111          pEntry->MaxSamplesPerCycle = dynamic_cast<gig::Engine*>(pConsumer)->pAudioOutputDevice->MaxSamplesPerCycle();          gig::EngineChannel* pEngineChannel = dynamic_cast<gig::EngineChannel*>(pConsumer);
112            // and we save this to check if we need to reallocate for a engine with higher value of 'MaxSamplesPerSecond'
113            pEntry->MaxSamplesPerCycle =
114                (pEngineChannel->GetEngine()) ? dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle()
115                                              : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
116          pArg = pEntry;          pArg = pEntry;
117    
118          return pInstrument;          return pInstrument;
# Line 75  namespace LinuxSampler { namespace gig { Line 126  namespace LinuxSampler { namespace gig {
126    
127      void InstrumentResourceManager::OnBorrow(::gig::Instrument* pResource, InstrumentConsumer* pConsumer, void*& pArg) {      void InstrumentResourceManager::OnBorrow(::gig::Instrument* pResource, InstrumentConsumer* pConsumer, void*& pArg) {
128          instr_entry_t* pEntry = (instr_entry_t*) pArg;          instr_entry_t* pEntry = (instr_entry_t*) pArg;
129          if (pEntry->MaxSamplesPerCycle < dynamic_cast<gig::Engine*>(pConsumer)->pAudioOutputDevice->MaxSamplesPerCycle()) {          gig::EngineChannel* pEngineChannel = dynamic_cast<gig::EngineChannel*>(pConsumer);
130            uint maxSamplesPerCycle =
131                (pEngineChannel->GetEngine()) ? dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle()
132                                              : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
133            if (pEntry->MaxSamplesPerCycle < maxSamplesPerCycle) {
134              Update(pResource, pConsumer);              Update(pResource, pConsumer);
135          }          }
136      }      }
# Line 87  namespace LinuxSampler { namespace gig { Line 142  namespace LinuxSampler { namespace gig {
142       *  samples is needed to compensate disk reading latency.       *  samples is needed to compensate disk reading latency.
143       *       *
144       *  @param pSample - points to the sample to be cached       *  @param pSample - points to the sample to be cached
145       *  @param pEngine - pointer to Gig Engine which caused this call       *  @param pEngineChannel - pointer to Gig Engine Channel which caused this call
146       */       */
147      void InstrumentResourceManager::CacheInitialSamples(::gig::Sample* pSample, gig::Engine* pEngine) {      void InstrumentResourceManager::CacheInitialSamples(::gig::Sample* pSample, gig::EngineChannel* pEngineChannel) {
148          if (!pSample || pSample->GetCache().Size) return;          if (!pSample) {
149          if (pSample->SamplesTotal <= NUM_RAM_PRELOAD_SAMPLES) {              dmsg(4,("gig::InstrumentResourceManager: Skipping sample (pSample == NULL)\n"));
150                return;
151            }
152            if (!pSample->SamplesTotal) return; // skip zero size samples
153    
154            if (pSample->SamplesTotal <= CONFIG_PRELOAD_SAMPLES) {
155              // Sample is too short for disk streaming, so we load the whole              // Sample is too short for disk streaming, so we load the whole
156              // sample into RAM and place 'pAudioIO->FragmentSize << MAX_PITCH'              // sample into RAM and place 'pAudioIO->FragmentSize << CONFIG_MAX_PITCH'
157              // number of '0' samples (silence samples) behind the official buffer              // number of '0' samples (silence samples) behind the official buffer
158              // 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
159              // the sample.              // the sample.
160              ::gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension((pEngine->pAudioOutputDevice->MaxSamplesPerCycle() << MAX_PITCH) + 3);              const uint maxSamplesPerCycle =
161              dmsg(4,("Cached %d Bytes, %d silence bytes.\n", buf.Size, buf.NullExtensionSize));                  (pEngineChannel->GetEngine()) ? dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle()
162                                                  : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
163                const uint neededSilenceSamples = (maxSamplesPerCycle << CONFIG_MAX_PITCH) + 3;
164                const uint currentlyCachedSilenceSamples = pSample->GetCache().NullExtensionSize / pSample->FrameSize;
165                if (currentlyCachedSilenceSamples < neededSilenceSamples) {
166                    dmsg(3,("Caching whole sample (sample name: \"%s\", sample size: %d)\n", pSample->pInfo->Name.c_str(), pSample->SamplesTotal));
167                    ::gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(neededSilenceSamples);
168                    dmsg(4,("Cached %d Bytes, %d silence bytes.\n", buf.Size, buf.NullExtensionSize));
169                }
170          }          }
171          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
172              pSample->LoadSampleData(NUM_RAM_PRELOAD_SAMPLES);              if (!pSample->GetCache().Size) pSample->LoadSampleData(CONFIG_PRELOAD_SAMPLES);
173          }          }
174    
175          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;

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

  ViewVC Help
Powered by ViewVC