/[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 2837 - (show annotations) (download)
Sun Aug 23 06:14:00 2015 UTC (8 years, 7 months ago) by persson
File size: 166014 byte(s)
* fixed printf type errors (mostly in debug messages)


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(),int(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(),int(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=%u,ChannelId=%u)\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