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

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2008 Christian Schoenebeck *
7 * Copyright (C) 2009 - 2012 Christian Schoenebeck and 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 String InstrumentResourceManager::GetInstrumentName(instrument_id_t ID) {
39 Lock();
40 ::sfz::Instrument* pInstrument = Resource(ID, false);
41 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 std::vector<instrument_id_t> result;
48 instrument_id_t id;
49 id.FileName = File;
50 id.Index = 0;
51 result.push_back(id);
52 return result;
53 }
54
55 InstrumentResourceManager::instrument_info_t InstrumentResourceManager::GetInstrumentInfo(instrument_id_t ID) throw (InstrumentManagerException) {
56 if (ID.Index) throw InstrumentManagerException("There is no instrument " + ToString(ID.Index) + " in " + ID.FileName);
57 Lock();
58 ::sfz::Instrument* pInstrument = Resource(ID, false);
59 bool loaded = (pInstrument != NULL);
60 if (!loaded) Unlock();
61
62 ::sfz::File* sfz = NULL;
63 try {
64 if (!loaded) {
65 sfz = new ::sfz::File(ID.FileName);
66 pInstrument = sfz->GetInstrument();
67 }
68
69 if (!pInstrument) throw InstrumentManagerException("There is no instrument " + ToString(ID.Index) + " in " + ID.FileName);
70
71 instrument_info_t info;
72 info.InstrumentName = Path::getBaseName(ID.FileName);
73
74 for (int i = 0; i < 128; i++) {
75 info.KeyBindings[i] = pInstrument->HasKeyBinding(i);
76 info.KeySwitchBindings[i] = pInstrument->HasKeySwitchBinding(i);
77 }
78
79 if (loaded) Unlock();
80
81 if (sfz) delete sfz;
82 return info;
83 } catch (::sfz::Exception e) {
84 if (loaded) Unlock();
85 if (sfz) delete sfz;
86 throw InstrumentManagerException(e.Message());
87 } catch (...) {
88 if (loaded) Unlock();
89 if (sfz) delete sfz;
90 throw InstrumentManagerException("Unknown exception while trying to parse '" + ID.FileName + "'");
91 }
92 }
93
94 ::sfz::Instrument* InstrumentResourceManager::Create(instrument_id_t Key, InstrumentConsumer* pConsumer, void*& pArg) {
95 // get sfz file from internal sfz file manager
96 ::sfz::File* pSfz = Sfzs.Borrow(Key.FileName, reinterpret_cast<SfzConsumer*>(Key.Index)); // conversion kinda hackish :/
97
98 dmsg(1,("Loading sfz instrument ('%s',%d)...",Key.FileName.c_str(),Key.Index));
99 if (Key.Index) {
100 std::stringstream msg;
101 msg << "There's no instrument with index " << Key.Index << ".";
102 throw InstrumentManagerException(msg.str());
103 }
104 ::sfz::Instrument* pInstrument = pSfz->GetInstrument();
105 if (!pInstrument) {
106 std::stringstream msg;
107 msg << "There's no instrument with index " << Key.Index << ".";
108 throw InstrumentManagerException(msg.str());
109 }
110 dmsg(1,("OK\n"));
111
112 // cache initial samples points (for actually needed samples)
113 dmsg(1,("Caching initial samples..."));
114 int regionCount = pInstrument->regions.size();
115 uint maxSamplesPerCycle = GetMaxSamplesPerCycle(pConsumer);
116 for (int i = 0 ; i < regionCount ; i++) {
117 float localProgress = (float) i / (float) regionCount;
118 DispatchResourceProgressEvent(Key, localProgress);
119 CacheInitialSamples(pInstrument->regions[i]->GetSample(), maxSamplesPerCycle);
120 //pInstrument->regions[i]->GetSample()->Close();
121 }
122 dmsg(1,("OK\n"));
123 DispatchResourceProgressEvent(Key, 1.0f); // done; notify all consumers about progress 100%
124
125 // we need the following for destruction later
126 instr_entry_t* pEntry = new instr_entry_t;
127 pEntry->ID.FileName = Key.FileName;
128 pEntry->ID.Index = Key.Index;
129 pEntry->pFile = pSfz;
130
131 // and we save this to check if we need to reallocate for an engine with higher value of 'MaxSamplesPerSecond'
132 pEntry->MaxSamplesPerCycle = maxSamplesPerCycle;
133
134 pArg = pEntry;
135
136 return pInstrument;
137 }
138
139 void InstrumentResourceManager::Destroy(::sfz::Instrument* pResource, void* pArg) {
140 instr_entry_t* pEntry = (instr_entry_t*) pArg;
141 // we don't need the .sfz file here anymore
142 Sfzs.HandBack(pEntry->pFile, reinterpret_cast<SfzConsumer*>(pEntry->ID.Index)); // conversion kinda hackish :/
143 delete pEntry;
144 }
145
146 void InstrumentResourceManager::DeleteRegionIfNotUsed(::sfz::Region* pRegion, region_info_t* pRegInfo) {
147 ::sfz::File* file = pRegInfo->file;
148 if (file == NULL) return;
149
150 file->GetInstrument()->DestroyRegion(pRegion);
151 if (file->GetInstrument()->regions.empty()) {
152 dmsg(2,("No more regions in use - freeing sfz\n"));
153 delete file;
154 }
155 }
156
157 void InstrumentResourceManager::DeleteSampleIfNotUsed(Sample* pSample, region_info_t* pRegInfo) {
158
159 }
160
161
162
163 // internal sfz file manager
164
165 ::sfz::File* InstrumentResourceManager::SfzResourceManager::Create(String Key, SfzConsumer* pConsumer, void*& pArg) {
166 dmsg(1,("Loading sfz file \'%s\'...", Key.c_str()));
167 ::sfz::File* pSfz = new ::sfz::File(Key, &sampleManager);
168 dmsg(1,("OK\n"));
169 return pSfz;
170 }
171
172 void InstrumentResourceManager::SfzResourceManager::Destroy(::sfz::File* pResource, void* pArg) {
173 dmsg(1,("Freeing sfz file from memory..."));
174
175 // Delete as much as possible of the sfz file. Some of the
176 // regions and samples may still be in use - these
177 // will be deleted later by the HandBackRegion function.
178 bool deleteInstrument = true;
179 ::sfz::Instrument* pInstr = pResource->GetInstrument();
180
181 for (int i = pInstr->regions.size() - 1; i >= 0 ; i--) {
182 ::sfz::Region* pRegion = pInstr->regions[i];
183 std::map< ::sfz::Region*, region_info_t>::iterator iter = parent->RegionInfo.find(pRegion);
184 if (iter != parent->RegionInfo.end()) {
185 region_info_t& regInfo = (*iter).second;
186 regInfo.file = pResource;
187 deleteInstrument = false;
188 } else {
189 pInstr->DestroyRegion(pRegion);
190 }
191 }
192
193 if (deleteInstrument) delete pResource;
194 else dmsg(2,("keeping some samples that are in use..."));
195
196 dmsg(1,("OK\n"));
197 }
198
199 }} // namespace LinuxSampler::sfz

  ViewVC Help
Powered by ViewVC