/[svn]/linuxsampler/trunk/src/network/lscpserver.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/network/lscpserver.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2687 - (show annotations) (download)
Sun Jan 4 17:16:05 2015 UTC (9 years, 3 months ago) by schoenebeck
File size: 166001 byte(s)
* Instrument editor interface: Changed instrument editor plugin interface,
providing additional informations like the EngineChannel for which the
instrument editor was spawned for. This allows the instrument editors to
interact more actively with the sampler.
* Bumped version (1.0.0.svn60).

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2015 Christian Schoenebeck *
7 * *
8 * 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 *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24 #include <algorithm>
25 #include <string>
26
27 #include "../common/File.h"
28 #include "lscpserver.h"
29 #include "lscpresultset.h"
30 #include "lscpevent.h"
31
32 #if defined(WIN32)
33 #include <windows.h>
34 #else
35 #include <fcntl.h>
36 #endif
37
38 #if ! HAVE_SQLITE3
39 #define DOESNT_HAVE_SQLITE3 "No database support. SQLITE3 was not installed when linuxsampler was built."
40 #endif
41
42 #include "../engines/EngineFactory.h"
43 #include "../engines/EngineChannelFactory.h"
44 #include "../drivers/audio/AudioOutputDeviceFactory.h"
45 #include "../drivers/midi/MidiInputDeviceFactory.h"
46 #include "../effects/EffectFactory.h"
47
48 namespace LinuxSampler {
49
50 String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param, bool possibilities);
51
52 /**
53 * Returns a copy of the given string where all special characters are
54 * replaced by LSCP escape sequences ("\xHH"). This function shall be used
55 * to escape LSCP response fields in case the respective response field is
56 * actually defined as using escape sequences in the LSCP specs.
57 *
58 * @e Caution: DO NOT use this function for escaping path based responses,
59 * use the Path class (src/common/Path.h) for this instead!
60 */
61 static String _escapeLscpResponse(String txt) {
62 for (int i = 0; i < txt.length(); i++) {
63 const char c = txt.c_str()[i];
64 if (
65 !(c >= '0' && c <= '9') &&
66 !(c >= 'a' && c <= 'z') &&
67 !(c >= 'A' && c <= 'Z') &&
68 !(c == ' ') && !(c == '!') && !(c == '#') && !(c == '$') &&
69 !(c == '%') && !(c == '&') && !(c == '(') && !(c == ')') &&
70 !(c == '*') && !(c == '+') && !(c == ',') && !(c == '-') &&
71 !(c == '.') && !(c == '/') && !(c == ':') && !(c == ';') &&
72 !(c == '<') && !(c == '=') && !(c == '>') && !(c == '?') &&
73 !(c == '@') && !(c == '[') && !(c == ']') &&
74 !(c == '^') && !(c == '_') && !(c == '`') && !(c == '{') &&
75 !(c == '|') && !(c == '}') && !(c == '~')
76 ) {
77 // convert the "special" character into a "\xHH" LSCP escape sequence
78 char buf[5];
79 snprintf(buf, sizeof(buf), "\\x%02x", static_cast<unsigned char>(c));
80 txt.replace(i, 1, buf);
81 i += 3;
82 }
83 }
84 return txt;
85 }
86
87 /**
88 * Below are a few static members of the LSCPServer class.
89 * The big assumption here is that LSCPServer is going to remain a singleton.
90 * These members are used to support client connections.
91 * Class handles multiple connections at the same time using select() and non-blocking recv()
92 * Commands are processed by a single LSCPServer thread.
93 * Notifications are delivered either by the thread that originated them
94 * or (if the resultset is currently in progress) by the LSCPServer thread
95 * after the resultset was sent out.
96 * This makes sure that resultsets can not be interrupted by notifications.
97 * This also makes sure that the thread sending notification is not blocked
98 * by the LSCPServer thread.
99 */
100 fd_set LSCPServer::fdSet;
101 int LSCPServer::currentSocket = -1;
102 std::vector<yyparse_param_t> LSCPServer::Sessions;
103 std::vector<yyparse_param_t>::iterator itCurrentSession;
104 std::map<int,String> LSCPServer::bufferedNotifies;
105 std::map<int,String> LSCPServer::bufferedCommands;
106 std::map< LSCPEvent::event_t, std::list<int> > LSCPServer::eventSubscriptions;
107 Mutex LSCPServer::NotifyMutex;
108 Mutex LSCPServer::NotifyBufferMutex;
109 Mutex LSCPServer::SubscriptionMutex;
110 Mutex LSCPServer::RTNotifyMutex;
111
112 LSCPServer::LSCPServer(Sampler* pSampler, long int addr, short int port) : Thread(true, false, 0, -4), eventHandler(this) {
113 SocketAddress.sin_family = AF_INET;
114 SocketAddress.sin_addr.s_addr = addr;
115 SocketAddress.sin_port = port;
116 this->pSampler = pSampler;
117 LSCPEvent::RegisterEvent(LSCPEvent::event_audio_device_count, "AUDIO_OUTPUT_DEVICE_COUNT");
118 LSCPEvent::RegisterEvent(LSCPEvent::event_audio_device_info, "AUDIO_OUTPUT_DEVICE_INFO");
119 LSCPEvent::RegisterEvent(LSCPEvent::event_midi_device_count, "MIDI_INPUT_DEVICE_COUNT");
120 LSCPEvent::RegisterEvent(LSCPEvent::event_midi_device_info, "MIDI_INPUT_DEVICE_INFO");
121 LSCPEvent::RegisterEvent(LSCPEvent::event_channel_count, "CHANNEL_COUNT");
122 LSCPEvent::RegisterEvent(LSCPEvent::event_voice_count, "VOICE_COUNT");
123 LSCPEvent::RegisterEvent(LSCPEvent::event_stream_count, "STREAM_COUNT");
124 LSCPEvent::RegisterEvent(LSCPEvent::event_buffer_fill, "BUFFER_FILL");
125 LSCPEvent::RegisterEvent(LSCPEvent::event_channel_info, "CHANNEL_INFO");
126 LSCPEvent::RegisterEvent(LSCPEvent::event_fx_send_count, "FX_SEND_COUNT");
127 LSCPEvent::RegisterEvent(LSCPEvent::event_fx_send_info, "FX_SEND_INFO");
128 LSCPEvent::RegisterEvent(LSCPEvent::event_midi_instr_map_count, "MIDI_INSTRUMENT_MAP_COUNT");
129 LSCPEvent::RegisterEvent(LSCPEvent::event_midi_instr_map_info, "MIDI_INSTRUMENT_MAP_INFO");
130 LSCPEvent::RegisterEvent(LSCPEvent::event_midi_instr_count, "MIDI_INSTRUMENT_COUNT");
131 LSCPEvent::RegisterEvent(LSCPEvent::event_midi_instr_info, "MIDI_INSTRUMENT_INFO");
132 LSCPEvent::RegisterEvent(LSCPEvent::event_db_instr_dir_count, "DB_INSTRUMENT_DIRECTORY_COUNT");
133 LSCPEvent::RegisterEvent(LSCPEvent::event_db_instr_dir_info, "DB_INSTRUMENT_DIRECTORY_INFO");
134 LSCPEvent::RegisterEvent(LSCPEvent::event_db_instr_count, "DB_INSTRUMENT_COUNT");
135 LSCPEvent::RegisterEvent(LSCPEvent::event_db_instr_info, "DB_INSTRUMENT_INFO");
136 LSCPEvent::RegisterEvent(LSCPEvent::event_db_instrs_job_info, "DB_INSTRUMENTS_JOB_INFO");
137 LSCPEvent::RegisterEvent(LSCPEvent::event_misc, "MISCELLANEOUS");
138 LSCPEvent::RegisterEvent(LSCPEvent::event_total_stream_count, "TOTAL_STREAM_COUNT");
139 LSCPEvent::RegisterEvent(LSCPEvent::event_total_voice_count, "TOTAL_VOICE_COUNT");
140 LSCPEvent::RegisterEvent(LSCPEvent::event_global_info, "GLOBAL_INFO");
141 LSCPEvent::RegisterEvent(LSCPEvent::event_channel_midi, "CHANNEL_MIDI");
142 LSCPEvent::RegisterEvent(LSCPEvent::event_device_midi, "DEVICE_MIDI");
143 LSCPEvent::RegisterEvent(LSCPEvent::event_fx_instance_count, "EFFECT_INSTANCE_COUNT");
144 LSCPEvent::RegisterEvent(LSCPEvent::event_fx_instance_info, "EFFECT_INSTANCE_INFO");
145 LSCPEvent::RegisterEvent(LSCPEvent::event_send_fx_chain_count, "SEND_EFFECT_CHAIN_COUNT");
146 LSCPEvent::RegisterEvent(LSCPEvent::event_send_fx_chain_info, "SEND_EFFECT_CHAIN_INFO");
147 hSocket = -1;
148 }
149
150 LSCPServer::~LSCPServer() {
151 CloseAllConnections();
152 InstrumentManager::StopBackgroundThread();
153 #if defined(WIN32)
154 if (hSocket >= 0) closesocket(hSocket);
155 #else
156 if (hSocket >= 0) close(hSocket);
157 #endif
158 }
159
160 LSCPServer::EventHandler::EventHandler(LSCPServer* pParent) {
161 this->pParent = pParent;
162 }
163
164 LSCPServer::EventHandler::~EventHandler() {
165 std::vector<midi_listener_entry> l = channelMidiListeners;
166 channelMidiListeners.clear();
167 for (int i = 0; i < l.size(); i++)
168 delete l[i].pMidiListener;
169 }
170
171 void LSCPServer::EventHandler::ChannelCountChanged(int NewCount) {
172 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_channel_count, NewCount));
173 }
174
175 void LSCPServer::EventHandler::ChannelAdded(SamplerChannel* pChannel) {
176 pChannel->AddEngineChangeListener(this);
177 }
178
179 void LSCPServer::EventHandler::ChannelToBeRemoved(SamplerChannel* pChannel) {
180 if (!pChannel->GetEngineChannel()) return;
181 EngineToBeChanged(pChannel->Index());
182 }
183
184 void LSCPServer::EventHandler::EngineToBeChanged(int ChannelId) {
185 SamplerChannel* pSamplerChannel =
186 pParent->pSampler->GetSamplerChannel(ChannelId);
187 if (!pSamplerChannel) return;
188 EngineChannel* pEngineChannel =
189 pSamplerChannel->GetEngineChannel();
190 if (!pEngineChannel) return;
191 for (std::vector<midi_listener_entry>::iterator iter = channelMidiListeners.begin(); iter != channelMidiListeners.end(); ++iter) {
192 if ((*iter).pEngineChannel == pEngineChannel) {
193 VirtualMidiDevice* pMidiListener = (*iter).pMidiListener;
194 pEngineChannel->Disconnect(pMidiListener);
195 channelMidiListeners.erase(iter);
196 delete pMidiListener;
197 return;
198 }
199 }
200 }
201
202 void LSCPServer::EventHandler::EngineChanged(int ChannelId) {
203 SamplerChannel* pSamplerChannel =
204 pParent->pSampler->GetSamplerChannel(ChannelId);
205 if (!pSamplerChannel) return;
206 EngineChannel* pEngineChannel =
207 pSamplerChannel->GetEngineChannel();
208 if (!pEngineChannel) return;
209 VirtualMidiDevice* pMidiListener = new VirtualMidiDevice;
210 pEngineChannel->Connect(pMidiListener);
211 midi_listener_entry entry = {
212 pSamplerChannel, pEngineChannel, pMidiListener
213 };
214 channelMidiListeners.push_back(entry);
215 }
216
217 void LSCPServer::EventHandler::AudioDeviceCountChanged(int NewCount) {
218 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_audio_device_count, NewCount));
219 }
220
221 void LSCPServer::EventHandler::MidiDeviceCountChanged(int NewCount) {
222 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_device_count, NewCount));
223 }
224
225 void LSCPServer::EventHandler::MidiDeviceToBeDestroyed(MidiInputDevice* pDevice) {
226 pDevice->RemoveMidiPortCountListener(this);
227 for (int i = 0; i < pDevice->PortCount(); ++i)
228 MidiPortToBeRemoved(pDevice->GetPort(i));
229 }
230
231 void LSCPServer::EventHandler::MidiDeviceCreated(MidiInputDevice* pDevice) {
232 pDevice->AddMidiPortCountListener(this);
233 for (int i = 0; i < pDevice->PortCount(); ++i)
234 MidiPortAdded(pDevice->GetPort(i));
235 }
236
237 void LSCPServer::EventHandler::MidiPortCountChanged(int NewCount) {
238 // yet unused
239 }
240
241 void LSCPServer::EventHandler::MidiPortToBeRemoved(MidiInputPort* pPort) {
242 for (std::vector<device_midi_listener_entry>::iterator iter = deviceMidiListeners.begin(); iter != deviceMidiListeners.end(); ++iter) {
243 if ((*iter).pPort == pPort) {
244 VirtualMidiDevice* pMidiListener = (*iter).pMidiListener;
245 pPort->Disconnect(pMidiListener);
246 deviceMidiListeners.erase(iter);
247 delete pMidiListener;
248 return;
249 }
250 }
251 }
252
253 void LSCPServer::EventHandler::MidiPortAdded(MidiInputPort* pPort) {
254 // find out the device ID
255 std::map<uint, MidiInputDevice*> devices =
256 pParent->pSampler->GetMidiInputDevices();
257 for (
258 std::map<uint, MidiInputDevice*>::iterator iter = devices.begin();
259 iter != devices.end(); ++iter
260 ) {
261 if (iter->second == pPort->GetDevice()) { // found
262 VirtualMidiDevice* pMidiListener = new VirtualMidiDevice;
263 pPort->Connect(pMidiListener);
264 device_midi_listener_entry entry = {
265 pPort, pMidiListener, iter->first
266 };
267 deviceMidiListeners.push_back(entry);
268 return;
269 }
270 }
271 }
272
273 void LSCPServer::EventHandler::MidiInstrumentCountChanged(int MapId, int NewCount) {
274 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_count, MapId, NewCount));
275 }
276
277 void LSCPServer::EventHandler::MidiInstrumentInfoChanged(int MapId, int Bank, int Program) {
278 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_info, MapId, Bank, Program));
279 }
280
281 void LSCPServer::EventHandler::MidiInstrumentMapCountChanged(int NewCount) {
282 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_map_count, NewCount));
283 }
284
285 void LSCPServer::EventHandler::MidiInstrumentMapInfoChanged(int MapId) {
286 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_map_info, MapId));
287 }
288
289 void LSCPServer::EventHandler::FxSendCountChanged(int ChannelId, int NewCount) {
290 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_count, ChannelId, NewCount));
291 }
292
293 void LSCPServer::EventHandler::VoiceCountChanged(int ChannelId, int NewCount) {
294 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_voice_count, ChannelId, NewCount));
295 }
296
297 void LSCPServer::EventHandler::StreamCountChanged(int ChannelId, int NewCount) {
298 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_stream_count, ChannelId, NewCount));
299 }
300
301 void LSCPServer::EventHandler::BufferFillChanged(int ChannelId, String FillData) {
302 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_buffer_fill, ChannelId, FillData));
303 }
304
305 void LSCPServer::EventHandler::TotalVoiceCountChanged(int NewCount) {
306 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_total_voice_count, NewCount));
307 }
308
309 void LSCPServer::EventHandler::TotalStreamCountChanged(int NewCount) {
310 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_total_stream_count, NewCount));
311 }
312
313 #if HAVE_SQLITE3
314 void LSCPServer::DbInstrumentsEventHandler::DirectoryCountChanged(String Dir) {
315 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_dir_count, InstrumentsDb::toEscapedPath(Dir)));
316 }
317
318 void LSCPServer::DbInstrumentsEventHandler::DirectoryInfoChanged(String Dir) {
319 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_dir_info, InstrumentsDb::toEscapedPath(Dir)));
320 }
321
322 void LSCPServer::DbInstrumentsEventHandler::DirectoryNameChanged(String Dir, String NewName) {
323 Dir = "'" + InstrumentsDb::toEscapedPath(Dir) + "'";
324 NewName = "'" + InstrumentsDb::toEscapedPath(NewName) + "'";
325 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_dir_info, "NAME", Dir, NewName));
326 }
327
328 void LSCPServer::DbInstrumentsEventHandler::InstrumentCountChanged(String Dir) {
329 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_count, InstrumentsDb::toEscapedPath(Dir)));
330 }
331
332 void LSCPServer::DbInstrumentsEventHandler::InstrumentInfoChanged(String Instr) {
333 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_info, InstrumentsDb::toEscapedPath(Instr)));
334 }
335
336 void LSCPServer::DbInstrumentsEventHandler::InstrumentNameChanged(String Instr, String NewName) {
337 Instr = "'" + InstrumentsDb::toEscapedPath(Instr) + "'";
338 NewName = "'" + InstrumentsDb::toEscapedPath(NewName) + "'";
339 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_info, "NAME", Instr, NewName));
340 }
341
342 void LSCPServer::DbInstrumentsEventHandler::JobStatusChanged(int JobId) {
343 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instrs_job_info, JobId));
344 }
345 #endif // HAVE_SQLITE3
346
347 void LSCPServer::RemoveListeners() {
348 pSampler->RemoveChannelCountListener(&eventHandler);
349 pSampler->RemoveAudioDeviceCountListener(&eventHandler);
350 pSampler->RemoveMidiDeviceCountListener(&eventHandler);
351 pSampler->RemoveVoiceCountListener(&eventHandler);
352 pSampler->RemoveStreamCountListener(&eventHandler);
353 pSampler->RemoveBufferFillListener(&eventHandler);
354 pSampler->RemoveTotalStreamCountListener(&eventHandler);
355 pSampler->RemoveTotalVoiceCountListener(&eventHandler);
356 pSampler->RemoveFxSendCountListener(&eventHandler);
357 MidiInstrumentMapper::RemoveMidiInstrumentCountListener(&eventHandler);
358 MidiInstrumentMapper::RemoveMidiInstrumentInfoListener(&eventHandler);
359 MidiInstrumentMapper::RemoveMidiInstrumentMapCountListener(&eventHandler);
360 MidiInstrumentMapper::RemoveMidiInstrumentMapInfoListener(&eventHandler);
361 #if HAVE_SQLITE3
362 InstrumentsDb::GetInstrumentsDb()->RemoveInstrumentsDbListener(&dbInstrumentsEventHandler);
363 #endif
364 }
365
366 /**
367 * Blocks the calling thread until the LSCP Server is initialized and
368 * accepting socket connections, if the server is already initialized then
369 * this method will return immediately.
370 * @param TimeoutSeconds - optional: max. wait time in seconds
371 * (default: 0s)
372 * @param TimeoutNanoSeconds - optional: max wait time in nano seconds
373 * (default: 0ns)
374 * @returns 0 on success, a value less than 0 if timeout exceeded
375 */
376 int LSCPServer::WaitUntilInitialized(long TimeoutSeconds, long TimeoutNanoSeconds) {
377 return Initialized.WaitAndUnlockIf(false, TimeoutSeconds, TimeoutNanoSeconds);
378 }
379
380 int LSCPServer::Main() {
381 #if defined(WIN32)
382 WSADATA wsaData;
383 int iResult;
384 iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
385 if (iResult != 0) {
386 std::cerr << "LSCPServer: WSAStartup failed: " << iResult << "\n";
387 exit(EXIT_FAILURE);
388 }
389 #endif
390 hSocket = socket(AF_INET, SOCK_STREAM, 0);
391 if (hSocket < 0) {
392 std::cerr << "LSCPServer: Could not create server socket." << std::endl;
393 //return -1;
394 exit(EXIT_FAILURE);
395 }
396
397 if (bind(hSocket, (sockaddr*) &SocketAddress, sizeof(sockaddr_in)) < 0) {
398 std::cerr << "LSCPServer: Could not bind server socket, retrying for " << ToString(LSCP_SERVER_BIND_TIMEOUT) << " seconds...";
399 for (int trial = 0; true; trial++) { // retry for LSCP_SERVER_BIND_TIMEOUT seconds
400 if (bind(hSocket, (sockaddr*) &SocketAddress, sizeof(sockaddr_in)) < 0) {
401 if (trial > LSCP_SERVER_BIND_TIMEOUT) {
402 std::cerr << "gave up!" << std::endl;
403 #if defined(WIN32)
404 closesocket(hSocket);
405 #else
406 close(hSocket);
407 #endif
408 //return -1;
409 exit(EXIT_FAILURE);
410 }
411 else sleep(1); // sleep 1s
412 }
413 else break; // success
414 }
415 }
416
417 listen(hSocket, 1);
418 Initialized.Set(true);
419
420 // Registering event listeners
421 pSampler->AddChannelCountListener(&eventHandler);
422 pSampler->AddAudioDeviceCountListener(&eventHandler);
423 pSampler->AddMidiDeviceCountListener(&eventHandler);
424 pSampler->AddVoiceCountListener(&eventHandler);
425 pSampler->AddStreamCountListener(&eventHandler);
426 pSampler->AddBufferFillListener(&eventHandler);
427 pSampler->AddTotalStreamCountListener(&eventHandler);
428 pSampler->AddTotalVoiceCountListener(&eventHandler);
429 pSampler->AddFxSendCountListener(&eventHandler);
430 MidiInstrumentMapper::AddMidiInstrumentCountListener(&eventHandler);
431 MidiInstrumentMapper::AddMidiInstrumentInfoListener(&eventHandler);
432 MidiInstrumentMapper::AddMidiInstrumentMapCountListener(&eventHandler);
433 MidiInstrumentMapper::AddMidiInstrumentMapInfoListener(&eventHandler);
434 #if HAVE_SQLITE3
435 InstrumentsDb::GetInstrumentsDb()->AddInstrumentsDbListener(&dbInstrumentsEventHandler);
436 #endif
437 // now wait for client connections and handle their requests
438 sockaddr_in client;
439 int length = sizeof(client);
440 FD_ZERO(&fdSet);
441 FD_SET(hSocket, &fdSet);
442 int maxSessions = hSocket;
443
444 timeval timeout;
445
446 while (true) {
447 #if CONFIG_PTHREAD_TESTCANCEL
448 TestCancel();
449 #endif
450 // check if some engine channel's parameter / status changed, if so notify the respective LSCP event subscribers
451 {
452 LockGuard lock(EngineChannelFactory::EngineChannelsMutex);
453 std::set<EngineChannel*> engineChannels = EngineChannelFactory::EngineChannelInstances();
454 std::set<EngineChannel*>::iterator itEngineChannel = engineChannels.begin();
455 std::set<EngineChannel*>::iterator itEnd = engineChannels.end();
456 for (; itEngineChannel != itEnd; ++itEngineChannel) {
457 if ((*itEngineChannel)->StatusChanged()) {
458 SendLSCPNotify(LSCPEvent(LSCPEvent::event_channel_info, (*itEngineChannel)->GetSamplerChannel()->Index()));
459 }
460
461 for (int i = 0; i < (*itEngineChannel)->GetFxSendCount(); i++) {
462 FxSend* fxs = (*itEngineChannel)->GetFxSend(i);
463 if(fxs != NULL && fxs->IsInfoChanged()) {
464 int chn = (*itEngineChannel)->GetSamplerChannel()->Index();
465 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_info, chn, fxs->Id()));
466 fxs->SetInfoChanged(false);
467 }
468 }
469 }
470 }
471
472 // check if MIDI data arrived on some engine channel
473 for (int i = 0; i < eventHandler.channelMidiListeners.size(); ++i) {
474 const EventHandler::midi_listener_entry entry =
475 eventHandler.channelMidiListeners[i];
476 VirtualMidiDevice* pMidiListener = entry.pMidiListener;
477 if (pMidiListener->NotesChanged()) {
478 for (int iNote = 0; iNote < 128; iNote++) {
479 if (pMidiListener->NoteChanged(iNote)) {
480 const bool bActive = pMidiListener->NoteIsActive(iNote);
481 LSCPServer::SendLSCPNotify(
482 LSCPEvent(
483 LSCPEvent::event_channel_midi,
484 entry.pSamplerChannel->Index(),
485 std::string(bActive ? "NOTE_ON" : "NOTE_OFF"),
486 iNote,
487 bActive ? pMidiListener->NoteOnVelocity(iNote)
488 : pMidiListener->NoteOffVelocity(iNote)
489 )
490 );
491 }
492 }
493 }
494 }
495
496 // check if MIDI data arrived on some MIDI device
497 for (int i = 0; i < eventHandler.deviceMidiListeners.size(); ++i) {
498 const EventHandler::device_midi_listener_entry entry =
499 eventHandler.deviceMidiListeners[i];
500 VirtualMidiDevice* pMidiListener = entry.pMidiListener;
501 if (pMidiListener->NotesChanged()) {
502 for (int iNote = 0; iNote < 128; iNote++) {
503 if (pMidiListener->NoteChanged(iNote)) {
504 const bool bActive = pMidiListener->NoteIsActive(iNote);
505 LSCPServer::SendLSCPNotify(
506 LSCPEvent(
507 LSCPEvent::event_device_midi,
508 entry.uiDeviceID,
509 entry.pPort->GetPortNumber(),
510 std::string(bActive ? "NOTE_ON" : "NOTE_OFF"),
511 iNote,
512 bActive ? pMidiListener->NoteOnVelocity(iNote)
513 : pMidiListener->NoteOffVelocity(iNote)
514 )
515 );
516 }
517 }
518 }
519 }
520
521 //Now let's deliver late notifies (if any)
522 {
523 LockGuard lock(NotifyBufferMutex);
524 for (std::map<int,String>::iterator iterNotify = bufferedNotifies.begin(); iterNotify != bufferedNotifies.end(); iterNotify++) {
525 #ifdef MSG_NOSIGNAL
526 send(iterNotify->first, iterNotify->second.c_str(), iterNotify->second.size(), MSG_NOSIGNAL);
527 #else
528 send(iterNotify->first, iterNotify->second.c_str(), iterNotify->second.size(), 0);
529 #endif
530 }
531 bufferedNotifies.clear();
532 }
533
534 fd_set selectSet = fdSet;
535 timeout.tv_sec = 0;
536 timeout.tv_usec = 100000;
537
538 int retval = select(maxSessions+1, &selectSet, NULL, NULL, &timeout);
539
540 if (retval == 0 || (retval == -1 && errno == EINTR))
541 continue; //Nothing try again
542 if (retval == -1) {
543 std::cerr << "LSCPServer: Socket select error." << std::endl;
544 #if defined(WIN32)
545 closesocket(hSocket);
546 #else
547 close(hSocket);
548 #endif
549 exit(EXIT_FAILURE);
550 }
551
552 //Accept new connections now (if any)
553 if (FD_ISSET(hSocket, &selectSet)) {
554 int socket = accept(hSocket, (sockaddr*) &client, (socklen_t*) &length);
555 if (socket < 0) {
556 std::cerr << "LSCPServer: Client connection failed." << std::endl;
557 exit(EXIT_FAILURE);
558 }
559
560 #if defined(WIN32)
561 u_long nonblock_io = 1;
562 if( ioctlsocket(socket, FIONBIO, &nonblock_io) ) {
563 std::cerr << "LSCPServer: ioctlsocket: set FIONBIO failed. Error " << WSAGetLastError() << std::endl;
564 exit(EXIT_FAILURE);
565 }
566 #else
567 struct linger linger;
568 linger.l_onoff = 1;
569 linger.l_linger = 0;
570 if(setsockopt(socket, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger))) {
571 std::cerr << "LSCPServer: Failed to set SO_LINGER\n";
572 }
573
574 if (fcntl(socket, F_SETFL, O_NONBLOCK)) {
575 std::cerr << "LSCPServer: F_SETFL O_NONBLOCK failed." << std::endl;
576 exit(EXIT_FAILURE);
577 }
578 #endif
579
580 // Parser initialization
581 yyparse_param_t yyparse_param;
582 yyparse_param.pServer = this;
583 yyparse_param.hSession = socket;
584
585 Sessions.push_back(yyparse_param);
586 FD_SET(socket, &fdSet);
587 if (socket > maxSessions)
588 maxSessions = socket;
589 dmsg(1,("LSCPServer: Client connection established on socket:%d.\n", socket));
590 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_misc, "Client connection established on socket", socket));
591 continue; //Maybe this was the only selected socket, better select again
592 }
593
594 //Something was selected and it was not the hSocket, so it must be some command(s) coming.
595 for (std::vector<yyparse_param_t>::iterator iter = Sessions.begin(); iter != Sessions.end(); iter++) {
596 if (FD_ISSET((*iter).hSession, &selectSet)) { //Was it this socket?
597 currentSocket = (*iter).hSession; //a hack
598 if (GetLSCPCommand(iter)) { //Have we read the entire command?
599 dmsg(3,("LSCPServer: Got command on socket %d, calling parser.\n", currentSocket));
600 int dummy; // just a temporary hack to fulfill the restart() function prototype
601 restart(NULL, dummy); // restart the 'scanner'
602 itCurrentSession = iter; // another hack
603 dmsg(2,("LSCPServer: [%s]\n",bufferedCommands[currentSocket].c_str()));
604 if ((*iter).bVerbose) { // if echo mode enabled
605 AnswerClient(bufferedCommands[currentSocket]);
606 }
607 int result = yyparse(&(*iter));
608 currentSocket = -1; //continuation of a hack
609 itCurrentSession = Sessions.end(); // hack as well
610 dmsg(3,("LSCPServer: Done parsing on socket %d.\n", currentSocket));
611 if (result == LSCP_QUIT) { //Was it a quit command by any chance?
612 CloseConnection(iter);
613 }
614 }
615 currentSocket = -1; //continuation of a hack
616 //socket may have been closed, iter may be invalid, get out of the loop for now.
617 //we'll be back if there is data.
618 break;
619 }
620 }
621 }
622 }
623
624 void LSCPServer::CloseConnection( std::vector<yyparse_param_t>::iterator iter ) {
625 int socket = (*iter).hSession;
626 dmsg(1,("LSCPServer: Client connection terminated on socket:%d.\n",socket));
627 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_misc, "Client connection terminated on socket", socket));
628 Sessions.erase(iter);
629 FD_CLR(socket, &fdSet);
630 {
631 LockGuard lock(SubscriptionMutex);
632 // Must unsubscribe this socket from all events (if any)
633 for (std::map< LSCPEvent::event_t, std::list<int> >::iterator iter = eventSubscriptions.begin(); iter != eventSubscriptions.end(); iter++) {
634 iter->second.remove(socket);
635 }
636 }
637 LockGuard lock(NotifyMutex);
638 bufferedCommands.erase(socket);
639 bufferedNotifies.erase(socket);
640 #if defined(WIN32)
641 closesocket(socket);
642 #else
643 close(socket);
644 #endif
645 }
646
647 void LSCPServer::CloseAllConnections() {
648 std::vector<yyparse_param_t>::iterator iter = Sessions.begin();
649 while(iter != Sessions.end()) {
650 CloseConnection(iter);
651 iter = Sessions.begin();
652 }
653 }
654
655 int LSCPServer::EventSubscribers( std::list<LSCPEvent::event_t> events ) {
656 int subs = 0;
657 LockGuard lock(SubscriptionMutex);
658 for( std::list<LSCPEvent::event_t>::iterator iter = events.begin();
659 iter != events.end(); iter++)
660 {
661 subs += eventSubscriptions.count(*iter);
662 }
663 return subs;
664 }
665
666 void LSCPServer::SendLSCPNotify( LSCPEvent event ) {
667 LockGuard lock(SubscriptionMutex);
668 if (eventSubscriptions.count(event.GetType()) == 0) {
669 // Nobody is subscribed to this event
670 return;
671 }
672 std::list<int>::iterator iter = eventSubscriptions[event.GetType()].begin();
673 std::list<int>::iterator end = eventSubscriptions[event.GetType()].end();
674 String notify = event.Produce();
675
676 while (true) {
677 if (NotifyMutex.Trylock()) {
678 for(;iter != end; iter++)
679 #ifdef MSG_NOSIGNAL
680 send(*iter, notify.c_str(), notify.size(), MSG_NOSIGNAL);
681 #else
682 send(*iter, notify.c_str(), notify.size(), 0);
683 #endif
684 NotifyMutex.Unlock();
685 break;
686 } else {
687 if (NotifyBufferMutex.Trylock()) {
688 for(;iter != end; iter++)
689 bufferedNotifies[*iter] += notify;
690 NotifyBufferMutex.Unlock();
691 break;
692 }
693 }
694 }
695 }
696
697 extern int GetLSCPCommand( void *buf, int max_size ) {
698 String command = LSCPServer::bufferedCommands[LSCPServer::currentSocket];
699 if (command.size() == 0) { //Parser wants input but we have nothing.
700 strcpy((char*) buf, "\n"); //So give it an empty command
701 return 1; //to keep it happy.
702 }
703
704 if (max_size < command.size()) {
705 std::cerr << "getLSCPCommand: Flex buffer too small, ignoring the command." << std::endl;
706 return 0; //This will never happen
707 }
708
709 strcpy((char*) buf, command.c_str());
710 LSCPServer::bufferedCommands.erase(LSCPServer::currentSocket);
711 return command.size();
712 }
713
714 extern yyparse_param_t* GetCurrentYaccSession() {
715 return &(*itCurrentSession);
716 }
717
718 /**
719 * Generate the relevant LSCP documentation reference section if necessary.
720 * The documentation section for the currently active command on the LSCP
721 * shell's command line will be encoded in a special format, specifically for
722 * the LSCP shell application.
723 *
724 * @param line - current LSCP command line
725 * @param param - reentrant Bison parser parameters
726 *
727 * @return encoded reference string or empty string if nothing shall be sent
728 * to LSCP shell (client) at this point
729 */
730 String LSCPServer::generateLSCPDocReply(const String& line, yyparse_param_t* param) {
731 String result;
732 lscp_ref_entry_t* ref = lscp_reference_for_command(line.c_str());
733 // Pointer comparison works here, since the function above always
734 // returns the same constant pointer for the respective LSCP
735 // command ... Only send the LSCP reference section to the client if
736 // another LSCP reference section became relevant now:
737 if (ref != param->pLSCPDocRef) {
738 param->pLSCPDocRef = ref;
739 if (ref) { // send a new LSCP doc section to client ...
740 result += "SHD:" + ToString(LSCP_SHD_MATCH) + ":" + String(ref->name) + "\n";
741 result += String(ref->section) + "\n";
742 result += "."; // dot line marks the end of the text for client
743 } else { // inform client that no LSCP doc section matches right now ...
744 result = "SHD:" + ToString(LSCP_SHD_NO_MATCH);
745 }
746 }
747 dmsg(4,("LSCP doc reply -> '%s'\n", result.c_str()));
748 return result;
749 }
750
751 /**
752 * Will be called to try to read the command from the socket
753 * If command is read, it will return true. Otherwise false is returned.
754 * In any case the received portion (complete or incomplete) is saved into bufferedCommand map.
755 */
756 bool LSCPServer::GetLSCPCommand( std::vector<yyparse_param_t>::iterator iter ) {
757 int socket = (*iter).hSession;
758 int result;
759 char c;
760 std::vector<char> input;
761
762 // first get as many character as possible and add it to the 'input' buffer
763 while (true) {
764 #if defined(WIN32)
765 result = recv(socket, (char *)&c, 1, 0); //Read one character at a time for now
766 #else
767 result = recv(socket, (void *)&c, 1, 0); //Read one character at a time for now
768 #endif
769 if (result == 1) input.push_back(c);
770 else break; // end of input or some error
771 if (c == '\n') break; // process line by line
772 }
773
774 // process input buffer
775 for (int i = 0; i < input.size(); ++i) {
776 c = input[i];
777 if (c == '\r') continue; //Ignore CR
778 if (c == '\n') {
779 // only if the other side is the LSCP shell application:
780 // check the current (incomplete) command line for syntax errors,
781 // possible completions and report everything back to the shell
782 if ((*iter).bShellInteract || (*iter).bShellAutoCorrect) {
783 String s = lscpParserProcessShellInteraction(bufferedCommands[socket], &(*iter), false);
784 if (!s.empty() && (*iter).bShellInteract) AnswerClient(s + "\n");
785 }
786 // if other side is LSCP shell application, send the relevant LSCP
787 // documentation section of the current command line (if necessary)
788 if ((*iter).bShellSendLSCPDoc && (*iter).bShellInteract) {
789 String s = generateLSCPDocReply(bufferedCommands[socket], &(*iter));
790 if (!s.empty()) AnswerClient(s + "\n");
791 }
792 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_misc, "Received \'" + bufferedCommands[socket] + "\' on socket", socket));
793 bufferedCommands[socket] += "\r\n";
794 return true; //Complete command was read
795 } else if (c == 2) { // custom ASCII code usage for moving cursor left (LSCP shell)
796 if (iter->iCursorOffset + bufferedCommands[socket].size() > 0)
797 iter->iCursorOffset--;
798 } else if (c == 3) { // custom ASCII code usage for moving cursor right (LSCP shell)
799 if (iter->iCursorOffset < 0) iter->iCursorOffset++;
800 } else {
801 size_t cursorPos = bufferedCommands[socket].size() + iter->iCursorOffset;
802 // backspace character - should only happen with shell
803 if (c == '\b') {
804 if (!bufferedCommands[socket].empty() && cursorPos > 0)
805 bufferedCommands[socket].erase(cursorPos - 1, 1);
806 } else { // append (or insert) new character (at current cursor position) ...
807 if (cursorPos >= 0)
808 bufferedCommands[socket].insert(cursorPos, String(1,c)); // insert
809 else
810 bufferedCommands[socket] += c; // append
811 }
812 }
813 // Only if the other side (client) is the LSCP shell application:
814 // The following block takes care about automatic correction, auto
815 // completion (and suggestions), LSCP reference documentation, etc.
816 // The "if" statement here is for optimization reasons, so that the
817 // heavy LSCP grammar evaluation algorithm is only executed once for an
818 // entire command line received.
819 if (i == input.size() - 1) {
820 // check the current (incomplete) command line for syntax errors,
821 // possible completions and report everything back to the shell
822 if ((*iter).bShellInteract || (*iter).bShellAutoCorrect) {
823 String s = lscpParserProcessShellInteraction(bufferedCommands[socket], &(*iter), true);
824 if (!s.empty() && (*iter).bShellInteract && i == input.size() - 1)
825 AnswerClient(s + "\n");
826 }
827 // if other side is LSCP shell application, send the relevant LSCP
828 // documentation section of the current command line (if necessary)
829 if ((*iter).bShellSendLSCPDoc && (*iter).bShellInteract) {
830 String s = generateLSCPDocReply(bufferedCommands[socket], &(*iter));
831 if (!s.empty()) AnswerClient(s + "\n");
832 }
833 }
834 }
835
836 // handle network errors ...
837 if (result == 0) { //socket was selected, so 0 here means client has closed the connection
838 CloseConnection(iter);
839 return false;
840 }
841 #if defined(WIN32)
842 if (result == SOCKET_ERROR) {
843 int wsa_lasterror = WSAGetLastError();
844 if (wsa_lasterror == WSAEWOULDBLOCK) //Would block, try again later.
845 return false;
846 dmsg(2,("LSCPScanner: Socket error after recv() Error %d.\n", wsa_lasterror));
847 CloseConnection(iter);
848 return false;
849 }
850 #else
851 if (result == -1) {
852 if (errno == EAGAIN) //Would block, try again later.
853 return false;
854 switch(errno) {
855 case EBADF:
856 dmsg(2,("LSCPScanner: The argument s is an invalid descriptor.\n"));
857 return false;
858 case ECONNREFUSED:
859 dmsg(2,("LSCPScanner: A remote host refused to allow the network connection (typically because it is not running the requested service).\n"));
860 return false;
861 case ENOTCONN:
862 dmsg(2,("LSCPScanner: The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2)).\n"));
863 return false;
864 case ENOTSOCK:
865 dmsg(2,("LSCPScanner: The argument s does not refer to a socket.\n"));
866 return false;
867 case EAGAIN:
868 dmsg(2,("LSCPScanner: The socket is marked non-blocking and the receive operation would block, or a receive timeout had been set and the timeout expired before data was received.\n"));
869 return false;
870 case EINTR:
871 dmsg(2,("LSCPScanner: The receive was interrupted by delivery of a signal before any data were available.\n"));
872 return false;
873 case EFAULT:
874 dmsg(2,("LSCPScanner: The receive buffer pointer(s) point outside the process's address space.\n"));
875 return false;
876 case EINVAL:
877 dmsg(2,("LSCPScanner: Invalid argument passed.\n"));
878 return false;
879 case ENOMEM:
880 dmsg(2,("LSCPScanner: Could not allocate memory for recvmsg.\n"));
881 return false;
882 default:
883 dmsg(2,("LSCPScanner: Unknown recv() error.\n"));
884 return false;
885 }
886 CloseConnection(iter);
887 return false;
888 }
889 #endif
890
891 return false;
892 }
893
894 /**
895 * Will be called by the parser whenever it wants to send an answer to the
896 * client / frontend.
897 *
898 * @param ReturnMessage - message that will be send to the client
899 */
900 void LSCPServer::AnswerClient(String ReturnMessage) {
901 dmsg(2,("LSCPServer::AnswerClient(ReturnMessage='%s')", ReturnMessage.c_str()));
902 if (currentSocket != -1) {
903 LockGuard lock(NotifyMutex);
904
905 // just if other side is LSCP shell: in case respose is a multi-line
906 // one, then inform client about it before sending the actual mult-line
907 // response
908 if (GetCurrentYaccSession()->bShellInteract) {
909 // check if this is a multi-line response
910 int n = 0;
911 for (int i = 0; i < ReturnMessage.size(); ++i)
912 if (ReturnMessage[i] == '\n') ++n;
913 if (n >= 2) {
914 dmsg(2,("LSCP Shell <- expect mult-line response\n"));
915 String s = LSCP_SHK_EXPECT_MULTI_LINE "\r\n";
916 #ifdef MSG_NOSIGNAL
917 send(currentSocket, s.c_str(), s.size(), MSG_NOSIGNAL);
918 #else
919 send(currentSocket, s.c_str(), s.size(), 0);
920 #endif
921 }
922 }
923
924 #ifdef MSG_NOSIGNAL
925 send(currentSocket, ReturnMessage.c_str(), ReturnMessage.size(), MSG_NOSIGNAL);
926 #else
927 send(currentSocket, ReturnMessage.c_str(), ReturnMessage.size(), 0);
928 #endif
929 }
930 }
931
932 /**
933 * Find a created audio output device index.
934 */
935 int LSCPServer::GetAudioOutputDeviceIndex ( AudioOutputDevice *pDevice )
936 {
937 // Search for the created device to get its index
938 std::map<uint, AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
939 std::map<uint, AudioOutputDevice*>::iterator iter = devices.begin();
940 for (; iter != devices.end(); iter++) {
941 if (iter->second == pDevice)
942 return iter->first;
943 }
944 // Not found.
945 return -1;
946 }
947
948 /**
949 * Find a created midi input device index.
950 */
951 int LSCPServer::GetMidiInputDeviceIndex ( MidiInputDevice *pDevice )
952 {
953 // Search for the created device to get its index
954 std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
955 std::map<uint, MidiInputDevice*>::iterator iter = devices.begin();
956 for (; iter != devices.end(); iter++) {
957 if (iter->second == pDevice)
958 return iter->first;
959 }
960 // Not found.
961 return -1;
962 }
963
964 String LSCPServer::CreateAudioOutputDevice(String Driver, std::map<String,String> Parameters) {
965 dmsg(2,("LSCPServer: CreateAudioOutputDevice(Driver=%s)\n", Driver.c_str()));
966 LSCPResultSet result;
967 try {
968 AudioOutputDevice* pDevice = pSampler->CreateAudioOutputDevice(Driver, Parameters);
969 // search for the created device to get its index
970 int index = GetAudioOutputDeviceIndex(pDevice);
971 if (index == -1) throw Exception("Internal error: could not find created audio output device.");
972 result = index; // success
973 }
974 catch (Exception e) {
975 result.Error(e);
976 }
977 return result.Produce();
978 }
979
980 String LSCPServer::CreateMidiInputDevice(String Driver, std::map<String,String> Parameters) {
981 dmsg(2,("LSCPServer: CreateMidiInputDevice(Driver=%s)\n", Driver.c_str()));
982 LSCPResultSet result;
983 try {
984 MidiInputDevice* pDevice = pSampler->CreateMidiInputDevice(Driver, Parameters);
985 // search for the created device to get its index
986 int index = GetMidiInputDeviceIndex(pDevice);
987 if (index == -1) throw Exception("Internal error: could not find created midi input device.");
988 result = index; // success
989 }
990 catch (Exception e) {
991 result.Error(e);
992 }
993 return result.Produce();
994 }
995
996 String LSCPServer::DestroyAudioOutputDevice(uint DeviceIndex) {
997 dmsg(2,("LSCPServer: DestroyAudioOutputDevice(DeviceIndex=%d)\n", DeviceIndex));
998 LSCPResultSet result;
999 try {
1000 std::map<uint, AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
1001 if (!devices.count(DeviceIndex)) throw Exception("There is no audio output device with index " + ToString(DeviceIndex) + ".");
1002 AudioOutputDevice* pDevice = devices[DeviceIndex];
1003 pSampler->DestroyAudioOutputDevice(pDevice);
1004 }
1005 catch (Exception e) {
1006 result.Error(e);
1007 }
1008 return result.Produce();
1009 }
1010
1011 String LSCPServer::DestroyMidiInputDevice(uint DeviceIndex) {
1012 dmsg(2,("LSCPServer: DestroyMidiInputDevice(DeviceIndex=%d)\n", DeviceIndex));
1013 LSCPResultSet result;
1014 try {
1015 std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
1016 if (!devices.count(DeviceIndex)) throw Exception("There is no audio output device with index " + ToString(DeviceIndex) + ".");
1017 MidiInputDevice* pDevice = devices[DeviceIndex];
1018 pSampler->DestroyMidiInputDevice(pDevice);
1019 }
1020 catch (Exception e) {
1021 result.Error(e);
1022 }
1023 return result.Produce();
1024 }
1025
1026 EngineChannel* LSCPServer::GetEngineChannel(uint uiSamplerChannel) {
1027 SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1028 if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1029
1030 EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();
1031 if (!pEngineChannel) throw Exception("There is no engine deployed on this sampler channel yet");
1032
1033 return pEngineChannel;
1034 }
1035
1036 /**
1037 * Will be called by the parser to load an instrument.
1038 */
1039 String LSCPServer::LoadInstrument(String Filename, uint uiInstrument, uint uiSamplerChannel, bool bBackground) {
1040 dmsg(2,("LSCPServer: LoadInstrument(Filename=%s,Instrument=%d,SamplerChannel=%d)\n", Filename.c_str(), uiInstrument, uiSamplerChannel));
1041 LSCPResultSet result;
1042 try {
1043 SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1044 if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1045 EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();
1046 if (!pEngineChannel) throw Exception("No engine type assigned to sampler channel yet");
1047 if (!pSamplerChannel->GetAudioOutputDevice())
1048 throw Exception("No audio output device connected to sampler channel");
1049 if (bBackground) {
1050 InstrumentManager::instrument_id_t id;
1051 id.FileName = Filename;
1052 id.Index = uiInstrument;
1053 InstrumentManager::LoadInstrumentInBackground(id, pEngineChannel);
1054 }
1055 else {
1056 // tell the engine channel which instrument to load
1057 pEngineChannel->PrepareLoadInstrument(Filename.c_str(), uiInstrument);
1058 // actually start to load the instrument (blocks until completed)
1059 pEngineChannel->LoadInstrument();
1060 }
1061 }
1062 catch (Exception e) {
1063 result.Error(e);
1064 }
1065 return result.Produce();
1066 }
1067
1068 /**
1069 * Will be called by the parser to assign a sampler engine type to a
1070 * sampler channel.
1071 */
1072 String LSCPServer::SetEngineType(String EngineName, uint uiSamplerChannel) {
1073 dmsg(2,("LSCPServer: SetEngineType(EngineName=%s,uiSamplerChannel=%d)\n", EngineName.c_str(), uiSamplerChannel));
1074 LSCPResultSet result;
1075 try {
1076 SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1077 if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1078 LockGuard lock(RTNotifyMutex);
1079 pSamplerChannel->SetEngineType(EngineName);
1080 if(HasSoloChannel()) pSamplerChannel->GetEngineChannel()->SetMute(-1);
1081 }
1082 catch (Exception e) {
1083 result.Error(e);
1084 }
1085 return result.Produce();
1086 }
1087
1088 /**
1089 * Will be called by the parser to get the amount of sampler channels.
1090 */
1091 String LSCPServer::GetChannels() {
1092 dmsg(2,("LSCPServer: GetChannels()\n"));
1093 LSCPResultSet result;
1094 result.Add(pSampler->SamplerChannels());
1095 return result.Produce();
1096 }
1097
1098 /**
1099 * Will be called by the parser to get the list of sampler channels.
1100 */
1101 String LSCPServer::ListChannels() {
1102 dmsg(2,("LSCPServer: ListChannels()\n"));
1103 String list;
1104 std::map<uint,SamplerChannel*> channels = pSampler->GetSamplerChannels();
1105 std::map<uint,SamplerChannel*>::iterator iter = channels.begin();
1106 for (; iter != channels.end(); iter++) {
1107 if (list != "") list += ",";
1108 list += ToString(iter->first);
1109 }
1110 LSCPResultSet result;
1111 result.Add(list);
1112 return result.Produce();
1113 }
1114
1115 /**
1116 * Will be called by the parser to add a sampler channel.
1117 */
1118 String LSCPServer::AddChannel() {
1119 dmsg(2,("LSCPServer: AddChannel()\n"));
1120 SamplerChannel* pSamplerChannel;
1121 {
1122 LockGuard lock(RTNotifyMutex);
1123 pSamplerChannel = pSampler->AddSamplerChannel();
1124 }
1125 LSCPResultSet result(pSamplerChannel->Index());
1126 return result.Produce();
1127 }
1128
1129 /**
1130 * Will be called by the parser to remove a sampler channel.
1131 */
1132 String LSCPServer::RemoveChannel(uint uiSamplerChannel) {
1133 dmsg(2,("LSCPServer: RemoveChannel(SamplerChannel=%d)\n", uiSamplerChannel));
1134 LSCPResultSet result;
1135 {
1136 LockGuard lock(RTNotifyMutex);
1137 pSampler->RemoveSamplerChannel(uiSamplerChannel);
1138 }
1139 return result.Produce();
1140 }
1141
1142 /**
1143 * Will be called by the parser to get the amount of all available engines.
1144 */
1145 String LSCPServer::GetAvailableEngines() {
1146 dmsg(2,("LSCPServer: GetAvailableEngines()\n"));
1147 LSCPResultSet result;
1148 try {
1149 int n = EngineFactory::AvailableEngineTypes().size();
1150 result.Add(n);
1151 }
1152 catch (Exception e) {
1153 result.Error(e);
1154 }
1155 return result.Produce();
1156 }
1157
1158 /**
1159 * Will be called by the parser to get a list of all available engines.
1160 */
1161 String LSCPServer::ListAvailableEngines() {
1162 dmsg(2,("LSCPServer: ListAvailableEngines()\n"));
1163 LSCPResultSet result;
1164 try {
1165 String s = EngineFactory::AvailableEngineTypesAsString();
1166 result.Add(s);
1167 }
1168 catch (Exception e) {
1169 result.Error(e);
1170 }
1171 return result.Produce();
1172 }
1173
1174 /**
1175 * Will be called by the parser to get descriptions for a particular
1176 * sampler engine.
1177 */
1178 String LSCPServer::GetEngineInfo(String EngineName) {
1179 dmsg(2,("LSCPServer: GetEngineInfo(EngineName=%s)\n", EngineName.c_str()));
1180 LSCPResultSet result;
1181 {
1182 LockGuard lock(RTNotifyMutex);
1183 try {
1184 Engine* pEngine = EngineFactory::Create(EngineName);
1185 result.Add("DESCRIPTION", _escapeLscpResponse(pEngine->Description()));
1186 result.Add("VERSION", pEngine->Version());
1187 EngineFactory::Destroy(pEngine);
1188 }
1189 catch (Exception e) {
1190 result.Error(e);
1191 }
1192 }
1193 return result.Produce();
1194 }
1195
1196 /**
1197 * Will be called by the parser to get informations about a particular
1198 * sampler channel.
1199 */
1200 String LSCPServer::GetChannelInfo(uint uiSamplerChannel) {
1201 dmsg(2,("LSCPServer: GetChannelInfo(SamplerChannel=%d)\n", uiSamplerChannel));
1202 LSCPResultSet result;
1203 try {
1204 SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1205 if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1206 EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();
1207
1208 //Defaults values
1209 String EngineName = "NONE";
1210 float Volume = 0.0f;
1211 String InstrumentFileName = "NONE";
1212 String InstrumentName = "NONE";
1213 int InstrumentIndex = -1;
1214 int InstrumentStatus = -1;
1215 int AudioOutputChannels = 0;
1216 String AudioRouting;
1217 int Mute = 0;
1218 bool Solo = false;
1219 String MidiInstrumentMap = "NONE";
1220
1221 if (pEngineChannel) {
1222 EngineName = pEngineChannel->EngineName();
1223 AudioOutputChannels = pEngineChannel->Channels();
1224 Volume = pEngineChannel->Volume();
1225 InstrumentStatus = pEngineChannel->InstrumentStatus();
1226 InstrumentIndex = pEngineChannel->InstrumentIndex();
1227 if (InstrumentIndex != -1) {
1228 InstrumentFileName = pEngineChannel->InstrumentFileName();
1229 InstrumentName = pEngineChannel->InstrumentName();
1230 }
1231 for (int chan = 0; chan < pEngineChannel->Channels(); chan++) {
1232 if (AudioRouting != "") AudioRouting += ",";
1233 AudioRouting += ToString(pEngineChannel->OutputChannel(chan));
1234 }
1235 Mute = pEngineChannel->GetMute();
1236 Solo = pEngineChannel->GetSolo();
1237 if (pEngineChannel->UsesNoMidiInstrumentMap())
1238 MidiInstrumentMap = "NONE";
1239 else if (pEngineChannel->UsesDefaultMidiInstrumentMap())
1240 MidiInstrumentMap = "DEFAULT";
1241 else
1242 MidiInstrumentMap = ToString(pEngineChannel->GetMidiInstrumentMap());
1243 }
1244
1245 result.Add("ENGINE_NAME", EngineName);
1246 result.Add("VOLUME", Volume);
1247
1248 //Some not-so-hardcoded stuff to make GUI look good
1249 result.Add("AUDIO_OUTPUT_DEVICE", GetAudioOutputDeviceIndex(pSamplerChannel->GetAudioOutputDevice()));
1250 result.Add("AUDIO_OUTPUT_CHANNELS", AudioOutputChannels);
1251 result.Add("AUDIO_OUTPUT_ROUTING", AudioRouting);
1252
1253 result.Add("MIDI_INPUT_DEVICE", GetMidiInputDeviceIndex(pSamplerChannel->GetMidiInputDevice()));
1254 result.Add("MIDI_INPUT_PORT", pSamplerChannel->GetMidiInputPort());
1255 if (pSamplerChannel->GetMidiInputChannel() == midi_chan_all) result.Add("MIDI_INPUT_CHANNEL", "ALL");
1256 else result.Add("MIDI_INPUT_CHANNEL", pSamplerChannel->GetMidiInputChannel());
1257
1258 // convert the filename into the correct encoding as defined for LSCP
1259 // (especially in terms of special characters -> escape sequences)
1260 if (InstrumentFileName != "NONE" && InstrumentFileName != "") {
1261 #if WIN32
1262 InstrumentFileName = Path::fromWindows(InstrumentFileName).toLscp();
1263 #else
1264 // assuming POSIX
1265 InstrumentFileName = Path::fromPosix(InstrumentFileName).toLscp();
1266 #endif
1267 }
1268
1269 result.Add("INSTRUMENT_FILE", InstrumentFileName);
1270 result.Add("INSTRUMENT_NR", InstrumentIndex);
1271 result.Add("INSTRUMENT_NAME", _escapeLscpResponse(InstrumentName));
1272 result.Add("INSTRUMENT_STATUS", InstrumentStatus);
1273 result.Add("MUTE", Mute == -1 ? "MUTED_BY_SOLO" : (Mute ? "true" : "false"));
1274 result.Add("SOLO", Solo);
1275 result.Add("MIDI_INSTRUMENT_MAP", MidiInstrumentMap);
1276 }
1277 catch (Exception e) {
1278 result.Error(e);
1279 }
1280 return result.Produce();
1281 }
1282
1283 /**
1284 * Will be called by the parser to get the amount of active voices on a
1285 * particular sampler channel.
1286 */
1287 String LSCPServer::GetVoiceCount(uint uiSamplerChannel) {
1288 dmsg(2,("LSCPServer: GetVoiceCount(SamplerChannel=%d)\n", uiSamplerChannel));
1289 LSCPResultSet result;
1290 try {
1291 EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
1292 if (!pEngineChannel->GetEngine()) throw Exception("No audio output device connected to sampler channel");
1293 result.Add(pEngineChannel->GetEngine()->VoiceCount());
1294 }
1295 catch (Exception e) {
1296 result.Error(e);
1297 }
1298 return result.Produce();
1299 }
1300
1301 /**
1302 * Will be called by the parser to get the amount of active disk streams on a
1303 * particular sampler channel.
1304 */
1305 String LSCPServer::GetStreamCount(uint uiSamplerChannel) {
1306 dmsg(2,("LSCPServer: GetStreamCount(SamplerChannel=%d)\n", uiSamplerChannel));
1307 LSCPResultSet result;
1308 try {
1309 EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
1310 if (!pEngineChannel->GetEngine()) throw Exception("No audio output device connected to sampler channel");
1311 result.Add(pEngineChannel->GetEngine()->DiskStreamCount());
1312 }
1313 catch (Exception e) {
1314 result.Error(e);
1315 }
1316 return result.Produce();
1317 }
1318
1319 /**
1320 * Will be called by the parser to get the buffer fill states of all disk
1321 * streams on a particular sampler channel.
1322 */
1323 String LSCPServer::GetBufferFill(fill_response_t ResponseType, uint uiSamplerChannel) {
1324 dmsg(2,("LSCPServer: GetBufferFill(ResponseType=%d, SamplerChannel=%d)\n", ResponseType, uiSamplerChannel));
1325 LSCPResultSet result;
1326 try {
1327 EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
1328 if (!pEngineChannel->GetEngine()) throw Exception("No audio output device connected to sampler channel");
1329 if (!pEngineChannel->GetEngine()->DiskStreamSupported()) result.Add("NA");
1330 else {
1331 switch (ResponseType) {
1332 case fill_response_bytes:
1333 result.Add(pEngineChannel->GetEngine()->DiskStreamBufferFillBytes());
1334 break;
1335 case fill_response_percentage:
1336 result.Add(pEngineChannel->GetEngine()->DiskStreamBufferFillPercentage());
1337 break;
1338 default:
1339 throw Exception("Unknown fill response type");
1340 }
1341 }
1342 }
1343 catch (Exception e) {
1344 result.Error(e);
1345 }
1346 return result.Produce();
1347 }
1348
1349 String LSCPServer::GetAvailableAudioOutputDrivers() {
1350 dmsg(2,("LSCPServer: GetAvailableAudioOutputDrivers()\n"));
1351 LSCPResultSet result;
1352 try {
1353 int n = AudioOutputDeviceFactory::AvailableDrivers().size();
1354 result.Add(n);
1355 }
1356 catch (Exception e) {
1357 result.Error(e);
1358 }
1359 return result.Produce();
1360 }
1361
1362 String LSCPServer::ListAvailableAudioOutputDrivers() {
1363 dmsg(2,("LSCPServer: ListAvailableAudioOutputDrivers()\n"));
1364 LSCPResultSet result;
1365 try {
1366 String s = AudioOutputDeviceFactory::AvailableDriversAsString();
1367 result.Add(s);
1368 }
1369 catch (Exception e) {
1370 result.Error(e);
1371 }
1372 return result.Produce();
1373 }
1374
1375 String LSCPServer::GetAvailableMidiInputDrivers() {
1376 dmsg(2,("LSCPServer: GetAvailableMidiInputDrivers()\n"));
1377 LSCPResultSet result;
1378 try {
1379 int n = MidiInputDeviceFactory::AvailableDrivers().size();
1380 result.Add(n);
1381 }
1382 catch (Exception e) {
1383 result.Error(e);
1384 }
1385 return result.Produce();
1386 }
1387
1388 String LSCPServer::ListAvailableMidiInputDrivers() {
1389 dmsg(2,("LSCPServer: ListAvailableMidiInputDrivers()\n"));
1390 LSCPResultSet result;
1391 try {
1392 String s = MidiInputDeviceFactory::AvailableDriversAsString();
1393 result.Add(s);
1394 }
1395 catch (Exception e) {
1396 result.Error(e);
1397 }
1398 return result.Produce();
1399 }
1400
1401 String LSCPServer::GetMidiInputDriverInfo(String Driver) {
1402 dmsg(2,("LSCPServer: GetMidiInputDriverInfo(Driver=%s)\n",Driver.c_str()));
1403 LSCPResultSet result;
1404 try {
1405 result.Add("DESCRIPTION", MidiInputDeviceFactory::GetDriverDescription(Driver));
1406 result.Add("VERSION", MidiInputDeviceFactory::GetDriverVersion(Driver));
1407
1408 std::map<String,DeviceCreationParameter*> parameters = MidiInputDeviceFactory::GetAvailableDriverParameters(Driver);
1409 if (parameters.size()) { // if there are parameters defined for this driver
1410 String s;
1411 std::map<String,DeviceCreationParameter*>::iterator iter = parameters.begin();
1412 for (;iter != parameters.end(); iter++) {
1413 if (s != "") s += ",";
1414 s += iter->first;
1415 delete iter->second;
1416 }
1417 result.Add("PARAMETERS", s);
1418 }
1419 }
1420 catch (Exception e) {
1421 result.Error(e);
1422 }
1423 return result.Produce();
1424 }
1425
1426 String LSCPServer::GetAudioOutputDriverInfo(String Driver) {
1427 dmsg(2,("LSCPServer: GetAudioOutputDriverInfo(Driver=%s)\n",Driver.c_str()));
1428 LSCPResultSet result;
1429 try {
1430 result.Add("DESCRIPTION", AudioOutputDeviceFactory::GetDriverDescription(Driver));
1431 result.Add("VERSION", AudioOutputDeviceFactory::GetDriverVersion(Driver));
1432
1433 std::map<String,DeviceCreationParameter*> parameters = AudioOutputDeviceFactory::GetAvailableDriverParameters(Driver);
1434 if (parameters.size()) { // if there are parameters defined for this driver
1435 String s;
1436 std::map<String,DeviceCreationParameter*>::iterator iter = parameters.begin();
1437 for (;iter != parameters.end(); iter++) {
1438 if (s != "") s += ",";
1439 s += iter->first;
1440 delete iter->second;
1441 }
1442 result.Add("PARAMETERS", s);
1443 }
1444 }
1445 catch (Exception e) {
1446 result.Error(e);
1447 }
1448 return result.Produce();
1449 }
1450
1451 String LSCPServer::GetMidiInputDriverParameterInfo(String Driver, String Parameter, std::map<String,String> DependencyList) {
1452 dmsg(2,("LSCPServer: GetMidiInputDriverParameterInfo(Driver=%s,Parameter=%s,DependencyListSize=%d)\n",Driver.c_str(),Parameter.c_str(),DependencyList.size()));
1453 LSCPResultSet result;
1454 try {
1455 DeviceCreationParameter* pParameter = MidiInputDeviceFactory::GetDriverParameter(Driver, Parameter);
1456 result.Add("TYPE", pParameter->Type());
1457 result.Add("DESCRIPTION", pParameter->Description());
1458 result.Add("MANDATORY", pParameter->Mandatory());
1459 result.Add("FIX", pParameter->Fix());
1460 result.Add("MULTIPLICITY", pParameter->Multiplicity());
1461 optional<String> oDepends = pParameter->Depends();
1462 optional<String> oDefault = pParameter->Default(DependencyList);
1463 optional<String> oRangeMin = pParameter->RangeMin(DependencyList);
1464 optional<String> oRangeMax = pParameter->RangeMax(DependencyList);
1465 optional<String> oPossibilities = pParameter->Possibilities(DependencyList);
1466 if (oDepends) result.Add("DEPENDS", *oDepends);
1467 if (oDefault) result.Add("DEFAULT", *oDefault);
1468 if (oRangeMin) result.Add("RANGE_MIN", *oRangeMin);
1469 if (oRangeMax) result.Add("RANGE_MAX", *oRangeMax);
1470 if (oPossibilities) result.Add("POSSIBILITIES", *oPossibilities);
1471 delete pParameter;
1472 }
1473 catch (Exception e) {
1474 result.Error(e);
1475 }
1476 return result.Produce();
1477 }
1478
1479 String LSCPServer::GetAudioOutputDriverParameterInfo(String Driver, String Parameter, std::map<String,String> DependencyList) {
1480 dmsg(2,("LSCPServer: GetAudioOutputDriverParameterInfo(Driver=%s,Parameter=%s,DependencyListSize=%d)\n",Driver.c_str(),Parameter.c_str(),DependencyList.size()));
1481 LSCPResultSet result;
1482 try {
1483 DeviceCreationParameter* pParameter = AudioOutputDeviceFactory::GetDriverParameter(Driver, Parameter);
1484 result.Add("TYPE", pParameter->Type());
1485 result.Add("DESCRIPTION", pParameter->Description());
1486 result.Add("MANDATORY", pParameter->Mandatory());
1487 result.Add("FIX", pParameter->Fix());
1488 result.Add("MULTIPLICITY", pParameter->Multiplicity());
1489 optional<String> oDepends = pParameter->Depends();
1490 optional<String> oDefault = pParameter->Default(DependencyList);
1491 optional<String> oRangeMin = pParameter->RangeMin(DependencyList);
1492 optional<String> oRangeMax = pParameter->RangeMax(DependencyList);
1493 optional<String> oPossibilities = pParameter->Possibilities(DependencyList);
1494 if (oDepends) result.Add("DEPENDS", *oDepends);
1495 if (oDefault) result.Add("DEFAULT", *oDefault);
1496 if (oRangeMin) result.Add("RANGE_MIN", *oRangeMin);
1497 if (oRangeMax) result.Add("RANGE_MAX", *oRangeMax);
1498 if (oPossibilities) result.Add("POSSIBILITIES", *oPossibilities);
1499 delete pParameter;
1500 }
1501 catch (Exception e) {
1502 result.Error(e);
1503 }
1504 return result.Produce();
1505 }
1506
1507 String LSCPServer::GetAudioOutputDeviceCount() {
1508 dmsg(2,("LSCPServer: GetAudioOutputDeviceCount()\n"));
1509 LSCPResultSet result;
1510 try {
1511 uint count = pSampler->AudioOutputDevices();
1512 result.Add(count); // success
1513 }
1514 catch (Exception e) {
1515 result.Error(e);
1516 }
1517 return result.Produce();
1518 }
1519
1520 String LSCPServer::GetMidiInputDeviceCount() {
1521 dmsg(2,("LSCPServer: GetMidiInputDeviceCount()\n"));
1522 LSCPResultSet result;
1523 try {
1524 uint count = pSampler->MidiInputDevices();
1525 result.Add(count); // success
1526 }
1527 catch (Exception e) {
1528 result.Error(e);
1529 }
1530 return result.Produce();
1531 }
1532
1533 String LSCPServer::GetAudioOutputDevices() {
1534 dmsg(2,("LSCPServer: GetAudioOutputDevices()\n"));
1535 LSCPResultSet result;
1536 try {
1537 String s;
1538 std::map<uint, AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
1539 std::map<uint, AudioOutputDevice*>::iterator iter = devices.begin();
1540 for (; iter != devices.end(); iter++) {
1541 if (s != "") s += ",";
1542 s += ToString(iter->first);
1543 }
1544 result.Add(s);
1545 }
1546 catch (Exception e) {
1547 result.Error(e);
1548 }
1549 return result.Produce();
1550 }
1551
1552 String LSCPServer::GetMidiInputDevices() {
1553 dmsg(2,("LSCPServer: GetMidiInputDevices()\n"));
1554 LSCPResultSet result;
1555 try {
1556 String s;
1557 std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
1558 std::map<uint, MidiInputDevice*>::iterator iter = devices.begin();
1559 for (; iter != devices.end(); iter++) {
1560 if (s != "") s += ",";
1561 s += ToString(iter->first);
1562 }
1563 result.Add(s);
1564 }
1565 catch (Exception e) {
1566 result.Error(e);
1567 }
1568 return result.Produce();
1569 }
1570
1571 String LSCPServer::GetAudioOutputDeviceInfo(uint DeviceIndex) {
1572 dmsg(2,("LSCPServer: GetAudioOutputDeviceInfo(DeviceIndex=%d)\n",DeviceIndex));
1573 LSCPResultSet result;
1574 try {
1575 std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
1576 if (!devices.count(DeviceIndex)) throw Exception("There is no audio output device with index " + ToString(DeviceIndex) + ".");
1577 AudioOutputDevice* pDevice = devices[DeviceIndex];
1578 result.Add("DRIVER", pDevice->Driver());
1579 std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();
1580 std::map<String,DeviceCreationParameter*>::iterator iter = parameters.begin();
1581 for (; iter != parameters.end(); iter++) {
1582 result.Add(iter->first, iter->second->Value());
1583 }
1584 }
1585 catch (Exception e) {
1586 result.Error(e);
1587 }
1588 return result.Produce();
1589 }
1590
1591 String LSCPServer::GetMidiInputDeviceInfo(uint DeviceIndex) {
1592 dmsg(2,("LSCPServer: GetMidiInputDeviceInfo(DeviceIndex=%d)\n",DeviceIndex));
1593 LSCPResultSet result;
1594 try {
1595 std::map<uint,MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
1596 if (!devices.count(DeviceIndex)) throw Exception("There is no MIDI input device with index " + ToString(DeviceIndex) + ".");
1597 MidiInputDevice* pDevice = devices[DeviceIndex];
1598 result.Add("DRIVER", pDevice->Driver());
1599 std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();
1600 std::map<String,DeviceCreationParameter*>::iterator iter = parameters.begin();
1601 for (; iter != parameters.end(); iter++) {
1602 result.Add(iter->first, iter->second->Value());
1603 }
1604 }
1605 catch (Exception e) {
1606 result.Error(e);
1607 }
1608 return result.Produce();
1609 }
1610 String LSCPServer::GetMidiInputPortInfo(uint DeviceIndex, uint PortIndex) {
1611 dmsg(2,("LSCPServer: GetMidiInputPortInfo(DeviceIndex=%d, PortIndex=%d)\n",DeviceIndex, PortIndex));
1612 LSCPResultSet result;
1613 try {
1614 // get MIDI input device
1615 std::map<uint,MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
1616 if (!devices.count(DeviceIndex)) throw Exception("There is no MIDI input device with index " + ToString(DeviceIndex) + ".");
1617 MidiInputDevice* pDevice = devices[DeviceIndex];
1618
1619 // get MIDI port
1620 MidiInputPort* pMidiInputPort = pDevice->GetPort(PortIndex);
1621 if (!pMidiInputPort) throw Exception("There is no MIDI input port with index " + ToString(PortIndex) + ".");
1622
1623 // return the values of all MIDI port parameters
1624 std::map<String,DeviceRuntimeParameter*> parameters = pMidiInputPort->PortParameters();
1625 std::map<String,DeviceRuntimeParameter*>::iterator iter = parameters.begin();
1626 for (; iter != parameters.end(); iter++) {
1627 result.Add(iter->first, iter->second->Value());
1628 }
1629 }
1630 catch (Exception e) {
1631 result.Error(e);
1632 }
1633 return result.Produce();
1634 }
1635
1636 String LSCPServer::GetAudioOutputChannelInfo(uint DeviceId, uint ChannelId) {
1637 dmsg(2,("LSCPServer: GetAudioOutputChannelInfo(DeviceId=%d,ChannelId)\n",DeviceId,ChannelId));
1638 LSCPResultSet result;
1639 try {
1640 // get audio output device
1641 std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
1642 if (!devices.count(DeviceId)) throw Exception("There is no audio output device with index " + ToString(DeviceId) + ".");
1643 AudioOutputDevice* pDevice = devices[DeviceId];
1644
1645 // get audio channel
1646 AudioChannel* pChannel = pDevice->Channel(ChannelId);
1647 if (!pChannel) throw Exception("Audio output device does not have audio channel " + ToString(ChannelId) + ".");
1648
1649 // return the values of all audio channel parameters
1650 std::map<String,DeviceRuntimeParameter*> parameters = pChannel->ChannelParameters();
1651 std::map<String,DeviceRuntimeParameter*>::iterator iter = parameters.begin();
1652 for (; iter != parameters.end(); iter++) {
1653 result.Add(iter->first, iter->second->Value());
1654 }
1655 }
1656 catch (Exception e) {
1657 result.Error(e);
1658 }
1659 return result.Produce();
1660 }
1661
1662 String LSCPServer::GetMidiInputPortParameterInfo(uint DeviceId, uint PortId, String ParameterName) {
1663 dmsg(2,("LSCPServer: GetMidiInputPortParameterInfo(DeviceId=%d,PortId=%d,ParameterName=%s)\n",DeviceId,PortId,ParameterName.c_str()));
1664 LSCPResultSet result;
1665 try {
1666 // get MIDI input device
1667 std::map<uint,MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
1668 if (!devices.count(DeviceId)) throw Exception("There is no midi input device with index " + ToString(DeviceId) + ".");
1669 MidiInputDevice* pDevice = devices[DeviceId];
1670
1671 // get midi port
1672 MidiInputPort* pPort = pDevice->GetPort(PortId);
1673 if (!pPort) throw Exception("Midi input device does not have port " + ToString(PortId) + ".");
1674
1675 // get desired port parameter
1676 std::map<String,DeviceRuntimeParameter*> parameters = pPort->PortParameters();
1677 if (!parameters.count(ParameterName)) throw Exception("Midi port does not provide a parameter '" + ParameterName + "'.");
1678 DeviceRuntimeParameter* pParameter = parameters[ParameterName];
1679
1680 // return all fields of this audio channel parameter
1681 result.Add("TYPE", pParameter->Type());
1682 result.Add("DESCRIPTION", pParameter->Description());
1683 result.Add("FIX", pParameter->Fix());
1684 result.Add("MULTIPLICITY", pParameter->Multiplicity());
1685 if (pParameter->RangeMin()) result.Add("RANGE_MIN", *pParameter->RangeMin());
1686 if (pParameter->RangeMax()) result.Add("RANGE_MAX", *pParameter->RangeMax());
1687 if (pParameter->Possibilities()) result.Add("POSSIBILITIES", *pParameter->Possibilities());
1688 }
1689 catch (Exception e) {
1690 result.Error(e);
1691 }
1692 return result.Produce();
1693 }
1694
1695 String LSCPServer::GetAudioOutputChannelParameterInfo(uint DeviceId, uint ChannelId, String ParameterName) {
1696 dmsg(2,("LSCPServer: GetAudioOutputChannelParameterInfo(DeviceId=%d,ChannelId=%d,ParameterName=%s)\n",DeviceId,ChannelId,ParameterName.c_str()));
1697 LSCPResultSet result;
1698 try {
1699 // get audio output device
1700 std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
1701 if (!devices.count(DeviceId)) throw Exception("There is no audio output device with index " + ToString(DeviceId) + ".");
1702 AudioOutputDevice* pDevice = devices[DeviceId];
1703
1704 // get audio channel
1705 AudioChannel* pChannel = pDevice->Channel(ChannelId);
1706 if (!pChannel) throw Exception("Audio output device does not have audio channel " + ToString(ChannelId) + ".");
1707
1708 // get desired audio channel parameter
1709 std::map<String,DeviceRuntimeParameter*> parameters = pChannel->ChannelParameters();
1710 if (!parameters.count(ParameterName)) throw Exception("Audio channel does not provide a parameter '" + ParameterName + "'.");
1711 DeviceRuntimeParameter* pParameter = parameters[ParameterName];
1712
1713 // return all fields of this audio channel parameter
1714 result.Add("TYPE", pParameter->Type());
1715 result.Add("DESCRIPTION", pParameter->Description());
1716 result.Add("FIX", pParameter->Fix());
1717 result.Add("MULTIPLICITY", pParameter->Multiplicity());
1718 if (pParameter->RangeMin()) result.Add("RANGE_MIN", *pParameter->RangeMin());
1719 if (pParameter->RangeMax()) result.Add("RANGE_MAX", *pParameter->RangeMax());
1720 if (pParameter->Possibilities()) result.Add("POSSIBILITIES", *pParameter->Possibilities());
1721 }
1722 catch (Exception e) {
1723 result.Error(e);
1724 }
1725 return result.Produce();
1726 }
1727
1728 String LSCPServer::SetAudioOutputChannelParameter(uint DeviceId, uint ChannelId, String ParamKey, String ParamVal) {
1729 dmsg(2,("LSCPServer: SetAudioOutputChannelParameter(DeviceId=%d,ChannelId=%d,ParamKey=%s,ParamVal=%s)\n",DeviceId,ChannelId,ParamKey.c_str(),ParamVal.c_str()));
1730 LSCPResultSet result;
1731 try {
1732 // get audio output device
1733 std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
1734 if (!devices.count(DeviceId)) throw Exception("There is no audio output device with index " + ToString(DeviceId) + ".");
1735 AudioOutputDevice* pDevice = devices[DeviceId];
1736
1737 // get audio channel
1738 AudioChannel* pChannel = pDevice->Channel(ChannelId);
1739 if (!pChannel) throw Exception("Audio output device does not have audio channel " + ToString(ChannelId) + ".");
1740
1741 // get desired audio channel parameter
1742 std::map<String,DeviceRuntimeParameter*> parameters = pChannel->ChannelParameters();
1743 if (!parameters.count(ParamKey)) throw Exception("Audio channel does not provide a parameter '" + ParamKey + "'.");
1744 DeviceRuntimeParameter* pParameter = parameters[ParamKey];
1745
1746 // set new channel parameter value
1747 pParameter->SetValue(ParamVal);
1748 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_audio_device_info, DeviceId));
1749 }
1750 catch (Exception e) {
1751 result.Error(e);
1752 }
1753 return result.Produce();
1754 }
1755
1756 String LSCPServer::SetAudioOutputDeviceParameter(uint DeviceIndex, String ParamKey, String ParamVal) {
1757 dmsg(2,("LSCPServer: SetAudioOutputDeviceParameter(DeviceIndex=%d,ParamKey=%s,ParamVal=%s)\n",DeviceIndex,ParamKey.c_str(),ParamVal.c_str()));
1758 LSCPResultSet result;
1759 try {
1760 std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
1761 if (!devices.count(DeviceIndex)) throw Exception("There is no audio output device with index " + ToString(DeviceIndex) + ".");
1762 AudioOutputDevice* pDevice = devices[DeviceIndex];
1763 std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();
1764 if (!parameters.count(ParamKey)) throw Exception("Audio output device " + ToString(DeviceIndex) + " does not have a device parameter '" + ParamKey + "'");
1765 parameters[ParamKey]->SetValue(ParamVal);
1766 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_audio_device_info, DeviceIndex));
1767 }
1768 catch (Exception e) {
1769 result.Error(e);
1770 }
1771 return result.Produce();
1772 }
1773
1774 String LSCPServer::SetMidiInputDeviceParameter(uint DeviceIndex, String ParamKey, String ParamVal) {
1775 dmsg(2,("LSCPServer: SetMidiOutputDeviceParameter(DeviceIndex=%d,ParamKey=%s,ParamVal=%s)\n",DeviceIndex,ParamKey.c_str(),ParamVal.c_str()));
1776 LSCPResultSet result;
1777 try {
1778 std::map<uint,MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
1779 if (!devices.count(DeviceIndex)) throw Exception("There is no MIDI input device with index " + ToString(DeviceIndex) + ".");
1780 MidiInputDevice* pDevice = devices[DeviceIndex];
1781 std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();
1782 if (!parameters.count(ParamKey)) throw Exception("MIDI input device " + ToString(DeviceIndex) + " does not have a device parameter '" + ParamKey + "'");
1783 parameters[ParamKey]->SetValue(ParamVal);
1784 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_device_info, DeviceIndex));
1785 }
1786 catch (Exception e) {
1787 result.Error(e);
1788 }
1789 return result.Produce();
1790 }
1791
1792 String LSCPServer::SetMidiInputPortParameter(uint DeviceIndex, uint PortIndex, String ParamKey, String ParamVal) {
1793 dmsg(2,("LSCPServer: SetMidiOutputDeviceParameter(DeviceIndex=%d,ParamKey=%s,ParamVal=%s)\n",DeviceIndex,ParamKey.c_str(),ParamVal.c_str()));
1794 LSCPResultSet result;
1795 try {
1796 // get MIDI input device
1797 std::map<uint,MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
1798 if (!devices.count(DeviceIndex)) throw Exception("There is no MIDI input device with index " + ToString(DeviceIndex) + ".");
1799 MidiInputDevice* pDevice = devices[DeviceIndex];
1800
1801 // get MIDI port
1802 MidiInputPort* pMidiInputPort = pDevice->GetPort(PortIndex);
1803 if (!pMidiInputPort) throw Exception("There is no MIDI input port with index " + ToString(PortIndex) + ".");
1804
1805 // set port parameter value
1806 std::map<String,DeviceRuntimeParameter*> parameters = pMidiInputPort->PortParameters();
1807 if (!parameters.count(ParamKey)) throw Exception("MIDI input device " + ToString(PortIndex) + " does not have a parameter '" + ParamKey + "'");
1808 parameters[ParamKey]->SetValue(ParamVal);
1809 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_device_info, DeviceIndex));
1810 }
1811 catch (Exception e) {
1812 result.Error(e);
1813 }
1814 return result.Produce();
1815 }
1816
1817 /**
1818 * Will be called by the parser to change the audio output channel for
1819 * playback on a particular sampler channel.
1820 */
1821 String LSCPServer::SetAudioOutputChannel(uint ChannelAudioOutputChannel, uint AudioOutputDeviceInputChannel, uint uiSamplerChannel) {
1822 dmsg(2,("LSCPServer: SetAudioOutputChannel(ChannelAudioOutputChannel=%d, AudioOutputDeviceInputChannel=%d, SamplerChannel=%d)\n",ChannelAudioOutputChannel,AudioOutputDeviceInputChannel,uiSamplerChannel));
1823 LSCPResultSet result;
1824 try {
1825 SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1826 if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1827 EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();
1828 if (!pEngineChannel) throw Exception("No engine type yet assigned to sampler channel " + ToString(uiSamplerChannel));
1829 if (!pSamplerChannel->GetAudioOutputDevice()) throw Exception("No audio output device connected to sampler channel " + ToString(uiSamplerChannel));
1830 pEngineChannel->SetOutputChannel(ChannelAudioOutputChannel, AudioOutputDeviceInputChannel);
1831 }
1832 catch (Exception e) {
1833 result.Error(e);
1834 }
1835 return result.Produce();
1836 }
1837
1838 String LSCPServer::SetAudioOutputDevice(uint AudioDeviceId, uint uiSamplerChannel) {
1839 dmsg(2,("LSCPServer: SetAudiotOutputDevice(AudioDeviceId=%d, SamplerChannel=%d)\n",AudioDeviceId,uiSamplerChannel));
1840 LSCPResultSet result;
1841 {
1842 LockGuard lock(RTNotifyMutex);
1843 try {
1844 SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1845 if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1846 std::map<uint, AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
1847 if (!devices.count(AudioDeviceId)) throw Exception("There is no audio output device with index " + ToString(AudioDeviceId));
1848 AudioOutputDevice* pDevice = devices[AudioDeviceId];
1849 pSamplerChannel->SetAudioOutputDevice(pDevice);
1850 }
1851 catch (Exception e) {
1852 result.Error(e);
1853 }
1854 }
1855 return result.Produce();
1856 }
1857
1858 String LSCPServer::SetAudioOutputType(String AudioOutputDriver, uint uiSamplerChannel) {
1859 dmsg(2,("LSCPServer: SetAudioOutputType(String AudioOutputDriver=%s, SamplerChannel=%d)\n",AudioOutputDriver.c_str(),uiSamplerChannel));
1860 LSCPResultSet result;
1861 {
1862 LockGuard lock(RTNotifyMutex);
1863 try {
1864 SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1865 if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1866 // Driver type name aliasing...
1867 if (AudioOutputDriver == "Alsa") AudioOutputDriver = "ALSA";
1868 if (AudioOutputDriver == "Jack") AudioOutputDriver = "JACK";
1869 // Check if there's one audio output device already created
1870 // for the intended audio driver type (AudioOutputDriver)...
1871 AudioOutputDevice *pDevice = NULL;
1872 std::map<uint, AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
1873 std::map<uint, AudioOutputDevice*>::iterator iter = devices.begin();
1874 for (; iter != devices.end(); iter++) {
1875 if ((iter->second)->Driver() == AudioOutputDriver) {
1876 pDevice = iter->second;
1877 break;
1878 }
1879 }
1880 // If it doesn't exist, create a new one with default parameters...
1881 if (pDevice == NULL) {
1882 std::map<String,String> params;
1883 pDevice = pSampler->CreateAudioOutputDevice(AudioOutputDriver, params);
1884 }
1885 // Must have a device...
1886 if (pDevice == NULL)
1887 throw Exception("Internal error: could not create audio output device.");
1888 // Set it as the current channel device...
1889 pSamplerChannel->SetAudioOutputDevice(pDevice);
1890 }
1891 catch (Exception e) {
1892 result.Error(e);
1893 }
1894 }
1895 return result.Produce();
1896 }
1897
1898 String LSCPServer::AddChannelMidiInput(uint uiSamplerChannel, uint MIDIDeviceId, uint MIDIPort) {
1899 dmsg(2,("LSCPServer: AddChannelMidiInput(uiSamplerChannel=%d, MIDIDeviceId=%d, MIDIPort=%d)\n",uiSamplerChannel,MIDIDeviceId,MIDIPort));
1900 LSCPResultSet result;
1901 try {
1902 SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1903 if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1904
1905 std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
1906 if (!devices.count(MIDIDeviceId)) throw Exception("There is no MIDI input device with index " + ToString(MIDIDeviceId));
1907 MidiInputDevice* pDevice = devices[MIDIDeviceId];
1908
1909 MidiInputPort* pPort = pDevice->GetPort(MIDIPort);
1910 if (!pPort) throw Exception("There is no MIDI input port with index " + ToString(MIDIPort) + " on MIDI input device with index " + ToString(MIDIDeviceId));
1911
1912 pSamplerChannel->Connect(pPort);
1913 } catch (Exception e) {
1914 result.Error(e);
1915 }
1916 return result.Produce();
1917 }
1918
1919 String LSCPServer::RemoveChannelMidiInput(uint uiSamplerChannel) {
1920 dmsg(2,("LSCPServer: RemoveChannelMidiInput(uiSamplerChannel=%d)\n",uiSamplerChannel));
1921 LSCPResultSet result;
1922 try {
1923 SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1924 if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1925 pSamplerChannel->DisconnectAllMidiInputPorts();
1926 } catch (Exception e) {
1927 result.Error(e);
1928 }
1929 return result.Produce();
1930 }
1931
1932 String LSCPServer::RemoveChannelMidiInput(uint uiSamplerChannel, uint MIDIDeviceId) {
1933 dmsg(2,("LSCPServer: RemoveChannelMidiInput(uiSamplerChannel=%d, MIDIDeviceId=%d)\n",uiSamplerChannel,MIDIDeviceId));
1934 LSCPResultSet result;
1935 try {
1936 SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1937 if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1938
1939 std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
1940 if (!devices.count(MIDIDeviceId)) throw Exception("There is no MIDI input device with index " + ToString(MIDIDeviceId));
1941 MidiInputDevice* pDevice = devices[MIDIDeviceId];
1942
1943 std::vector<MidiInputPort*> vPorts = pSamplerChannel->GetMidiInputPorts();
1944 for (int i = 0; i < vPorts.size(); ++i)
1945 if (vPorts[i]->GetDevice() == pDevice)
1946 pSamplerChannel->Disconnect(vPorts[i]);
1947
1948 } catch (Exception e) {
1949 result.Error(e);
1950 }
1951 return result.Produce();
1952 }
1953
1954 String LSCPServer::RemoveChannelMidiInput(uint uiSamplerChannel, uint MIDIDeviceId, uint MIDIPort) {
1955 dmsg(2,("LSCPServer: RemoveChannelMidiInput(uiSamplerChannel=%d, MIDIDeviceId=%d, MIDIPort=%d)\n",uiSamplerChannel,MIDIDeviceId,MIDIPort));
1956 LSCPResultSet result;
1957 try {
1958 SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1959 if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1960
1961 std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
1962 if (!devices.count(MIDIDeviceId)) throw Exception("There is no MIDI input device with index " + ToString(MIDIDeviceId));
1963 MidiInputDevice* pDevice = devices[MIDIDeviceId];
1964
1965 MidiInputPort* pPort = pDevice->GetPort(MIDIPort);
1966 if (!pPort) throw Exception("There is no MIDI input port with index " + ToString(MIDIPort) + " on MIDI input device with index " + ToString(MIDIDeviceId));
1967
1968 pSamplerChannel->Disconnect(pPort);
1969 } catch (Exception e) {
1970 result.Error(e);
1971 }
1972 return result.Produce();
1973 }
1974
1975 String LSCPServer::ListChannelMidiInputs(uint uiSamplerChannel) {
1976 dmsg(2,("LSCPServer: ListChannelMidiInputs(uiSamplerChannel=%d)\n",uiSamplerChannel));
1977 LSCPResultSet result;
1978 try {
1979 SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1980 if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1981 std::vector<MidiInputPort*> vPorts = pSamplerChannel->GetMidiInputPorts();
1982
1983 String s;
1984 for (int i = 0; i < vPorts.size(); ++i) {
1985 const int iDeviceID = vPorts[i]->GetDevice()->MidiInputDeviceID();
1986 const int iPortNr = vPorts[i]->GetPortNumber();
1987 if (s.size()) s += ",";
1988 s += "{" + ToString(iDeviceID) + ","
1989 + ToString(iPortNr) + "}";
1990 }
1991 result.Add(s);
1992 } catch (Exception e) {
1993 result.Error(e);
1994 }
1995 return result.Produce();
1996 }
1997
1998 String LSCPServer::SetMIDIInputPort(uint MIDIPort, uint uiSamplerChannel) {
1999 dmsg(2,("LSCPServer: SetMIDIInputPort(MIDIPort=%d, SamplerChannel=%d)\n",MIDIPort,uiSamplerChannel));
2000 LSCPResultSet result;
2001 try {
2002 SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
2003 if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
2004 pSamplerChannel->SetMidiInputPort(MIDIPort);
2005 }
2006 catch (Exception e) {
2007 result.Error(e);
2008 }
2009 return result.Produce();
2010 }
2011
2012 String LSCPServer::SetMIDIInputChannel(uint MIDIChannel, uint uiSamplerChannel) {
2013 dmsg(2,("LSCPServer: SetMIDIInputChannel(MIDIChannel=%d, SamplerChannel=%d)\n",MIDIChannel,uiSamplerChannel));
2014 LSCPResultSet result;
2015 try {
2016 SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
2017 if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
2018 pSamplerChannel->SetMidiInputChannel((midi_chan_t) MIDIChannel);
2019 }
2020 catch (Exception e) {
2021 result.Error(e);
2022 }
2023 return result.Produce();
2024 }
2025
2026 String LSCPServer::SetMIDIInputDevice(uint MIDIDeviceId, uint uiSamplerChannel) {
2027 dmsg(2,("LSCPServer: SetMIDIInputDevice(MIDIDeviceId=%d, SamplerChannel=%d)\n",MIDIDeviceId,uiSamplerChannel));
2028 LSCPResultSet result;
2029 try {
2030 SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
2031 if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
2032 std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
2033 if (!devices.count(MIDIDeviceId)) throw Exception("There is no MIDI input device with index " + ToString(MIDIDeviceId));
2034 MidiInputDevice* pDevice = devices[MIDIDeviceId];
2035 pSamplerChannel->SetMidiInputDevice(pDevice);
2036 }
2037 catch (Exception e) {
2038 result.Error(e);
2039 }
2040 return result.Produce();
2041 }
2042
2043 String LSCPServer::SetMIDIInputType(String MidiInputDriver, uint uiSamplerChannel) {
2044 dmsg(2,("LSCPServer: SetMIDIInputType(String MidiInputDriver=%s, SamplerChannel=%d)\n",MidiInputDriver.c_str(),uiSamplerChannel));
2045 LSCPResultSet result;
2046 try {
2047 SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
2048 if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
2049 // Driver type name aliasing...
2050 if (MidiInputDriver == "Alsa") MidiInputDriver = "ALSA";
2051 // Check if there's one MIDI input device already created
2052 // for the intended MIDI driver type (MidiInputDriver)...
2053 MidiInputDevice *pDevice = NULL;
2054 std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
2055 std::map<uint, MidiInputDevice*>::iterator iter = devices.begin();
2056 for (; iter != devices.end(); iter++) {
2057 if ((iter->second)->Driver() == MidiInputDriver) {
2058 pDevice = iter->second;
2059 break;
2060 }
2061 }
2062 // If it doesn't exist, create a new one with default parameters...
2063 if (pDevice == NULL) {
2064 std::map<String,String> params;
2065 pDevice = pSampler->CreateMidiInputDevice(MidiInputDriver, params);
2066 // Make it with at least one initial port.
2067 std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();
2068 }
2069 // Must have a device...
2070 if (pDevice == NULL)
2071 throw Exception("Internal error: could not create MIDI input device.");
2072 // Set it as the current channel device...
2073 pSamplerChannel->SetMidiInputDevice(pDevice);
2074 }
2075 catch (Exception e) {
2076 result.Error(e);
2077 }
2078 return result.Produce();
2079 }
2080
2081 /**
2082 * Will be called by the parser to change the MIDI input device, port and channel on which
2083 * engine of a particular sampler channel should listen to.
2084 */
2085 String LSCPServer::SetMIDIInput(uint MIDIDeviceId, uint MIDIPort, uint MIDIChannel, uint uiSamplerChannel) {
2086 dmsg(2,("LSCPServer: SetMIDIInput(MIDIDeviceId=%d, MIDIPort=%d, MIDIChannel=%d, SamplerChannel=%d)\n", MIDIDeviceId, MIDIPort, MIDIChannel, uiSamplerChannel));
2087 LSCPResultSet result;
2088 try {
2089 SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
2090 if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
2091 std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
2092 if (!devices.count(MIDIDeviceId)) throw Exception("There is no MIDI input device with index " + ToString(MIDIDeviceId));
2093 MidiInputDevice* pDevice = devices[MIDIDeviceId];
2094 pSamplerChannel->SetMidiInput(pDevice, MIDIPort, (midi_chan_t) MIDIChannel);
2095 }
2096 catch (Exception e) {
2097 result.Error(e);
2098 }
2099 return result.Produce();
2100 }
2101
2102 /**
2103 * Will be called by the parser to change the global volume factor on a
2104 * particular sampler channel.
2105 */
2106 String LSCPServer::SetVolume(double dVolume, uint uiSamplerChannel) {
2107 dmsg(2,("LSCPServer: SetVolume(Volume=%f, SamplerChannel=%d)\n", dVolume, uiSamplerChannel));
2108 LSCPResultSet result;
2109 try {
2110 EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2111 pEngineChannel->Volume(dVolume);
2112 }
2113 catch (Exception e) {
2114 result.Error(e);
2115 }
2116 return result.Produce();
2117 }
2118
2119 /**
2120 * Will be called by the parser to mute/unmute particular sampler channel.
2121 */
2122 String LSCPServer::SetChannelMute(bool bMute, uint uiSamplerChannel) {
2123 dmsg(2,("LSCPServer: SetChannelMute(bMute=%d,uiSamplerChannel=%d)\n",bMute,uiSamplerChannel));
2124 LSCPResultSet result;
2125 try {
2126 EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2127
2128 if(!bMute) pEngineChannel->SetMute((HasSoloChannel() && !pEngineChannel->GetSolo()) ? -1 : 0);
2129 else pEngineChannel->SetMute(1);
2130 } catch (Exception e) {
2131 result.Error(e);
2132 }
2133 return result.Produce();
2134 }
2135
2136 /**
2137 * Will be called by the parser to solo particular sampler channel.
2138 */
2139 String LSCPServer::SetChannelSolo(bool bSolo, uint uiSamplerChannel) {
2140 dmsg(2,("LSCPServer: SetChannelSolo(bSolo=%d,uiSamplerChannel=%d)\n",bSolo,uiSamplerChannel));
2141 LSCPResultSet result;
2142 try {
2143 EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2144
2145 bool oldSolo = pEngineChannel->GetSolo();
2146 bool hadSoloChannel = HasSoloChannel();
2147
2148 pEngineChannel->SetSolo(bSolo);
2149
2150 if(!oldSolo && bSolo) {
2151 if(pEngineChannel->GetMute() == -1) pEngineChannel->SetMute(0);
2152 if(!hadSoloChannel) MuteNonSoloChannels();
2153 }
2154
2155 if(oldSolo && !bSolo) {
2156 if(!HasSoloChannel()) UnmuteChannels();
2157 else if(!pEngineChannel->GetMute()) pEngineChannel->SetMute(-1);
2158 }
2159 } catch (Exception e) {
2160 result.Error(e);
2161 }
2162 return result.Produce();
2163 }
2164
2165 /**
2166 * Determines whether there is at least one solo channel in the channel list.
2167 *
2168 * @returns true if there is at least one solo channel in the channel list,
2169 * false otherwise.
2170 */
2171 bool LSCPServer::HasSoloChannel() {
2172 std::map<uint,SamplerChannel*> channels = pSampler->GetSamplerChannels();
2173 std::map<uint,SamplerChannel*>::iterator iter = channels.begin();
2174 for (; iter != channels.end(); iter++) {
2175 EngineChannel* c = iter->second->GetEngineChannel();
2176 if(c && c->GetSolo()) return true;
2177 }
2178
2179 return false;
2180 }
2181
2182 /**
2183 * Mutes all unmuted non-solo channels. Notice that the channels are muted
2184 * with -1 which indicates that they are muted because of the presence
2185 * of a solo channel(s). Channels muted with -1 will be automatically unmuted
2186 * when there are no solo channels left.
2187 */
2188 void LSCPServer::MuteNonSoloChannels() {
2189 dmsg(2,("LSCPServer: MuteNonSoloChannels()\n"));
2190 std::map<uint,SamplerChannel*> channels = pSampler->GetSamplerChannels();
2191 std::map<uint,SamplerChannel*>::iterator iter = channels.begin();
2192 for (; iter != channels.end(); iter++) {
2193 EngineChannel* c = iter->second->GetEngineChannel();
2194 if(c && !c->GetSolo() && !c->GetMute()) c->SetMute(-1);
2195 }
2196 }
2197
2198 /**
2199 * Unmutes all channels that are muted because of the presence
2200 * of a solo channel(s).
2201 */
2202 void LSCPServer::UnmuteChannels() {
2203 dmsg(2,("LSCPServer: UnmuteChannels()\n"));
2204 std::map<uint,SamplerChannel*> channels = pSampler->GetSamplerChannels();
2205 std::map<uint,SamplerChannel*>::iterator iter = channels.begin();
2206 for (; iter != channels.end(); iter++) {
2207 EngineChannel* c = iter->second->GetEngineChannel();
2208 if(c && c->GetMute() == -1) c->SetMute(0);
2209 }
2210 }
2211
2212 String LSCPServer::AddOrReplaceMIDIInstrumentMapping(uint MidiMapID, uint MidiBank, uint MidiProg, String EngineType, String InstrumentFile, uint InstrumentIndex, float Volume, MidiInstrumentMapper::mode_t LoadMode, String Name, bool bModal) {
2213 dmsg(2,("LSCPServer: AddOrReplaceMIDIInstrumentMapping()\n"));
2214
2215 midi_prog_index_t idx;
2216 idx.midi_bank_msb = (MidiBank >> 7) & 0x7f;
2217 idx.midi_bank_lsb = MidiBank & 0x7f;
2218 idx.midi_prog = MidiProg;
2219
2220 MidiInstrumentMapper::entry_t entry;
2221 entry.EngineName = EngineType;
2222 entry.InstrumentFile = InstrumentFile;
2223 entry.InstrumentIndex = InstrumentIndex;
2224 entry.LoadMode = LoadMode;
2225 entry.Volume = Volume;
2226 entry.Name = Name;
2227
2228 LSCPResultSet result;
2229 try {
2230 // PERSISTENT mapping commands might block for a long time, so in
2231 // that case we add/replace the mapping in another thread in case
2232 // the NON_MODAL argument was supplied, non persistent mappings
2233 // should return immediately, so we don't need to do that for them
2234 bool bInBackground = (entry.LoadMode == MidiInstrumentMapper::PERSISTENT && !bModal);
2235 MidiInstrumentMapper::AddOrReplaceEntry(MidiMapID, idx, entry, bInBackground);
2236 } catch (Exception e) {
2237 result.Error(e);
2238 }
2239 return result.Produce();
2240 }
2241
2242 String LSCPServer::RemoveMIDIInstrumentMapping(uint MidiMapID, uint MidiBank, uint MidiProg) {
2243 dmsg(2,("LSCPServer: RemoveMIDIInstrumentMapping()\n"));
2244
2245 midi_prog_index_t idx;
2246 idx.midi_bank_msb = (MidiBank >> 7) & 0x7f;
2247 idx.midi_bank_lsb = MidiBank & 0x7f;
2248 idx.midi_prog = MidiProg;
2249
2250 LSCPResultSet result;
2251 try {
2252 MidiInstrumentMapper::RemoveEntry(MidiMapID, idx);
2253 } catch (Exception e) {
2254 result.Error(e);
2255 }
2256 return result.Produce();
2257 }
2258
2259 String LSCPServer::GetMidiInstrumentMappings(uint MidiMapID) {
2260 dmsg(2,("LSCPServer: GetMidiInstrumentMappings()\n"));
2261 LSCPResultSet result;
2262 try {
2263 result.Add(MidiInstrumentMapper::GetInstrumentCount(MidiMapID));
2264 } catch (Exception e) {
2265 result.Error(e);
2266 }
2267 return result.Produce();
2268 }
2269
2270
2271 String LSCPServer::GetAllMidiInstrumentMappings() {
2272 dmsg(2,("LSCPServer: GetAllMidiInstrumentMappings()\n"));
2273 LSCPResultSet result;
2274 try {
2275 result.Add(MidiInstrumentMapper::GetInstrumentCount());
2276 } catch (Exception e) {
2277 result.Error(e);
2278 }
2279 return result.Produce();
2280 }
2281
2282 String LSCPServer::GetMidiInstrumentMapping(uint MidiMapID, uint MidiBank, uint MidiProg) {
2283 dmsg(2,("LSCPServer: GetMidiIstrumentMapping()\n"));
2284 LSCPResultSet result;
2285 try {
2286 MidiInstrumentMapper::entry_t entry = MidiInstrumentMapper::GetEntry(MidiMapID, MidiBank, MidiProg);
2287 // convert the filename into the correct encoding as defined for LSCP
2288 // (especially in terms of special characters -> escape sequences)
2289 #if WIN32
2290 const String instrumentFileName = Path::fromWindows(entry.InstrumentFile).toLscp();
2291 #else
2292 // assuming POSIX
2293 const String instrumentFileName = Path::fromPosix(entry.InstrumentFile).toLscp();
2294 #endif
2295
2296 result.Add("NAME", _escapeLscpResponse(entry.Name));
2297 result.Add("ENGINE_NAME", entry.EngineName);
2298 result.Add("INSTRUMENT_FILE", instrumentFileName);
2299 result.Add("INSTRUMENT_NR", (int) entry.InstrumentIndex);
2300 String instrumentName;
2301 Engine* pEngine = EngineFactory::Create(entry.EngineName);
2302 if (pEngine) {
2303 if (pEngine->GetInstrumentManager()) {
2304 InstrumentManager::instrument_id_t instrID;
2305 instrID.FileName = entry.InstrumentFile;
2306 instrID.Index = entry.InstrumentIndex;
2307 instrumentName = pEngine->GetInstrumentManager()->GetInstrumentName(instrID);
2308 }
2309 EngineFactory::Destroy(pEngine);
2310 }
2311 result.Add("INSTRUMENT_NAME", _escapeLscpResponse(instrumentName));
2312 switch (entry.LoadMode) {
2313 case MidiInstrumentMapper::ON_DEMAND:
2314 result.Add("LOAD_MODE", "ON_DEMAND");
2315 break;
2316 case MidiInstrumentMapper::ON_DEMAND_HOLD:
2317 result.Add("LOAD_MODE", "ON_DEMAND_HOLD");
2318 break;
2319 case MidiInstrumentMapper::PERSISTENT:
2320 result.Add("LOAD_MODE", "PERSISTENT");
2321 break;
2322 default:
2323 throw Exception("entry reflects invalid LOAD_MODE, consider this as a bug!");
2324 }
2325 result.Add("VOLUME", entry.Volume);
2326 } catch (Exception e) {
2327 result.Error(e);
2328 }
2329 return result.Produce();
2330 }
2331
2332 String LSCPServer::ListMidiInstrumentMappings(uint MidiMapID) {
2333 dmsg(2,("LSCPServer: ListMidiInstrumentMappings()\n"));
2334 LSCPResultSet result;
2335 try {
2336 String s;
2337 std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t> mappings = MidiInstrumentMapper::Entries(MidiMapID);
2338 std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t>::iterator iter = mappings.begin();
2339 for (; iter != mappings.end(); iter++) {
2340 if (s.size()) s += ",";
2341 s += "{" + ToString(MidiMapID) + ","
2342 + ToString((int(iter->first.midi_bank_msb) << 7) | int(iter->first.midi_bank_lsb)) + ","
2343 + ToString(int(iter->first.midi_prog)) + "}";
2344 }
2345 result.Add(s);
2346 } catch (Exception e) {
2347 result.Error(e);
2348 }
2349 return result.Produce();
2350 }
2351
2352 String LSCPServer::ListAllMidiInstrumentMappings() {
2353 dmsg(2,("LSCPServer: ListAllMidiInstrumentMappings()\n"));
2354 LSCPResultSet result;
2355 try {
2356 std::vector<int> maps = MidiInstrumentMapper::Maps();
2357 String s;
2358 for (int i = 0; i < maps.size(); i++) {
2359 std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t> mappings = MidiInstrumentMapper::Entries(maps[i]);
2360 std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t>::iterator iter = mappings.begin();
2361 for (; iter != mappings.end(); iter++) {
2362 if (s.size()) s += ",";
2363 s += "{" + ToString(maps[i]) + ","
2364 + ToString((int(iter->first.midi_bank_msb) << 7) | int(iter->first.midi_bank_lsb)) + ","
2365 + ToString(int(iter->first.midi_prog)) + "}";
2366 }
2367 }
2368 result.Add(s);
2369 } catch (Exception e) {
2370 result.Error(e);
2371 }
2372 return result.Produce();
2373 }
2374
2375 String LSCPServer::ClearMidiInstrumentMappings(uint MidiMapID) {
2376 dmsg(2,("LSCPServer: ClearMidiInstrumentMappings()\n"));
2377 LSCPResultSet result;
2378 try {
2379 MidiInstrumentMapper::RemoveAllEntries(MidiMapID);
2380 } catch (Exception e) {
2381 result.Error(e);
2382 }
2383 return result.Produce();
2384 }
2385
2386 String LSCPServer::ClearAllMidiInstrumentMappings() {
2387 dmsg(2,("LSCPServer: ClearAllMidiInstrumentMappings()\n"));
2388 LSCPResultSet result;
2389 try {
2390 std::vector<int> maps = MidiInstrumentMapper::Maps();
2391 for (int i = 0; i < maps.size(); i++)
2392 MidiInstrumentMapper::RemoveAllEntries(maps[i]);
2393 } catch (Exception e) {
2394 result.Error(e);
2395 }
2396 return result.Produce();
2397 }
2398
2399 String LSCPServer::AddMidiInstrumentMap(String MapName) {
2400 dmsg(2,("LSCPServer: AddMidiInstrumentMap()\n"));
2401 LSCPResultSet result;
2402 try {
2403 int MapID = MidiInstrumentMapper::AddMap(MapName);
2404 result = LSCPResultSet(MapID);
2405 } catch (Exception e) {
2406 result.Error(e);
2407 }
2408 return result.Produce();
2409 }
2410
2411 String LSCPServer::RemoveMidiInstrumentMap(uint MidiMapID) {
2412 dmsg(2,("LSCPServer: RemoveMidiInstrumentMap()\n"));
2413 LSCPResultSet result;
2414 try {
2415 MidiInstrumentMapper::RemoveMap(MidiMapID);
2416 } catch (Exception e) {
2417 result.Error(e);
2418 }
2419 return result.Produce();
2420 }
2421
2422 String LSCPServer::RemoveAllMidiInstrumentMaps() {
2423 dmsg(2,("LSCPServer: RemoveAllMidiInstrumentMaps()\n"));
2424 LSCPResultSet result;
2425 try {
2426 MidiInstrumentMapper::RemoveAllMaps();
2427 } catch (Exception e) {
2428 result.Error(e);
2429 }
2430 return result.Produce();
2431 }
2432
2433 String LSCPServer::GetMidiInstrumentMaps() {
2434 dmsg(2,("LSCPServer: GetMidiInstrumentMaps()\n"));
2435 LSCPResultSet result;
2436 try {
2437 result.Add(MidiInstrumentMapper::Maps().size());
2438 } catch (Exception e) {
2439 result.Error(e);
2440 }
2441 return result.Produce();
2442 }
2443
2444 String LSCPServer::ListMidiInstrumentMaps() {
2445 dmsg(2,("LSCPServer: ListMidiInstrumentMaps()\n"));
2446 LSCPResultSet result;
2447 try {
2448 std::vector<int> maps = MidiInstrumentMapper::Maps();
2449 String sList;
2450 for (int i = 0; i < maps.size(); i++) {
2451 if (sList != "") sList += ",";
2452 sList += ToString(maps[i]);
2453 }
2454 result.Add(sList);
2455 } catch (Exception e) {
2456 result.Error(e);
2457 }
2458 return result.Produce();
2459 }
2460
2461 String LSCPServer::GetMidiInstrumentMap(uint MidiMapID) {
2462 dmsg(2,("LSCPServer: GetMidiInstrumentMap()\n"));
2463 LSCPResultSet result;
2464 try {
2465 result.Add("NAME", _escapeLscpResponse(MidiInstrumentMapper::MapName(MidiMapID)));
2466 result.Add("DEFAULT", MidiInstrumentMapper::GetDefaultMap() == MidiMapID);
2467 } catch (Exception e) {
2468 result.Error(e);
2469 }
2470 return result.Produce();
2471 }
2472
2473 String LSCPServer::SetMidiInstrumentMapName(uint MidiMapID, String NewName) {
2474 dmsg(2,("LSCPServer: SetMidiInstrumentMapName()\n"));
2475 LSCPResultSet result;
2476 try {
2477 MidiInstrumentMapper::RenameMap(MidiMapID, NewName);
2478 } catch (Exception e) {
2479 result.Error(e);
2480 }
2481 return result.Produce();
2482 }
2483
2484 /**
2485 * Set the MIDI instrument map the given sampler channel shall use for
2486 * handling MIDI program change messages. There are the following two
2487 * special (negative) values:
2488 *
2489 * - (-1) : set to NONE (ignore program changes)
2490 * - (-2) : set to DEFAULT map
2491 */
2492 String LSCPServer::SetChannelMap(uint uiSamplerChannel, int MidiMapID) {
2493 dmsg(2,("LSCPServer: SetChannelMap()\n"));
2494 LSCPResultSet result;
2495 try {
2496 EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2497
2498 if (MidiMapID == -1) pEngineChannel->SetMidiInstrumentMapToNone();
2499 else if (MidiMapID == -2) pEngineChannel->SetMidiInstrumentMapToDefault();
2500 else pEngineChannel->SetMidiInstrumentMap(MidiMapID);
2501 } catch (Exception e) {
2502 result.Error(e);
2503 }
2504 return result.Produce();
2505 }
2506
2507 String LSCPServer::CreateFxSend(uint uiSamplerChannel, uint MidiCtrl, String Name) {
2508 dmsg(2,("LSCPServer: CreateFxSend()\n"));
2509 LSCPResultSet result;
2510 try {
2511 EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2512
2513 FxSend* pFxSend = pEngineChannel->AddFxSend(MidiCtrl, Name);
2514 if (!pFxSend) throw Exception("Could not add FxSend, don't ask, I don't know why (probably a bug)");
2515
2516 result = LSCPResultSet(pFxSend->Id()); // success
2517 } catch (Exception e) {
2518 result.Error(e);
2519 }
2520 return result.Produce();
2521 }
2522
2523 String LSCPServer::DestroyFxSend(uint uiSamplerChannel, uint FxSendID) {
2524 dmsg(2,("LSCPServer: DestroyFxSend()\n"));
2525 LSCPResultSet result;
2526 try {
2527 EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2528
2529 FxSend* pFxSend = NULL;
2530 for (int i = 0; i < pEngineChannel->GetFxSendCount(); i++) {
2531 if (pEngineChannel->GetFxSend(i)->Id() == FxSendID) {
2532 pFxSend = pEngineChannel->GetFxSend(i);
2533 break;
2534 }
2535 }
2536 if (!pFxSend) throw Exception("There is no FxSend with that ID on the given sampler channel");
2537 pEngineChannel->RemoveFxSend(pFxSend);
2538 } catch (Exception e) {
2539 result.Error(e);
2540 }
2541 return result.Produce();
2542 }
2543
2544 String LSCPServer::GetFxSends(uint uiSamplerChannel) {
2545 dmsg(2,("LSCPServer: GetFxSends()\n"));
2546 LSCPResultSet result;
2547 try {
2548 EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2549
2550 result.Add(pEngineChannel->GetFxSendCount());
2551 } catch (Exception e) {
2552 result.Error(e);
2553 }
2554 return result.Produce();
2555 }
2556
2557 String LSCPServer::ListFxSends(uint uiSamplerChannel) {
2558 dmsg(2,("LSCPServer: ListFxSends()\n"));
2559 LSCPResultSet result;
2560 String list;
2561 try {
2562 EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2563
2564 for (int i = 0; i < pEngineChannel->GetFxSendCount(); i++) {
2565 FxSend* pFxSend = pEngineChannel->GetFxSend(i);
2566 if (list != "") list += ",";
2567 list += ToString(pFxSend->Id());
2568 }
2569 result.Add(list);
2570 } catch (Exception e) {
2571 result.Error(e);
2572 }
2573 return result.Produce();
2574 }
2575
2576 FxSend* LSCPServer::GetFxSend(uint uiSamplerChannel, uint FxSendID) {
2577 EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2578
2579 FxSend* pFxSend = NULL;
2580 for (int i = 0; i < pEngineChannel->GetFxSendCount(); i++) {
2581 if (pEngineChannel->GetFxSend(i)->Id() == FxSendID) {
2582 pFxSend = pEngineChannel->GetFxSend(i);
2583 break;
2584 }
2585 }
2586 if (!pFxSend) throw Exception("There is no FxSend with that ID on the given sampler channel");
2587 return pFxSend;
2588 }
2589
2590 String LSCPServer::GetFxSendInfo(uint uiSamplerChannel, uint FxSendID) {
2591 dmsg(2,("LSCPServer: GetFxSendInfo()\n"));
2592 LSCPResultSet result;
2593 try {
2594 EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2595 FxSend* pFxSend = GetFxSend(uiSamplerChannel, FxSendID);
2596
2597 // gather audio routing informations
2598 String AudioRouting;
2599 for (int chan = 0; chan < pEngineChannel->Channels(); chan++) {
2600 if (AudioRouting != "") AudioRouting += ",";
2601 AudioRouting += ToString(pFxSend->DestinationChannel(chan));
2602 }
2603
2604 const String sEffectRouting =
2605 (pFxSend->DestinationEffectChain() >= 0 && pFxSend->DestinationEffectChainPosition() >= 0)
2606 ? ToString(pFxSend->DestinationEffectChain()) + "," + ToString(pFxSend->DestinationEffectChainPosition())
2607 : "NONE";
2608
2609 // success
2610 result.Add("NAME", _escapeLscpResponse(pFxSend->Name()));
2611 result.Add("MIDI_CONTROLLER", pFxSend->MidiController());
2612 result.Add("LEVEL", ToString(pFxSend->Level()));
2613 result.Add("AUDIO_OUTPUT_ROUTING", AudioRouting);
2614 result.Add("EFFECT", sEffectRouting);
2615 } catch (Exception e) {
2616 result.Error(e);
2617 }
2618 return result.Produce();
2619 }
2620
2621 String LSCPServer::SetFxSendName(uint uiSamplerChannel, uint FxSendID, String Name) {
2622 dmsg(2,("LSCPServer: SetFxSendName()\n"));
2623 LSCPResultSet result;
2624 try {
2625 FxSend* pFxSend = GetFxSend(uiSamplerChannel, FxSendID);
2626
2627 pFxSend->SetName(Name);
2628 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_info, uiSamplerChannel, FxSendID));
2629 } catch (Exception e) {
2630 result.Error(e);
2631 }
2632 return result.Produce();
2633 }
2634
2635 String LSCPServer::SetFxSendAudioOutputChannel(uint uiSamplerChannel, uint FxSendID, uint FxSendChannel, uint DeviceChannel) {
2636 dmsg(2,("LSCPServer: SetFxSendAudioOutputChannel()\n"));
2637 LSCPResultSet result;
2638 try {
2639 FxSend* pFxSend = GetFxSend(uiSamplerChannel, FxSendID);
2640
2641 pFxSend->SetDestinationChannel(FxSendChannel, DeviceChannel);
2642 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_info, uiSamplerChannel, FxSendID));
2643 } catch (Exception e) {
2644 result.Error(e);
2645 }
2646 return result.Produce();
2647 }
2648
2649 String LSCPServer::SetFxSendMidiController(uint uiSamplerChannel, uint FxSendID, uint MidiController) {
2650 dmsg(2,("LSCPServer: SetFxSendMidiController()\n"));
2651 LSCPResultSet result;
2652 try {
2653 FxSend* pFxSend = GetFxSend(uiSamplerChannel, FxSendID);
2654
2655 pFxSend->SetMidiController(MidiController);
2656 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_info, uiSamplerChannel, FxSendID));
2657 } catch (Exception e) {
2658 result.Error(e);
2659 }
2660 return result.Produce();
2661 }
2662
2663 String LSCPServer::SetFxSendLevel(uint uiSamplerChannel, uint FxSendID, double dLevel) {
2664 dmsg(2,("LSCPServer: SetFxSendLevel()\n"));
2665 LSCPResultSet result;
2666 try {
2667 FxSend* pFxSend = GetFxSend(uiSamplerChannel, FxSendID);
2668
2669 pFxSend->SetLevel((float)dLevel);
2670 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_info, uiSamplerChannel, FxSendID));
2671 } catch (Exception e) {
2672 result.Error(e);
2673 }
2674 return result.Produce();
2675 }
2676
2677 String LSCPServer::SetFxSendEffect(uint uiSamplerChannel, uint FxSendID, int iSendEffectChain, int iEffectChainPosition) {
2678 dmsg(2,("LSCPServer: SetFxSendEffect(%d,%d)\n", iSendEffectChain, iEffectChainPosition));
2679 LSCPResultSet result;
2680 try {
2681 FxSend* pFxSend = GetFxSend(uiSamplerChannel, FxSendID);
2682
2683 pFxSend->SetDestinationEffect(iSendEffectChain, iEffectChainPosition);
2684 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_info, uiSamplerChannel, FxSendID));
2685 } catch (Exception e) {
2686 result.Error(e);
2687 }
2688 return result.Produce();
2689 }
2690
2691 String LSCPServer::GetAvailableEffects() {
2692 dmsg(2,("LSCPServer: GetAvailableEffects()\n"));
2693 LSCPResultSet result;
2694 try {
2695 int n = EffectFactory::AvailableEffectsCount();
2696 result.Add(n);
2697 }
2698 catch (Exception e) {
2699 result.Error(e);
2700 }
2701 return result.Produce();
2702 }
2703
2704 String LSCPServer::ListAvailableEffects() {
2705 dmsg(2,("LSCPServer: ListAvailableEffects()\n"));
2706 LSCPResultSet result;
2707 String list;
2708 try {
2709 //FIXME: for now we simply enumerate from 0 .. EffectFactory::AvailableEffectsCount() here, in future we should use unique IDs for effects during the whole sampler session. This issue comes into game when the user forces a reload of available effect plugins
2710 int n = EffectFactory::AvailableEffectsCount();
2711 for (int i = 0; i < n; i++) {
2712 if (i) list += ",";
2713 list += ToString(i);
2714 }
2715 }
2716 catch (Exception e) {
2717 result.Error(e);
2718 }
2719 result.Add(list);
2720 return result.Produce();
2721 }
2722
2723 String LSCPServer::GetEffectInfo(int iEffectIndex) {
2724 dmsg(2,("LSCPServer: GetEffectInfo(%d)\n", iEffectIndex));
2725 LSCPResultSet result;
2726 try {
2727 EffectInfo* pEffectInfo = EffectFactory::GetEffectInfo(iEffectIndex);
2728 if (!pEffectInfo)
2729 throw Exception("There is no effect with index " + ToString(iEffectIndex));
2730
2731 // convert the filename into the correct encoding as defined for LSCP
2732 // (especially in terms of special characters -> escape sequences)
2733 #if WIN32
2734 const String dllFileName = Path::fromWindows(pEffectInfo->Module()).toLscp();
2735 #else
2736 // assuming POSIX
2737 const String dllFileName = Path::fromPosix(pEffectInfo->Module()).toLscp();
2738 #endif
2739
2740 result.Add("SYSTEM", pEffectInfo->EffectSystem());
2741 result.Add("MODULE", dllFileName);
2742 result.Add("NAME", _escapeLscpResponse(pEffectInfo->Name()));
2743 result.Add("DESCRIPTION", _escapeLscpResponse(pEffectInfo->Description()));
2744 }
2745 catch (Exception e) {
2746 result.Error(e);
2747 }
2748 return result.Produce();
2749 }
2750
2751 String LSCPServer::GetEffectInstanceInfo(int iEffectInstance) {
2752 dmsg(2,("LSCPServer: GetEffectInstanceInfo(%d)\n", iEffectInstance));
2753 LSCPResultSet result;
2754 try {
2755 Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
2756 if (!pEffect)
2757 throw Exception("There is no effect instance with ID " + ToString(iEffectInstance));
2758
2759 EffectInfo* pEffectInfo = pEffect->GetEffectInfo();
2760
2761 // convert the filename into the correct encoding as defined for LSCP
2762 // (especially in terms of special characters -> escape sequences)
2763 #if WIN32
2764 const String dllFileName = Path::fromWindows(pEffectInfo->Module()).toLscp();
2765 #else
2766 // assuming POSIX
2767 const String dllFileName = Path::fromPosix(pEffectInfo->Module()).toLscp();
2768 #endif
2769
2770 result.Add("SYSTEM", pEffectInfo->EffectSystem());
2771 result.Add("MODULE", dllFileName);
2772 result.Add("NAME", _escapeLscpResponse(pEffectInfo->Name()));
2773 result.Add("DESCRIPTION", _escapeLscpResponse(pEffectInfo->Description()));
2774 result.Add("INPUT_CONTROLS", ToString(pEffect->InputControlCount()));
2775 }
2776 catch (Exception e) {
2777 result.Error(e);
2778 }
2779 return result.Produce();
2780 }
2781
2782 String LSCPServer::GetEffectInstanceInputControlInfo(int iEffectInstance, int iInputControlIndex) {
2783 dmsg(2,("LSCPServer: GetEffectInstanceInputControlInfo(%d,%d)\n", iEffectInstance, iInputControlIndex));
2784 LSCPResultSet result;
2785 try {
2786 Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
2787 if (!pEffect)
2788 throw Exception("There is no effect instance with ID " + ToString(iEffectInstance));
2789
2790 EffectControl* pEffectControl = pEffect->InputControl(iInputControlIndex);
2791 if (!pEffectControl)
2792 throw Exception(
2793 "Effect instance " + ToString(iEffectInstance) +
2794 " does not have an input control with index " +
2795 ToString(iInputControlIndex)
2796 );
2797
2798 result.Add("DESCRIPTION", _escapeLscpResponse(pEffectControl->Description()));
2799 result.Add("VALUE", pEffectControl->Value());
2800 if (pEffectControl->MinValue())
2801 result.Add("RANGE_MIN", *pEffectControl->MinValue());
2802 if (pEffectControl->MaxValue())
2803 result.Add("RANGE_MAX", *pEffectControl->MaxValue());
2804 if (!pEffectControl->Possibilities().empty())
2805 result.Add("POSSIBILITIES", pEffectControl->Possibilities());
2806 if (pEffectControl->DefaultValue())
2807 result.Add("DEFAULT", *pEffectControl->DefaultValue());
2808 } catch (Exception e) {
2809 result.Error(e);
2810 }
2811 return result.Produce();
2812 }
2813
2814 String LSCPServer::SetEffectInstanceInputControlValue(int iEffectInstance, int iInputControlIndex, double dValue) {
2815 dmsg(2,("LSCPServer: SetEffectInstanceInputControlValue(%d,%d,%f)\n", iEffectInstance, iInputControlIndex, dValue));
2816 LSCPResultSet result;
2817 try {
2818 Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
2819 if (!pEffect)
2820 throw Exception("There is no effect instance with ID " + ToString(iEffectInstance));
2821
2822 EffectControl* pEffectControl = pEffect->InputControl(iInputControlIndex);
2823 if (!pEffectControl)
2824 throw Exception(
2825 "Effect instance " + ToString(iEffectInstance) +
2826 " does not have an input control with index " +
2827 ToString(iInputControlIndex)
2828 );
2829
2830 pEffectControl->SetValue(dValue);
2831 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_instance_info, iEffectInstance));
2832 } catch (Exception e) {
2833 result.Error(e);
2834 }
2835 return result.Produce();
2836 }
2837
2838 String LSCPServer::CreateEffectInstance(int iEffectIndex) {
2839 dmsg(2,("LSCPServer: CreateEffectInstance(%d)\n", iEffectIndex));
2840 LSCPResultSet result;
2841 try {
2842 EffectInfo* pEffectInfo = EffectFactory::GetEffectInfo(iEffectIndex);
2843 if (!pEffectInfo)
2844 throw Exception("There is no effect with index " + ToString(iEffectIndex));
2845 Effect* pEffect = EffectFactory::Create(pEffectInfo);
2846 result = pEffect->ID(); // success
2847 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_instance_count, EffectFactory::EffectInstancesCount()));
2848 } catch (Exception e) {
2849 result.Error(e);
2850 }
2851 return result.Produce();
2852 }
2853
2854 String LSCPServer::CreateEffectInstance(String effectSystem, String module, String effectName) {
2855 dmsg(2,("LSCPServer: CreateEffectInstance('%s','%s','%s')\n", effectSystem.c_str(), module.c_str(), effectName.c_str()));
2856 LSCPResultSet result;
2857 try {
2858 // to allow loading the same LSCP session file on different systems
2859 // successfully, probably with different effect plugin DLL paths or even
2860 // running completely different operating systems, we do the following
2861 // for finding the right effect:
2862 //
2863 // first try to search for an exact match of the effect plugin DLL
2864 // (a.k.a 'module'), to avoid picking the wrong DLL with the same
2865 // effect name ...
2866 EffectInfo* pEffectInfo = EffectFactory::GetEffectInfo(effectSystem, module, effectName, EffectFactory::MODULE_MATCH_EXACTLY);
2867 // ... if no effect with exactly matchin DLL filename was found, then
2868 // try to lower the restrictions of matching the effect plugin DLL
2869 // filename and try again and again ...
2870 if (!pEffectInfo) {
2871 dmsg(2,("no exact module match, trying MODULE_IGNORE_PATH\n"));
2872 pEffectInfo = EffectFactory::GetEffectInfo(effectSystem, module, effectName, EffectFactory::MODULE_IGNORE_PATH);
2873 }
2874 if (!pEffectInfo) {
2875 dmsg(2,("no module match, trying MODULE_IGNORE_PATH | MODULE_IGNORE_CASE\n"));
2876 pEffectInfo = EffectFactory::GetEffectInfo(effectSystem, module, effectName, EffectFactory::MODULE_IGNORE_PATH | EffectFactory::MODULE_IGNORE_CASE);
2877 }
2878 if (!pEffectInfo) {
2879 dmsg(2,("no module match, trying MODULE_IGNORE_PATH | MODULE_IGNORE_CASE | MODULE_IGNORE_EXTENSION\n"));
2880 pEffectInfo = EffectFactory::GetEffectInfo(effectSystem, module, effectName, EffectFactory::MODULE_IGNORE_PATH | EffectFactory::MODULE_IGNORE_CASE | EffectFactory::MODULE_IGNORE_EXTENSION);
2881 }
2882 // ... if there was still no effect found, then completely ignore the
2883 // DLL plugin filename argument and just search for the matching effect
2884 // system type and effect name
2885 if (!pEffectInfo) {
2886 dmsg(2,("no module match, trying MODULE_IGNORE_ALL\n"));
2887 pEffectInfo = EffectFactory::GetEffectInfo(effectSystem, module, effectName, EffectFactory::MODULE_IGNORE_ALL);
2888 }
2889 if (!pEffectInfo)
2890 throw Exception("There is no such effect '" + effectSystem + "' '" + module + "' '" + effectName + "'");
2891
2892 Effect* pEffect = EffectFactory::Create(pEffectInfo);
2893 result = LSCPResultSet(pEffect->ID());
2894 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_instance_count, EffectFactory::EffectInstancesCount()));
2895 } catch (Exception e) {
2896 result.Error(e);
2897 }
2898 return result.Produce();
2899 }
2900
2901 String LSCPServer::DestroyEffectInstance(int iEffectInstance) {
2902 dmsg(2,("LSCPServer: DestroyEffectInstance(%d)\n", iEffectInstance));
2903 LSCPResultSet result;
2904 try {
2905 Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
2906 if (!pEffect)
2907 throw Exception("There is no effect instance with ID " + ToString(iEffectInstance));
2908 EffectFactory::Destroy(pEffect);
2909 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_instance_count, EffectFactory::EffectInstancesCount()));
2910 } catch (Exception e) {
2911 result.Error(e);
2912 }
2913 return result.Produce();
2914 }
2915
2916 String LSCPServer::GetEffectInstances() {
2917 dmsg(2,("LSCPServer: GetEffectInstances()\n"));
2918 LSCPResultSet result;
2919 try {
2920 int n = EffectFactory::EffectInstancesCount();
2921 result.Add(n);
2922 } catch (Exception e) {
2923 result.Error(e);
2924 }
2925 return result.Produce();
2926 }
2927
2928 String LSCPServer::ListEffectInstances() {
2929 dmsg(2,("LSCPServer: ListEffectInstances()\n"));
2930 LSCPResultSet result;
2931 String list;
2932 try {
2933 int n = EffectFactory::EffectInstancesCount();
2934 for (int i = 0; i < n; i++) {
2935 Effect* pEffect = EffectFactory::GetEffectInstance(i);
2936 if (i) list += ",";
2937 list += ToString(pEffect->ID());
2938 }
2939 } catch (Exception e) {
2940 result.Error(e);
2941 }
2942 result.Add(list);
2943 return result.Produce();
2944 }
2945
2946 String LSCPServer::GetSendEffectChains(int iAudioOutputDevice) {
2947 dmsg(2,("LSCPServer: GetSendEffectChains(%d)\n", iAudioOutputDevice));
2948 LSCPResultSet result;
2949 try {
2950 std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
2951 if (!devices.count(iAudioOutputDevice))
2952 throw Exception("There is no audio output device with index " + ToString(iAudioOutputDevice) + ".");
2953 AudioOutputDevice* pDevice = devices[iAudioOutputDevice];
2954 int n = pDevice->SendEffectChainCount();
2955 result.Add(n);
2956 } catch (Exception e) {
2957 result.Error(e);
2958 }
2959 return result.Produce();
2960 }
2961
2962 String LSCPServer::ListSendEffectChains(int iAudioOutputDevice) {
2963 dmsg(2,("LSCPServer: ListSendEffectChains(%d)\n", iAudioOutputDevice));
2964 LSCPResultSet result;
2965 String list;
2966 try {
2967 std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
2968 if (!devices.count(iAudioOutputDevice))
2969 throw Exception("There is no audio output device with index " + ToString(iAudioOutputDevice) + ".");
2970 AudioOutputDevice* pDevice = devices[iAudioOutputDevice];
2971 int n = pDevice->SendEffectChainCount();
2972 for (int i = 0; i < n; i++) {
2973 EffectChain* pEffectChain = pDevice->SendEffectChain(i);
2974 if (i) list += ",";
2975 list += ToString(pEffectChain->ID());
2976 }
2977 } catch (Exception e) {
2978 result.Error(e);
2979 }
2980 result.Add(list);
2981 return result.Produce();
2982 }
2983
2984 String LSCPServer::AddSendEffectChain(int iAudioOutputDevice) {
2985 dmsg(2,("LSCPServer: AddSendEffectChain(%d)\n", iAudioOutputDevice));
2986 LSCPResultSet result;
2987 try {
2988 std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
2989 if (!devices.count(iAudioOutputDevice))
2990 throw Exception("There is no audio output device with index " + ToString(iAudioOutputDevice) + ".");
2991 AudioOutputDevice* pDevice = devices[iAudioOutputDevice];
2992 EffectChain* pEffectChain = pDevice->AddSendEffectChain();
2993 result = pEffectChain->ID();
2994 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_send_fx_chain_count, iAudioOutputDevice, pDevice->SendEffectChainCount()));
2995 } catch (Exception e) {
2996 result.Error(e);
2997 }
2998 return result.Produce();
2999 }
3000
3001 String LSCPServer::RemoveSendEffectChain(int iAudioOutputDevice, int iSendEffectChain) {
3002 dmsg(2,("LSCPServer: RemoveSendEffectChain(%d,%d)\n", iAudioOutputDevice, iSendEffectChain));
3003 LSCPResultSet result;
3004 try {
3005 std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
3006 if (!devices.count(iAudioOutputDevice))
3007 throw Exception("There is no audio output device with index " + ToString(iAudioOutputDevice) + ".");
3008
3009 std::set<EngineChannel*> engineChannels = EngineChannelFactory::EngineChannelInstances();
3010 std::set<EngineChannel*>::iterator itEngineChannel = engineChannels.begin();
3011 std::set<EngineChannel*>::iterator itEnd = engineChannels.end();
3012 for (; itEngineChannel != itEnd; ++itEngineChannel) {
3013 AudioOutputDevice* pDev = (*itEngineChannel)->GetAudioOutputDevice();
3014 if (pDev != NULL && pDev->deviceId() == iAudioOutputDevice) {
3015 for (int i = 0; i < (*itEngineChannel)->GetFxSendCount(); i++) {
3016 FxSend* fxs = (*itEngineChannel)->GetFxSend(i);
3017 if(fxs != NULL && fxs->DestinationEffectChain() == iSendEffectChain) {
3018 throw Exception("The effect chain is still in use by channel " + ToString((*itEngineChannel)->GetSamplerChannel()->Index()));
3019 }
3020 }
3021 }
3022 }
3023
3024 AudioOutputDevice* pDevice = devices[iAudioOutputDevice];
3025 for (int i = 0; i < pDevice->SendEffectChainCount(); i++) {
3026 EffectChain* pEffectChain = pDevice->SendEffectChain(i);
3027 if (pEffectChain->ID() == iSendEffectChain) {
3028 pDevice->RemoveSendEffectChain(i);
3029 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_send_fx_chain_count, iAudioOutputDevice, pDevice->SendEffectChainCount()));
3030 return result.Produce();
3031 }
3032 }
3033 throw Exception(
3034 "There is no send effect chain with ID " +
3035 ToString(iSendEffectChain) + " for audio output device " +
3036 ToString(iAudioOutputDevice) + "."
3037 );
3038 } catch (Exception e) {
3039 result.Error(e);
3040 }
3041 return result.Produce();
3042 }
3043
3044 static EffectChain* _getSendEffectChain(Sampler* pSampler, int iAudioOutputDevice, int iSendEffectChain) throw (Exception) {
3045 std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
3046 if (!devices.count(iAudioOutputDevice))
3047 throw Exception(
3048 "There is no audio output device with index " +
3049 ToString(iAudioOutputDevice) + "."
3050 );
3051 AudioOutputDevice* pDevice = devices[iAudioOutputDevice];
3052 EffectChain* pEffectChain = pDevice->SendEffectChainByID(iSendEffectChain);
3053 if(pEffectChain != NULL) return pEffectChain;
3054 throw Exception(
3055 "There is no send effect chain with ID " +
3056 ToString(iSendEffectChain) + " for audio output device " +
3057 ToString(iAudioOutputDevice) + "."
3058 );
3059 }
3060
3061 String LSCPServer::GetSendEffectChainInfo(int iAudioOutputDevice, int iSendEffectChain) {
3062 dmsg(2,("LSCPServer: GetSendEffectChainInfo(%d,%d)\n", iAudioOutputDevice, iSendEffectChain));
3063 LSCPResultSet result;
3064 try {
3065 EffectChain* pEffectChain =
3066 _getSendEffectChain(pSampler, iAudioOutputDevice, iSendEffectChain);
3067 String sEffectSequence;
3068 for (int i = 0; i < pEffectChain->EffectCount(); i++) {
3069 if (i) sEffectSequence += ",";
3070 sEffectSequence += ToString(pEffectChain->GetEffect(i)->ID());
3071 }
3072 result.Add("EFFECT_COUNT", pEffectChain->EffectCount());
3073 result.Add("EFFECT_SEQUENCE", sEffectSequence);
3074 } catch (Exception e) {
3075 result.Error(e);
3076 }
3077 return result.Produce();
3078 }
3079
3080 String LSCPServer::AppendSendEffectChainEffect(int iAudioOutputDevice, int iSendEffectChain, int iEffectInstance) {
3081 dmsg(2,("LSCPServer: AppendSendEffectChainEffect(%d,%d,%d)\n", iAudioOutputDevice, iSendEffectChain, iEffectInstance));
3082 LSCPResultSet result;
3083 try {
3084 EffectChain* pEffectChain =
3085 _getSendEffectChain(pSampler, iAudioOutputDevice, iSendEffectChain);
3086 Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
3087 if (!pEffect)
3088 throw Exception("There is no effect instance with ID " + ToString(iEffectInstance));
3089 pEffectChain->AppendEffect(pEffect);
3090 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_send_fx_chain_info, iAudioOutputDevice, iSendEffectChain, pEffectChain->EffectCount()));
3091 } catch (Exception e) {
3092 result.Error(e);
3093 }
3094 return result.Produce();
3095 }
3096
3097 String LSCPServer::InsertSendEffectChainEffect(int iAudioOutputDevice, int iSendEffectChain, int iEffectChainPosition, int iEffectInstance) {
3098 dmsg(2,("LSCPServer: InsertSendEffectChainEffect(%d,%d,%d,%d)\n", iAudioOutputDevice, iSendEffectChain, iEffectChainPosition, iEffectInstance));
3099 LSCPResultSet result;
3100 try {
3101 EffectChain* pEffectChain =
3102 _getSendEffectChain(pSampler, iAudioOutputDevice, iSendEffectChain);
3103 Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
3104 if (!pEffect)
3105 throw Exception("There is no effect instance with index " + ToString(iEffectInstance));
3106 pEffectChain->InsertEffect(pEffect, iEffectChainPosition);
3107 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_send_fx_chain_info, iAudioOutputDevice, iSendEffectChain, pEffectChain->EffectCount()));
3108 } catch (Exception e) {
3109 result.Error(e);
3110 }
3111 return result.Produce();
3112 }
3113
3114 String LSCPServer::RemoveSendEffectChainEffect(int iAudioOutputDevice, int iSendEffectChain, int iEffectChainPosition) {
3115 dmsg(2,("LSCPServer: RemoveSendEffectChainEffect(%d,%d,%d)\n", iAudioOutputDevice, iSendEffectChain, iEffectChainPosition));
3116 LSCPResultSet result;
3117 try {
3118 EffectChain* pEffectChain =
3119 _getSendEffectChain(pSampler, iAudioOutputDevice, iSendEffectChain);
3120
3121 std::set<EngineChannel*> engineChannels = EngineChannelFactory::EngineChannelInstances();
3122 std::set<EngineChannel*>::iterator itEngineChannel = engineChannels.begin();
3123 std::set<EngineChannel*>::iterator itEnd = engineChannels.end();
3124 for (; itEngineChannel != itEnd; ++itEngineChannel) {
3125 AudioOutputDevice* pDev = (*itEngineChannel)->GetAudioOutputDevice();
3126 if (pDev != NULL && pDev->deviceId() == iAudioOutputDevice) {
3127 for (int i = 0; i < (*itEngineChannel)->GetFxSendCount(); i++) {
3128 FxSend* fxs = (*itEngineChannel)->GetFxSend(i);
3129 if(fxs != NULL && fxs->DestinationEffectChain() == iSendEffectChain && fxs->DestinationEffectChainPosition() == iEffectChainPosition) {
3130 throw Exception("The effect instance is still in use by channel " + ToString((*itEngineChannel)->GetSamplerChannel()->Index()));
3131 }
3132 }
3133 }
3134 }
3135
3136 pEffectChain->RemoveEffect(iEffectChainPosition);
3137 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_send_fx_chain_info, iAudioOutputDevice, iSendEffectChain, pEffectChain->EffectCount()));
3138 } catch (Exception e) {
3139 result.Error(e);
3140 }
3141 return result.Produce();
3142 }
3143
3144 String LSCPServer::EditSamplerChannelInstrument(uint uiSamplerChannel) {
3145 dmsg(2,("LSCPServer: EditSamplerChannelInstrument(SamplerChannel=%d)\n", uiSamplerChannel));
3146 LSCPResultSet result;
3147 try {
3148 EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
3149 if (pEngineChannel->InstrumentStatus() < 0) throw Exception("No instrument loaded to sampler channel");
3150 Engine* pEngine = pEngineChannel->GetEngine();
3151 InstrumentManager* pInstrumentManager = pEngine->GetInstrumentManager();
3152 if (!pInstrumentManager) throw Exception("Engine does not provide an instrument manager");
3153 InstrumentManager::instrument_id_t instrumentID;
3154 instrumentID.FileName = pEngineChannel->InstrumentFileName();
3155 instrumentID.Index = pEngineChannel->InstrumentIndex();
3156 pInstrumentManager->LaunchInstrumentEditor(pEngineChannel, instrumentID);
3157 } catch (Exception e) {
3158 result.Error(e);
3159 }
3160 return result.Produce();
3161 }
3162
3163 String LSCPServer::SendChannelMidiData(String MidiMsg, uint uiSamplerChannel, uint Arg1, uint Arg2) {
3164 dmsg(2,("LSCPServer: SendChannelMidiData(MidiMsg=%s,uiSamplerChannel=%d,Arg1=%d,Arg2=%d)\n", MidiMsg.c_str(), uiSamplerChannel, Arg1, Arg2));
3165 LSCPResultSet result;
3166 try {
3167 EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
3168
3169 if (Arg1 > 127 || Arg2 > 127) {
3170 throw Exception("Invalid MIDI message");
3171 }
3172
3173 VirtualMidiDevice* pMidiDevice = NULL;
3174 std::vector<EventHandler::midi_listener_entry>::iterator iter = eventHandler.channelMidiListeners.begin();
3175 for (; iter != eventHandler.channelMidiListeners.end(); ++iter) {
3176 if ((*iter).pEngineChannel == pEngineChannel) {
3177 pMidiDevice = (*iter).pMidiListener;
3178 break;
3179 }
3180 }
3181
3182 if(pMidiDevice == NULL) throw Exception("Couldn't find virtual MIDI device");
3183
3184 if (MidiMsg == "NOTE_ON") {
3185 pMidiDevice->SendNoteOnToDevice(Arg1, Arg2);
3186 bool b = pMidiDevice->SendNoteOnToSampler(Arg1, Arg2);
3187 if (!b) throw Exception("MIDI event failed: " + MidiMsg + " " + ToString(Arg1) + " " + ToString(Arg2));
3188 } else if (MidiMsg == "NOTE_OFF") {
3189 pMidiDevice->SendNoteOffToDevice(Arg1, Arg2);
3190 bool b = pMidiDevice->SendNoteOffToSampler(Arg1, Arg2);
3191 if (!b) throw Exception("MIDI event failed: " + MidiMsg + " " + ToString(Arg1) + " " + ToString(Arg2));
3192 } else if (MidiMsg == "CC") {
3193 pMidiDevice->SendCCToDevice(Arg1, Arg2);
3194 bool b = pMidiDevice->SendCCToSampler(Arg1, Arg2);
3195 if (!b) throw Exception("MIDI event failed: " + MidiMsg + " " + ToString(Arg1) + " " + ToString(Arg2));
3196 } else {
3197 throw Exception("Unknown MIDI message type: " + MidiMsg);
3198 }
3199 } catch (Exception e) {
3200 result.Error(e);
3201 }
3202 return result.Produce();
3203 }
3204
3205 /**
3206 * Will be called by the parser to reset a particular sampler channel.
3207 */
3208 String LSCPServer::ResetChannel(uint uiSamplerChannel) {
3209 dmsg(2,("LSCPServer: ResetChannel(SamplerChannel=%d)\n", uiSamplerChannel));
3210 LSCPResultSet result;
3211 try {
3212 EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
3213 pEngineChannel->Reset();
3214 }
3215 catch (Exception e) {
3216 result.Error(e);
3217 }
3218 return result.Produce();
3219 }
3220
3221 /**
3222 * Will be called by the parser to reset the whole sampler.
3223 */
3224 String LSCPServer::ResetSampler() {
3225 dmsg(2,("LSCPServer: ResetSampler()\n"));
3226 pSampler->Reset();
3227 LSCPResultSet result;
3228 return result.Produce();
3229 }
3230
3231 /**
3232 * Will be called by the parser to return general informations about this
3233 * sampler.
3234 */
3235 String LSCPServer::GetServerInfo() {
3236 dmsg(2,("LSCPServer: GetServerInfo()\n"));
3237 const std::string description =
3238 _escapeLscpResponse("LinuxSampler - modular, streaming capable sampler");
3239 LSCPResultSet result;
3240 result.Add("DESCRIPTION", description);
3241 result.Add("VERSION", VERSION);
3242 result.Add("PROTOCOL_VERSION", ToString(LSCP_RELEASE_MAJOR) + "." + ToString(LSCP_RELEASE_MINOR));
3243 #if HAVE_SQLITE3
3244 result.Add("INSTRUMENTS_DB_SUPPORT", "yes");
3245 #else
3246 result.Add("INSTRUMENTS_DB_SUPPORT", "no");
3247 #endif
3248
3249 return result.Produce();
3250 }
3251
3252 /**
3253 * Will be called by the parser to return the current number of all active streams.
3254 */
3255 String LSCPServer::GetTotalStreamCount() {
3256 dmsg(2,("LSCPServer: GetTotalStreamCount()\n"));
3257 LSCPResultSet result;
3258 result.Add(pSampler->GetDiskStreamCount());
3259 return result.Produce();
3260 }
3261
3262 /**
3263 * Will be called by the parser to return the current number of all active voices.
3264 */
3265 String LSCPServer::GetTotalVoiceCount() {
3266 dmsg(2,("LSCPServer: GetTotalVoiceCount()\n"));
3267 LSCPResultSet result;
3268 result.Add(pSampler->GetVoiceCount());
3269 return result.Produce();
3270 }
3271
3272 /**
3273 * Will be called by the parser to return the maximum number of voices.
3274 */
3275 String LSCPServer::GetTotalVoiceCountMax() {
3276 dmsg(2,("LSCPServer: GetTotalVoiceCountMax()\n"));
3277 LSCPResultSet result;
3278 result.Add(EngineFactory::EngineInstances().size() * pSampler->GetGlobalMaxVoices());
3279 return result.Produce();
3280 }
3281
3282 /**
3283 * Will be called by the parser to return the sampler global maximum
3284 * allowed number of voices.
3285 */
3286 String LSCPServer::GetGlobalMaxVoices() {
3287 dmsg(2,("LSCPServer: GetGlobalMaxVoices()\n"));
3288 LSCPResultSet result;
3289 result.Add(pSampler->GetGlobalMaxVoices());
3290 return result.Produce();
3291 }
3292
3293 /**
3294 * Will be called by the parser to set the sampler global maximum number of
3295 * voices.
3296 */
3297 String LSCPServer::SetGlobalMaxVoices(int iVoices) {
3298 dmsg(2,("LSCPServer: SetGlobalMaxVoices(%d)\n", iVoices));
3299 LSCPResultSet result;
3300 try {
3301 pSampler->SetGlobalMaxVoices(iVoices);
3302 LSCPServer::SendLSCPNotify(
3303 LSCPEvent(LSCPEvent::event_global_info, "VOICES", pSampler->GetGlobalMaxVoices())
3304 );
3305 } catch (Exception e) {
3306 result.Error(e);
3307 }
3308 return result.Produce();
3309 }
3310
3311 /**
3312 * Will be called by the parser to return the sampler global maximum
3313 * allowed number of disk streams.
3314 */
3315 String LSCPServer::GetGlobalMaxStreams() {
3316 dmsg(2,("LSCPServer: GetGlobalMaxStreams()\n"));
3317 LSCPResultSet result;
3318 result.Add(pSampler->GetGlobalMaxStreams());
3319 return result.Produce();
3320 }
3321
3322 /**
3323 * Will be called by the parser to set the sampler global maximum number of
3324 * disk streams.
3325 */
3326 String LSCPServer::SetGlobalMaxStreams(int iStreams) {
3327 dmsg(2,("LSCPServer: SetGlobalMaxStreams(%d)\n", iStreams));
3328 LSCPResultSet result;
3329 try {
3330 pSampler->SetGlobalMaxStreams(iStreams);
3331 LSCPServer::SendLSCPNotify(
3332 LSCPEvent(LSCPEvent::event_global_info, "STREAMS", pSampler->GetGlobalMaxStreams())
3333 );
3334 } catch (Exception e) {
3335 result.Error(e);
3336 }
3337 return result.Produce();
3338 }
3339
3340 String LSCPServer::GetGlobalVolume() {
3341 LSCPResultSet result;
3342 result.Add(ToString(GLOBAL_VOLUME)); // see common/global.cpp
3343 return result.Produce();
3344 }
3345
3346 String LSCPServer::SetGlobalVolume(double dVolume) {
3347 LSCPResultSet result;
3348 try {
3349 if (dVolume < 0) throw Exception("Volume may not be negative");
3350 GLOBAL_VOLUME = dVolume; // see common/global_private.cpp
3351 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_global_info, "VOLUME", GLOBAL_VOLUME));
3352 } catch (Exception e) {
3353 result.Error(e);
3354 }
3355 return result.Produce();
3356 }
3357
3358 String LSCPServer::GetFileInstruments(String Filename) {
3359 dmsg(2,("LSCPServer: GetFileInstruments(String Filename=%s)\n",Filename.c_str()));
3360 LSCPResultSet result;
3361 try {
3362 VerifyFile(Filename);
3363 } catch (Exception e) {
3364 result.Error(e);
3365 return result.Produce();
3366 }
3367 // try to find a sampler engine that can handle the file
3368 bool bFound = false;
3369 std::vector<String> engineTypes = EngineFactory::AvailableEngineTypes();
3370 for (int i = 0; !bFound && i < engineTypes.size(); i++) {
3371 Engine* pEngine = NULL;
3372 try {
3373 pEngine = EngineFactory::Create(engineTypes[i]);
3374 if (!pEngine) throw Exception("Internal error: could not create '" + engineTypes[i] + "' engine");
3375 InstrumentManager* pManager = pEngine->GetInstrumentManager();
3376 if (pManager) {
3377 std::vector<InstrumentManager::instrument_id_t> IDs =
3378 pManager->GetInstrumentFileContent(Filename);
3379 // return the amount of instruments in the file
3380 result.Add(IDs.size());
3381 // no more need to ask other engine types
3382 bFound = true;
3383 } else dmsg(1,("Warning: engine '%s' does not provide an instrument manager\n", engineTypes[i].c_str()));
3384 } catch (Exception e) {
3385 // NOOP, as exception is thrown if engine doesn't support file
3386 }
3387 if (pEngine) EngineFactory::Destroy(pEngine);
3388 }
3389
3390 if (!bFound) result.Error("Unknown file format");
3391 return result.Produce();
3392 }
3393
3394 String LSCPServer::ListFileInstruments(String Filename) {
3395 dmsg(2,("LSCPServer: ListFileInstruments(String Filename=%s)\n",Filename.c_str()));
3396 LSCPResultSet result;
3397 try {
3398 VerifyFile(Filename);
3399 } catch (Exception e) {
3400 result.Error(e);
3401 return result.Produce();
3402 }
3403 // try to find a sampler engine that can handle the file
3404 bool bFound = false;
3405 std::vector<String> engineTypes = EngineFactory::AvailableEngineTypes();
3406 for (int i = 0; !bFound && i < engineTypes.size(); i++) {
3407 Engine* pEngine = NULL;
3408 try {
3409 pEngine = EngineFactory::Create(engineTypes[i]);
3410 if (!pEngine) throw Exception("Internal error: could not create '" + engineTypes[i] + "' engine");
3411 InstrumentManager* pManager = pEngine->GetInstrumentManager();
3412 if (pManager) {
3413 std::vector<InstrumentManager::instrument_id_t> IDs =
3414 pManager->GetInstrumentFileContent(Filename);
3415 // return a list of IDs of the instruments in the file
3416 String s;
3417 for (int j = 0; j < IDs.size(); j++) {
3418 if (s.size()) s += ",";
3419 s += ToString(IDs[j].Index);
3420 }
3421 result.Add(s);
3422 // no more need to ask other engine types
3423 bFound = true;
3424 } else dmsg(1,("Warning: engine '%s' does not provide an instrument manager\n", engineTypes[i].c_str()));
3425 } catch (Exception e) {
3426 // NOOP, as exception is thrown if engine doesn't support file
3427 }
3428 if (pEngine) EngineFactory::Destroy(pEngine);
3429 }
3430
3431 if (!bFound) result.Error("Unknown file format");
3432 return result.Produce();
3433 }
3434
3435 String LSCPServer::GetFileInstrumentInfo(String Filename, uint InstrumentID) {
3436 dmsg(2,("LSCPServer: GetFileInstrumentInfo(String Filename=%s, InstrumentID=%d)\n",Filename.c_str(),InstrumentID));
3437 LSCPResultSet result;
3438 try {
3439 VerifyFile(Filename);
3440 } catch (Exception e) {
3441 result.Error(e);
3442 return result.Produce();
3443 }
3444 InstrumentManager::instrument_id_t id;
3445 id.FileName = Filename;
3446 id.Index = InstrumentID;
3447 // try to find a sampler engine that can handle the file
3448 bool bFound = false;
3449 bool bFatalErr = false;
3450 std::vector<String> engineTypes = EngineFactory::AvailableEngineTypes();
3451 for (int i = 0; !bFound && !bFatalErr && i < engineTypes.size(); i++) {
3452 Engine* pEngine = NULL;
3453 try {
3454 pEngine = EngineFactory::Create(engineTypes[i]);
3455 if (!pEngine) throw Exception("Internal error: could not create '" + engineTypes[i] + "' engine");
3456 InstrumentManager* pManager = pEngine->GetInstrumentManager();
3457 if (pManager) {
3458 // check if the instrument index is valid
3459 // FIXME: this won't work if an engine only supports parts of the instrument file
3460 std::vector<InstrumentManager::instrument_id_t> IDs =
3461 pManager->GetInstrumentFileContent(Filename);
3462 if (std::find(IDs.begin(), IDs.end(), id) == IDs.end()) {
3463 std::stringstream ss;
3464 ss << "Invalid instrument index " << InstrumentID << " for instrument file '" << Filename << "'";
3465 bFatalErr = true;
3466 throw Exception(ss.str());
3467 }
3468 // get the info of the requested instrument
3469 InstrumentManager::instrument_info_t info =
3470 pManager->GetInstrumentInfo(id);
3471 // return detailed informations about the file
3472 result.Add("NAME", info.InstrumentName);
3473 result.Add("FORMAT_FAMILY", engineTypes[i]);
3474 result.Add("FORMAT_VERSION", info.FormatVersion);
3475 result.Add("PRODUCT", info.Product);
3476 result.Add("ARTISTS", info.Artists);
3477
3478 std::stringstream ss;
3479 bool b = false;
3480 for (int i = 0; i < 128; i++) {
3481 if (info.KeyBindings[i]) {
3482 if (b) ss << ',';
3483 ss << i; b = true;
3484 }
3485 }
3486 result.Add("KEY_BINDINGS", ss.str());
3487
3488 b = false;
3489 std::stringstream ss2;
3490 for (int i = 0; i < 128; i++) {
3491 if (info.KeySwitchBindings[i]) {
3492 if (b) ss2 << ',';
3493 ss2 << i; b = true;
3494 }
3495 }
3496 result.Add("KEYSWITCH_BINDINGS", ss2.str());
3497 // no more need to ask other engine types
3498 bFound = true;
3499 } else dmsg(1,("Warning: engine '%s' does not provide an instrument manager\n", engineTypes[i].c_str()));
3500 } catch (Exception e) {
3501 // usually NOOP, as exception is thrown if engine doesn't support file
3502 if (bFatalErr) result.Error(e);
3503 }
3504 if (pEngine) EngineFactory::Destroy(pEngine);
3505 }
3506
3507 if (!bFound && !bFatalErr) result.Error("Unknown file format");
3508 return result.Produce();
3509 }
3510
3511 void LSCPServer::VerifyFile(String Filename) {
3512 #if WIN32
3513 WIN32_FIND_DATA win32FileAttributeData;
3514 BOOL res = GetFileAttributesEx( Filename.c_str(), GetFileExInfoStandard, &win32FileAttributeData );
3515 if (!res) {
3516 std::stringstream ss;
3517 ss << "File does not exist, GetFileAttributesEx failed `" << Filename << "`: Error " << GetLastError();
3518 throw Exception(ss.str());
3519 }
3520 if ( win32FileAttributeData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
3521 throw Exception("Directory is specified");
3522 }
3523 #else
3524 File f(Filename);
3525 if(!f.Exist()) throw Exception(f.GetErrorMsg());
3526 if (f.IsDirectory()) throw Exception("Directory is specified");
3527 #endif
3528 }
3529
3530 /**
3531 * Will be called by the parser to subscribe a client (frontend) on the
3532 * server for receiving event messages.
3533 */
3534 String LSCPServer::SubscribeNotification(LSCPEvent::event_t type) {
3535 dmsg(2,("LSCPServer: SubscribeNotification(Event=%s)\n", LSCPEvent::Name(type).c_str()));
3536 LSCPResultSet result;
3537 {
3538 LockGuard lock(SubscriptionMutex);
3539 eventSubscriptions[type].push_back(currentSocket);
3540 }
3541 return result.Produce();
3542 }
3543
3544 /**
3545 * Will be called by the parser to unsubscribe a client on the server
3546 * for not receiving further event messages.
3547 */
3548 String LSCPServer::UnsubscribeNotification(LSCPEvent::event_t type) {
3549 dmsg(2,("LSCPServer: UnsubscribeNotification(Event=%s)\n", LSCPEvent::Name(type).c_str()));
3550 LSCPResultSet result;
3551 {
3552 LockGuard lock(SubscriptionMutex);
3553 eventSubscriptions[type].remove(currentSocket);
3554 }
3555 return result.Produce();
3556 }
3557
3558 String LSCPServer::AddDbInstrumentDirectory(String Dir) {
3559 dmsg(2,("LSCPServer: AddDbInstrumentDirectory(Dir=%s)\n", Dir.c_str()));
3560 LSCPResultSet result;
3561 #if HAVE_SQLITE3
3562 try {
3563 InstrumentsDb::GetInstrumentsDb()->AddDirectory(Dir);
3564 } catch (Exception e) {
3565 result.Error(e);
3566 }
3567 #else
3568 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3569 #endif
3570 return result.Produce();
3571 }
3572
3573 String LSCPServer::RemoveDbInstrumentDirectory(String Dir, bool Force) {
3574 dmsg(2,("LSCPServer: RemoveDbInstrumentDirectory(Dir=%s,Force=%d)\n", Dir.c_str(), Force));
3575 LSCPResultSet result;
3576 #if HAVE_SQLITE3
3577 try {
3578 InstrumentsDb::GetInstrumentsDb()->RemoveDirectory(Dir, Force);
3579 } catch (Exception e) {
3580 result.Error(e);
3581 }
3582 #else
3583 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3584 #endif
3585 return result.Produce();
3586 }
3587
3588 String LSCPServer::GetDbInstrumentDirectoryCount(String Dir, bool Recursive) {
3589 dmsg(2,("LSCPServer: GetDbInstrumentDirectoryCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
3590 LSCPResultSet result;
3591 #if HAVE_SQLITE3
3592 try {
3593 result.Add(InstrumentsDb::GetInstrumentsDb()->GetDirectoryCount(Dir, Recursive));
3594 } catch (Exception e) {
3595 result.Error(e);
3596 }
3597 #else
3598 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3599 #endif
3600 return result.Produce();
3601 }
3602
3603 String LSCPServer::GetDbInstrumentDirectories(String Dir, bool Recursive) {
3604 dmsg(2,("LSCPServer: GetDbInstrumentDirectories(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
3605 LSCPResultSet result;
3606 #if HAVE_SQLITE3
3607 try {
3608 String list;
3609 StringListPtr dirs = InstrumentsDb::GetInstrumentsDb()->GetDirectories(Dir, Recursive);
3610
3611 for (int i = 0; i < dirs->size(); i++) {
3612 if (list != "") list += ",";
3613 list += "'" + InstrumentsDb::toEscapedPath(dirs->at(i)) + "'";
3614 }
3615
3616 result.Add(list);
3617 } catch (Exception e) {
3618 result.Error(e);
3619 }
3620 #else
3621 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3622 #endif
3623 return result.Produce();
3624 }
3625
3626 String LSCPServer::GetDbInstrumentDirectoryInfo(String Dir) {
3627 dmsg(2,("LSCPServer: GetDbInstrumentDirectoryInfo(Dir=%s)\n", Dir.c_str()));
3628 LSCPResultSet result;
3629 #if HAVE_SQLITE3
3630 try {
3631 DbDirectory info = InstrumentsDb::GetInstrumentsDb()->GetDirectoryInfo(Dir);
3632
3633 result.Add("DESCRIPTION", _escapeLscpResponse(info.Description));
3634 result.Add("CREATED", info.Created);
3635 result.Add("MODIFIED", info.Modified);
3636 } catch (Exception e) {
3637 result.Error(e);
3638 }
3639 #else
3640 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3641 #endif
3642 return result.Produce();
3643 }
3644
3645 String LSCPServer::SetDbInstrumentDirectoryName(String Dir, String Name) {
3646 dmsg(2,("LSCPServer: SetDbInstrumentDirectoryName(Dir=%s,Name=%s)\n", Dir.c_str(), Name.c_str()));
3647 LSCPResultSet result;
3648 #if HAVE_SQLITE3
3649 try {
3650 InstrumentsDb::GetInstrumentsDb()->RenameDirectory(Dir, Name);
3651 } catch (Exception e) {
3652 result.Error(e);
3653 }
3654 #else
3655 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3656 #endif
3657 return result.Produce();
3658 }
3659
3660 String LSCPServer::MoveDbInstrumentDirectory(String Dir, String Dst) {
3661 dmsg(2,("LSCPServer: MoveDbInstrumentDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));
3662 LSCPResultSet result;
3663 #if HAVE_SQLITE3
3664 try {
3665 InstrumentsDb::GetInstrumentsDb()->MoveDirectory(Dir, Dst);
3666 } catch (Exception e) {
3667 result.Error(e);
3668 }
3669 #else
3670 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3671 #endif
3672 return result.Produce();
3673 }
3674
3675 String LSCPServer::CopyDbInstrumentDirectory(String Dir, String Dst) {
3676 dmsg(2,("LSCPServer: CopyDbInstrumentDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));
3677 LSCPResultSet result;
3678 #if HAVE_SQLITE3
3679 try {
3680 InstrumentsDb::GetInstrumentsDb()->CopyDirectory(Dir, Dst);
3681 } catch (Exception e) {
3682 result.Error(e);
3683 }
3684 #else
3685 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3686 #endif
3687 return result.Produce();
3688 }
3689
3690 String LSCPServer::SetDbInstrumentDirectoryDescription(String Dir, String Desc) {
3691 dmsg(2,("LSCPServer: SetDbInstrumentDirectoryDescription(Dir=%s,Desc=%s)\n", Dir.c_str(), Desc.c_str()));
3692 LSCPResultSet result;
3693 #if HAVE_SQLITE3
3694 try {
3695 InstrumentsDb::GetInstrumentsDb()->SetDirectoryDescription(Dir, Desc);
3696 } catch (Exception e) {
3697 result.Error(e);
3698 }
3699 #else
3700 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3701 #endif
3702 return result.Produce();
3703 }
3704
3705 String LSCPServer::AddDbInstruments(String DbDir, String FilePath, int Index, bool bBackground) {
3706 dmsg(2,("LSCPServer: AddDbInstruments(DbDir=%s,FilePath=%s,Index=%d,bBackground=%d)\n", DbDir.c_str(), FilePath.c_str(), Index, bBackground));
3707 LSCPResultSet result;
3708 #if HAVE_SQLITE3
3709 try {
3710 int id;
3711 InstrumentsDb* db = InstrumentsDb::GetInstrumentsDb();
3712 id = db->AddInstruments(DbDir, FilePath, Index, bBackground);
3713 if (bBackground) result = id;
3714 } catch (Exception e) {
3715 result.Error(e);
3716 }
3717 #else
3718 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3719 #endif
3720 return result.Produce();
3721 }
3722
3723 String LSCPServer::AddDbInstruments(String ScanMode, String DbDir, String FsDir, bool bBackground, bool insDir) {
3724 dmsg(2,("LSCPServer: AddDbInstruments(ScanMode=%s,DbDir=%s,FsDir=%s,bBackground=%d,insDir=%d)\n", ScanMode.c_str(), DbDir.c_str(), FsDir.c_str(), bBackground, insDir));
3725 LSCPResultSet result;
3726 #if HAVE_SQLITE3
3727 try {
3728 int id;
3729 InstrumentsDb* db = InstrumentsDb::GetInstrumentsDb();
3730 if (ScanMode.compare("RECURSIVE") == 0) {
3731 id = db->AddInstruments(RECURSIVE, DbDir, FsDir, bBackground, insDir);
3732 } else if (ScanMode.compare("NON_RECURSIVE") == 0) {
3733 id = db->AddInstruments(NON_RECURSIVE, DbDir, FsDir, bBackground, insDir);
3734 } else if (ScanMode.compare("FLAT") == 0) {
3735 id = db->AddInstruments(FLAT, DbDir, FsDir, bBackground, insDir);
3736 } else {
3737 throw Exception("Unknown scan mode: " + ScanMode);
3738 }
3739
3740 if (bBackground) result = id;
3741 } catch (Exception e) {
3742 result.Error(e);
3743 }
3744 #else
3745 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3746 #endif
3747 return result.Produce();
3748 }
3749
3750 String LSCPServer::RemoveDbInstrument(String Instr) {
3751 dmsg(2,("LSCPServer: RemoveDbInstrument(Instr=%s)\n", Instr.c_str()));
3752 LSCPResultSet result;
3753 #if HAVE_SQLITE3
3754 try {
3755 InstrumentsDb::GetInstrumentsDb()->RemoveInstrument(Instr);
3756 } catch (Exception e) {
3757 result.Error(e);
3758 }
3759 #else
3760 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3761 #endif
3762 return result.Produce();
3763 }
3764
3765 String LSCPServer::GetDbInstrumentCount(String Dir, bool Recursive) {
3766 dmsg(2,("LSCPServer: GetDbInstrumentCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
3767 LSCPResultSet result;
3768 #if HAVE_SQLITE3
3769 try {
3770 result.Add(InstrumentsDb::GetInstrumentsDb()->GetInstrumentCount(Dir, Recursive));
3771 } catch (Exception e) {
3772 result.Error(e);
3773 }
3774 #else
3775 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3776 #endif
3777 return result.Produce();
3778 }
3779
3780 String LSCPServer::GetDbInstruments(String Dir, bool Recursive) {
3781 dmsg(2,("LSCPServer: GetDbInstruments(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
3782 LSCPResultSet result;
3783 #if HAVE_SQLITE3
3784 try {
3785 String list;
3786 StringListPtr instrs = InstrumentsDb::GetInstrumentsDb()->GetInstruments(Dir, Recursive);
3787
3788 for (int i = 0; i < instrs->size(); i++) {
3789 if (list != "") list += ",";
3790 list += "'" + InstrumentsDb::toEscapedPath(instrs->at(i)) + "'";
3791 }
3792
3793 result.Add(list);
3794 } catch (Exception e) {
3795 result.Error(e);
3796 }
3797 #else
3798 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3799 #endif
3800 return result.Produce();
3801 }
3802
3803 String LSCPServer::GetDbInstrumentInfo(String Instr) {
3804 dmsg(2,("LSCPServer: GetDbInstrumentInfo(Instr=%s)\n", Instr.c_str()));
3805 LSCPResultSet result;
3806 #if HAVE_SQLITE3
3807 try {
3808 DbInstrument info = InstrumentsDb::GetInstrumentsDb()->GetInstrumentInfo(Instr);
3809
3810 result.Add("INSTRUMENT_FILE", info.InstrFile);
3811 result.Add("INSTRUMENT_NR", info.InstrNr);
3812 result.Add("FORMAT_FAMILY", info.FormatFamily);
3813 result.Add("FORMAT_VERSION", info.FormatVersion);
3814 result.Add("SIZE", (int)info.Size);
3815 result.Add("CREATED", info.Created);
3816 result.Add("MODIFIED", info.Modified);
3817 result.Add("DESCRIPTION", _escapeLscpResponse(info.Description));
3818 result.Add("IS_DRUM", info.IsDrum);
3819 result.Add("PRODUCT", _escapeLscpResponse(info.Product));
3820 result.Add("ARTISTS", _escapeLscpResponse(info.Artists));
3821 result.Add("KEYWORDS", _escapeLscpResponse(info.Keywords));
3822 } catch (Exception e) {
3823 result.Error(e);
3824 }
3825 #else
3826 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3827 #endif
3828 return result.Produce();
3829 }
3830
3831 String LSCPServer::GetDbInstrumentsJobInfo(int JobId) {
3832 dmsg(2,("LSCPServer: GetDbInstrumentsJobInfo(JobId=%d)\n", JobId));
3833 LSCPResultSet result;
3834 #if HAVE_SQLITE3
3835 try {
3836 ScanJob job = InstrumentsDb::GetInstrumentsDb()->Jobs.GetJobById(JobId);
3837
3838 result.Add("FILES_TOTAL", job.FilesTotal);
3839 result.Add("FILES_SCANNED", job.FilesScanned);
3840 result.Add("SCANNING", job.Scanning);
3841 result.Add("STATUS", job.Status);
3842 } catch (Exception e) {
3843 result.Error(e);
3844 }
3845 #else
3846 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3847 #endif
3848 return result.Produce();
3849 }
3850
3851 String LSCPServer::SetDbInstrumentName(String Instr, String Name) {
3852 dmsg(2,("LSCPServer: SetDbInstrumentName(Instr=%s,Name=%s)\n", Instr.c_str(), Name.c_str()));
3853 LSCPResultSet result;
3854 #if HAVE_SQLITE3
3855 try {
3856 InstrumentsDb::GetInstrumentsDb()->RenameInstrument(Instr, Name);
3857 } catch (Exception e) {
3858 result.Error(e);
3859 }
3860 #else
3861 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3862 #endif
3863 return result.Produce();
3864 }
3865
3866 String LSCPServer::MoveDbInstrument(String Instr, String Dst) {
3867 dmsg(2,("LSCPServer: MoveDbInstrument(Instr=%s,Dst=%s)\n", Instr.c_str(), Dst.c_str()));
3868 LSCPResultSet result;
3869 #if HAVE_SQLITE3
3870 try {
3871 InstrumentsDb::GetInstrumentsDb()->MoveInstrument(Instr, Dst);
3872 } catch (Exception e) {
3873 result.Error(e);
3874 }
3875 #else
3876 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3877 #endif
3878 return result.Produce();
3879 }
3880
3881 String LSCPServer::CopyDbInstrument(String Instr, String Dst) {
3882 dmsg(2,("LSCPServer: CopyDbInstrument(Instr=%s,Dst=%s)\n", Instr.c_str(), Dst.c_str()));
3883 LSCPResultSet result;
3884 #if HAVE_SQLITE3
3885 try {
3886 InstrumentsDb::GetInstrumentsDb()->CopyInstrument(Instr, Dst);
3887 } catch (Exception e) {
3888 result.Error(e);
3889 }
3890 #else
3891 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3892 #endif
3893 return result.Produce();
3894 }
3895
3896 String LSCPServer::SetDbInstrumentDescription(String Instr, String Desc) {
3897 dmsg(2,("LSCPServer: SetDbInstrumentDescription(Instr=%s,Desc=%s)\n", Instr.c_str(), Desc.c_str()));
3898 LSCPResultSet result;
3899 #if HAVE_SQLITE3
3900 try {
3901 InstrumentsDb::GetInstrumentsDb()->SetInstrumentDescription(Instr, Desc);
3902 } catch (Exception e) {
3903 result.Error(e);
3904 }
3905 #else
3906 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3907 #endif
3908 return result.Produce();
3909 }
3910
3911 String LSCPServer::SetDbInstrumentFilePath(String OldPath, String NewPath) {
3912 dmsg(2,("LSCPServer: SetDbInstrumentFilePath(OldPath=%s,NewPath=%s)\n", OldPath.c_str(), NewPath.c_str()));
3913 LSCPResultSet result;
3914 #if HAVE_SQLITE3
3915 try {
3916 InstrumentsDb::GetInstrumentsDb()->SetInstrumentFilePath(OldPath, NewPath);
3917 } catch (Exception e) {
3918 result.Error(e);
3919 }
3920 #else
3921 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3922 #endif
3923 return result.Produce();
3924 }
3925
3926 String LSCPServer::FindLostDbInstrumentFiles() {
3927 dmsg(2,("LSCPServer: FindLostDbInstrumentFiles()\n"));
3928 LSCPResultSet result;
3929 #if HAVE_SQLITE3
3930 try {
3931 String list;
3932 StringListPtr pLostFiles = InstrumentsDb::GetInstrumentsDb()->FindLostInstrumentFiles();
3933
3934 for (int i = 0; i < pLostFiles->size(); i++) {
3935 if (list != "") list += ",";
3936 list += "'" + pLostFiles->at(i) + "'";
3937 }
3938
3939 result.Add(list);
3940 } catch (Exception e) {
3941 result.Error(e);
3942 }
3943 #else
3944 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3945 #endif
3946 return result.Produce();
3947 }
3948
3949 String LSCPServer::FindDbInstrumentDirectories(String Dir, std::map<String,String> Parameters, bool Recursive) {
3950 dmsg(2,("LSCPServer: FindDbInstrumentDirectories(Dir=%s)\n", Dir.c_str()));
3951 LSCPResultSet result;
3952 #if HAVE_SQLITE3
3953 try {
3954 SearchQuery Query;
3955 std::map<String,String>::iterator iter;
3956 for (iter = Parameters.begin(); iter != Parameters.end(); iter++) {
3957 if (iter->first.compare("NAME") == 0) {
3958 Query.Name = iter->second;
3959 } else if (iter->first.compare("CREATED") == 0) {
3960 Query.SetCreated(iter->second);
3961 } else if (iter->first.compare("MODIFIED") == 0) {
3962 Query.SetModified(iter->second);
3963 } else if (iter->first.compare("DESCRIPTION") == 0) {
3964 Query.Description = iter->second;
3965 } else {
3966 throw Exception("Unknown search criteria: " + iter->first);
3967 }
3968 }
3969
3970 String list;
3971 StringListPtr pDirectories =
3972 InstrumentsDb::GetInstrumentsDb()->FindDirectories(Dir, &Query, Recursive);
3973
3974 for (int i = 0; i < pDirectories->size(); i++) {
3975 if (list != "") list += ",";
3976 list += "'" + InstrumentsDb::toEscapedPath(pDirectories->at(i)) + "'";
3977 }
3978
3979 result.Add(list);
3980 } catch (Exception e) {
3981 result.Error(e);
3982 }
3983 #else
3984 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3985 #endif
3986 return result.Produce();
3987 }
3988
3989 String LSCPServer::FindDbInstruments(String Dir, std::map<String,String> Parameters, bool Recursive) {
3990 dmsg(2,("LSCPServer: FindDbInstruments(Dir=%s)\n", Dir.c_str()));
3991 LSCPResultSet result;
3992 #if HAVE_SQLITE3
3993 try {
3994 SearchQuery Query;
3995 std::map<String,String>::iterator iter;
3996 for (iter = Parameters.begin(); iter != Parameters.end(); iter++) {
3997 if (iter->first.compare("NAME") == 0) {
3998 Query.Name = iter->second;
3999 } else if (iter->first.compare("FORMAT_FAMILIES") == 0) {
4000 Query.SetFormatFamilies(iter->second);
4001 } else if (iter->first.compare("SIZE") == 0) {
4002 Query.SetSize(iter->second);
4003 } else if (iter->first.compare("CREATED") == 0) {
4004 Query.SetCreated(iter->second);
4005 } else if (iter->first.compare("MODIFIED") == 0) {
4006 Query.SetModified(iter->second);
4007 } else if (iter->first.compare("DESCRIPTION") == 0) {
4008 Query.Description = iter->second;
4009 } else if (iter->first.compare("IS_DRUM") == 0) {
4010 if (!strcasecmp(iter->second.c_str(), "true")) {
4011 Query.InstrType = SearchQuery::DRUM;
4012 } else {
4013 Query.InstrType = SearchQuery::CHROMATIC;
4014 }
4015 } else if (iter->first.compare("PRODUCT") == 0) {
4016 Query.Product = iter->second;
4017 } else if (iter->first.compare("ARTISTS") == 0) {
4018 Query.Artists = iter->second;
4019 } else if (iter->first.compare("KEYWORDS") == 0) {
4020 Query.Keywords = iter->second;
4021 } else {
4022 throw Exception("Unknown search criteria: " + iter->first);
4023 }
4024 }
4025
4026 String list;
4027 StringListPtr pInstruments =
4028 InstrumentsDb::GetInstrumentsDb()->FindInstruments(Dir, &Query, Recursive);
4029
4030 for (int i = 0; i < pInstruments->size(); i++) {
4031 if (list != "") list += ",";
4032 list += "'" + InstrumentsDb::toEscapedPath(pInstruments->at(i)) + "'";
4033 }
4034
4035 result.Add(list);
4036 } catch (Exception e) {
4037 result.Error(e);
4038 }
4039 #else
4040 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
4041 #endif
4042 return result.Produce();
4043 }
4044
4045 String LSCPServer::FormatInstrumentsDb() {
4046 dmsg(2,("LSCPServer: FormatInstrumentsDb()\n"));
4047 LSCPResultSet result;
4048 #if HAVE_SQLITE3
4049 try {
4050 InstrumentsDb::GetInstrumentsDb()->Format();
4051 } catch (Exception e) {
4052 result.Error(e);
4053 }
4054 #else
4055 result.Error(String(DOESNT_HAVE_SQLITE3), 0);
4056 #endif
4057 return result.Produce();
4058 }
4059
4060
4061 /**
4062 * Will be called by the parser to enable or disable echo mode; if echo
4063 * mode is enabled, all commands from the client will (immediately) be
4064 * echoed back to the client.
4065 */
4066 String LSCPServer::SetEcho(yyparse_param_t* pSession, double boolean_value) {
4067 dmsg(2,("LSCPServer: SetEcho(val=%f)\n", boolean_value));
4068 LSCPResultSet result;
4069 try {
4070 if (boolean_value == 0) pSession->bVerbose = false;
4071 else if (boolean_value == 1) pSession->bVerbose = true;
4072 else throw Exception("Not a boolean value, must either be 0 or 1");
4073 }
4074 catch (Exception e) {
4075 result.Error(e);
4076 }
4077 return result.Produce();
4078 }
4079
4080 String LSCPServer::SetShellInteract(yyparse_param_t* pSession, double boolean_value) {
4081 dmsg(2,("LSCPServer: SetShellInteract(val=%f)\n", boolean_value));
4082 LSCPResultSet result;
4083 try {
4084 if (boolean_value == 0) pSession->bShellInteract = false;
4085 else if (boolean_value == 1) pSession->bShellInteract = true;
4086 else throw Exception("Not a boolean value, must either be 0 or 1");
4087 } catch (Exception e) {
4088 result.Error(e);
4089 }
4090 return result.Produce();
4091 }
4092
4093 String LSCPServer::SetShellAutoCorrect(yyparse_param_t* pSession, double boolean_value) {
4094 dmsg(2,("LSCPServer: SetShellAutoCorrect(val=%f)\n", boolean_value));
4095 LSCPResultSet result;
4096 try {
4097 if (boolean_value == 0) pSession->bShellAutoCorrect = false;
4098 else if (boolean_value == 1) pSession->bShellAutoCorrect = true;
4099 else throw Exception("Not a boolean value, must either be 0 or 1");
4100 } catch (Exception e) {
4101 result.Error(e);
4102 }
4103 return result.Produce();
4104 }
4105
4106 String LSCPServer::SetShellDoc(yyparse_param_t* pSession, double boolean_value) {
4107 dmsg(2,("LSCPServer: SetShellDoc(val=%f)\n", boolean_value));
4108 LSCPResultSet result;
4109 try {
4110 if (boolean_value == 0) pSession->bShellSendLSCPDoc = false;
4111 else if (boolean_value == 1) pSession->bShellSendLSCPDoc = true;
4112 else throw Exception("Not a boolean value, must either be 0 or 1");
4113 } catch (Exception e) {
4114 result.Error(e);
4115 }
4116 return result.Produce();
4117 }
4118
4119 }

  ViewVC Help
Powered by ViewVC