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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2275 - (show annotations) (download)
Mon Sep 19 21:48:45 2011 UTC (9 years, 11 months 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 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2011 Christian Schoenebeck *
7 * Copyright (C) 2009 - 2011 Grigor Iliev *
8 * *
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 ::sf2::Preset* pInstrument = Resource(ID, false);
58 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 ::sf2::Preset* pInstrument = Resource(ID, false);
93 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 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 } else {
127 SetKeyBindings(info.KeyBindings, low, high, ::sf2::NONE);
128 }
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 ::sf2::Preset* InstrumentResourceManager::Create(instrument_id_t Key, InstrumentConsumer* pConsumer, void*& pArg) {
150 // get sfz file from internal sfz file manager
151 ::sf2::File* pSf2 = Sf2s.Borrow(Key.FileName, reinterpret_cast<Sf2Consumer*>(Key.Index)); // conversion kinda hackish :/
152
153 dmsg(1,("Loading sf2 instrument ('%s',%d)...",Key.FileName.c_str(),Key.Index));
154 ::sf2::Preset* pInstrument = GetSfInstrument(pSf2, Key.Index);
155 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 // (try to resolve the audio device context)
185 EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(pConsumer);
186 AudioOutputDevice* pDevice =
187 (pEngineChannel) ? dynamic_cast<Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice : NULL;
188
189 // and we save this to check if we need to reallocate for a engine with higher value of 'MaxSamplesPerSecond'
190 pEntry->MaxSamplesPerCycle =
191 (pDevice) ? pDevice->MaxSamplesPerCycle() : DefaultMaxSamplesPerCycle();
192
193 pArg = pEntry;
194
195 return pInstrument;
196 }
197
198 void InstrumentResourceManager::Destroy( ::sf2::Preset* pResource, void* pArg) {
199 instr_entry_t* pEntry = (instr_entry_t*) pArg;
200 // we don't need the .sf2 file here anymore
201 Sf2s.HandBack(pEntry->pSf2, reinterpret_cast<Sf2Consumer*>(pEntry->ID.Index)); // conversion kinda hackish :/
202 delete pEntry;
203 }
204
205 void InstrumentResourceManager::OnBorrow(::sf2::Preset* pResource, InstrumentConsumer* pConsumer, void*& pArg) {
206 instr_entry_t* pEntry = (instr_entry_t*) pArg;
207
208 // (try to resolve the audio device context)
209 EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(pConsumer);
210 AudioOutputDevice* pDevice =
211 (pEngineChannel) ? dynamic_cast<Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice : NULL;
212
213 uint maxSamplesPerCycle =
214 (pDevice) ? pDevice->MaxSamplesPerCycle() : DefaultMaxSamplesPerCycle();
215
216 if (pEntry->MaxSamplesPerCycle < maxSamplesPerCycle) {
217 dmsg(1,("Completely reloading instrument due to insufficient precached samples ...\n"));
218 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 // Delete as much as possible of the sf2 file. Some of the
256 // regions and samples may still be in use - these
257 // will be deleted later by the HandBackRegion function.
258 bool deleteFile = true;
259
260 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 }
275
276 if (deleteInstrument) pResource->DeleteInstrument(pInstr);
277 }
278
279 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
292 dmsg(1,("OK\n"));
293 }
294
295 int InstrumentResourceManager::GetSfInstrumentCount(::sf2::File* pFile) {
296 return pFile->GetPresetCount();
297 }
298
299 ::sf2::Preset* InstrumentResourceManager::GetSfInstrument(::sf2::File* pFile, int idx) {
300 if (idx >= pFile->GetPresetCount()) {
301 throw InstrumentManagerException("There is no instrument with index " + ToString(idx));
302 }
303 return pFile->GetPreset(idx);
304 }
305
306 }} // namespace LinuxSampler::sfz

  ViewVC Help
Powered by ViewVC