/[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 3054 - (hide annotations) (download) (as text)
Thu Dec 15 12:47:45 2016 UTC (7 years, 4 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 13645 byte(s)
* Fixed numerous compiler warnings.
* Bumped version (2.0.0.svn32).

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 schoenebeck 3054 * Copyright (C) 2009 Christian Schoenebeck and Grigor Iliev *
8     * Copyright (C) 2010-2016 Christian Schoenebeck and Andreas Persson *
9 iliev 2012 * *
10     * This library is free software; you can redistribute it and/or modify *
11     * it under the terms of the GNU General Public License as published by *
12     * the Free Software Foundation; either version 2 of the License, or *
13     * (at your option) any later version. *
14     * *
15     * This library is distributed in the hope that it will be useful, *
16     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18     * GNU General Public License for more details. *
19     * *
20     * You should have received a copy of the GNU General Public License *
21     * along with this library; if not, write to the Free Software *
22     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
23     * MA 02111-1307 USA *
24     ***************************************************************************/
25    
26     #ifndef __LS_INSTRUMENTMANAGERBASE_H__
27     #define __LS_INSTRUMENTMANAGERBASE_H__
28    
29 schoenebeck 2611 #include "common/AbstractInstrumentManager.h"
30     #include "../drivers/audio/AudioOutputDeviceFactory.h"
31 iliev 2012 #include "AbstractEngine.h"
32     #include "AbstractEngineChannel.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 persson 2326 #define RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE 128
40 iliev 2012
41     namespace LinuxSampler {
42    
43     template <class F /* Instrument File */, class I /* Instrument */, class R /* Regions */, class S /*Sample */>
44 schoenebeck 2611 class InstrumentManagerBase : public AbstractInstrumentManager, public ResourceManager<InstrumentManager::instrument_id_t, I> {
45 iliev 2012 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 schoenebeck 2611 InstrumentManagerBase() : AbstractInstrumentManager() { }
59 iliev 2012 virtual ~InstrumentManagerBase() { }
60    
61 schoenebeck 2687 virtual InstrumentEditor* LaunchInstrumentEditor(EngineChannel* pEngineChannel, instrument_id_t ID, void* pUserData = NULL) throw (InstrumentManagerException) OVERRIDE {
62 iliev 2012 throw InstrumentManagerException(
63     "Instrument editing is not supported for this instrument format"
64     );
65     }
66    
67 schoenebeck 2434 virtual String GetInstrumentDataStructureName(instrument_id_t ID) OVERRIDE {
68 iliev 2012 throw InstrumentManagerException("Not implemented");
69     }
70    
71 schoenebeck 2434 virtual String GetInstrumentDataStructureVersion(instrument_id_t ID) OVERRIDE {
72 iliev 2012 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 persson 2427 LockGuard lock(RegionInfoMutex);
88 iliev 2012 for (typename RTList<R*>::Iterator i = pRegionsInUse->first() ; i != pRegionsInUse->end() ; i++) {
89     RegionInfo[*i].refCount++;
90     SampleRefCount[(*i)->pSample]++;
91     }
92 persson 2335 this->HandBack(pResource, pConsumer, true);
93 iliev 2012 }
94    
95     /**
96     * Give back a region that belongs to an instrument that
97     * was previously handed back.
98     */
99 persson 2460 virtual void HandBackRegion(R* pRegion) {
100 persson 2427 LockGuard lock(RegionInfoMutex);
101 iliev 2012 if (RegionInfo.find(pRegion) == RegionInfo.end()) {
102     std::cerr << "Handing back unknown region. This is a BUG!!!" << std::endl;
103     }
104     region_info_t& regInfo = RegionInfo[pRegion];
105     int regionRefCount = --regInfo.refCount;
106     int sampleRefCount = --SampleRefCount[pRegion->pSample];
107     if (regionRefCount == 0) {
108 persson 2058 S* pSample = pRegion->pSample;
109    
110 iliev 2012 DeleteRegionIfNotUsed(pRegion, &regInfo);
111    
112     if (sampleRefCount == 0) {
113 persson 2058 SampleRefCount.erase(pSample);
114     DeleteSampleIfNotUsed(pSample, &regInfo);
115 iliev 2012 }
116 persson 2058 RegionInfo.erase(pRegion);
117 iliev 2012 }
118     }
119    
120 schoenebeck 2434 virtual InstrumentManager::mode_t GetMode(const InstrumentManager::instrument_id_t& ID) OVERRIDE {
121 iliev 2012 return static_cast<InstrumentManager::mode_t>(ResourceManager<instrument_id_t, I>::AvailabilityMode(ID));
122     }
123    
124 schoenebeck 2434 virtual void SetMode(const InstrumentManager::instrument_id_t& ID, InstrumentManager::mode_t Mode) OVERRIDE {
125 iliev 2012 dmsg(2,("InstrumentManagerBase: setting mode for %s (Index=%d) to %d\n",ID.FileName.c_str(),ID.Index,Mode));
126 persson 2335 this->SetAvailabilityMode(ID, static_cast<typename ResourceManager<instrument_id_t, I>::mode_t>(Mode));
127 iliev 2012 }
128 persson 2326
129     protected:
130     // data stored as long as an instrument resource exists
131     struct instr_entry_t {
132     InstrumentManager::instrument_id_t ID;
133     F* pFile;
134     uint MaxSamplesPerCycle; ///< if some engine requests an already allocated instrument with a higher value, we have to reallocate the instrument
135     };
136    
137    
138 schoenebeck 2275 /**
139     * Used by the implementing instrument manager descendents in case
140     * they don't have a reference to a sampler channel, which in turn
141     * provides a reference to an audio device which would actually
142     * define the maximum amount of sample points per audio render
143     * cycle. So in those missing cases (e.g. when MIDI instrument maps
144     * are created), this method will iterate through all already
145     * existing audio devices and return the biggest max. samples per
146     * cycle value of those audio devices.
147     *
148     * In case no audio device is currently created, this method will
149     * return a hard coded constant default value.
150     *
151     * Background: We need to know the maximum number of sample points
152     * which are going to be processed for each render cycle of the
153     * audio output driver, to know how many initial sample points we
154     * need to cache into RAM by the implementing instrument manager.
155     */
156     virtual uint DefaultMaxSamplesPerCycle() {
157     uint samples = 0;
158     std::map<uint, AudioOutputDevice*> devices = AudioOutputDeviceFactory::Devices();
159     for (std::map<uint, AudioOutputDevice*>::iterator iter = devices.begin(); iter != devices.end(); ++iter) {
160     AudioOutputDevice* pDevice = iter->second;
161     if (pDevice->MaxSamplesPerCycle() > samples)
162     samples = pDevice->MaxSamplesPerCycle();
163     }
164 persson 2326 return (samples != 0) ? samples : RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
165 schoenebeck 2275 }
166 iliev 2012
167 persson 2326 uint GetMaxSamplesPerCycle(InstrumentConsumer* pConsumer) {
168     // try to resolve the audio device context
169     AbstractEngineChannel* pEngineChannel = dynamic_cast<AbstractEngineChannel*>(pConsumer);
170     AudioOutputDevice* pDevice = pEngineChannel ? pEngineChannel->GetAudioOutputDeviceSafe() : 0;
171     return pDevice ? pDevice->MaxSamplesPerCycle() : DefaultMaxSamplesPerCycle();
172     }
173    
174 iliev 2012 Mutex RegionInfoMutex; ///< protects the RegionInfo and SampleRefCount maps from concurrent access by the instrument loader and disk threads
175     std::map< R*, region_info_t> RegionInfo; ///< contains dimension regions that are still in use but belong to released instrument
176     std::map< S*, int> SampleRefCount; ///< contains samples that are still in use but belong to a released instrument
177    
178     virtual void DeleteRegionIfNotUsed(R* pRegion, region_info_t* pRegInfo) = 0;
179     virtual void DeleteSampleIfNotUsed(S* pSample, region_info_t* pRegInfo) = 0;
180    
181 iliev 2027 void SetKeyBindings(uint8_t* bindingsArray, int low, int high, int undefined = -1) {
182     if (low == undefined || high == undefined) return;
183     if (low < 0 || low > 127 || high < 0 || high > 127 || low > high) {
184     std::cerr << "Invalid key range: " << low << " - " << high << std::endl;
185     return;
186     }
187    
188     for (int i = low; i <= high; i++) bindingsArray[i] = 1;
189     }
190    
191 persson 2326 /**
192     * Caches a certain size at the beginning of the given sample in RAM. If the
193     * sample is very short, the whole sample will be loaded into RAM and thus
194     * no disk streaming is needed for this sample. Caching an initial part of
195     * samples is needed to compensate disk reading latency.
196     *
197     * @param pSample - points to the sample to be cached
198     * @param maxSamplesPerCycle - max samples per cycle
199     */
200     void CacheInitialSamples(S* pSample, uint maxSamplesPerCycle) {
201 iliev 2012 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 schoenebeck 3054 const uint neededSilenceSamples = uint((maxSamplesPerCycle << CONFIG_MAX_PITCH) + 3);
214     const uint currentlyCachedSilenceSamples = uint(pSample->GetCache().NullExtensionSize / pSample->GetFrameSize());
215 iliev 2012 if (currentlyCachedSilenceSamples < neededSilenceSamples) {
216 persson 2837 dmsg(3,("Caching whole sample (sample name: \"%s\", sample size: %ld)\n", pSample->GetName().c_str(), pSample->GetTotalFrameCount()));
217 iliev 2012 typename S::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(neededSilenceSamples);
218 persson 2837 dmsg(4,("Cached %lu Bytes, %lu silence bytes.\n", buf.Size, buf.NullExtensionSize));
219 iliev 2012 }
220     }
221     else { // we only cache CONFIG_PRELOAD_SAMPLES and stream the other sample points from disk
222     if (!pSample->GetCache().Size) pSample->LoadSampleData(CONFIG_PRELOAD_SAMPLES);
223     }
224    
225     if (!pSample->GetCache().Size) std::cerr << "Unable to cache sample - maybe memory full!" << std::endl << std::flush;
226     }
227    
228 persson 2326 // implementation of derived abstract methods from 'InstrumentManager'
229 schoenebeck 3054 std::vector<instrument_id_t> Instruments() OVERRIDE {
230 persson 2326 return ResourceManager<InstrumentManager::instrument_id_t, I>::Entries();
231 iliev 2012 }
232 persson 2326
233     // implementation of derived abstract methods from 'ResourceManager'
234 schoenebeck 3054 void OnBorrow(I* pResource, InstrumentConsumer* pConsumer, void*& pArg) OVERRIDE {
235 persson 2326 instr_entry_t* pEntry = static_cast<instr_entry_t*>(pArg);
236    
237     uint maxSamplesPerCycle = GetMaxSamplesPerCycle(pConsumer);
238    
239     if (pEntry->MaxSamplesPerCycle < maxSamplesPerCycle) {
240     dmsg(1,("Completely reloading instrument due to insufficient precached samples ...\n"));
241 persson 2335 this->Update(pResource, pConsumer);
242 persson 2326 }
243     }
244 iliev 2012 };
245    
246     } // namespace LinuxSampler
247    
248 persson 2045 #endif // __LS_INSTRUMENTMANAGERBASE_H__

  ViewVC Help
Powered by ViewVC