/[svn]/linuxsampler/trunk/src/engines/InstrumentManagerBase.h
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/InstrumentManagerBase.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2275 - (show annotations) (download) (as text)
Mon Sep 19 21:48:45 2011 UTC (12 years, 7 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 13432 byte(s)
* Bugfix: When creating MIDI instrument map entries with "PERSISTENT"
  type, the instruments were uselessly precached with zero samples,
  however it still took the full preloading time and on 1st program
  change the respective instrument was completely reloaded again.
* Bumped version to 1.0.0.svn15

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2011 Christian Schoenebeck *
7 * Copyright (C) 2009 Grigor Iliev *
8 * *
9 * This library is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 * This library is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17 * GNU General Public License for more details. *
18 * *
19 * You should have received a copy of the GNU General Public License *
20 * along with this library; if not, write to the Free Software *
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
22 * MA 02111-1307 USA *
23 ***************************************************************************/
24
25 #ifndef __LS_INSTRUMENTMANAGERBASE_H__
26 #define __LS_INSTRUMENTMANAGERBASE_H__
27
28 #include "InstrumentManager.h"
29 #include "AbstractEngine.h"
30 #include "AbstractEngineChannel.h"
31 #include "../common/ResourceManager.h"
32 #include "../common/global_private.h"
33 #include "../drivers/audio/AudioOutputDeviceFactory.h"
34
35 // We need to know the maximum number of sample points which are going to
36 // be processed for each render cycle of the audio output driver, to know
37 // how much initial sample points we need to cache into RAM. If the given
38 // sampler channel does not have an audio output device assigned yet
39 // though, we simply use this default value.
40 #define GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE 128
41
42 namespace LinuxSampler {
43
44 template <class F /* Instrument File */, class I /* Instrument */, class R /* Regions */, class S /*Sample */>
45 class InstrumentManagerBase : virtual public InstrumentManager, virtual public ResourceManager<InstrumentManager::instrument_id_t, I> {
46 public:
47 struct region_info_t {
48 int refCount;
49 F* file;
50 void* pArg;
51
52 region_info_t() {
53 refCount = 0; file = NULL; pArg = NULL;
54 }
55 };
56
57 typedef ResourceConsumer<I> InstrumentConsumer;
58
59 InstrumentManagerBase() { }
60 virtual ~InstrumentManagerBase() { }
61
62 virtual InstrumentEditor* LaunchInstrumentEditor(instrument_id_t ID, void* pUserData = NULL) throw (InstrumentManagerException) {
63 throw InstrumentManagerException(
64 "Instrument editing is not supported for this instrument format"
65 );
66 }
67
68 virtual String GetInstrumentDataStructureName(instrument_id_t ID) {
69 throw InstrumentManagerException("Not implemented");
70 }
71
72 virtual String GetInstrumentDataStructureVersion(instrument_id_t ID) {
73 throw InstrumentManagerException("Not implemented");
74 }
75
76 /**
77 * Give back an instrument. This should be used instead of
78 * HandBack if there are some regions that are still in
79 * use. (When an instrument is changed, the voices currently
80 * playing are allowed to keep playing with the old instrument
81 * until note off arrives. New notes will use the new instrument.)
82 */
83 void HandBackInstrument (
84 I* pResource,
85 InstrumentConsumer* pConsumer,
86 RTList<R*>* pRegionsInUse
87 ) {
88 RegionInfoMutex.Lock();
89 for (typename RTList<R*>::Iterator i = pRegionsInUse->first() ; i != pRegionsInUse->end() ; i++) {
90 RegionInfo[*i].refCount++;
91 SampleRefCount[(*i)->pSample]++;
92 }
93 HandBack(pResource, pConsumer, true);
94 RegionInfoMutex.Unlock();
95 }
96
97 /**
98 * Give back a region that belongs to an instrument that
99 * was previously handed back.
100 */
101 virtual void HandBackRegion(R* pRegion) {
102 RegionInfoMutex.Lock();
103 if (RegionInfo.find(pRegion) == RegionInfo.end()) {
104 std::cerr << "Handing back unknown region. This is a BUG!!!" << std::endl;
105 }
106 region_info_t& regInfo = RegionInfo[pRegion];
107 int regionRefCount = --regInfo.refCount;
108 int sampleRefCount = --SampleRefCount[pRegion->pSample];
109 if (regionRefCount == 0) {
110 S* pSample = pRegion->pSample;
111
112 DeleteRegionIfNotUsed(pRegion, &regInfo);
113
114 if (sampleRefCount == 0) {
115 SampleRefCount.erase(pSample);
116 DeleteSampleIfNotUsed(pSample, &regInfo);
117 }
118 RegionInfo.erase(pRegion);
119 }
120 RegionInfoMutex.Unlock();
121 }
122
123 virtual InstrumentManager::mode_t GetMode(const InstrumentManager::instrument_id_t& ID) {
124 return static_cast<InstrumentManager::mode_t>(ResourceManager<instrument_id_t, I>::AvailabilityMode(ID));
125 }
126
127 virtual void SetMode(const InstrumentManager::instrument_id_t& ID, InstrumentManager::mode_t Mode) {
128 dmsg(2,("InstrumentManagerBase: setting mode for %s (Index=%d) to %d\n",ID.FileName.c_str(),ID.Index,Mode));
129 SetAvailabilityMode(ID, static_cast<typename ResourceManager<instrument_id_t, I>::mode_t>(Mode));
130 }
131
132 /**
133 * Used by the implementing instrument manager descendents in case
134 * they don't have a reference to a sampler channel, which in turn
135 * provides a reference to an audio device which would actually
136 * define the maximum amount of sample points per audio render
137 * cycle. So in those missing cases (e.g. when MIDI instrument maps
138 * are created), this method will iterate through all already
139 * existing audio devices and return the biggest max. samples per
140 * cycle value of those audio devices.
141 *
142 * In case no audio device is currently created, this method will
143 * return a hard coded constant default value.
144 *
145 * Background: We need to know the maximum number of sample points
146 * which are going to be processed for each render cycle of the
147 * audio output driver, to know how many initial sample points we
148 * need to cache into RAM by the implementing instrument manager.
149 */
150 virtual uint DefaultMaxSamplesPerCycle() {
151 uint samples = 0;
152 std::map<uint, AudioOutputDevice*> devices = AudioOutputDeviceFactory::Devices();
153 for (std::map<uint, AudioOutputDevice*>::iterator iter = devices.begin(); iter != devices.end(); ++iter) {
154 AudioOutputDevice* pDevice = iter->second;
155 if (pDevice->MaxSamplesPerCycle() > samples)
156 samples = pDevice->MaxSamplesPerCycle();
157 }
158 return (samples != 0) ? samples : 128 /* some fallback default value*/;
159 }
160
161 protected:
162 Mutex RegionInfoMutex; ///< protects the RegionInfo and SampleRefCount maps from concurrent access by the instrument loader and disk threads
163 std::map< R*, region_info_t> RegionInfo; ///< contains dimension regions that are still in use but belong to released instrument
164 std::map< S*, int> SampleRefCount; ///< contains samples that are still in use but belong to a released instrument
165
166 /**
167 * Caches a certain size at the beginning of the given sample in RAM. If the
168 * sample is very short, the whole sample will be loaded into RAM and thus
169 * no disk streaming is needed for this sample. Caching an initial part of
170 * samples is needed to compensate disk reading latency.
171 *
172 * @param pSample - points to the sample to be cached
173 * @param pEngine - pointer to Engine which caused this call
174 * (may be NULL, in this case default amount of samples
175 * will be cached)
176 */
177 virtual void CacheInitialSamples(S* pSample, AbstractEngine* pEngine) = 0;
178
179 virtual void DeleteRegionIfNotUsed(R* pRegion, region_info_t* pRegInfo) = 0;
180 virtual void DeleteSampleIfNotUsed(S* pSample, region_info_t* pRegInfo) = 0;
181
182 void SetKeyBindings(uint8_t* bindingsArray, int low, int high, int undefined = -1) {
183 if (low == undefined || high == undefined) return;
184 if (low < 0 || low > 127 || high < 0 || high > 127 || low > high) {
185 std::cerr << "Invalid key range: " << low << " - " << high << std::endl;
186 return;
187 }
188
189 for (int i = low; i <= high; i++) bindingsArray[i] = 1;
190 }
191
192 };
193
194 template <class F /* Instrument File */, class I /* Instrument */, class R /* Region */, class S /* Sample */>
195 class InstrumentManagerDefaultImpl : public InstrumentManagerBase<F, I, R, S> {
196 public:
197 InstrumentManagerDefaultImpl() { }
198 virtual ~InstrumentManagerDefaultImpl() { }
199 protected:
200 virtual void CacheInitialSamples(S* pSample, AbstractEngine* pEngine) {
201 if (!pSample) {
202 dmsg(4,("InstrumentManagerBase: Skipping sample (pSample == NULL)\n"));
203 return;
204 }
205 if (!pSample->GetTotalFrameCount()) return; // skip zero size samples
206
207 if (pSample->GetTotalFrameCount() <= CONFIG_PRELOAD_SAMPLES) {
208 // Sample is too short for disk streaming, so we load the whole
209 // sample into RAM and place 'pAudioIO->FragmentSize << CONFIG_MAX_PITCH'
210 // number of '0' samples (silence samples) behind the official buffer
211 // border, to allow the interpolator do it's work even at the end of
212 // the sample.
213 const uint maxSamplesPerCycle =
214 (pEngine) ? pEngine->pAudioOutputDevice->MaxSamplesPerCycle()
215 : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
216 const uint neededSilenceSamples = (maxSamplesPerCycle << CONFIG_MAX_PITCH) + 3;
217 const uint currentlyCachedSilenceSamples = pSample->GetCache().NullExtensionSize / pSample->GetFrameSize();
218 if (currentlyCachedSilenceSamples < neededSilenceSamples) {
219 dmsg(3,("Caching whole sample (sample name: \"%s\", sample size: %d)\n", pSample->GetName().c_str(), pSample->GetTotalFrameCount()));
220 typename S::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(neededSilenceSamples);
221 dmsg(4,("Cached %d Bytes, %d silence bytes.\n", buf.Size, buf.NullExtensionSize));
222 }
223 }
224 else { // we only cache CONFIG_PRELOAD_SAMPLES and stream the other sample points from disk
225 if (!pSample->GetCache().Size) pSample->LoadSampleData(CONFIG_PRELOAD_SAMPLES);
226 }
227
228 if (!pSample->GetCache().Size) std::cerr << "Unable to cache sample - maybe memory full!" << std::endl << std::flush;
229 }
230
231 /**
232 * Just a wrapper around the other @c CacheInitialSamples() method.
233 *
234 * @param pSample - points to the sample to be cached
235 * @param pEngine - pointer to Gig Engine Channel which caused this call
236 * (may be NULL, in this case default amount of samples
237 * will be cached)
238 */
239 virtual void CacheInitialSamples(S* pSample, EngineChannel* pEngineChannel) {
240 AbstractEngine* pEngine =
241 (pEngineChannel && pEngineChannel->GetEngine()) ?
242 dynamic_cast<AbstractEngine*>(pEngineChannel->GetEngine()) : NULL;
243 CacheInitialSamples(pSample, pEngine);
244 }
245 };
246
247 } // namespace LinuxSampler
248
249 #endif // __LS_INSTRUMENTMANAGERBASE_H__

  ViewVC Help
Powered by ViewVC