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 - 2013 Christian Schoenebeck * |
* Copyright (C) 2005 - 2014 Christian Schoenebeck * |
7 |
* * |
* * |
8 |
* This library is free software; you can redistribute it and/or modify * |
* This library 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 * |
44 |
pSampler = pS; |
pSampler = pS; |
45 |
pEngineChannel = NULL; |
pEngineChannel = NULL; |
46 |
pAudioOutputDevice = NULL; |
pAudioOutputDevice = NULL; |
|
pMidiInputDevice = NULL; |
|
47 |
iMidiPort = 0; |
iMidiPort = 0; |
48 |
midiChannel = midi_chan_all; |
midiChannel = midi_chan_all; |
49 |
iIndex = -1; |
iIndex = -1; |
54 |
Engine* engine = pEngineChannel->GetEngine(); |
Engine* engine = pEngineChannel->GetEngine(); |
55 |
if (pAudioOutputDevice) pAudioOutputDevice->Disconnect(engine); |
if (pAudioOutputDevice) pAudioOutputDevice->Disconnect(engine); |
56 |
|
|
|
MidiInputPort* pMidiInputPort = (pEngineChannel) ? pEngineChannel->GetMidiInputPort() : __GetMidiInputDevicePort(GetMidiInputChannel()); |
|
|
if (pMidiInputPort) pMidiInputPort->Disconnect(pEngineChannel); |
|
57 |
if (pEngineChannel) { |
if (pEngineChannel) { |
58 |
|
pEngineChannel->DisconnectAllMidiInputPorts(); |
59 |
|
|
60 |
if (pAudioOutputDevice) pEngineChannel->DisconnectAudioOutputDevice(); |
if (pAudioOutputDevice) pEngineChannel->DisconnectAudioOutputDevice(); |
61 |
EngineChannelFactory::Destroy(pEngineChannel); |
EngineChannelFactory::Destroy(pEngineChannel); |
62 |
|
|
83 |
EngineChannel* pNewEngineChannel = EngineChannelFactory::Create(EngineType); |
EngineChannel* pNewEngineChannel = EngineChannelFactory::Create(EngineType); |
84 |
if (!pNewEngineChannel) throw Exception("Unknown engine type"); |
if (!pNewEngineChannel) throw Exception("Unknown engine type"); |
85 |
|
|
86 |
pNewEngineChannel->SetSamplerChannel(this); |
// remember current MIDI input connections |
87 |
|
std::vector<MidiInputPort*> vMidiInputs = GetMidiInputPorts(); |
|
// dereference midi input port. |
|
|
MidiInputPort* pMidiInputPort = __GetMidiInputDevicePort(GetMidiInputPort()); |
|
88 |
midi_chan_t midiChannel = GetMidiInputChannel(); |
midi_chan_t midiChannel = GetMidiInputChannel(); |
89 |
// disconnect old engine channel |
|
90 |
if (pEngineChannel) { |
try { |
91 |
Engine* engine = pEngineChannel->GetEngine(); |
pNewEngineChannel->SetSamplerChannel(this); |
|
if (pAudioOutputDevice) pAudioOutputDevice->Disconnect(engine); |
|
92 |
|
|
93 |
if (pMidiInputPort) pMidiInputPort->Disconnect(pEngineChannel); |
// disconnect old engine channel |
94 |
if (pAudioOutputDevice) pEngineChannel->DisconnectAudioOutputDevice(); |
if (pEngineChannel) { |
95 |
EngineChannelFactory::Destroy(pEngineChannel); |
Engine* engine = pEngineChannel->GetEngine(); |
96 |
|
if (pAudioOutputDevice) pAudioOutputDevice->Disconnect(engine); |
97 |
|
|
98 |
// reconnect engine if it still exists |
pEngineChannel->DisconnectAllMidiInputPorts(); |
99 |
const std::set<Engine*>& engines = EngineFactory::EngineInstances(); |
if (pAudioOutputDevice) pEngineChannel->DisconnectAudioOutputDevice(); |
100 |
if (engines.find(engine) != engines.end()) pAudioOutputDevice->Connect(engine); |
EngineChannelFactory::Destroy(pEngineChannel); |
101 |
} |
pEngineChannel = NULL; |
102 |
|
|
103 |
// connect new engine channel |
// reconnect engine if it still exists |
104 |
if (pAudioOutputDevice) { |
const std::set<Engine*>& engines = EngineFactory::EngineInstances(); |
105 |
pNewEngineChannel->Connect(pAudioOutputDevice); |
if (engines.find(engine) != engines.end()) pAudioOutputDevice->Connect(engine); |
106 |
pAudioOutputDevice->Connect(pNewEngineChannel->GetEngine()); |
} |
107 |
|
|
108 |
|
// connect new engine channel |
109 |
|
if (pAudioOutputDevice) { |
110 |
|
pNewEngineChannel->Connect(pAudioOutputDevice); |
111 |
|
pAudioOutputDevice->Connect(pNewEngineChannel->GetEngine()); |
112 |
|
} |
113 |
|
pNewEngineChannel->SetMidiChannel(midiChannel); |
114 |
|
for (int i = 0; i < vMidiInputs.size(); ++i) { |
115 |
|
pNewEngineChannel->Connect(vMidiInputs[i]); |
116 |
|
} |
117 |
|
} catch (...) { |
118 |
|
EngineChannelFactory::Destroy(pNewEngineChannel); |
119 |
|
throw; // re-throw the same exception |
120 |
} |
} |
|
if (pMidiInputPort) pMidiInputPort->Connect(pNewEngineChannel, midiChannel); |
|
121 |
pEngineChannel = pNewEngineChannel; |
pEngineChannel = pNewEngineChannel; |
122 |
|
|
123 |
// from now on get MIDI device and port from EngineChannel object |
// from now on get MIDI input ports from EngineChannel object |
124 |
this->pMidiInputDevice = NULL; |
this->vMidiInputs.clear(); |
125 |
this->iMidiPort = 0; |
this->iMidiPort = 0; |
126 |
|
|
127 |
pEngineChannel->StatusChanged(true); |
pEngineChannel->StatusChanged(true); |
155 |
} |
} |
156 |
} |
} |
157 |
|
|
158 |
|
void SamplerChannel::Connect(MidiInputPort* pPort) throw (Exception) { |
159 |
|
if (!pPort) throw Exception("No MIDI input port provided"); |
160 |
|
|
161 |
|
// prevent attempts to connect non-autonomous MIDI ports |
162 |
|
// (host plugins like VST, AU, LV2, DSSI) |
163 |
|
if (!pPort->GetDevice()->isAutonomousDevice()) |
164 |
|
throw Exception("The MIDI input port '" + pPort->GetDevice()->Driver() + "' cannot be managed manually!"); |
165 |
|
|
166 |
|
std::vector<MidiInputPort*> vMidiPorts = GetMidiInputPorts(); |
167 |
|
|
168 |
|
// ignore if port is already connected |
169 |
|
for (int i = 0; i < vMidiPorts.size(); ++i) { |
170 |
|
if (vMidiPorts[i] == pPort) return; |
171 |
|
} |
172 |
|
|
173 |
|
// connect this new port |
174 |
|
if (pEngineChannel) { |
175 |
|
pEngineChannel->Connect(pPort); |
176 |
|
} else { // no engine channel yet, remember it for future connection ... |
177 |
|
const midi_conn_t c = { |
178 |
|
pPort->GetDevice()->MidiInputDeviceID(), |
179 |
|
pPort->GetPortNumber() |
180 |
|
}; |
181 |
|
this->vMidiInputs.push_back(c); |
182 |
|
} |
183 |
|
} |
184 |
|
|
185 |
|
void SamplerChannel::Disconnect(MidiInputPort* pPort) throw (Exception) { |
186 |
|
if (!pPort) return; |
187 |
|
|
188 |
|
// prevent attempts to alter channels with non-autonomous devices |
189 |
|
// (host plugins like VST, AU, LV2, DSSI) |
190 |
|
if (!pPort->GetDevice()->isAutonomousDevice()) |
191 |
|
throw Exception("The MIDI input port '" + pPort->GetDevice()->Driver() + "' cannot be managed manually!"); |
192 |
|
|
193 |
|
// disconnect this port |
194 |
|
if (pEngineChannel) { |
195 |
|
pEngineChannel->Disconnect(pPort); |
196 |
|
} else { // no engine channel yet, forget it regarding future connection ... |
197 |
|
const midi_conn_t c = { |
198 |
|
pPort->GetDevice()->MidiInputDeviceID(), |
199 |
|
pPort->GetPortNumber() |
200 |
|
}; |
201 |
|
for (int i = this->vMidiInputs.size() - 1; i >= 0; --i) { |
202 |
|
if (this->vMidiInputs[i] == c) |
203 |
|
this->vMidiInputs.erase(this->vMidiInputs.begin() + i); |
204 |
|
// no break or return here, for safety reasons |
205 |
|
// (just in case there were really duplicates for some reason) |
206 |
|
} |
207 |
|
} |
208 |
|
} |
209 |
|
|
210 |
|
void SamplerChannel::DisconnectAllMidiInputPorts() throw (Exception) { |
211 |
|
std::vector<MidiInputPort*> vMidiPorts = GetMidiInputPorts(); |
212 |
|
for (int i = 0; i < vMidiPorts.size(); ++i) Disconnect(vMidiPorts[i]); |
213 |
|
} |
214 |
|
|
215 |
|
std::vector<MidiInputPort*> SamplerChannel::GetMidiInputPorts() { |
216 |
|
std::vector<MidiInputPort*> v; |
217 |
|
if (pEngineChannel) { |
218 |
|
MidiInputPort* pPort = pEngineChannel->GetMidiInputPort(0); |
219 |
|
for (int i = 0; pPort; pPort = pEngineChannel->GetMidiInputPort(++i)) |
220 |
|
v.push_back(pPort); |
221 |
|
} else { |
222 |
|
for (int i = 0; i < this->vMidiInputs.size(); ++i) { |
223 |
|
MidiInputPort* pPort = _getPortForID(this->vMidiInputs[i]); |
224 |
|
if (pPort) v.push_back(pPort); |
225 |
|
} |
226 |
|
} |
227 |
|
return v; |
228 |
|
} |
229 |
|
|
230 |
void SamplerChannel::SetMidiInputDevice(MidiInputDevice* pDevice) throw (Exception) { |
void SamplerChannel::SetMidiInputDevice(MidiInputDevice* pDevice) throw (Exception) { |
231 |
SetMidiInput(pDevice, 0, GetMidiInputChannel()); |
SetMidiInput(pDevice, 0, GetMidiInputChannel()); |
232 |
} |
} |
236 |
} |
} |
237 |
|
|
238 |
void SamplerChannel::SetMidiInputChannel(midi_chan_t MidiChannel) { |
void SamplerChannel::SetMidiInputChannel(midi_chan_t MidiChannel) { |
239 |
SetMidiInput(GetMidiInputDevice(), GetMidiInputPort(), MidiChannel); |
if (!isValidMidiChan(MidiChannel)) throw Exception("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")"); |
240 |
|
if (pEngineChannel) pEngineChannel->SetMidiChannel(MidiChannel); |
241 |
|
this->midiChannel = MidiChannel; |
242 |
} |
} |
243 |
|
|
244 |
void SamplerChannel::SetMidiInput(MidiInputDevice* pDevice, int iMidiPort, midi_chan_t MidiChannel) throw (Exception) { |
void SamplerChannel::SetMidiInput(MidiInputDevice* pDevice, int iMidiPort, midi_chan_t MidiChannel) throw (Exception) { |
245 |
if (!pDevice) throw Exception("No MIDI input device assigned."); |
if (!pDevice) throw Exception("No MIDI input device assigned."); |
246 |
|
|
247 |
// get old and new midi input port |
// apply new MIDI channel |
248 |
MidiInputPort* pOldMidiInputPort = __GetMidiInputDevicePort(GetMidiInputPort()); |
SetMidiInputChannel(MidiChannel); |
249 |
MidiInputPort* pNewMidiInputPort = pDevice->GetPort(iMidiPort); |
|
250 |
|
MidiInputPort* pNewPort = pDevice->GetPort(iMidiPort); |
251 |
// disconnect old device port |
if (!pNewPort) throw Exception("There is no MIDI input port with index " + ToString(iMidiPort) + "."); |
252 |
if (pOldMidiInputPort && pEngineChannel) { |
|
253 |
MidiInputDevice* pOldDevice = pOldMidiInputPort->GetDevice(); |
std::vector<MidiInputPort*> vMidiPorts = GetMidiInputPorts(); |
254 |
if (pOldMidiInputPort != pNewMidiInputPort && |
|
255 |
pOldDevice && !pOldDevice->isAutonomousDevice() |
// prevent attempts to remove non-autonomous MIDI ports |
256 |
) throw Exception("The MIDI input port '" + pOldDevice->Driver() + "' cannot be altered on this sampler channel!"); |
// (host plugins like VST, AU, LV2, DSSI) |
257 |
|
for (int i = 0; i < vMidiPorts.size(); ++i) { |
258 |
pOldMidiInputPort->Disconnect(pEngineChannel); |
if (vMidiPorts[i] == pNewPort) continue; |
259 |
} |
if (!vMidiPorts[i]->GetDevice()->isAutonomousDevice()) |
260 |
|
throw Exception("The MIDI input port '" + vMidiPorts[i]->GetDevice()->Driver() + "' cannot be altered on this sampler channel!"); |
261 |
// remember new device, port and channel if not engine channel yet created |
} |
262 |
if (!pEngineChannel) { |
|
263 |
this->pMidiInputDevice = pDevice; |
if (pEngineChannel) { |
264 |
this->iMidiPort = iMidiPort; |
// remove all current connections |
265 |
this->midiChannel = MidiChannel; |
pEngineChannel->DisconnectAllMidiInputPorts(); |
266 |
} |
// create the new connection (alone) |
267 |
|
pEngineChannel->Connect(pNewPort); |
268 |
// connect new device port |
} else { // if there is no engine channel yet, then store connection for future ... |
269 |
if (pNewMidiInputPort && pEngineChannel) pNewMidiInputPort->Connect(pEngineChannel, MidiChannel); |
// delete all previously scheduled connections |
270 |
// Ooops. |
this->vMidiInputs.clear(); |
271 |
if (pNewMidiInputPort == NULL) |
// store the new connection (alone) |
272 |
throw Exception("There is no MIDI input port with index " + ToString(iMidiPort) + "."); |
const midi_conn_t c = { |
273 |
|
pNewPort->GetDevice()->MidiInputDeviceID(), |
274 |
|
pNewPort->GetPortNumber() |
275 |
|
}; |
276 |
|
this->vMidiInputs.push_back(c); |
277 |
|
this->iMidiPort = iMidiPort; |
278 |
|
} |
279 |
} |
} |
280 |
|
|
281 |
EngineChannel* SamplerChannel::GetEngineChannel() { |
EngineChannel* SamplerChannel::GetEngineChannel() { |
288 |
} |
} |
289 |
|
|
290 |
int SamplerChannel::GetMidiInputPort() { |
int SamplerChannel::GetMidiInputPort() { |
291 |
MidiInputPort* pMidiInputPort = (pEngineChannel) ? pEngineChannel->GetMidiInputPort() : NULL; |
MidiInputPort* pMidiInputPort = (pEngineChannel) ? pEngineChannel->GetMidiInputPort(0) : NULL; |
292 |
if (pMidiInputPort) this->iMidiPort = (int) pMidiInputPort->GetPortNumber(); |
if (pMidiInputPort) this->iMidiPort = (int) pMidiInputPort->GetPortNumber(); |
293 |
return iMidiPort; |
return iMidiPort; |
294 |
} |
} |
299 |
|
|
300 |
MidiInputDevice* SamplerChannel::GetMidiInputDevice() { |
MidiInputDevice* SamplerChannel::GetMidiInputDevice() { |
301 |
if (pEngineChannel) |
if (pEngineChannel) |
302 |
pMidiInputDevice = (pEngineChannel->GetMidiInputPort()) ? pEngineChannel->GetMidiInputPort()->GetDevice() : NULL; |
return (pEngineChannel->GetMidiInputPort(0)) ? pEngineChannel->GetMidiInputPort(0)->GetDevice() : NULL; |
303 |
return pMidiInputDevice; |
|
304 |
|
if (vMidiInputs.empty()) |
305 |
|
return NULL; |
306 |
|
|
307 |
|
std::map<uint, MidiInputDevice*> mAllDevices = MidiInputDeviceFactory::Devices(); |
308 |
|
if (!mAllDevices.count(vMidiInputs[0].deviceID)) |
309 |
|
return NULL; |
310 |
|
|
311 |
|
return mAllDevices[vMidiInputs[0].deviceID]; |
312 |
} |
} |
313 |
|
|
314 |
uint SamplerChannel::Index() { |
uint SamplerChannel::Index() { |
352 |
llEngineChangeListeners.GetListener(i)->EngineChanged(Index()); |
llEngineChangeListeners.GetListener(i)->EngineChanged(Index()); |
353 |
} |
} |
354 |
} |
} |
355 |
|
|
356 |
|
/** |
357 |
|
* Takes a numeric MIDI device ID, port ID pair as argument and returns |
358 |
|
* the actual MIDI input port associated with that unique ID pair. |
359 |
|
*/ |
360 |
|
MidiInputPort* SamplerChannel::_getPortForID(const midi_conn_t& c) { |
361 |
|
std::map<uint, MidiInputDevice*> mAllDevices = MidiInputDeviceFactory::Devices(); |
362 |
|
if (!mAllDevices.count(c.deviceID)) |
363 |
|
return NULL; |
364 |
|
|
365 |
MidiInputPort* SamplerChannel::__GetMidiInputDevicePort(int iMidiPort) { |
return mAllDevices[c.deviceID]->GetPort(c.portNr); |
|
MidiInputPort* pMidiInputPort = NULL; |
|
|
MidiInputDevice* pMidiInputDevice = GetMidiInputDevice(); |
|
|
if (pMidiInputDevice) |
|
|
pMidiInputPort = pMidiInputDevice->GetPort(iMidiPort); |
|
|
return pMidiInputPort; |
|
366 |
} |
} |
367 |
|
|
368 |
|
|
|
|
|
369 |
// ****************************************************************** |
// ****************************************************************** |
370 |
// * Sampler |
// * Sampler |
371 |
|
|
722 |
if (pDevice) { |
if (pDevice) { |
723 |
// check if there are still sampler engines connected to this device |
// check if there are still sampler engines connected to this device |
724 |
for (SamplerChannelMap::iterator iterChan = mSamplerChannels.begin(); |
for (SamplerChannelMap::iterator iterChan = mSamplerChannels.begin(); |
725 |
iterChan != mSamplerChannels.end(); iterChan++ |
iterChan != mSamplerChannels.end(); ++iterChan) |
726 |
) if (iterChan->second->GetMidiInputDevice() == pDevice) throw Exception("Sampler channel " + ToString(iterChan->first) + " is still connected to the midi input device."); |
{ |
727 |
|
std::vector<MidiInputPort*> vPorts = iterChan->second->GetMidiInputPorts(); |
728 |
|
for (int k = 0; k < vPorts.size(); ++k) |
729 |
|
if (vPorts[k]->GetDevice() == pDevice) |
730 |
|
throw Exception("Sampler channel " + ToString(iterChan->first) + " is still connected to the midi input device."); |
731 |
|
} |
732 |
|
|
733 |
fireMidiDeviceToBeDestroyed(pDevice); |
fireMidiDeviceToBeDestroyed(pDevice); |
734 |
MidiInputDeviceFactory::Destroy(pDevice); |
MidiInputDeviceFactory::Destroy(pDevice); |