/[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 2611 - (hide annotations) (download) (as text)
Mon Jun 9 19:20:37 2014 UTC (9 years, 10 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 13504 byte(s)
* Fixed crash when loading an instrument script.
* Fixed "init" script handler only to be executed once:
  when the script was loaded.
* Fixed aftertouch script event which always had value zero
  and controller number was set to aftertouch value instead.
* gig Engine: Fixed handling of "smartmidi" dimension, which
  was recognized as "unknown" dimension.
* Fixed script function gig_set_dim_zone(): was accessing
  wrong event.
* ls_instr_script command line tool: is now not limited to
  core language scripts, but can now also parse sampler format
  dependent instrument scripts, with the respective specific
  built-in script variables and functions.
* ScriptVM: Fixed runtime behavior of "and" and "or" binary
  script expressions, which also evaluated the right hand side
  of the expression even if the left hand side already failed
  the overall expression semantic to become true.
* Bumped version (1.0.0.svn46).

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 2427 * Copyright (C) 2009 - 2013 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 2434 virtual InstrumentEditor* LaunchInstrumentEditor(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     dmsg(3,("Caching whole sample (sample name: \"%s\", sample size: %d)\n", pSample->GetName().c_str(), pSample->GetTotalFrameCount()));
216     typename S::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(neededSilenceSamples);
217     dmsg(4,("Cached %d Bytes, %d silence bytes.\n", buf.Size, buf.NullExtensionSize));
218     }
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