/[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 907 by iliev, Fri Jul 28 21:35:06 2006 UTC revision 2198 by iliev, Sun Jul 3 18:06:51 2011 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, 2006 Christian Schoenebeck                        *   *   Copyright (C) 2005 - 2010 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"
 //#include "../common/global.h"  
31    
32    #if defined(WIN32)
33    #include <windows.h>
34    #else
35  #include <fcntl.h>  #include <fcntl.h>
36    #endif
37    
38  #if HAVE_SQLITE3  #if ! HAVE_SQLITE3
39  # include "sqlite3.h"  #define DOESNT_HAVE_SQLITE3 "No database support. SQLITE3 was not installed when linuxsampler was built."
40  #endif  #endif
41    
42  #include "../engines/EngineFactory.h"  #include "../engines/EngineFactory.h"
43  #include "../engines/EngineChannelFactory.h"  #include "../engines/EngineChannelFactory.h"
44  #include "../drivers/audio/AudioOutputDeviceFactory.h"  #include "../drivers/audio/AudioOutputDeviceFactory.h"
45  #include "../drivers/midi/MidiInputDeviceFactory.h"  #include "../drivers/midi/MidiInputDeviceFactory.h"
46    #include "../effects/EffectFactory.h"
47    
48    namespace LinuxSampler {
49    
50    /**
51     * Returns a copy of the given string where all special characters are
52     * replaced by LSCP escape sequences ("\xHH"). This function shall be used
53     * to escape LSCP response fields in case the respective response field is
54     * actually defined as using escape sequences in the LSCP specs.
55     *
56     * @e Caution: DO NOT use this function for escaping path based responses,
57     * use the Path class (src/common/Path.h) for this instead!
58     */
59    static String _escapeLscpResponse(String txt) {
60        for (int i = 0; i < txt.length(); i++) {
61            const char c = txt.c_str()[i];
62            if (
63                !(c >= '0' && c <= '9') &&
64                !(c >= 'a' && c <= 'z') &&
65                !(c >= 'A' && c <= 'Z') &&
66                !(c == ' ') && !(c == '!') && !(c == '#') && !(c == '$') &&
67                !(c == '%') && !(c == '&') && !(c == '(') && !(c == ')') &&
68                !(c == '*') && !(c == '+') && !(c == ',') && !(c == '-') &&
69                !(c == '.') && !(c == '/') && !(c == ':') && !(c == ';') &&
70                !(c == '<') && !(c == '=') && !(c == '>') && !(c == '?') &&
71                !(c == '@') && !(c == '[') && !(c == ']') &&
72                !(c == '^') && !(c == '_') && !(c == '`') && !(c == '{') &&
73                !(c == '|') && !(c == '}') && !(c == '~')
74            ) {
75                // convert the "special" character into a "\xHH" LSCP escape sequence
76                char buf[5];
77                snprintf(buf, sizeof(buf), "\\x%02x", static_cast<unsigned char>(c));
78                txt.replace(i, 1, buf);
79                i += 3;
80            }
81        }
82        return txt;
83    }
84    
85  /**  /**
86   * Below are a few static members of the LSCPServer class.   * Below are a few static members of the LSCPServer class.
# Line 53  Line 98 
98  fd_set LSCPServer::fdSet;  fd_set LSCPServer::fdSet;
99  int LSCPServer::currentSocket = -1;  int LSCPServer::currentSocket = -1;
100  std::vector<yyparse_param_t> LSCPServer::Sessions = std::vector<yyparse_param_t>();  std::vector<yyparse_param_t> LSCPServer::Sessions = std::vector<yyparse_param_t>();
101    std::vector<yyparse_param_t>::iterator itCurrentSession = std::vector<yyparse_param_t>::iterator();
102  std::map<int,String> LSCPServer::bufferedNotifies = std::map<int,String>();  std::map<int,String> LSCPServer::bufferedNotifies = std::map<int,String>();
103  std::map<int,String> LSCPServer::bufferedCommands = std::map<int,String>();  std::map<int,String> LSCPServer::bufferedCommands = std::map<int,String>();
104  std::map< LSCPEvent::event_t, std::list<int> > LSCPServer::eventSubscriptions = std::map< LSCPEvent::event_t, std::list<int> >();  std::map< LSCPEvent::event_t, std::list<int> > LSCPServer::eventSubscriptions = std::map< LSCPEvent::event_t, std::list<int> >();
# Line 61  Mutex LSCPServer::NotifyBufferMutex = Mu Line 107  Mutex LSCPServer::NotifyBufferMutex = Mu
107  Mutex LSCPServer::SubscriptionMutex = Mutex();  Mutex LSCPServer::SubscriptionMutex = Mutex();
108  Mutex LSCPServer::RTNotifyMutex = Mutex();  Mutex LSCPServer::RTNotifyMutex = Mutex();
109    
110  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) {
111      SocketAddress.sin_family      = AF_INET;      SocketAddress.sin_family      = AF_INET;
112      SocketAddress.sin_addr.s_addr = addr;      SocketAddress.sin_addr.s_addr = addr;
113      SocketAddress.sin_port        = port;      SocketAddress.sin_port        = port;
114      this->pSampler = pSampler;      this->pSampler = pSampler;
115        LSCPEvent::RegisterEvent(LSCPEvent::event_audio_device_count, "AUDIO_OUTPUT_DEVICE_COUNT");
116        LSCPEvent::RegisterEvent(LSCPEvent::event_audio_device_info, "AUDIO_OUTPUT_DEVICE_INFO");
117        LSCPEvent::RegisterEvent(LSCPEvent::event_midi_device_count, "MIDI_INPUT_DEVICE_COUNT");
118        LSCPEvent::RegisterEvent(LSCPEvent::event_midi_device_info, "MIDI_INPUT_DEVICE_INFO");
119      LSCPEvent::RegisterEvent(LSCPEvent::event_channel_count, "CHANNEL_COUNT");      LSCPEvent::RegisterEvent(LSCPEvent::event_channel_count, "CHANNEL_COUNT");
120      LSCPEvent::RegisterEvent(LSCPEvent::event_voice_count, "VOICE_COUNT");      LSCPEvent::RegisterEvent(LSCPEvent::event_voice_count, "VOICE_COUNT");
121      LSCPEvent::RegisterEvent(LSCPEvent::event_stream_count, "STREAM_COUNT");      LSCPEvent::RegisterEvent(LSCPEvent::event_stream_count, "STREAM_COUNT");
122      LSCPEvent::RegisterEvent(LSCPEvent::event_buffer_fill, "BUFFER_FILL");      LSCPEvent::RegisterEvent(LSCPEvent::event_buffer_fill, "BUFFER_FILL");
123      LSCPEvent::RegisterEvent(LSCPEvent::event_channel_info, "CHANNEL_INFO");      LSCPEvent::RegisterEvent(LSCPEvent::event_channel_info, "CHANNEL_INFO");
124        LSCPEvent::RegisterEvent(LSCPEvent::event_fx_send_count, "FX_SEND_COUNT");
125        LSCPEvent::RegisterEvent(LSCPEvent::event_fx_send_info, "FX_SEND_INFO");
126        LSCPEvent::RegisterEvent(LSCPEvent::event_midi_instr_map_count, "MIDI_INSTRUMENT_MAP_COUNT");
127        LSCPEvent::RegisterEvent(LSCPEvent::event_midi_instr_map_info, "MIDI_INSTRUMENT_MAP_INFO");
128        LSCPEvent::RegisterEvent(LSCPEvent::event_midi_instr_count, "MIDI_INSTRUMENT_COUNT");
129        LSCPEvent::RegisterEvent(LSCPEvent::event_midi_instr_info, "MIDI_INSTRUMENT_INFO");
130        LSCPEvent::RegisterEvent(LSCPEvent::event_db_instr_dir_count, "DB_INSTRUMENT_DIRECTORY_COUNT");
131        LSCPEvent::RegisterEvent(LSCPEvent::event_db_instr_dir_info, "DB_INSTRUMENT_DIRECTORY_INFO");
132        LSCPEvent::RegisterEvent(LSCPEvent::event_db_instr_count, "DB_INSTRUMENT_COUNT");
133        LSCPEvent::RegisterEvent(LSCPEvent::event_db_instr_info, "DB_INSTRUMENT_INFO");
134        LSCPEvent::RegisterEvent(LSCPEvent::event_db_instrs_job_info, "DB_INSTRUMENTS_JOB_INFO");
135      LSCPEvent::RegisterEvent(LSCPEvent::event_misc, "MISCELLANEOUS");      LSCPEvent::RegisterEvent(LSCPEvent::event_misc, "MISCELLANEOUS");
136        LSCPEvent::RegisterEvent(LSCPEvent::event_total_stream_count, "TOTAL_STREAM_COUNT");
137      LSCPEvent::RegisterEvent(LSCPEvent::event_total_voice_count, "TOTAL_VOICE_COUNT");      LSCPEvent::RegisterEvent(LSCPEvent::event_total_voice_count, "TOTAL_VOICE_COUNT");
138        LSCPEvent::RegisterEvent(LSCPEvent::event_global_info, "GLOBAL_INFO");
139        LSCPEvent::RegisterEvent(LSCPEvent::event_channel_midi, "CHANNEL_MIDI");
140        LSCPEvent::RegisterEvent(LSCPEvent::event_device_midi, "DEVICE_MIDI");
141        LSCPEvent::RegisterEvent(LSCPEvent::event_fx_instance_count, "EFFECT_INSTANCE_COUNT");
142        LSCPEvent::RegisterEvent(LSCPEvent::event_fx_instance_info, "EFFECT_INSTANCE_INFO");
143        LSCPEvent::RegisterEvent(LSCPEvent::event_send_fx_chain_count, "SEND_EFFECT_CHAIN_COUNT");
144        LSCPEvent::RegisterEvent(LSCPEvent::event_send_fx_chain_info, "SEND_EFFECT_CHAIN_INFO");
145      hSocket = -1;      hSocket = -1;
146  }  }
147    
148  LSCPServer::~LSCPServer() {  LSCPServer::~LSCPServer() {
149        CloseAllConnections();
150        InstrumentManager::StopBackgroundThread();
151    #if defined(WIN32)
152        if (hSocket >= 0) closesocket(hSocket);
153    #else
154      if (hSocket >= 0) close(hSocket);      if (hSocket >= 0) close(hSocket);
155    #endif
156    }
157    
158    LSCPServer::EventHandler::EventHandler(LSCPServer* pParent) {
159        this->pParent = pParent;
160    }
161    
162    LSCPServer::EventHandler::~EventHandler() {
163        std::vector<midi_listener_entry> l = channelMidiListeners;
164        channelMidiListeners.clear();
165        for (int i = 0; i < l.size(); i++)
166            delete l[i].pMidiListener;
167    }
168    
169    void LSCPServer::EventHandler::ChannelCountChanged(int NewCount) {
170        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_channel_count, NewCount));
171    }
172    
173    void LSCPServer::EventHandler::ChannelAdded(SamplerChannel* pChannel) {
174        pChannel->AddEngineChangeListener(this);
175    }
176    
177    void LSCPServer::EventHandler::ChannelToBeRemoved(SamplerChannel* pChannel) {
178        if (!pChannel->GetEngineChannel()) return;
179        EngineToBeChanged(pChannel->Index());
180    }
181    
182    void LSCPServer::EventHandler::EngineToBeChanged(int ChannelId) {
183        SamplerChannel* pSamplerChannel =
184            pParent->pSampler->GetSamplerChannel(ChannelId);
185        if (!pSamplerChannel) return;
186        EngineChannel* pEngineChannel =
187            pSamplerChannel->GetEngineChannel();
188        if (!pEngineChannel) return;
189        for (std::vector<midi_listener_entry>::iterator iter = channelMidiListeners.begin(); iter != channelMidiListeners.end(); ++iter) {
190            if ((*iter).pEngineChannel == pEngineChannel) {
191                VirtualMidiDevice* pMidiListener = (*iter).pMidiListener;
192                pEngineChannel->Disconnect(pMidiListener);
193                channelMidiListeners.erase(iter);
194                delete pMidiListener;
195                return;
196            }
197        }
198    }
199    
200    void LSCPServer::EventHandler::EngineChanged(int ChannelId) {
201        SamplerChannel* pSamplerChannel =
202            pParent->pSampler->GetSamplerChannel(ChannelId);
203        if (!pSamplerChannel) return;
204        EngineChannel* pEngineChannel =
205            pSamplerChannel->GetEngineChannel();
206        if (!pEngineChannel) return;
207        VirtualMidiDevice* pMidiListener = new VirtualMidiDevice;
208        pEngineChannel->Connect(pMidiListener);
209        midi_listener_entry entry = {
210            pSamplerChannel, pEngineChannel, pMidiListener
211        };
212        channelMidiListeners.push_back(entry);
213    }
214    
215    void LSCPServer::EventHandler::AudioDeviceCountChanged(int NewCount) {
216        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_audio_device_count, NewCount));
217    }
218    
219    void LSCPServer::EventHandler::MidiDeviceCountChanged(int NewCount) {
220        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_device_count, NewCount));
221    }
222    
223    void LSCPServer::EventHandler::MidiDeviceToBeDestroyed(MidiInputDevice* pDevice) {
224        pDevice->RemoveMidiPortCountListener(this);
225        for (int i = 0; i < pDevice->PortCount(); ++i)
226            MidiPortToBeRemoved(pDevice->GetPort(i));
227    }
228    
229    void LSCPServer::EventHandler::MidiDeviceCreated(MidiInputDevice* pDevice) {
230        pDevice->AddMidiPortCountListener(this);
231        for (int i = 0; i < pDevice->PortCount(); ++i)
232            MidiPortAdded(pDevice->GetPort(i));
233    }
234    
235    void LSCPServer::EventHandler::MidiPortCountChanged(int NewCount) {
236        // yet unused
237    }
238    
239    void LSCPServer::EventHandler::MidiPortToBeRemoved(MidiInputPort* pPort) {
240        for (std::vector<device_midi_listener_entry>::iterator iter = deviceMidiListeners.begin(); iter != deviceMidiListeners.end(); ++iter) {
241            if ((*iter).pPort == pPort) {
242                VirtualMidiDevice* pMidiListener = (*iter).pMidiListener;
243                pPort->Disconnect(pMidiListener);
244                deviceMidiListeners.erase(iter);
245                delete pMidiListener;
246                return;
247            }
248        }
249    }
250    
251    void LSCPServer::EventHandler::MidiPortAdded(MidiInputPort* pPort) {
252        // find out the device ID
253        std::map<uint, MidiInputDevice*> devices =
254            pParent->pSampler->GetMidiInputDevices();
255        for (
256            std::map<uint, MidiInputDevice*>::iterator iter = devices.begin();
257            iter != devices.end(); ++iter
258        ) {
259            if (iter->second == pPort->GetDevice()) { // found
260                VirtualMidiDevice* pMidiListener = new VirtualMidiDevice;
261                pPort->Connect(pMidiListener);
262                device_midi_listener_entry entry = {
263                    pPort, pMidiListener, iter->first
264                };
265                deviceMidiListeners.push_back(entry);
266                return;
267            }
268        }
269    }
270    
271    void LSCPServer::EventHandler::MidiInstrumentCountChanged(int MapId, int NewCount) {
272        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_count, MapId, NewCount));
273    }
274    
275    void LSCPServer::EventHandler::MidiInstrumentInfoChanged(int MapId, int Bank, int Program) {
276        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_info, MapId, Bank, Program));
277    }
278    
279    void LSCPServer::EventHandler::MidiInstrumentMapCountChanged(int NewCount) {
280        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_map_count, NewCount));
281    }
282    
283    void LSCPServer::EventHandler::MidiInstrumentMapInfoChanged(int MapId) {
284        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_map_info, MapId));
285    }
286    
287    void LSCPServer::EventHandler::FxSendCountChanged(int ChannelId, int NewCount) {
288        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_count, ChannelId, NewCount));
289    }
290    
291    void LSCPServer::EventHandler::VoiceCountChanged(int ChannelId, int NewCount) {
292        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_voice_count, ChannelId, NewCount));
293    }
294    
295    void LSCPServer::EventHandler::StreamCountChanged(int ChannelId, int NewCount) {
296        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_stream_count, ChannelId, NewCount));
297    }
298    
299    void LSCPServer::EventHandler::BufferFillChanged(int ChannelId, String FillData) {
300        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_buffer_fill, ChannelId, FillData));
301    }
302    
303    void LSCPServer::EventHandler::TotalVoiceCountChanged(int NewCount) {
304        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_total_voice_count, NewCount));
305    }
306    
307    void LSCPServer::EventHandler::TotalStreamCountChanged(int NewCount) {
308        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_total_stream_count, NewCount));
309    }
310    
311    #if HAVE_SQLITE3
312    void LSCPServer::DbInstrumentsEventHandler::DirectoryCountChanged(String Dir) {
313        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_dir_count, InstrumentsDb::toEscapedPath(Dir)));
314    }
315    
316    void LSCPServer::DbInstrumentsEventHandler::DirectoryInfoChanged(String Dir) {
317        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_dir_info, InstrumentsDb::toEscapedPath(Dir)));
318    }
319    
320    void LSCPServer::DbInstrumentsEventHandler::DirectoryNameChanged(String Dir, String NewName) {
321        Dir = "'" + InstrumentsDb::toEscapedPath(Dir) + "'";
322        NewName = "'" + InstrumentsDb::toEscapedPath(NewName) + "'";
323        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_dir_info, "NAME", Dir, NewName));
324    }
325    
326    void LSCPServer::DbInstrumentsEventHandler::InstrumentCountChanged(String Dir) {
327        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_count, InstrumentsDb::toEscapedPath(Dir)));
328    }
329    
330    void LSCPServer::DbInstrumentsEventHandler::InstrumentInfoChanged(String Instr) {
331        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_info, InstrumentsDb::toEscapedPath(Instr)));
332    }
333    
334    void LSCPServer::DbInstrumentsEventHandler::InstrumentNameChanged(String Instr, String NewName) {
335        Instr = "'" + InstrumentsDb::toEscapedPath(Instr) + "'";
336        NewName = "'" + InstrumentsDb::toEscapedPath(NewName) + "'";
337        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instr_info, "NAME", Instr, NewName));
338    }
339    
340    void LSCPServer::DbInstrumentsEventHandler::JobStatusChanged(int JobId) {
341        LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_db_instrs_job_info, JobId));
342    }
343    #endif // HAVE_SQLITE3
344    
345    void LSCPServer::RemoveListeners() {
346        pSampler->RemoveChannelCountListener(&eventHandler);
347        pSampler->RemoveAudioDeviceCountListener(&eventHandler);
348        pSampler->RemoveMidiDeviceCountListener(&eventHandler);
349        pSampler->RemoveVoiceCountListener(&eventHandler);
350        pSampler->RemoveStreamCountListener(&eventHandler);
351        pSampler->RemoveBufferFillListener(&eventHandler);
352        pSampler->RemoveTotalStreamCountListener(&eventHandler);
353        pSampler->RemoveTotalVoiceCountListener(&eventHandler);
354        pSampler->RemoveFxSendCountListener(&eventHandler);
355        MidiInstrumentMapper::RemoveMidiInstrumentCountListener(&eventHandler);
356        MidiInstrumentMapper::RemoveMidiInstrumentInfoListener(&eventHandler);
357        MidiInstrumentMapper::RemoveMidiInstrumentMapCountListener(&eventHandler);
358        MidiInstrumentMapper::RemoveMidiInstrumentMapInfoListener(&eventHandler);
359    #if HAVE_SQLITE3
360        InstrumentsDb::GetInstrumentsDb()->RemoveInstrumentsDbListener(&dbInstrumentsEventHandler);
361    #endif
362  }  }
363    
364  /**  /**
# Line 95  int LSCPServer::WaitUntilInitialized(lon Line 376  int LSCPServer::WaitUntilInitialized(lon
376  }  }
377    
378  int LSCPServer::Main() {  int LSCPServer::Main() {
379            #if defined(WIN32)
380            WSADATA wsaData;
381            int iResult;
382            iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
383            if (iResult != 0) {
384                    std::cerr << "LSCPServer: WSAStartup failed: " << iResult << "\n";
385                    exit(EXIT_FAILURE);
386            }
387            #endif
388      hSocket = socket(AF_INET, SOCK_STREAM, 0);      hSocket = socket(AF_INET, SOCK_STREAM, 0);
389      if (hSocket < 0) {      if (hSocket < 0) {
390          std::cerr << "LSCPServer: Could not create server socket." << std::endl;          std::cerr << "LSCPServer: Could not create server socket." << std::endl;
# Line 108  int LSCPServer::Main() { Line 398  int LSCPServer::Main() {
398              if (bind(hSocket, (sockaddr*) &SocketAddress, sizeof(sockaddr_in)) < 0) {              if (bind(hSocket, (sockaddr*) &SocketAddress, sizeof(sockaddr_in)) < 0) {
399                  if (trial > LSCP_SERVER_BIND_TIMEOUT) {                  if (trial > LSCP_SERVER_BIND_TIMEOUT) {
400                      std::cerr << "gave up!" << std::endl;                      std::cerr << "gave up!" << std::endl;
401                        #if defined(WIN32)
402                        closesocket(hSocket);
403                        #else
404                      close(hSocket);                      close(hSocket);
405                        #endif
406                      //return -1;                      //return -1;
407                      exit(EXIT_FAILURE);                      exit(EXIT_FAILURE);
408                  }                  }
# Line 121  int LSCPServer::Main() { Line 415  int LSCPServer::Main() {
415      listen(hSocket, 1);      listen(hSocket, 1);
416      Initialized.Set(true);      Initialized.Set(true);
417    
418        // Registering event listeners
419        pSampler->AddChannelCountListener(&eventHandler);
420        pSampler->AddAudioDeviceCountListener(&eventHandler);
421        pSampler->AddMidiDeviceCountListener(&eventHandler);
422        pSampler->AddVoiceCountListener(&eventHandler);
423        pSampler->AddStreamCountListener(&eventHandler);
424        pSampler->AddBufferFillListener(&eventHandler);
425        pSampler->AddTotalStreamCountListener(&eventHandler);
426        pSampler->AddTotalVoiceCountListener(&eventHandler);
427        pSampler->AddFxSendCountListener(&eventHandler);
428        MidiInstrumentMapper::AddMidiInstrumentCountListener(&eventHandler);
429        MidiInstrumentMapper::AddMidiInstrumentInfoListener(&eventHandler);
430        MidiInstrumentMapper::AddMidiInstrumentMapCountListener(&eventHandler);
431        MidiInstrumentMapper::AddMidiInstrumentMapInfoListener(&eventHandler);
432    #if HAVE_SQLITE3
433        InstrumentsDb::GetInstrumentsDb()->AddInstrumentsDbListener(&dbInstrumentsEventHandler);
434    #endif
435      // now wait for client connections and handle their requests      // now wait for client connections and handle their requests
436      sockaddr_in client;      sockaddr_in client;
437      int length = sizeof(client);      int length = sizeof(client);
# Line 131  int LSCPServer::Main() { Line 442  int LSCPServer::Main() {
442      timeval timeout;      timeval timeout;
443    
444      while (true) {      while (true) {
445            #if CONFIG_PTHREAD_TESTCANCEL
446                    TestCancel();
447            #endif
448          // 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
449          {          {
450              std::set<EngineChannel*> engineChannels = EngineChannelFactory::EngineChannelInstances();              std::set<EngineChannel*> engineChannels = EngineChannelFactory::EngineChannelInstances();
# Line 138  int LSCPServer::Main() { Line 452  int LSCPServer::Main() {
452              std::set<EngineChannel*>::iterator itEnd           = engineChannels.end();              std::set<EngineChannel*>::iterator itEnd           = engineChannels.end();
453              for (; itEngineChannel != itEnd; ++itEngineChannel) {              for (; itEngineChannel != itEnd; ++itEngineChannel) {
454                  if ((*itEngineChannel)->StatusChanged()) {                  if ((*itEngineChannel)->StatusChanged()) {
455                      SendLSCPNotify(LSCPEvent(LSCPEvent::event_channel_info, (*itEngineChannel)->iSamplerChannelIndex));                      SendLSCPNotify(LSCPEvent(LSCPEvent::event_channel_info, (*itEngineChannel)->GetSamplerChannel()->Index()));
456                    }
457    
458                    for (int i = 0; i < (*itEngineChannel)->GetFxSendCount(); i++) {
459                        FxSend* fxs = (*itEngineChannel)->GetFxSend(i);
460                        if(fxs != NULL && fxs->IsInfoChanged()) {
461                            int chn = (*itEngineChannel)->GetSamplerChannel()->Index();
462                            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_info, chn, fxs->Id()));
463                            fxs->SetInfoChanged(false);
464                        }
465                    }
466                }
467            }
468    
469            // check if MIDI data arrived on some engine channel
470            for (int i = 0; i < eventHandler.channelMidiListeners.size(); ++i) {
471                const EventHandler::midi_listener_entry entry =
472                    eventHandler.channelMidiListeners[i];
473                VirtualMidiDevice* pMidiListener = entry.pMidiListener;
474                if (pMidiListener->NotesChanged()) {
475                    for (int iNote = 0; iNote < 128; iNote++) {
476                        if (pMidiListener->NoteChanged(iNote)) {
477                            const bool bActive = pMidiListener->NoteIsActive(iNote);
478                            LSCPServer::SendLSCPNotify(
479                                LSCPEvent(
480                                    LSCPEvent::event_channel_midi,
481                                    entry.pSamplerChannel->Index(),
482                                    std::string(bActive ? "NOTE_ON" : "NOTE_OFF"),
483                                    iNote,
484                                    bActive ? pMidiListener->NoteOnVelocity(iNote)
485                                            : pMidiListener->NoteOffVelocity(iNote)
486                                )
487                            );
488                        }
489                    }
490                }
491            }
492    
493            // check if MIDI data arrived on some MIDI device
494            for (int i = 0; i < eventHandler.deviceMidiListeners.size(); ++i) {
495                const EventHandler::device_midi_listener_entry entry =
496                    eventHandler.deviceMidiListeners[i];
497                VirtualMidiDevice* pMidiListener = entry.pMidiListener;
498                if (pMidiListener->NotesChanged()) {
499                    for (int iNote = 0; iNote < 128; iNote++) {
500                        if (pMidiListener->NoteChanged(iNote)) {
501                            const bool bActive = pMidiListener->NoteIsActive(iNote);
502                            LSCPServer::SendLSCPNotify(
503                                LSCPEvent(
504                                    LSCPEvent::event_device_midi,
505                                    entry.uiDeviceID,
506                                    entry.pPort->GetPortNumber(),
507                                    std::string(bActive ? "NOTE_ON" : "NOTE_OFF"),
508                                    iNote,
509                                    bActive ? pMidiListener->NoteOnVelocity(iNote)
510                                            : pMidiListener->NoteOffVelocity(iNote)
511                                )
512                            );
513                        }
514                  }                  }
515              }              }
516          }          }
# Line 161  int LSCPServer::Main() { Line 533  int LSCPServer::Main() {
533    
534          int retval = select(maxSessions+1, &selectSet, NULL, NULL, &timeout);          int retval = select(maxSessions+1, &selectSet, NULL, NULL, &timeout);
535    
536          if (retval == 0)          if (retval == 0 || (retval == -1 && errno == EINTR))
537                  continue; //Nothing try again                  continue; //Nothing try again
538          if (retval == -1) {          if (retval == -1) {
539                  std::cerr << "LSCPServer: Socket select error." << std::endl;                  std::cerr << "LSCPServer: Socket select error." << std::endl;
540                    #if defined(WIN32)
541                    closesocket(hSocket);
542                    #else
543                  close(hSocket);                  close(hSocket);
544                    #endif
545                  exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
546          }          }
547    
# Line 177  int LSCPServer::Main() { Line 553  int LSCPServer::Main() {
553                          exit(EXIT_FAILURE);                          exit(EXIT_FAILURE);
554                  }                  }
555    
556                    #if defined(WIN32)
557                    u_long nonblock_io = 1;
558                    if( ioctlsocket(socket, FIONBIO, &nonblock_io) ) {
559                      std::cerr << "LSCPServer: ioctlsocket: set FIONBIO failed. Error " << WSAGetLastError() << std::endl;
560                      exit(EXIT_FAILURE);
561                    }
562            #else
563                    struct linger linger;
564                    linger.l_onoff = 1;
565                    linger.l_linger = 0;
566                    if(setsockopt(socket, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger))) {
567                        std::cerr << "LSCPServer: Failed to set SO_LINGER\n";
568                    }
569    
570                  if (fcntl(socket, F_SETFL, O_NONBLOCK)) {                  if (fcntl(socket, F_SETFL, O_NONBLOCK)) {
571                          std::cerr << "LSCPServer: F_SETFL O_NONBLOCK failed." << std::endl;                          std::cerr << "LSCPServer: F_SETFL O_NONBLOCK failed." << std::endl;
572                          exit(EXIT_FAILURE);                          exit(EXIT_FAILURE);
573                  }                  }
574                    #endif
575    
576                  // Parser initialization                  // Parser initialization
577                  yyparse_param_t yyparse_param;                  yyparse_param_t yyparse_param;
# Line 204  int LSCPServer::Main() { Line 595  int LSCPServer::Main() {
595                                  int dummy; // just a temporary hack to fulfill the restart() function prototype                                  int dummy; // just a temporary hack to fulfill the restart() function prototype
596                                  restart(NULL, dummy); // restart the 'scanner'                                  restart(NULL, dummy); // restart the 'scanner'
597                                  currentSocket = (*iter).hSession;  //a hack                                  currentSocket = (*iter).hSession;  //a hack
598                                    itCurrentSession = iter; // another hack
599                                  dmsg(2,("LSCPServer: [%s]\n",bufferedCommands[currentSocket].c_str()));                                  dmsg(2,("LSCPServer: [%s]\n",bufferedCommands[currentSocket].c_str()));
600                                  if ((*iter).bVerbose) { // if echo mode enabled                                  if ((*iter).bVerbose) { // if echo mode enabled
601                                      AnswerClient(bufferedCommands[currentSocket]);                                      AnswerClient(bufferedCommands[currentSocket]);
602                                  }                                  }
603                                  int result = yyparse(&(*iter));                                  int result = yyparse(&(*iter));
604                                  currentSocket = -1;     //continuation of a hack                                  currentSocket = -1;     //continuation of a hack
605                                    itCurrentSession = Sessions.end(); // hack as well
606                                  dmsg(3,("LSCPServer: Done parsing on socket %d.\n", currentSocket));                                  dmsg(3,("LSCPServer: Done parsing on socket %d.\n", currentSocket));
607                                  if (result == LSCP_QUIT) { //Was it a quit command by any chance?                                  if (result == LSCP_QUIT) { //Was it a quit command by any chance?
608                                          CloseConnection(iter);                                          CloseConnection(iter);
# Line 237  void LSCPServer::CloseConnection( std::v Line 630  void LSCPServer::CloseConnection( std::v
630          NotifyMutex.Lock();          NotifyMutex.Lock();
631          bufferedCommands.erase(socket);          bufferedCommands.erase(socket);
632          bufferedNotifies.erase(socket);          bufferedNotifies.erase(socket);
633            #if defined(WIN32)
634            closesocket(socket);
635            #else
636          close(socket);          close(socket);
637            #endif
638          NotifyMutex.Unlock();          NotifyMutex.Unlock();
639  }  }
640    
641    void LSCPServer::CloseAllConnections() {
642        std::vector<yyparse_param_t>::iterator iter = Sessions.begin();
643        while(iter != Sessions.end()) {
644            CloseConnection(iter);
645            iter = Sessions.begin();
646        }
647    }
648    
649    void LSCPServer::LockRTNotify() {
650        RTNotifyMutex.Lock();
651    }
652    
653    void LSCPServer::UnlockRTNotify() {
654        RTNotifyMutex.Unlock();
655    }
656    
657  int LSCPServer::EventSubscribers( std::list<LSCPEvent::event_t> events ) {  int LSCPServer::EventSubscribers( std::list<LSCPEvent::event_t> events ) {
658          int subs = 0;          int subs = 0;
659          SubscriptionMutex.Lock();          SubscriptionMutex.Lock();
# Line 302  extern int GetLSCPCommand( void *buf, in Line 715  extern int GetLSCPCommand( void *buf, in
715          return command.size();          return command.size();
716  }  }
717    
718    extern yyparse_param_t* GetCurrentYaccSession() {
719        return &(*itCurrentSession);
720    }
721    
722  /**  /**
723   * Will be called to try to read the command from the socket   * Will be called to try to read the command from the socket
724   * If command is read, it will return true. Otherwise false is returned.   * If command is read, it will return true. Otherwise false is returned.
# Line 312  bool LSCPServer::GetLSCPCommand( std::ve Line 729  bool LSCPServer::GetLSCPCommand( std::ve
729          char c;          char c;
730          int i = 0;          int i = 0;
731          while (true) {          while (true) {
732                    #if defined(WIN32)
733                    int result = recv(socket, (char *)&c, 1, 0); //Read one character at a time for now
734                    #else
735                  int result = recv(socket, (void *)&c, 1, 0); //Read one character at a time for now                  int result = recv(socket, (void *)&c, 1, 0); //Read one character at a time for now
736                    #endif
737                  if (result == 0) { //socket was selected, so 0 here means client has closed the connection                  if (result == 0) { //socket was selected, so 0 here means client has closed the connection
738                          CloseConnection(iter);                          CloseConnection(iter);
739                          break;                          break;
# Line 327  bool LSCPServer::GetLSCPCommand( std::ve Line 748  bool LSCPServer::GetLSCPCommand( std::ve
748                          }                          }
749                          bufferedCommands[socket] += c;                          bufferedCommands[socket] += c;
750                  }                  }
751                    #if defined(WIN32)
752                    if (result == SOCKET_ERROR) {
753                        int wsa_lasterror = WSAGetLastError();
754                            if (wsa_lasterror == WSAEWOULDBLOCK) //Would block, try again later.
755                                    return false;
756                            dmsg(2,("LSCPScanner: Socket error after recv() Error %d.\n", wsa_lasterror));
757                            CloseConnection(iter);
758                            break;
759                    }
760                    #else
761                  if (result == -1) {                  if (result == -1) {
762                          if (errno == EAGAIN) //Would block, try again later.                          if (errno == EAGAIN) //Would block, try again later.
763                                  return false;                                  return false;
# Line 365  bool LSCPServer::GetLSCPCommand( std::ve Line 796  bool LSCPServer::GetLSCPCommand( std::ve
796                          CloseConnection(iter);                          CloseConnection(iter);
797                          break;                          break;
798                  }                  }
799                    #endif
800          }          }
801          return false;          return false;
802  }  }
# Line 482  String LSCPServer::DestroyMidiInputDevic Line 914  String LSCPServer::DestroyMidiInputDevic
914      return result.Produce();      return result.Produce();
915  }  }
916    
917    EngineChannel* LSCPServer::GetEngineChannel(uint uiSamplerChannel) {
918        SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
919        if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel));
920    
921        EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();
922        if (!pEngineChannel) throw Exception("There is no engine deployed on this sampler channel yet");
923    
924        return pEngineChannel;
925    }
926    
927  /**  /**
928   * Will be called by the parser to load an instrument.   * Will be called by the parser to load an instrument.
929   */   */
# Line 496  String LSCPServer::LoadInstrument(String Line 938  String LSCPServer::LoadInstrument(String
938          if (!pSamplerChannel->GetAudioOutputDevice())          if (!pSamplerChannel->GetAudioOutputDevice())
939              throw Exception("No audio output device connected to sampler channel");              throw Exception("No audio output device connected to sampler channel");
940          if (bBackground) {          if (bBackground) {
941              InstrumentLoader.StartNewLoad(Filename, uiInstrument, pEngineChannel);              InstrumentManager::instrument_id_t id;
942                id.FileName = Filename;
943                id.Index    = uiInstrument;
944                InstrumentManager::LoadInstrumentInBackground(id, pEngineChannel);
945          }          }
946          else {          else {
947              // tell the engine channel which instrument to load              // tell the engine channel which instrument to load
# Line 625  String LSCPServer::GetEngineInfo(String Line 1070  String LSCPServer::GetEngineInfo(String
1070      LockRTNotify();      LockRTNotify();
1071      try {      try {
1072          Engine* pEngine = EngineFactory::Create(EngineName);          Engine* pEngine = EngineFactory::Create(EngineName);
1073          result.Add("DESCRIPTION", pEngine->Description());          result.Add("DESCRIPTION", _escapeLscpResponse(pEngine->Description()));
1074          result.Add("VERSION",     pEngine->Version());          result.Add("VERSION",     pEngine->Version());
1075          EngineFactory::Destroy(pEngine);          EngineFactory::Destroy(pEngine);
1076      }      }
# Line 659  String LSCPServer::GetChannelInfo(uint u Line 1104  String LSCPServer::GetChannelInfo(uint u
1104          String AudioRouting;          String AudioRouting;
1105          int Mute = 0;          int Mute = 0;
1106          bool Solo = false;          bool Solo = false;
1107            String MidiInstrumentMap = "NONE";
1108    
1109          if (pEngineChannel) {          if (pEngineChannel) {
1110              EngineName          = pEngineChannel->EngineName();              EngineName          = pEngineChannel->EngineName();
# Line 676  String LSCPServer::GetChannelInfo(uint u Line 1122  String LSCPServer::GetChannelInfo(uint u
1122              }              }
1123              Mute = pEngineChannel->GetMute();              Mute = pEngineChannel->GetMute();
1124              Solo = pEngineChannel->GetSolo();              Solo = pEngineChannel->GetSolo();
1125                if (pEngineChannel->UsesNoMidiInstrumentMap())
1126                    MidiInstrumentMap = "NONE";
1127                else if (pEngineChannel->UsesDefaultMidiInstrumentMap())
1128                    MidiInstrumentMap = "DEFAULT";
1129                else
1130                    MidiInstrumentMap = ToString(pEngineChannel->GetMidiInstrumentMap());
1131          }          }
1132    
1133          result.Add("ENGINE_NAME", EngineName);          result.Add("ENGINE_NAME", EngineName);
# Line 691  String LSCPServer::GetChannelInfo(uint u Line 1143  String LSCPServer::GetChannelInfo(uint u
1143          if (pSamplerChannel->GetMidiInputChannel() == midi_chan_all) result.Add("MIDI_INPUT_CHANNEL", "ALL");          if (pSamplerChannel->GetMidiInputChannel() == midi_chan_all) result.Add("MIDI_INPUT_CHANNEL", "ALL");
1144          else result.Add("MIDI_INPUT_CHANNEL", pSamplerChannel->GetMidiInputChannel());          else result.Add("MIDI_INPUT_CHANNEL", pSamplerChannel->GetMidiInputChannel());
1145    
1146            // convert the filename into the correct encoding as defined for LSCP
1147            // (especially in terms of special characters -> escape sequences)
1148            if (InstrumentFileName != "NONE" && InstrumentFileName != "") {
1149    #if WIN32
1150                InstrumentFileName = Path::fromWindows(InstrumentFileName).toLscp();
1151    #else
1152                // assuming POSIX
1153                InstrumentFileName = Path::fromPosix(InstrumentFileName).toLscp();
1154    #endif
1155            }
1156    
1157          result.Add("INSTRUMENT_FILE", InstrumentFileName);          result.Add("INSTRUMENT_FILE", InstrumentFileName);
1158          result.Add("INSTRUMENT_NR", InstrumentIndex);          result.Add("INSTRUMENT_NR", InstrumentIndex);
1159          result.Add("INSTRUMENT_NAME", InstrumentName);          result.Add("INSTRUMENT_NAME", _escapeLscpResponse(InstrumentName));
1160          result.Add("INSTRUMENT_STATUS", InstrumentStatus);          result.Add("INSTRUMENT_STATUS", InstrumentStatus);
1161          result.Add("MUTE", Mute == -1 ? "MUTED_BY_SOLO" : (Mute ? "true" : "false"));          result.Add("MUTE", Mute == -1 ? "MUTED_BY_SOLO" : (Mute ? "true" : "false"));
1162          result.Add("SOLO", Solo);          result.Add("SOLO", Solo);
1163            result.Add("MIDI_INSTRUMENT_MAP", MidiInstrumentMap);
1164      }      }
1165      catch (Exception e) {      catch (Exception e) {
1166           result.Error(e);           result.Error(e);
# Line 712  String LSCPServer::GetVoiceCount(uint ui Line 1176  String LSCPServer::GetVoiceCount(uint ui
1176      dmsg(2,("LSCPServer: GetVoiceCount(SamplerChannel=%d)\n", uiSamplerChannel));      dmsg(2,("LSCPServer: GetVoiceCount(SamplerChannel=%d)\n", uiSamplerChannel));
1177      LSCPResultSet result;      LSCPResultSet result;
1178      try {      try {
1179          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");  
1180          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");
1181          result.Add(pEngineChannel->GetEngine()->VoiceCount());          result.Add(pEngineChannel->GetEngine()->VoiceCount());
1182      }      }
# Line 733  String LSCPServer::GetStreamCount(uint u Line 1194  String LSCPServer::GetStreamCount(uint u
1194      dmsg(2,("LSCPServer: GetStreamCount(SamplerChannel=%d)\n", uiSamplerChannel));      dmsg(2,("LSCPServer: GetStreamCount(SamplerChannel=%d)\n", uiSamplerChannel));
1195      LSCPResultSet result;      LSCPResultSet result;
1196      try {      try {
1197          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");  
1198          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");
1199          result.Add(pEngineChannel->GetEngine()->DiskStreamCount());          result.Add(pEngineChannel->GetEngine()->DiskStreamCount());
1200      }      }
# Line 754  String LSCPServer::GetBufferFill(fill_re Line 1212  String LSCPServer::GetBufferFill(fill_re
1212      dmsg(2,("LSCPServer: GetBufferFill(ResponseType=%d, SamplerChannel=%d)\n", ResponseType, uiSamplerChannel));      dmsg(2,("LSCPServer: GetBufferFill(ResponseType=%d, SamplerChannel=%d)\n", ResponseType, uiSamplerChannel));
1213      LSCPResultSet result;      LSCPResultSet result;
1214      try {      try {
1215          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");  
1216          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");
1217          if (!pEngineChannel->GetEngine()->DiskStreamSupported()) result.Add("NA");          if (!pEngineChannel->GetEngine()->DiskStreamSupported()) result.Add("NA");
1218          else {          else {
# Line 845  String LSCPServer::GetMidiInputDriverInf Line 1300  String LSCPServer::GetMidiInputDriverInf
1300              for (;iter != parameters.end(); iter++) {              for (;iter != parameters.end(); iter++) {
1301                  if (s != "") s += ",";                  if (s != "") s += ",";
1302                  s += iter->first;                  s += iter->first;
1303                    delete iter->second;
1304              }              }
1305              result.Add("PARAMETERS", s);              result.Add("PARAMETERS", s);
1306          }          }
# Line 869  String LSCPServer::GetAudioOutputDriverI Line 1325  String LSCPServer::GetAudioOutputDriverI
1325              for (;iter != parameters.end(); iter++) {              for (;iter != parameters.end(); iter++) {
1326                  if (s != "") s += ",";                  if (s != "") s += ",";
1327                  s += iter->first;                  s += iter->first;
1328                    delete iter->second;
1329              }              }
1330              result.Add("PARAMETERS", s);              result.Add("PARAMETERS", s);
1331          }          }
# Line 899  String LSCPServer::GetMidiInputDriverPar Line 1356  String LSCPServer::GetMidiInputDriverPar
1356          if (oRangeMin)      result.Add("RANGE_MIN",     *oRangeMin);          if (oRangeMin)      result.Add("RANGE_MIN",     *oRangeMin);
1357          if (oRangeMax)      result.Add("RANGE_MAX",     *oRangeMax);          if (oRangeMax)      result.Add("RANGE_MAX",     *oRangeMax);
1358          if (oPossibilities) result.Add("POSSIBILITIES", *oPossibilities);          if (oPossibilities) result.Add("POSSIBILITIES", *oPossibilities);
1359            delete pParameter;
1360      }      }
1361      catch (Exception e) {      catch (Exception e) {
1362          result.Error(e);          result.Error(e);
# Line 926  String LSCPServer::GetAudioOutputDriverP Line 1384  String LSCPServer::GetAudioOutputDriverP
1384          if (oRangeMin)      result.Add("RANGE_MIN",     *oRangeMin);          if (oRangeMin)      result.Add("RANGE_MIN",     *oRangeMin);
1385          if (oRangeMax)      result.Add("RANGE_MAX",     *oRangeMax);          if (oRangeMax)      result.Add("RANGE_MAX",     *oRangeMax);
1386          if (oPossibilities) result.Add("POSSIBILITIES", *oPossibilities);          if (oPossibilities) result.Add("POSSIBILITIES", *oPossibilities);
1387            delete pParameter;
1388      }      }
1389      catch (Exception e) {      catch (Exception e) {
1390          result.Error(e);          result.Error(e);
# Line 1174  String LSCPServer::SetAudioOutputChannel Line 1633  String LSCPServer::SetAudioOutputChannel
1633    
1634          // set new channel parameter value          // set new channel parameter value
1635          pParameter->SetValue(ParamVal);          pParameter->SetValue(ParamVal);
1636            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_audio_device_info, DeviceId));
1637      }      }
1638      catch (Exception e) {      catch (Exception e) {
1639          result.Error(e);          result.Error(e);
# Line 1191  String LSCPServer::SetAudioOutputDeviceP Line 1651  String LSCPServer::SetAudioOutputDeviceP
1651          std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();          std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();
1652          if (!parameters.count(ParamKey)) throw Exception("Audio output device " + ToString(DeviceIndex) + " does not have a device parameter '" + ParamKey + "'");          if (!parameters.count(ParamKey)) throw Exception("Audio output device " + ToString(DeviceIndex) + " does not have a device parameter '" + ParamKey + "'");
1653          parameters[ParamKey]->SetValue(ParamVal);          parameters[ParamKey]->SetValue(ParamVal);
1654            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_audio_device_info, DeviceIndex));
1655      }      }
1656      catch (Exception e) {      catch (Exception e) {
1657          result.Error(e);          result.Error(e);
# Line 1208  String LSCPServer::SetMidiInputDevicePar Line 1669  String LSCPServer::SetMidiInputDevicePar
1669          std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();          std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();
1670          if (!parameters.count(ParamKey)) throw Exception("MIDI input device " + ToString(DeviceIndex) + " does not have a device parameter '" + ParamKey + "'");          if (!parameters.count(ParamKey)) throw Exception("MIDI input device " + ToString(DeviceIndex) + " does not have a device parameter '" + ParamKey + "'");
1671          parameters[ParamKey]->SetValue(ParamVal);          parameters[ParamKey]->SetValue(ParamVal);
1672            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_device_info, DeviceIndex));
1673      }      }
1674      catch (Exception e) {      catch (Exception e) {
1675          result.Error(e);          result.Error(e);
# Line 1232  String LSCPServer::SetMidiInputPortParam Line 1694  String LSCPServer::SetMidiInputPortParam
1694          std::map<String,DeviceRuntimeParameter*> parameters = pMidiInputPort->PortParameters();          std::map<String,DeviceRuntimeParameter*> parameters = pMidiInputPort->PortParameters();
1695          if (!parameters.count(ParamKey)) throw Exception("MIDI input device " + ToString(PortIndex) + " does not have a parameter '" + ParamKey + "'");          if (!parameters.count(ParamKey)) throw Exception("MIDI input device " + ToString(PortIndex) + " does not have a parameter '" + ParamKey + "'");
1696          parameters[ParamKey]->SetValue(ParamVal);          parameters[ParamKey]->SetValue(ParamVal);
1697            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_device_info, DeviceIndex));
1698      }      }
1699      catch (Exception e) {      catch (Exception e) {
1700          result.Error(e);          result.Error(e);
# Line 1388  String LSCPServer::SetMIDIInputType(Stri Line 1851  String LSCPServer::SetMIDIInputType(Stri
1851              pDevice = pSampler->CreateMidiInputDevice(MidiInputDriver, params);              pDevice = pSampler->CreateMidiInputDevice(MidiInputDriver, params);
1852              // Make it with at least one initial port.              // Make it with at least one initial port.
1853              std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();              std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();
             parameters["PORTS"]->SetValue("1");  
1854          }          }
1855          // Must have a device...          // Must have a device...
1856          if (pDevice == NULL)          if (pDevice == NULL)
# Line 1431  String LSCPServer::SetVolume(double dVol Line 1893  String LSCPServer::SetVolume(double dVol
1893      dmsg(2,("LSCPServer: SetVolume(Volume=%f, SamplerChannel=%d)\n", dVolume, uiSamplerChannel));      dmsg(2,("LSCPServer: SetVolume(Volume=%f, SamplerChannel=%d)\n", dVolume, uiSamplerChannel));
1894      LSCPResultSet result;      LSCPResultSet result;
1895      try {      try {
1896          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");  
1897          pEngineChannel->Volume(dVolume);          pEngineChannel->Volume(dVolume);
1898      }      }
1899      catch (Exception e) {      catch (Exception e) {
# Line 1450  String LSCPServer::SetChannelMute(bool b Line 1909  String LSCPServer::SetChannelMute(bool b
1909      dmsg(2,("LSCPServer: SetChannelMute(bMute=%d,uiSamplerChannel=%d)\n",bMute,uiSamplerChannel));      dmsg(2,("LSCPServer: SetChannelMute(bMute=%d,uiSamplerChannel=%d)\n",bMute,uiSamplerChannel));
1910      LSCPResultSet result;      LSCPResultSet result;
1911      try {      try {
1912          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");  
1913    
1914          if(!bMute) pEngineChannel->SetMute((HasSoloChannel() && !pEngineChannel->GetSolo()) ? -1 : 0);          if(!bMute) pEngineChannel->SetMute((HasSoloChannel() && !pEngineChannel->GetSolo()) ? -1 : 0);
1915          else pEngineChannel->SetMute(1);          else pEngineChannel->SetMute(1);
# Line 1471  String LSCPServer::SetChannelSolo(bool b Line 1926  String LSCPServer::SetChannelSolo(bool b
1926      dmsg(2,("LSCPServer: SetChannelSolo(bSolo=%d,uiSamplerChannel=%d)\n",bSolo,uiSamplerChannel));      dmsg(2,("LSCPServer: SetChannelSolo(bSolo=%d,uiSamplerChannel=%d)\n",bSolo,uiSamplerChannel));
1927      LSCPResultSet result;      LSCPResultSet result;
1928      try {      try {
1929          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");  
1930    
1931          bool oldSolo = pEngineChannel->GetSolo();          bool oldSolo = pEngineChannel->GetSolo();
1932          bool hadSoloChannel = HasSoloChannel();          bool hadSoloChannel = HasSoloChannel();
1933            
1934          pEngineChannel->SetSolo(bSolo);          pEngineChannel->SetSolo(bSolo);
1935            
1936          if(!oldSolo && bSolo) {          if(!oldSolo && bSolo) {
1937              if(pEngineChannel->GetMute() == -1) pEngineChannel->SetMute(0);              if(pEngineChannel->GetMute() == -1) pEngineChannel->SetMute(0);
1938              if(!hadSoloChannel) MuteNonSoloChannels();              if(!hadSoloChannel) MuteNonSoloChannels();
1939          }          }
1940            
1941          if(oldSolo && !bSolo) {          if(oldSolo && !bSolo) {
1942              if(!HasSoloChannel()) UnmuteChannels();              if(!HasSoloChannel()) UnmuteChannels();
1943              else if(!pEngineChannel->GetMute()) pEngineChannel->SetMute(-1);              else if(!pEngineChannel->GetMute()) pEngineChannel->SetMute(-1);
# Line 1544  void  LSCPServer::UnmuteChannels() { Line 1995  void  LSCPServer::UnmuteChannels() {
1995      }      }
1996  }  }
1997    
1998    String LSCPServer::AddOrReplaceMIDIInstrumentMapping(uint MidiMapID, uint MidiBank, uint MidiProg, String EngineType, String InstrumentFile, uint InstrumentIndex, float Volume, MidiInstrumentMapper::mode_t LoadMode, String Name, bool bModal) {
1999        dmsg(2,("LSCPServer: AddOrReplaceMIDIInstrumentMapping()\n"));
2000    
2001        midi_prog_index_t idx;
2002        idx.midi_bank_msb = (MidiBank >> 7) & 0x7f;
2003        idx.midi_bank_lsb = MidiBank & 0x7f;
2004        idx.midi_prog     = MidiProg;
2005    
2006        MidiInstrumentMapper::entry_t entry;
2007        entry.EngineName      = EngineType;
2008        entry.InstrumentFile  = InstrumentFile;
2009        entry.InstrumentIndex = InstrumentIndex;
2010        entry.LoadMode        = LoadMode;
2011        entry.Volume          = Volume;
2012        entry.Name            = Name;
2013    
2014        LSCPResultSet result;
2015        try {
2016            // PERSISTENT mapping commands might block for a long time, so in
2017            // that case we add/replace the mapping in another thread in case
2018            // the NON_MODAL argument was supplied, non persistent mappings
2019            // should return immediately, so we don't need to do that for them
2020            bool bInBackground = (entry.LoadMode == MidiInstrumentMapper::PERSISTENT && !bModal);
2021            MidiInstrumentMapper::AddOrReplaceEntry(MidiMapID, idx, entry, bInBackground);
2022        } catch (Exception e) {
2023            result.Error(e);
2024        }
2025        return result.Produce();
2026    }
2027    
2028    String LSCPServer::RemoveMIDIInstrumentMapping(uint MidiMapID, uint MidiBank, uint MidiProg) {
2029        dmsg(2,("LSCPServer: RemoveMIDIInstrumentMapping()\n"));
2030    
2031        midi_prog_index_t idx;
2032        idx.midi_bank_msb = (MidiBank >> 7) & 0x7f;
2033        idx.midi_bank_lsb = MidiBank & 0x7f;
2034        idx.midi_prog     = MidiProg;
2035    
2036        LSCPResultSet result;
2037        try {
2038            MidiInstrumentMapper::RemoveEntry(MidiMapID, idx);
2039        } catch (Exception e) {
2040            result.Error(e);
2041        }
2042        return result.Produce();
2043    }
2044    
2045    String LSCPServer::GetMidiInstrumentMappings(uint MidiMapID) {
2046        dmsg(2,("LSCPServer: GetMidiInstrumentMappings()\n"));
2047        LSCPResultSet result;
2048        try {
2049            result.Add(MidiInstrumentMapper::GetInstrumentCount(MidiMapID));
2050        } catch (Exception e) {
2051            result.Error(e);
2052        }
2053        return result.Produce();
2054    }
2055    
2056    
2057    String LSCPServer::GetAllMidiInstrumentMappings() {
2058        dmsg(2,("LSCPServer: GetAllMidiInstrumentMappings()\n"));
2059        LSCPResultSet result;
2060        try {
2061            result.Add(MidiInstrumentMapper::GetInstrumentCount());
2062        } catch (Exception e) {
2063            result.Error(e);
2064        }
2065        return result.Produce();
2066    }
2067    
2068    String LSCPServer::GetMidiInstrumentMapping(uint MidiMapID, uint MidiBank, uint MidiProg) {
2069        dmsg(2,("LSCPServer: GetMidiIstrumentMapping()\n"));
2070        LSCPResultSet result;
2071        try {
2072            MidiInstrumentMapper::entry_t entry = MidiInstrumentMapper::GetEntry(MidiMapID, MidiBank, MidiProg);
2073            // convert the filename into the correct encoding as defined for LSCP
2074            // (especially in terms of special characters -> escape sequences)
2075    #if WIN32
2076            const String instrumentFileName = Path::fromWindows(entry.InstrumentFile).toLscp();
2077    #else
2078            // assuming POSIX
2079            const String instrumentFileName = Path::fromPosix(entry.InstrumentFile).toLscp();
2080    #endif
2081    
2082            result.Add("NAME", _escapeLscpResponse(entry.Name));
2083            result.Add("ENGINE_NAME", entry.EngineName);
2084            result.Add("INSTRUMENT_FILE", instrumentFileName);
2085            result.Add("INSTRUMENT_NR", (int) entry.InstrumentIndex);
2086            String instrumentName;
2087            Engine* pEngine = EngineFactory::Create(entry.EngineName);
2088            if (pEngine) {
2089                if (pEngine->GetInstrumentManager()) {
2090                    InstrumentManager::instrument_id_t instrID;
2091                    instrID.FileName = entry.InstrumentFile;
2092                    instrID.Index    = entry.InstrumentIndex;
2093                    instrumentName = pEngine->GetInstrumentManager()->GetInstrumentName(instrID);
2094                }
2095                EngineFactory::Destroy(pEngine);
2096            }
2097            result.Add("INSTRUMENT_NAME", _escapeLscpResponse(instrumentName));
2098            switch (entry.LoadMode) {
2099                case MidiInstrumentMapper::ON_DEMAND:
2100                    result.Add("LOAD_MODE", "ON_DEMAND");
2101                    break;
2102                case MidiInstrumentMapper::ON_DEMAND_HOLD:
2103                    result.Add("LOAD_MODE", "ON_DEMAND_HOLD");
2104                    break;
2105                case MidiInstrumentMapper::PERSISTENT:
2106                    result.Add("LOAD_MODE", "PERSISTENT");
2107                    break;
2108                default:
2109                    throw Exception("entry reflects invalid LOAD_MODE, consider this as a bug!");
2110            }
2111            result.Add("VOLUME", entry.Volume);
2112        } catch (Exception e) {
2113            result.Error(e);
2114        }
2115        return result.Produce();
2116    }
2117    
2118    String LSCPServer::ListMidiInstrumentMappings(uint MidiMapID) {
2119        dmsg(2,("LSCPServer: ListMidiInstrumentMappings()\n"));
2120        LSCPResultSet result;
2121        try {
2122            String s;
2123            std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t> mappings = MidiInstrumentMapper::Entries(MidiMapID);
2124            std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t>::iterator iter = mappings.begin();
2125            for (; iter != mappings.end(); iter++) {
2126                if (s.size()) s += ",";
2127                s += "{" + ToString(MidiMapID) + ","
2128                         + ToString((int(iter->first.midi_bank_msb) << 7) | int(iter->first.midi_bank_lsb)) + ","
2129                         + ToString(int(iter->first.midi_prog)) + "}";
2130            }
2131            result.Add(s);
2132        } catch (Exception e) {
2133            result.Error(e);
2134        }
2135        return result.Produce();
2136    }
2137    
2138    String LSCPServer::ListAllMidiInstrumentMappings() {
2139        dmsg(2,("LSCPServer: ListAllMidiInstrumentMappings()\n"));
2140        LSCPResultSet result;
2141        try {
2142            std::vector<int> maps = MidiInstrumentMapper::Maps();
2143            String s;
2144            for (int i = 0; i < maps.size(); i++) {
2145                std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t> mappings = MidiInstrumentMapper::Entries(maps[i]);
2146                std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t>::iterator iter = mappings.begin();
2147                for (; iter != mappings.end(); iter++) {
2148                    if (s.size()) s += ",";
2149                    s += "{" + ToString(maps[i]) + ","
2150                             + ToString((int(iter->first.midi_bank_msb) << 7) | int(iter->first.midi_bank_lsb)) + ","
2151                             + ToString(int(iter->first.midi_prog)) + "}";
2152                }
2153            }
2154            result.Add(s);
2155        } catch (Exception e) {
2156            result.Error(e);
2157        }
2158        return result.Produce();
2159    }
2160    
2161    String LSCPServer::ClearMidiInstrumentMappings(uint MidiMapID) {
2162        dmsg(2,("LSCPServer: ClearMidiInstrumentMappings()\n"));
2163        LSCPResultSet result;
2164        try {
2165            MidiInstrumentMapper::RemoveAllEntries(MidiMapID);
2166        } catch (Exception e) {
2167            result.Error(e);
2168        }
2169        return result.Produce();
2170    }
2171    
2172    String LSCPServer::ClearAllMidiInstrumentMappings() {
2173        dmsg(2,("LSCPServer: ClearAllMidiInstrumentMappings()\n"));
2174        LSCPResultSet result;
2175        try {
2176            std::vector<int> maps = MidiInstrumentMapper::Maps();
2177            for (int i = 0; i < maps.size(); i++)
2178                MidiInstrumentMapper::RemoveAllEntries(maps[i]);
2179        } catch (Exception e) {
2180            result.Error(e);
2181        }
2182        return result.Produce();
2183    }
2184    
2185    String LSCPServer::AddMidiInstrumentMap(String MapName) {
2186        dmsg(2,("LSCPServer: AddMidiInstrumentMap()\n"));
2187        LSCPResultSet result;
2188        try {
2189            int MapID = MidiInstrumentMapper::AddMap(MapName);
2190            result = LSCPResultSet(MapID);
2191        } catch (Exception e) {
2192            result.Error(e);
2193        }
2194        return result.Produce();
2195    }
2196    
2197    String LSCPServer::RemoveMidiInstrumentMap(uint MidiMapID) {
2198        dmsg(2,("LSCPServer: RemoveMidiInstrumentMap()\n"));
2199        LSCPResultSet result;
2200        try {
2201            MidiInstrumentMapper::RemoveMap(MidiMapID);
2202        } catch (Exception e) {
2203            result.Error(e);
2204        }
2205        return result.Produce();
2206    }
2207    
2208    String LSCPServer::RemoveAllMidiInstrumentMaps() {
2209        dmsg(2,("LSCPServer: RemoveAllMidiInstrumentMaps()\n"));
2210        LSCPResultSet result;
2211        try {
2212            MidiInstrumentMapper::RemoveAllMaps();
2213        } catch (Exception e) {
2214            result.Error(e);
2215        }
2216        return result.Produce();
2217    }
2218    
2219    String LSCPServer::GetMidiInstrumentMaps() {
2220        dmsg(2,("LSCPServer: GetMidiInstrumentMaps()\n"));
2221        LSCPResultSet result;
2222        try {
2223            result.Add(MidiInstrumentMapper::Maps().size());
2224        } catch (Exception e) {
2225            result.Error(e);
2226        }
2227        return result.Produce();
2228    }
2229    
2230    String LSCPServer::ListMidiInstrumentMaps() {
2231        dmsg(2,("LSCPServer: ListMidiInstrumentMaps()\n"));
2232        LSCPResultSet result;
2233        try {
2234            std::vector<int> maps = MidiInstrumentMapper::Maps();
2235            String sList;
2236            for (int i = 0; i < maps.size(); i++) {
2237                if (sList != "") sList += ",";
2238                sList += ToString(maps[i]);
2239            }
2240            result.Add(sList);
2241        } catch (Exception e) {
2242            result.Error(e);
2243        }
2244        return result.Produce();
2245    }
2246    
2247    String LSCPServer::GetMidiInstrumentMap(uint MidiMapID) {
2248        dmsg(2,("LSCPServer: GetMidiInstrumentMap()\n"));
2249        LSCPResultSet result;
2250        try {
2251            result.Add("NAME", _escapeLscpResponse(MidiInstrumentMapper::MapName(MidiMapID)));
2252            result.Add("DEFAULT", MidiInstrumentMapper::GetDefaultMap() == MidiMapID);
2253        } catch (Exception e) {
2254            result.Error(e);
2255        }
2256        return result.Produce();
2257    }
2258    
2259    String LSCPServer::SetMidiInstrumentMapName(uint MidiMapID, String NewName) {
2260        dmsg(2,("LSCPServer: SetMidiInstrumentMapName()\n"));
2261        LSCPResultSet result;
2262        try {
2263            MidiInstrumentMapper::RenameMap(MidiMapID, NewName);
2264        } catch (Exception e) {
2265            result.Error(e);
2266        }
2267        return result.Produce();
2268    }
2269    
2270    /**
2271     * Set the MIDI instrument map the given sampler channel shall use for
2272     * handling MIDI program change messages. There are the following two
2273     * special (negative) values:
2274     *
2275     *    - (-1) :  set to NONE (ignore program changes)
2276     *    - (-2) :  set to DEFAULT map
2277     */
2278    String LSCPServer::SetChannelMap(uint uiSamplerChannel, int MidiMapID) {
2279        dmsg(2,("LSCPServer: SetChannelMap()\n"));
2280        LSCPResultSet result;
2281        try {
2282            EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2283    
2284            if      (MidiMapID == -1) pEngineChannel->SetMidiInstrumentMapToNone();
2285            else if (MidiMapID == -2) pEngineChannel->SetMidiInstrumentMapToDefault();
2286            else                      pEngineChannel->SetMidiInstrumentMap(MidiMapID);
2287        } catch (Exception e) {
2288            result.Error(e);
2289        }
2290        return result.Produce();
2291    }
2292    
2293    String LSCPServer::CreateFxSend(uint uiSamplerChannel, uint MidiCtrl, String Name) {
2294        dmsg(2,("LSCPServer: CreateFxSend()\n"));
2295        LSCPResultSet result;
2296        try {
2297            EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2298    
2299            FxSend* pFxSend = pEngineChannel->AddFxSend(MidiCtrl, Name);
2300            if (!pFxSend) throw Exception("Could not add FxSend, don't ask, I don't know why (probably a bug)");
2301    
2302            result = LSCPResultSet(pFxSend->Id()); // success
2303        } catch (Exception e) {
2304            result.Error(e);
2305        }
2306        return result.Produce();
2307    }
2308    
2309    String LSCPServer::DestroyFxSend(uint uiSamplerChannel, uint FxSendID) {
2310        dmsg(2,("LSCPServer: DestroyFxSend()\n"));
2311        LSCPResultSet result;
2312        try {
2313            EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2314    
2315            FxSend* pFxSend = NULL;
2316            for (int i = 0; i < pEngineChannel->GetFxSendCount(); i++) {
2317                if (pEngineChannel->GetFxSend(i)->Id() == FxSendID) {
2318                    pFxSend = pEngineChannel->GetFxSend(i);
2319                    break;
2320                }
2321            }
2322            if (!pFxSend) throw Exception("There is no FxSend with that ID on the given sampler channel");
2323            pEngineChannel->RemoveFxSend(pFxSend);
2324        } catch (Exception e) {
2325            result.Error(e);
2326        }
2327        return result.Produce();
2328    }
2329    
2330    String LSCPServer::GetFxSends(uint uiSamplerChannel) {
2331        dmsg(2,("LSCPServer: GetFxSends()\n"));
2332        LSCPResultSet result;
2333        try {
2334            EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2335    
2336            result.Add(pEngineChannel->GetFxSendCount());
2337        } catch (Exception e) {
2338            result.Error(e);
2339        }
2340        return result.Produce();
2341    }
2342    
2343    String LSCPServer::ListFxSends(uint uiSamplerChannel) {
2344        dmsg(2,("LSCPServer: ListFxSends()\n"));
2345        LSCPResultSet result;
2346        String list;
2347        try {
2348            EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2349    
2350            for (int i = 0; i < pEngineChannel->GetFxSendCount(); i++) {
2351                FxSend* pFxSend = pEngineChannel->GetFxSend(i);
2352                if (list != "") list += ",";
2353                list += ToString(pFxSend->Id());
2354            }
2355            result.Add(list);
2356        } catch (Exception e) {
2357            result.Error(e);
2358        }
2359        return result.Produce();
2360    }
2361    
2362    FxSend* LSCPServer::GetFxSend(uint uiSamplerChannel, uint FxSendID) {
2363        EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2364    
2365        FxSend* pFxSend = NULL;
2366        for (int i = 0; i < pEngineChannel->GetFxSendCount(); i++) {
2367            if (pEngineChannel->GetFxSend(i)->Id() == FxSendID) {
2368                pFxSend = pEngineChannel->GetFxSend(i);
2369                break;
2370            }
2371        }
2372        if (!pFxSend) throw Exception("There is no FxSend with that ID on the given sampler channel");
2373        return pFxSend;
2374    }
2375    
2376    String LSCPServer::GetFxSendInfo(uint uiSamplerChannel, uint FxSendID) {
2377        dmsg(2,("LSCPServer: GetFxSendInfo()\n"));
2378        LSCPResultSet result;
2379        try {
2380            EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2381            FxSend* pFxSend = GetFxSend(uiSamplerChannel, FxSendID);
2382    
2383            // gather audio routing informations
2384            String AudioRouting;
2385            for (int chan = 0; chan < pEngineChannel->Channels(); chan++) {
2386                if (AudioRouting != "") AudioRouting += ",";
2387                AudioRouting += ToString(pFxSend->DestinationChannel(chan));
2388            }
2389    
2390            const String sEffectRouting =
2391                (pFxSend->DestinationEffectChain() >= 0 && pFxSend->DestinationEffectChainPosition() >= 0)
2392                    ? ToString(pFxSend->DestinationEffectChain()) + "," + ToString(pFxSend->DestinationEffectChainPosition())
2393                    : "NONE";
2394    
2395            // success
2396            result.Add("NAME", _escapeLscpResponse(pFxSend->Name()));
2397            result.Add("MIDI_CONTROLLER", pFxSend->MidiController());
2398            result.Add("LEVEL", ToString(pFxSend->Level()));
2399            result.Add("AUDIO_OUTPUT_ROUTING", AudioRouting);
2400            result.Add("EFFECT", sEffectRouting);
2401        } catch (Exception e) {
2402            result.Error(e);
2403        }
2404        return result.Produce();
2405    }
2406    
2407    String LSCPServer::SetFxSendName(uint uiSamplerChannel, uint FxSendID, String Name) {
2408        dmsg(2,("LSCPServer: SetFxSendName()\n"));
2409        LSCPResultSet result;
2410        try {
2411            FxSend* pFxSend = GetFxSend(uiSamplerChannel, FxSendID);
2412    
2413            pFxSend->SetName(Name);
2414            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_info, uiSamplerChannel, FxSendID));
2415        } catch (Exception e) {
2416            result.Error(e);
2417        }
2418        return result.Produce();
2419    }
2420    
2421    String LSCPServer::SetFxSendAudioOutputChannel(uint uiSamplerChannel, uint FxSendID, uint FxSendChannel, uint DeviceChannel) {
2422        dmsg(2,("LSCPServer: SetFxSendAudioOutputChannel()\n"));
2423        LSCPResultSet result;
2424        try {
2425            FxSend* pFxSend = GetFxSend(uiSamplerChannel, FxSendID);
2426    
2427            pFxSend->SetDestinationChannel(FxSendChannel, DeviceChannel);
2428            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_info, uiSamplerChannel, FxSendID));
2429        } catch (Exception e) {
2430            result.Error(e);
2431        }
2432        return result.Produce();
2433    }
2434    
2435    String LSCPServer::SetFxSendMidiController(uint uiSamplerChannel, uint FxSendID, uint MidiController) {
2436        dmsg(2,("LSCPServer: SetFxSendMidiController()\n"));
2437        LSCPResultSet result;
2438        try {
2439            FxSend* pFxSend = GetFxSend(uiSamplerChannel, FxSendID);
2440    
2441            pFxSend->SetMidiController(MidiController);
2442            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_info, uiSamplerChannel, FxSendID));
2443        } catch (Exception e) {
2444            result.Error(e);
2445        }
2446        return result.Produce();
2447    }
2448    
2449    String LSCPServer::SetFxSendLevel(uint uiSamplerChannel, uint FxSendID, double dLevel) {
2450        dmsg(2,("LSCPServer: SetFxSendLevel()\n"));
2451        LSCPResultSet result;
2452        try {
2453            FxSend* pFxSend = GetFxSend(uiSamplerChannel, FxSendID);
2454    
2455            pFxSend->SetLevel((float)dLevel);
2456            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_info, uiSamplerChannel, FxSendID));
2457        } catch (Exception e) {
2458            result.Error(e);
2459        }
2460        return result.Produce();
2461    }
2462    
2463    String LSCPServer::SetFxSendEffect(uint uiSamplerChannel, uint FxSendID, int iSendEffectChain, int iEffectChainPosition) {
2464        dmsg(2,("LSCPServer: SetFxSendEffect(%d,%d)\n", iSendEffectChain, iEffectChainPosition));
2465        LSCPResultSet result;
2466        try {
2467            FxSend* pFxSend = GetFxSend(uiSamplerChannel, FxSendID);
2468    
2469            pFxSend->SetDestinationEffect(iSendEffectChain, iEffectChainPosition);
2470            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_info, uiSamplerChannel, FxSendID));
2471        } catch (Exception e) {
2472            result.Error(e);
2473        }
2474        return result.Produce();
2475    }
2476    
2477    String LSCPServer::GetAvailableEffects() {
2478        dmsg(2,("LSCPServer: GetAvailableEffects()\n"));
2479        LSCPResultSet result;
2480        try {
2481            int n = EffectFactory::AvailableEffectsCount();
2482            result.Add(n);
2483        }
2484        catch (Exception e) {
2485            result.Error(e);
2486        }
2487        return result.Produce();
2488    }
2489    
2490    String LSCPServer::ListAvailableEffects() {
2491        dmsg(2,("LSCPServer: ListAvailableEffects()\n"));
2492        LSCPResultSet result;
2493        String list;
2494        try {
2495            //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
2496            int n = EffectFactory::AvailableEffectsCount();
2497            for (int i = 0; i < n; i++) {
2498                if (i) list += ",";
2499                list += ToString(i);
2500            }
2501        }
2502        catch (Exception e) {
2503            result.Error(e);
2504        }
2505        result.Add(list);
2506        return result.Produce();
2507    }
2508    
2509    String LSCPServer::GetEffectInfo(int iEffectIndex) {
2510        dmsg(2,("LSCPServer: GetEffectInfo(%d)\n", iEffectIndex));
2511        LSCPResultSet result;
2512        try {
2513            EffectInfo* pEffectInfo = EffectFactory::GetEffectInfo(iEffectIndex);
2514            if (!pEffectInfo)
2515                throw Exception("There is no effect with index " + ToString(iEffectIndex));
2516    
2517            // convert the filename into the correct encoding as defined for LSCP
2518            // (especially in terms of special characters -> escape sequences)
2519    #if WIN32
2520            const String dllFileName = Path::fromWindows(pEffectInfo->Module()).toLscp();
2521    #else
2522            // assuming POSIX
2523            const String dllFileName = Path::fromPosix(pEffectInfo->Module()).toLscp();
2524    #endif
2525    
2526            result.Add("SYSTEM", pEffectInfo->EffectSystem());
2527            result.Add("MODULE", dllFileName);
2528            result.Add("NAME", _escapeLscpResponse(pEffectInfo->Name()));
2529            result.Add("DESCRIPTION", _escapeLscpResponse(pEffectInfo->Description()));
2530        }
2531        catch (Exception e) {
2532            result.Error(e);
2533        }
2534        return result.Produce();    
2535    }
2536    
2537    String LSCPServer::GetEffectInstanceInfo(int iEffectInstance) {
2538        dmsg(2,("LSCPServer: GetEffectInstanceInfo(%d)\n", iEffectInstance));
2539        LSCPResultSet result;
2540        try {
2541            Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
2542            if (!pEffect)
2543                throw Exception("There is no effect instance with ID " + ToString(iEffectInstance));
2544    
2545            EffectInfo* pEffectInfo = pEffect->GetEffectInfo();
2546    
2547            // convert the filename into the correct encoding as defined for LSCP
2548            // (especially in terms of special characters -> escape sequences)
2549    #if WIN32
2550            const String dllFileName = Path::fromWindows(pEffectInfo->Module()).toLscp();
2551    #else
2552            // assuming POSIX
2553            const String dllFileName = Path::fromPosix(pEffectInfo->Module()).toLscp();
2554    #endif
2555    
2556            result.Add("SYSTEM", pEffectInfo->EffectSystem());
2557            result.Add("MODULE", dllFileName);
2558            result.Add("NAME", _escapeLscpResponse(pEffectInfo->Name()));
2559            result.Add("DESCRIPTION", _escapeLscpResponse(pEffectInfo->Description()));
2560            result.Add("INPUT_CONTROLS", ToString(pEffect->InputControlCount()));
2561        }
2562        catch (Exception e) {
2563            result.Error(e);
2564        }
2565        return result.Produce();
2566    }
2567    
2568    String LSCPServer::GetEffectInstanceInputControlInfo(int iEffectInstance, int iInputControlIndex) {
2569        dmsg(2,("LSCPServer: GetEffectInstanceInputControlInfo(%d,%d)\n", iEffectInstance, iInputControlIndex));
2570        LSCPResultSet result;
2571        try {
2572            Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
2573            if (!pEffect)
2574                throw Exception("There is no effect instance with ID " + ToString(iEffectInstance));
2575    
2576            EffectControl* pEffectControl = pEffect->InputControl(iInputControlIndex);
2577            if (!pEffectControl)
2578                throw Exception(
2579                    "Effect instance " + ToString(iEffectInstance) +
2580                    " does not have an input control with index " +
2581                    ToString(iInputControlIndex)
2582                );
2583    
2584            result.Add("DESCRIPTION", _escapeLscpResponse(pEffectControl->Description()));
2585            result.Add("VALUE", pEffectControl->Value());
2586            if (pEffectControl->MinValue())
2587                 result.Add("RANGE_MIN", *pEffectControl->MinValue());
2588            if (pEffectControl->MaxValue())
2589                 result.Add("RANGE_MAX", *pEffectControl->MaxValue());
2590            if (!pEffectControl->Possibilities().empty())
2591                 result.Add("POSSIBILITIES", pEffectControl->Possibilities());
2592            if (pEffectControl->DefaultValue())
2593                 result.Add("DEFAULT", *pEffectControl->DefaultValue());
2594        } catch (Exception e) {
2595            result.Error(e);
2596        }
2597        return result.Produce();
2598    }
2599    
2600    String LSCPServer::SetEffectInstanceInputControlValue(int iEffectInstance, int iInputControlIndex, double dValue) {
2601        dmsg(2,("LSCPServer: SetEffectInstanceInputControlValue(%d,%d,%f)\n", iEffectInstance, iInputControlIndex, dValue));
2602        LSCPResultSet result;
2603        try {
2604            Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
2605            if (!pEffect)
2606                throw Exception("There is no effect instance with ID " + ToString(iEffectInstance));
2607    
2608            EffectControl* pEffectControl = pEffect->InputControl(iInputControlIndex);
2609            if (!pEffectControl)
2610                throw Exception(
2611                    "Effect instance " + ToString(iEffectInstance) +
2612                    " does not have an input control with index " +
2613                    ToString(iInputControlIndex)
2614                );
2615    
2616            pEffectControl->SetValue(dValue);
2617            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_instance_info, iEffectInstance));
2618        } catch (Exception e) {
2619            result.Error(e);
2620        }
2621        return result.Produce();
2622    }
2623    
2624    String LSCPServer::CreateEffectInstance(int iEffectIndex) {
2625        dmsg(2,("LSCPServer: CreateEffectInstance(%d)\n", iEffectIndex));
2626        LSCPResultSet result;
2627        try {
2628            EffectInfo* pEffectInfo = EffectFactory::GetEffectInfo(iEffectIndex);
2629            if (!pEffectInfo)
2630                throw Exception("There is no effect with index " + ToString(iEffectIndex));
2631            Effect* pEffect = EffectFactory::Create(pEffectInfo);
2632            result = pEffect->ID(); // success
2633            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_instance_count, EffectFactory::EffectInstancesCount()));
2634        } catch (Exception e) {
2635            result.Error(e);
2636        }
2637        return result.Produce();
2638    }
2639    
2640    String LSCPServer::CreateEffectInstance(String effectSystem, String module, String effectName) {
2641        dmsg(2,("LSCPServer: CreateEffectInstance('%s','%s','%s')\n", effectSystem.c_str(), module.c_str(), effectName.c_str()));
2642        LSCPResultSet result;
2643        try {
2644            // to allow loading the same LSCP session file on different systems
2645            // successfully, probably with different effect plugin DLL paths or even
2646            // running completely different operating systems, we do the following
2647            // for finding the right effect:
2648            //
2649            // first try to search for an exact match of the effect plugin DLL
2650            // (a.k.a 'module'), to avoid picking the wrong DLL with the same
2651            // effect name ...
2652            EffectInfo* pEffectInfo = EffectFactory::GetEffectInfo(effectSystem, module, effectName, EffectFactory::MODULE_MATCH_EXACTLY);
2653            // ... if no effect with exactly matchin DLL filename was found, then
2654            // try to lower the restrictions of matching the effect plugin DLL
2655            // filename and try again and again ...
2656            if (!pEffectInfo) {
2657                dmsg(2,("no exact module match, trying MODULE_IGNORE_PATH\n"));
2658                pEffectInfo = EffectFactory::GetEffectInfo(effectSystem, module, effectName, EffectFactory::MODULE_IGNORE_PATH);
2659            }
2660            if (!pEffectInfo) {
2661                dmsg(2,("no module match, trying MODULE_IGNORE_PATH | MODULE_IGNORE_CASE\n"));
2662                pEffectInfo = EffectFactory::GetEffectInfo(effectSystem, module, effectName, EffectFactory::MODULE_IGNORE_PATH | EffectFactory::MODULE_IGNORE_CASE);
2663            }
2664            if (!pEffectInfo) {
2665                dmsg(2,("no module match, trying MODULE_IGNORE_PATH | MODULE_IGNORE_CASE | MODULE_IGNORE_EXTENSION\n"));
2666                pEffectInfo = EffectFactory::GetEffectInfo(effectSystem, module, effectName, EffectFactory::MODULE_IGNORE_PATH | EffectFactory::MODULE_IGNORE_CASE | EffectFactory::MODULE_IGNORE_EXTENSION);
2667            }
2668            // ... if there was still no effect found, then completely ignore the
2669            // DLL plugin filename argument and just search for the matching effect
2670            // system type and effect name
2671            if (!pEffectInfo) {
2672                dmsg(2,("no module match, trying MODULE_IGNORE_ALL\n"));
2673                pEffectInfo = EffectFactory::GetEffectInfo(effectSystem, module, effectName, EffectFactory::MODULE_IGNORE_ALL);
2674            }
2675            if (!pEffectInfo)
2676                throw Exception("There is no such effect '" + effectSystem + "' '" + module + "' '" + effectName + "'");
2677    
2678            Effect* pEffect = EffectFactory::Create(pEffectInfo);
2679            result = LSCPResultSet(pEffect->ID());
2680            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_instance_count, EffectFactory::EffectInstancesCount()));
2681        } catch (Exception e) {
2682            result.Error(e);
2683        }
2684        return result.Produce();
2685    }
2686    
2687    String LSCPServer::DestroyEffectInstance(int iEffectInstance) {
2688        dmsg(2,("LSCPServer: DestroyEffectInstance(%d)\n", iEffectInstance));
2689        LSCPResultSet result;
2690        try {
2691            Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
2692            if (!pEffect)
2693                throw Exception("There is no effect instance with ID " + ToString(iEffectInstance));
2694            EffectFactory::Destroy(pEffect);
2695            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_instance_count, EffectFactory::EffectInstancesCount()));
2696        } catch (Exception e) {
2697            result.Error(e);
2698        }
2699        return result.Produce();
2700    }
2701    
2702    String LSCPServer::GetEffectInstances() {
2703        dmsg(2,("LSCPServer: GetEffectInstances()\n"));
2704        LSCPResultSet result;
2705        try {
2706            int n = EffectFactory::EffectInstancesCount();
2707            result.Add(n);
2708        } catch (Exception e) {
2709            result.Error(e);
2710        }
2711        return result.Produce();
2712    }
2713    
2714    String LSCPServer::ListEffectInstances() {
2715        dmsg(2,("LSCPServer: ListEffectInstances()\n"));
2716        LSCPResultSet result;
2717        String list;
2718        try {
2719            int n = EffectFactory::EffectInstancesCount();
2720            for (int i = 0; i < n; i++) {
2721                Effect* pEffect = EffectFactory::GetEffectInstance(i);
2722                if (i) list += ",";
2723                list += ToString(pEffect->ID());
2724            }
2725        } catch (Exception e) {
2726            result.Error(e);
2727        }
2728        result.Add(list);
2729        return result.Produce();
2730    }
2731    
2732    String LSCPServer::GetSendEffectChains(int iAudioOutputDevice) {
2733        dmsg(2,("LSCPServer: GetSendEffectChains(%d)\n", iAudioOutputDevice));
2734        LSCPResultSet result;
2735        try {
2736            std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
2737            if (!devices.count(iAudioOutputDevice))
2738                throw Exception("There is no audio output device with index " + ToString(iAudioOutputDevice) + ".");
2739            AudioOutputDevice* pDevice = devices[iAudioOutputDevice];
2740            int n = pDevice->SendEffectChainCount();
2741            result.Add(n);
2742        } catch (Exception e) {
2743            result.Error(e);
2744        }
2745        return result.Produce();
2746    }
2747    
2748    String LSCPServer::ListSendEffectChains(int iAudioOutputDevice) {
2749        dmsg(2,("LSCPServer: ListSendEffectChains(%d)\n", iAudioOutputDevice));
2750        LSCPResultSet result;
2751        String list;
2752        try {
2753            std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
2754            if (!devices.count(iAudioOutputDevice))
2755                throw Exception("There is no audio output device with index " + ToString(iAudioOutputDevice) + ".");
2756            AudioOutputDevice* pDevice = devices[iAudioOutputDevice];
2757            int n = pDevice->SendEffectChainCount();
2758            for (int i = 0; i < n; i++) {
2759                EffectChain* pEffectChain = pDevice->SendEffectChain(i);
2760                if (i) list += ",";
2761                list += ToString(pEffectChain->ID());
2762            }
2763        } catch (Exception e) {
2764            result.Error(e);
2765        }
2766        result.Add(list);
2767        return result.Produce();
2768    }
2769    
2770    String LSCPServer::AddSendEffectChain(int iAudioOutputDevice) {
2771        dmsg(2,("LSCPServer: AddSendEffectChain(%d)\n", iAudioOutputDevice));
2772        LSCPResultSet result;
2773        try {
2774            std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
2775            if (!devices.count(iAudioOutputDevice))
2776                throw Exception("There is no audio output device with index " + ToString(iAudioOutputDevice) + ".");
2777            AudioOutputDevice* pDevice = devices[iAudioOutputDevice];
2778            EffectChain* pEffectChain = pDevice->AddSendEffectChain();
2779            result = pEffectChain->ID();
2780            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_send_fx_chain_count, iAudioOutputDevice, pDevice->SendEffectChainCount()));
2781        } catch (Exception e) {
2782            result.Error(e);
2783        }
2784        return result.Produce();
2785    }
2786    
2787    String LSCPServer::RemoveSendEffectChain(int iAudioOutputDevice, int iSendEffectChain) {
2788        dmsg(2,("LSCPServer: RemoveSendEffectChain(%d,%d)\n", iAudioOutputDevice, iSendEffectChain));
2789        LSCPResultSet result;
2790        try {
2791            std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
2792            if (!devices.count(iAudioOutputDevice))
2793                throw Exception("There is no audio output device with index " + ToString(iAudioOutputDevice) + ".");
2794    
2795            std::set<EngineChannel*> engineChannels = EngineChannelFactory::EngineChannelInstances();
2796            std::set<EngineChannel*>::iterator itEngineChannel = engineChannels.begin();
2797            std::set<EngineChannel*>::iterator itEnd           = engineChannels.end();
2798            for (; itEngineChannel != itEnd; ++itEngineChannel) {
2799                AudioOutputDevice* pDev = (*itEngineChannel)->GetAudioOutputDevice();
2800                if (pDev != NULL && pDev->deviceId() == iAudioOutputDevice) {
2801                    for (int i = 0; i < (*itEngineChannel)->GetFxSendCount(); i++) {
2802                        FxSend* fxs = (*itEngineChannel)->GetFxSend(i);
2803                        if(fxs != NULL && fxs->DestinationEffectChain() == iSendEffectChain) {
2804                            throw Exception("The effect chain is still in use by channel " + ToString((*itEngineChannel)->GetSamplerChannel()->Index()));
2805                        }
2806                    }
2807                }
2808            }
2809    
2810            AudioOutputDevice* pDevice = devices[iAudioOutputDevice];
2811            for (int i = 0; i < pDevice->SendEffectChainCount(); i++) {
2812                EffectChain* pEffectChain = pDevice->SendEffectChain(i);
2813                if (pEffectChain->ID() == iSendEffectChain) {
2814                    pDevice->RemoveSendEffectChain(i);
2815                    LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_send_fx_chain_count, iAudioOutputDevice, pDevice->SendEffectChainCount()));
2816                    return result.Produce();
2817                }
2818            }
2819            throw Exception(
2820                "There is no send effect chain with ID " +
2821                ToString(iSendEffectChain) + " for audio output device " +
2822                ToString(iAudioOutputDevice) + "."
2823            );
2824        } catch (Exception e) {
2825            result.Error(e);
2826        }
2827        return result.Produce();
2828    }
2829    
2830    static EffectChain* _getSendEffectChain(Sampler* pSampler, int iAudioOutputDevice, int iSendEffectChain) throw (Exception) {
2831        std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
2832        if (!devices.count(iAudioOutputDevice))
2833            throw Exception(
2834                "There is no audio output device with index " +
2835                ToString(iAudioOutputDevice) + "."
2836            );
2837        AudioOutputDevice* pDevice = devices[iAudioOutputDevice];
2838        EffectChain* pEffectChain = pDevice->SendEffectChainByID(iSendEffectChain);
2839        if(pEffectChain != NULL) return pEffectChain;
2840        throw Exception(
2841            "There is no send effect chain with ID " +
2842            ToString(iSendEffectChain) + " for audio output device " +
2843            ToString(iAudioOutputDevice) + "."
2844        );
2845    }
2846    
2847    String LSCPServer::GetSendEffectChainInfo(int iAudioOutputDevice, int iSendEffectChain) {
2848        dmsg(2,("LSCPServer: GetSendEffectChainInfo(%d,%d)\n", iAudioOutputDevice, iSendEffectChain));
2849        LSCPResultSet result;
2850        try {
2851            EffectChain* pEffectChain =
2852                _getSendEffectChain(pSampler, iAudioOutputDevice, iSendEffectChain);
2853            String sEffectSequence;
2854            for (int i = 0; i < pEffectChain->EffectCount(); i++) {
2855                if (i) sEffectSequence += ",";
2856                sEffectSequence += ToString(pEffectChain->GetEffect(i)->ID());
2857            }
2858            result.Add("EFFECT_COUNT", pEffectChain->EffectCount());
2859            result.Add("EFFECT_SEQUENCE", sEffectSequence);
2860        } catch (Exception e) {
2861            result.Error(e);
2862        }
2863        return result.Produce();
2864    }
2865    
2866    String LSCPServer::AppendSendEffectChainEffect(int iAudioOutputDevice, int iSendEffectChain, int iEffectInstance) {
2867        dmsg(2,("LSCPServer: AppendSendEffectChainEffect(%d,%d,%d)\n", iAudioOutputDevice, iSendEffectChain, iEffectInstance));
2868        LSCPResultSet result;
2869        try {
2870            EffectChain* pEffectChain =
2871                _getSendEffectChain(pSampler, iAudioOutputDevice, iSendEffectChain);
2872            Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
2873            if (!pEffect)
2874                throw Exception("There is no effect instance with ID " + ToString(iEffectInstance));
2875            pEffectChain->AppendEffect(pEffect);
2876            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_send_fx_chain_info, iAudioOutputDevice, iSendEffectChain, pEffectChain->EffectCount()));
2877        } catch (Exception e) {
2878            result.Error(e);
2879        }
2880        return result.Produce();
2881    }
2882    
2883    String LSCPServer::InsertSendEffectChainEffect(int iAudioOutputDevice, int iSendEffectChain, int iEffectChainPosition, int iEffectInstance) {
2884        dmsg(2,("LSCPServer: InsertSendEffectChainEffect(%d,%d,%d,%d)\n", iAudioOutputDevice, iSendEffectChain, iEffectChainPosition, iEffectInstance));
2885        LSCPResultSet result;
2886        try {
2887            EffectChain* pEffectChain =
2888                _getSendEffectChain(pSampler, iAudioOutputDevice, iSendEffectChain);
2889            Effect* pEffect = EffectFactory::GetEffectInstanceByID(iEffectInstance);
2890            if (!pEffect)
2891                throw Exception("There is no effect instance with index " + ToString(iEffectInstance));
2892            pEffectChain->InsertEffect(pEffect, iEffectChainPosition);
2893            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_send_fx_chain_info, iAudioOutputDevice, iSendEffectChain, pEffectChain->EffectCount()));
2894        } catch (Exception e) {
2895            result.Error(e);
2896        }
2897        return result.Produce();
2898    }
2899    
2900    String LSCPServer::RemoveSendEffectChainEffect(int iAudioOutputDevice, int iSendEffectChain, int iEffectChainPosition) {
2901        dmsg(2,("LSCPServer: RemoveSendEffectChainEffect(%d,%d,%d)\n", iAudioOutputDevice, iSendEffectChain, iEffectChainPosition));
2902        LSCPResultSet result;
2903        try {
2904            EffectChain* pEffectChain =
2905                _getSendEffectChain(pSampler, iAudioOutputDevice, iSendEffectChain);
2906    
2907            std::set<EngineChannel*> engineChannels = EngineChannelFactory::EngineChannelInstances();
2908            std::set<EngineChannel*>::iterator itEngineChannel = engineChannels.begin();
2909            std::set<EngineChannel*>::iterator itEnd           = engineChannels.end();
2910            for (; itEngineChannel != itEnd; ++itEngineChannel) {
2911                AudioOutputDevice* pDev = (*itEngineChannel)->GetAudioOutputDevice();
2912                if (pDev != NULL && pDev->deviceId() == iAudioOutputDevice) {
2913                    for (int i = 0; i < (*itEngineChannel)->GetFxSendCount(); i++) {
2914                        FxSend* fxs = (*itEngineChannel)->GetFxSend(i);
2915                        if(fxs != NULL && fxs->DestinationEffectChain() == iSendEffectChain && fxs->DestinationEffectChainPosition() == iEffectChainPosition) {
2916                            throw Exception("The effect instance is still in use by channel " + ToString((*itEngineChannel)->GetSamplerChannel()->Index()));
2917                        }
2918                    }
2919                }
2920            }
2921    
2922            pEffectChain->RemoveEffect(iEffectChainPosition);
2923            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_send_fx_chain_info, iAudioOutputDevice, iSendEffectChain, pEffectChain->EffectCount()));
2924        } catch (Exception e) {
2925            result.Error(e);
2926        }
2927        return result.Produce();
2928    }
2929    
2930    String LSCPServer::EditSamplerChannelInstrument(uint uiSamplerChannel) {
2931        dmsg(2,("LSCPServer: EditSamplerChannelInstrument(SamplerChannel=%d)\n", uiSamplerChannel));
2932        LSCPResultSet result;
2933        try {
2934            EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2935            if (pEngineChannel->InstrumentStatus() < 0) throw Exception("No instrument loaded to sampler channel");
2936            Engine* pEngine = pEngineChannel->GetEngine();
2937            InstrumentManager* pInstrumentManager = pEngine->GetInstrumentManager();
2938            if (!pInstrumentManager) throw Exception("Engine does not provide an instrument manager");
2939            InstrumentManager::instrument_id_t instrumentID;
2940            instrumentID.FileName = pEngineChannel->InstrumentFileName();
2941            instrumentID.Index    = pEngineChannel->InstrumentIndex();
2942            pInstrumentManager->LaunchInstrumentEditor(instrumentID);
2943        } catch (Exception e) {
2944            result.Error(e);
2945        }
2946        return result.Produce();
2947    }
2948    
2949    String LSCPServer::SendChannelMidiData(String MidiMsg, uint uiSamplerChannel, uint Arg1, uint Arg2) {
2950        dmsg(2,("LSCPServer: SendChannelMidiData(MidiMsg=%s,uiSamplerChannel=%d,Arg1=%d,Arg2=%d)\n", MidiMsg.c_str(), uiSamplerChannel, Arg1, Arg2));
2951        LSCPResultSet result;
2952        try {
2953            EngineChannel* pEngineChannel = GetEngineChannel(uiSamplerChannel);
2954    
2955            if (Arg1 > 127 || Arg2 > 127) {
2956                throw Exception("Invalid MIDI message");
2957            }
2958    
2959            VirtualMidiDevice* pMidiDevice = NULL;
2960            std::vector<EventHandler::midi_listener_entry>::iterator iter = eventHandler.channelMidiListeners.begin();
2961            for (; iter != eventHandler.channelMidiListeners.end(); ++iter) {
2962                if ((*iter).pEngineChannel == pEngineChannel) {
2963                    pMidiDevice = (*iter).pMidiListener;
2964                    break;
2965                }
2966            }
2967            
2968            if(pMidiDevice == NULL) throw Exception("Couldn't find virtual MIDI device");
2969    
2970            if (MidiMsg == "NOTE_ON") {
2971                pMidiDevice->SendNoteOnToDevice(Arg1, Arg2);
2972                bool b = pMidiDevice->SendNoteOnToSampler(Arg1, Arg2);
2973                if (!b) throw Exception("MIDI event failed: " + MidiMsg + " " + ToString(Arg1) + " " + ToString(Arg2));
2974            } else if (MidiMsg == "NOTE_OFF") {
2975                pMidiDevice->SendNoteOffToDevice(Arg1, Arg2);
2976                bool b = pMidiDevice->SendNoteOffToSampler(Arg1, Arg2);
2977                if (!b) throw Exception("MIDI event failed: " + MidiMsg + " " + ToString(Arg1) + " " + ToString(Arg2));
2978            } else if (MidiMsg == "CC") {
2979                pMidiDevice->SendCCToDevice(Arg1, Arg2);
2980                bool b = pMidiDevice->SendCCToSampler(Arg1, Arg2);
2981                if (!b) throw Exception("MIDI event failed: " + MidiMsg + " " + ToString(Arg1) + " " + ToString(Arg2));
2982            } else {
2983                throw Exception("Unknown MIDI message type: " + MidiMsg);
2984            }
2985        } catch (Exception e) {
2986            result.Error(e);
2987        }
2988        return result.Produce();
2989    }
2990    
2991  /**  /**
2992   * Will be called by the parser to reset a particular sampler channel.   * Will be called by the parser to reset a particular sampler channel.
2993   */   */
# Line 1551  String LSCPServer::ResetChannel(uint uiS Line 2995  String LSCPServer::ResetChannel(uint uiS
2995      dmsg(2,("LSCPServer: ResetChannel(SamplerChannel=%d)\n", uiSamplerChannel));      dmsg(2,("LSCPServer: ResetChannel(SamplerChannel=%d)\n", uiSamplerChannel));
2996      LSCPResultSet result;      LSCPResultSet result;
2997      try {      try {
2998          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");  
2999          pEngineChannel->Reset();          pEngineChannel->Reset();
3000      }      }
3001      catch (Exception e) {      catch (Exception e) {
# Line 1579  String LSCPServer::ResetSampler() { Line 3020  String LSCPServer::ResetSampler() {
3020   */   */
3021  String LSCPServer::GetServerInfo() {  String LSCPServer::GetServerInfo() {
3022      dmsg(2,("LSCPServer: GetServerInfo()\n"));      dmsg(2,("LSCPServer: GetServerInfo()\n"));
3023        const std::string description =
3024            _escapeLscpResponse("LinuxSampler - modular, streaming capable sampler");
3025      LSCPResultSet result;      LSCPResultSet result;
3026      result.Add("DESCRIPTION", "LinuxSampler - modular, streaming capable sampler");      result.Add("DESCRIPTION", description);
3027      result.Add("VERSION", VERSION);      result.Add("VERSION", VERSION);
3028      result.Add("PROTOCOL_VERSION", "1.0");      result.Add("PROTOCOL_VERSION", ToString(LSCP_RELEASE_MAJOR) + "." + ToString(LSCP_RELEASE_MINOR));
3029    #if HAVE_SQLITE3
3030        result.Add("INSTRUMENTS_DB_SUPPORT", "yes");
3031    #else
3032        result.Add("INSTRUMENTS_DB_SUPPORT", "no");
3033    #endif
3034    
3035        return result.Produce();
3036    }
3037    
3038    /**
3039     * Will be called by the parser to return the current number of all active streams.
3040     */
3041    String LSCPServer::GetTotalStreamCount() {
3042        dmsg(2,("LSCPServer: GetTotalStreamCount()\n"));
3043        LSCPResultSet result;
3044        result.Add(pSampler->GetDiskStreamCount());
3045      return result.Produce();      return result.Produce();
3046  }  }
3047    
# Line 1602  String LSCPServer::GetTotalVoiceCount() Line 3061  String LSCPServer::GetTotalVoiceCount()
3061  String LSCPServer::GetTotalVoiceCountMax() {  String LSCPServer::GetTotalVoiceCountMax() {
3062      dmsg(2,("LSCPServer: GetTotalVoiceCountMax()\n"));      dmsg(2,("LSCPServer: GetTotalVoiceCountMax()\n"));
3063      LSCPResultSet result;      LSCPResultSet result;
3064      result.Add(EngineFactory::EngineInstances().size() * CONFIG_MAX_VOICES);      result.Add(EngineFactory::EngineInstances().size() * GLOBAL_MAX_VOICES);
3065      return result.Produce();      return result.Produce();
3066  }  }
3067    
3068  /**  /**
3069     * Will be called by the parser to return the sampler global maximum
3070     * allowed number of voices.
3071     */
3072    String LSCPServer::GetGlobalMaxVoices() {
3073        dmsg(2,("LSCPServer: GetGlobalMaxVoices()\n"));
3074        LSCPResultSet result;
3075        result.Add(GLOBAL_MAX_VOICES);
3076        return result.Produce();
3077    }
3078    
3079    /**
3080     * Will be called by the parser to set the sampler global maximum number of
3081     * voices.
3082     */
3083    String LSCPServer::SetGlobalMaxVoices(int iVoices) {
3084        dmsg(2,("LSCPServer: SetGlobalMaxVoices(%d)\n", iVoices));
3085        LSCPResultSet result;
3086        try {
3087            if (iVoices < 1) throw Exception("Maximum voices may not be less than 1");
3088            GLOBAL_MAX_VOICES = iVoices; // see common/global_private.cpp
3089            const std::set<Engine*>& engines = EngineFactory::EngineInstances();
3090            if (engines.size() > 0) {
3091                std::set<Engine*>::iterator iter = engines.begin();
3092                std::set<Engine*>::iterator end  = engines.end();
3093                for (; iter != end; ++iter) {
3094                    (*iter)->SetMaxVoices(iVoices);
3095                }
3096            }
3097            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_global_info, "VOICES", GLOBAL_MAX_VOICES));
3098        } catch (Exception e) {
3099            result.Error(e);
3100        }
3101        return result.Produce();
3102    }
3103    
3104    /**
3105     * Will be called by the parser to return the sampler global maximum
3106     * allowed number of disk streams.
3107     */
3108    String LSCPServer::GetGlobalMaxStreams() {
3109        dmsg(2,("LSCPServer: GetGlobalMaxStreams()\n"));
3110        LSCPResultSet result;
3111        result.Add(GLOBAL_MAX_STREAMS);
3112        return result.Produce();
3113    }
3114    
3115    /**
3116     * Will be called by the parser to set the sampler global maximum number of
3117     * disk streams.
3118     */
3119    String LSCPServer::SetGlobalMaxStreams(int iStreams) {
3120        dmsg(2,("LSCPServer: SetGlobalMaxStreams(%d)\n", iStreams));
3121        LSCPResultSet result;
3122        try {
3123            if (iStreams < 0) throw Exception("Maximum disk streams may not be negative");
3124            GLOBAL_MAX_STREAMS = iStreams; // see common/global_private.cpp
3125            const std::set<Engine*>& engines = EngineFactory::EngineInstances();
3126            if (engines.size() > 0) {
3127                std::set<Engine*>::iterator iter = engines.begin();
3128                std::set<Engine*>::iterator end  = engines.end();
3129                for (; iter != end; ++iter) {
3130                    (*iter)->SetMaxDiskStreams(iStreams);
3131                }
3132            }
3133            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_global_info, "STREAMS", GLOBAL_MAX_STREAMS));
3134        } catch (Exception e) {
3135            result.Error(e);
3136        }
3137        return result.Produce();
3138    }
3139    
3140    String LSCPServer::GetGlobalVolume() {
3141        LSCPResultSet result;
3142        result.Add(ToString(GLOBAL_VOLUME)); // see common/global.cpp
3143        return result.Produce();
3144    }
3145    
3146    String LSCPServer::SetGlobalVolume(double dVolume) {
3147        LSCPResultSet result;
3148        try {
3149            if (dVolume < 0) throw Exception("Volume may not be negative");
3150            GLOBAL_VOLUME = dVolume; // see common/global_private.cpp
3151            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_global_info, "VOLUME", GLOBAL_VOLUME));
3152        } catch (Exception e) {
3153            result.Error(e);
3154        }
3155        return result.Produce();
3156    }
3157    
3158    String LSCPServer::GetFileInstruments(String Filename) {
3159        dmsg(2,("LSCPServer: GetFileInstruments(String Filename=%s)\n",Filename.c_str()));
3160        LSCPResultSet result;
3161        try {
3162            VerifyFile(Filename);
3163        } catch (Exception e) {
3164            result.Error(e);
3165            return result.Produce();
3166        }
3167        // try to find a sampler engine that can handle the file
3168        bool bFound = false;
3169        std::vector<String> engineTypes = EngineFactory::AvailableEngineTypes();
3170        for (int i = 0; !bFound && i < engineTypes.size(); i++) {
3171            Engine* pEngine = NULL;
3172            try {
3173                pEngine = EngineFactory::Create(engineTypes[i]);
3174                if (!pEngine) throw Exception("Internal error: could not create '" + engineTypes[i] + "' engine");
3175                InstrumentManager* pManager = pEngine->GetInstrumentManager();
3176                if (pManager) {
3177                    std::vector<InstrumentManager::instrument_id_t> IDs =
3178                        pManager->GetInstrumentFileContent(Filename);
3179                    // return the amount of instruments in the file
3180                    result.Add(IDs.size());
3181                    // no more need to ask other engine types
3182                    bFound = true;
3183                } else dmsg(1,("Warning: engine '%s' does not provide an instrument manager\n", engineTypes[i].c_str()));
3184            } catch (Exception e) {
3185                // NOOP, as exception is thrown if engine doesn't support file
3186            }
3187            if (pEngine) EngineFactory::Destroy(pEngine);
3188        }
3189    
3190        if (!bFound) result.Error("Unknown file format");
3191        return result.Produce();
3192    }
3193    
3194    String LSCPServer::ListFileInstruments(String Filename) {
3195        dmsg(2,("LSCPServer: ListFileInstruments(String Filename=%s)\n",Filename.c_str()));
3196        LSCPResultSet result;
3197        try {
3198            VerifyFile(Filename);
3199        } catch (Exception e) {
3200            result.Error(e);
3201            return result.Produce();
3202        }
3203        // try to find a sampler engine that can handle the file
3204        bool bFound = false;
3205        std::vector<String> engineTypes = EngineFactory::AvailableEngineTypes();
3206        for (int i = 0; !bFound && i < engineTypes.size(); i++) {
3207            Engine* pEngine = NULL;
3208            try {
3209                pEngine = EngineFactory::Create(engineTypes[i]);
3210                if (!pEngine) throw Exception("Internal error: could not create '" + engineTypes[i] + "' engine");
3211                InstrumentManager* pManager = pEngine->GetInstrumentManager();
3212                if (pManager) {
3213                    std::vector<InstrumentManager::instrument_id_t> IDs =
3214                        pManager->GetInstrumentFileContent(Filename);
3215                    // return a list of IDs of the instruments in the file
3216                    String s;
3217                    for (int j = 0; j < IDs.size(); j++) {
3218                        if (s.size()) s += ",";
3219                        s += ToString(IDs[j].Index);
3220                    }
3221                    result.Add(s);
3222                    // no more need to ask other engine types
3223                    bFound = true;
3224                } else dmsg(1,("Warning: engine '%s' does not provide an instrument manager\n", engineTypes[i].c_str()));
3225            } catch (Exception e) {
3226                // NOOP, as exception is thrown if engine doesn't support file
3227            }
3228            if (pEngine) EngineFactory::Destroy(pEngine);
3229        }
3230    
3231        if (!bFound) result.Error("Unknown file format");
3232        return result.Produce();
3233    }
3234    
3235    String LSCPServer::GetFileInstrumentInfo(String Filename, uint InstrumentID) {
3236        dmsg(2,("LSCPServer: GetFileInstrumentInfo(String Filename=%s, InstrumentID=%d)\n",Filename.c_str(),InstrumentID));
3237        LSCPResultSet result;
3238        try {
3239            VerifyFile(Filename);
3240        } catch (Exception e) {
3241            result.Error(e);
3242            return result.Produce();
3243        }
3244        InstrumentManager::instrument_id_t id;
3245        id.FileName = Filename;
3246        id.Index    = InstrumentID;
3247        // try to find a sampler engine that can handle the file
3248        bool bFound = false;
3249        bool bFatalErr = false;
3250        std::vector<String> engineTypes = EngineFactory::AvailableEngineTypes();
3251        for (int i = 0; !bFound && !bFatalErr && i < engineTypes.size(); i++) {
3252            Engine* pEngine = NULL;
3253            try {
3254                pEngine = EngineFactory::Create(engineTypes[i]);
3255                if (!pEngine) throw Exception("Internal error: could not create '" + engineTypes[i] + "' engine");
3256                InstrumentManager* pManager = pEngine->GetInstrumentManager();
3257                if (pManager) {
3258                    // check if the instrument index is valid
3259                    // FIXME: this won't work if an engine only supports parts of the instrument file
3260                    std::vector<InstrumentManager::instrument_id_t> IDs =
3261                        pManager->GetInstrumentFileContent(Filename);
3262                    if (std::find(IDs.begin(), IDs.end(), id) == IDs.end()) {
3263                        std::stringstream ss;
3264                        ss << "Invalid instrument index " << InstrumentID << " for instrument file '" << Filename << "'";
3265                        bFatalErr = true;
3266                        throw Exception(ss.str());
3267                    }
3268                    // get the info of the requested instrument
3269                    InstrumentManager::instrument_info_t info =
3270                        pManager->GetInstrumentInfo(id);
3271                    // return detailed informations about the file
3272                    result.Add("NAME", info.InstrumentName);
3273                    result.Add("FORMAT_FAMILY", engineTypes[i]);
3274                    result.Add("FORMAT_VERSION", info.FormatVersion);
3275                    result.Add("PRODUCT", info.Product);
3276                    result.Add("ARTISTS", info.Artists);
3277    
3278                    std::stringstream ss;
3279                    bool b = false;
3280                    for (int i = 0; i < 128; i++) {
3281                        if (info.KeyBindings[i]) {
3282                            if (b) ss << ',';
3283                            ss << i; b = true;
3284                        }
3285                    }
3286                    result.Add("KEY_BINDINGS", ss.str());
3287    
3288                    b = false;
3289                    std::stringstream ss2;
3290                    for (int i = 0; i < 128; i++) {
3291                        if (info.KeySwitchBindings[i]) {
3292                            if (b) ss2 << ',';
3293                            ss2 << i; b = true;
3294                        }
3295                    }
3296                    result.Add("KEYSWITCH_BINDINGS", ss2.str());
3297                    // no more need to ask other engine types
3298                    bFound = true;
3299                } else dmsg(1,("Warning: engine '%s' does not provide an instrument manager\n", engineTypes[i].c_str()));
3300            } catch (Exception e) {
3301                // usually NOOP, as exception is thrown if engine doesn't support file
3302                if (bFatalErr) result.Error(e);
3303            }
3304            if (pEngine) EngineFactory::Destroy(pEngine);
3305        }
3306    
3307        if (!bFound && !bFatalErr) result.Error("Unknown file format");
3308        return result.Produce();
3309    }
3310    
3311    void LSCPServer::VerifyFile(String Filename) {
3312        #if WIN32
3313        WIN32_FIND_DATA win32FileAttributeData;
3314        BOOL res = GetFileAttributesEx( Filename.c_str(), GetFileExInfoStandard, &win32FileAttributeData );
3315        if (!res) {
3316            std::stringstream ss;
3317            ss << "File does not exist, GetFileAttributesEx failed `" << Filename << "`: Error " << GetLastError();
3318            throw Exception(ss.str());
3319        }
3320        if ( win32FileAttributeData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
3321            throw Exception("Directory is specified");
3322        }
3323        #else
3324        File f(Filename);
3325        if(!f.Exist()) throw Exception(f.GetErrorMsg());
3326        if (f.IsDirectory()) throw Exception("Directory is specified");
3327        #endif
3328    }
3329    
3330    /**
3331   * 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
3332   * server for receiving event messages.   * server for receiving event messages.
3333   */   */
# Line 1632  String LSCPServer::UnsubscribeNotificati Line 3353  String LSCPServer::UnsubscribeNotificati
3353      return result.Produce();      return result.Produce();
3354  }  }
3355    
3356  static int select_callback(void * lscpResultSet, int argc,  String LSCPServer::AddDbInstrumentDirectory(String Dir) {
3357                          char **argv, char **azColName)      dmsg(2,("LSCPServer: AddDbInstrumentDirectory(Dir=%s)\n", Dir.c_str()));
3358  {      LSCPResultSet result;
3359      LSCPResultSet* resultSet = (LSCPResultSet*) lscpResultSet;  #if HAVE_SQLITE3
3360      resultSet->Add(argc, argv);      try {
3361      return 0;          InstrumentsDb::GetInstrumentsDb()->AddDirectory(Dir);
3362        } catch (Exception e) {
3363             result.Error(e);
3364        }
3365    #else
3366        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3367    #endif
3368        return result.Produce();
3369    }
3370    
3371    String LSCPServer::RemoveDbInstrumentDirectory(String Dir, bool Force) {
3372        dmsg(2,("LSCPServer: RemoveDbInstrumentDirectory(Dir=%s,Force=%d)\n", Dir.c_str(), Force));
3373        LSCPResultSet result;
3374    #if HAVE_SQLITE3
3375        try {
3376            InstrumentsDb::GetInstrumentsDb()->RemoveDirectory(Dir, Force);
3377        } catch (Exception e) {
3378             result.Error(e);
3379        }
3380    #else
3381        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3382    #endif
3383        return result.Produce();
3384    }
3385    
3386    String LSCPServer::GetDbInstrumentDirectoryCount(String Dir, bool Recursive) {
3387        dmsg(2,("LSCPServer: GetDbInstrumentDirectoryCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
3388        LSCPResultSet result;
3389    #if HAVE_SQLITE3
3390        try {
3391            result.Add(InstrumentsDb::GetInstrumentsDb()->GetDirectoryCount(Dir, Recursive));
3392        } catch (Exception e) {
3393             result.Error(e);
3394        }
3395    #else
3396        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3397    #endif
3398        return result.Produce();
3399    }
3400    
3401    String LSCPServer::GetDbInstrumentDirectories(String Dir, bool Recursive) {
3402        dmsg(2,("LSCPServer: GetDbInstrumentDirectories(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
3403        LSCPResultSet result;
3404    #if HAVE_SQLITE3
3405        try {
3406            String list;
3407            StringListPtr dirs = InstrumentsDb::GetInstrumentsDb()->GetDirectories(Dir, Recursive);
3408    
3409            for (int i = 0; i < dirs->size(); i++) {
3410                if (list != "") list += ",";
3411                list += "'" + InstrumentsDb::toEscapedPath(dirs->at(i)) + "'";
3412            }
3413    
3414            result.Add(list);
3415        } catch (Exception e) {
3416             result.Error(e);
3417        }
3418    #else
3419        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3420    #endif
3421        return result.Produce();
3422    }
3423    
3424    String LSCPServer::GetDbInstrumentDirectoryInfo(String Dir) {
3425        dmsg(2,("LSCPServer: GetDbInstrumentDirectoryInfo(Dir=%s)\n", Dir.c_str()));
3426        LSCPResultSet result;
3427    #if HAVE_SQLITE3
3428        try {
3429            DbDirectory info = InstrumentsDb::GetInstrumentsDb()->GetDirectoryInfo(Dir);
3430    
3431            result.Add("DESCRIPTION", _escapeLscpResponse(info.Description));
3432            result.Add("CREATED", info.Created);
3433            result.Add("MODIFIED", info.Modified);
3434        } catch (Exception e) {
3435             result.Error(e);
3436        }
3437    #else
3438        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3439    #endif
3440        return result.Produce();
3441    }
3442    
3443    String LSCPServer::SetDbInstrumentDirectoryName(String Dir, String Name) {
3444        dmsg(2,("LSCPServer: SetDbInstrumentDirectoryName(Dir=%s,Name=%s)\n", Dir.c_str(), Name.c_str()));
3445        LSCPResultSet result;
3446    #if HAVE_SQLITE3
3447        try {
3448            InstrumentsDb::GetInstrumentsDb()->RenameDirectory(Dir, Name);
3449        } catch (Exception e) {
3450             result.Error(e);
3451        }
3452    #else
3453        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3454    #endif
3455        return result.Produce();
3456    }
3457    
3458    String LSCPServer::MoveDbInstrumentDirectory(String Dir, String Dst) {
3459        dmsg(2,("LSCPServer: MoveDbInstrumentDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));
3460        LSCPResultSet result;
3461    #if HAVE_SQLITE3
3462        try {
3463            InstrumentsDb::GetInstrumentsDb()->MoveDirectory(Dir, Dst);
3464        } catch (Exception e) {
3465             result.Error(e);
3466        }
3467    #else
3468        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3469    #endif
3470        return result.Produce();
3471    }
3472    
3473    String LSCPServer::CopyDbInstrumentDirectory(String Dir, String Dst) {
3474        dmsg(2,("LSCPServer: CopyDbInstrumentDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));
3475        LSCPResultSet result;
3476    #if HAVE_SQLITE3
3477        try {
3478            InstrumentsDb::GetInstrumentsDb()->CopyDirectory(Dir, Dst);
3479        } catch (Exception e) {
3480             result.Error(e);
3481        }
3482    #else
3483        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3484    #endif
3485        return result.Produce();
3486    }
3487    
3488    String LSCPServer::SetDbInstrumentDirectoryDescription(String Dir, String Desc) {
3489        dmsg(2,("LSCPServer: SetDbInstrumentDirectoryDescription(Dir=%s,Desc=%s)\n", Dir.c_str(), Desc.c_str()));
3490        LSCPResultSet result;
3491    #if HAVE_SQLITE3
3492        try {
3493            InstrumentsDb::GetInstrumentsDb()->SetDirectoryDescription(Dir, Desc);
3494        } catch (Exception e) {
3495             result.Error(e);
3496        }
3497    #else
3498        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3499    #endif
3500        return result.Produce();
3501  }  }
3502    
3503  String LSCPServer::QueryDatabase(String query) {  String LSCPServer::AddDbInstruments(String DbDir, String FilePath, int Index, bool bBackground) {
3504        dmsg(2,("LSCPServer: AddDbInstruments(DbDir=%s,FilePath=%s,Index=%d,bBackground=%d)\n", DbDir.c_str(), FilePath.c_str(), Index, bBackground));
3505      LSCPResultSet result;      LSCPResultSet result;
3506  #if HAVE_SQLITE3  #if HAVE_SQLITE3
3507      char* zErrMsg = NULL;      try {
3508      sqlite3 *db;          int id;
3509      String selectStr = "SELECT " + query;          InstrumentsDb* db = InstrumentsDb::GetInstrumentsDb();
3510            id = db->AddInstruments(DbDir, FilePath, Index, bBackground);
3511            if (bBackground) result = id;
3512        } catch (Exception e) {
3513             result.Error(e);
3514        }
3515    #else
3516        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3517    #endif
3518        return result.Produce();
3519    }
3520    
3521    String LSCPServer::AddDbInstruments(String ScanMode, String DbDir, String FsDir, bool bBackground, bool insDir) {
3522        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));
3523        LSCPResultSet result;
3524    #if HAVE_SQLITE3
3525        try {
3526            int id;
3527            InstrumentsDb* db = InstrumentsDb::GetInstrumentsDb();
3528            if (ScanMode.compare("RECURSIVE") == 0) {
3529                id = db->AddInstruments(RECURSIVE, DbDir, FsDir, bBackground, insDir);
3530            } else if (ScanMode.compare("NON_RECURSIVE") == 0) {
3531                id = db->AddInstruments(NON_RECURSIVE, DbDir, FsDir, bBackground, insDir);
3532            } else if (ScanMode.compare("FLAT") == 0) {
3533                id = db->AddInstruments(FLAT, DbDir, FsDir, bBackground, insDir);
3534            } else {
3535                throw Exception("Unknown scan mode: " + ScanMode);
3536            }
3537    
3538      int rc = sqlite3_open("linuxsampler.db", &db);          if (bBackground) result = id;
3539      if (rc == SQLITE_OK)      } catch (Exception e) {
3540      {           result.Error(e);
             rc = sqlite3_exec(db, selectStr.c_str(), select_callback, &result, &zErrMsg);  
3541      }      }
3542      if ( rc != SQLITE_OK )  #else
3543      {      result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3544              result.Error(String(zErrMsg), rc);  #endif
3545        return result.Produce();
3546    }
3547    
3548    String LSCPServer::RemoveDbInstrument(String Instr) {
3549        dmsg(2,("LSCPServer: RemoveDbInstrument(Instr=%s)\n", Instr.c_str()));
3550        LSCPResultSet result;
3551    #if HAVE_SQLITE3
3552        try {
3553            InstrumentsDb::GetInstrumentsDb()->RemoveInstrument(Instr);
3554        } catch (Exception e) {
3555             result.Error(e);
3556      }      }
     sqlite3_close(db);  
3557  #else  #else
3558      result.Error(String("SQLITE3 was not installed when linuxsampler was built. SELECT statement is not available."), 0);      result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3559  #endif  #endif
3560      return result.Produce();      return result.Produce();
3561  }  }
3562    
3563    String LSCPServer::GetDbInstrumentCount(String Dir, bool Recursive) {
3564        dmsg(2,("LSCPServer: GetDbInstrumentCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
3565        LSCPResultSet result;
3566    #if HAVE_SQLITE3
3567        try {
3568            result.Add(InstrumentsDb::GetInstrumentsDb()->GetInstrumentCount(Dir, Recursive));
3569        } catch (Exception e) {
3570             result.Error(e);
3571        }
3572    #else
3573        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3574    #endif
3575        return result.Produce();
3576    }
3577    
3578    String LSCPServer::GetDbInstruments(String Dir, bool Recursive) {
3579        dmsg(2,("LSCPServer: GetDbInstruments(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
3580        LSCPResultSet result;
3581    #if HAVE_SQLITE3
3582        try {
3583            String list;
3584            StringListPtr instrs = InstrumentsDb::GetInstrumentsDb()->GetInstruments(Dir, Recursive);
3585    
3586            for (int i = 0; i < instrs->size(); i++) {
3587                if (list != "") list += ",";
3588                list += "'" + InstrumentsDb::toEscapedPath(instrs->at(i)) + "'";
3589            }
3590    
3591            result.Add(list);
3592        } catch (Exception e) {
3593             result.Error(e);
3594        }
3595    #else
3596        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3597    #endif
3598        return result.Produce();
3599    }
3600    
3601    String LSCPServer::GetDbInstrumentInfo(String Instr) {
3602        dmsg(2,("LSCPServer: GetDbInstrumentInfo(Instr=%s)\n", Instr.c_str()));
3603        LSCPResultSet result;
3604    #if HAVE_SQLITE3
3605        try {
3606            DbInstrument info = InstrumentsDb::GetInstrumentsDb()->GetInstrumentInfo(Instr);
3607    
3608            result.Add("INSTRUMENT_FILE", info.InstrFile);
3609            result.Add("INSTRUMENT_NR", info.InstrNr);
3610            result.Add("FORMAT_FAMILY", info.FormatFamily);
3611            result.Add("FORMAT_VERSION", info.FormatVersion);
3612            result.Add("SIZE", (int)info.Size);
3613            result.Add("CREATED", info.Created);
3614            result.Add("MODIFIED", info.Modified);
3615            result.Add("DESCRIPTION", _escapeLscpResponse(info.Description));
3616            result.Add("IS_DRUM", info.IsDrum);
3617            result.Add("PRODUCT", _escapeLscpResponse(info.Product));
3618            result.Add("ARTISTS", _escapeLscpResponse(info.Artists));
3619            result.Add("KEYWORDS", _escapeLscpResponse(info.Keywords));
3620        } catch (Exception e) {
3621             result.Error(e);
3622        }
3623    #else
3624        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3625    #endif
3626        return result.Produce();
3627    }
3628    
3629    String LSCPServer::GetDbInstrumentsJobInfo(int JobId) {
3630        dmsg(2,("LSCPServer: GetDbInstrumentsJobInfo(JobId=%d)\n", JobId));
3631        LSCPResultSet result;
3632    #if HAVE_SQLITE3
3633        try {
3634            ScanJob job = InstrumentsDb::GetInstrumentsDb()->Jobs.GetJobById(JobId);
3635    
3636            result.Add("FILES_TOTAL", job.FilesTotal);
3637            result.Add("FILES_SCANNED", job.FilesScanned);
3638            result.Add("SCANNING", job.Scanning);
3639            result.Add("STATUS", job.Status);
3640        } catch (Exception e) {
3641             result.Error(e);
3642        }
3643    #else
3644        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3645    #endif
3646        return result.Produce();
3647    }
3648    
3649    String LSCPServer::SetDbInstrumentName(String Instr, String Name) {
3650        dmsg(2,("LSCPServer: SetDbInstrumentName(Instr=%s,Name=%s)\n", Instr.c_str(), Name.c_str()));
3651        LSCPResultSet result;
3652    #if HAVE_SQLITE3
3653        try {
3654            InstrumentsDb::GetInstrumentsDb()->RenameInstrument(Instr, Name);
3655        } catch (Exception e) {
3656             result.Error(e);
3657        }
3658    #else
3659        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3660    #endif
3661        return result.Produce();
3662    }
3663    
3664    String LSCPServer::MoveDbInstrument(String Instr, String Dst) {
3665        dmsg(2,("LSCPServer: MoveDbInstrument(Instr=%s,Dst=%s)\n", Instr.c_str(), Dst.c_str()));
3666        LSCPResultSet result;
3667    #if HAVE_SQLITE3
3668        try {
3669            InstrumentsDb::GetInstrumentsDb()->MoveInstrument(Instr, Dst);
3670        } catch (Exception e) {
3671             result.Error(e);
3672        }
3673    #else
3674        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3675    #endif
3676        return result.Produce();
3677    }
3678    
3679    String LSCPServer::CopyDbInstrument(String Instr, String Dst) {
3680        dmsg(2,("LSCPServer: CopyDbInstrument(Instr=%s,Dst=%s)\n", Instr.c_str(), Dst.c_str()));
3681        LSCPResultSet result;
3682    #if HAVE_SQLITE3
3683        try {
3684            InstrumentsDb::GetInstrumentsDb()->CopyInstrument(Instr, Dst);
3685        } catch (Exception e) {
3686             result.Error(e);
3687        }
3688    #else
3689        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3690    #endif
3691        return result.Produce();
3692    }
3693    
3694    String LSCPServer::SetDbInstrumentDescription(String Instr, String Desc) {
3695        dmsg(2,("LSCPServer: SetDbInstrumentDescription(Instr=%s,Desc=%s)\n", Instr.c_str(), Desc.c_str()));
3696        LSCPResultSet result;
3697    #if HAVE_SQLITE3
3698        try {
3699            InstrumentsDb::GetInstrumentsDb()->SetInstrumentDescription(Instr, Desc);
3700        } catch (Exception e) {
3701             result.Error(e);
3702        }
3703    #else
3704        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3705    #endif
3706        return result.Produce();
3707    }
3708    
3709    String LSCPServer::SetDbInstrumentFilePath(String OldPath, String NewPath) {
3710        dmsg(2,("LSCPServer: SetDbInstrumentFilePath(OldPath=%s,NewPath=%s)\n", OldPath.c_str(), NewPath.c_str()));
3711        LSCPResultSet result;
3712    #if HAVE_SQLITE3
3713        try {
3714            InstrumentsDb::GetInstrumentsDb()->SetInstrumentFilePath(OldPath, NewPath);
3715        } catch (Exception e) {
3716             result.Error(e);
3717        }
3718    #else
3719        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3720    #endif
3721        return result.Produce();
3722    }
3723    
3724    String LSCPServer::FindLostDbInstrumentFiles() {
3725        dmsg(2,("LSCPServer: FindLostDbInstrumentFiles()\n"));
3726        LSCPResultSet result;
3727    #if HAVE_SQLITE3
3728        try {
3729            String list;
3730            StringListPtr pLostFiles = InstrumentsDb::GetInstrumentsDb()->FindLostInstrumentFiles();
3731    
3732            for (int i = 0; i < pLostFiles->size(); i++) {
3733                if (list != "") list += ",";
3734                list += "'" + pLostFiles->at(i) + "'";
3735            }
3736    
3737            result.Add(list);
3738        } catch (Exception e) {
3739             result.Error(e);
3740        }
3741    #else
3742        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3743    #endif
3744        return result.Produce();
3745    }
3746    
3747    String LSCPServer::FindDbInstrumentDirectories(String Dir, std::map<String,String> Parameters, bool Recursive) {
3748        dmsg(2,("LSCPServer: FindDbInstrumentDirectories(Dir=%s)\n", Dir.c_str()));
3749        LSCPResultSet result;
3750    #if HAVE_SQLITE3
3751        try {
3752            SearchQuery Query;
3753            std::map<String,String>::iterator iter;
3754            for (iter = Parameters.begin(); iter != Parameters.end(); iter++) {
3755                if (iter->first.compare("NAME") == 0) {
3756                    Query.Name = iter->second;
3757                } else if (iter->first.compare("CREATED") == 0) {
3758                    Query.SetCreated(iter->second);
3759                } else if (iter->first.compare("MODIFIED") == 0) {
3760                    Query.SetModified(iter->second);
3761                } else if (iter->first.compare("DESCRIPTION") == 0) {
3762                    Query.Description = iter->second;
3763                } else {
3764                    throw Exception("Unknown search criteria: " + iter->first);
3765                }
3766            }
3767    
3768            String list;
3769            StringListPtr pDirectories =
3770                InstrumentsDb::GetInstrumentsDb()->FindDirectories(Dir, &Query, Recursive);
3771    
3772            for (int i = 0; i < pDirectories->size(); i++) {
3773                if (list != "") list += ",";
3774                list += "'" + InstrumentsDb::toEscapedPath(pDirectories->at(i)) + "'";
3775            }
3776    
3777            result.Add(list);
3778        } catch (Exception e) {
3779             result.Error(e);
3780        }
3781    #else
3782        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3783    #endif
3784        return result.Produce();
3785    }
3786    
3787    String LSCPServer::FindDbInstruments(String Dir, std::map<String,String> Parameters, bool Recursive) {
3788        dmsg(2,("LSCPServer: FindDbInstruments(Dir=%s)\n", Dir.c_str()));
3789        LSCPResultSet result;
3790    #if HAVE_SQLITE3
3791        try {
3792            SearchQuery Query;
3793            std::map<String,String>::iterator iter;
3794            for (iter = Parameters.begin(); iter != Parameters.end(); iter++) {
3795                if (iter->first.compare("NAME") == 0) {
3796                    Query.Name = iter->second;
3797                } else if (iter->first.compare("FORMAT_FAMILIES") == 0) {
3798                    Query.SetFormatFamilies(iter->second);
3799                } else if (iter->first.compare("SIZE") == 0) {
3800                    Query.SetSize(iter->second);
3801                } else if (iter->first.compare("CREATED") == 0) {
3802                    Query.SetCreated(iter->second);
3803                } else if (iter->first.compare("MODIFIED") == 0) {
3804                    Query.SetModified(iter->second);
3805                } else if (iter->first.compare("DESCRIPTION") == 0) {
3806                    Query.Description = iter->second;
3807                } else if (iter->first.compare("IS_DRUM") == 0) {
3808                    if (!strcasecmp(iter->second.c_str(), "true")) {
3809                        Query.InstrType = SearchQuery::DRUM;
3810                    } else {
3811                        Query.InstrType = SearchQuery::CHROMATIC;
3812                    }
3813                } else if (iter->first.compare("PRODUCT") == 0) {
3814                     Query.Product = iter->second;
3815                } else if (iter->first.compare("ARTISTS") == 0) {
3816                     Query.Artists = iter->second;
3817                } else if (iter->first.compare("KEYWORDS") == 0) {
3818                     Query.Keywords = iter->second;
3819                } else {
3820                    throw Exception("Unknown search criteria: " + iter->first);
3821                }
3822            }
3823    
3824            String list;
3825            StringListPtr pInstruments =
3826                InstrumentsDb::GetInstrumentsDb()->FindInstruments(Dir, &Query, Recursive);
3827    
3828            for (int i = 0; i < pInstruments->size(); i++) {
3829                if (list != "") list += ",";
3830                list += "'" + InstrumentsDb::toEscapedPath(pInstruments->at(i)) + "'";
3831            }
3832    
3833            result.Add(list);
3834        } catch (Exception e) {
3835             result.Error(e);
3836        }
3837    #else
3838        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3839    #endif
3840        return result.Produce();
3841    }
3842    
3843    String LSCPServer::FormatInstrumentsDb() {
3844        dmsg(2,("LSCPServer: FormatInstrumentsDb()\n"));
3845        LSCPResultSet result;
3846    #if HAVE_SQLITE3
3847        try {
3848            InstrumentsDb::GetInstrumentsDb()->Format();
3849        } catch (Exception e) {
3850             result.Error(e);
3851        }
3852    #else
3853        result.Error(String(DOESNT_HAVE_SQLITE3), 0);
3854    #endif
3855        return result.Produce();
3856    }
3857    
3858    
3859  /**  /**
3860   * 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
3861   * mode is enabled, all commands from the client will (immediately) be   * mode is enabled, all commands from the client will (immediately) be
# Line 1681  String LSCPServer::SetEcho(yyparse_param Line 3874  String LSCPServer::SetEcho(yyparse_param
3874      }      }
3875      return result.Produce();      return result.Produce();
3876  }  }
3877    
3878    }

Legend:
Removed from v.907  
changed lines
  Added in v.2198

  ViewVC Help
Powered by ViewVC