/[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 2326 - (hide annotations) (download) (as text)
Thu Mar 8 19:40:14 2012 UTC (12 years, 1 month ago) by persson
File MIME type: text/x-c++hdr
File size: 13531 byte(s)
* bugfix: instrument loading crashed for sfz and sf2 in Ardour (#176)
* more thread safety fixes for the instrument loading thread

1 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 persson 2326 * Copyright (C) 2005 - 2008 Christian Schoenebeck *
7     * Copyright (C) 2009 - 2012 Christian Schoenebeck and Grigor Iliev *
8 iliev 2012 * *
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 persson 2326 #define RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE 128
41 iliev 2012
42     namespace LinuxSampler {
43    
44     template <class F /* Instrument File */, class I /* Instrument */, class R /* Regions */, class S /*Sample */>
45 persson 2326 class InstrumentManagerBase : public InstrumentManager, public ResourceManager<InstrumentManager::instrument_id_t, I> {
46 iliev 2012 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 persson 2326
132     protected:
133     // data stored as long as an instrument resource exists
134     struct instr_entry_t {
135     InstrumentManager::instrument_id_t ID;
136     F* pFile;
137     uint MaxSamplesPerCycle; ///< if some engine requests an already allocated instrument with a higher value, we have to reallocate the instrument
138     };
139    
140    
141 schoenebeck 2275 /**
142     * Used by the implementing instrument manager descendents in case
143     * they don't have a reference to a sampler channel, which in turn
144     * provides a reference to an audio device which would actually
145     * define the maximum amount of sample points per audio render
146     * cycle. So in those missing cases (e.g. when MIDI instrument maps
147     * are created), this method will iterate through all already
148     * existing audio devices and return the biggest max. samples per
149     * cycle value of those audio devices.
150     *
151     * In case no audio device is currently created, this method will
152     * return a hard coded constant default value.
153     *
154     * Background: We need to know the maximum number of sample points
155     * which are going to be processed for each render cycle of the
156     * audio output driver, to know how many initial sample points we
157     * need to cache into RAM by the implementing instrument manager.
158     */
159     virtual uint DefaultMaxSamplesPerCycle() {
160     uint samples = 0;
161     std::map<uint, AudioOutputDevice*> devices = AudioOutputDeviceFactory::Devices();
162     for (std::map<uint, AudioOutputDevice*>::iterator iter = devices.begin(); iter != devices.end(); ++iter) {
163     AudioOutputDevice* pDevice = iter->second;
164     if (pDevice->MaxSamplesPerCycle() > samples)
165     samples = pDevice->MaxSamplesPerCycle();
166     }
167 persson 2326 return (samples != 0) ? samples : RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
168 schoenebeck 2275 }
169 iliev 2012
170 persson 2326 uint GetMaxSamplesPerCycle(InstrumentConsumer* pConsumer) {
171     // try to resolve the audio device context
172     AbstractEngineChannel* pEngineChannel = dynamic_cast<AbstractEngineChannel*>(pConsumer);
173     AudioOutputDevice* pDevice = pEngineChannel ? pEngineChannel->GetAudioOutputDeviceSafe() : 0;
174     return pDevice ? pDevice->MaxSamplesPerCycle() : DefaultMaxSamplesPerCycle();
175     }
176    
177 iliev 2012 Mutex RegionInfoMutex; ///< protects the RegionInfo and SampleRefCount maps from concurrent access by the instrument loader and disk threads
178     std::map< R*, region_info_t> RegionInfo; ///< contains dimension regions that are still in use but belong to released instrument
179     std::map< S*, int> SampleRefCount; ///< contains samples that are still in use but belong to a released instrument
180    
181     virtual void DeleteRegionIfNotUsed(R* pRegion, region_info_t* pRegInfo) = 0;
182     virtual void DeleteSampleIfNotUsed(S* pSample, region_info_t* pRegInfo) = 0;
183    
184 iliev 2027 void SetKeyBindings(uint8_t* bindingsArray, int low, int high, int undefined = -1) {
185     if (low == undefined || high == undefined) return;
186     if (low < 0 || low > 127 || high < 0 || high > 127 || low > high) {
187     std::cerr << "Invalid key range: " << low << " - " << high << std::endl;
188     return;
189     }
190    
191     for (int i = low; i <= high; i++) bindingsArray[i] = 1;
192     }
193    
194 persson 2326 /**
195     * Caches a certain size at the beginning of the given sample in RAM. If the
196     * sample is very short, the whole sample will be loaded into RAM and thus
197     * no disk streaming is needed for this sample. Caching an initial part of
198     * samples is needed to compensate disk reading latency.
199     *
200     * @param pSample - points to the sample to be cached
201     * @param maxSamplesPerCycle - max samples per cycle
202     */
203     void CacheInitialSamples(S* pSample, uint maxSamplesPerCycle) {
204 iliev 2012 if (!pSample) {
205     dmsg(4,("InstrumentManagerBase: Skipping sample (pSample == NULL)\n"));
206     return;
207     }
208     if (!pSample->GetTotalFrameCount()) return; // skip zero size samples
209    
210     if (pSample->GetTotalFrameCount() <= CONFIG_PRELOAD_SAMPLES) {
211     // Sample is too short for disk streaming, so we load the whole
212     // sample into RAM and place 'pAudioIO->FragmentSize << CONFIG_MAX_PITCH'
213     // number of '0' samples (silence samples) behind the official buffer
214     // border, to allow the interpolator do it's work even at the end of
215     // the sample.
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 persson 2326 // implementation of derived abstract methods from 'InstrumentManager'
232     std::vector<instrument_id_t> Instruments() {
233     return ResourceManager<InstrumentManager::instrument_id_t, I>::Entries();
234 iliev 2012 }
235 persson 2326
236     // implementation of derived abstract methods from 'ResourceManager'
237     void OnBorrow(I* pResource, InstrumentConsumer* pConsumer, void*& pArg) {
238     instr_entry_t* pEntry = static_cast<instr_entry_t*>(pArg);
239    
240     uint maxSamplesPerCycle = GetMaxSamplesPerCycle(pConsumer);
241    
242     if (pEntry->MaxSamplesPerCycle < maxSamplesPerCycle) {
243     dmsg(1,("Completely reloading instrument due to insufficient precached samples ...\n"));
244     Update(pResource, pConsumer);
245     }
246     }
247 iliev 2012 };
248    
249     } // namespace LinuxSampler
250    
251 persson 2045 #endif // __LS_INSTRUMENTMANAGERBASE_H__

  ViewVC Help
Powered by ViewVC