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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4019 - (hide annotations) (download)
Mon Jan 3 17:45:26 2022 UTC (2 years, 3 months ago) by schoenebeck
File size: 11237 byte(s)
* SFZ engine: Automatically reload .sfz files on file changes
  (e.g. by some external text editor).

* Bumped version (2.2.0.svn14).

1 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 4019 * Copyright (C) 2005 - 2022 Christian Schoenebeck *
7     * Copyright (C) 2009 - 2012 Grigor Iliev *
8 iliev 2012 * *
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 persson 2326 if (!loaded) {
65 iliev 2012 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 schoenebeck 4019 ::sfz::File* pSfz = Sfzs.Borrow(Key.FileName, &Sfzs);
97 iliev 2012
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 schoenebeck 3054 int regionCount = (int) pInstrument->regions.size();
115 persson 2326 uint maxSamplesPerCycle = GetMaxSamplesPerCycle(pConsumer);
116     for (int i = 0 ; i < regionCount ; i++) {
117     float localProgress = (float) i / (float) regionCount;
118 iliev 2012 DispatchResourceProgressEvent(Key, localProgress);
119 persson 2326 CacheInitialSamples(pInstrument->regions[i]->GetSample(), maxSamplesPerCycle);
120 iliev 2012 //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 persson 2326 pEntry->pFile = pSfz;
130 iliev 2012
131 persson 2326 // and we save this to check if we need to reallocate for an engine with higher value of 'MaxSamplesPerSecond'
132     pEntry->MaxSamplesPerCycle = maxSamplesPerCycle;
133 schoenebeck 2275
134 iliev 2012 pArg = pEntry;
135    
136     return pInstrument;
137     }
138    
139 persson 2326 void InstrumentResourceManager::Destroy(::sfz::Instrument* pResource, void* pArg) {
140 iliev 2012 instr_entry_t* pEntry = (instr_entry_t*) pArg;
141     // we don't need the .sfz file here anymore
142 persson 2326 Sfzs.HandBack(pEntry->pFile, reinterpret_cast<SfzConsumer*>(pEntry->ID.Index)); // conversion kinda hackish :/
143 iliev 2012 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 persson 2326 if (file->GetInstrument()->regions.empty()) {
152 iliev 2012 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 schoenebeck 4019 InstrumentManagerThread* thread = parent->GetInstrumentManagerThread();
170     // let this code be executed periodically by instrument manager thread
171     // in order to automatically reload this .sfz file whenever it was
172     // modified, e.g. by some external text editor application
173     thread->AddPeriodicJob("autoreload_sfz:" + Key, [this,Key,pSfz]{
174     if (pSfz->checkFileModified()) {
175     dmsg(1,("Sfz file was modified: auto reloading '%s'\n", Key.c_str()));
176     // passing NULL as consumer here instead of 'this' to ensure
177     // that the ResourceToBeUpdated() and ResourceUpdated() method
178     // pair below is executed
179     Update(pSfz, NULL);
180     }
181     });
182 iliev 2012 return pSfz;
183     }
184    
185     void InstrumentResourceManager::SfzResourceManager::Destroy(::sfz::File* pResource, void* pArg) {
186     dmsg(1,("Freeing sfz file from memory..."));
187    
188 schoenebeck 4019 // stop periodic job previously scheduled above before freeing sfz file
189     const String key = pResource->filename();
190     InstrumentManagerThread* thread = parent->GetInstrumentManagerThread();
191     thread->RemovePeriodicJob("autoreload_sfz:" + key);
192    
193 iliev 2012 // Delete as much as possible of the sfz file. Some of the
194     // regions and samples may still be in use - these
195     // will be deleted later by the HandBackRegion function.
196     bool deleteInstrument = true;
197     ::sfz::Instrument* pInstr = pResource->GetInstrument();
198    
199 schoenebeck 3054 for (int i = (int)pInstr->regions.size() - 1; i >= 0 ; i--) {
200 iliev 2012 ::sfz::Region* pRegion = pInstr->regions[i];
201     std::map< ::sfz::Region*, region_info_t>::iterator iter = parent->RegionInfo.find(pRegion);
202     if (iter != parent->RegionInfo.end()) {
203     region_info_t& regInfo = (*iter).second;
204     regInfo.file = pResource;
205     deleteInstrument = false;
206     } else {
207 persson 2058 pInstr->DestroyRegion(pRegion);
208 iliev 2012 }
209     }
210    
211 schoenebeck 4019 // free sfz file
212 persson 2326 if (deleteInstrument) delete pResource;
213 iliev 2012 else dmsg(2,("keeping some samples that are in use..."));
214    
215     dmsg(1,("OK\n"));
216     }
217    
218 schoenebeck 4019 void InstrumentResourceManager::SfzResourceManager::ResourceToBeUpdated(::sfz::File* pResource, void*& pUpdateArg) {
219     // Since the respective sfz::Instrument objects will already be
220     // invalidated when ResourceUpdated() will be called subsequently, we
221     // must assemble a list of the current sfz::Instrument objects being
222     // subject of the .sfz file changed already here.
223     std::set<::sfz::Instrument*>* pInstruments = new std::set<::sfz::Instrument*>();
224     {
225     std::vector<::sfz::Instrument*> instrumentsInUse = parent->Resources(false);
226     for (size_t i = 0; i < instrumentsInUse.size(); i++) {
227     ::sfz::File* f = instrumentsInUse[i]->GetFile();
228     if (f == pResource) pInstruments->insert(instrumentsInUse[i]);
229     }
230     }
231     pUpdateArg = pInstruments;
232     }
233    
234     void InstrumentResourceManager::SfzResourceManager::ResourceUpdated(::sfz::File* pOldResource, ::sfz::File* pNewResource, void* pUpdateArg) {
235     // force reload sfz::Instrument objects on engine channels that used that sfz file
236     std::set<::sfz::Instrument*>* pInstruments = (std::set<::sfz::Instrument*>*)pUpdateArg;
237     std::set<::sfz::Instrument*>::const_iterator it = pInstruments->begin();
238     std::set<::sfz::Instrument*>::const_iterator end = pInstruments->end();
239     for (; it != end; ++it) {
240     ::sfz::Instrument* instrument = *it;
241     parent->Update(instrument, reinterpret_cast<SfzInstrConsumer*>(this));
242     }
243     delete pInstruments;
244     }
245    
246 iliev 2012 }} // namespace LinuxSampler::sfz

  ViewVC Help
Powered by ViewVC