/[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 2326 - (hide annotations) (download)
Thu Mar 8 19:40:14 2012 UTC (12 years, 1 month ago) by persson
File size: 11527 byte(s)
* bugfix: instrument loading crashed for sfz and sf2 in Ardour (#176)
* more thread safety fixes for the instrument loading thread

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     * Copyright (C) 2009 - 2012 Christian Schoenebeck and 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     String InstrumentResourceManager::GetInstrumentName(instrument_id_t ID) {
39     Lock();
40 iliev 2027 ::sf2::Preset* pInstrument = Resource(ID, false);
41 iliev 2012 String res = (pInstrument) ? pInstrument->GetName() : "";
42     Unlock();
43     return res;
44     }
45    
46     std::vector<InstrumentResourceManager::instrument_id_t> InstrumentResourceManager::GetInstrumentFileContent(String File) throw (InstrumentManagerException) {
47     ::RIFF::File* riff = NULL;
48     ::sf2::File* sf2 = NULL;
49     try {
50     std::vector<instrument_id_t> result;
51     riff = new ::RIFF::File(File);
52     sf2 = new ::sf2::File(riff);
53     for (int i = 0; i < GetSfInstrumentCount(sf2); i++) {
54     instrument_id_t id;
55     id.FileName = File;
56     id.Index = i;
57     result.push_back(id);
58     }
59     if (sf2) delete sf2;
60     if (riff) delete riff;
61     return result;
62     } catch (::RIFF::Exception e) {
63     if (sf2) delete sf2;
64     if (riff) delete riff;
65     throw InstrumentManagerException(e.Message);
66     } catch (...) {
67     if (sf2) delete sf2;
68     if (riff) delete riff;
69     throw InstrumentManagerException("Unknown exception while trying to parse '" + File + "'");
70     }
71     }
72    
73     InstrumentResourceManager::instrument_info_t InstrumentResourceManager::GetInstrumentInfo(instrument_id_t ID) throw (InstrumentManagerException) {
74     Lock();
75 iliev 2027 ::sf2::Preset* pInstrument = Resource(ID, false);
76 iliev 2012 bool loaded = (pInstrument != NULL);
77     if (!loaded) Unlock();
78    
79     ::RIFF::File* riff = NULL;
80     ::sf2::File* sf2 = NULL;
81     try {
82 persson 2326 if (!loaded) {
83 iliev 2012 riff = new ::RIFF::File(ID.FileName);
84     sf2 = new ::sf2::File(riff);
85     pInstrument = GetSfInstrument(sf2, ID.Index);
86     }
87    
88     instrument_info_t info;
89     for (int i = 0; i < 128; i++) { info.KeyBindings[i] = info.KeySwitchBindings[i] = 0; }
90    
91     ::sf2::File* pFile = pInstrument->GetFile();
92    
93     info.FormatVersion = ToString(pFile->pInfo->pVer->Major);
94     info.Product = pFile->pInfo->Product;
95     info.Artists = pFile->pInfo->Engineers;
96    
97     info.InstrumentName = pInstrument->Name;
98    
99     for (int i = 0; i < pInstrument->GetRegionCount(); i++) {
100     int low = pInstrument->GetRegion(i)->loKey;
101     int high = pInstrument->GetRegion(i)->hiKey;
102 iliev 2027 if (low == ::sf2::NONE || high == ::sf2::NONE) {
103     ::sf2::Instrument* layer = pInstrument->GetRegion(i)->pInstrument;
104     for (int j = 0; j < layer->GetRegionCount(); j++) {
105     int lo = layer->GetRegion(j)->loKey;
106     int hi = layer->GetRegion(j)->hiKey;
107     SetKeyBindings(info.KeyBindings, lo, hi, ::sf2::NONE);
108     }
109 iliev 2012 } else {
110 iliev 2027 SetKeyBindings(info.KeyBindings, low, high, ::sf2::NONE);
111 iliev 2012 }
112     }
113    
114     if (loaded) Unlock();
115    
116     if (sf2) delete sf2;
117     if (riff) delete riff;
118     return info;
119     } catch (::sf2::Exception e) {
120     if (loaded) Unlock();
121     if (sf2) delete sf2;
122     if (riff) delete riff;
123     throw InstrumentManagerException(e.Message);
124     } catch (...) {
125     if (loaded) Unlock();
126     if (sf2) delete sf2;
127     if (riff) delete riff;
128     throw InstrumentManagerException("Unknown exception while trying to parse '" + ID.FileName + "'");
129     }
130     }
131    
132 iliev 2027 ::sf2::Preset* InstrumentResourceManager::Create(instrument_id_t Key, InstrumentConsumer* pConsumer, void*& pArg) {
133 iliev 2012 // get sfz file from internal sfz file manager
134 persson 2185 ::sf2::File* pSf2 = Sf2s.Borrow(Key.FileName, reinterpret_cast<Sf2Consumer*>(Key.Index)); // conversion kinda hackish :/
135 iliev 2012
136     dmsg(1,("Loading sf2 instrument ('%s',%d)...",Key.FileName.c_str(),Key.Index));
137 iliev 2027 ::sf2::Preset* pInstrument = GetSfInstrument(pSf2, Key.Index);
138 iliev 2012 dmsg(1,("OK\n"));
139    
140     // cache initial samples points (for actually needed samples)
141     dmsg(1,("Caching initial samples..."));
142     float regTotal = 0, regCurrent = 0;
143 persson 2326 for (int i = 0 ; i < pInstrument->GetRegionCount() ; i++) {
144 iliev 2012 ::sf2::Instrument* sf2Instr = pInstrument->GetRegion(i)->pInstrument;
145 persson 2326 if (sf2Instr) regTotal += sf2Instr->GetRegionCount();
146 iliev 2012 }
147 persson 2326 uint maxSamplesPerCycle = GetMaxSamplesPerCycle(pConsumer);
148     for (int i = 0 ; i < pInstrument->GetRegionCount() ; i++) {
149 iliev 2012 ::sf2::Instrument* sf2Instr = pInstrument->GetRegion(i)->pInstrument;
150 persson 2326 if (sf2Instr) {
151 iliev 2012 // pInstrument is ::sf2::Preset
152 persson 2326 for (int j = 0 ; j < sf2Instr->GetRegionCount() ; j++) {
153     float localProgress = regCurrent++ / regTotal;
154 iliev 2012 DispatchResourceProgressEvent(Key, localProgress);
155 persson 2326 CacheInitialSamples(sf2Instr->GetRegion(j)->GetSample(), maxSamplesPerCycle);
156 iliev 2012 }
157     }
158     }
159     dmsg(1,("OK\n"));
160     DispatchResourceProgressEvent(Key, 1.0f); // done; notify all consumers about progress 100%
161    
162     // we need the following for destruction later
163     instr_entry_t* pEntry = new instr_entry_t;
164     pEntry->ID.FileName = Key.FileName;
165     pEntry->ID.Index = Key.Index;
166 persson 2326 pEntry->pFile = pSf2;
167 iliev 2012
168 persson 2326 // and we save this to check if we need to reallocate for an engine with higher value of 'MaxSamplesPerSecond'
169     pEntry->MaxSamplesPerCycle = maxSamplesPerCycle;
170 schoenebeck 2275
171 iliev 2012 pArg = pEntry;
172    
173     return pInstrument;
174     }
175    
176 persson 2326 void InstrumentResourceManager::Destroy(::sf2::Preset* pResource, void* pArg) {
177 iliev 2012 instr_entry_t* pEntry = (instr_entry_t*) pArg;
178     // we don't need the .sf2 file here anymore
179 persson 2326 Sf2s.HandBack(pEntry->pFile, reinterpret_cast<Sf2Consumer*>(pEntry->ID.Index)); // conversion kinda hackish :/
180 iliev 2012 delete pEntry;
181     }
182    
183     void InstrumentResourceManager::DeleteRegionIfNotUsed(::sf2::Region* pRegion, region_info_t* pRegInfo) {
184     // TODO: we could delete Region and Instrument here if they have become unused
185     }
186    
187     void InstrumentResourceManager::DeleteSampleIfNotUsed(::sf2::Sample* pSample, region_info_t* pRegInfo) {
188     ::sf2::File* sf2 = pRegInfo->file;
189     ::RIFF::File* riff = static_cast< ::RIFF::File*>(pRegInfo->pArg);
190     if (sf2) {
191     sf2->DeleteSample(pSample);
192     if (!sf2->HasSamples()) {
193     dmsg(2,("No more samples in use - freeing sf2\n"));
194     delete sf2;
195     delete riff;
196     }
197     }
198     }
199    
200    
201    
202     // internal sfz file manager
203    
204     ::sf2::File* InstrumentResourceManager::Sf2ResourceManager::Create(String Key, Sf2Consumer* pConsumer, void*& pArg) {
205     dmsg(1,("Loading sf2 file \'%s\'...", Key.c_str()));
206     ::RIFF::File* pRIFF = new ::RIFF::File(Key);
207     ::sf2::File* pSf2 = new ::sf2::File(pRIFF);
208     pArg = pRIFF;
209     dmsg(1,("OK\n"));
210     return pSf2;
211     }
212    
213     void InstrumentResourceManager::Sf2ResourceManager::Destroy(::sf2::File* pResource, void* pArg) {
214     dmsg(1,("Freeing sf2 file from memory..."));
215    
216 iliev 2021 // Delete as much as possible of the sf2 file. Some of the
217 iliev 2012 // regions and samples may still be in use - these
218     // will be deleted later by the HandBackRegion function.
219 iliev 2021 bool deleteFile = true;
220 iliev 2012
221 iliev 2021 for (int i = pResource->GetInstrumentCount() - 1; i >= 0; i--) {
222     ::sf2::Instrument* pInstr = pResource->GetInstrument(i);
223     bool deleteInstrument = true;
224    
225     for (int j = pInstr->GetRegionCount() - 1; j >= 0 ; j--) {
226     ::sf2::Region* pRegion = pInstr->GetRegion(j);
227     std::map< ::sf2::Region*, region_info_t>::iterator iter = parent->RegionInfo.find(pRegion);
228     if (iter != parent->RegionInfo.end()) {
229     region_info_t& regInfo = (*iter).second;
230     regInfo.file = pResource;
231     deleteFile = deleteInstrument = false;
232     } else {
233     pInstr->DeleteRegion(pRegion);
234     }
235 iliev 2012 }
236 iliev 2021
237     if (deleteInstrument) pResource->DeleteInstrument(pInstr);
238 iliev 2012 }
239    
240 iliev 2021 if (deleteFile) {
241     delete pResource;
242     delete (::RIFF::File*) pArg;
243     } else {
244     dmsg(2,("keeping some samples that are in use..."));
245     for (int i = pResource->GetSampleCount() - 1; i >= 0; i--) {
246     ::sf2::Sample* sample = pResource->GetSample(i);
247     if (parent->SampleRefCount.find(sample) == parent->SampleRefCount.end()) {
248     pResource->DeleteSample(sample);
249     }
250     }
251     }
252 iliev 2012
253     dmsg(1,("OK\n"));
254     }
255    
256     int InstrumentResourceManager::GetSfInstrumentCount(::sf2::File* pFile) {
257 iliev 2027 return pFile->GetPresetCount();
258 iliev 2012 }
259    
260 iliev 2027 ::sf2::Preset* InstrumentResourceManager::GetSfInstrument(::sf2::File* pFile, int idx) {
261     if (idx >= pFile->GetPresetCount()) {
262 iliev 2012 throw InstrumentManagerException("There is no instrument with index " + ToString(idx));
263     }
264 iliev 2027 return pFile->GetPreset(idx);
265 iliev 2012 }
266    
267     }} // namespace LinuxSampler::sfz

  ViewVC Help
Powered by ViewVC