/[svn]/linuxsampler/trunk/src/engines/sf2/InstrumentResourceManager.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/engines/sf2/InstrumentResourceManager.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2275 - (hide annotations) (download)
Mon Sep 19 21:48:45 2011 UTC (10 years ago) by schoenebeck
File size: 13379 byte(s)
* Bugfix: When creating MIDI instrument map entries with "PERSISTENT"
  type, the instruments were uselessly precached with zero samples,
  however it still took the full preloading time and on 1st program
  change the respective instrument was completely reloaded again.
* Bumped version to 1.0.0.svn15

1 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 2275 * Copyright (C) 2005 - 2011 Christian Schoenebeck *
7 persson 2185 * Copyright (C) 2009 - 2011 Grigor Iliev *
8 iliev 2012 * *
9     * This program 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 program 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 program; if not, write to the Free Software *
21     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
22     * MA 02111-1307 USA *
23     ***************************************************************************/
24    
25     #include <sstream>
26    
27     #include "InstrumentResourceManager.h"
28     #include "EngineChannel.h"
29     #include "Engine.h"
30    
31     #include "../../common/global_private.h"
32     #include "../../common/Path.h"
33     #include "../../plugins/InstrumentEditorFactory.h"
34    
35    
36     namespace LinuxSampler { namespace sf2 {
37    
38     // data stored as long as an instrument resource exists
39     struct instr_entry_t {
40     InstrumentManager::instrument_id_t ID;
41     ::sf2::File* pSf2;
42     uint MaxSamplesPerCycle; ///< if some engine requests an already allocated instrument with a higher value, we have to reallocate the instrument
43     };
44    
45     // some data needed for the libgig callback function
46     struct progress_callback_arg_t {
47     InstrumentResourceManager* pManager;
48     InstrumentManager::instrument_id_t* pInstrumentKey;
49     };
50    
51     std::vector<InstrumentResourceManager::instrument_id_t> InstrumentResourceManager::Instruments() {
52     return Entries();
53     }
54    
55     String InstrumentResourceManager::GetInstrumentName(instrument_id_t ID) {
56     Lock();
57 iliev 2027 ::sf2::Preset* pInstrument = Resource(ID, false);
58 iliev 2012 String res = (pInstrument) ? pInstrument->GetName() : "";
59     Unlock();
60     return res;
61     }
62    
63     std::vector<InstrumentResourceManager::instrument_id_t> InstrumentResourceManager::GetInstrumentFileContent(String File) throw (InstrumentManagerException) {
64     ::RIFF::File* riff = NULL;
65     ::sf2::File* sf2 = NULL;
66     try {
67     std::vector<instrument_id_t> result;
68     riff = new ::RIFF::File(File);
69     sf2 = new ::sf2::File(riff);
70     for (int i = 0; i < GetSfInstrumentCount(sf2); i++) {
71     instrument_id_t id;
72     id.FileName = File;
73     id.Index = i;
74     result.push_back(id);
75     }
76     if (sf2) delete sf2;
77     if (riff) delete riff;
78     return result;
79     } catch (::RIFF::Exception e) {
80     if (sf2) delete sf2;
81     if (riff) delete riff;
82     throw InstrumentManagerException(e.Message);
83     } catch (...) {
84     if (sf2) delete sf2;
85     if (riff) delete riff;
86     throw InstrumentManagerException("Unknown exception while trying to parse '" + File + "'");
87     }
88     }
89    
90     InstrumentResourceManager::instrument_info_t InstrumentResourceManager::GetInstrumentInfo(instrument_id_t ID) throw (InstrumentManagerException) {
91     Lock();
92 iliev 2027 ::sf2::Preset* pInstrument = Resource(ID, false);
93 iliev 2012 bool loaded = (pInstrument != NULL);
94     if (!loaded) Unlock();
95    
96     ::RIFF::File* riff = NULL;
97     ::sf2::File* sf2 = NULL;
98     try {
99     if(!loaded) {
100     riff = new ::RIFF::File(ID.FileName);
101     sf2 = new ::sf2::File(riff);
102     pInstrument = GetSfInstrument(sf2, ID.Index);
103     }
104    
105     instrument_info_t info;
106     for (int i = 0; i < 128; i++) { info.KeyBindings[i] = info.KeySwitchBindings[i] = 0; }
107    
108     ::sf2::File* pFile = pInstrument->GetFile();
109    
110     info.FormatVersion = ToString(pFile->pInfo->pVer->Major);
111     info.Product = pFile->pInfo->Product;
112     info.Artists = pFile->pInfo->Engineers;
113    
114     info.InstrumentName = pInstrument->Name;
115    
116     for (int i = 0; i < pInstrument->GetRegionCount(); i++) {
117     int low = pInstrument->GetRegion(i)->loKey;
118     int high = pInstrument->GetRegion(i)->hiKey;
119 iliev 2027 if (low == ::sf2::NONE || high == ::sf2::NONE) {
120     ::sf2::Instrument* layer = pInstrument->GetRegion(i)->pInstrument;
121     for (int j = 0; j < layer->GetRegionCount(); j++) {
122     int lo = layer->GetRegion(j)->loKey;
123     int hi = layer->GetRegion(j)->hiKey;
124     SetKeyBindings(info.KeyBindings, lo, hi, ::sf2::NONE);
125     }
126 iliev 2012 } else {
127 iliev 2027 SetKeyBindings(info.KeyBindings, low, high, ::sf2::NONE);
128 iliev 2012 }
129     }
130    
131     if (loaded) Unlock();
132    
133     if (sf2) delete sf2;
134     if (riff) delete riff;
135     return info;
136     } catch (::sf2::Exception e) {
137     if (loaded) Unlock();
138     if (sf2) delete sf2;
139     if (riff) delete riff;
140     throw InstrumentManagerException(e.Message);
141     } catch (...) {
142     if (loaded) Unlock();
143     if (sf2) delete sf2;
144     if (riff) delete riff;
145     throw InstrumentManagerException("Unknown exception while trying to parse '" + ID.FileName + "'");
146     }
147     }
148    
149 iliev 2027 ::sf2::Preset* InstrumentResourceManager::Create(instrument_id_t Key, InstrumentConsumer* pConsumer, void*& pArg) {
150 iliev 2012 // get sfz file from internal sfz file manager
151 persson 2185 ::sf2::File* pSf2 = Sf2s.Borrow(Key.FileName, reinterpret_cast<Sf2Consumer*>(Key.Index)); // conversion kinda hackish :/
152 iliev 2012
153     dmsg(1,("Loading sf2 instrument ('%s',%d)...",Key.FileName.c_str(),Key.Index));
154 iliev 2027 ::sf2::Preset* pInstrument = GetSfInstrument(pSf2, Key.Index);
155 iliev 2012 dmsg(1,("OK\n"));
156    
157     // cache initial samples points (for actually needed samples)
158     dmsg(1,("Caching initial samples..."));
159     float regTotal = 0, regCurrent = 0;
160     for(int i = 0 ; i < pInstrument->GetRegionCount(); i++) {
161     ::sf2::Instrument* sf2Instr = pInstrument->GetRegion(i)->pInstrument;
162     if(sf2Instr) regTotal += sf2Instr->GetRegionCount();
163     }
164     for(int i = 0 ; i < pInstrument->GetRegionCount(); i++) {
165     ::sf2::Instrument* sf2Instr = pInstrument->GetRegion(i)->pInstrument;
166     if(sf2Instr != NULL) {
167     // pInstrument is ::sf2::Preset
168     for(int j = 0; j < sf2Instr->GetRegionCount(); j++) {
169     const float localProgress = regCurrent++ / regTotal;
170     DispatchResourceProgressEvent(Key, localProgress);
171     CacheInitialSamples(sf2Instr->GetRegion(j)->GetSample(), dynamic_cast<AbstractEngineChannel*>(pConsumer));
172     }
173     }
174     }
175     dmsg(1,("OK\n"));
176     DispatchResourceProgressEvent(Key, 1.0f); // done; notify all consumers about progress 100%
177    
178     // we need the following for destruction later
179     instr_entry_t* pEntry = new instr_entry_t;
180     pEntry->ID.FileName = Key.FileName;
181     pEntry->ID.Index = Key.Index;
182     pEntry->pSf2 = pSf2;
183    
184 schoenebeck 2275 // (try to resolve the audio device context)
185 iliev 2012 EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(pConsumer);
186 schoenebeck 2275 AudioOutputDevice* pDevice =
187     (pEngineChannel) ? dynamic_cast<Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice : NULL;
188    
189 iliev 2012 // and we save this to check if we need to reallocate for a engine with higher value of 'MaxSamplesPerSecond'
190     pEntry->MaxSamplesPerCycle =
191 schoenebeck 2275 (pDevice) ? pDevice->MaxSamplesPerCycle() : DefaultMaxSamplesPerCycle();
192    
193 iliev 2012 pArg = pEntry;
194    
195     return pInstrument;
196     }
197    
198 iliev 2027 void InstrumentResourceManager::Destroy( ::sf2::Preset* pResource, void* pArg) {
199 iliev 2012 instr_entry_t* pEntry = (instr_entry_t*) pArg;
200     // we don't need the .sf2 file here anymore
201 persson 2185 Sf2s.HandBack(pEntry->pSf2, reinterpret_cast<Sf2Consumer*>(pEntry->ID.Index)); // conversion kinda hackish :/
202 iliev 2012 delete pEntry;
203     }
204    
205 iliev 2027 void InstrumentResourceManager::OnBorrow(::sf2::Preset* pResource, InstrumentConsumer* pConsumer, void*& pArg) {
206 iliev 2012 instr_entry_t* pEntry = (instr_entry_t*) pArg;
207 schoenebeck 2275
208     // (try to resolve the audio device context)
209 iliev 2012 EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(pConsumer);
210 schoenebeck 2275 AudioOutputDevice* pDevice =
211     (pEngineChannel) ? dynamic_cast<Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice : NULL;
212    
213 iliev 2012 uint maxSamplesPerCycle =
214 schoenebeck 2275 (pDevice) ? pDevice->MaxSamplesPerCycle() : DefaultMaxSamplesPerCycle();
215    
216 iliev 2012 if (pEntry->MaxSamplesPerCycle < maxSamplesPerCycle) {
217 schoenebeck 2275 dmsg(1,("Completely reloading instrument due to insufficient precached samples ...\n"));
218 iliev 2012 Update(pResource, pConsumer);
219     }
220     }
221    
222     void InstrumentResourceManager::DeleteRegionIfNotUsed(::sf2::Region* pRegion, region_info_t* pRegInfo) {
223     // TODO: we could delete Region and Instrument here if they have become unused
224     }
225    
226     void InstrumentResourceManager::DeleteSampleIfNotUsed(::sf2::Sample* pSample, region_info_t* pRegInfo) {
227     ::sf2::File* sf2 = pRegInfo->file;
228     ::RIFF::File* riff = static_cast< ::RIFF::File*>(pRegInfo->pArg);
229     if (sf2) {
230     sf2->DeleteSample(pSample);
231     if (!sf2->HasSamples()) {
232     dmsg(2,("No more samples in use - freeing sf2\n"));
233     delete sf2;
234     delete riff;
235     }
236     }
237     }
238    
239    
240    
241     // internal sfz file manager
242    
243     ::sf2::File* InstrumentResourceManager::Sf2ResourceManager::Create(String Key, Sf2Consumer* pConsumer, void*& pArg) {
244     dmsg(1,("Loading sf2 file \'%s\'...", Key.c_str()));
245     ::RIFF::File* pRIFF = new ::RIFF::File(Key);
246     ::sf2::File* pSf2 = new ::sf2::File(pRIFF);
247     pArg = pRIFF;
248     dmsg(1,("OK\n"));
249     return pSf2;
250     }
251    
252     void InstrumentResourceManager::Sf2ResourceManager::Destroy(::sf2::File* pResource, void* pArg) {
253     dmsg(1,("Freeing sf2 file from memory..."));
254    
255 iliev 2021 // Delete as much as possible of the sf2 file. Some of the
256 iliev 2012 // regions and samples may still be in use - these
257     // will be deleted later by the HandBackRegion function.
258 iliev 2021 bool deleteFile = true;
259 iliev 2012
260 iliev 2021 for (int i = pResource->GetInstrumentCount() - 1; i >= 0; i--) {
261     ::sf2::Instrument* pInstr = pResource->GetInstrument(i);
262     bool deleteInstrument = true;
263    
264     for (int j = pInstr->GetRegionCount() - 1; j >= 0 ; j--) {
265     ::sf2::Region* pRegion = pInstr->GetRegion(j);
266     std::map< ::sf2::Region*, region_info_t>::iterator iter = parent->RegionInfo.find(pRegion);
267     if (iter != parent->RegionInfo.end()) {
268     region_info_t& regInfo = (*iter).second;
269     regInfo.file = pResource;
270     deleteFile = deleteInstrument = false;
271     } else {
272     pInstr->DeleteRegion(pRegion);
273     }
274 iliev 2012 }
275 iliev 2021
276     if (deleteInstrument) pResource->DeleteInstrument(pInstr);
277 iliev 2012 }
278    
279 iliev 2021 if (deleteFile) {
280     delete pResource;
281     delete (::RIFF::File*) pArg;
282     } else {
283     dmsg(2,("keeping some samples that are in use..."));
284     for (int i = pResource->GetSampleCount() - 1; i >= 0; i--) {
285     ::sf2::Sample* sample = pResource->GetSample(i);
286     if (parent->SampleRefCount.find(sample) == parent->SampleRefCount.end()) {
287     pResource->DeleteSample(sample);
288     }
289     }
290     }
291 iliev 2012
292     dmsg(1,("OK\n"));
293     }
294    
295     int InstrumentResourceManager::GetSfInstrumentCount(::sf2::File* pFile) {
296 iliev 2027 return pFile->GetPresetCount();
297 iliev 2012 }
298    
299 iliev 2027 ::sf2::Preset* InstrumentResourceManager::GetSfInstrument(::sf2::File* pFile, int idx) {
300     if (idx >= pFile->GetPresetCount()) {
301 iliev 2012 throw InstrumentManagerException("There is no instrument with index " + ToString(idx));
302     }
303 iliev 2027 return pFile->GetPreset(idx);
304 iliev 2012 }
305    
306     }} // namespace LinuxSampler::sfz

  ViewVC Help
Powered by ViewVC