/[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 958 - (hide annotations) (download)
Wed Nov 29 19:48:38 2006 UTC (17 years, 4 months ago) by schoenebeck
File size: 11896 byte(s)
* store volume for each MIDI instrument mapper entry individually instead
  of managing the volume as shared setting with the respective instrument
  entry of its InstrumentManager

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 958 ::gig::Instrument* pInstrument = Resource(ID);
82     return (pInstrument) ? pInstrument->pInfo->Name : "";
83 schoenebeck 947 }
84    
85 schoenebeck 53 ::gig::Instrument* InstrumentResourceManager::Create(instrument_id_t Key, InstrumentConsumer* pConsumer, void*& pArg) {
86     // get gig file from inernal gig file manager
87 schoenebeck 947 ::gig::File* pGig = Gigs.Borrow(Key.FileName, (GigConsumer*) Key.Index); // conversion kinda hackish :/
88 schoenebeck 53
89 schoenebeck 517 // we pass this to the progress callback mechanism of libgig
90     progress_callback_arg_t callbackArg;
91     callbackArg.pManager = this;
92     callbackArg.pInstrumentKey = &Key;
93    
94     ::gig::progress_t progress;
95     progress.callback = OnInstrumentLoadingProgress;
96     progress.custom = &callbackArg;
97    
98 schoenebeck 947 dmsg(1,("Loading gig instrument ('%s',%d)...",Key.FileName.c_str(),Key.Index));
99     ::gig::Instrument* pInstrument = pGig->GetInstrument(Key.Index, &progress);
100 schoenebeck 53 if (!pInstrument) {
101     std::stringstream msg;
102 schoenebeck 947 msg << "There's no instrument with index " << Key.Index << ".";
103 schoenebeck 53 throw InstrumentResourceManagerException(msg.str());
104     }
105     pGig->GetFirstSample(); // just to force complete instrument loading
106     dmsg(1,("OK\n"));
107    
108     // cache initial samples points (for actually needed samples)
109     dmsg(1,("Caching initial samples..."));
110 schoenebeck 517 uint iRegion = 0; // just for progress calculation
111 schoenebeck 53 ::gig::Region* pRgn = pInstrument->GetFirstRegion();
112     while (pRgn) {
113 schoenebeck 517 // we randomly schedule 90% for the .gig file loading and the remaining 10% now for sample caching
114     const float localProgress = 0.9f + 0.1f * (float) iRegion / (float) pInstrument->Regions;
115 schoenebeck 947 DispatchResourceProgressEvent(Key, localProgress);
116    
117 schoenebeck 354 if (pRgn->GetSample() && !pRgn->GetSample()->GetCache().Size) {
118 schoenebeck 53 dmsg(2,("C"));
119 schoenebeck 947 CacheInitialSamples(pRgn->GetSample(), (gig::EngineChannel*) pConsumer);
120 schoenebeck 53 }
121     for (uint i = 0; i < pRgn->DimensionRegions; i++) {
122 schoenebeck 947 CacheInitialSamples(pRgn->pDimensionRegions[i]->pSample, (gig::EngineChannel*) pConsumer);
123 schoenebeck 53 }
124    
125     pRgn = pInstrument->GetNextRegion();
126 schoenebeck 517 iRegion++;
127 schoenebeck 53 }
128     dmsg(1,("OK\n"));
129 schoenebeck 517 DispatchResourceProgressEvent(Key, 1.0f); // done; notify all consumers about progress 100%
130 schoenebeck 53
131     // we need the following for destruction later
132     instr_entry_t* pEntry = new instr_entry_t;
133 schoenebeck 947 pEntry->ID.FileName = Key.FileName;
134     pEntry->ID.Index = Key.Index;
135 schoenebeck 53 pEntry->pGig = pGig;
136 persson 438
137 schoenebeck 947 gig::EngineChannel* pEngineChannel = (gig::EngineChannel*) pConsumer;
138 schoenebeck 411 // and we save this to check if we need to reallocate for a engine with higher value of 'MaxSamplesPerSecond'
139     pEntry->MaxSamplesPerCycle =
140 schoenebeck 947 (pEngineChannel && pEngineChannel->GetEngine()) ? dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle()
141 schoenebeck 411 : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
142 schoenebeck 53 pArg = pEntry;
143    
144     return pInstrument;
145     }
146    
147     void InstrumentResourceManager::Destroy( ::gig::Instrument* pResource, void* pArg) {
148     instr_entry_t* pEntry = (instr_entry_t*) pArg;
149 schoenebeck 947 // we don't need the .gig file here anymore
150     Gigs.HandBack(pEntry->pGig, (GigConsumer*) pEntry->ID.Index); // conversion kinda hackish :/
151 schoenebeck 53 delete pEntry;
152     }
153    
154     void InstrumentResourceManager::OnBorrow(::gig::Instrument* pResource, InstrumentConsumer* pConsumer, void*& pArg) {
155     instr_entry_t* pEntry = (instr_entry_t*) pArg;
156 schoenebeck 411 gig::EngineChannel* pEngineChannel = dynamic_cast<gig::EngineChannel*>(pConsumer);
157     uint maxSamplesPerCycle =
158     (pEngineChannel->GetEngine()) ? dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle()
159     : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
160     if (pEntry->MaxSamplesPerCycle < maxSamplesPerCycle) {
161 schoenebeck 53 Update(pResource, pConsumer);
162     }
163     }
164    
165     /**
166     * Caches a certain size at the beginning of the given sample in RAM. If the
167     * sample is very short, the whole sample will be loaded into RAM and thus
168     * no disk streaming is needed for this sample. Caching an initial part of
169     * samples is needed to compensate disk reading latency.
170     *
171     * @param pSample - points to the sample to be cached
172 schoenebeck 411 * @param pEngineChannel - pointer to Gig Engine Channel which caused this call
173 schoenebeck 53 */
174 persson 438 void InstrumentResourceManager::CacheInitialSamples(::gig::Sample* pSample, gig::EngineChannel* pEngineChannel) {
175 schoenebeck 420 if (!pSample) {
176 persson 438 dmsg(4,("gig::InstrumentResourceManager: Skipping sample (pSample == NULL)\n"));
177 schoenebeck 420 return;
178     }
179     if (!pSample->SamplesTotal) return; // skip zero size samples
180 persson 438
181 schoenebeck 554 if (pSample->SamplesTotal <= CONFIG_PRELOAD_SAMPLES) {
182 schoenebeck 53 // Sample is too short for disk streaming, so we load the whole
183 schoenebeck 554 // sample into RAM and place 'pAudioIO->FragmentSize << CONFIG_MAX_PITCH'
184 schoenebeck 53 // number of '0' samples (silence samples) behind the official buffer
185     // border, to allow the interpolator do it's work even at the end of
186 persson 438 // the sample.
187 schoenebeck 411 const uint maxSamplesPerCycle =
188 schoenebeck 947 (pEngineChannel && pEngineChannel->GetEngine()) ? dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle()
189 schoenebeck 411 : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
190 schoenebeck 554 const uint neededSilenceSamples = (maxSamplesPerCycle << CONFIG_MAX_PITCH) + 3;
191 schoenebeck 420 const uint currentlyCachedSilenceSamples = pSample->GetCache().NullExtensionSize / pSample->FrameSize;
192     if (currentlyCachedSilenceSamples < neededSilenceSamples) {
193     dmsg(3,("Caching whole sample (sample name: \"%s\", sample size: %d)\n", pSample->pInfo->Name.c_str(), pSample->SamplesTotal));
194     ::gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(neededSilenceSamples);
195     dmsg(4,("Cached %d Bytes, %d silence bytes.\n", buf.Size, buf.NullExtensionSize));
196     }
197 schoenebeck 53 }
198 schoenebeck 554 else { // we only cache CONFIG_PRELOAD_SAMPLES and stream the other sample points from disk
199     if (!pSample->GetCache().Size) pSample->LoadSampleData(CONFIG_PRELOAD_SAMPLES);
200 schoenebeck 53 }
201    
202     if (!pSample->GetCache().Size) std::cerr << "Unable to cache sample - maybe memory full!" << std::endl << std::flush;
203     }
204    
205    
206    
207     // internal gig file manager
208    
209     ::gig::File* InstrumentResourceManager::GigResourceManager::Create(String Key, GigConsumer* pConsumer, void*& pArg) {
210     dmsg(1,("Loading gig file \'%s\'...", Key.c_str()));
211     ::RIFF::File* pRIFF = new ::RIFF::File(Key);
212     ::gig::File* pGig = new ::gig::File(pRIFF);
213     pArg = pRIFF;
214     dmsg(1,("OK\n"));
215     return pGig;
216     }
217    
218     void InstrumentResourceManager::GigResourceManager::Destroy(::gig::File* pResource, void* pArg) {
219     dmsg(1,("Freeing gig file from memory..."));
220     delete pResource;
221     delete (::RIFF::File*) pArg;
222     dmsg(1,("OK\n"));
223     }
224    
225     }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC