3 |
* LinuxSampler - modular, streaming capable sampler * |
* LinuxSampler - modular, streaming capable sampler * |
4 |
* * |
* * |
5 |
* Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * |
* Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * |
6 |
* Copyright (C) 2005, 2006 Christian Schoenebeck * |
* Copyright (C) 2005 - 2007 Christian Schoenebeck * |
7 |
* * |
* * |
8 |
* This program is free software; you can redistribute it and/or modify * |
* This program is free software; you can redistribute it and/or modify * |
9 |
* it under the terms of the GNU General Public License as published by * |
* it under the terms of the GNU General Public License as published by * |
25 |
|
|
26 |
#include "InstrumentResourceManager.h" |
#include "InstrumentResourceManager.h" |
27 |
|
|
28 |
|
#include "../InstrumentEditorFactory.h" |
29 |
|
|
30 |
// We need to know the maximum number of sample points which are going to |
// We need to know the maximum number of sample points which are going to |
31 |
// be processed for each render cycle of the audio output driver, to know |
// be processed for each render cycle of the audio output driver, to know |
32 |
// how much initial sample points we need to cache into RAM. If the given |
// how much initial sample points we need to cache into RAM. If the given |
49 |
InstrumentManager::instrument_id_t* pInstrumentKey; |
InstrumentManager::instrument_id_t* pInstrumentKey; |
50 |
}; |
}; |
51 |
|
|
52 |
|
// we use this to react on events concerning an instrument on behalf of an instrument editor |
53 |
|
class InstrumentEditorProxy : public InstrumentConsumer { |
54 |
|
public: |
55 |
|
virtual void ResourceToBeUpdated(::gig::Instrument* pResource, void*& pUpdateArg) { |
56 |
|
//TODO: inform the instrument editor about the pending update |
57 |
|
} |
58 |
|
|
59 |
|
virtual void ResourceUpdated(::gig::Instrument* pOldResource, ::gig::Instrument* pNewResource, void* pUpdateArg) { |
60 |
|
//TODO:: inform the instrument editor about finished update |
61 |
|
} |
62 |
|
|
63 |
|
virtual void OnResourceProgress(float fProgress) { |
64 |
|
//TODO: inform the instrument editor about the progress of an update |
65 |
|
} |
66 |
|
|
67 |
|
// the instrument we borrowed on behalf of the editor |
68 |
|
::gig::Instrument* pInstrument; |
69 |
|
}; |
70 |
|
|
71 |
/** |
/** |
72 |
* Callback function which will be called by libgig during loading of |
* Callback function which will be called by libgig during loading of |
73 |
* instruments to inform about the current progress. Or to be more |
* instruments to inform about the current progress. Or to be more |
106 |
return res; |
return res; |
107 |
} |
} |
108 |
|
|
109 |
|
String InstrumentResourceManager::GetInstrumentTypeName(instrument_id_t ID) { |
110 |
|
return ::gig::libraryName(); |
111 |
|
} |
112 |
|
|
113 |
|
String InstrumentResourceManager::GetInstrumentTypeVersion(instrument_id_t ID) { |
114 |
|
return ::gig::libraryVersion(); |
115 |
|
} |
116 |
|
|
117 |
|
void InstrumentResourceManager::LaunchInstrumentEditor(instrument_id_t ID) throw (InstrumentManagerException) { |
118 |
|
const String sDataType = GetInstrumentTypeName(ID); |
119 |
|
const String sDataVersion = GetInstrumentTypeVersion(ID); |
120 |
|
// find instrument editors capable to handle given instrument |
121 |
|
std::vector<String> vEditors = |
122 |
|
InstrumentEditorFactory::MatchingEditors(sDataType, sDataVersion); |
123 |
|
if (!vEditors.size()) |
124 |
|
throw InstrumentManagerException( |
125 |
|
"There is no instrument editor capable to handle this instrument" |
126 |
|
); |
127 |
|
// simply use the first editor in the result set |
128 |
|
dmsg(1,("Found matching editor '%s' for instrument ('%s', %d) having data structure ('%s','%s')\n", |
129 |
|
vEditors[0].c_str(), ID.FileName.c_str(), ID.Index, sDataType.c_str(), sDataVersion.c_str())); |
130 |
|
InstrumentEditor* pEditor = InstrumentEditorFactory::Create(vEditors[0]); |
131 |
|
// we want to know when you'll die X| (see OnInstrumentEditorQuit()) |
132 |
|
pEditor->AddListener(this); |
133 |
|
// create a proxy that reacts on notification on behalf of the editor |
134 |
|
InstrumentEditorProxy* pProxy = new InstrumentEditorProxy; |
135 |
|
// borrow the instrument on behalf of the instrument editor |
136 |
|
::gig::Instrument* pInstrument = Borrow(ID, pProxy); |
137 |
|
// remember the proxy and instrument for this instrument editor |
138 |
|
pProxy->pInstrument = pInstrument; |
139 |
|
InstrumentEditorProxiesMutex.Lock(); |
140 |
|
InstrumentEditorProxies[pEditor] = pProxy; |
141 |
|
InstrumentEditorProxiesMutex.Unlock(); |
142 |
|
// launch the instrument editor for the given instrument |
143 |
|
pEditor->Launch(pInstrument, sDataType, sDataVersion); |
144 |
|
} |
145 |
|
|
146 |
|
/** |
147 |
|
* Will be called by the respective instrument editor once it left its |
148 |
|
* Main() loop. That way we can handle cleanup before its thread finally |
149 |
|
* dies. |
150 |
|
* |
151 |
|
* @param pSender - instrument editor that stops execution |
152 |
|
*/ |
153 |
|
void InstrumentResourceManager::OnInstrumentEditorQuit(InstrumentEditor* pSender) { |
154 |
|
dmsg(1,("InstrumentResourceManager: instrument editor quit, doing cleanup\n")); |
155 |
|
// hand back instrument and free proxy |
156 |
|
InstrumentEditorProxiesMutex.Lock(); |
157 |
|
if (InstrumentEditorProxies.count(pSender)) { |
158 |
|
InstrumentEditorProxy* pProxy = |
159 |
|
dynamic_cast<InstrumentEditorProxy*>( |
160 |
|
InstrumentEditorProxies[pSender] |
161 |
|
); |
162 |
|
InstrumentEditorProxies.erase(pSender); |
163 |
|
InstrumentEditorProxiesMutex.Unlock(); |
164 |
|
HandBack(pProxy->pInstrument, pProxy); |
165 |
|
if (pProxy) delete pProxy; |
166 |
|
} else { |
167 |
|
InstrumentEditorProxiesMutex.Unlock(); |
168 |
|
std::cerr << "Eeeek, could not find instrument editor proxy, this is a bug!\n" << std::flush; |
169 |
|
} |
170 |
|
// free the editor |
171 |
|
InstrumentEditorFactory::Destroy(pSender); |
172 |
|
} |
173 |
|
|
174 |
::gig::Instrument* InstrumentResourceManager::Create(instrument_id_t Key, InstrumentConsumer* pConsumer, void*& pArg) { |
::gig::Instrument* InstrumentResourceManager::Create(instrument_id_t Key, InstrumentConsumer* pConsumer, void*& pArg) { |
175 |
// get gig file from inernal gig file manager |
// get gig file from inernal gig file manager |
176 |
::gig::File* pGig = Gigs.Borrow(Key.FileName, (GigConsumer*) Key.Index); // conversion kinda hackish :/ |
::gig::File* pGig = Gigs.Borrow(Key.FileName, (GigConsumer*) Key.Index); // conversion kinda hackish :/ |
189 |
if (!pInstrument) { |
if (!pInstrument) { |
190 |
std::stringstream msg; |
std::stringstream msg; |
191 |
msg << "There's no instrument with index " << Key.Index << "."; |
msg << "There's no instrument with index " << Key.Index << "."; |
192 |
throw InstrumentResourceManagerException(msg.str()); |
throw InstrumentManagerException(msg.str()); |
193 |
} |
} |
194 |
pGig->GetFirstSample(); // just to force complete instrument loading |
pGig->GetFirstSample(); // just to force complete instrument loading |
195 |
dmsg(1,("OK\n")); |
dmsg(1,("OK\n")); |
223 |
pEntry->ID.Index = Key.Index; |
pEntry->ID.Index = Key.Index; |
224 |
pEntry->pGig = pGig; |
pEntry->pGig = pGig; |
225 |
|
|
226 |
gig::EngineChannel* pEngineChannel = (gig::EngineChannel*) pConsumer; |
gig::EngineChannel* pEngineChannel = dynamic_cast<gig::EngineChannel*>(pConsumer); |
227 |
// and we save this to check if we need to reallocate for a engine with higher value of 'MaxSamplesPerSecond' |
// and we save this to check if we need to reallocate for a engine with higher value of 'MaxSamplesPerSecond' |
228 |
pEntry->MaxSamplesPerCycle = |
pEntry->MaxSamplesPerCycle = |
229 |
(pEngineChannel && pEngineChannel->GetEngine()) ? dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle() |
(!pEngineChannel) ? 0 /* don't care for instrument editors */ : |
230 |
: GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE; |
(pEngineChannel->GetEngine()) ? |
231 |
|
dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle() |
232 |
|
: GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE; |
233 |
pArg = pEntry; |
pArg = pEntry; |
234 |
|
|
235 |
return pInstrument; |
return pInstrument; |
246 |
instr_entry_t* pEntry = (instr_entry_t*) pArg; |
instr_entry_t* pEntry = (instr_entry_t*) pArg; |
247 |
gig::EngineChannel* pEngineChannel = dynamic_cast<gig::EngineChannel*>(pConsumer); |
gig::EngineChannel* pEngineChannel = dynamic_cast<gig::EngineChannel*>(pConsumer); |
248 |
uint maxSamplesPerCycle = |
uint maxSamplesPerCycle = |
249 |
(pEngineChannel->GetEngine()) ? dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle() |
(pEngineChannel && pEngineChannel->GetEngine()) ? dynamic_cast<gig::Engine*>(pEngineChannel->GetEngine())->pAudioOutputDevice->MaxSamplesPerCycle() |
250 |
: GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE; |
: GIG_RESOURCE_MANAGER_DEFAULT_MAX_SAMPLES_PER_CYCLE; |
251 |
if (pEntry->MaxSamplesPerCycle < maxSamplesPerCycle) { |
if (pEntry->MaxSamplesPerCycle < maxSamplesPerCycle) { |
252 |
Update(pResource, pConsumer); |
Update(pResource, pConsumer); |