/[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 2275 - (hide 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 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 2275 * Copyright (C) 2005 - 2011 Christian Schoenebeck *
7 persson 2185 * Copyright (C) 2009 - 2011 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     // 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 persson 2185 ::sfz::File* pSfz = Sfzs.Borrow(Key.FileName, reinterpret_cast<SfzConsumer*>(Key.Index)); // conversion kinda hackish :/
114 iliev 2012
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 schoenebeck 2275 // (try to resolve the audio device context)
148 iliev 2012 EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(pConsumer);
149 schoenebeck 2275 AudioOutputDevice* pDevice =
150     (pEngineChannel) ? dynamic_cast<Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice : NULL;
151    
152 iliev 2012 // and we save this to check if we need to reallocate for a engine with higher value of 'MaxSamplesPerSecond'
153     pEntry->MaxSamplesPerCycle =
154 schoenebeck 2275 (pDevice) ? pDevice->MaxSamplesPerCycle() : DefaultMaxSamplesPerCycle();
155    
156 iliev 2012 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 persson 2185 Sfzs.HandBack(pEntry->pSfz, reinterpret_cast<SfzConsumer*>(pEntry->ID.Index)); // conversion kinda hackish :/
165 iliev 2012 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 schoenebeck 2275
171     // (try to resolve the audio device context)
172 iliev 2012 EngineChannel* pEngineChannel = dynamic_cast<EngineChannel*>(pConsumer);
173 schoenebeck 2275 AudioOutputDevice* pDevice =
174     (pEngineChannel) ? dynamic_cast<Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice : NULL;
175    
176 iliev 2012 uint maxSamplesPerCycle =
177 schoenebeck 2275 (pDevice) ? pDevice->MaxSamplesPerCycle() : DefaultMaxSamplesPerCycle();
178    
179 iliev 2012 if (pEntry->MaxSamplesPerCycle < maxSamplesPerCycle) {
180 schoenebeck 2275 dmsg(1,("Completely reloading instrument due to insufficient precached samples ...\n"));
181 iliev 2012 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 persson 2058 pInstr->DestroyRegion(pRegion);
229 iliev 2012 }
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