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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2275 - (hide 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 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 2275 * Copyright (C) 2005 - 2011 Christian Schoenebeck *
7 iliev 2012 * 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 schoenebeck 2275 #include "../drivers/audio/AudioOutputDeviceFactory.h"
34 iliev 2012
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 persson 2058 S* pSample = pRegion->pSample;
111    
112 iliev 2012 DeleteRegionIfNotUsed(pRegion, &regInfo);
113    
114     if (sampleRefCount == 0) {
115 persson 2058 SampleRefCount.erase(pSample);
116     DeleteSampleIfNotUsed(pSample, &regInfo);
117 iliev 2012 }
118 persson 2058 RegionInfo.erase(pRegion);
119 iliev 2012 }
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 schoenebeck 2275
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 iliev 2012
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 iliev 2027 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 iliev 2012 };
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 persson 2045 #endif // __LS_INSTRUMENTMANAGERBASE_H__

  ViewVC Help
Powered by ViewVC