/[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 2837 - (hide annotations) (download) (as text)
Sun Aug 23 06:14:00 2015 UTC (8 years, 8 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 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 persson 2837 * Copyright (C) 2009 - 2015 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 schoenebeck 2611 #include "common/AbstractInstrumentManager.h"
29     #include "../drivers/audio/AudioOutputDeviceFactory.h"
30 iliev 2012 #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 persson 2326 #define RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE 128
39 iliev 2012
40     namespace LinuxSampler {
41    
42     template <class F /* Instrument File */, class I /* Instrument */, class R /* Regions */, class S /*Sample */>
43 schoenebeck 2611 class InstrumentManagerBase : public AbstractInstrumentManager, public ResourceManager<InstrumentManager::instrument_id_t, I> {
44 iliev 2012 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 schoenebeck 2611 InstrumentManagerBase() : AbstractInstrumentManager() { }
58 iliev 2012 virtual ~InstrumentManagerBase() { }
59    
60 schoenebeck 2687 virtual InstrumentEditor* LaunchInstrumentEditor(EngineChannel* pEngineChannel, instrument_id_t ID, void* pUserData = NULL) throw (InstrumentManagerException) OVERRIDE {
61 iliev 2012 throw InstrumentManagerException(
62     "Instrument editing is not supported for this instrument format"
63     );
64     }
65    
66 schoenebeck 2434 virtual String GetInstrumentDataStructureName(instrument_id_t ID) OVERRIDE {
67 iliev 2012 throw InstrumentManagerException("Not implemented");
68     }
69    
70 schoenebeck 2434 virtual String GetInstrumentDataStructureVersion(instrument_id_t ID) OVERRIDE {
71 iliev 2012 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 persson 2427 LockGuard lock(RegionInfoMutex);
87 iliev 2012 for (typename RTList<R*>::Iterator i = pRegionsInUse->first() ; i != pRegionsInUse->end() ; i++) {
88     RegionInfo[*i].refCount++;
89     SampleRefCount[(*i)->pSample]++;
90     }
91 persson 2335 this->HandBack(pResource, pConsumer, true);
92 iliev 2012 }
93    
94     /**
95     * Give back a region that belongs to an instrument that
96     * was previously handed back.
97     */
98 persson 2460 virtual void HandBackRegion(R* pRegion) {
99 persson 2427 LockGuard lock(RegionInfoMutex);
100 iliev 2012 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 persson 2058 S* pSample = pRegion->pSample;
108    
109 iliev 2012 DeleteRegionIfNotUsed(pRegion, &regInfo);
110    
111     if (sampleRefCount == 0) {
112 persson 2058 SampleRefCount.erase(pSample);
113     DeleteSampleIfNotUsed(pSample, &regInfo);
114 iliev 2012 }
115 persson 2058 RegionInfo.erase(pRegion);
116 iliev 2012 }
117     }
118    
119 schoenebeck 2434 virtual InstrumentManager::mode_t GetMode(const InstrumentManager::instrument_id_t& ID) OVERRIDE {
120 iliev 2012 return static_cast<InstrumentManager::mode_t>(ResourceManager<instrument_id_t, I>::AvailabilityMode(ID));
121     }
122    
123 schoenebeck 2434 virtual void SetMode(const InstrumentManager::instrument_id_t& ID, InstrumentManager::mode_t Mode) OVERRIDE {
124 iliev 2012 dmsg(2,("InstrumentManagerBase: setting mode for %s (Index=%d) to %d\n",ID.FileName.c_str(),ID.Index,Mode));
125 persson 2335 this->SetAvailabilityMode(ID, static_cast<typename ResourceManager<instrument_id_t, I>::mode_t>(Mode));
126 iliev 2012 }
127 persson 2326
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 schoenebeck 2275 /**
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 persson 2326 return (samples != 0) ? samples : RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
164 schoenebeck 2275 }
165 iliev 2012
166 persson 2326 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 iliev 2012 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 iliev 2027 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 persson 2326 /**
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 iliev 2012 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 persson 2837 dmsg(3,("Caching whole sample (sample name: \"%s\", sample size: %ld)\n", pSample->GetName().c_str(), pSample->GetTotalFrameCount()));
216 iliev 2012 typename S::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(neededSilenceSamples);
217 persson 2837 dmsg(4,("Cached %lu Bytes, %lu silence bytes.\n", buf.Size, buf.NullExtensionSize));
218 iliev 2012 }
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 persson 2326 // implementation of derived abstract methods from 'InstrumentManager'
228     std::vector<instrument_id_t> Instruments() {
229     return ResourceManager<InstrumentManager::instrument_id_t, I>::Entries();
230 iliev 2012 }
231 persson 2326
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 persson 2335 this->Update(pResource, pConsumer);
241 persson 2326 }
242     }
243 iliev 2012 };
244    
245     } // namespace LinuxSampler
246    
247 persson 2045 #endif // __LS_INSTRUMENTMANAGERBASE_H__

  ViewVC Help
Powered by ViewVC