/[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 2611 - (show annotations) (download) (as text)
Mon Jun 9 19:20:37 2014 UTC (9 years, 10 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 13504 byte(s)
* Fixed crash when loading an instrument script.
* Fixed "init" script handler only to be executed once:
  when the script was loaded.
* Fixed aftertouch script event which always had value zero
  and controller number was set to aftertouch value instead.
* gig Engine: Fixed handling of "smartmidi" dimension, which
  was recognized as "unknown" dimension.
* Fixed script function gig_set_dim_zone(): was accessing
  wrong event.
* ls_instr_script command line tool: is now not limited to
  core language scripts, but can now also parse sampler format
  dependent instrument scripts, with the respective specific
  built-in script variables and functions.
* ScriptVM: Fixed runtime behavior of "and" and "or" binary
  script expressions, which also evaluated the right hand side
  of the expression even if the left hand side already failed
  the overall expression semantic to become true.
* Bumped version (1.0.0.svn46).

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 - 2013 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(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: %d)\n", pSample->GetName().c_str(), pSample->GetTotalFrameCount()));
216 typename S::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(neededSilenceSamples);
217 dmsg(4,("Cached %d Bytes, %d 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