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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2012 - (show annotations) (download)
Fri Oct 23 17:53:17 2009 UTC (10 years ago) by iliev
File size: 10558 byte(s)
* Refactoring: moved the independent code from
  the Gigasampler format engine to base classes
* SFZ format engine: experimental code (not usable yet)
* SoundFont format engine: experimental code (not usable yet)
* Fixed crash which may occur when MIDI key + transpose is out of range

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 sfz {
37
38 // data stored as long as an instrument resource exists
39 struct instr_entry_t {
40 InstrumentManager::instrument_id_t ID;
41 ::sfz::File* pSfz;
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 ::sfz::Instrument* 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 std::vector<instrument_id_t> result;
65 instrument_id_t id;
66 id.FileName = File;
67 id.Index = 0;
68 result.push_back(id);
69 return result;
70 }
71
72 InstrumentResourceManager::instrument_info_t InstrumentResourceManager::GetInstrumentInfo(instrument_id_t ID) throw (InstrumentManagerException) {
73 if (ID.Index) throw InstrumentManagerException("There is no instrument " + ToString(ID.Index) + " in " + ID.FileName);
74 Lock();
75 ::sfz::Instrument* pInstrument = Resource(ID, false);
76 bool loaded = (pInstrument != NULL);
77 if (!loaded) Unlock();
78
79 ::sfz::File* sfz = NULL;
80 try {
81 if(!loaded) {
82 sfz = new ::sfz::File(ID.FileName);
83 pInstrument = sfz->GetInstrument();
84 }
85
86 if (!pInstrument) throw InstrumentManagerException("There is no instrument " + ToString(ID.Index) + " in " + ID.FileName);
87
88 instrument_info_t info;
89 info.InstrumentName = Path::getBaseName(ID.FileName);
90
91 for (int i = 0; i < 128; i++) {
92 info.KeyBindings[i] = pInstrument->HasKeyBinding(i);
93 info.KeySwitchBindings[i] = pInstrument->HasKeySwitchBinding(i);
94 }
95
96 if (loaded) Unlock();
97
98 if (sfz) delete sfz;
99 return info;
100 } catch (::sfz::Exception e) {
101 if (loaded) Unlock();
102 if (sfz) delete sfz;
103 throw InstrumentManagerException(e.Message());
104 } catch (...) {
105 if (loaded) Unlock();
106 if (sfz) delete sfz;
107 throw InstrumentManagerException("Unknown exception while trying to parse '" + ID.FileName + "'");
108 }
109 }
110
111 ::sfz::Instrument* InstrumentResourceManager::Create(instrument_id_t Key, InstrumentConsumer* pConsumer, void*& pArg) {
112 // get sfz file from internal sfz file manager
113 ::sfz::File* pSfz = Sfzs.Borrow(Key.FileName, (SfzConsumer*) Key.Index); // conversion kinda hackish :/
114
115 dmsg(1,("Loading sfz instrument ('%s',%d)...",Key.FileName.c_str(),Key.Index));
116 if (Key.Index) {
117 std::stringstream msg;
118 msg << "There's no instrument with index " << Key.Index << ".";
119 throw InstrumentManagerException(msg.str());
120 }
121 ::sfz::Instrument* pInstrument = pSfz->GetInstrument();
122 if (!pInstrument) {
123 std::stringstream msg;
124 msg << "There's no instrument with index " << Key.Index << ".";
125 throw InstrumentManagerException(msg.str());
126 }
127 dmsg(1,("OK\n"));
128
129 // cache initial samples points (for actually needed samples)
130 dmsg(1,("Caching initial samples..."));
131 int regionCount = pInstrument->regions.size();
132 for(int i = 0 ; i < regionCount; i++) {
133 const float localProgress = (float) i / (float) regionCount;
134 DispatchResourceProgressEvent(Key, localProgress);
135 CacheInitialSamples(pInstrument->regions[i]->GetSample(), dynamic_cast<AbstractEngineChannel*>(pConsumer));
136 //pInstrument->regions[i]->GetSample()->Close();
137 }
138 dmsg(1,("OK\n"));
139 DispatchResourceProgressEvent(Key, 1.0f); // done; notify all consumers about progress 100%
140
141 // we need the following for destruction later
142 instr_entry_t* pEntry = new instr_entry_t;
143 pEntry->ID.FileName = Key.FileName;
144 pEntry->ID.Index = Key.Index;
145 pEntry->pSfz = pSfz;
146
147 EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(pConsumer);
148 // and we save this to check if we need to reallocate for a engine with higher value of 'MaxSamplesPerSecond'
149 pEntry->MaxSamplesPerCycle =
150 (!pEngineChannel) ? 0 /* don't care for instrument editors */ :
151 (pEngineChannel->GetEngine()) ?
152 dynamic_cast<Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle()
153 : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
154 pArg = pEntry;
155
156 return pInstrument;
157 }
158
159 void InstrumentResourceManager::Destroy( ::sfz::Instrument* pResource, void* pArg) {
160 instr_entry_t* pEntry = (instr_entry_t*) pArg;
161 // we don't need the .sfz file here anymore
162 Sfzs.HandBack(pEntry->pSfz, (SfzConsumer*) pEntry->ID.Index); // conversion kinda hackish :/
163 delete pEntry;
164 }
165
166 void InstrumentResourceManager::OnBorrow(::sfz::Instrument* pResource, InstrumentConsumer* pConsumer, void*& pArg) {
167 instr_entry_t* pEntry = (instr_entry_t*) pArg;
168 EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(pConsumer);
169 uint maxSamplesPerCycle =
170 (pEngineChannel && pEngineChannel->GetEngine()) ? dynamic_cast<Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle()
171 : GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE;
172 if (pEntry->MaxSamplesPerCycle < maxSamplesPerCycle) {
173 Update(pResource, pConsumer);
174 }
175 }
176
177 void InstrumentResourceManager::DeleteRegionIfNotUsed(::sfz::Region* pRegion, region_info_t* pRegInfo) {
178 ::sfz::File* file = pRegInfo->file;
179 if (file == NULL) return;
180
181 file->GetInstrument()->DestroyRegion(pRegion);
182 if(file->GetInstrument()->regions.empty()) {
183 dmsg(2,("No more regions in use - freeing sfz\n"));
184 delete file;
185 }
186 }
187
188 void InstrumentResourceManager::DeleteSampleIfNotUsed(Sample* pSample, region_info_t* pRegInfo) {
189
190 }
191
192
193
194 // internal sfz file manager
195
196 ::sfz::File* InstrumentResourceManager::SfzResourceManager::Create(String Key, SfzConsumer* pConsumer, void*& pArg) {
197 dmsg(1,("Loading sfz file \'%s\'...", Key.c_str()));
198 ::sfz::File* pSfz = new ::sfz::File(Key, &sampleManager);
199 dmsg(1,("OK\n"));
200 return pSfz;
201 }
202
203 void InstrumentResourceManager::SfzResourceManager::Destroy(::sfz::File* pResource, void* pArg) {
204 dmsg(1,("Freeing sfz file from memory..."));
205
206 // Delete as much as possible of the sfz file. Some of the
207 // regions and samples may still be in use - these
208 // will be deleted later by the HandBackRegion function.
209 bool deleteInstrument = true;
210 ::sfz::Instrument* pInstr = pResource->GetInstrument();
211
212 for (int i = pInstr->regions.size() - 1; i >= 0 ; i--) {
213 ::sfz::Region* pRegion = pInstr->regions[i];
214 std::map< ::sfz::Region*, region_info_t>::iterator iter = parent->RegionInfo.find(pRegion);
215 if (iter != parent->RegionInfo.end()) {
216 region_info_t& regInfo = (*iter).second;
217 regInfo.file = pResource;
218 deleteInstrument = false;
219 } else {
220 SampleFile* sf = pRegion->GetSample(false);
221 if (sf != NULL) pInstr->GetSampleManager()->RemoveSampleConsumer(sf, pRegion);
222 if (sf == NULL || !pInstr->GetSampleManager()->HasSampleConsumers(sf)) pInstr->DestroyRegion(pRegion);
223 }
224 }
225
226 if(deleteInstrument) delete pResource;
227 else dmsg(2,("keeping some samples that are in use..."));
228
229 dmsg(1,("OK\n"));
230 }
231
232 }} // namespace LinuxSampler::sfz

  ViewVC Help
Powered by ViewVC