/[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 2275 - (show annotations) (download)
Mon Sep 19 21:48:45 2011 UTC (12 years, 7 months ago) by schoenebeck
File size: 10522 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 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, reinterpret_cast<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 // (try to resolve the audio device context)
148 EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(pConsumer);
149 AudioOutputDevice* pDevice =
150 (pEngineChannel) ? dynamic_cast<Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice : NULL;
151
152 // and we save this to check if we need to reallocate for a engine with higher value of 'MaxSamplesPerSecond'
153 pEntry->MaxSamplesPerCycle =
154 (pDevice) ? pDevice->MaxSamplesPerCycle() : DefaultMaxSamplesPerCycle();
155
156 pArg = pEntry;
157
158 return pInstrument;
159 }
160
161 void InstrumentResourceManager::Destroy( ::sfz::Instrument* pResource, void* pArg) {
162 instr_entry_t* pEntry = (instr_entry_t*) pArg;
163 // we don't need the .sfz file here anymore
164 Sfzs.HandBack(pEntry->pSfz, reinterpret_cast<SfzConsumer*>(pEntry->ID.Index)); // conversion kinda hackish :/
165 delete pEntry;
166 }
167
168 void InstrumentResourceManager::OnBorrow(::sfz::Instrument* pResource, InstrumentConsumer* pConsumer, void*& pArg) {
169 instr_entry_t* pEntry = (instr_entry_t*) pArg;
170
171 // (try to resolve the audio device context)
172 EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(pConsumer);
173 AudioOutputDevice* pDevice =
174 (pEngineChannel) ? dynamic_cast<Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice : NULL;
175
176 uint maxSamplesPerCycle =
177 (pDevice) ? pDevice->MaxSamplesPerCycle() : DefaultMaxSamplesPerCycle();
178
179 if (pEntry->MaxSamplesPerCycle < maxSamplesPerCycle) {
180 dmsg(1,("Completely reloading instrument due to insufficient precached samples ...\n"));
181 Update(pResource, pConsumer);
182 }
183 }
184
185 void InstrumentResourceManager::DeleteRegionIfNotUsed(::sfz::Region* pRegion, region_info_t* pRegInfo) {
186 ::sfz::File* file = pRegInfo->file;
187 if (file == NULL) return;
188
189 file->GetInstrument()->DestroyRegion(pRegion);
190 if(file->GetInstrument()->regions.empty()) {
191 dmsg(2,("No more regions in use - freeing sfz\n"));
192 delete file;
193 }
194 }
195
196 void InstrumentResourceManager::DeleteSampleIfNotUsed(Sample* pSample, region_info_t* pRegInfo) {
197
198 }
199
200
201
202 // internal sfz file manager
203
204 ::sfz::File* InstrumentResourceManager::SfzResourceManager::Create(String Key, SfzConsumer* pConsumer, void*& pArg) {
205 dmsg(1,("Loading sfz file \'%s\'...", Key.c_str()));
206 ::sfz::File* pSfz = new ::sfz::File(Key, &sampleManager);
207 dmsg(1,("OK\n"));
208 return pSfz;
209 }
210
211 void InstrumentResourceManager::SfzResourceManager::Destroy(::sfz::File* pResource, void* pArg) {
212 dmsg(1,("Freeing sfz file from memory..."));
213
214 // Delete as much as possible of the sfz file. Some of the
215 // regions and samples may still be in use - these
216 // will be deleted later by the HandBackRegion function.
217 bool deleteInstrument = true;
218 ::sfz::Instrument* pInstr = pResource->GetInstrument();
219
220 for (int i = pInstr->regions.size() - 1; i >= 0 ; i--) {
221 ::sfz::Region* pRegion = pInstr->regions[i];
222 std::map< ::sfz::Region*, region_info_t>::iterator iter = parent->RegionInfo.find(pRegion);
223 if (iter != parent->RegionInfo.end()) {
224 region_info_t& regInfo = (*iter).second;
225 regInfo.file = pResource;
226 deleteInstrument = false;
227 } else {
228 pInstr->DestroyRegion(pRegion);
229 }
230 }
231
232 if(deleteInstrument) delete pResource;
233 else dmsg(2,("keeping some samples that are in use..."));
234
235 dmsg(1,("OK\n"));
236 }
237
238 }} // namespace LinuxSampler::sfz

  ViewVC Help
Powered by ViewVC