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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 970 - (hide annotations) (download)
Wed Dec 6 22:28:17 2006 UTC (17 years, 3 months ago) by schoenebeck
File size: 11963 byte(s)
* fixed crash occuring in conjunction with the new 'MAP MIDI_INSTRUMENT'
  LSCP command (cause: RingBuffer was not able to do deep copies)

1 schoenebeck 53 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5 schoenebeck 56 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 947 * Copyright (C) 2005, 2006 Christian Schoenebeck *
7 schoenebeck 53 * *
8     * This program is free software; you can redistribute it and/or modify *
9     * it under the terms of the GNU General Public License as published by *
10     * the Free Software Foundation; either version 2 of the License, or *
11     * (at your option) any later version. *
12     * *
13     * This program is distributed in the hope that it will be useful, *
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16     * GNU General Public License for more details. *
17     * *
18     * You should have received a copy of the GNU General Public License *
19     * along with this program; if not, write to the Free Software *
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21     * MA 02111-1307 USA *
22     ***************************************************************************/
23    
24     #include <sstream>
25    
26     #include "InstrumentResourceManager.h"
27    
28 schoenebeck 411 // 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 schoenebeck 53 namespace LinuxSampler { namespace gig {
36    
37 schoenebeck 947 // data stored as long as an instrument resource exists
38     struct instr_entry_t {
39     InstrumentManager::instrument_id_t ID;
40     ::gig::File* pGig;
41     uint MaxSamplesPerCycle; ///< if some engine requests an already allocated instrument with a higher value, we have to reallocate the instrument
42     };
43    
44 schoenebeck 517 // some data needed for the libgig callback function
45     struct progress_callback_arg_t {
46 schoenebeck 947 InstrumentResourceManager* pManager;
47     InstrumentManager::instrument_id_t* pInstrumentKey;
48 schoenebeck 517 };
49    
50     /**
51     * Callback function which will be called by libgig during loading of
52     * instruments to inform about the current progress. Or to be more
53     * specific; it will be called during the GetInstrument() call.
54     *
55     * @param pProgress - contains current progress value, pointer to the
56     * InstrumentResourceManager instance and
57     * instrument ID
58     */
59     void InstrumentResourceManager::OnInstrumentLoadingProgress(::gig::progress_t* pProgress) {
60     dmsg(7,("gig::InstrumentResourceManager: progress %f%", pProgress->factor));
61     progress_callback_arg_t* pArg = static_cast<progress_callback_arg_t*>(pProgress->custom);
62     // we randomly schedule 90% for the .gig file loading and the remaining 10% later for sample caching
63     const float localProgress = 0.9f * pProgress->factor;
64     pArg->pManager->DispatchResourceProgressEvent(*pArg->pInstrumentKey, localProgress);
65     }
66    
67 schoenebeck 947 std::vector<InstrumentResourceManager::instrument_id_t> InstrumentResourceManager::Instruments() {
68     return Entries();
69     }
70    
71     InstrumentManager::mode_t InstrumentResourceManager::GetMode(const instrument_id_t& ID) {
72     return static_cast<InstrumentManager::mode_t>(AvailabilityMode(ID));
73     }
74    
75     void InstrumentResourceManager::SetMode(const instrument_id_t& ID, InstrumentManager::mode_t Mode) {
76     dmsg(2,("gig::InstrumentResourceManager: setting mode for %s (Index=%d) to %d\n",ID.FileName.c_str(),ID.Index,Mode));
77     SetAvailabilityMode(ID, static_cast<ResourceManager<InstrumentManager::instrument_id_t, ::gig::Instrument>::mode_t>(Mode));
78     }
79    
80     String InstrumentResourceManager::GetInstrumentName(instrument_id_t ID) {
81 schoenebeck 970 Lock();
82     ::gig::Instrument* pInstrument = Resource(ID, false);
83     String res = (pInstrument) ? pInstrument->pInfo->Name : "";
84     Unlock();
85     return res;
86 schoenebeck 947 }
87    
88 schoenebeck 53 ::gig::Instrument* InstrumentResourceManager::Create(instrument_id_t Key, InstrumentConsumer* pConsumer, void*& pArg) {
89     // get gig file from inernal gig file manager
90 schoenebeck 947 ::gig::File* pGig = Gigs.Borrow(Key.FileName, (GigConsumer*) Key.Index); // conversion kinda hackish :/
91 schoenebeck 53
92 schoenebeck 517 // we pass this to the progress callback mechanism of libgig
93     progress_callback_arg_t callbackArg;
94     callbackArg.pManager = this;
95     callbackArg.pInstrumentKey = &Key;
96    
97     ::gig::progress_t progress;
98     progress.callback = OnInstrumentLoadingProgress;
99     progress.custom = &callbackArg;
100    
101 schoenebeck 947 dmsg(1,("Loading gig instrument ('%s',%d)...",Key.FileName.c_str(),Key.Index));
102     ::gig::Instrument* pInstrument = pGig->GetInstrument(Key.Index, &progress);
103 schoenebeck 53 if (!pInstrument) {
104     std::stringstream msg;
105 schoenebeck 947 msg << "There's no instrument with index " << Key.Index << ".";
106 schoenebeck 53 throw InstrumentResourceManagerException(msg.str());
107     }
108     pGig->GetFirstSample(); // just to force complete instrument loading
109     dmsg(1,("OK\n"));
110    
111     // cache initial samples points (for actually needed samples)
112     dmsg(1,("Caching initial samples..."));
113 schoenebeck 517 uint iRegion = 0; // just for progress calculation
114 schoenebeck 53 ::gig::Region* pRgn = pInstrument->GetFirstRegion();
115     while (pRgn) {
116 schoenebeck 517 // we randomly schedule 90% for the .gig file loading and the remaining 10% now for sample caching
117     const float localProgress = 0.9f + 0.1f * (float) iRegion / (float) pInstrument->Regions;
118 schoenebeck 947 DispatchResourceProgressEvent(Key, localProgress);
119    
120 schoenebeck 354 if (pRgn->GetSample() && !pRgn->GetSample()->GetCache().Size) {
121 schoenebeck 53 dmsg(2,("C"));
122 schoenebeck 947 CacheInitialSamples(pRgn->GetSample(), (gig::EngineChannel*) pConsumer);
123 schoenebeck 53 }
124     for (uint i = 0; i < pRgn->DimensionRegions; i++) {
125 schoenebeck 947 CacheInitialSamples(pRgn->pDimensionRegions[i]->pSample, (gig::EngineChannel*) pConsumer);
126 schoenebeck 53 }
127    
128     pRgn = pInstrument->GetNextRegion();
129 schoenebeck 517 iRegion++;
130 schoenebeck 53 }
131     dmsg(1,("OK\n"));
132 schoenebeck 517 DispatchResourceProgressEvent(Key, 1.0f); // done; notify all consumers about progress 100%
133 schoenebeck 53
134     // we need the following for destruction later
135     instr_entry_t* pEntry = new instr_entry_t;
136 schoenebeck 947 pEntry->ID.FileName = Key.FileName;
137     pEntry->ID.Index = Key.Index;
138 schoenebeck 53 pEntry->pGig = pGig;
139 persson 438
140 schoenebeck 947 gig::EngineChannel* pEngineChannel = (gig::EngineChannel*) pConsumer;
141 schoenebeck 411 // and we save this to check if we need to reallocate for a engine with higher value of 'MaxSamplesPerSecond'
142     pEntry->MaxSamplesPerCycle =
143 schoenebeck 947 (pEngineChannel && pEngineChannel->GetEngine()) ? dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle()
144 schoenebeck 411 : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
145 schoenebeck 53 pArg = pEntry;
146    
147     return pInstrument;
148     }
149    
150     void InstrumentResourceManager::Destroy( ::gig::Instrument* pResource, void* pArg) {
151     instr_entry_t* pEntry = (instr_entry_t*) pArg;
152 schoenebeck 947 // we don't need the .gig file here anymore
153     Gigs.HandBack(pEntry->pGig, (GigConsumer*) pEntry->ID.Index); // conversion kinda hackish :/
154 schoenebeck 53 delete pEntry;
155     }
156    
157     void InstrumentResourceManager::OnBorrow(::gig::Instrument* pResource, InstrumentConsumer* pConsumer, void*& pArg) {
158     instr_entry_t* pEntry = (instr_entry_t*) pArg;
159 schoenebeck 411 gig::EngineChannel* pEngineChannel = dynamic_cast<gig::EngineChannel*>(pConsumer);
160     uint maxSamplesPerCycle =
161     (pEngineChannel->GetEngine()) ? dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle()
162     : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
163     if (pEntry->MaxSamplesPerCycle < maxSamplesPerCycle) {
164 schoenebeck 53 Update(pResource, pConsumer);
165     }
166     }
167    
168     /**
169     * Caches a certain size at the beginning of the given sample in RAM. If the
170     * sample is very short, the whole sample will be loaded into RAM and thus
171     * no disk streaming is needed for this sample. Caching an initial part of
172     * samples is needed to compensate disk reading latency.
173     *
174     * @param pSample - points to the sample to be cached
175 schoenebeck 411 * @param pEngineChannel - pointer to Gig Engine Channel which caused this call
176 schoenebeck 53 */
177 persson 438 void InstrumentResourceManager::CacheInitialSamples(::gig::Sample* pSample, gig::EngineChannel* pEngineChannel) {
178 schoenebeck 420 if (!pSample) {
179 persson 438 dmsg(4,("gig::InstrumentResourceManager: Skipping sample (pSample == NULL)\n"));
180 schoenebeck 420 return;
181     }
182     if (!pSample->SamplesTotal) return; // skip zero size samples
183 persson 438
184 schoenebeck 554 if (pSample->SamplesTotal <= CONFIG_PRELOAD_SAMPLES) {
185 schoenebeck 53 // Sample is too short for disk streaming, so we load the whole
186 schoenebeck 554 // sample into RAM and place 'pAudioIO->FragmentSize << CONFIG_MAX_PITCH'
187 schoenebeck 53 // number of '0' samples (silence samples) behind the official buffer
188     // border, to allow the interpolator do it's work even at the end of
189 persson 438 // the sample.
190 schoenebeck 411 const uint maxSamplesPerCycle =
191 schoenebeck 947 (pEngineChannel && pEngineChannel->GetEngine()) ? dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle()
192 schoenebeck 411 : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
193 schoenebeck 554 const uint neededSilenceSamples = (maxSamplesPerCycle << CONFIG_MAX_PITCH) + 3;
194 schoenebeck 420 const uint currentlyCachedSilenceSamples = pSample->GetCache().NullExtensionSize / pSample->FrameSize;
195     if (currentlyCachedSilenceSamples < neededSilenceSamples) {
196     dmsg(3,("Caching whole sample (sample name: \"%s\", sample size: %d)\n", pSample->pInfo->Name.c_str(), pSample->SamplesTotal));
197     ::gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(neededSilenceSamples);
198     dmsg(4,("Cached %d Bytes, %d silence bytes.\n", buf.Size, buf.NullExtensionSize));
199     }
200 schoenebeck 53 }
201 schoenebeck 554 else { // we only cache CONFIG_PRELOAD_SAMPLES and stream the other sample points from disk
202     if (!pSample->GetCache().Size) pSample->LoadSampleData(CONFIG_PRELOAD_SAMPLES);
203 schoenebeck 53 }
204    
205     if (!pSample->GetCache().Size) std::cerr << "Unable to cache sample - maybe memory full!" << std::endl << std::flush;
206     }
207    
208    
209    
210     // internal gig file manager
211    
212     ::gig::File* InstrumentResourceManager::GigResourceManager::Create(String Key, GigConsumer* pConsumer, void*& pArg) {
213     dmsg(1,("Loading gig file \'%s\'...", Key.c_str()));
214     ::RIFF::File* pRIFF = new ::RIFF::File(Key);
215     ::gig::File* pGig = new ::gig::File(pRIFF);
216     pArg = pRIFF;
217     dmsg(1,("OK\n"));
218     return pGig;
219     }
220    
221     void InstrumentResourceManager::GigResourceManager::Destroy(::gig::File* pResource, void* pArg) {
222     dmsg(1,("Freeing gig file from memory..."));
223     delete pResource;
224     delete (::RIFF::File*) pArg;
225     dmsg(1,("OK\n"));
226     }
227    
228     }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC