/[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 2012 - (show annotations) (download) (as text)
Fri Oct 23 17:53:17 2009 UTC (14 years, 6 months ago) by iliev
File MIME type: text/x-c++hdr
File size: 11127 byte(s)
* Refactoring: moved the independent code from
  the Gigasampler format engine to base classes
* SFZ format engine: experimental code (not usable yet)
* SoundFont format engine: experimental code (not usable yet)
* Fixed crash which may occur when MIDI key + transpose is out of range

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2009 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
34 // We need to know the maximum number of sample points which are going to
35 // be processed for each render cycle of the audio output driver, to know
36 // how much initial sample points we need to cache into RAM. If the given
37 // sampler channel does not have an audio output device assigned yet
38 // though, we simply use this default value.
39 #define GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE 128
40
41 namespace LinuxSampler {
42
43 template <class F /* Instrument File */, class I /* Instrument */, class R /* Regions */, class S /*Sample */>
44 class InstrumentManagerBase : virtual public InstrumentManager, virtual public ResourceManager<InstrumentManager::instrument_id_t, I> {
45 public:
46 struct region_info_t {
47 int refCount;
48 F* file;
49 void* pArg;
50
51 region_info_t() {
52 refCount = 0; file = NULL; pArg = NULL;
53 }
54 };
55
56 typedef ResourceConsumer<I> InstrumentConsumer;
57
58 InstrumentManagerBase() { }
59 virtual ~InstrumentManagerBase() { }
60
61 virtual InstrumentEditor* LaunchInstrumentEditor(instrument_id_t ID, void* pUserData = NULL) throw (InstrumentManagerException) {
62 throw InstrumentManagerException(
63 "Instrument editing is not supported for this instrument format"
64 );
65 }
66
67 virtual String GetInstrumentDataStructureName(instrument_id_t ID) {
68 throw InstrumentManagerException("Not implemented");
69 }
70
71 virtual String GetInstrumentDataStructureVersion(instrument_id_t ID) {
72 throw InstrumentManagerException("Not implemented");
73 }
74
75 /**
76 * Give back an instrument. This should be used instead of
77 * HandBack if there are some regions that are still in
78 * use. (When an instrument is changed, the voices currently
79 * playing are allowed to keep playing with the old instrument
80 * until note off arrives. New notes will use the new instrument.)
81 */
82 void HandBackInstrument (
83 I* pResource,
84 InstrumentConsumer* pConsumer,
85 RTList<R*>* pRegionsInUse
86 ) {
87 RegionInfoMutex.Lock();
88 for (typename RTList<R*>::Iterator i = pRegionsInUse->first() ; i != pRegionsInUse->end() ; i++) {
89 RegionInfo[*i].refCount++;
90 SampleRefCount[(*i)->pSample]++;
91 }
92 HandBack(pResource, pConsumer, true);
93 RegionInfoMutex.Unlock();
94 }
95
96 /**
97 * Give back a region that belongs to an instrument that
98 * was previously handed back.
99 */
100 virtual void HandBackRegion(R* pRegion) {
101 RegionInfoMutex.Lock();
102 if (RegionInfo.find(pRegion) == RegionInfo.end()) {
103 std::cerr << "Handing back unknown region. This is a BUG!!!" << std::endl;
104 }
105 region_info_t& regInfo = RegionInfo[pRegion];
106 int regionRefCount = --regInfo.refCount;
107 int sampleRefCount = --SampleRefCount[pRegion->pSample];
108 if (regionRefCount == 0) {
109 RegionInfo.erase(pRegion);
110 DeleteRegionIfNotUsed(pRegion, &regInfo);
111
112 if (sampleRefCount == 0) {
113 SampleRefCount.erase(pRegion->pSample);
114 DeleteSampleIfNotUsed(pRegion->pSample, &regInfo);
115 }
116 }
117 RegionInfoMutex.Unlock();
118 }
119
120 virtual InstrumentManager::mode_t GetMode(const InstrumentManager::instrument_id_t& ID) {
121 return static_cast<InstrumentManager::mode_t>(ResourceManager<instrument_id_t, I>::AvailabilityMode(ID));
122 }
123
124 virtual void SetMode(const InstrumentManager::instrument_id_t& ID, InstrumentManager::mode_t Mode) {
125 dmsg(2,("InstrumentManagerBase: setting mode for %s (Index=%d) to %d\n",ID.FileName.c_str(),ID.Index,Mode));
126 SetAvailabilityMode(ID, static_cast<typename ResourceManager<instrument_id_t, I>::mode_t>(Mode));
127 }
128
129 protected:
130 Mutex RegionInfoMutex; ///< protects the RegionInfo and SampleRefCount maps from concurrent access by the instrument loader and disk threads
131 std::map< R*, region_info_t> RegionInfo; ///< contains dimension regions that are still in use but belong to released instrument
132 std::map< S*, int> SampleRefCount; ///< contains samples that are still in use but belong to a released instrument
133
134 /**
135 * Caches a certain size at the beginning of the given sample in RAM. If the
136 * sample is very short, the whole sample will be loaded into RAM and thus
137 * no disk streaming is needed for this sample. Caching an initial part of
138 * samples is needed to compensate disk reading latency.
139 *
140 * @param pSample - points to the sample to be cached
141 * @param pEngine - pointer to Engine which caused this call
142 * (may be NULL, in this case default amount of samples
143 * will be cached)
144 */
145 virtual void CacheInitialSamples(S* pSample, AbstractEngine* pEngine) = 0;
146
147 virtual void DeleteRegionIfNotUsed(R* pRegion, region_info_t* pRegInfo) = 0;
148 virtual void DeleteSampleIfNotUsed(S* pSample, region_info_t* pRegInfo) = 0;
149
150 };
151
152 template <class F /* Instrument File */, class I /* Instrument */, class R /* Region */, class S /* Sample */>
153 class InstrumentManagerDefaultImpl : public InstrumentManagerBase<F, I, R, S> {
154 public:
155 InstrumentManagerDefaultImpl() { }
156 virtual ~InstrumentManagerDefaultImpl() { }
157 protected:
158 virtual void CacheInitialSamples(S* pSample, AbstractEngine* pEngine) {
159 if (!pSample) {
160 dmsg(4,("InstrumentManagerBase: Skipping sample (pSample == NULL)\n"));
161 return;
162 }
163 if (!pSample->GetTotalFrameCount()) return; // skip zero size samples
164
165 if (pSample->GetTotalFrameCount() <= CONFIG_PRELOAD_SAMPLES) {
166 // Sample is too short for disk streaming, so we load the whole
167 // sample into RAM and place 'pAudioIO->FragmentSize << CONFIG_MAX_PITCH'
168 // number of '0' samples (silence samples) behind the official buffer
169 // border, to allow the interpolator do it's work even at the end of
170 // the sample.
171 const uint maxSamplesPerCycle =
172 (pEngine) ? pEngine->pAudioOutputDevice->MaxSamplesPerCycle()
173 : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
174 const uint neededSilenceSamples = (maxSamplesPerCycle << CONFIG_MAX_PITCH) + 3;
175 const uint currentlyCachedSilenceSamples = pSample->GetCache().NullExtensionSize / pSample->GetFrameSize();
176 if (currentlyCachedSilenceSamples < neededSilenceSamples) {
177 dmsg(3,("Caching whole sample (sample name: \"%s\", sample size: %d)\n", pSample->GetName().c_str(), pSample->GetTotalFrameCount()));
178 typename S::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(neededSilenceSamples);
179 dmsg(4,("Cached %d Bytes, %d silence bytes.\n", buf.Size, buf.NullExtensionSize));
180 }
181 }
182 else { // we only cache CONFIG_PRELOAD_SAMPLES and stream the other sample points from disk
183 if (!pSample->GetCache().Size) pSample->LoadSampleData(CONFIG_PRELOAD_SAMPLES);
184 }
185
186 if (!pSample->GetCache().Size) std::cerr << "Unable to cache sample - maybe memory full!" << std::endl << std::flush;
187 }
188
189 /**
190 * Just a wrapper around the other @c CacheInitialSamples() method.
191 *
192 * @param pSample - points to the sample to be cached
193 * @param pEngine - pointer to Gig Engine Channel which caused this call
194 * (may be NULL, in this case default amount of samples
195 * will be cached)
196 */
197 virtual void CacheInitialSamples(S* pSample, EngineChannel* pEngineChannel) {
198 AbstractEngine* pEngine =
199 (pEngineChannel && pEngineChannel->GetEngine()) ?
200 dynamic_cast<AbstractEngine*>(pEngineChannel->GetEngine()) : NULL;
201 CacheInitialSamples(pSample, pEngine);
202 }
203 };
204
205 } // namespace LinuxSampler
206
207 #endif // __LS_INSTRUMENTMANAGERBASE_H__

  ViewVC Help
Powered by ViewVC