/[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 2185 - (hide annotations) (download)
Sun Jun 19 09:09:38 2011 UTC (12 years, 10 months ago) by persson
File size: 13247 byte(s)
* fixed compilation with gcc 4.6.1
* another "make dist" fix, for LV2 plugin
* made --enable-pthread-testcancel default on Mac OS X
* Mac OS X: fixed hanging threads

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 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     EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(pConsumer);
185     // and we save this to check if we need to reallocate for a engine with higher value of 'MaxSamplesPerSecond'
186     pEntry->MaxSamplesPerCycle =
187     (!pEngineChannel) ? 0 /* don't care for instrument editors */ :
188     (pEngineChannel->GetEngine()) ?
189     dynamic_cast<Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle()
190     : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
191     pArg = pEntry;
192    
193     return pInstrument;
194     }
195    
196 iliev 2027 void InstrumentResourceManager::Destroy( ::sf2::Preset* pResource, void* pArg) {
197 iliev 2012 instr_entry_t* pEntry = (instr_entry_t*) pArg;
198     // we don't need the .sf2 file here anymore
199 persson 2185 Sf2s.HandBack(pEntry->pSf2, reinterpret_cast<Sf2Consumer*>(pEntry->ID.Index)); // conversion kinda hackish :/
200 iliev 2012 delete pEntry;
201     }
202    
203 iliev 2027 void InstrumentResourceManager::OnBorrow(::sf2::Preset* pResource, InstrumentConsumer* pConsumer, void*& pArg) {
204 iliev 2012 instr_entry_t* pEntry = (instr_entry_t*) pArg;
205     EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(pConsumer);
206     uint maxSamplesPerCycle =
207     (pEngineChannel && pEngineChannel->GetEngine()) ? dynamic_cast<Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle()
208     : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
209     if (pEntry->MaxSamplesPerCycle < maxSamplesPerCycle) {
210     Update(pResource, pConsumer);
211     }
212     }
213    
214     void InstrumentResourceManager::DeleteRegionIfNotUsed(::sf2::Region* pRegion, region_info_t* pRegInfo) {
215     // TODO: we could delete Region and Instrument here if they have become unused
216     }
217    
218     void InstrumentResourceManager::DeleteSampleIfNotUsed(::sf2::Sample* pSample, region_info_t* pRegInfo) {
219     ::sf2::File* sf2 = pRegInfo->file;
220     ::RIFF::File* riff = static_cast< ::RIFF::File*>(pRegInfo->pArg);
221     if (sf2) {
222     sf2->DeleteSample(pSample);
223     if (!sf2->HasSamples()) {
224     dmsg(2,("No more samples in use - freeing sf2\n"));
225     delete sf2;
226     delete riff;
227     }
228     }
229     }
230    
231    
232    
233     // internal sfz file manager
234    
235     ::sf2::File* InstrumentResourceManager::Sf2ResourceManager::Create(String Key, Sf2Consumer* pConsumer, void*& pArg) {
236     dmsg(1,("Loading sf2 file \'%s\'...", Key.c_str()));
237     ::RIFF::File* pRIFF = new ::RIFF::File(Key);
238     ::sf2::File* pSf2 = new ::sf2::File(pRIFF);
239     pArg = pRIFF;
240     dmsg(1,("OK\n"));
241     return pSf2;
242     }
243    
244     void InstrumentResourceManager::Sf2ResourceManager::Destroy(::sf2::File* pResource, void* pArg) {
245     dmsg(1,("Freeing sf2 file from memory..."));
246    
247 iliev 2021 // Delete as much as possible of the sf2 file. Some of the
248 iliev 2012 // regions and samples may still be in use - these
249     // will be deleted later by the HandBackRegion function.
250 iliev 2021 bool deleteFile = true;
251 iliev 2012
252 iliev 2021 for (int i = pResource->GetInstrumentCount() - 1; i >= 0; i--) {
253     ::sf2::Instrument* pInstr = pResource->GetInstrument(i);
254     bool deleteInstrument = true;
255    
256     for (int j = pInstr->GetRegionCount() - 1; j >= 0 ; j--) {
257     ::sf2::Region* pRegion = pInstr->GetRegion(j);
258     std::map< ::sf2::Region*, region_info_t>::iterator iter = parent->RegionInfo.find(pRegion);
259     if (iter != parent->RegionInfo.end()) {
260     region_info_t& regInfo = (*iter).second;
261     regInfo.file = pResource;
262     deleteFile = deleteInstrument = false;
263     } else {
264     pInstr->DeleteRegion(pRegion);
265     }
266 iliev 2012 }
267 iliev 2021
268     if (deleteInstrument) pResource->DeleteInstrument(pInstr);
269 iliev 2012 }
270    
271 iliev 2021 if (deleteFile) {
272     delete pResource;
273     delete (::RIFF::File*) pArg;
274     } else {
275     dmsg(2,("keeping some samples that are in use..."));
276     for (int i = pResource->GetSampleCount() - 1; i >= 0; i--) {
277     ::sf2::Sample* sample = pResource->GetSample(i);
278     if (parent->SampleRefCount.find(sample) == parent->SampleRefCount.end()) {
279     pResource->DeleteSample(sample);
280     }
281     }
282     }
283 iliev 2012
284     dmsg(1,("OK\n"));
285     }
286    
287     int InstrumentResourceManager::GetSfInstrumentCount(::sf2::File* pFile) {
288 iliev 2027 return pFile->GetPresetCount();
289 iliev 2012 }
290    
291 iliev 2027 ::sf2::Preset* InstrumentResourceManager::GetSfInstrument(::sf2::File* pFile, int idx) {
292     if (idx >= pFile->GetPresetCount()) {
293 iliev 2012 throw InstrumentManagerException("There is no instrument with index " + ToString(idx));
294     }
295 iliev 2027 return pFile->GetPreset(idx);
296 iliev 2012 }
297    
298     }} // namespace LinuxSampler::sfz

  ViewVC Help
Powered by ViewVC