/[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 2058 - (hide annotations) (download) (as text)
Sun Feb 14 11:40:49 2010 UTC (14 years, 2 months ago) by persson
File MIME type: text/x-c++hdr
File size: 11637 byte(s)
* sfz/sf2 engines: fixed memory leak and memory handling errors
* sfz engine: added support for sw_trigger=first, sw_trigger=legato
  and sw_previous
* sfz parser: allow non-numerical key values ("C#4" for example)
* sfz engine: "key" opcode now sets pitch_keycenter too
* sfz engine: fixed error when unloading instrument with same sample
  used by multiple regions
* sfz parser: added some opcode aliases, like loopmode for loop_mode,
  to be more compatible

1 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6     * Copyright (C) 2005 - 2009 Christian Schoenebeck *
7     * 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    
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     #define GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE 128
40    
41     namespace LinuxSampler {
42    
43     template <class F /* Instrument File */, class I /* Instrument */, class R /* Regions */, class S /*Sample */>
44     class InstrumentManagerBase : virtual public InstrumentManager, virtual public ResourceManager<InstrumentManager::instrument_id_t, I> {
45     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     InstrumentManagerBase() { }
59     virtual ~InstrumentManagerBase() { }
60    
61     virtual InstrumentEditor* LaunchInstrumentEditor(instrument_id_t ID, void* pUserData = NULL) throw (InstrumentManagerException) {
62     throw InstrumentManagerException(
63     "Instrument editing is not supported for this instrument format"
64     );
65     }
66    
67     virtual String GetInstrumentDataStructureName(instrument_id_t ID) {
68     throw InstrumentManagerException("Not implemented");
69     }
70    
71     virtual String GetInstrumentDataStructureVersion(instrument_id_t ID) {
72     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     RegionInfoMutex.Lock();
88     for (typename RTList<R*>::Iterator i = pRegionsInUse->first() ; i != pRegionsInUse->end() ; i++) {
89     RegionInfo[*i].refCount++;
90     SampleRefCount[(*i)->pSample]++;
91     }
92     HandBack(pResource, pConsumer, true);
93     RegionInfoMutex.Unlock();
94     }
95    
96     /**
97     * Give back a region that belongs to an instrument that
98     * was previously handed back.
99     */
100     virtual void HandBackRegion(R* pRegion) {
101     RegionInfoMutex.Lock();
102     if (RegionInfo.find(pRegion) == RegionInfo.end()) {
103     std::cerr << "Handing back unknown region. This is a BUG!!!" << std::endl;
104     }
105     region_info_t& regInfo = RegionInfo[pRegion];
106     int regionRefCount = --regInfo.refCount;
107     int sampleRefCount = --SampleRefCount[pRegion->pSample];
108     if (regionRefCount == 0) {
109 persson 2058 S* pSample = pRegion->pSample;
110    
111 iliev 2012 DeleteRegionIfNotUsed(pRegion, &regInfo);
112    
113     if (sampleRefCount == 0) {
114 persson 2058 SampleRefCount.erase(pSample);
115     DeleteSampleIfNotUsed(pSample, &regInfo);
116 iliev 2012 }
117 persson 2058 RegionInfo.erase(pRegion);
118 iliev 2012 }
119     RegionInfoMutex.Unlock();
120     }
121    
122     virtual InstrumentManager::mode_t GetMode(const InstrumentManager::instrument_id_t& ID) {
123     return static_cast<InstrumentManager::mode_t>(ResourceManager<instrument_id_t, I>::AvailabilityMode(ID));
124     }
125    
126     virtual void SetMode(const InstrumentManager::instrument_id_t& ID, InstrumentManager::mode_t Mode) {
127     dmsg(2,("InstrumentManagerBase: setting mode for %s (Index=%d) to %d\n",ID.FileName.c_str(),ID.Index,Mode));
128     SetAvailabilityMode(ID, static_cast<typename ResourceManager<instrument_id_t, I>::mode_t>(Mode));
129     }
130    
131     protected:
132     Mutex RegionInfoMutex; ///< protects the RegionInfo and SampleRefCount maps from concurrent access by the instrument loader and disk threads
133     std::map< R*, region_info_t> RegionInfo; ///< contains dimension regions that are still in use but belong to released instrument
134     std::map< S*, int> SampleRefCount; ///< contains samples that are still in use but belong to a released instrument
135    
136     /**
137     * Caches a certain size at the beginning of the given sample in RAM. If the
138     * sample is very short, the whole sample will be loaded into RAM and thus
139     * no disk streaming is needed for this sample. Caching an initial part of
140     * samples is needed to compensate disk reading latency.
141     *
142     * @param pSample - points to the sample to be cached
143     * @param pEngine - pointer to Engine which caused this call
144     * (may be NULL, in this case default amount of samples
145     * will be cached)
146     */
147     virtual void CacheInitialSamples(S* pSample, AbstractEngine* pEngine) = 0;
148    
149     virtual void DeleteRegionIfNotUsed(R* pRegion, region_info_t* pRegInfo) = 0;
150     virtual void DeleteSampleIfNotUsed(S* pSample, region_info_t* pRegInfo) = 0;
151    
152 iliev 2027 void SetKeyBindings(uint8_t* bindingsArray, int low, int high, int undefined = -1) {
153     if (low == undefined || high == undefined) return;
154     if (low < 0 || low > 127 || high < 0 || high > 127 || low > high) {
155     std::cerr << "Invalid key range: " << low << " - " << high << std::endl;
156     return;
157     }
158    
159     for (int i = low; i <= high; i++) bindingsArray[i] = 1;
160     }
161    
162 iliev 2012 };
163    
164     template <class F /* Instrument File */, class I /* Instrument */, class R /* Region */, class S /* Sample */>
165     class InstrumentManagerDefaultImpl : public InstrumentManagerBase<F, I, R, S> {
166     public:
167     InstrumentManagerDefaultImpl() { }
168     virtual ~InstrumentManagerDefaultImpl() { }
169     protected:
170     virtual void CacheInitialSamples(S* pSample, AbstractEngine* pEngine) {
171     if (!pSample) {
172     dmsg(4,("InstrumentManagerBase: Skipping sample (pSample == NULL)\n"));
173     return;
174     }
175     if (!pSample->GetTotalFrameCount()) return; // skip zero size samples
176    
177     if (pSample->GetTotalFrameCount() <= CONFIG_PRELOAD_SAMPLES) {
178     // Sample is too short for disk streaming, so we load the whole
179     // sample into RAM and place 'pAudioIO->FragmentSize << CONFIG_MAX_PITCH'
180     // number of '0' samples (silence samples) behind the official buffer
181     // border, to allow the interpolator do it's work even at the end of
182     // the sample.
183     const uint maxSamplesPerCycle =
184     (pEngine) ? pEngine->pAudioOutputDevice->MaxSamplesPerCycle()
185     : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
186     const uint neededSilenceSamples = (maxSamplesPerCycle << CONFIG_MAX_PITCH) + 3;
187     const uint currentlyCachedSilenceSamples = pSample->GetCache().NullExtensionSize / pSample->GetFrameSize();
188     if (currentlyCachedSilenceSamples < neededSilenceSamples) {
189     dmsg(3,("Caching whole sample (sample name: \"%s\", sample size: %d)\n", pSample->GetName().c_str(), pSample->GetTotalFrameCount()));
190     typename S::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(neededSilenceSamples);
191     dmsg(4,("Cached %d Bytes, %d silence bytes.\n", buf.Size, buf.NullExtensionSize));
192     }
193     }
194     else { // we only cache CONFIG_PRELOAD_SAMPLES and stream the other sample points from disk
195     if (!pSample->GetCache().Size) pSample->LoadSampleData(CONFIG_PRELOAD_SAMPLES);
196     }
197    
198     if (!pSample->GetCache().Size) std::cerr << "Unable to cache sample - maybe memory full!" << std::endl << std::flush;
199     }
200    
201     /**
202     * Just a wrapper around the other @c CacheInitialSamples() method.
203     *
204     * @param pSample - points to the sample to be cached
205     * @param pEngine - pointer to Gig Engine Channel which caused this call
206     * (may be NULL, in this case default amount of samples
207     * will be cached)
208     */
209     virtual void CacheInitialSamples(S* pSample, EngineChannel* pEngineChannel) {
210     AbstractEngine* pEngine =
211     (pEngineChannel && pEngineChannel->GetEngine()) ?
212     dynamic_cast<AbstractEngine*>(pEngineChannel->GetEngine()) : NULL;
213     CacheInitialSamples(pSample, pEngine);
214     }
215     };
216    
217     } // namespace LinuxSampler
218    
219 persson 2045 #endif // __LS_INSTRUMENTMANAGERBASE_H__

  ViewVC Help
Powered by ViewVC