/[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 2837 - (show annotations) (download) (as text)
Sun Aug 23 06:14:00 2015 UTC (8 years, 7 months ago) by persson
File MIME type: text/x-c++hdr
File size: 13538 byte(s)
* fixed printf type errors (mostly in debug messages)


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

  ViewVC Help
Powered by ViewVC