/[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 2018 - (show annotations) (download)
Tue Oct 27 19:04:57 2009 UTC (14 years, 5 months ago) by iliev
File size: 13180 byte(s)
* SFZ format engine: Implemented sfz version 1
   Filter EG, Amplifier EG and Pitch EG
* use SF2 file loader from libgig

1 /***************************************************************************
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 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::InstrumentBase* 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::InstrumentBase* 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 < 0 || low > 127 || high < 0 || high > 127 || low > high) {
120 std::cerr << "Invalid key range: " << low << " - " << high << std::endl;
121 } else {
122 for (int i = low; i <= high; i++) info.KeyBindings[i] = 1;
123 }
124 }
125
126 if (loaded) Unlock();
127
128 if (sf2) delete sf2;
129 if (riff) delete riff;
130 return info;
131 } catch (::sf2::Exception e) {
132 if (loaded) Unlock();
133 if (sf2) delete sf2;
134 if (riff) delete riff;
135 throw InstrumentManagerException(e.Message);
136 } catch (...) {
137 if (loaded) Unlock();
138 if (sf2) delete sf2;
139 if (riff) delete riff;
140 throw InstrumentManagerException("Unknown exception while trying to parse '" + ID.FileName + "'");
141 }
142 }
143
144 ::sf2::InstrumentBase* InstrumentResourceManager::Create(instrument_id_t Key, InstrumentConsumer* pConsumer, void*& pArg) {
145 // get sfz file from internal sfz file manager
146 ::sf2::File* pSf2 = Sf2s.Borrow(Key.FileName, (Sf2Consumer*) Key.Index); // conversion kinda hackish :/
147
148 dmsg(1,("Loading sf2 instrument ('%s',%d)...",Key.FileName.c_str(),Key.Index));
149 ::sf2::InstrumentBase* pInstrument = GetSfInstrument(pSf2, Key.Index);
150 dmsg(1,("OK\n"));
151
152 // cache initial samples points (for actually needed samples)
153 dmsg(1,("Caching initial samples..."));
154 float regTotal = 0, regCurrent = 0;
155 for(int i = 0 ; i < pInstrument->GetRegionCount(); i++) {
156 ::sf2::Instrument* sf2Instr = pInstrument->GetRegion(i)->pInstrument;
157 if(sf2Instr) regTotal += sf2Instr->GetRegionCount();
158 else regTotal++; // if sf2Instr is null, than pInstrument is not a preset
159 }
160 for(int i = 0 ; i < pInstrument->GetRegionCount(); i++) {
161 ::sf2::Instrument* sf2Instr = pInstrument->GetRegion(i)->pInstrument;
162 ::sf2::Sample* sf2Sample = pInstrument->GetRegion(i)->GetSample();
163 if(sf2Instr != NULL) {
164 // pInstrument is ::sf2::Preset
165 for(int j = 0; j < sf2Instr->GetRegionCount(); j++) {
166 const float localProgress = regCurrent++ / regTotal;
167 DispatchResourceProgressEvent(Key, localProgress);
168 CacheInitialSamples(sf2Instr->GetRegion(j)->GetSample(), dynamic_cast<AbstractEngineChannel*>(pConsumer));
169 }
170 } else if(sf2Sample != NULL) {
171 // pInstrument is ::sf2::Instrument
172 CacheInitialSamples(sf2Sample, dynamic_cast<AbstractEngineChannel*>(pConsumer));
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 void InstrumentResourceManager::Destroy( ::sf2::InstrumentBase* pResource, void* pArg) {
197 instr_entry_t* pEntry = (instr_entry_t*) pArg;
198 // we don't need the .sf2 file here anymore
199 Sf2s.HandBack(pEntry->pSf2, (Sf2Consumer*) pEntry->ID.Index); // conversion kinda hackish :/
200 delete pEntry;
201 }
202
203 void InstrumentResourceManager::OnBorrow(::sf2::InstrumentBase* pResource, InstrumentConsumer* pConsumer, void*& pArg) {
204 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 /* // Delete as much as possible of the sfz file. Some of the
248 // regions and samples may still be in use - these
249 // will be deleted later by the HandBackRegion function.
250 bool deleteInstrument = true;
251 ::sf2::Instrument* pInstr = pResource->GetInstrument();
252
253 for (int i = pInstr->regions.size() - 1; i >= 0 ; i--) {
254 ::sfz::Region* pRegion = pInstr->regions[i];
255 std::map< ::sfz::Region*, region_info_t>::iterator iter = parent->RegionInfo.find(pRegion);
256 if (iter != parent->RegionInfo.end()) {
257 region_info_t& regInfo = (*iter).second;
258 regInfo.file = pResource;
259 deleteInstrument = false;
260 } else {
261 SampleFile* sf = pRegion->GetSample(false);
262 if (sf != NULL) pInstr->GetSampleManager()->RemoveSampleConsumer(sf, pRegion);
263 if (sf == NULL || !pInstr->GetSampleManager()->HasSampleConsumers(sf)) pInstr->DestroyRegion(pRegion);
264 }
265 }
266
267 if(deleteInstrument) delete pResource;
268 else dmsg(2,("keeping some samples that are in use..."));*/
269
270 dmsg(1,("OK\n"));
271 }
272
273 int InstrumentResourceManager::GetSfInstrumentCount(::sf2::File* pFile) {
274 return pFile->GetInstrumentCount() + pFile->GetPresetCount();
275 }
276
277 ::sf2::InstrumentBase* InstrumentResourceManager::GetSfInstrument(::sf2::File* pFile, int idx) {
278 if (idx >= pFile->GetInstrumentCount() + pFile->GetPresetCount()) {
279 throw InstrumentManagerException("There is no instrument with index " + ToString(idx));
280 }
281
282 if (idx < pFile->GetInstrumentCount()) {
283 return pFile->GetInstrument(idx);
284 }
285
286 int presetIdx = idx - pFile->GetInstrumentCount();
287 return pFile->GetPreset(presetIdx);
288 }
289
290 }} // namespace LinuxSampler::sfz

  ViewVC Help
Powered by ViewVC