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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1212 by schoenebeck, Tue May 29 23:59:36 2007 UTC revision 3766 by schoenebeck, Mon Apr 6 12:41:49 2020 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6   *   Copyright (C) 2005 - 2007 Christian Schoenebeck                       *   *   Copyright (C) 2005 - 2020 Christian Schoenebeck                       *
7   *                                                                         *   *                                                                         *
8   *   This library is free software; you can redistribute it and/or modify  *   *   This library is free software; you can redistribute it and/or modify  *
9   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 21  Line 21 
21   *   MA  02111-1307  USA                                                   *   *   MA  02111-1307  USA                                                   *
22   ***************************************************************************/   ***************************************************************************/
23    
24    #include <algorithm>
25    #include <string>
26    
27    #include "../common/File.h"
28  #include "lscpserver.h"  #include "lscpserver.h"
29  #include "lscpresultset.h"  #include "lscpresultset.h"
30  #include "lscpevent.h"  #include "lscpevent.h"
31    
32    #if defined(WIN32)
33    #include <windows.h>
34    typedef unsigned short in_port_t;
35    typedef unsigned long in_addr_t;
36    #else
37  #include <fcntl.h>  #include <fcntl.h>
38    #endif
39    
40  #if ! HAVE_SQLITE3  #if ! HAVE_SQLITE3
41  #define DOESNT_HAVE_SQLITE3 "No database support. SQLITE3 was not installed when linuxsampler was built."  #define DOESNT_HAVE_SQLITE3 "No database support. SQLITE3 was not installed when linuxsampler was built."
# Line 35  Line 45 
45  #include "../engines/EngineChannelFactory.h"  #include "../engines/EngineChannelFactory.h"
46  #include "../drivers/audio/AudioOutputDeviceFactory.h"  #include "../drivers/audio/AudioOutputDeviceFactory.h"
47  #include "../drivers/midi/MidiInputDeviceFactory.h"  #include "../drivers/midi/MidiInputDeviceFactory.h"
48    #include "../effects/EffectFactory.h"
49    
50    namespace LinuxSampler {
51    
52    String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param, bool possibilities);
53    
54    /**
55     * Returns a copy of the given string where all special characters are
56     * replaced by LSCP escape sequences ("\xHH"). This function shall be used
57     * to escape LSCP response fields in case the respective response field is
58     * actually defined as using escape sequences in the LSCP specs.
59     *
60     * @e Caution: DO NOT use this function for escaping path based responses,
61     * use the Path class (src/common/Path.h) for this instead!
62     */
63    static String _escapeLscpResponse(String txt) {
64        for (int i = 0; i < txt.length(); i++) {
65            const char c = txt.c_str()[i];
66            if (
67                !(c >= '0' && c <= '9') &&
68                !(c >= 'a' && c <= 'z') &&
69                !(c >= 'A' && c <= 'Z') &&
70                !(c == ' ') && !(c == '!') && !(c == '#') && !(c == '$') &&
71                !(c == '%') && !(c == '&') && !(c == '(') && !(c == ')') &&
72                !(c == '*') && !(c == '+') && !(c == ',') && !(c == '-') &&
73                !(c == '.') && !(c == '/') && !(c == ':') && !(c == ';') &&
74                !(c == '<') && !(c == '=') && !(c == '>') && !(c == '?') &&
75                !(c == '@') && !(c == '[') && !(c == ']') &&
76                !(c == '^') && !(c == '_') && !(c == '`') && !(c == '{') &&
77                !(c == '|') && !(c == '}') && !(c == '~')
78            ) {
79                // convert the "special" character into a "\xHH" LSCP escape sequence
80                char buf[5];
81                snprintf(buf, sizeof(buf), "\\x%02x", static_cast<unsigned char>(c));
82                txt.replace(i, 1, buf);
83                i += 3;
84            }
85        }
86        return txt;
87    }
88    
89  /**  /**
90   * Below are a few static members of the LSCPServer class.   * Below are a few static members of the LSCPServer class.
# Line 51  Line 101 
101   */   */
102  fd_set LSCPServer::fdSet;  fd_set LSCPServer::fdSet;
103  int LSCPServer::currentSocket = -1;  int LSCPServer::currentSocket = -1;
104  std::vector<yyparse_param_t> LSCPServer::Sessions = std::vector<yyparse_param_t>();  std::vector<yyparse_param_t> LSCPServer::Sessions;
105  std::map<int,String> LSCPServer::bufferedNotifies = std::map<int,String>();  std::vector<yyparse_param_t>::iterator itCurrentSession;
106  std::map<int,String> LSCPServer::bufferedCommands = std::map<int,String>();  std::map<int,String> LSCPServer::bufferedNotifies;
107  std::map< LSCPEvent::event_t, std::list<int> > LSCPServer::eventSubscriptions = std::map< LSCPEvent::event_t, std::list<int> >();  std::map<int,String> LSCPServer::bufferedCommands;
108  Mutex LSCPServer::NotifyMutex = Mutex();  std::map< LSCPEvent::event_t, std::list<int> > LSCPServer::eventSubscriptions;
109  Mutex LSCPServer::NotifyBufferMutex = Mutex();  Mutex LSCPServer::NotifyMutex;
110  Mutex LSCPServer::SubscriptionMutex = Mutex();  Mutex LSCPServer::NotifyBufferMutex;
111  Mutex LSCPServer::RTNotifyMutex = Mutex();  Mutex LSCPServer::SubscriptionMutex;
112    Mutex LSCPServer::RTNotifyMutex;
113    
114  LSCPServer::LSCPServer(Sampler* pSampler, long int addr, short int port) : Thread(true, false, 0, -4) {  LSCPServer::LSCPServer(Sampler* pSampler, long int addr, short int port) : Thread(true, false, 0, -4), eventHandler(this) {
115      SocketAddress.sin_family      = AF_INET;      SocketAddress.sin_family      = AF_INET;
116      SocketAddress.sin_addr.s_addr = addr;      SocketAddress.sin_addr.s_addr = (in_addr_t)addr;
117      SocketAddress.sin_port        = port;      SocketAddress.sin_port        = (in_port_t)port;
118      this->pSampler = pSampler;      this->pSampler = pSampler;
119      LSCPEvent::RegisterEvent(LSCPEvent::event_audio_device_count, "AUDIO_OUTPUT_DEVICE_COUNT");      LSCPEvent::RegisterEvent(LSCPEvent::event_audio_device_count, "AUDIO_OUTPUT_DEVICE_COUNT");
120      LSCPEvent::RegisterEvent(LSCPEvent::event_audio_device_info, "AUDIO_OUTPUT_DEVICE_INFO");      LSCPEvent::RegisterEvent(LSCPEvent::event_audio_device_info, "AUDIO_OUTPUT_DEVICE_INFO");
# Line 86  LSCPServer::LSCPServer(Sampler* pSampler Line 137  LSCPServer::LSCPServer(Sampler* pSampler
137      LSCPEvent::RegisterEvent(LSCPEvent::event_db_instr_info, "DB_INSTRUMENT_INFO");      LSCPEvent::RegisterEvent(LSCPEvent::event_db_instr_info, "DB_INSTRUMENT_INFO");
138      LSCPEvent::RegisterEvent(LSCPEvent::event_db_instrs_job_info, "DB_INSTRUMENTS_JOB_INFO");      LSCPEvent::RegisterEvent(LSCPEvent::event_db_instrs_job_info, "DB_INSTRUMENTS_JOB_INFO");
139      LSCPEvent::RegisterEvent(LSCPEvent::event_misc, "MISCELLANEOUS");      LSCPEvent::RegisterEvent(LSCPEvent::event_misc, "MISCELLANEOUS");
140        LSCPEvent::RegisterEvent(LSCPEvent::event_total_stream_count, "TOTAL_STREAM_COUNT");
141      LSCPEvent::RegisterEvent(LSCPEvent::event_total_voice_count, "TOTAL_VOICE_COUNT");      LSCPEvent::RegisterEvent(LSCPEvent::event_total_voice_count, "TOTAL_VOICE_COUNT");
142      LSCPEvent::RegisterEvent(LSCPEvent::event_global_info, "GLOBAL_INFO");      LSCPEvent::RegisterEvent(LSCPEvent::event_global_info, "GLOBAL_INFO");
143        LSCPEvent::RegisterEvent(LSCPEvent::event_channel_midi, "CHANNEL_MIDI");
144        LSCPEvent::RegisterEvent(LSCPEvent::event_device_midi, "DEVICE_MIDI");
145        LSCPEvent::RegisterEvent(LSCPEvent::event_fx_instance_count, "EFFECT_INSTANCE_COUNT");
146        LSCPEvent::RegisterEvent(LSCPEvent::event_fx_instance_info, "EFFECT_INSTANCE_INFO");
147        LSCPEvent::RegisterEvent(LSCPEvent::event_send_fx_chain_count, "SEND_EFFECT_CHAIN_COUNT");
148        LSCPEvent::RegisterEvent(LSCPEvent::event_send_fx_chain_info, "SEND_EFFECT_CHAIN_INFO");
149      hSocket = -1;      hSocket = -1;
150  }  }
151    
152  LSCPServer::~LSCPServer() {  LSCPServer::~LSCPServer() {
153        CloseAllConnections();
154        InstrumentManager::StopBackgroundThread();
155    #if defined(WIN32)
156        if (hSocket >= 0) closesocket(hSocket);
157    #else
158      if (hSocket >= 0) close(hSocket);      if (hSocket >= 0) close(hSocket);
159    #endif
160    }
161    
162    LSCPServer::EventHandler::EventHandler(LSCPServer* pParent) {
163        this->pParent = pParent;
164    }
165    
166    LSCPServer::EventHandler::~EventHandler() {
167        std::vector<midi_listener_entry> l = channelMidiListeners;
168        channelMidiListeners.clear();
169        for (int i = 0; i < l.size(); i++)
170            delete l[i].pMidiListener;
171  }  }
172    
173  void LSCPServer::EventHandler::ChannelCountChanged(int NewCount) {  void LSCPServer::EventHandler::ChannelCountChanged(int NewCount) {
174      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_channel_count, NewCount));      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_channel_count, NewCount));
175  }  }
176    
177    void LSCPServer::EventHandler::ChannelAdded(SamplerChannel* pChannel) {
178        pChannel->AddEngineChangeListener(this);
179    }
180    
181    void LSCPServer::EventHandler::ChannelToBeRemoved(SamplerChannel* pChannel) {
182        if (!pChannel->GetEngineChannel()) return;
183        EngineToBeChanged(pChannel->Index());
184    }
185    
186    void LSCPServer::EventHandler::EngineToBeChanged(int ChannelId) {
187        SamplerChannel* pSamplerChannel =
188            pParent->pSampler->GetSamplerChannel(ChannelId);
189        if (!pSamplerChannel) return;
190        EngineChannel* pEngineChannel =
191            pSamplerChannel->GetEngineChannel();
192        if (!pEngineChannel) return;
193        for (std::vector<midi_listener_entry>::iterator iter = channelMidiListeners.begin(); iter != channelMidiListeners.end(); ++iter) {
194            if ((*iter).pEngineChannel == pEngineChannel) {
195                VirtualMidiDevice* pMidiListener = (*iter).pMidiListener;
196                pEngineChannel->Disconnect(pMidiListener);
197                channelMidiListeners.erase(iter);
198                delete pMidiListener;
199                return;
200            }
201        }
202    }
203    
204    void LSCPServer::EventHandler::EngineChanged(int ChannelId) {
205        SamplerChannel* pSamplerChannel =
206            pParent->pSampler->GetSamplerChannel(ChannelId);
207        if (!pSamplerChannel) return;
208        EngineChannel* pEngineChannel =
209            pSamplerChannel->GetEngineChannel();
210        if (!pEngineChannel) return;
211        VirtualMidiDevice* pMidiListener = new VirtualMidiDevice;
212        pEngineChannel->Connect(pMidiListener);
213        midi_listener_entry entry = {
214            pSamplerChannel, pEngineChannel, pMidiListener
215        };
216        channelMidiListeners.push_back(entry);
217    }
218    
219  void LSCPServer::EventHandler::AudioDeviceCountChanged(int NewCount) {  void LSCPServer::EventHandler::AudioDeviceCountChanged(int NewCount) {
220      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_audio_device_count, NewCount));      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_audio_device_count, NewCount));
221  }  }
# Line 107  void LSCPServer::EventHandler::MidiDevic Line 224  void LSCPServer::EventHandler::MidiDevic
224      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_device_count, NewCount));      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_device_count, NewCount));
225  }  }
226    
227    void LSCPServer::EventHandler::MidiDeviceToBeDestroyed(MidiInputDevice* pDevice) {
228        pDevice->RemoveMidiPortCountListener(this);
229        for (int i = 0; i < pDevice->PortCount(); ++i)
230            MidiPortToBeRemoved(pDevice->GetPort(i));
231    }
232    
233    void LSCPServer::EventHandler::MidiDeviceCreated(MidiInputDevice* pDevice) {
234        pDevice->AddMidiPortCountListener(this);
235        for (int i = 0; i < pDevice->PortCount(); ++i)
236            MidiPortAdded(pDevice->GetPort(i));
237    }
238    
239    void LSCPServer::EventHandler::MidiPortCountChanged(int NewCount) {
240        // yet unused
241    }
242    
243    void LSCPServer::EventHandler::MidiPortToBeRemoved(MidiInputPort* pPort) {
244        for (std::vector<device_midi_listener_entry>::iterator iter = deviceMidiListeners.begin(); iter != deviceMidiListeners.end(); ++iter) {
245            if ((*iter).pPort == pPort) {
246                VirtualMidiDevice* pMidiListener = (*iter).pMidiListener;
247                pPort->Disconnect(pMidiListener);
248                deviceMidiListeners.erase(iter);
249                delete pMidiListener;
250                return;
251            }
252        }
253    }
254    
255    void LSCPServer::EventHandler::MidiPortAdded(MidiInputPort* pPort) {
256        // find out the device ID
257        std::map<uint, MidiInputDevice*> devices =
258            pParent->pSampler->GetMidiInputDevices();
259        for (
260            std::map<uint, MidiInputDevice*>::iterator iter = devices.begin();
261            iter != devices.end(); ++iter
262        ) {
263            if (iter->second == pPort->GetDevice()) { // found
264                VirtualMidiDevice* pMidiListener = new VirtualMidiDevice;
265                pPort->Connect(pMidiListener);
266                device_midi_listener_entry entry = {
267                    pPort, pMidiListener, iter->first
268                };
269                deviceMidiListeners.push_back(entry);
270                return;
271            }
272        }
273    }
274    
275  void LSCPServer::EventHandler::MidiInstrumentCountChanged(int MapId, int NewCount) {  void LSCPServer::EventHandler::MidiInstrumentCountChanged(int MapId, int NewCount) {
276      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_count, MapId, NewCount));      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_count, MapId, NewCount));
277  }  }
# Line 143  void LSCPServer::EventHandler::TotalVoic Line 308  void LSCPServer::EventHandler::TotalVoic
308      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_total_voice_count, NewCount));      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_total_voice_count, NewCount));
309  }  }
310    
311    void LSCPServer::EventHandler::TotalStreamCountChanged(int NewCount) {
312        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_total_stream_count, NewCount));
313    }
314    
315  #if HAVE_SQLITE3  #if HAVE_SQLITE3
316  void LSCPServer::DbInstrumentsEventHandler::DirectoryCountChanged(String Dir) {  void LSCPServer::DbInstrumentsEventHandler::DirectoryCountChanged(String Dir) {
317      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_dir_count, Dir));      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_dir_count, InstrumentsDb::toEscapedPath(Dir)));
318  }  }
319    
320  void LSCPServer::DbInstrumentsEventHandler::DirectoryInfoChanged(String Dir) {  void LSCPServer::DbInstrumentsEventHandler::DirectoryInfoChanged(String Dir) {
321      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_dir_info, Dir));      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_dir_info, InstrumentsDb::toEscapedPath(Dir)));
322  }  }
323    
324  void LSCPServer::DbInstrumentsEventHandler::DirectoryNameChanged(String Dir, String NewName) {  void LSCPServer::DbInstrumentsEventHandler::DirectoryNameChanged(String Dir, String NewName) {
325      Dir = "'" + Dir + "'";      Dir = "'" + InstrumentsDb::toEscapedPath(Dir) + "'";
326      NewName = "'" + NewName + "'";      NewName = "'" + InstrumentsDb::toEscapedPath(NewName) + "'";
327      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_dir_info, "NAME", Dir, NewName));      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_dir_info, "NAME", Dir, NewName));
328  }  }
329    
330  void LSCPServer::DbInstrumentsEventHandler::InstrumentCountChanged(String Dir) {  void LSCPServer::DbInstrumentsEventHandler::InstrumentCountChanged(String Dir) {
331      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_count, Dir));      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_count, InstrumentsDb::toEscapedPath(Dir)));
332  }  }
333    
334  void LSCPServer::DbInstrumentsEventHandler::InstrumentInfoChanged(String Instr) {  void LSCPServer::DbInstrumentsEventHandler::InstrumentInfoChanged(String Instr) {
335      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_info, Instr));      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_info, InstrumentsDb::toEscapedPath(Instr)));
336  }  }
337    
338  void LSCPServer::DbInstrumentsEventHandler::InstrumentNameChanged(String Instr, String NewName) {  void LSCPServer::DbInstrumentsEventHandler::InstrumentNameChanged(String Instr, String NewName) {
339      Instr = "'" + Instr + "'";      Instr = "'" + InstrumentsDb::toEscapedPath(Instr) + "'";
340      NewName = "'" + NewName + "'";      NewName = "'" + InstrumentsDb::toEscapedPath(NewName) + "'";
341      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_info, "NAME", Instr, NewName));      LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_info, "NAME", Instr, NewName));
342  }  }
343    
# Line 177  void LSCPServer::DbInstrumentsEventHandl Line 346  void LSCPServer::DbInstrumentsEventHandl
346  }  }
347  #endif // HAVE_SQLITE3  #endif // HAVE_SQLITE3
348    
349    void LSCPServer::RemoveListeners() {
350        pSampler->RemoveChannelCountListener(&eventHandler);
351        pSampler->RemoveAudioDeviceCountListener(&eventHandler);
352        pSampler->RemoveMidiDeviceCountListener(&eventHandler);
353        pSampler->RemoveVoiceCountListener(&eventHandler);
354        pSampler->RemoveStreamCountListener(&eventHandler);
355        pSampler->RemoveBufferFillListener(&eventHandler);
356        pSampler->RemoveTotalStreamCountListener(&eventHandler);
357        pSampler->RemoveTotalVoiceCountListener(&eventHandler);
358        pSampler->RemoveFxSendCountListener(&eventHandler);
359        MidiInstrumentMapper::RemoveMidiInstrumentCountListener(&eventHandler);
360        MidiInstrumentMapper::RemoveMidiInstrumentInfoListener(&eventHandler);
361        MidiInstrumentMapper::RemoveMidiInstrumentMapCountListener(&eventHandler);
362        MidiInstrumentMapper::RemoveMidiInstrumentMapInfoListener(&eventHandler);
363    #if HAVE_SQLITE3
364        InstrumentsDb::GetInstrumentsDb()->RemoveInstrumentsDbListener(&dbInstrumentsEventHandler);
365    #endif
366    }
367    
368  /**  /**
369   * Blocks the calling thread until the LSCP Server is initialized and   * Blocks the calling thread until the LSCP Server is initialized and
# Line 193  int LSCPServer::WaitUntilInitialized(lon Line 380  int LSCPServer::WaitUntilInitialized(lon
380  }  }
381    
382  int LSCPServer::Main() {  int LSCPServer::Main() {
383        #if DEBUG
384        Thread::setNameOfCaller("LSCPServer");
385        #endif
386    
387            #if defined(WIN32)
388            WSADATA wsaData;
389            int iResult;
390            iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
391            if (iResult != 0) {
392                    std::cerr << "LSCPServer: WSAStartup failed: " << iResult << "\n";
393                    exit(EXIT_FAILURE);
394            }
395            #endif
396      hSocket = socket(AF_INET, SOCK_STREAM, 0);      hSocket = socket(AF_INET, SOCK_STREAM, 0);
397      if (hSocket < 0) {      if (hSocket < 0) {
398          std::cerr << "LSCPServer: Could not create server socket." << std::endl;          std::cerr << "LSCPServer: Could not create server socket." << std::endl;
# Line 206  int LSCPServer::Main() { Line 406  int LSCPServer::Main() {
406              if (bind(hSocket, (sockaddr*) &SocketAddress, sizeof(sockaddr_in)) < 0) {              if (bind(hSocket, (sockaddr*) &SocketAddress, sizeof(sockaddr_in)) < 0) {
407                  if (trial > LSCP_SERVER_BIND_TIMEOUT) {                  if (trial > LSCP_SERVER_BIND_TIMEOUT) {
408                      std::cerr << "gave up!" << std::endl;                      std::cerr << "gave up!" << std::endl;
409                        #if defined(WIN32)
410                        closesocket(hSocket);
411                        #else
412                      close(hSocket);                      close(hSocket);
413                        #endif
414                      //return -1;                      //return -1;
415                      exit(EXIT_FAILURE);                      exit(EXIT_FAILURE);
416                  }                  }
# Line 218  int LSCPServer::Main() { Line 422  int LSCPServer::Main() {
422    
423      listen(hSocket, 1);      listen(hSocket, 1);
424      Initialized.Set(true);      Initialized.Set(true);
425        
426      // Registering event listeners      // Registering event listeners
427      pSampler->AddChannelCountListener(&eventHandler);      pSampler->AddChannelCountListener(&eventHandler);
428      pSampler->AddAudioDeviceCountListener(&eventHandler);      pSampler->AddAudioDeviceCountListener(&eventHandler);
# Line 226  int LSCPServer::Main() { Line 430  int LSCPServer::Main() {
430      pSampler->AddVoiceCountListener(&eventHandler);      pSampler->AddVoiceCountListener(&eventHandler);
431      pSampler->AddStreamCountListener(&eventHandler);      pSampler->AddStreamCountListener(&eventHandler);
432      pSampler->AddBufferFillListener(&eventHandler);      pSampler->AddBufferFillListener(&eventHandler);
433        pSampler->AddTotalStreamCountListener(&eventHandler);
434      pSampler->AddTotalVoiceCountListener(&eventHandler);      pSampler->AddTotalVoiceCountListener(&eventHandler);
435      pSampler->AddFxSendCountListener(&eventHandler);      pSampler->AddFxSendCountListener(&eventHandler);
436      MidiInstrumentMapper::AddMidiInstrumentCountListener(&eventHandler);      MidiInstrumentMapper::AddMidiInstrumentCountListener(&eventHandler);
# Line 245  int LSCPServer::Main() { Line 450  int LSCPServer::Main() {
450      timeval timeout;      timeval timeout;
451    
452      while (true) {      while (true) {
453    
454                    TestCancel();
455    
456            // prevent thread from being cancelled
457            // (e.g. to prevent deadlocks while holding mutex lock(s))
458            pushCancelable(false);
459    
460          // check if some engine channel's parameter / status changed, if so notify the respective LSCP event subscribers          // check if some engine channel's parameter / status changed, if so notify the respective LSCP event subscribers
461          {          {
462                LockGuard lock(EngineChannelFactory::EngineChannelsMutex);
463              std::set<EngineChannel*> engineChannels = EngineChannelFactory::EngineChannelInstances();              std::set<EngineChannel*> engineChannels = EngineChannelFactory::EngineChannelInstances();
464              std::set<EngineChannel*>::iterator itEngineChannel = engineChannels.begin();              std::set<EngineChannel*>::iterator itEngineChannel = engineChannels.begin();
465              std::set<EngineChannel*>::iterator itEnd           = engineChannels.end();              std::set<EngineChannel*>::iterator itEnd           = engineChannels.end();
466              for (; itEngineChannel != itEnd; ++itEngineChannel) {              for (; itEngineChannel != itEnd; ++itEngineChannel) {
467                  if ((*itEngineChannel)->StatusChanged()) {                  if ((*itEngineChannel)->StatusChanged()) {
468                      SendLSCPNotify(LSCPEvent(LSCPEvent::event_channel_info, (*itEngineChannel)->iSamplerChannelIndex));                      SendLSCPNotify(LSCPEvent(LSCPEvent::event_channel_info, (*itEngineChannel)->GetSamplerChannel()->Index()));
469                  }                  }
470    
471                  for (int i = 0; i < (*itEngineChannel)->GetFxSendCount(); i++) {                  for (int i = 0; i < (*itEngineChannel)->GetFxSendCount(); i++) {
472                      FxSend* fxs = (*itEngineChannel)->GetFxSend(i);                      FxSend* fxs = (*itEngineChannel)->GetFxSend(i);
473                      if(fxs != NULL && fxs->IsInfoChanged()) {                      if(fxs != NULL && fxs->IsInfoChanged()) {
474                          int chn = (*itEngineChannel)->iSamplerChannelIndex;                          int chn = (*itEngineChannel)->GetSamplerChannel()->Index();
475                          LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_info, chn, fxs->Id()));                          LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_info, chn, fxs->Id()));
476                          fxs->SetInfoChanged(false);                          fxs->SetInfoChanged(false);
477                      }                      }
# Line 266  int LSCPServer::Main() { Line 479  int LSCPServer::Main() {
479              }              }
480          }          }
481    
482          //Now let's deliver late notifies (if any)          // check if MIDI data arrived on some engine channel
483          NotifyBufferMutex.Lock();          for (int i = 0; i < eventHandler.channelMidiListeners.size(); ++i) {
484          for (std::map<int,String>::iterator iterNotify = bufferedNotifies.begin(); iterNotify != bufferedNotifies.end(); iterNotify++) {              const EventHandler::midi_listener_entry entry =
485                    eventHandler.channelMidiListeners[i];
486                VirtualMidiDevice* pMidiListener = entry.pMidiListener;
487                if (pMidiListener->NotesChanged()) {
488                    for (int iNote = 0; iNote < 128; iNote++) {
489                        if (pMidiListener->NoteChanged(iNote)) {
490                            const bool bActive = pMidiListener->NoteIsActive(iNote);
491                            LSCPServer::SendLSCPNotify(
492                                LSCPEvent(
493                                    LSCPEvent::event_channel_midi,
494                                    entry.pSamplerChannel->Index(),
495                                    std::string(bActive ? "NOTE_ON" : "NOTE_OFF"),
496                                    iNote,
497                                    bActive ? pMidiListener->NoteOnVelocity(iNote)
498                                            : pMidiListener->NoteOffVelocity(iNote)
499                                )
500                            );
501                        }
502                    }
503                }
504            }
505    
506            // check if MIDI data arrived on some MIDI device
507            for (int i = 0; i < eventHandler.deviceMidiListeners.size(); ++i) {
508                const EventHandler::device_midi_listener_entry entry =
509                    eventHandler.deviceMidiListeners[i];
510                VirtualMidiDevice* pMidiListener = entry.pMidiListener;
511                if (pMidiListener->NotesChanged()) {
512                    for (int iNote = 0; iNote < 128; iNote++) {
513                        if (pMidiListener->NoteChanged(iNote)) {
514                            const bool bActive = pMidiListener->NoteIsActive(iNote);
515                            LSCPServer::SendLSCPNotify(
516                                LSCPEvent(
517                                    LSCPEvent::event_device_midi,
518                                    entry.uiDeviceID,
519                                    entry.pPort->GetPortNumber(),
520                                    std::string(bActive ? "NOTE_ON" : "NOTE_OFF"),
521                                    iNote,
522                                    bActive ? pMidiListener->NoteOnVelocity(iNote)
523                                            : pMidiListener->NoteOffVelocity(iNote)
524                                )
525                            );
526                        }
527                    }
528                }
529            }
530    
531            //Now let's deliver late notifies (if any)
532            {
533                LockGuard lock(NotifyBufferMutex);
534                for (std::map<int,String>::iterator iterNotify = bufferedNotifies.begin(); iterNotify != bufferedNotifies.end(); iterNotify++) {
535  #ifdef MSG_NOSIGNAL  #ifdef MSG_NOSIGNAL
536                  send(iterNotify->first, iterNotify->second.c_str(), iterNotify->second.size(), MSG_NOSIGNAL);                  send(iterNotify->first, iterNotify->second.c_str(), iterNotify->second.size(), MSG_NOSIGNAL);
537  #else  #else
538                  send(iterNotify->first, iterNotify->second.c_str(), iterNotify->second.size(), 0);                  send(iterNotify->first, iterNotify->second.c_str(), iterNotify->second.size(), 0);
539  #endif  #endif
540          }              }
541          bufferedNotifies.clear();              bufferedNotifies.clear();
542          NotifyBufferMutex.Unlock();          }
543    
544            // now allow thread being cancelled again
545            // (since all mutexes are now unlocked)
546            popCancelable();
547    
548          fd_set selectSet = fdSet;          fd_set selectSet = fdSet;
549          timeout.tv_sec  = 0;          timeout.tv_sec  = 0;
# Line 284  int LSCPServer::Main() { Line 551  int LSCPServer::Main() {
551    
552          int retval = select(maxSessions+1, &selectSet, NULL, NULL, &timeout);          int retval = select(maxSessions+1, &selectSet, NULL, NULL, &timeout);
553    
554          if (retval == 0)          if (retval == 0 || (retval == -1 && errno == EINTR))
555                  continue; //Nothing try again                  continue; //Nothing try again
556          if (retval == -1) {          if (retval == -1) {
557                  std::cerr << "LSCPServer: Socket select error." << std::endl;                  std::cerr << "LSCPServer: Socket select error." << std::endl;
558                    #if defined(WIN32)
559                    closesocket(hSocket);
560                    #else
561                  close(hSocket);                  close(hSocket);
562                    #endif
563                  exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
564          }          }
565    
# Line 300  int LSCPServer::Main() { Line 571  int LSCPServer::Main() {
571                          exit(EXIT_FAILURE);                          exit(EXIT_FAILURE);
572                  }                  }
573    
574                    #if defined(WIN32)
575                    u_long nonblock_io = 1;
576                    if( ioctlsocket(socket, FIONBIO, &nonblock_io) ) {
577                      std::cerr << "LSCPServer: ioctlsocket: set FIONBIO failed. Error " << WSAGetLastError() << std::endl;
578                      exit(EXIT_FAILURE);
579                    }
580            #else
581                    struct linger linger;
582                    linger.l_onoff = 1;
583                    linger.l_linger = 0;
584                    if(setsockopt(socket, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger))) {
585                        std::cerr << "LSCPServer: Failed to set SO_LINGER\n";
586                    }
587    
588                  if (fcntl(socket, F_SETFL, O_NONBLOCK)) {                  if (fcntl(socket, F_SETFL, O_NONBLOCK)) {
589                          std::cerr << "LSCPServer: F_SETFL O_NONBLOCK failed." << std::endl;                          std::cerr << "LSCPServer: F_SETFL O_NONBLOCK failed." << std::endl;
590                          exit(EXIT_FAILURE);                          exit(EXIT_FAILURE);
591                  }                  }
592                    #endif
593    
594                  // Parser initialization                  // Parser initialization
595                  yyparse_param_t yyparse_param;                  yyparse_param_t yyparse_param;
# Line 322  int LSCPServer::Main() { Line 608  int LSCPServer::Main() {
608          //Something was selected and it was not the hSocket, so it must be some command(s) coming.          //Something was selected and it was not the hSocket, so it must be some command(s) coming.
609          for (std::vector<yyparse_param_t>::iterator iter = Sessions.begin(); iter != Sessions.end(); iter++) {          for (std::vector<yyparse_param_t>::iterator iter = Sessions.begin(); iter != Sessions.end(); iter++) {
610                  if (FD_ISSET((*iter).hSession, &selectSet)) {   //Was it this socket?                  if (FD_ISSET((*iter).hSession, &selectSet)) {   //Was it this socket?
611                            currentSocket = (*iter).hSession;  //a hack
612                          if (GetLSCPCommand(iter)) {     //Have we read the entire command?                          if (GetLSCPCommand(iter)) {     //Have we read the entire command?
613                                  dmsg(3,("LSCPServer: Got command on socket %d, calling parser.\n", currentSocket));                                  dmsg(3,("LSCPServer: Got command on socket %d, calling parser.\n", currentSocket));
614                                  int dummy; // just a temporary hack to fulfill the restart() function prototype                                  int dummy; // just a temporary hack to fulfill the restart() function prototype
615                                  restart(NULL, dummy); // restart the 'scanner'                                  restart(NULL, dummy); // restart the 'scanner'
616                                  currentSocket = (*iter).hSession;  //a hack                                  itCurrentSession = iter; // another hack
617                                  dmsg(2,("LSCPServer: [%s]\n",bufferedCommands[currentSocket].c_str()));                                  dmsg(2,("LSCPServer: [%s]\n",bufferedCommands[currentSocket].c_str()));
618                                  if ((*iter).bVerbose) { // if echo mode enabled                                  if ((*iter).bVerbose) { // if echo mode enabled
619                                      AnswerClient(bufferedCommands[currentSocket]);                                      AnswerClient(bufferedCommands[currentSocket]);
620                                  }                                  }
621                                  int result = yyparse(&(*iter));                                  int result = yyparse(&(*iter));
622                                  currentSocket = -1;     //continuation of a hack                                  currentSocket = -1;     //continuation of a hack
623                                    itCurrentSession = Sessions.end(); // hack as well
624                                  dmsg(3,("LSCPServer: Done parsing on socket %d.\n", currentSocket));                                  dmsg(3,("LSCPServer: Done parsing on socket %d.\n", currentSocket));
625                                  if (result == LSCP_QUIT) { //Was it a quit command by any chance?                                  if (result == LSCP_QUIT) { //Was it a quit command by any chance?
626                                          CloseConnection(iter);                                          CloseConnection(iter);
627                                  }                                  }
628                          }                          }
629                            currentSocket = -1;     //continuation of a hack
630                          //socket may have been closed, iter may be invalid, get out of the loop for now.                          //socket may have been closed, iter may be invalid, get out of the loop for now.
631                          //we'll be back if there is data.                          //we'll be back if there is data.
632                          break;                          break;
# Line 352  void LSCPServer::CloseConnection( std::v Line 641  void LSCPServer::CloseConnection( std::v
641          LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_misc, "Client connection terminated on socket", socket));          LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_misc, "Client connection terminated on socket", socket));
642          Sessions.erase(iter);          Sessions.erase(iter);
643          FD_CLR(socket,  &fdSet);          FD_CLR(socket,  &fdSet);
644          SubscriptionMutex.Lock(); //Must unsubscribe this socket from all events (if any)          {
645          for (std::map< LSCPEvent::event_t, std::list<int> >::iterator iter = eventSubscriptions.begin(); iter != eventSubscriptions.end(); iter++) {              LockGuard lock(SubscriptionMutex);
646                  iter->second.remove(socket);              // Must unsubscribe this socket from all events (if any)
647          }              for (std::map< LSCPEvent::event_t, std::list<int> >::iterator iter = eventSubscriptions.begin(); iter != eventSubscriptions.end(); iter++) {
648          SubscriptionMutex.Unlock();                  iter->second.remove(socket);
649          NotifyMutex.Lock();              }
650            }
651            LockGuard lock(NotifyMutex);
652          bufferedCommands.erase(socket);          bufferedCommands.erase(socket);
653          bufferedNotifies.erase(socket);          bufferedNotifies.erase(socket);
654            #if defined(WIN32)
655            closesocket(socket);
656            #else
657          close(socket);          close(socket);
658          NotifyMutex.Unlock();          #endif
659    }
660    
661    void LSCPServer::CloseAllConnections() {
662        std::vector<yyparse_param_t>::iterator iter = Sessions.begin();
663        while(iter != Sessions.end()) {
664            CloseConnection(iter);
665            iter = Sessions.begin();
666        }
667  }  }
668    
669  int LSCPServer::EventSubscribers( std::list<LSCPEvent::event_t> events ) {  int LSCPServer::EventSubscribers( std::list<LSCPEvent::event_t> events ) {
670          int subs = 0;          int subs = 0;
671          SubscriptionMutex.Lock();          LockGuard lock(SubscriptionMutex);
672          for( std::list<LSCPEvent::event_t>::iterator iter = events.begin();          for( std::list<LSCPEvent::event_t>::iterator iter = events.begin();
673                          iter != events.end(); iter++)                          iter != events.end(); iter++)
674          {          {
675                  subs += eventSubscriptions.count(*iter);                  subs += eventSubscriptions.count(*iter);
676          }          }
         SubscriptionMutex.Unlock();  
677          return subs;          return subs;
678  }  }
679    
680  void LSCPServer::SendLSCPNotify( LSCPEvent event ) {  void LSCPServer::SendLSCPNotify( LSCPEvent event ) {
681          SubscriptionMutex.Lock();          LockGuard lock(SubscriptionMutex);
682          if (eventSubscriptions.count(event.GetType()) == 0) {          if (eventSubscriptions.count(event.GetType()) == 0) {
683                  SubscriptionMutex.Unlock();     //Nobody is subscribed to this event                  // Nobody is subscribed to this event
684                  return;                  return;
685          }          }
686          std::list<int>::iterator iter = eventSubscriptions[event.GetType()].begin();          std::list<int>::iterator iter = eventSubscriptions[event.GetType()].begin();
# Line 405  void LSCPServer::SendLSCPNotify( LSCPEve Line 706  void LSCPServer::SendLSCPNotify( LSCPEve
706                          }                          }
707                  }                  }
708          }          }
         SubscriptionMutex.Unlock();  
709  }  }
710    
711  extern int GetLSCPCommand( void *buf, int max_size ) {  extern int GetLSCPCommand( void *buf, int max_size ) {
# Line 422  extern int GetLSCPCommand( void *buf, in Line 722  extern int GetLSCPCommand( void *buf, in
722    
723          strcpy((char*) buf, command.c_str());          strcpy((char*) buf, command.c_str());
724          LSCPServer::bufferedCommands.erase(LSCPServer::currentSocket);          LSCPServer::bufferedCommands.erase(LSCPServer::currentSocket);
725          return command.size();          return (int) command.size();
726    }
727    
728    extern yyparse_param_t* GetCurrentYaccSession() {
729        return &(*itCurrentSession);
730    }
731    
732    /**
733     * Generate the relevant LSCP documentation reference section if necessary.
734     * The documentation section for the currently active command on the LSCP
735     * shell's command line will be encoded in a special format, specifically for
736     * the LSCP shell application.
737     *
738     * @param line - current LSCP command line
739     * @param param - reentrant Bison parser parameters
740     *
741     * @return encoded reference string or empty string if nothing shall be sent
742     *         to LSCP shell (client) at this point
743     */
744    String LSCPServer::generateLSCPDocReply(const String& line, yyparse_param_t* param) {
745        String result;
746        lscp_ref_entry_t* ref = lscp_reference_for_command(line.c_str());
747        // Pointer comparison works here, since the function above always
748        // returns the same constant pointer for the respective LSCP
749        // command ... Only send the LSCP reference section to the client if
750        // another LSCP reference section became relevant now:
751        if (ref != param->pLSCPDocRef) {
752            param->pLSCPDocRef = ref;
753            if (ref) { // send a new LSCP doc section to client ...
754                result += "SHD:" + ToString(LSCP_SHD_MATCH) + ":" + String(ref->name) + "\n";
755                result += String(ref->section) + "\n";
756                result += "."; // dot line marks the end of the text for client
757            } else { // inform client that no LSCP doc section matches right now ...
758                result = "SHD:" + ToString(LSCP_SHD_NO_MATCH);
759            }
760        }
761        dmsg(4,("LSCP doc reply -> '%s'\n", result.c_str()));
762        return result;
763  }  }
764    
765  /**  /**
# Line 432  extern int GetLSCPCommand( void *buf, in Line 769  extern int GetLSCPCommand( void *buf, in
769   */   */
770  bool LSCPServer::GetLSCPCommand( std::vector<yyparse_param_t>::iterator iter ) {  bool LSCPServer::GetLSCPCommand( std::vector<yyparse_param_t>::iterator iter ) {
771          int socket = (*iter).hSession;          int socket = (*iter).hSession;
772            int result;
773          char c;          char c;
774          int i = 0;          std::vector<char> input;
775    
776            // first get as many character as possible and add it to the 'input' buffer
777          while (true) {          while (true) {
778                  int result = recv(socket, (void *)&c, 1, 0); //Read one character at a time for now                  #if defined(WIN32)
779                  if (result == 0) { //socket was selected, so 0 here means client has closed the connection                  result = (int)recv(socket, (char*)&c, 1, 0); //Read one character at a time for now
780                          CloseConnection(iter);                  #else
781                          break;                  result = (int)recv(socket, (void*)&c, 1, 0); //Read one character at a time for now
782                  }                  #endif
783                  if (result == 1) {                  if (result == 1) input.push_back(c);
784                          if (c == '\r')                  else break; // end of input or some error
785                                  continue; //Ignore CR                  if (c == '\n') break; // process line by line
786                          if (c == '\n') {          }
787                                  LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_misc, "Received \'" + bufferedCommands[socket] + "\' on socket", socket));  
788                                  bufferedCommands[socket] += "\r\n";          // process input buffer
789                                  return true; //Complete command was read          for (int i = 0; i < input.size(); ++i) {
790                    c = input[i];
791                    if (c == '\r') continue; //Ignore CR
792                    if (c == '\n') {
793                            // only if the other side is the LSCP shell application:
794                            // check the current (incomplete) command line for syntax errors,
795                            // possible completions and report everything back to the shell
796                            if ((*iter).bShellInteract || (*iter).bShellAutoCorrect) {
797                                    String s = lscpParserProcessShellInteraction(bufferedCommands[socket], &(*iter), false);
798                                    if (!s.empty() && (*iter).bShellInteract) AnswerClient(s + "\n");
799                            }
800                            // if other side is LSCP shell application, send the relevant LSCP
801                            // documentation section of the current command line (if necessary)
802                            if ((*iter).bShellSendLSCPDoc && (*iter).bShellInteract) {
803                                    String s = generateLSCPDocReply(bufferedCommands[socket], &(*iter));
804                                    if (!s.empty()) AnswerClient(s + "\n");
805                            }
806                            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_misc, "Received \'" + bufferedCommands[socket] + "\' on socket", socket));
807                            bufferedCommands[socket] += "\r\n";
808                            return true; //Complete command was read
809                    } else if (c == 2) { // custom ASCII code usage for moving cursor left (LSCP shell)
810                            if (iter->iCursorOffset + bufferedCommands[socket].size() > 0)
811                                    iter->iCursorOffset--;
812                    } else if (c == 3) { // custom ASCII code usage for moving cursor right (LSCP shell)
813                            if (iter->iCursorOffset < 0) iter->iCursorOffset++;
814                    } else {
815                            ssize_t cursorPos = bufferedCommands[socket].size() + iter->iCursorOffset;
816                            // backspace character - should only happen with shell
817                            if (c == '\b') {
818                                    if (!bufferedCommands[socket].empty() && cursorPos > 0)
819                                            bufferedCommands[socket].erase(cursorPos - 1, 1);
820                            } else { // append (or insert) new character (at current cursor position) ...
821                                    if (cursorPos >= 0)
822                                            bufferedCommands[socket].insert(cursorPos, String(1,c)); // insert
823                                    else
824                                            bufferedCommands[socket] += c; // append
825                          }                          }
                         bufferedCommands[socket] += c;  
826                  }                  }
827                  if (result == -1) {                  // Only if the other side (client) is the LSCP shell application:
828                          if (errno == EAGAIN) //Would block, try again later.                  // The following block takes care about automatic correction, auto
829                                  return false;                  // completion (and suggestions), LSCP reference documentation, etc.
830                          switch(errno) {                  // The "if" statement here is for optimization reasons, so that the
831                                  case EBADF:                  // heavy LSCP grammar evaluation algorithm is only executed once for an
832                                          dmsg(2,("LSCPScanner: The argument s is an invalid descriptor.\n"));                  // entire command line received.
833                                          break;                  if (i == input.size() - 1) {
834                                  case ECONNREFUSED:                          // check the current (incomplete) command line for syntax errors,
835                                          dmsg(2,("LSCPScanner: A remote host refused to allow the network connection (typically because it is not running the requested service).\n"));                          // possible completions and report everything back to the shell
836                                          break;                          if ((*iter).bShellInteract || (*iter).bShellAutoCorrect) {
837                                  case ENOTCONN:                                  String s = lscpParserProcessShellInteraction(bufferedCommands[socket], &(*iter), true);
838                                          dmsg(2,("LSCPScanner: The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2)).\n"));                                  if (!s.empty() && (*iter).bShellInteract && i == input.size() - 1)
839                                          break;                                          AnswerClient(s + "\n");
                                 case ENOTSOCK:  
                                         dmsg(2,("LSCPScanner: The argument s does not refer to a socket.\n"));  
                                         break;  
                                 case EAGAIN:  
                                         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"));  
                                         break;  
                                 case EINTR:  
                                         dmsg(2,("LSCPScanner: The receive was interrupted by delivery of a signal before any data were available.\n"));  
                                         break;  
                                 case EFAULT:  
                                         dmsg(2,("LSCPScanner: The receive buffer pointer(s) point outside the process's address space.\n"));  
                                         break;  
                                 case EINVAL:  
                                         dmsg(2,("LSCPScanner: Invalid argument passed.\n"));  
                                         break;  
                                 case ENOMEM:  
                                         dmsg(2,("LSCPScanner: Could not allocate memory for recvmsg.\n"));  
                                         break;  
                                 default:  
                                         dmsg(2,("LSCPScanner: Unknown recv() error.\n"));  
                                         break;  
840                          }                          }
841                          CloseConnection(iter);                          // if other side is LSCP shell application, send the relevant LSCP
842                          break;                          // documentation section of the current command line (if necessary)
843                            if ((*iter).bShellSendLSCPDoc && (*iter).bShellInteract) {
844                                    String s = generateLSCPDocReply(bufferedCommands[socket], &(*iter));
845                                    if (!s.empty()) AnswerClient(s + "\n");
846                            }
847                    }
848            }
849    
850            // handle network errors ...
851            if (result == 0) { //socket was selected, so 0 here means client has closed the connection
852                    CloseConnection(iter);
853                    return false;
854            }
855            #if defined(WIN32)
856            if (result == SOCKET_ERROR) {
857                    int wsa_lasterror = WSAGetLastError();
858                    if (wsa_lasterror == WSAEWOULDBLOCK) //Would block, try again later.
859                            return false;
860                    dmsg(2,("LSCPScanner: Socket error after recv() Error %d.\n", wsa_lasterror));
861                    CloseConnection(iter);
862                    return false;
863            }
864            #else
865            if (result == -1) {
866                    switch(errno) {
867                            case EBADF:
868                                    dmsg(2,("LSCPScanner: The argument s is an invalid descriptor.\n"));
869                                    break; // close connection
870                            case ECONNREFUSED:
871                                    dmsg(2,("LSCPScanner: A remote host refused to allow the network connection (typically because it is not running the requested service).\n"));
872                                    break; // close connection
873                            case ENOTCONN:
874                                    dmsg(2,("LSCPScanner: The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2)).\n"));
875                                    break; // close connection
876                            case ENOTSOCK:
877                                    dmsg(2,("LSCPScanner: The argument s does not refer to a socket.\n"));
878                                    break; // close connection
879                            case EAGAIN:
880                                    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"));
881                                    return false; // don't close connection, try again later
882                            case EINTR:
883                                    dmsg(2,("LSCPScanner: The receive was interrupted by delivery of a signal before any data were available.\n"));
884                                    break; // close connection
885                            case EFAULT:
886                                    dmsg(2,("LSCPScanner: The receive buffer pointer(s) point outside the process's address space.\n"));
887                                    break; // close connection
888                            case EINVAL:
889                                    dmsg(2,("LSCPScanner: Invalid argument passed.\n"));
890                                    break; // close connection
891                            case ENOMEM:
892                                    dmsg(2,("LSCPScanner: Could not allocate memory for recvmsg.\n"));
893                                    break; // close connection
894                            default:
895                                    dmsg(2,("LSCPScanner: Unknown recv() error.\n"));
896                                    break; // close connection
897                  }                  }
898                    CloseConnection(iter);
899                    return false;
900          }          }
901            #endif
902    
903          return false;          return false;
904  }  }
905    
# Line 499  bool LSCPServer::GetLSCPCommand( std::ve Line 910  bool LSCPServer::GetLSCPCommand( std::ve
910   * @param ReturnMessage - message that will be send to the client   * @param ReturnMessage - message that will be send to the client
911   */   */
912  void LSCPServer::AnswerClient(String ReturnMessage) {  void LSCPServer::AnswerClient(String ReturnMessage) {
913      dmsg(2,("LSCPServer::AnswerClient(ReturnMessage=%s)", ReturnMessage.c_str()));      dmsg(2,("LSCPServer::AnswerClient(ReturnMessage='%s')", ReturnMessage.c_str()));
914      if (currentSocket != -1) {      if (currentSocket != -1) {
915              NotifyMutex.Lock();              LockGuard lock(NotifyMutex);
916    
917            // just if other side is LSCP shell: in case respose is a multi-line
918            // one, then inform client about it before sending the actual mult-line
919            // response
920            if (GetCurrentYaccSession()->bShellInteract) {
921                // check if this is a multi-line response
922                int n = 0;
923                for (int i = 0; i < ReturnMessage.size(); ++i)
924                    if (ReturnMessage[i] == '\n') ++n;
925                if (n >= 2) {
926                    dmsg(2,("LSCP Shell <- expect mult-line response\n"));
927                    String s = LSCP_SHK_EXPECT_MULTI_LINE "\r\n";
928    #ifdef MSG_NOSIGNAL
929                    send(currentSocket, s.c_str(), s.size(), MSG_NOSIGNAL);
930    #else
931                    send(currentSocket, s.c_str(), s.size(), 0);
932    #endif                
933                }
934            }
935    
936  #ifdef MSG_NOSIGNAL  #ifdef MSG_NOSIGNAL
937              send(currentSocket, ReturnMessage.c_str(), ReturnMessage.size(), MSG_NOSIGNAL);              send(currentSocket, ReturnMessage.c_str(), ReturnMessage.size(), MSG_NOSIGNAL);
938  #else  #else
939              send(currentSocket, ReturnMessage.c_str(), ReturnMessage.size(), 0);              send(currentSocket, ReturnMessage.c_str(), ReturnMessage.size(), 0);
940  #endif  #endif
             NotifyMutex.Unlock();  
941      }      }
942  }  }
943    
# Line 612  EngineChannel* LSCPServer::GetEngineChan Line 1042  EngineChannel* LSCPServer::GetEngineChan
1042      EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();      EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();
1043      if (!pEngineChannel) throw Exception("There is no engine deployed on this sampler channel yet");      if (!pEngineChannel) throw Exception("There is no engine deployed on this sampler channel yet");
1044    
1045      return pEngineChannel;              return pEngineChannel;
1046  }  }
1047    
1048  /**  /**
# Line 657  String LSCPServer::SetEngineType(String Line 1087  String LSCPServer::SetEngineType(String
1087      try {      try {
1088          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1089          if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));          if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1090          LockRTNotify();          LockGuard lock(RTNotifyMutex);
1091          pSamplerChannel->SetEngineType(EngineName);          pSamplerChannel->SetEngineType(EngineName);
1092          if(HasSoloChannel()) pSamplerChannel->GetEngineChannel()->SetMute(-1);          if(HasSoloChannel()) pSamplerChannel->GetEngineChannel()->SetMute(-1);
         UnlockRTNotify();  
1093      }      }
1094      catch (Exception e) {      catch (Exception e) {
1095           result.Error(e);           result.Error(e);
# Line 700  String LSCPServer::ListChannels() { Line 1129  String LSCPServer::ListChannels() {
1129   */   */
1130  String LSCPServer::AddChannel() {  String LSCPServer::AddChannel() {
1131      dmsg(2,("LSCPServer: AddChannel()\n"));      dmsg(2,("LSCPServer: AddChannel()\n"));
1132      LockRTNotify();      SamplerChannel* pSamplerChannel;
1133      SamplerChannel* pSamplerChannel = pSampler->AddSamplerChannel();      {
1134      UnlockRTNotify();          LockGuard lock(RTNotifyMutex);
1135            pSamplerChannel = pSampler->AddSamplerChannel();
1136        }
1137      LSCPResultSet result(pSamplerChannel->Index());      LSCPResultSet result(pSamplerChannel->Index());
1138      return result.Produce();      return result.Produce();
1139  }  }
# Line 713  String LSCPServer::AddChannel() { Line 1144  String LSCPServer::AddChannel() {
1144  String LSCPServer::RemoveChannel(uint uiSamplerChannel) {  String LSCPServer::RemoveChannel(uint uiSamplerChannel) {
1145      dmsg(2,("LSCPServer: RemoveChannel(SamplerChannel=%d)\n", uiSamplerChannel));      dmsg(2,("LSCPServer: RemoveChannel(SamplerChannel=%d)\n", uiSamplerChannel));
1146      LSCPResultSet result;      LSCPResultSet result;
1147      LockRTNotify();      {
1148      pSampler->RemoveSamplerChannel(uiSamplerChannel);          LockGuard lock(RTNotifyMutex);
1149      UnlockRTNotify();          pSampler->RemoveSamplerChannel(uiSamplerChannel);
1150        }
1151      return result.Produce();      return result.Produce();
1152  }  }
1153    
# Line 726  String LSCPServer::GetAvailableEngines() Line 1158  String LSCPServer::GetAvailableEngines()
1158      dmsg(2,("LSCPServer: GetAvailableEngines()\n"));      dmsg(2,("LSCPServer: GetAvailableEngines()\n"));
1159      LSCPResultSet result;      LSCPResultSet result;
1160      try {      try {
1161          int n = EngineFactory::AvailableEngineTypes().size();          int n = (int)EngineFactory::AvailableEngineTypes().size();
1162          result.Add(n);          result.Add(n);
1163      }      }
1164      catch (Exception e) {      catch (Exception e) {
# Line 758  String LSCPServer::ListAvailableEngines( Line 1190  String LSCPServer::ListAvailableEngines(
1190  String LSCPServer::GetEngineInfo(String EngineName) {  String LSCPServer::GetEngineInfo(String EngineName) {
1191      dmsg(2,("LSCPServer: GetEngineInfo(EngineName=%s)\n", EngineName.c_str()));      dmsg(2,("LSCPServer: GetEngineInfo(EngineName=%s)\n", EngineName.c_str()));
1192      LSCPResultSet result;      LSCPResultSet result;
1193      LockRTNotify();      {
1194      try {          LockGuard lock(RTNotifyMutex);
1195          Engine* pEngine = EngineFactory::Create(EngineName);          try {
1196          result.Add("DESCRIPTION", pEngine->Description());              Engine* pEngine = EngineFactory::Create(EngineName);
1197          result.Add("VERSION",     pEngine->Version());              result.Add("DESCRIPTION", _escapeLscpResponse(pEngine->Description()));
1198          EngineFactory::Destroy(pEngine);              result.Add("VERSION",     pEngine->Version());
1199      }              EngineFactory::Destroy(pEngine);
1200      catch (Exception e) {          }
1201           result.Error(e);          catch (Exception e) {
1202                result.Error(e);
1203            }
1204      }      }
     UnlockRTNotify();  
1205      return result.Produce();      return result.Produce();
1206  }  }
1207    
# Line 834  String LSCPServer::GetChannelInfo(uint u Line 1267  String LSCPServer::GetChannelInfo(uint u
1267          if (pSamplerChannel->GetMidiInputChannel() == midi_chan_all) result.Add("MIDI_INPUT_CHANNEL", "ALL");          if (pSamplerChannel->GetMidiInputChannel() == midi_chan_all) result.Add("MIDI_INPUT_CHANNEL", "ALL");
1268          else result.Add("MIDI_INPUT_CHANNEL", pSamplerChannel->GetMidiInputChannel());          else result.Add("MIDI_INPUT_CHANNEL", pSamplerChannel->GetMidiInputChannel());
1269    
1270            // convert the filename into the correct encoding as defined for LSCP
1271            // (especially in terms of special characters -> escape sequences)
1272            if (InstrumentFileName != "NONE" && InstrumentFileName != "") {
1273    #if WIN32
1274                InstrumentFileName = Path::fromWindows(InstrumentFileName).toLscp();
1275    #else
1276                // assuming POSIX
1277                InstrumentFileName = Path::fromPosix(InstrumentFileName).toLscp();
1278    #endif
1279            }
1280    
1281          result.Add("INSTRUMENT_FILE", InstrumentFileName);          result.Add("INSTRUMENT_FILE", InstrumentFileName);
1282          result.Add("INSTRUMENT_NR", InstrumentIndex);          result.Add("INSTRUMENT_NR", InstrumentIndex);
1283          result.Add("INSTRUMENT_NAME", InstrumentName);          result.Add("INSTRUMENT_NAME", _escapeLscpResponse(InstrumentName));
1284          result.Add("INSTRUMENT_STATUS", InstrumentStatus);          result.Add("INSTRUMENT_STATUS", InstrumentStatus);
1285          result.Add("MUTE", Mute == -1 ? "MUTED_BY_SOLO" : (Mute ? "true" : "false"));          result.Add("MUTE", Mute == -1 ? "MUTED_BY_SOLO" : (Mute ? "true" : "false"));
1286          result.Add("SOLO", Solo);          result.Add("SOLO", Solo);
# Line 856  String LSCPServer::GetVoiceCount(uint ui Line 1300  String LSCPServer::GetVoiceCount(uint ui
1300      dmsg(2,("LSCPServer: GetVoiceCount(SamplerChannel=%d)\n", uiSamplerChannel));      dmsg(2,("LSCPServer: GetVoiceCount(SamplerChannel=%d)\n", uiSamplerChannel));
1301      LSCPResultSet result;      LSCPResultSet result;
1302      try {      try {
1303          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);          EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
         if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));  
         EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();  
         if (!pEngineChannel) throw Exception("No engine loaded on sampler channel");  
1304          if (!pEngineChannel->GetEngine()) throw Exception("No audio output device connected to sampler channel");          if (!pEngineChannel->GetEngine()) throw Exception("No audio output device connected to sampler channel");
1305          result.Add(pEngineChannel->GetEngine()->VoiceCount());          result.Add(pEngineChannel->GetEngine()->VoiceCount());
1306      }      }
# Line 877  String LSCPServer::GetStreamCount(uint u Line 1318  String LSCPServer::GetStreamCount(uint u
1318      dmsg(2,("LSCPServer: GetStreamCount(SamplerChannel=%d)\n", uiSamplerChannel));      dmsg(2,("LSCPServer: GetStreamCount(SamplerChannel=%d)\n", uiSamplerChannel));
1319      LSCPResultSet result;      LSCPResultSet result;
1320      try {      try {
1321          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);          EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
         if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));  
         EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();  
         if (!pEngineChannel) throw Exception("No engine type assigned to sampler channel");  
1322          if (!pEngineChannel->GetEngine()) throw Exception("No audio output device connected to sampler channel");          if (!pEngineChannel->GetEngine()) throw Exception("No audio output device connected to sampler channel");
1323          result.Add(pEngineChannel->GetEngine()->DiskStreamCount());          result.Add(pEngineChannel->GetEngine()->DiskStreamCount());
1324      }      }
# Line 898  String LSCPServer::GetBufferFill(fill_re Line 1336  String LSCPServer::GetBufferFill(fill_re
1336      dmsg(2,("LSCPServer: GetBufferFill(ResponseType=%d, SamplerChannel=%d)\n", ResponseType, uiSamplerChannel));      dmsg(2,("LSCPServer: GetBufferFill(ResponseType=%d, SamplerChannel=%d)\n", ResponseType, uiSamplerChannel));
1337      LSCPResultSet result;      LSCPResultSet result;
1338      try {      try {
1339          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);          EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
         if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));  
         EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();  
         if (!pEngineChannel) throw Exception("No engine type assigned to sampler channel");  
1340          if (!pEngineChannel->GetEngine()) throw Exception("No audio output device connected to sampler channel");          if (!pEngineChannel->GetEngine()) throw Exception("No audio output device connected to sampler channel");
1341          if (!pEngineChannel->GetEngine()->DiskStreamSupported()) result.Add("NA");          if (!pEngineChannel->GetEngine()->DiskStreamSupported()) result.Add("NA");
1342          else {          else {
# Line 927  String LSCPServer::GetAvailableAudioOutp Line 1362  String LSCPServer::GetAvailableAudioOutp
1362      dmsg(2,("LSCPServer: GetAvailableAudioOutputDrivers()\n"));      dmsg(2,("LSCPServer: GetAvailableAudioOutputDrivers()\n"));
1363      LSCPResultSet result;      LSCPResultSet result;
1364      try {      try {
1365          int n = AudioOutputDeviceFactory::AvailableDrivers().size();          int n = (int) AudioOutputDeviceFactory::AvailableDrivers().size();
1366          result.Add(n);          result.Add(n);
1367      }      }
1368      catch (Exception e) {      catch (Exception e) {
# Line 953  String LSCPServer::GetAvailableMidiInput Line 1388  String LSCPServer::GetAvailableMidiInput
1388      dmsg(2,("LSCPServer: GetAvailableMidiInputDrivers()\n"));      dmsg(2,("LSCPServer: GetAvailableMidiInputDrivers()\n"));
1389      LSCPResultSet result;      LSCPResultSet result;
1390      try {      try {
1391          int n = MidiInputDeviceFactory::AvailableDrivers().size();          int n = (int)MidiInputDeviceFactory::AvailableDrivers().size();
1392          result.Add(n);          result.Add(n);
1393      }      }
1394      catch (Exception e) {      catch (Exception e) {
# Line 989  String LSCPServer::GetMidiInputDriverInf Line 1424  String LSCPServer::GetMidiInputDriverInf
1424              for (;iter != parameters.end(); iter++) {              for (;iter != parameters.end(); iter++) {
1425                  if (s != "") s += ",";                  if (s != "") s += ",";
1426                  s += iter->first;                  s += iter->first;
1427                    delete iter->second;
1428              }              }
1429              result.Add("PARAMETERS", s);              result.Add("PARAMETERS", s);
1430          }          }
# Line 1013  String LSCPServer::GetAudioOutputDriverI Line 1449  String LSCPServer::GetAudioOutputDriverI
1449              for (;iter != parameters.end(); iter++) {              for (;iter != parameters.end(); iter++) {
1450                  if (s != "") s += ",";                  if (s != "") s += ",";
1451                  s += iter->first;                  s += iter->first;
1452                    delete iter->second;
1453              }              }
1454              result.Add("PARAMETERS", s);              result.Add("PARAMETERS", s);
1455          }          }
# Line 1024  String LSCPServer::GetAudioOutputDriverI Line 1461  String LSCPServer::GetAudioOutputDriverI
1461  }  }
1462    
1463  String LSCPServer::GetMidiInputDriverParameterInfo(String Driver, String Parameter, std::map<String,String> DependencyList) {  String LSCPServer::GetMidiInputDriverParameterInfo(String Driver, String Parameter, std::map<String,String> DependencyList) {
1464      dmsg(2,("LSCPServer: GetMidiInputDriverParameterInfo(Driver=%s,Parameter=%s,DependencyListSize=%d)\n",Driver.c_str(),Parameter.c_str(),DependencyList.size()));      dmsg(2,("LSCPServer: GetMidiInputDriverParameterInfo(Driver=%s,Parameter=%s,DependencyListSize=%d)\n",Driver.c_str(),Parameter.c_str(),int(DependencyList.size())));
1465      LSCPResultSet result;      LSCPResultSet result;
1466      try {      try {
1467          DeviceCreationParameter* pParameter = MidiInputDeviceFactory::GetDriverParameter(Driver, Parameter);          DeviceCreationParameter* pParameter = MidiInputDeviceFactory::GetDriverParameter(Driver, Parameter);
# Line 1043  String LSCPServer::GetMidiInputDriverPar Line 1480  String LSCPServer::GetMidiInputDriverPar
1480          if (oRangeMin)      result.Add("RANGE_MIN",     *oRangeMin);          if (oRangeMin)      result.Add("RANGE_MIN",     *oRangeMin);
1481          if (oRangeMax)      result.Add("RANGE_MAX",     *oRangeMax);          if (oRangeMax)      result.Add("RANGE_MAX",     *oRangeMax);
1482          if (oPossibilities) result.Add("POSSIBILITIES", *oPossibilities);          if (oPossibilities) result.Add("POSSIBILITIES", *oPossibilities);
1483            delete pParameter;
1484      }      }
1485      catch (Exception e) {      catch (Exception e) {
1486          result.Error(e);          result.Error(e);
# Line 1051  String LSCPServer::GetMidiInputDriverPar Line 1489  String LSCPServer::GetMidiInputDriverPar
1489  }  }
1490    
1491  String LSCPServer::GetAudioOutputDriverParameterInfo(String Driver, String Parameter, std::map<String,String> DependencyList) {  String LSCPServer::GetAudioOutputDriverParameterInfo(String Driver, String Parameter, std::map<String,String> DependencyList) {
1492      dmsg(2,("LSCPServer: GetAudioOutputDriverParameterInfo(Driver=%s,Parameter=%s,DependencyListSize=%d)\n",Driver.c_str(),Parameter.c_str(),DependencyList.size()));      dmsg(2,("LSCPServer: GetAudioOutputDriverParameterInfo(Driver=%s,Parameter=%s,DependencyListSize=%d)\n",Driver.c_str(),Parameter.c_str(),int(DependencyList.size())));
1493      LSCPResultSet result;      LSCPResultSet result;
1494      try {      try {
1495          DeviceCreationParameter* pParameter = AudioOutputDeviceFactory::GetDriverParameter(Driver, Parameter);          DeviceCreationParameter* pParameter = AudioOutputDeviceFactory::GetDriverParameter(Driver, Parameter);
# Line 1070  String LSCPServer::GetAudioOutputDriverP Line 1508  String LSCPServer::GetAudioOutputDriverP
1508          if (oRangeMin)      result.Add("RANGE_MIN",     *oRangeMin);          if (oRangeMin)      result.Add("RANGE_MIN",     *oRangeMin);
1509          if (oRangeMax)      result.Add("RANGE_MAX",     *oRangeMax);          if (oRangeMax)      result.Add("RANGE_MAX",     *oRangeMax);
1510          if (oPossibilities) result.Add("POSSIBILITIES", *oPossibilities);          if (oPossibilities) result.Add("POSSIBILITIES", *oPossibilities);
1511            delete pParameter;
1512      }      }
1513      catch (Exception e) {      catch (Exception e) {
1514          result.Error(e);          result.Error(e);
# Line 1207  String LSCPServer::GetMidiInputPortInfo( Line 1646  String LSCPServer::GetMidiInputPortInfo(
1646  }  }
1647    
1648  String LSCPServer::GetAudioOutputChannelInfo(uint DeviceId, uint ChannelId) {  String LSCPServer::GetAudioOutputChannelInfo(uint DeviceId, uint ChannelId) {
1649      dmsg(2,("LSCPServer: GetAudioOutputChannelInfo(DeviceId=%d,ChannelId)\n",DeviceId,ChannelId));      dmsg(2,("LSCPServer: GetAudioOutputChannelInfo(DeviceId=%u,ChannelId=%u)\n",DeviceId,ChannelId));
1650      LSCPResultSet result;      LSCPResultSet result;
1651      try {      try {
1652          // get audio output device          // get audio output device
# Line 1411  String LSCPServer::SetAudioOutputChannel Line 1850  String LSCPServer::SetAudioOutputChannel
1850  String LSCPServer::SetAudioOutputDevice(uint AudioDeviceId, uint uiSamplerChannel) {  String LSCPServer::SetAudioOutputDevice(uint AudioDeviceId, uint uiSamplerChannel) {
1851      dmsg(2,("LSCPServer: SetAudiotOutputDevice(AudioDeviceId=%d, SamplerChannel=%d)\n",AudioDeviceId,uiSamplerChannel));      dmsg(2,("LSCPServer: SetAudiotOutputDevice(AudioDeviceId=%d, SamplerChannel=%d)\n",AudioDeviceId,uiSamplerChannel));
1852      LSCPResultSet result;      LSCPResultSet result;
1853      LockRTNotify();      {
1854            LockGuard lock(RTNotifyMutex);
1855            try {
1856                SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1857                if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1858                std::map<uint, AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
1859                if (!devices.count(AudioDeviceId)) throw Exception("There is no audio output device with index " + ToString(AudioDeviceId));
1860                AudioOutputDevice* pDevice = devices[AudioDeviceId];
1861                pSamplerChannel->SetAudioOutputDevice(pDevice);
1862            }
1863            catch (Exception e) {
1864                result.Error(e);
1865            }
1866        }
1867        return result.Produce();
1868    }
1869    
1870    String LSCPServer::SetAudioOutputType(String AudioOutputDriver, uint uiSamplerChannel) {
1871        dmsg(2,("LSCPServer: SetAudioOutputType(String AudioOutputDriver=%s, SamplerChannel=%d)\n",AudioOutputDriver.c_str(),uiSamplerChannel));
1872        LSCPResultSet result;
1873        {
1874            LockGuard lock(RTNotifyMutex);
1875            try {
1876                SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1877                if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1878                // Driver type name aliasing...
1879                if (AudioOutputDriver == "Alsa") AudioOutputDriver = "ALSA";
1880                if (AudioOutputDriver == "Jack") AudioOutputDriver = "JACK";
1881                // Check if there's one audio output device already created
1882                // for the intended audio driver type (AudioOutputDriver)...
1883                AudioOutputDevice *pDevice = NULL;
1884                std::map<uint, AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
1885                std::map<uint, AudioOutputDevice*>::iterator iter = devices.begin();
1886                for (; iter != devices.end(); iter++) {
1887                    if ((iter->second)->Driver() == AudioOutputDriver) {
1888                        pDevice = iter->second;
1889                        break;
1890                    }
1891                }
1892                // If it doesn't exist, create a new one with default parameters...
1893                if (pDevice == NULL) {
1894                    std::map<String,String> params;
1895                    pDevice = pSampler->CreateAudioOutputDevice(AudioOutputDriver, params);
1896                }
1897                // Must have a device...
1898                if (pDevice == NULL)
1899                    throw Exception("Internal error: could not create audio output device.");
1900                // Set it as the current channel device...
1901                pSamplerChannel->SetAudioOutputDevice(pDevice);
1902            }
1903            catch (Exception e) {
1904                result.Error(e);
1905            }
1906        }
1907        return result.Produce();
1908    }
1909    
1910    String LSCPServer::AddChannelMidiInput(uint uiSamplerChannel, uint MIDIDeviceId, uint MIDIPort) {
1911        dmsg(2,("LSCPServer: AddChannelMidiInput(uiSamplerChannel=%d, MIDIDeviceId=%d, MIDIPort=%d)\n",uiSamplerChannel,MIDIDeviceId,MIDIPort));
1912        LSCPResultSet result;
1913      try {      try {
1914          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1915          if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));          if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1916          std::map<uint, AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();  
1917          if (!devices.count(AudioDeviceId)) throw Exception("There is no audio output device with index " + ToString(AudioDeviceId));          std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
1918          AudioOutputDevice* pDevice = devices[AudioDeviceId];          if (!devices.count(MIDIDeviceId)) throw Exception("There is no MIDI input device with index " + ToString(MIDIDeviceId));
1919          pSamplerChannel->SetAudioOutputDevice(pDevice);          MidiInputDevice* pDevice = devices[MIDIDeviceId];
1920    
1921            MidiInputPort* pPort = pDevice->GetPort(MIDIPort);
1922            if (!pPort) throw Exception("There is no MIDI input port with index " + ToString(MIDIPort) + " on MIDI input device with index " + ToString(MIDIDeviceId));
1923    
1924            pSamplerChannel->Connect(pPort);
1925        } catch (Exception e) {
1926            result.Error(e);
1927      }      }
1928      catch (Exception e) {      return result.Produce();
1929           result.Error(e);  }
1930    
1931    String LSCPServer::RemoveChannelMidiInput(uint uiSamplerChannel) {
1932        dmsg(2,("LSCPServer: RemoveChannelMidiInput(uiSamplerChannel=%d)\n",uiSamplerChannel));
1933        LSCPResultSet result;
1934        try {
1935            SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1936            if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1937            pSamplerChannel->DisconnectAllMidiInputPorts();
1938        } catch (Exception e) {
1939            result.Error(e);
1940      }      }
     UnlockRTNotify();  
1941      return result.Produce();      return result.Produce();
1942  }  }
1943    
1944  String LSCPServer::SetAudioOutputType(String AudioOutputDriver, uint uiSamplerChannel) {  String LSCPServer::RemoveChannelMidiInput(uint uiSamplerChannel, uint MIDIDeviceId) {
1945      dmsg(2,("LSCPServer: SetAudioOutputType(String AudioOutputDriver=%s, SamplerChannel=%d)\n",AudioOutputDriver.c_str(),uiSamplerChannel));      dmsg(2,("LSCPServer: RemoveChannelMidiInput(uiSamplerChannel=%d, MIDIDeviceId=%d)\n",uiSamplerChannel,MIDIDeviceId));
1946      LSCPResultSet result;      LSCPResultSet result;
     LockRTNotify();  
1947      try {      try {
1948          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1949          if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));          if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1950          // Driver type name aliasing...  
1951          if (AudioOutputDriver == "Alsa") AudioOutputDriver = "ALSA";          std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
1952          if (AudioOutputDriver == "Jack") AudioOutputDriver = "JACK";          if (!devices.count(MIDIDeviceId)) throw Exception("There is no MIDI input device with index " + ToString(MIDIDeviceId));
1953          // Check if there's one audio output device already created          MidiInputDevice* pDevice = devices[MIDIDeviceId];
1954          // for the intended audio driver type (AudioOutputDriver)...          
1955          AudioOutputDevice *pDevice = NULL;          std::vector<MidiInputPort*> vPorts = pSamplerChannel->GetMidiInputPorts();
1956          std::map<uint, AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();          for (int i = 0; i < vPorts.size(); ++i)
1957          std::map<uint, AudioOutputDevice*>::iterator iter = devices.begin();              if (vPorts[i]->GetDevice() == pDevice)
1958          for (; iter != devices.end(); iter++) {                  pSamplerChannel->Disconnect(vPorts[i]);
1959              if ((iter->second)->Driver() == AudioOutputDriver) {  
1960                  pDevice = iter->second;      } catch (Exception e) {
1961                  break;          result.Error(e);
             }  
         }  
         // If it doesn't exist, create a new one with default parameters...  
         if (pDevice == NULL) {  
             std::map<String,String> params;  
             pDevice = pSampler->CreateAudioOutputDevice(AudioOutputDriver, params);  
         }  
         // Must have a device...  
         if (pDevice == NULL)  
             throw Exception("Internal error: could not create audio output device.");  
         // Set it as the current channel device...  
         pSamplerChannel->SetAudioOutputDevice(pDevice);  
1962      }      }
1963      catch (Exception e) {      return result.Produce();
1964           result.Error(e);  }
1965    
1966    String LSCPServer::RemoveChannelMidiInput(uint uiSamplerChannel, uint MIDIDeviceId, uint MIDIPort) {
1967        dmsg(2,("LSCPServer: RemoveChannelMidiInput(uiSamplerChannel=%d, MIDIDeviceId=%d, MIDIPort=%d)\n",uiSamplerChannel,MIDIDeviceId,MIDIPort));
1968        LSCPResultSet result;
1969        try {
1970            SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1971            if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1972    
1973            std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
1974            if (!devices.count(MIDIDeviceId)) throw Exception("There is no MIDI input device with index " + ToString(MIDIDeviceId));
1975            MidiInputDevice* pDevice = devices[MIDIDeviceId];
1976    
1977            MidiInputPort* pPort = pDevice->GetPort(MIDIPort);
1978            if (!pPort) throw Exception("There is no MIDI input port with index " + ToString(MIDIPort) + " on MIDI input device with index " + ToString(MIDIDeviceId));
1979    
1980            pSamplerChannel->Disconnect(pPort);
1981        } catch (Exception e) {
1982            result.Error(e);
1983        }
1984        return result.Produce();
1985    }
1986    
1987    String LSCPServer::ListChannelMidiInputs(uint uiSamplerChannel) {
1988        dmsg(2,("LSCPServer: ListChannelMidiInputs(uiSamplerChannel=%d)\n",uiSamplerChannel));
1989        LSCPResultSet result;
1990        try {
1991            SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1992            if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
1993            std::vector<MidiInputPort*> vPorts = pSamplerChannel->GetMidiInputPorts();
1994    
1995            String s;
1996            for (int i = 0; i < vPorts.size(); ++i) {
1997                const int iDeviceID = vPorts[i]->GetDevice()->MidiInputDeviceID();
1998                const int iPortNr   = vPorts[i]->GetPortNumber();
1999                if (s.size()) s += ",";
2000                s += "{" + ToString(iDeviceID) + ","
2001                         + ToString(iPortNr) + "}";
2002            }
2003            result.Add(s);
2004        } catch (Exception e) {
2005            result.Error(e);
2006      }      }
     UnlockRTNotify();  
2007      return result.Produce();      return result.Produce();
2008  }  }
2009    
# Line 1536  String LSCPServer::SetMIDIInputType(Stri Line 2077  String LSCPServer::SetMIDIInputType(Stri
2077              pDevice = pSampler->CreateMidiInputDevice(MidiInputDriver, params);              pDevice = pSampler->CreateMidiInputDevice(MidiInputDriver, params);
2078              // Make it with at least one initial port.              // Make it with at least one initial port.
2079              std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();              std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();
             parameters["PORTS"]->SetValue("1");  
2080          }          }
2081          // Must have a device...          // Must have a device...
2082          if (pDevice == NULL)          if (pDevice == NULL)
# Line 1579  String LSCPServer::SetVolume(double dVol Line 2119  String LSCPServer::SetVolume(double dVol
2119      dmsg(2,("LSCPServer: SetVolume(Volume=%f, SamplerChannel=%d)\n", dVolume, uiSamplerChannel));      dmsg(2,("LSCPServer: SetVolume(Volume=%f, SamplerChannel=%d)\n", dVolume, uiSamplerChannel));
2120      LSCPResultSet result;      LSCPResultSet result;
2121      try {      try {
2122          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);          EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
         if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));  
         EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();  
         if (!pEngineChannel) throw Exception("No engine type assigned to sampler channel");  
2123          pEngineChannel->Volume(dVolume);          pEngineChannel->Volume(dVolume);
2124      }      }
2125      catch (Exception e) {      catch (Exception e) {
# Line 1598  String LSCPServer::SetChannelMute(bool b Line 2135  String LSCPServer::SetChannelMute(bool b
2135      dmsg(2,("LSCPServer: SetChannelMute(bMute=%d,uiSamplerChannel=%d)\n",bMute,uiSamplerChannel));      dmsg(2,("LSCPServer: SetChannelMute(bMute=%d,uiSamplerChannel=%d)\n",bMute,uiSamplerChannel));
2136      LSCPResultSet result;      LSCPResultSet result;
2137      try {      try {
2138          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);          EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
         if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));  
   
         EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();  
         if (!pEngineChannel) throw Exception("No engine type assigned to sampler channel");  
2139    
2140          if(!bMute) pEngineChannel->SetMute((HasSoloChannel() && !pEngineChannel->GetSolo()) ? -1 : 0);          if(!bMute) pEngineChannel->SetMute((HasSoloChannel() && !pEngineChannel->GetSolo()) ? -1 : 0);
2141          else pEngineChannel->SetMute(1);          else pEngineChannel->SetMute(1);
# Line 1619  String LSCPServer::SetChannelSolo(bool b Line 2152  String LSCPServer::SetChannelSolo(bool b
2152      dmsg(2,("LSCPServer: SetChannelSolo(bSolo=%d,uiSamplerChannel=%d)\n",bSolo,uiSamplerChannel));      dmsg(2,("LSCPServer: SetChannelSolo(bSolo=%d,uiSamplerChannel=%d)\n",bSolo,uiSamplerChannel));
2153      LSCPResultSet result;      LSCPResultSet result;
2154      try {      try {
2155          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);          EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
         if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));  
   
         EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();  
         if (!pEngineChannel) throw Exception("No engine type assigned to sampler channel");  
2156    
2157          bool oldSolo = pEngineChannel->GetSolo();          bool oldSolo = pEngineChannel->GetSolo();
2158          bool hadSoloChannel = HasSoloChannel();          bool hadSoloChannel = HasSoloChannel();
# Line 1743  String LSCPServer::GetMidiInstrumentMapp Line 2272  String LSCPServer::GetMidiInstrumentMapp
2272      dmsg(2,("LSCPServer: GetMidiInstrumentMappings()\n"));      dmsg(2,("LSCPServer: GetMidiInstrumentMappings()\n"));
2273      LSCPResultSet result;      LSCPResultSet result;
2274      try {      try {
2275          result.Add(MidiInstrumentMapper::Entries(MidiMapID).size());          result.Add(MidiInstrumentMapper::GetInstrumentCount(MidiMapID));
2276      } catch (Exception e) {      } catch (Exception e) {
2277          result.Error(e);          result.Error(e);
2278      }      }
# Line 1754  String LSCPServer::GetMidiInstrumentMapp Line 2283  String LSCPServer::GetMidiInstrumentMapp
2283  String LSCPServer::GetAllMidiInstrumentMappings() {  String LSCPServer::GetAllMidiInstrumentMappings() {
2284      dmsg(2,("LSCPServer: GetAllMidiInstrumentMappings()\n"));      dmsg(2,("LSCPServer: GetAllMidiInstrumentMappings()\n"));
2285      LSCPResultSet result;      LSCPResultSet result;
2286      std::vector<int> maps = MidiInstrumentMapper::Maps();      try {
2287      int totalMappings = 0;          result.Add(MidiInstrumentMapper::GetInstrumentCount());
2288      for (int i = 0; i < maps.size(); i++) {      } catch (Exception e) {
2289          try {          result.Error(e);
             totalMappings += MidiInstrumentMapper::Entries(maps[i]).size();  
         } catch (Exception e) { /*NOOP*/ }  
2290      }      }
     result.Add(totalMappings);  
2291      return result.Produce();      return result.Produce();
2292  }  }
2293    
# Line 1769  String LSCPServer::GetMidiInstrumentMapp Line 2295  String LSCPServer::GetMidiInstrumentMapp
2295      dmsg(2,("LSCPServer: GetMidiIstrumentMapping()\n"));      dmsg(2,("LSCPServer: GetMidiIstrumentMapping()\n"));
2296      LSCPResultSet result;      LSCPResultSet result;
2297      try {      try {
2298          midi_prog_index_t idx;          MidiInstrumentMapper::entry_t entry = MidiInstrumentMapper::GetEntry(MidiMapID, MidiBank, MidiProg);
2299          idx.midi_bank_msb = (MidiBank >> 7) & 0x7f;          // convert the filename into the correct encoding as defined for LSCP
2300          idx.midi_bank_lsb = MidiBank & 0x7f;          // (especially in terms of special characters -> escape sequences)
2301          idx.midi_prog     = MidiProg;  #if WIN32
2302            const String instrumentFileName = Path::fromWindows(entry.InstrumentFile).toLscp();
2303    #else
2304            // assuming POSIX
2305            const String instrumentFileName = Path::fromPosix(entry.InstrumentFile).toLscp();
2306    #endif
2307    
2308          std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t> mappings = MidiInstrumentMapper::Entries(MidiMapID);          result.Add("NAME", _escapeLscpResponse(entry.Name));
2309          std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t>::iterator iter = mappings.find(idx);          result.Add("ENGINE_NAME", entry.EngineName);
2310          if (iter == mappings.end()) result.Error("there is no map entry with that index");          result.Add("INSTRUMENT_FILE", instrumentFileName);
2311          else { // found          result.Add("INSTRUMENT_NR", (int) entry.InstrumentIndex);
2312              result.Add("NAME", iter->second.Name);          String instrumentName;
2313              result.Add("ENGINE_NAME", iter->second.EngineName);          Engine* pEngine = EngineFactory::Create(entry.EngineName);
2314              result.Add("INSTRUMENT_FILE", iter->second.InstrumentFile);          if (pEngine) {
2315              result.Add("INSTRUMENT_NR", (int) iter->second.InstrumentIndex);              if (pEngine->GetInstrumentManager()) {
2316              String instrumentName;                  InstrumentManager::instrument_id_t instrID;
2317              Engine* pEngine = EngineFactory::Create(iter->second.EngineName);                  instrID.FileName = entry.InstrumentFile;
2318              if (pEngine) {                  instrID.Index    = entry.InstrumentIndex;
2319                  if (pEngine->GetInstrumentManager()) {                  instrumentName = pEngine->GetInstrumentManager()->GetInstrumentName(instrID);
                     InstrumentManager::instrument_id_t instrID;  
                     instrID.FileName = iter->second.InstrumentFile;  
                     instrID.Index    = iter->second.InstrumentIndex;  
                     instrumentName = pEngine->GetInstrumentManager()->GetInstrumentName(instrID);  
                 }  
                 EngineFactory::Destroy(pEngine);  
             }  
             result.Add("INSTRUMENT_NAME", instrumentName);  
             switch (iter->second.LoadMode) {  
                 case MidiInstrumentMapper::ON_DEMAND:  
                     result.Add("LOAD_MODE", "ON_DEMAND");  
                     break;  
                 case MidiInstrumentMapper::ON_DEMAND_HOLD:  
                     result.Add("LOAD_MODE", "ON_DEMAND_HOLD");  
                     break;  
                 case MidiInstrumentMapper::PERSISTENT:  
                     result.Add("LOAD_MODE", "PERSISTENT");  
                     break;  
                 default:  
                     throw Exception("entry reflects invalid LOAD_MODE, consider this as a bug!");  
2320              }              }
2321              result.Add("VOLUME", iter->second.Volume);              EngineFactory::Destroy(pEngine);
2322            }
2323            result.Add("INSTRUMENT_NAME", _escapeLscpResponse(instrumentName));
2324            switch (entry.LoadMode) {
2325                case MidiInstrumentMapper::ON_DEMAND:
2326                    result.Add("LOAD_MODE", "ON_DEMAND");
2327                    break;
2328                case MidiInstrumentMapper::ON_DEMAND_HOLD:
2329                    result.Add("LOAD_MODE", "ON_DEMAND_HOLD");
2330                    break;
2331                case MidiInstrumentMapper::PERSISTENT:
2332                    result.Add("LOAD_MODE", "PERSISTENT");
2333                    break;
2334                default:
2335                    throw Exception("entry reflects invalid LOAD_MODE, consider this as a bug!");
2336          }          }
2337            result.Add("VOLUME", entry.Volume);
2338      } catch (Exception e) {      } catch (Exception e) {
2339          result.Error(e);          result.Error(e);
2340      }      }
# Line 1920  String LSCPServer::GetMidiInstrumentMaps Line 2446  String LSCPServer::GetMidiInstrumentMaps
2446      dmsg(2,("LSCPServer: GetMidiInstrumentMaps()\n"));      dmsg(2,("LSCPServer: GetMidiInstrumentMaps()\n"));
2447      LSCPResultSet result;      LSCPResultSet result;
2448      try {      try {
2449          result.Add(MidiInstrumentMapper::Maps().size());          result.Add(int(MidiInstrumentMapper::Maps().size()));
2450      } catch (Exception e) {      } catch (Exception e) {
2451          result.Error(e);          result.Error(e);
2452      }      }
# Line 1948  String LSCPServer::GetMidiInstrumentMap( Line 2474  String LSCPServer::GetMidiInstrumentMap(
2474      dmsg(2,("LSCPServer: GetMidiInstrumentMap()\n"));      dmsg(2,("LSCPServer: GetMidiInstrumentMap()\n"));
2475      LSCPResultSet result;      LSCPResultSet result;
2476      try {      try {
2477          result.Add("NAME", MidiInstrumentMapper::MapName(MidiMapID));          result.Add("NAME", _escapeLscpResponse(MidiInstrumentMapper::MapName(MidiMapID)));
2478          result.Add("DEFAULT", MidiInstrumentMapper::GetDefaultMap() == MidiMapID);          result.Add("DEFAULT", MidiInstrumentMapper::GetDefaultMap() == MidiMapID);
2479      } catch (Exception e) {      } catch (Exception e) {
2480          result.Error(e);          result.Error(e);
# Line 1979  String LSCPServer::SetChannelMap(uint ui Line 2505  String LSCPServer::SetChannelMap(uint ui
2505      dmsg(2,("LSCPServer: SetChannelMap()\n"));      dmsg(2,("LSCPServer: SetChannelMap()\n"));
2506      LSCPResultSet result;      LSCPResultSet result;
2507      try {      try {
2508          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);          EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
         if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));  
   
         EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();  
         if (!pEngineChannel) throw Exception("There is no engine deployed on this sampler channel yet");  
2509    
2510          if      (MidiMapID == -1) pEngineChannel->SetMidiInstrumentMapToNone();          if      (MidiMapID == -1) pEngineChannel->SetMidiInstrumentMapToNone();
2511          else if (MidiMapID == -2) pEngineChannel->SetMidiInstrumentMapToDefault();          else if (MidiMapID == -2) pEngineChannel->SetMidiInstrumentMapToDefault();
# Line 1999  String LSCPServer::CreateFxSend(uint uiS Line 2521  String LSCPServer::CreateFxSend(uint uiS
2521      LSCPResultSet result;      LSCPResultSet result;
2522      try {      try {
2523          EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);          EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2524            
2525          FxSend* pFxSend = pEngineChannel->AddFxSend(MidiCtrl, Name);          FxSend* pFxSend = pEngineChannel->AddFxSend(MidiCtrl, Name);
2526          if (!pFxSend) throw Exception("Could not add FxSend, don't ask, I don't know why (probably a bug)");          if (!pFxSend) throw Exception("Could not add FxSend, don't ask, I don't know why (probably a bug)");
2527    
# Line 2083  String LSCPServer::GetFxSendInfo(uint ui Line 2605  String LSCPServer::GetFxSendInfo(uint ui
2605      try {      try {
2606          EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);          EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2607          FxSend* pFxSend = GetFxSend(uiSamplerChannel, FxSendID);          FxSend* pFxSend = GetFxSend(uiSamplerChannel, FxSendID);
2608            
2609          // gather audio routing informations          // gather audio routing informations
2610          String AudioRouting;          String AudioRouting;
2611          for (int chan = 0; chan < pEngineChannel->Channels(); chan++) {          for (int chan = 0; chan < pEngineChannel->Channels(); chan++) {
# Line 2091  String LSCPServer::GetFxSendInfo(uint ui Line 2613  String LSCPServer::GetFxSendInfo(uint ui
2613              AudioRouting += ToString(pFxSend->DestinationChannel(chan));              AudioRouting += ToString(pFxSend->DestinationChannel(chan));
2614          }          }
2615    
2616            const String sEffectRouting =
2617                (pFxSend->DestinationEffectChain() >= 0 && pFxSend->DestinationEffectChainPosition() >= 0)
2618                    ? ToString(pFxSend->DestinationEffectChain()) + "," + ToString(pFxSend->DestinationEffectChainPosition())
2619                    : "NONE";
2620    
2621          // success          // success
2622          result.Add("NAME", pFxSend->Name());          result.Add("NAME", _escapeLscpResponse(pFxSend->Name()));
2623          result.Add("MIDI_CONTROLLER", pFxSend->MidiController());          result.Add("MIDI_CONTROLLER", pFxSend->MidiController());
2624          result.Add("LEVEL", ToString(pFxSend->Level()));          result.Add("LEVEL", ToString(pFxSend->Level()));
2625          result.Add("AUDIO_OUTPUT_ROUTING", AudioRouting);          result.Add("AUDIO_OUTPUT_ROUTING", AudioRouting);
2626            result.Add("EFFECT", sEffectRouting);
2627      } catch (Exception e) {      } catch (Exception e) {
2628          result.Error(e);          result.Error(e);
2629      }      }
# Line 2158  String LSCPServer::SetFxSendLevel(uint u Line 2686  String LSCPServer::SetFxSendLevel(uint u
2686      return result.Produce();      return result.Produce();
2687  }  }
2688    
2689    String LSCPServer::SetFxSendEffect(uint uiSamplerChannel, uint FxSendID, int iSendEffectChain, int iEffectChainPosition) {
2690        dmsg(2,("LSCPServer: SetFxSendEffect(%d,%d)\n", iSendEffectChain, iEffectChainPosition));
2691        LSCPResultSet result;
2692        try {
2693            FxSend* pFxSend = GetFxSend(uiSamplerChannel, FxSendID);
2694    
2695            pFxSend->SetDestinationEffect(iSendEffectChain, iEffectChainPosition);
2696            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_info, uiSamplerChannel, FxSendID));
2697        } catch (Exception e) {
2698            result.Error(e);
2699        }
2700        return result.Produce();
2701    }
2702    
2703    String LSCPServer::GetAvailableEffects() {
2704        dmsg(2,("LSCPServer: GetAvailableEffects()\n"));
2705        LSCPResultSet result;
2706        try {
2707            int n = EffectFactory::AvailableEffectsCount();
2708            result.Add(n);
2709        }
2710        catch (Exception e) {
2711            result.Error(e);
2712        }
2713        return result.Produce();
2714    }
2715    
2716    String LSCPServer::ListAvailableEffects() {
2717        dmsg(2,("LSCPServer: ListAvailableEffects()\n"));
2718        LSCPResultSet result;
2719        String list;
2720        try {
2721            //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
2722            int n = EffectFactory::AvailableEffectsCount();
2723            for (int i = 0; i < n; i++) {
2724                if (i) list += ",";
2725                list += ToString(i);
2726            }
2727        }
2728        catch (Exception e) {
2729            result.Error(e);
2730        }
2731        result.Add(list);
2732        return result.Produce();
2733    }
2734    
2735    String LSCPServer::GetEffectInfo(int iEffectIndex) {
2736        dmsg(2,("LSCPServer: GetEffectInfo(%d)\n", iEffectIndex));
2737        LSCPResultSet result;
2738        try {
2739            EffectInfo* pEffectInfo = EffectFactory::GetEffectInfo(iEffectIndex);
2740            if (!pEffectInfo)
2741                throw Exception("There is no effect with index " + ToString(iEffectIndex));
2742    
2743            // convert the filename into the correct encoding as defined for LSCP
2744            // (especially in terms of special characters -> escape sequences)
2745    #if WIN32
2746            const String dllFileName = Path::fromWindows(pEffectInfo->Module()).toLscp();
2747    #else
2748            // assuming POSIX
2749            const String dllFileName = Path::fromPosix(pEffectInfo->Module()).toLscp();
2750    #endif
2751    
2752            result.Add("SYSTEM", pEffectInfo->EffectSystem());
2753            result.Add("MODULE", dllFileName);
2754            result.Add("NAME", _escapeLscpResponse(pEffectInfo->Name()));
2755            result.Add("DESCRIPTION", _escapeLscpResponse(pEffectInfo->Description()));
2756        }
2757        catch (Exception e) {
2758            result.Error(e);
2759        }
2760        return result.Produce();    
2761    }
2762    
2763    String LSCPServer::GetEffectInstanceInfo(int iEffectInstance) {
2764        dmsg(2,("LSCPServer: GetEffectInstanceInfo(%d)\n", iEffectInstance));
2765        LSCPResultSet result;
2766        try {
2767            Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
2768            if (!pEffect)
2769                throw Exception("There is no effect instance with ID " + ToString(iEffectInstance));
2770    
2771            EffectInfo* pEffectInfo = pEffect->GetEffectInfo();
2772    
2773            // convert the filename into the correct encoding as defined for LSCP
2774            // (especially in terms of special characters -> escape sequences)
2775    #if WIN32
2776            const String dllFileName = Path::fromWindows(pEffectInfo->Module()).toLscp();
2777    #else
2778            // assuming POSIX
2779            const String dllFileName = Path::fromPosix(pEffectInfo->Module()).toLscp();
2780    #endif
2781    
2782            result.Add("SYSTEM", pEffectInfo->EffectSystem());
2783            result.Add("MODULE", dllFileName);
2784            result.Add("NAME", _escapeLscpResponse(pEffectInfo->Name()));
2785            result.Add("DESCRIPTION", _escapeLscpResponse(pEffectInfo->Description()));
2786            result.Add("INPUT_CONTROLS", ToString(pEffect->InputControlCount()));
2787        }
2788        catch (Exception e) {
2789            result.Error(e);
2790        }
2791        return result.Produce();
2792    }
2793    
2794    String LSCPServer::GetEffectInstanceInputControlInfo(int iEffectInstance, int iInputControlIndex) {
2795        dmsg(2,("LSCPServer: GetEffectInstanceInputControlInfo(%d,%d)\n", iEffectInstance, iInputControlIndex));
2796        LSCPResultSet result;
2797        try {
2798            Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
2799            if (!pEffect)
2800                throw Exception("There is no effect instance with ID " + ToString(iEffectInstance));
2801    
2802            EffectControl* pEffectControl = pEffect->InputControl(iInputControlIndex);
2803            if (!pEffectControl)
2804                throw Exception(
2805                    "Effect instance " + ToString(iEffectInstance) +
2806                    " does not have an input control with index " +
2807                    ToString(iInputControlIndex)
2808                );
2809    
2810            result.Add("DESCRIPTION", _escapeLscpResponse(pEffectControl->Description()));
2811            result.Add("VALUE", pEffectControl->Value());
2812            if (pEffectControl->MinValue())
2813                 result.Add("RANGE_MIN", *pEffectControl->MinValue());
2814            if (pEffectControl->MaxValue())
2815                 result.Add("RANGE_MAX", *pEffectControl->MaxValue());
2816            if (!pEffectControl->Possibilities().empty())
2817                 result.Add("POSSIBILITIES", pEffectControl->Possibilities());
2818            if (pEffectControl->DefaultValue())
2819                 result.Add("DEFAULT", *pEffectControl->DefaultValue());
2820        } catch (Exception e) {
2821            result.Error(e);
2822        }
2823        return result.Produce();
2824    }
2825    
2826    String LSCPServer::SetEffectInstanceInputControlValue(int iEffectInstance, int iInputControlIndex, double dValue) {
2827        dmsg(2,("LSCPServer: SetEffectInstanceInputControlValue(%d,%d,%f)\n", iEffectInstance, iInputControlIndex, dValue));
2828        LSCPResultSet result;
2829        try {
2830            Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
2831            if (!pEffect)
2832                throw Exception("There is no effect instance with ID " + ToString(iEffectInstance));
2833    
2834            EffectControl* pEffectControl = pEffect->InputControl(iInputControlIndex);
2835            if (!pEffectControl)
2836                throw Exception(
2837                    "Effect instance " + ToString(iEffectInstance) +
2838                    " does not have an input control with index " +
2839                    ToString(iInputControlIndex)
2840                );
2841    
2842            pEffectControl->SetValue(dValue);
2843            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_instance_info, iEffectInstance));
2844        } catch (Exception e) {
2845            result.Error(e);
2846        }
2847        return result.Produce();
2848    }
2849    
2850    String LSCPServer::CreateEffectInstance(int iEffectIndex) {
2851        dmsg(2,("LSCPServer: CreateEffectInstance(%d)\n", iEffectIndex));
2852        LSCPResultSet result;
2853        try {
2854            EffectInfo* pEffectInfo = EffectFactory::GetEffectInfo(iEffectIndex);
2855            if (!pEffectInfo)
2856                throw Exception("There is no effect with index " + ToString(iEffectIndex));
2857            Effect* pEffect = EffectFactory::Create(pEffectInfo);
2858            result = pEffect->ID(); // success
2859            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_instance_count, EffectFactory::EffectInstancesCount()));
2860        } catch (Exception e) {
2861            result.Error(e);
2862        }
2863        return result.Produce();
2864    }
2865    
2866    String LSCPServer::CreateEffectInstance(String effectSystem, String module, String effectName) {
2867        dmsg(2,("LSCPServer: CreateEffectInstance('%s','%s','%s')\n", effectSystem.c_str(), module.c_str(), effectName.c_str()));
2868        LSCPResultSet result;
2869        try {
2870            // to allow loading the same LSCP session file on different systems
2871            // successfully, probably with different effect plugin DLL paths or even
2872            // running completely different operating systems, we do the following
2873            // for finding the right effect:
2874            //
2875            // first try to search for an exact match of the effect plugin DLL
2876            // (a.k.a 'module'), to avoid picking the wrong DLL with the same
2877            // effect name ...
2878            EffectInfo* pEffectInfo = EffectFactory::GetEffectInfo(effectSystem, module, effectName, EffectFactory::MODULE_MATCH_EXACTLY);
2879            // ... if no effect with exactly matchin DLL filename was found, then
2880            // try to lower the restrictions of matching the effect plugin DLL
2881            // filename and try again and again ...
2882            if (!pEffectInfo) {
2883                dmsg(2,("no exact module match, trying MODULE_IGNORE_PATH\n"));
2884                pEffectInfo = EffectFactory::GetEffectInfo(effectSystem, module, effectName, EffectFactory::MODULE_IGNORE_PATH);
2885            }
2886            if (!pEffectInfo) {
2887                dmsg(2,("no module match, trying MODULE_IGNORE_PATH | MODULE_IGNORE_CASE\n"));
2888                pEffectInfo = EffectFactory::GetEffectInfo(effectSystem, module, effectName, EffectFactory::MODULE_IGNORE_PATH | EffectFactory::MODULE_IGNORE_CASE);
2889            }
2890            if (!pEffectInfo) {
2891                dmsg(2,("no module match, trying MODULE_IGNORE_PATH | MODULE_IGNORE_CASE | MODULE_IGNORE_EXTENSION\n"));
2892                pEffectInfo = EffectFactory::GetEffectInfo(effectSystem, module, effectName, EffectFactory::MODULE_IGNORE_PATH | EffectFactory::MODULE_IGNORE_CASE | EffectFactory::MODULE_IGNORE_EXTENSION);
2893            }
2894            // ... if there was still no effect found, then completely ignore the
2895            // DLL plugin filename argument and just search for the matching effect
2896            // system type and effect name
2897            if (!pEffectInfo) {
2898                dmsg(2,("no module match, trying MODULE_IGNORE_ALL\n"));
2899                pEffectInfo = EffectFactory::GetEffectInfo(effectSystem, module, effectName, EffectFactory::MODULE_IGNORE_ALL);
2900            }
2901            if (!pEffectInfo)
2902                throw Exception("There is no such effect '" + effectSystem + "' '" + module + "' '" + effectName + "'");
2903    
2904            Effect* pEffect = EffectFactory::Create(pEffectInfo);
2905            result = LSCPResultSet(pEffect->ID());
2906            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_instance_count, EffectFactory::EffectInstancesCount()));
2907        } catch (Exception e) {
2908            result.Error(e);
2909        }
2910        return result.Produce();
2911    }
2912    
2913    String LSCPServer::DestroyEffectInstance(int iEffectInstance) {
2914        dmsg(2,("LSCPServer: DestroyEffectInstance(%d)\n", iEffectInstance));
2915        LSCPResultSet result;
2916        try {
2917            Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
2918            if (!pEffect)
2919                throw Exception("There is no effect instance with ID " + ToString(iEffectInstance));
2920            EffectFactory::Destroy(pEffect);
2921            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_instance_count, EffectFactory::EffectInstancesCount()));
2922        } catch (Exception e) {
2923            result.Error(e);
2924        }
2925        return result.Produce();
2926    }
2927    
2928    String LSCPServer::GetEffectInstances() {
2929        dmsg(2,("LSCPServer: GetEffectInstances()\n"));
2930        LSCPResultSet result;
2931        try {
2932            int n = EffectFactory::EffectInstancesCount();
2933            result.Add(n);
2934        } catch (Exception e) {
2935            result.Error(e);
2936        }
2937        return result.Produce();
2938    }
2939    
2940    String LSCPServer::ListEffectInstances() {
2941        dmsg(2,("LSCPServer: ListEffectInstances()\n"));
2942        LSCPResultSet result;
2943        String list;
2944        try {
2945            int n = EffectFactory::EffectInstancesCount();
2946            for (int i = 0; i < n; i++) {
2947                Effect* pEffect = EffectFactory::GetEffectInstance(i);
2948                if (i) list += ",";
2949                list += ToString(pEffect->ID());
2950            }
2951        } catch (Exception e) {
2952            result.Error(e);
2953        }
2954        result.Add(list);
2955        return result.Produce();
2956    }
2957    
2958    String LSCPServer::GetSendEffectChains(int iAudioOutputDevice) {
2959        dmsg(2,("LSCPServer: GetSendEffectChains(%d)\n", iAudioOutputDevice));
2960        LSCPResultSet result;
2961        try {
2962            std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
2963            if (!devices.count(iAudioOutputDevice))
2964                throw Exception("There is no audio output device with index " + ToString(iAudioOutputDevice) + ".");
2965            AudioOutputDevice* pDevice = devices[iAudioOutputDevice];
2966            int n = pDevice->SendEffectChainCount();
2967            result.Add(n);
2968        } catch (Exception e) {
2969            result.Error(e);
2970        }
2971        return result.Produce();
2972    }
2973    
2974    String LSCPServer::ListSendEffectChains(int iAudioOutputDevice) {
2975        dmsg(2,("LSCPServer: ListSendEffectChains(%d)\n", iAudioOutputDevice));
2976        LSCPResultSet result;
2977        String list;
2978        try {
2979            std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
2980            if (!devices.count(iAudioOutputDevice))
2981                throw Exception("There is no audio output device with index " + ToString(iAudioOutputDevice) + ".");
2982            AudioOutputDevice* pDevice = devices[iAudioOutputDevice];
2983            int n = pDevice->SendEffectChainCount();
2984            for (int i = 0; i < n; i++) {
2985                EffectChain* pEffectChain = pDevice->SendEffectChain(i);
2986                if (i) list += ",";
2987                list += ToString(pEffectChain->ID());
2988            }
2989        } catch (Exception e) {
2990            result.Error(e);
2991        }
2992        result.Add(list);
2993        return result.Produce();
2994    }
2995    
2996    String LSCPServer::AddSendEffectChain(int iAudioOutputDevice) {
2997        dmsg(2,("LSCPServer: AddSendEffectChain(%d)\n", iAudioOutputDevice));
2998        LSCPResultSet result;
2999        try {
3000            std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
3001            if (!devices.count(iAudioOutputDevice))
3002                throw Exception("There is no audio output device with index " + ToString(iAudioOutputDevice) + ".");
3003            AudioOutputDevice* pDevice = devices[iAudioOutputDevice];
3004            EffectChain* pEffectChain = pDevice->AddSendEffectChain();
3005            result = pEffectChain->ID();
3006            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_send_fx_chain_count, iAudioOutputDevice, pDevice->SendEffectChainCount()));
3007        } catch (Exception e) {
3008            result.Error(e);
3009        }
3010        return result.Produce();
3011    }
3012    
3013    String LSCPServer::RemoveSendEffectChain(int iAudioOutputDevice, int iSendEffectChain) {
3014        dmsg(2,("LSCPServer: RemoveSendEffectChain(%d,%d)\n", iAudioOutputDevice, iSendEffectChain));
3015        LSCPResultSet result;
3016        try {
3017            std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
3018            if (!devices.count(iAudioOutputDevice))
3019                throw Exception("There is no audio output device with index " + ToString(iAudioOutputDevice) + ".");
3020    
3021            std::set<EngineChannel*> engineChannels = EngineChannelFactory::EngineChannelInstances();
3022            std::set<EngineChannel*>::iterator itEngineChannel = engineChannels.begin();
3023            std::set<EngineChannel*>::iterator itEnd           = engineChannels.end();
3024            for (; itEngineChannel != itEnd; ++itEngineChannel) {
3025                AudioOutputDevice* pDev = (*itEngineChannel)->GetAudioOutputDevice();
3026                if (pDev != NULL && pDev->deviceId() == iAudioOutputDevice) {
3027                    for (int i = 0; i < (*itEngineChannel)->GetFxSendCount(); i++) {
3028                        FxSend* fxs = (*itEngineChannel)->GetFxSend(i);
3029                        if(fxs != NULL && fxs->DestinationEffectChain() == iSendEffectChain) {
3030                            throw Exception("The effect chain is still in use by channel " + ToString((*itEngineChannel)->GetSamplerChannel()->Index()));
3031                        }
3032                    }
3033                }
3034            }
3035    
3036            AudioOutputDevice* pDevice = devices[iAudioOutputDevice];
3037            for (int i = 0; i < pDevice->SendEffectChainCount(); i++) {
3038                EffectChain* pEffectChain = pDevice->SendEffectChain(i);
3039                if (pEffectChain->ID() == iSendEffectChain) {
3040                    pDevice->RemoveSendEffectChain(i);
3041                    LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_send_fx_chain_count, iAudioOutputDevice, pDevice->SendEffectChainCount()));
3042                    return result.Produce();
3043                }
3044            }
3045            throw Exception(
3046                "There is no send effect chain with ID " +
3047                ToString(iSendEffectChain) + " for audio output device " +
3048                ToString(iAudioOutputDevice) + "."
3049            );
3050        } catch (Exception e) {
3051            result.Error(e);
3052        }
3053        return result.Produce();
3054    }
3055    
3056    static EffectChain* _getSendEffectChain(Sampler* pSampler, int iAudioOutputDevice, int iSendEffectChain) throw (Exception) {
3057        std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
3058        if (!devices.count(iAudioOutputDevice))
3059            throw Exception(
3060                "There is no audio output device with index " +
3061                ToString(iAudioOutputDevice) + "."
3062            );
3063        AudioOutputDevice* pDevice = devices[iAudioOutputDevice];
3064        EffectChain* pEffectChain = pDevice->SendEffectChainByID(iSendEffectChain);
3065        if(pEffectChain != NULL) return pEffectChain;
3066        throw Exception(
3067            "There is no send effect chain with ID " +
3068            ToString(iSendEffectChain) + " for audio output device " +
3069            ToString(iAudioOutputDevice) + "."
3070        );
3071    }
3072    
3073    String LSCPServer::GetSendEffectChainInfo(int iAudioOutputDevice, int iSendEffectChain) {
3074        dmsg(2,("LSCPServer: GetSendEffectChainInfo(%d,%d)\n", iAudioOutputDevice, iSendEffectChain));
3075        LSCPResultSet result;
3076        try {
3077            EffectChain* pEffectChain =
3078                _getSendEffectChain(pSampler, iAudioOutputDevice, iSendEffectChain);
3079            String sEffectSequence;
3080            for (int i = 0; i < pEffectChain->EffectCount(); i++) {
3081                if (i) sEffectSequence += ",";
3082                sEffectSequence += ToString(pEffectChain->GetEffect(i)->ID());
3083            }
3084            result.Add("EFFECT_COUNT", pEffectChain->EffectCount());
3085            result.Add("EFFECT_SEQUENCE", sEffectSequence);
3086        } catch (Exception e) {
3087            result.Error(e);
3088        }
3089        return result.Produce();
3090    }
3091    
3092    String LSCPServer::AppendSendEffectChainEffect(int iAudioOutputDevice, int iSendEffectChain, int iEffectInstance) {
3093        dmsg(2,("LSCPServer: AppendSendEffectChainEffect(%d,%d,%d)\n", iAudioOutputDevice, iSendEffectChain, iEffectInstance));
3094        LSCPResultSet result;
3095        try {
3096            EffectChain* pEffectChain =
3097                _getSendEffectChain(pSampler, iAudioOutputDevice, iSendEffectChain);
3098            Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
3099            if (!pEffect)
3100                throw Exception("There is no effect instance with ID " + ToString(iEffectInstance));
3101            pEffectChain->AppendEffect(pEffect);
3102            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_send_fx_chain_info, iAudioOutputDevice, iSendEffectChain, pEffectChain->EffectCount()));
3103        } catch (Exception e) {
3104            result.Error(e);
3105        }
3106        return result.Produce();
3107    }
3108    
3109    String LSCPServer::InsertSendEffectChainEffect(int iAudioOutputDevice, int iSendEffectChain, int iEffectChainPosition, int iEffectInstance) {
3110        dmsg(2,("LSCPServer: InsertSendEffectChainEffect(%d,%d,%d,%d)\n", iAudioOutputDevice, iSendEffectChain, iEffectChainPosition, iEffectInstance));
3111        LSCPResultSet result;
3112        try {
3113            EffectChain* pEffectChain =
3114                _getSendEffectChain(pSampler, iAudioOutputDevice, iSendEffectChain);
3115            Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
3116            if (!pEffect)
3117                throw Exception("There is no effect instance with index " + ToString(iEffectInstance));
3118            pEffectChain->InsertEffect(pEffect, iEffectChainPosition);
3119            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_send_fx_chain_info, iAudioOutputDevice, iSendEffectChain, pEffectChain->EffectCount()));
3120        } catch (Exception e) {
3121            result.Error(e);
3122        }
3123        return result.Produce();
3124    }
3125    
3126    String LSCPServer::RemoveSendEffectChainEffect(int iAudioOutputDevice, int iSendEffectChain, int iEffectChainPosition) {
3127        dmsg(2,("LSCPServer: RemoveSendEffectChainEffect(%d,%d,%d)\n", iAudioOutputDevice, iSendEffectChain, iEffectChainPosition));
3128        LSCPResultSet result;
3129        try {
3130            EffectChain* pEffectChain =
3131                _getSendEffectChain(pSampler, iAudioOutputDevice, iSendEffectChain);
3132    
3133            std::set<EngineChannel*> engineChannels = EngineChannelFactory::EngineChannelInstances();
3134            std::set<EngineChannel*>::iterator itEngineChannel = engineChannels.begin();
3135            std::set<EngineChannel*>::iterator itEnd           = engineChannels.end();
3136            for (; itEngineChannel != itEnd; ++itEngineChannel) {
3137                AudioOutputDevice* pDev = (*itEngineChannel)->GetAudioOutputDevice();
3138                if (pDev != NULL && pDev->deviceId() == iAudioOutputDevice) {
3139                    for (int i = 0; i < (*itEngineChannel)->GetFxSendCount(); i++) {
3140                        FxSend* fxs = (*itEngineChannel)->GetFxSend(i);
3141                        if(fxs != NULL && fxs->DestinationEffectChain() == iSendEffectChain && fxs->DestinationEffectChainPosition() == iEffectChainPosition) {
3142                            throw Exception("The effect instance is still in use by channel " + ToString((*itEngineChannel)->GetSamplerChannel()->Index()));
3143                        }
3144                    }
3145                }
3146            }
3147    
3148            pEffectChain->RemoveEffect(iEffectChainPosition);
3149            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_send_fx_chain_info, iAudioOutputDevice, iSendEffectChain, pEffectChain->EffectCount()));
3150        } catch (Exception e) {
3151            result.Error(e);
3152        }
3153        return result.Produce();
3154    }
3155    
3156  String LSCPServer::EditSamplerChannelInstrument(uint uiSamplerChannel) {  String LSCPServer::EditSamplerChannelInstrument(uint uiSamplerChannel) {
3157      dmsg(2,("LSCPServer: EditSamplerChannelInstrument(SamplerChannel=%d)\n", uiSamplerChannel));      dmsg(2,("LSCPServer: EditSamplerChannelInstrument(SamplerChannel=%d)\n", uiSamplerChannel));
3158      LSCPResultSet result;      LSCPResultSet result;
3159      try {      try {
3160          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);          EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
3161          if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));          if (pEngineChannel->InstrumentStatus() < 0) throw Exception("No instrument loaded to sampler channel");
         EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();  
         if (!pEngineChannel) throw Exception("No engine type assigned to sampler channel");  
3162          Engine* pEngine = pEngineChannel->GetEngine();          Engine* pEngine = pEngineChannel->GetEngine();
3163          InstrumentManager* pInstrumentManager = pEngine->GetInstrumentManager();          InstrumentManager* pInstrumentManager = pEngine->GetInstrumentManager();
3164          if (!pInstrumentManager) throw Exception("Engine does not provide an instrument manager");          if (!pInstrumentManager) throw Exception("Engine does not provide an instrument manager");
3165          InstrumentManager::instrument_id_t instrumentID;          InstrumentManager::instrument_id_t instrumentID;
3166          instrumentID.FileName = pEngineChannel->InstrumentFileName();          instrumentID.FileName = pEngineChannel->InstrumentFileName();
3167          instrumentID.Index    = pEngineChannel->InstrumentIndex();          instrumentID.Index    = pEngineChannel->InstrumentIndex();
3168          pInstrumentManager->LaunchInstrumentEditor(instrumentID);          pInstrumentManager->LaunchInstrumentEditor(pEngineChannel, instrumentID);
3169        } catch (Exception e) {
3170            result.Error(e);
3171        }
3172        return result.Produce();
3173    }
3174    
3175    String LSCPServer::SendChannelMidiData(String MidiMsg, uint uiSamplerChannel, uint Arg1, uint Arg2) {
3176        dmsg(2,("LSCPServer: SendChannelMidiData(MidiMsg=%s,uiSamplerChannel=%d,Arg1=%d,Arg2=%d)\n", MidiMsg.c_str(), uiSamplerChannel, Arg1, Arg2));
3177        LSCPResultSet result;
3178        try {
3179            EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
3180    
3181            if (Arg1 > 127 || Arg2 > 127) {
3182                throw Exception("Invalid MIDI message");
3183            }
3184    
3185            VirtualMidiDevice* pMidiDevice = NULL;
3186            std::vector<EventHandler::midi_listener_entry>::iterator iter = eventHandler.channelMidiListeners.begin();
3187            for (; iter != eventHandler.channelMidiListeners.end(); ++iter) {
3188                if ((*iter).pEngineChannel == pEngineChannel) {
3189                    pMidiDevice = (*iter).pMidiListener;
3190                    break;
3191                }
3192            }
3193            
3194            if(pMidiDevice == NULL) throw Exception("Couldn't find virtual MIDI device");
3195    
3196            if (MidiMsg == "NOTE_ON") {
3197                pMidiDevice->SendNoteOnToDevice(Arg1, Arg2);
3198                bool b = pMidiDevice->SendNoteOnToSampler(Arg1, Arg2);
3199                if (!b) throw Exception("MIDI event failed: " + MidiMsg + " " + ToString(Arg1) + " " + ToString(Arg2));
3200            } else if (MidiMsg == "NOTE_OFF") {
3201                pMidiDevice->SendNoteOffToDevice(Arg1, Arg2);
3202                bool b = pMidiDevice->SendNoteOffToSampler(Arg1, Arg2);
3203                if (!b) throw Exception("MIDI event failed: " + MidiMsg + " " + ToString(Arg1) + " " + ToString(Arg2));
3204            } else if (MidiMsg == "CC") {
3205                pMidiDevice->SendCCToDevice(Arg1, Arg2);
3206                bool b = pMidiDevice->SendCCToSampler(Arg1, Arg2);
3207                if (!b) throw Exception("MIDI event failed: " + MidiMsg + " " + ToString(Arg1) + " " + ToString(Arg2));
3208            } else {
3209                throw Exception("Unknown MIDI message type: " + MidiMsg);
3210            }
3211      } catch (Exception e) {      } catch (Exception e) {
3212          result.Error(e);          result.Error(e);
3213      }      }
# Line 2186  String LSCPServer::ResetChannel(uint uiS Line 3221  String LSCPServer::ResetChannel(uint uiS
3221      dmsg(2,("LSCPServer: ResetChannel(SamplerChannel=%d)\n", uiSamplerChannel));      dmsg(2,("LSCPServer: ResetChannel(SamplerChannel=%d)\n", uiSamplerChannel));
3222      LSCPResultSet result;      LSCPResultSet result;
3223      try {      try {
3224          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);          EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
         if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));  
         EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();  
         if (!pEngineChannel) throw Exception("No engine type assigned to sampler channel");  
3225          pEngineChannel->Reset();          pEngineChannel->Reset();
3226      }      }
3227      catch (Exception e) {      catch (Exception e) {
# Line 2214  String LSCPServer::ResetSampler() { Line 3246  String LSCPServer::ResetSampler() {
3246   */   */
3247  String LSCPServer::GetServerInfo() {  String LSCPServer::GetServerInfo() {
3248      dmsg(2,("LSCPServer: GetServerInfo()\n"));      dmsg(2,("LSCPServer: GetServerInfo()\n"));
3249        const std::string description =
3250            _escapeLscpResponse("LinuxSampler - modular, streaming capable sampler");
3251      LSCPResultSet result;      LSCPResultSet result;
3252      result.Add("DESCRIPTION", "LinuxSampler - modular, streaming capable sampler");      result.Add("DESCRIPTION", description);
3253      result.Add("VERSION", VERSION);      result.Add("VERSION", VERSION);
3254      result.Add("PROTOCOL_VERSION", ToString(LSCP_RELEASE_MAJOR) + "." + ToString(LSCP_RELEASE_MINOR));      result.Add("PROTOCOL_VERSION", ToString(LSCP_RELEASE_MAJOR) + "." + ToString(LSCP_RELEASE_MINOR));
3255  #if HAVE_SQLITE3  #if HAVE_SQLITE3
# Line 2223  String LSCPServer::GetServerInfo() { Line 3257  String LSCPServer::GetServerInfo() {
3257  #else  #else
3258      result.Add("INSTRUMENTS_DB_SUPPORT", "no");      result.Add("INSTRUMENTS_DB_SUPPORT", "no");
3259  #endif  #endif
3260        
3261        return result.Produce();
3262    }
3263    
3264    /**
3265     * Will be called by the parser to return the current number of all active streams.
3266     */
3267    String LSCPServer::GetTotalStreamCount() {
3268        dmsg(2,("LSCPServer: GetTotalStreamCount()\n"));
3269        LSCPResultSet result;
3270        result.Add(pSampler->GetDiskStreamCount());
3271      return result.Produce();      return result.Produce();
3272  }  }
3273    
# Line 2243  String LSCPServer::GetTotalVoiceCount() Line 3287  String LSCPServer::GetTotalVoiceCount()
3287  String LSCPServer::GetTotalVoiceCountMax() {  String LSCPServer::GetTotalVoiceCountMax() {
3288      dmsg(2,("LSCPServer: GetTotalVoiceCountMax()\n"));      dmsg(2,("LSCPServer: GetTotalVoiceCountMax()\n"));
3289      LSCPResultSet result;      LSCPResultSet result;
3290      result.Add(EngineFactory::EngineInstances().size() * CONFIG_MAX_VOICES);      result.Add(int(EngineFactory::EngineInstances().size() * pSampler->GetGlobalMaxVoices()));
3291        return result.Produce();
3292    }
3293    
3294    /**
3295     * Will be called by the parser to return the sampler global maximum
3296     * allowed number of voices.
3297     */
3298    String LSCPServer::GetGlobalMaxVoices() {
3299        dmsg(2,("LSCPServer: GetGlobalMaxVoices()\n"));
3300        LSCPResultSet result;
3301        result.Add(pSampler->GetGlobalMaxVoices());
3302        return result.Produce();
3303    }
3304    
3305    /**
3306     * Will be called by the parser to set the sampler global maximum number of
3307     * voices.
3308     */
3309    String LSCPServer::SetGlobalMaxVoices(int iVoices) {
3310        dmsg(2,("LSCPServer: SetGlobalMaxVoices(%d)\n", iVoices));
3311        LSCPResultSet result;
3312        try {
3313            pSampler->SetGlobalMaxVoices(iVoices);
3314            LSCPServer::SendLSCPNotify(
3315                LSCPEvent(LSCPEvent::event_global_info, "VOICES", pSampler->GetGlobalMaxVoices())
3316            );
3317        } catch (Exception e) {
3318            result.Error(e);
3319        }
3320        return result.Produce();
3321    }
3322    
3323    /**
3324     * Will be called by the parser to return the sampler global maximum
3325     * allowed number of disk streams.
3326     */
3327    String LSCPServer::GetGlobalMaxStreams() {
3328        dmsg(2,("LSCPServer: GetGlobalMaxStreams()\n"));
3329        LSCPResultSet result;
3330        result.Add(pSampler->GetGlobalMaxStreams());
3331        return result.Produce();
3332    }
3333    
3334    /**
3335     * Will be called by the parser to set the sampler global maximum number of
3336     * disk streams.
3337     */
3338    String LSCPServer::SetGlobalMaxStreams(int iStreams) {
3339        dmsg(2,("LSCPServer: SetGlobalMaxStreams(%d)\n", iStreams));
3340        LSCPResultSet result;
3341        try {
3342            pSampler->SetGlobalMaxStreams(iStreams);
3343            LSCPServer::SendLSCPNotify(
3344                LSCPEvent(LSCPEvent::event_global_info, "STREAMS", pSampler->GetGlobalMaxStreams())
3345            );
3346        } catch (Exception e) {
3347            result.Error(e);
3348        }
3349      return result.Produce();      return result.Produce();
3350  }  }
3351    
# Line 2257  String LSCPServer::SetGlobalVolume(doubl Line 3359  String LSCPServer::SetGlobalVolume(doubl
3359      LSCPResultSet result;      LSCPResultSet result;
3360      try {      try {
3361          if (dVolume < 0) throw Exception("Volume may not be negative");          if (dVolume < 0) throw Exception("Volume may not be negative");
3362          GLOBAL_VOLUME = dVolume; // see common/global.cpp          GLOBAL_VOLUME = dVolume; // see common/global_private.cpp
3363          LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_global_info, "VOLUME", GLOBAL_VOLUME));          LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_global_info, "VOLUME", GLOBAL_VOLUME));
3364      } catch (Exception e) {      } catch (Exception e) {
3365          result.Error(e);          result.Error(e);
# Line 2265  String LSCPServer::SetGlobalVolume(doubl Line 3367  String LSCPServer::SetGlobalVolume(doubl
3367      return result.Produce();      return result.Produce();
3368  }  }
3369    
3370    String LSCPServer::GetFileInstruments(String Filename) {
3371        dmsg(2,("LSCPServer: GetFileInstruments(String Filename=%s)\n",Filename.c_str()));
3372        LSCPResultSet result;
3373        try {
3374            VerifyFile(Filename);
3375        } catch (Exception e) {
3376            result.Error(e);
3377            return result.Produce();
3378        }
3379        // try to find a sampler engine that can handle the file
3380        bool bFound = false;
3381        std::vector<String> engineTypes = EngineFactory::AvailableEngineTypes();
3382        for (int i = 0; !bFound && i < engineTypes.size(); i++) {
3383            Engine* pEngine = NULL;
3384            try {
3385                pEngine = EngineFactory::Create(engineTypes[i]);
3386                if (!pEngine) throw Exception("Internal error: could not create '" + engineTypes[i] + "' engine");
3387                InstrumentManager* pManager = pEngine->GetInstrumentManager();
3388                if (pManager) {
3389                    std::vector<InstrumentManager::instrument_id_t> IDs =
3390                        pManager->GetInstrumentFileContent(Filename);
3391                    // return the amount of instruments in the file
3392                    result.Add((int)IDs.size());
3393                    // no more need to ask other engine types
3394                    bFound = true;
3395                } else dmsg(1,("Warning: engine '%s' does not provide an instrument manager\n", engineTypes[i].c_str()));
3396            } catch (Exception e) {
3397                // NOOP, as exception is thrown if engine doesn't support file
3398            }
3399            if (pEngine) EngineFactory::Destroy(pEngine);
3400        }
3401    
3402        if (!bFound) result.Error("Unknown file format");
3403        return result.Produce();
3404    }
3405    
3406    String LSCPServer::ListFileInstruments(String Filename) {
3407        dmsg(2,("LSCPServer: ListFileInstruments(String Filename=%s)\n",Filename.c_str()));
3408        LSCPResultSet result;
3409        try {
3410            VerifyFile(Filename);
3411        } catch (Exception e) {
3412            result.Error(e);
3413            return result.Produce();
3414        }
3415        // try to find a sampler engine that can handle the file
3416        bool bFound = false;
3417        std::vector<String> engineTypes = EngineFactory::AvailableEngineTypes();
3418        for (int i = 0; !bFound && i < engineTypes.size(); i++) {
3419            Engine* pEngine = NULL;
3420            try {
3421                pEngine = EngineFactory::Create(engineTypes[i]);
3422                if (!pEngine) throw Exception("Internal error: could not create '" + engineTypes[i] + "' engine");
3423                InstrumentManager* pManager = pEngine->GetInstrumentManager();
3424                if (pManager) {
3425                    std::vector<InstrumentManager::instrument_id_t> IDs =
3426                        pManager->GetInstrumentFileContent(Filename);
3427                    // return a list of IDs of the instruments in the file
3428                    String s;
3429                    for (int j = 0; j < IDs.size(); j++) {
3430                        if (s.size()) s += ",";
3431                        s += ToString(IDs[j].Index);
3432                    }
3433                    result.Add(s);
3434                    // no more need to ask other engine types
3435                    bFound = true;
3436                } else dmsg(1,("Warning: engine '%s' does not provide an instrument manager\n", engineTypes[i].c_str()));
3437            } catch (Exception e) {
3438                // NOOP, as exception is thrown if engine doesn't support file
3439            }
3440            if (pEngine) EngineFactory::Destroy(pEngine);
3441        }
3442    
3443        if (!bFound) result.Error("Unknown file format");
3444        return result.Produce();
3445    }
3446    
3447    String LSCPServer::GetFileInstrumentInfo(String Filename, uint InstrumentID) {
3448        dmsg(2,("LSCPServer: GetFileInstrumentInfo(String Filename=%s, InstrumentID=%d)\n",Filename.c_str(),InstrumentID));
3449        LSCPResultSet result;
3450        try {
3451            VerifyFile(Filename);
3452        } catch (Exception e) {
3453            result.Error(e);
3454            return result.Produce();
3455        }
3456        InstrumentManager::instrument_id_t id;
3457        id.FileName = Filename;
3458        id.Index    = InstrumentID;
3459        // try to find a sampler engine that can handle the file
3460        bool bFound = false;
3461        bool bFatalErr = false;
3462        std::vector<String> engineTypes = EngineFactory::AvailableEngineTypes();
3463        for (int i = 0; !bFound && !bFatalErr && i < engineTypes.size(); i++) {
3464            Engine* pEngine = NULL;
3465            try {
3466                pEngine = EngineFactory::Create(engineTypes[i]);
3467                if (!pEngine) throw Exception("Internal error: could not create '" + engineTypes[i] + "' engine");
3468                InstrumentManager* pManager = pEngine->GetInstrumentManager();
3469                if (pManager) {
3470                    // check if the instrument index is valid
3471                    // FIXME: this won't work if an engine only supports parts of the instrument file
3472                    std::vector<InstrumentManager::instrument_id_t> IDs =
3473                        pManager->GetInstrumentFileContent(Filename);
3474                    if (std::find(IDs.begin(), IDs.end(), id) == IDs.end()) {
3475                        std::stringstream ss;
3476                        ss << "Invalid instrument index " << InstrumentID << " for instrument file '" << Filename << "'";
3477                        bFatalErr = true;
3478                        throw Exception(ss.str());
3479                    }
3480                    // get the info of the requested instrument
3481                    InstrumentManager::instrument_info_t info =
3482                        pManager->GetInstrumentInfo(id);
3483                    // return detailed informations about the file
3484                    result.Add("NAME", info.InstrumentName);
3485                    result.Add("FORMAT_FAMILY", engineTypes[i]);
3486                    result.Add("FORMAT_VERSION", info.FormatVersion);
3487                    result.Add("PRODUCT", info.Product);
3488                    result.Add("ARTISTS", info.Artists);
3489    
3490                    std::stringstream ss;
3491                    bool b = false;
3492                    for (int i = 0; i < 128; i++) {
3493                        if (info.KeyBindings[i]) {
3494                            if (b) ss << ',';
3495                            ss << i; b = true;
3496                        }
3497                    }
3498                    result.Add("KEY_BINDINGS", ss.str());
3499    
3500                    b = false;
3501                    std::stringstream ss2;
3502                    for (int i = 0; i < 128; i++) {
3503                        if (info.KeySwitchBindings[i]) {
3504                            if (b) ss2 << ',';
3505                            ss2 << i; b = true;
3506                        }
3507                    }
3508                    result.Add("KEYSWITCH_BINDINGS", ss2.str());
3509                    // no more need to ask other engine types
3510                    bFound = true;
3511                } else dmsg(1,("Warning: engine '%s' does not provide an instrument manager\n", engineTypes[i].c_str()));
3512            } catch (Exception e) {
3513                // usually NOOP, as exception is thrown if engine doesn't support file
3514                if (bFatalErr) result.Error(e);
3515            }
3516            if (pEngine) EngineFactory::Destroy(pEngine);
3517        }
3518    
3519        if (!bFound && !bFatalErr) result.Error("Unknown file format");
3520        return result.Produce();
3521    }
3522    
3523    void LSCPServer::VerifyFile(String Filename) {
3524        #if WIN32
3525        WIN32_FIND_DATA win32FileAttributeData;
3526        BOOL res = GetFileAttributesEx( Filename.c_str(), GetFileExInfoStandard, &win32FileAttributeData );
3527        if (!res) {
3528            std::stringstream ss;
3529            ss << "File does not exist, GetFileAttributesEx failed `" << Filename << "`: Error " << GetLastError();
3530            throw Exception(ss.str());
3531        }
3532        if ( win32FileAttributeData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
3533            throw Exception("Directory is specified");
3534        }
3535        #else
3536        File f(Filename);
3537        if(!f.Exist()) throw Exception(f.GetErrorMsg());
3538        if (f.IsDirectory()) throw Exception("Directory is specified");
3539        #endif
3540    }
3541    
3542  /**  /**
3543   * Will be called by the parser to subscribe a client (frontend) on the   * Will be called by the parser to subscribe a client (frontend) on the
3544   * server for receiving event messages.   * server for receiving event messages.
# Line 2272  String LSCPServer::SetGlobalVolume(doubl Line 3546  String LSCPServer::SetGlobalVolume(doubl
3546  String LSCPServer::SubscribeNotification(LSCPEvent::event_t type) {  String LSCPServer::SubscribeNotification(LSCPEvent::event_t type) {
3547      dmsg(2,("LSCPServer: SubscribeNotification(Event=%s)\n", LSCPEvent::Name(type).c_str()));      dmsg(2,("LSCPServer: SubscribeNotification(Event=%s)\n", LSCPEvent::Name(type).c_str()));
3548      LSCPResultSet result;      LSCPResultSet result;
3549      SubscriptionMutex.Lock();      {
3550      eventSubscriptions[type].push_back(currentSocket);          LockGuard lock(SubscriptionMutex);
3551      SubscriptionMutex.Unlock();          eventSubscriptions[type].push_back(currentSocket);
3552        }
3553      return result.Produce();      return result.Produce();
3554  }  }
3555    
# Line 2285  String LSCPServer::SubscribeNotification Line 3560  String LSCPServer::SubscribeNotification
3560  String LSCPServer::UnsubscribeNotification(LSCPEvent::event_t type) {  String LSCPServer::UnsubscribeNotification(LSCPEvent::event_t type) {
3561      dmsg(2,("LSCPServer: UnsubscribeNotification(Event=%s)\n", LSCPEvent::Name(type).c_str()));      dmsg(2,("LSCPServer: UnsubscribeNotification(Event=%s)\n", LSCPEvent::Name(type).c_str()));
3562      LSCPResultSet result;      LSCPResultSet result;
3563      SubscriptionMutex.Lock();      {
3564      eventSubscriptions[type].remove(currentSocket);          LockGuard lock(SubscriptionMutex);
3565      SubscriptionMutex.Unlock();          eventSubscriptions[type].remove(currentSocket);
3566        }
3567      return result.Produce();      return result.Produce();
3568  }  }
3569    
# Line 2346  String LSCPServer::GetDbInstrumentDirect Line 3622  String LSCPServer::GetDbInstrumentDirect
3622    
3623          for (int i = 0; i < dirs->size(); i++) {          for (int i = 0; i < dirs->size(); i++) {
3624              if (list != "") list += ",";              if (list != "") list += ",";
3625              list += "'" + dirs->at(i) + "'";              list += "'" + InstrumentsDb::toEscapedPath(dirs->at(i)) + "'";
3626          }          }
3627    
3628          result.Add(list);          result.Add(list);
# Line 2366  String LSCPServer::GetDbInstrumentDirect Line 3642  String LSCPServer::GetDbInstrumentDirect
3642      try {      try {
3643          DbDirectory info = InstrumentsDb::GetInstrumentsDb()->GetDirectoryInfo(Dir);          DbDirectory info = InstrumentsDb::GetInstrumentsDb()->GetDirectoryInfo(Dir);
3644    
3645          result.Add("DESCRIPTION", info.Description);          result.Add("DESCRIPTION", _escapeLscpResponse(info.Description));
3646          result.Add("CREATED", info.Created);          result.Add("CREATED", info.Created);
3647          result.Add("MODIFIED", info.Modified);          result.Add("MODIFIED", info.Modified);
3648      } catch (Exception e) {      } catch (Exception e) {
# Line 2456  String LSCPServer::AddDbInstruments(Stri Line 3732  String LSCPServer::AddDbInstruments(Stri
3732      return result.Produce();      return result.Produce();
3733  }  }
3734    
3735  String LSCPServer::AddDbInstruments(String ScanMode, String DbDir, String FsDir, bool bBackground) {  String LSCPServer::AddDbInstruments(String ScanMode, String DbDir, String FsDir, bool bBackground, bool insDir) {
3736      dmsg(2,("LSCPServer: AddDbInstruments(ScanMode=%s,DbDir=%s,FsDir=%s,bBackground=%d)\n", ScanMode.c_str(), DbDir.c_str(), FsDir.c_str(), bBackground));      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));
3737      LSCPResultSet result;      LSCPResultSet result;
3738  #if HAVE_SQLITE3  #if HAVE_SQLITE3
3739      try {      try {
3740          int id;          int id;
3741          InstrumentsDb* db = InstrumentsDb::GetInstrumentsDb();          InstrumentsDb* db = InstrumentsDb::GetInstrumentsDb();
3742          if (ScanMode.compare("RECURSIVE") == 0) {          if (ScanMode.compare("RECURSIVE") == 0) {
3743             id = db->AddInstruments(RECURSIVE, DbDir, FsDir, bBackground);              id = db->AddInstruments(RECURSIVE, DbDir, FsDir, bBackground, insDir);
3744          } else if (ScanMode.compare("NON_RECURSIVE") == 0) {          } else if (ScanMode.compare("NON_RECURSIVE") == 0) {
3745             id = db->AddInstruments(NON_RECURSIVE, DbDir, FsDir, bBackground);              id = db->AddInstruments(NON_RECURSIVE, DbDir, FsDir, bBackground, insDir);
3746          } else if (ScanMode.compare("FLAT") == 0) {          } else if (ScanMode.compare("FLAT") == 0) {
3747             id = db->AddInstruments(FLAT, DbDir, FsDir, bBackground);              id = db->AddInstruments(FLAT, DbDir, FsDir, bBackground, insDir);
3748          } else {          } else {
3749              throw Exception("Unknown scan mode: " + ScanMode);              throw Exception("Unknown scan mode: " + ScanMode);
3750          }          }
3751            
3752          if (bBackground) result = id;          if (bBackground) result = id;
3753      } catch (Exception e) {      } catch (Exception e) {
3754           result.Error(e);           result.Error(e);
# Line 2523  String LSCPServer::GetDbInstruments(Stri Line 3799  String LSCPServer::GetDbInstruments(Stri
3799    
3800          for (int i = 0; i < instrs->size(); i++) {          for (int i = 0; i < instrs->size(); i++) {
3801              if (list != "") list += ",";              if (list != "") list += ",";
3802              list += "'" + instrs->at(i) + "'";              list += "'" + InstrumentsDb::toEscapedPath(instrs->at(i)) + "'";
3803          }          }
3804    
3805          result.Add(list);          result.Add(list);
# Line 2550  String LSCPServer::GetDbInstrumentInfo(S Line 3826  String LSCPServer::GetDbInstrumentInfo(S
3826          result.Add("SIZE", (int)info.Size);          result.Add("SIZE", (int)info.Size);
3827          result.Add("CREATED", info.Created);          result.Add("CREATED", info.Created);
3828          result.Add("MODIFIED", info.Modified);          result.Add("MODIFIED", info.Modified);
3829          result.Add("DESCRIPTION", FilterEndlines(info.Description));          result.Add("DESCRIPTION", _escapeLscpResponse(info.Description));
3830          result.Add("IS_DRUM", info.IsDrum);          result.Add("IS_DRUM", info.IsDrum);
3831          result.Add("PRODUCT", FilterEndlines(info.Product));          result.Add("PRODUCT", _escapeLscpResponse(info.Product));
3832          result.Add("ARTISTS", FilterEndlines(info.Artists));          result.Add("ARTISTS", _escapeLscpResponse(info.Artists));
3833          result.Add("KEYWORDS", FilterEndlines(info.Keywords));          result.Add("KEYWORDS", _escapeLscpResponse(info.Keywords));
3834      } catch (Exception e) {      } catch (Exception e) {
3835           result.Error(e);           result.Error(e);
3836      }      }
# Line 2644  String LSCPServer::SetDbInstrumentDescri Line 3920  String LSCPServer::SetDbInstrumentDescri
3920      return result.Produce();      return result.Produce();
3921  }  }
3922    
3923    String LSCPServer::SetDbInstrumentFilePath(String OldPath, String NewPath) {
3924        dmsg(2,("LSCPServer: SetDbInstrumentFilePath(OldPath=%s,NewPath=%s)\n", OldPath.c_str(), NewPath.c_str()));
3925        LSCPResultSet result;
3926    #if HAVE_SQLITE3
3927        try {
3928            InstrumentsDb::GetInstrumentsDb()->SetInstrumentFilePath(OldPath, NewPath);
3929        } catch (Exception e) {
3930             result.Error(e);
3931        }
3932    #else
3933        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3934    #endif
3935        return result.Produce();
3936    }
3937    
3938    String LSCPServer::FindLostDbInstrumentFiles() {
3939        dmsg(2,("LSCPServer: FindLostDbInstrumentFiles()\n"));
3940        LSCPResultSet result;
3941    #if HAVE_SQLITE3
3942        try {
3943            String list;
3944            StringListPtr pLostFiles = InstrumentsDb::GetInstrumentsDb()->FindLostInstrumentFiles();
3945    
3946            for (int i = 0; i < pLostFiles->size(); i++) {
3947                if (list != "") list += ",";
3948                list += "'" + pLostFiles->at(i) + "'";
3949            }
3950    
3951            result.Add(list);
3952        } catch (Exception e) {
3953             result.Error(e);
3954        }
3955    #else
3956        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3957    #endif
3958        return result.Produce();
3959    }
3960    
3961  String LSCPServer::FindDbInstrumentDirectories(String Dir, std::map<String,String> Parameters, bool Recursive) {  String LSCPServer::FindDbInstrumentDirectories(String Dir, std::map<String,String> Parameters, bool Recursive) {
3962      dmsg(2,("LSCPServer: FindDbInstrumentDirectories(Dir=%s)\n", Dir.c_str()));      dmsg(2,("LSCPServer: FindDbInstrumentDirectories(Dir=%s)\n", Dir.c_str()));
3963      LSCPResultSet result;      LSCPResultSet result;
# Line 2671  String LSCPServer::FindDbInstrumentDirec Line 3985  String LSCPServer::FindDbInstrumentDirec
3985    
3986          for (int i = 0; i < pDirectories->size(); i++) {          for (int i = 0; i < pDirectories->size(); i++) {
3987              if (list != "") list += ",";              if (list != "") list += ",";
3988              list += "'" + pDirectories->at(i) + "'";              list += "'" + InstrumentsDb::toEscapedPath(pDirectories->at(i)) + "'";
3989          }          }
3990    
3991          result.Add(list);          result.Add(list);
# Line 2727  String LSCPServer::FindDbInstruments(Str Line 4041  String LSCPServer::FindDbInstruments(Str
4041    
4042          for (int i = 0; i < pInstruments->size(); i++) {          for (int i = 0; i < pInstruments->size(); i++) {
4043              if (list != "") list += ",";              if (list != "") list += ",";
4044              list += "'" + pInstruments->at(i) + "'";              list += "'" + InstrumentsDb::toEscapedPath(pInstruments->at(i)) + "'";
4045          }          }
4046    
4047          result.Add(list);          result.Add(list);
# Line 2740  String LSCPServer::FindDbInstruments(Str Line 4054  String LSCPServer::FindDbInstruments(Str
4054      return result.Produce();      return result.Produce();
4055  }  }
4056    
4057    String LSCPServer::FormatInstrumentsDb() {
4058        dmsg(2,("LSCPServer: FormatInstrumentsDb()\n"));
4059        LSCPResultSet result;
4060    #if HAVE_SQLITE3
4061        try {
4062            InstrumentsDb::GetInstrumentsDb()->Format();
4063        } catch (Exception e) {
4064             result.Error(e);
4065        }
4066    #else
4067        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
4068    #endif
4069        return result.Produce();
4070    }
4071    
4072    
4073  /**  /**
4074   * Will be called by the parser to enable or disable echo mode; if echo   * Will be called by the parser to enable or disable echo mode; if echo
# Line 2760  String LSCPServer::SetEcho(yyparse_param Line 4089  String LSCPServer::SetEcho(yyparse_param
4089      return result.Produce();      return result.Produce();
4090  }  }
4091    
4092  String LSCPServer::FilterEndlines(String s) {  String LSCPServer::SetShellInteract(yyparse_param_t* pSession, double boolean_value) {
4093      String s2 = s;      dmsg(2,("LSCPServer: SetShellInteract(val=%f)\n", boolean_value));
4094      for (int i = 0; i < s2.length(); i++) {      LSCPResultSet result;
4095          if (s2.at(i) == '\r') s2.at(i) = ' ';      try {
4096          else if (s2.at(i) == '\n') s2.at(i) = ' ';          if      (boolean_value == 0) pSession->bShellInteract = false;
4097            else if (boolean_value == 1) pSession->bShellInteract = true;
4098            else throw Exception("Not a boolean value, must either be 0 or 1");
4099        } catch (Exception e) {
4100            result.Error(e);
4101        }
4102        return result.Produce();
4103    }
4104    
4105    String LSCPServer::SetShellAutoCorrect(yyparse_param_t* pSession, double boolean_value) {
4106        dmsg(2,("LSCPServer: SetShellAutoCorrect(val=%f)\n", boolean_value));
4107        LSCPResultSet result;
4108        try {
4109            if      (boolean_value == 0) pSession->bShellAutoCorrect = false;
4110            else if (boolean_value == 1) pSession->bShellAutoCorrect = true;
4111            else throw Exception("Not a boolean value, must either be 0 or 1");
4112        } catch (Exception e) {
4113            result.Error(e);
4114      }      }
4115            return result.Produce();
4116      return s2;  }
4117    
4118    String LSCPServer::SetShellDoc(yyparse_param_t* pSession, double boolean_value) {
4119        dmsg(2,("LSCPServer: SetShellDoc(val=%f)\n", boolean_value));
4120        LSCPResultSet result;
4121        try {
4122            if      (boolean_value == 0) pSession->bShellSendLSCPDoc = false;
4123            else if (boolean_value == 1) pSession->bShellSendLSCPDoc = true;
4124            else throw Exception("Not a boolean value, must either be 0 or 1");
4125        } catch (Exception e) {
4126            result.Error(e);
4127        }
4128        return result.Produce();
4129    }
4130    
4131  }  }

Legend:
Removed from v.1212  
changed lines
  Added in v.3766

  ViewVC Help
Powered by ViewVC