/[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 35 by schoenebeck, Fri Mar 5 13:46:15 2004 UTC revision 211 by schoenebeck, Sun Jul 25 23:27:41 2004 UTC
# Line 2  Line 2 
2   *                                                                         *   *                                                                         *
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003 by Benno Senoner and Christian Schoenebeck         *   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6   *                                                                         *   *                                                                         *
7   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
8   *   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   ***************************************************************************/   ***************************************************************************/
22    
23  #include "lscpserver.h"  #include "lscpserver.h"
24    #include "lscpresultset.h"
25    #include "lscpevent.h"
26    
27  LSCPServer::LSCPServer(AudioThread* pEngine) : Thread(false, 0, -4) {  #include "../engines/gig/Engine.h"
28      this->pEngine = pEngine;  #include "../drivers/audio/AudioOutputDeviceFactory.h"
29    #include "../drivers/midi/MidiInputDeviceFactory.h"
30    
31    /**
32     * Below are a few static members of the LSCPServer class.
33     * The big assumption here is that LSCPServer is going to remain a singleton.
34     * These members are used to support client connections.
35     * Class handles multiple connections at the same time using select() and non-blocking recv()
36     * Commands are processed by a single LSCPServer thread.
37     * Notifications are delivered either by the thread that originated them
38     * or (if the resultset is currently in progress) by the LSCPServer thread
39     * after the resultset was sent out.
40     * This makes sure that resultsets can not be interrupted by notifications.
41     * This also makes sure that the thread sending notification is not blocked
42     * by the LSCPServer thread.
43     */
44    fd_set LSCPServer::fdSet;
45    int LSCPServer::currentSocket = -1;
46    std::vector<yyparse_param_t> LSCPServer::Sessions = std::vector<yyparse_param_t>();
47    std::map<int,String> LSCPServer::bufferedNotifies = std::map<int,String>();
48    std::map<int,String> LSCPServer::bufferedCommands = std::map<int,String>();
49    std::map< LSCPEvent::event_t, std::list<int> > LSCPServer::eventSubscriptions = std::map< LSCPEvent::event_t, std::list<int> >();
50    Mutex LSCPServer::NotifyMutex = Mutex();
51    Mutex LSCPServer::NotifyBufferMutex = Mutex();
52    Mutex LSCPServer::SubscriptionMutex = Mutex();
53    
54    LSCPServer::LSCPServer(Sampler* pSampler) : Thread(false, 0, -4) {
55        this->pSampler = pSampler;
56        LSCPEvent::RegisterEvent(LSCPEvent::event_channels, "CHANNELS");
57        LSCPEvent::RegisterEvent(LSCPEvent::event_voice_count, "VOICE_COUNT");
58        LSCPEvent::RegisterEvent(LSCPEvent::event_stream_count, "STREAM_COUNT");
59        LSCPEvent::RegisterEvent(LSCPEvent::event_buffer_fill, "BUFFER_FILL");
60        LSCPEvent::RegisterEvent(LSCPEvent::event_info, "INFO");
61        LSCPEvent::RegisterEvent(LSCPEvent::event_misc, "MISCELLANEOUS");
62    }
63    
64    /**
65     * Blocks the calling thread until the LSCP Server is initialized and
66     * accepting socket connections, if the server is already initialized then
67     * this method will return immediately.
68     * @param TimeoutSeconds     - optional: max. wait time in seconds
69     *                             (default: 0s)
70     * @param TimeoutNanoSeconds - optional: max wait time in nano seconds
71     *                             (default: 0ns)
72     * @returns  0 on success, a value less than 0 if timeout exceeded
73     */
74    int LSCPServer::WaitUntilInitialized(long TimeoutSeconds, long TimeoutNanoSeconds) {
75        return Initialized.WaitAndUnlockIf(false, TimeoutSeconds, TimeoutNanoSeconds);
76  }  }
77    
78  int LSCPServer::Main() {  int LSCPServer::Main() {
79      hSocket = socket(AF_INET, SOCK_STREAM, 0);      int hSocket = socket(AF_INET, SOCK_STREAM, 0);
80      if (hSocket < 0) {      if (hSocket < 0) {
81          std::cerr << "LSCPServer: Could not create server socket." << std::endl;          std::cerr << "LSCPServer: Could not create server socket." << std::endl;
82          return -1;          //return -1;
83            exit(EXIT_FAILURE);
84      }      }
85    
86      SocketAddress.sin_family      = AF_INET;      SocketAddress.sin_family      = AF_INET;
# Line 40  int LSCPServer::Main() { Line 90  int LSCPServer::Main() {
90      if (bind(hSocket, (sockaddr*) &SocketAddress, sizeof(sockaddr_in)) < 0) {      if (bind(hSocket, (sockaddr*) &SocketAddress, sizeof(sockaddr_in)) < 0) {
91          std::cerr << "LSCPServer: Could not bind server socket." << std::endl;          std::cerr << "LSCPServer: Could not bind server socket." << std::endl;
92          close(hSocket);          close(hSocket);
93          return -1;          //return -1;
94            exit(EXIT_FAILURE);
95      }      }
96    
97      listen(hSocket, 1);      listen(hSocket, 1);
98      dmsg(1,("LSCPServer: Server running.\n")); // server running      Initialized.Set(true);
99    
100      // now wait for client connections and handle their requests      // now wait for client connections and handle their requests
101      sockaddr_in client;      sockaddr_in client;
102      int length = sizeof(client);      int length = sizeof(client);
103      while (true) {      FD_ZERO(&fdSet);
104          hSession = accept(hSocket, (sockaddr*) &client, (socklen_t*) &length);      FD_SET(hSocket, &fdSet);
105          if (hSession < 0) {      int maxSessions = hSocket;
             std::cerr << "LSCPServer: Client connection failed." << std::endl;  
             close(hSocket);  
             return -1;  
         }  
   
         dmsg(1,("LSCPServer: Client connection established.\n"));  
         //send(hSession, "Welcome!\r\n", 10, 0);  
   
         // Parser invocation  
         yyparse_param_t yyparse_param;  
         yyparse_param.pServer = this;  
         yylex_init(&yyparse_param.pScanner);  
         while (yyparse(&yyparse_param) == LSCP_SYNTAX_ERROR); // recall parser in case of syntax error  
         yylex_destroy(yyparse_param.pScanner);  
106    
107          close(hSession);      while (true) {
108          dmsg(1,("LSCPServer: Client connection terminated.\n"));          fd_set selectSet = fdSet;
109            int retval = select(maxSessions+1, &selectSet, NULL, NULL, NULL);
110            if (retval == 0)
111                    continue; //Nothing try again
112            if (retval == -1) {
113                    std::cerr << "LSCPServer: Socket select error." << std::endl;
114                    close(hSocket);
115                    exit(EXIT_FAILURE);
116            }
117    
118            //Accept new connections now (if any)
119            if (FD_ISSET(hSocket, &selectSet)) {
120                    int socket = accept(hSocket, (sockaddr*) &client, (socklen_t*) &length);
121                    if (socket < 0) {
122                            std::cerr << "LSCPServer: Client connection failed." << std::endl;
123                            exit(EXIT_FAILURE);
124                    }
125    
126                    if (fcntl(socket, F_SETFL, O_NONBLOCK)) {
127                            std::cerr << "LSCPServer: F_SETFL O_NONBLOCK failed." << std::endl;
128                            exit(EXIT_FAILURE);
129                    }
130    
131                    // Parser initialization
132                    yyparse_param_t yyparse_param;
133                    yyparse_param.pServer  = this;
134                    yyparse_param.hSession = socket;
135    
136                    Sessions.push_back(yyparse_param);
137                    FD_SET(socket, &fdSet);
138                    if (socket > maxSessions)
139                            maxSessions = socket;
140                    dmsg(1,("LSCPServer: Client connection established on socket:%d.\n", socket));
141                    LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_misc, "Client connection established on socket", socket));
142                    continue; //Maybe this was the only selected socket, better select again
143            }
144    
145            //Something was selected and it was not the hSocket, so it must be some command(s) coming.
146            for (std::vector<yyparse_param_t>::iterator iter = Sessions.begin(); iter != Sessions.end(); iter++) {
147                    if (FD_ISSET((*iter).hSession, &selectSet)) {   //Was it this socket?
148                            if (GetLSCPCommand(iter)) {     //Have we read the entire command?
149                                    dmsg(3,("LSCPServer: Got command on socket %d, calling parser.\n", currentSocket));
150                                    yylex_init(&((*iter).pScanner)); //FIXME: should me moved out of this loop and initialized only when a new session is created
151                                    currentSocket = (*iter).hSession;  //a hack
152                                    if ((*iter).bVerbose) { // if echo mode enabled
153                                        AnswerClient(bufferedCommands[currentSocket]);
154                                    }
155                                    int result = yyparse(&(*iter));
156                                    currentSocket = -1;     //continuation of a hack
157                                    dmsg(3,("LSCPServer: Done parsing on socket %d.\n", currentSocket));
158                                    if (result == LSCP_QUIT) { //Was it a quit command by any chance?
159                                            CloseConnection(iter);
160                                    }
161                            }
162                            //socket may have been closed, iter may be invalid, get out of the loop for now.
163                            //we'll be back if there is data.
164                            break;
165                    }
166            }
167    
168            //Now let's deliver late notifies (if any)
169            NotifyBufferMutex.Lock();
170            for (std::map<int,String>::iterator iterNotify = bufferedNotifies.begin(); iterNotify != bufferedNotifies.end(); iterNotify++) {
171                    send(iterNotify->first, iterNotify->second.c_str(), iterNotify->second.size(), 0);
172                    bufferedNotifies.erase(iterNotify);
173            }
174            NotifyBufferMutex.Unlock();
175      }      }
176        //It will never get here anyway
177        //yylex_destroy(yyparse_param.pScanner);
178    }
179    
180    void LSCPServer::CloseConnection( std::vector<yyparse_param_t>::iterator iter ) {
181            int socket = (*iter).hSession;
182            dmsg(1,("LSCPServer: Client connection terminated on socket:%d.\n",socket));
183            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_misc, "Client connection terminated on socket", socket));
184            Sessions.erase(iter);
185            FD_CLR(socket,  &fdSet);
186            SubscriptionMutex.Lock(); //Must unsubscribe this socket from all events (if any)
187            for (std::map< LSCPEvent::event_t, std::list<int> >::iterator iter = eventSubscriptions.begin(); iter != eventSubscriptions.end(); iter++) {
188                    iter->second.remove(socket);
189            }
190            SubscriptionMutex.Unlock();
191            NotifyMutex.Lock();
192            bufferedCommands.erase(socket);
193            bufferedNotifies.erase(socket);
194            close(socket);
195            NotifyMutex.Unlock();
196            //yylex_destroy((*iter).pScanner);
197    }
198    
199    void LSCPServer::SendLSCPNotify( LSCPEvent event ) {
200            SubscriptionMutex.Lock();
201            if (eventSubscriptions.count(event.GetType()) == 0) {
202                    SubscriptionMutex.Unlock();     //Nobody is subscribed to this event
203                    return;
204            }
205            std::list<int>::iterator iter = eventSubscriptions[event.GetType()].begin();
206            std::list<int>::iterator end = eventSubscriptions[event.GetType()].end();
207            String notify = event.Produce();
208    
209            while (true) {
210                    if (NotifyMutex.Trylock()) {
211                            for(;iter != end; iter++)
212                                    send(*iter, notify.c_str(), notify.size(), 0);
213                            NotifyMutex.Unlock();
214                            break;
215                    } else {
216                            if (NotifyBufferMutex.Trylock()) {
217                                    for(;iter != end; iter++)
218                                            bufferedNotifies[*iter] += notify;
219                                    NotifyBufferMutex.Unlock();
220                                    break;
221                            }
222                    }
223            }
224            SubscriptionMutex.Unlock();
225    }
226    
227    extern int GetLSCPCommand( void *buf, int max_size ) {
228            String command = LSCPServer::bufferedCommands[LSCPServer::currentSocket];
229            if (command.size() == 0) {              //Parser wants input but we have nothing.
230                    strcpy((char*) buf, "\n");      //So give it an empty command
231                    return 1;                       //to keep it happy.
232            }
233    
234            if (max_size < command.size()) {
235                    std::cerr << "getLSCPCommand: Flex buffer too small, ignoring the command." << std::endl;
236                    return 0;       //This will never happen
237            }
238    
239            strcpy((char*) buf, command.c_str());
240            LSCPServer::bufferedCommands.erase(LSCPServer::currentSocket);
241            return command.size();
242    }
243    
244    /**
245     * Will be called to try to read the command from the socket
246     * If command is read, it will return true. Otherwise false is returned.
247     * In any case the received portion (complete or incomplete) is saved into bufferedCommand map.
248     */
249    bool LSCPServer::GetLSCPCommand( std::vector<yyparse_param_t>::iterator iter ) {
250            int socket = (*iter).hSession;
251            char c;
252            int i = 0;
253            while (true) {
254                    int result = recv(socket, (void *)&c, 1, 0); //Read one character at a time for now
255                    if (result == 0) { //socket was selected, so 0 here means client has closed the connection
256                            CloseConnection(iter);
257                            break;
258                    }
259                    if (result == 1) {
260                            if (c == '\r')
261                                    continue; //Ignore CR
262                            if (c == '\n') {
263                                    LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_misc, "Received \'" + bufferedCommands[socket] + "\' on socket", socket));
264                                    bufferedCommands[socket] += "\n";
265                                    return true; //Complete command was read
266                            }
267                            bufferedCommands[socket] += c;
268                    }
269                    if (result == -1) {
270                            if (errno == EAGAIN) //Would block, try again later.
271                                    return false;
272                            switch(errno) {
273                                    case EBADF:
274                                            dmsg(2,("LSCPScanner: The argument s is an invalid descriptor.\n"));
275                                            break;
276                                    case ECONNREFUSED:
277                                            dmsg(2,("LSCPScanner: A remote host refused to allow the network connection (typically because it is not running the requested service).\n"));
278                                            break;
279                                    case ENOTCONN:
280                                            dmsg(2,("LSCPScanner: The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2)).\n"));
281                                            break;
282                                    case ENOTSOCK:
283                                            dmsg(2,("LSCPScanner: The argument s does not refer to a socket.\n"));
284                                            break;
285                                    case EAGAIN:
286                                            dmsg(2,("LSCPScanner: The socket is marked non-blocking and the receive operation would block, or a receive timeout had been set and the timeout expired before data was received.\n"));
287                                            break;
288                                    case EINTR:
289                                            dmsg(2,("LSCPScanner: The receive was interrupted by delivery of a signal before any data were available.\n"));
290                                            break;
291                                    case EFAULT:
292                                            dmsg(2,("LSCPScanner: The receive buffer pointer(s) point outside the process's address space.\n"));
293                                            break;
294                                    case EINVAL:
295                                            dmsg(2,("LSCPScanner: Invalid argument passed.\n"));
296                                            break;
297                                    case ENOMEM:
298                                            dmsg(2,("LSCPScanner: Could not allocate memory for recvmsg.\n"));
299                                            break;
300                                    default:
301                                            dmsg(2,("LSCPScanner: Unknown recv() error.\n"));
302                                            break;
303                            }
304                            CloseConnection(iter);
305                            break;
306                    }
307            }
308            return false;
309  }  }
310    
311  /**  /**
# Line 80  int LSCPServer::Main() { Line 316  int LSCPServer::Main() {
316   */   */
317  void LSCPServer::AnswerClient(String ReturnMessage) {  void LSCPServer::AnswerClient(String ReturnMessage) {
318      dmsg(2,("LSCPServer::AnswerClient(ReturnMessage=%s)", ReturnMessage.c_str()));      dmsg(2,("LSCPServer::AnswerClient(ReturnMessage=%s)", ReturnMessage.c_str()));
319      send(hSession, ReturnMessage.c_str(), ReturnMessage.size(), 0);      if (currentSocket != -1) {
320                NotifyMutex.Lock();
321                send(currentSocket, ReturnMessage.c_str(), ReturnMessage.size(), 0);
322                NotifyMutex.Unlock();
323        }
324    }
325    
326    /**
327     * Find a created audio output device index.
328     */
329    int LSCPServer::GetAudioOutputDeviceIndex ( AudioOutputDevice *pDevice )
330    {
331        // Search for the created device to get its index
332        std::map<uint, AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
333        std::map<uint, AudioOutputDevice*>::iterator iter = devices.begin();
334        for (; iter != devices.end(); iter++) {
335            if (iter->second == pDevice)
336                return iter->first;
337        }
338        // Not found.
339        return -1;
340    }
341    
342    /**
343     * Find a created midi input device index.
344     */
345    int LSCPServer::GetMidiInputDeviceIndex ( MidiInputDevice *pDevice )
346    {
347        // Search for the created device to get its index
348        std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
349        std::map<uint, MidiInputDevice*>::iterator iter = devices.begin();
350        for (; iter != devices.end(); iter++) {
351            if (iter->second == pDevice)
352                return iter->first;
353        }
354        // Not found.
355        return -1;
356    }
357    
358    String LSCPServer::CreateAudioOutputDevice(String Driver, std::map<String,String> Parameters) {
359        dmsg(2,("LSCPServer: CreateAudioOutputDevice(Driver=%s)\n", Driver.c_str()));
360        LSCPResultSet result;
361        try {
362            AudioOutputDevice* pDevice = pSampler->CreateAudioOutputDevice(Driver, Parameters);
363            // search for the created device to get its index
364            int index = GetAudioOutputDeviceIndex(pDevice);
365            if (index == -1) throw LinuxSamplerException("Internal error: could not find created audio output device.");
366            result = index; // success
367        }
368        catch (LinuxSamplerException e) {
369            result.Error(e);
370        }
371        return result.Produce();
372    }
373    
374    String LSCPServer::CreateMidiInputDevice(String Driver, std::map<String,String> Parameters) {
375        dmsg(2,("LSCPServer: CreateMidiInputDevice(Driver=%s)\n", Driver.c_str()));
376        LSCPResultSet result;
377        try {
378            MidiInputDevice* pDevice = pSampler->CreateMidiInputDevice(Driver, Parameters);
379            // search for the created device to get its index
380            int index = GetMidiInputDeviceIndex(pDevice);
381            if (index == -1) throw LinuxSamplerException("Internal error: could not find created midi input device.");
382            result = index; // success
383        }
384        catch (LinuxSamplerException e) {
385            result.Error(e);
386        }
387        return result.Produce();
388    }
389    
390    String LSCPServer::DestroyAudioOutputDevice(uint DeviceIndex) {
391        dmsg(2,("LSCPServer: DestroyAudioOutputDevice(DeviceIndex=%d)\n", DeviceIndex));
392        LSCPResultSet result;
393        try {
394            std::map<uint, AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
395            if (!devices[DeviceIndex]) throw LinuxSamplerException("There is no audio output device with index " + ToString(DeviceIndex) + ".");
396            AudioOutputDevice* pDevice = devices[DeviceIndex];
397            pSampler->DestroyAudioOutputDevice(pDevice);
398        }
399        catch (LinuxSamplerException e) {
400            result.Error(e);
401        }
402        return result.Produce();
403    }
404    
405    String LSCPServer::DestroyMidiInputDevice(uint DeviceIndex) {
406        dmsg(2,("LSCPServer: DestroyMidiInputDevice(DeviceIndex=%d)\n", DeviceIndex));
407        LSCPResultSet result;
408        try {
409            std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
410            MidiInputDevice* pDevice = devices[DeviceIndex];
411            if (!pDevice) throw LinuxSamplerException("There is no audio output device with index " + ToString(DeviceIndex) + ".");
412            pSampler->DestroyMidiInputDevice(pDevice);
413        }
414        catch (LinuxSamplerException e) {
415            result.Error(e);
416        }
417        return result.Produce();
418  }  }
419    
420  /**  /**
421   * Will be called by the parser to load an instrument.   * Will be called by the parser to load an instrument.
422   */   */
423  String LSCPServer::LoadInstrument(String Filename, uint Instrument, uint SamplerChannel) {  String LSCPServer::LoadInstrument(String Filename, uint uiInstrument, uint uiSamplerChannel, bool bBackground) {
424      dmsg(2,("LSCPServer: LoadInstrument(Filename=%s,Instrument=%d,SamplerChannel=%d)\n", Filename.c_str(), Instrument, SamplerChannel));      dmsg(2,("LSCPServer: LoadInstrument(Filename=%s,Instrument=%d,SamplerChannel=%d)\n", Filename.c_str(), uiInstrument, uiSamplerChannel));
425      result_t res = pEngine->LoadInstrument(Filename.c_str(), Instrument);      LSCPResultSet result;
426      return ConvertResult(res);      try {
427            SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
428            if (!pSamplerChannel) throw LinuxSamplerException("Index out of bounds");
429            Engine* pEngine = pSamplerChannel->GetEngine();
430            if (!pEngine) throw LinuxSamplerException("No engine loaded on channel");
431            if (pSamplerChannel->GetAudioOutputDevice() == NULL)
432                throw LinuxSamplerException("No audio output device on channel");
433            if (bBackground) {
434                LSCPLoadInstrument *pLoadInstrument = new LSCPLoadInstrument(pEngine, Filename.c_str(), uiInstrument);
435                pLoadInstrument->StartThread();
436            }
437            else pEngine->LoadInstrument(Filename.c_str(), uiInstrument);
438        }
439        catch (LinuxSamplerException e) {
440             result.Error(e);
441        }
442        return result.Produce();
443  }  }
444    
445  /**  /**
446   * Will be called by the parser to load and deploy an engine.   * Will be called by the parser to load and deploy an engine.
447   */   */
448  String LSCPServer::LoadEngine(String EngineName, uint SamplerChannel) {  String LSCPServer::LoadEngine(String EngineName, uint uiSamplerChannel) {
449      dmsg(2,("LSCPServer: LoadEngine(EngineName=%s,SamplerChannel=%d)\n", EngineName.c_str(), SamplerChannel));      dmsg(2,("LSCPServer: LoadEngine(EngineName=%s,SamplerChannel=%d)\n", EngineName.c_str(), uiSamplerChannel));
450      return "ERR:0:Not implemented yet.\r\n";      LSCPResultSet result;
451        try {
452            Engine::type_t type;
453            if ((EngineName == "GigEngine") || (EngineName == "gig")) type = Engine::type_gig;
454            else throw LinuxSamplerException("Unknown engine type");
455            SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
456            if (!pSamplerChannel) throw LinuxSamplerException("Index out of bounds");
457            pSamplerChannel->LoadEngine(type);
458        }
459        catch (LinuxSamplerException e) {
460             result.Error(e);
461        }
462        return result.Produce();
463  }  }
464    
465  /**  /**
# Line 105  String LSCPServer::LoadEngine(String Eng Line 467  String LSCPServer::LoadEngine(String Eng
467   */   */
468  String LSCPServer::GetChannels() {  String LSCPServer::GetChannels() {
469      dmsg(2,("LSCPServer: GetChannels()\n"));      dmsg(2,("LSCPServer: GetChannels()\n"));
470      return "1\r\n";      LSCPResultSet result;
471        result.Add(pSampler->SamplerChannels());
472        return result.Produce();
473    }
474    
475    /**
476     * Will be called by the parser to get the list of sampler channels.
477     */
478    String LSCPServer::ListChannels() {
479        dmsg(2,("LSCPServer: ListChannels()\n"));
480        String list;
481        std::map<uint,SamplerChannel*> channels = pSampler->GetSamplerChannels();
482        std::map<uint,SamplerChannel*>::iterator iter = channels.begin();
483        for (; iter != channels.end(); iter++) {
484            if (list != "") list += ",";
485            list += ToString(iter->first);
486        }
487        LSCPResultSet result;
488        result.Add(list);
489        return result.Produce();
490  }  }
491    
492  /**  /**
# Line 113  String LSCPServer::GetChannels() { Line 494  String LSCPServer::GetChannels() {
494   */   */
495  String LSCPServer::AddChannel() {  String LSCPServer::AddChannel() {
496      dmsg(2,("LSCPServer: AddChannel()\n"));      dmsg(2,("LSCPServer: AddChannel()\n"));
497      return "ERR:0:Not implemented yet.\r\n";      SamplerChannel* pSamplerChannel = pSampler->AddSamplerChannel();
498        LSCPResultSet result(pSamplerChannel->Index());
499        return result.Produce();
500  }  }
501    
502  /**  /**
503   * Will be called by the parser to remove a sampler channel.   * Will be called by the parser to remove a sampler channel.
504   */   */
505  String LSCPServer::RemoveChannel(uint SamplerChannel) {  String LSCPServer::RemoveChannel(uint uiSamplerChannel) {
506      dmsg(2,("LSCPServer: RemoveChannel(SamplerChannel=%d)\n", SamplerChannel));      dmsg(2,("LSCPServer: RemoveChannel(SamplerChannel=%d)\n", uiSamplerChannel));
507      return "ERR:0:Not implemented yet.\r\n";      LSCPResultSet result;
508        pSampler->RemoveSamplerChannel(uiSamplerChannel);
509        return result.Produce();
510  }  }
511    
512  /**  /**
# Line 129  String LSCPServer::RemoveChannel(uint Sa Line 514  String LSCPServer::RemoveChannel(uint Sa
514   */   */
515  String LSCPServer::GetAvailableEngines() {  String LSCPServer::GetAvailableEngines() {
516      dmsg(2,("LSCPServer: GetAvailableEngines()\n"));      dmsg(2,("LSCPServer: GetAvailableEngines()\n"));
517      return "ERR:0:Not implemented yet.\r\n";      LSCPResultSet result("GigEngine");
518        return result.Produce();
519  }  }
520    
521  /**  /**
# Line 137  String LSCPServer::GetAvailableEngines() Line 523  String LSCPServer::GetAvailableEngines()
523   */   */
524  String LSCPServer::GetEngineInfo(String EngineName) {  String LSCPServer::GetEngineInfo(String EngineName) {
525      dmsg(2,("LSCPServer: GetEngineInfo(EngineName=%s)\n", EngineName.c_str()));      dmsg(2,("LSCPServer: GetEngineInfo(EngineName=%s)\n", EngineName.c_str()));
526      return "ERR:0:Not implemented yet.\r\n";      LSCPResultSet result;
527        try {
528            if ((EngineName == "GigEngine") || (EngineName == "gig")) {
529                Engine* pEngine = new LinuxSampler::gig::Engine;
530                result.Add(pEngine->Description());
531                result.Add(pEngine->Version());
532                delete pEngine;
533            }
534            else throw LinuxSamplerException("Unknown engine type");
535        }
536        catch (LinuxSamplerException e) {
537             result.Error(e);
538        }
539        return result.Produce();
540  }  }
541    
542  /**  /**
543   * Will be called by the parser to get informations about a particular   * Will be called by the parser to get informations about a particular
544   * sampler channel.   * sampler channel.
545   */   */
546  String LSCPServer::GetChannelInfo(uint SamplerChannel) {  String LSCPServer::GetChannelInfo(uint uiSamplerChannel) {
547      dmsg(2,("LSCPServer: GetChannelInfo(SamplerChannel=%d)\n", SamplerChannel));      dmsg(2,("LSCPServer: GetChannelInfo(SamplerChannel=%d)\n", uiSamplerChannel));
548      return "ERR:0:Not implemented yet.\r\n";      LSCPResultSet result;
549        try {
550            SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
551            if (!pSamplerChannel) throw LinuxSamplerException("Index out of bounds");
552            Engine* pEngine = pSamplerChannel->GetEngine();
553    
554            //Defaults values
555            String EngineName = "NONE";
556            float Volume = 0;
557            String InstrumentFileName = "NONE";
558            int InstrumentIndex = -1;
559            int InstrumentStatus = -1;
560    
561            if (pEngine) {
562                EngineName =  pEngine->EngineName();
563                Volume = pEngine->Volume();
564                InstrumentStatus = pEngine->InstrumentStatus();
565                InstrumentIndex = pEngine->InstrumentIndex();
566                if (InstrumentIndex != -1)
567                    InstrumentFileName = pEngine->InstrumentFileName();
568            }
569    
570            result.Add("ENGINE_NAME", EngineName);
571            result.Add("VOLUME", Volume);
572    
573            //Some not-so-hardcoded stuff to make GUI look good
574            result.Add("AUDIO_OUTPUT_DEVICE", GetAudioOutputDeviceIndex(pSamplerChannel->GetAudioOutputDevice()));
575            result.Add("AUDIO_OUTPUT_CHANNELS", "2");
576            result.Add("AUDIO_OUTPUT_ROUTING", "0,1");
577    
578            result.Add("MIDI_INPUT_DEVICE", GetMidiInputDeviceIndex(pSamplerChannel->GetMidiInputDevice()));
579            result.Add("MIDI_INPUT_PORT", pSamplerChannel->GetMidiInputPort());
580            result.Add("MIDI_INPUT_CHANNEL", pSamplerChannel->GetMidiInputChannel());
581    
582            result.Add("INSTRUMENT_FILE", InstrumentFileName);
583            result.Add("INSTRUMENT_NR", InstrumentIndex);
584            result.Add("INSTRUMENT_STATUS", InstrumentStatus);
585        }
586        catch (LinuxSamplerException e) {
587             result.Error(e);
588        }
589        return result.Produce();
590  }  }
591    
592  /**  /**
593   * Will be called by the parser to get the amount of active voices on a   * Will be called by the parser to get the amount of active voices on a
594   * particular sampler channel.   * particular sampler channel.
595   */   */
596  String LSCPServer::GetVoiceCount(uint SamplerChannel) {  String LSCPServer::GetVoiceCount(uint uiSamplerChannel) {
597      dmsg(2,("LSCPServer: GetVoiceCount(SamplerChannel=%d)\n", SamplerChannel));      dmsg(2,("LSCPServer: GetVoiceCount(SamplerChannel=%d)\n", uiSamplerChannel));
598      return ToString(pEngine->ActiveVoiceCount) + "\r\n";      LSCPResultSet result;
599        try {
600            SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
601            if (!pSamplerChannel) throw LinuxSamplerException("Index out of bounds");
602            Engine* pEngine = pSamplerChannel->GetEngine();
603            if (!pEngine) throw LinuxSamplerException("No engine loaded on channel");
604            result.Add(pEngine->VoiceCount());
605        }
606        catch (LinuxSamplerException e) {
607             result.Error(e);
608        }
609        return result.Produce();
610  }  }
611    
612  /**  /**
613   * Will be called by the parser to get the amount of active disk streams on a   * Will be called by the parser to get the amount of active disk streams on a
614   * particular sampler channel.   * particular sampler channel.
615   */   */
616  String LSCPServer::GetStreamCount(uint SamplerChannel) {  String LSCPServer::GetStreamCount(uint uiSamplerChannel) {
617      dmsg(2,("LSCPServer: GetStreamCount(SamplerChannel=%d)\n", SamplerChannel));      dmsg(2,("LSCPServer: GetStreamCount(SamplerChannel=%d)\n", uiSamplerChannel));
618      return ToString(pEngine->pDiskThread->ActiveStreamCount) + "\r\n";      LSCPResultSet result;
619        try {
620            SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
621            if (!pSamplerChannel) throw LinuxSamplerException("Index out of bounds");
622            Engine* pEngine = pSamplerChannel->GetEngine();
623            if (!pEngine) throw LinuxSamplerException("No engine loaded on channel");
624            result.Add(pEngine->DiskStreamCount());
625        }
626        catch (LinuxSamplerException e) {
627             result.Error(e);
628        }
629        return result.Produce();
630  }  }
631    
632  /**  /**
633   * Will be called by the parser to get the buffer fill states of all disk   * Will be called by the parser to get the buffer fill states of all disk
634   * streams on a particular sampler channel.   * streams on a particular sampler channel.
635   */   */
636  String LSCPServer::GetBufferFill(fill_response_t ResponseType, uint SamplerChannel) {  String LSCPServer::GetBufferFill(fill_response_t ResponseType, uint uiSamplerChannel) {
637      dmsg(2,("LSCPServer: GetBufferFill(ResponseType=%d, SamplerChannel=%d)\n", ResponseType, SamplerChannel));      dmsg(2,("LSCPServer: GetBufferFill(ResponseType=%d, SamplerChannel=%d)\n", ResponseType, uiSamplerChannel));
638      return (ResponseType == fill_response_bytes) ? pEngine->pDiskThread->GetBufferFillBytes() + "\r\n"      LSCPResultSet result;
639                                                   : pEngine->pDiskThread->GetBufferFillPercentage() + "\r\n";      try {
640            SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
641            if (!pSamplerChannel) throw LinuxSamplerException("Index out of bounds");
642            Engine* pEngine = pSamplerChannel->GetEngine();
643            if (!pEngine) throw LinuxSamplerException("No engine loaded on channel");
644            if (!pEngine->DiskStreamSupported())
645                result.Add("NA");
646            else {
647                switch (ResponseType) {
648                    case fill_response_bytes:
649                        result.Add(pEngine->DiskStreamBufferFillBytes());
650                        break;
651                    case fill_response_percentage:
652                        result.Add(pEngine->DiskStreamBufferFillPercentage());
653                        break;
654                    default:
655                        throw LinuxSamplerException("Unknown fill response type");
656                }
657            }
658        }
659        catch (LinuxSamplerException e) {
660             result.Error(e);
661        }
662        return result.Produce();
663  }  }
664    
665  /**  String LSCPServer::GetAvailableAudioOutputDrivers() {
666   * Will be called by the parser to change the audio output type on a      dmsg(2,("LSCPServer: GetAvailableAudioOutputDrivers()\n"));
667   * particular sampler channel.      LSCPResultSet result;
668   */      try {
669  String LSCPServer::SetAudioOutputType(audio_output_type_t AudioOutputType, uint SamplerChannel) {          String s = AudioOutputDeviceFactory::AvailableDriversAsString();
670      dmsg(2,("LSCPServer: SetAudioOutputType(AudioOutputType=%d, SamplerChannel=%d)\n", AudioOutputType, SamplerChannel));          result.Add(s);
671      return "ERR:0:Not implemented yet.\r\n";      }
672        catch (LinuxSamplerException e) {
673            result.Error(e);
674        }
675        return result.Produce();
676    }
677    
678    String LSCPServer::GetAvailableMidiInputDrivers() {
679        dmsg(2,("LSCPServer: GetAvailableMidiInputDrivers()\n"));
680        LSCPResultSet result;
681        try {
682            String s = MidiInputDeviceFactory::AvailableDriversAsString();
683            result.Add(s);
684        }
685        catch (LinuxSamplerException e) {
686            result.Error(e);
687        }
688        return result.Produce();
689    }
690    
691    String LSCPServer::GetMidiInputDriverInfo(String Driver) {
692        dmsg(2,("LSCPServer: GetMidiInputDriverInfo(Driver=%s)\n",Driver.c_str()));
693        LSCPResultSet result;
694        try {
695            result.Add("DESCRIPTION", MidiInputDeviceFactory::GetDriverDescription(Driver));
696            result.Add("VERSION",     MidiInputDeviceFactory::GetDriverVersion(Driver));
697    
698            std::map<String,DeviceCreationParameter*> parameters = MidiInputDeviceFactory::GetAvailableDriverParameters(Driver);
699            if (parameters.size()) { // if there are parameters defined for this driver
700                String s;
701                std::map<String,DeviceCreationParameter*>::iterator iter = parameters.begin();
702                for (;iter != parameters.end(); iter++) {
703                    if (s != "") s += ",";
704                    s += iter->first;
705                }
706                result.Add("PARAMETERS", s);
707            }
708        }
709        catch (LinuxSamplerException e) {
710            result.Error(e);
711        }
712        return result.Produce();
713    }
714    
715    String LSCPServer::GetAudioOutputDriverInfo(String Driver) {
716        dmsg(2,("LSCPServer: GetAudioOutputDriverInfo(Driver=%s)\n",Driver.c_str()));
717        LSCPResultSet result;
718        try {
719            result.Add("DESCRIPTION", AudioOutputDeviceFactory::GetDriverDescription(Driver));
720            result.Add("VERSION",     AudioOutputDeviceFactory::GetDriverVersion(Driver));
721    
722            std::map<String,DeviceCreationParameter*> parameters = AudioOutputDeviceFactory::GetAvailableDriverParameters(Driver);
723            if (parameters.size()) { // if there are parameters defined for this driver
724                String s;
725                std::map<String,DeviceCreationParameter*>::iterator iter = parameters.begin();
726                for (;iter != parameters.end(); iter++) {
727                    if (s != "") s += ",";
728                    s += iter->first;
729                }
730                result.Add("PARAMETERS", s);
731            }
732        }
733        catch (LinuxSamplerException e) {
734            result.Error(e);
735        }
736        return result.Produce();
737    }
738    
739    String LSCPServer::GetMidiInputDriverParameterInfo(String Driver, String Parameter, std::map<String,String> DependencyList) {
740        dmsg(2,("LSCPServer: GetMidiInputDriverParameterInfo(Driver=%s,Parameter=%s)\n",Driver.c_str(),Parameter.c_str()));
741        LSCPResultSet result;
742        try {
743            DeviceCreationParameter* pParameter = MidiInputDeviceFactory::GetDriverParameter(Driver, Parameter);
744            result.Add("TYPE",         pParameter->Type());
745            result.Add("DESCRIPTION",  pParameter->Description());
746            result.Add("MANDATORY",    pParameter->Mandatory());
747            result.Add("FIX",          pParameter->Fix());
748            result.Add("MULTIPLICITY", pParameter->Multiplicity());
749            if (pParameter->Depends())       result.Add("DEPENDS",       pParameter->Depends());
750            if (pParameter->Default())       result.Add("DEFAULT",       pParameter->Default());
751            if (pParameter->RangeMin())      result.Add("RANGE_MIN",     pParameter->RangeMin());
752            if (pParameter->RangeMax())      result.Add("RANGE_MAX",     pParameter->RangeMax());
753            if (pParameter->Possibilities()) result.Add("POSSIBILITIES", pParameter->Possibilities());
754        }
755        catch (LinuxSamplerException e) {
756            result.Error(e);
757        }
758        return result.Produce();
759    }
760    
761    String LSCPServer::GetAudioOutputDriverParameterInfo(String Driver, String Parameter, std::map<String,String> DependencyList) {
762        dmsg(2,("LSCPServer: GetAudioOutputDriverParameterInfo(Driver=%s,Parameter=%s)\n",Driver.c_str(),Parameter.c_str()));
763        LSCPResultSet result;
764        try {
765            DeviceCreationParameter* pParameter = AudioOutputDeviceFactory::GetDriverParameter(Driver, Parameter);
766            result.Add("TYPE",         pParameter->Type());
767            result.Add("DESCRIPTION",  pParameter->Description());
768            result.Add("MANDATORY",    pParameter->Mandatory());
769            result.Add("FIX",          pParameter->Fix());
770            result.Add("MULTIPLICITY", pParameter->Multiplicity());
771            if (pParameter->Depends())       result.Add("DEPENDS",       pParameter->Depends());
772            if (pParameter->Default())       result.Add("DEFAULT",       pParameter->Default());
773            if (pParameter->RangeMin())      result.Add("RANGE_MIN",     pParameter->RangeMin());
774            if (pParameter->RangeMax())      result.Add("RANGE_MAX",     pParameter->RangeMax());
775            if (pParameter->Possibilities()) result.Add("POSSIBILITIES", pParameter->Possibilities());
776        }
777        catch (LinuxSamplerException e) {
778            result.Error(e);
779        }
780        return result.Produce();
781    }
782    
783    String LSCPServer::GetAudioOutputDeviceCount() {
784        dmsg(2,("LSCPServer: GetAudioOutputDeviceCount()\n"));
785        LSCPResultSet result;
786        try {
787            uint count = pSampler->AudioOutputDevices();
788            result.Add(count); // success
789        }
790        catch (LinuxSamplerException e) {
791            result.Error(e);
792        }
793        return result.Produce();
794    }
795    
796    String LSCPServer::GetMidiInputDeviceCount() {
797        dmsg(2,("LSCPServer: GetMidiInputDeviceCount()\n"));
798        LSCPResultSet result;
799        try {
800            uint count = pSampler->MidiInputDevices();
801            result.Add(count); // success
802        }
803        catch (LinuxSamplerException e) {
804            result.Error(e);
805        }
806        return result.Produce();
807    }
808    
809    String LSCPServer::GetAudioOutputDevices() {
810        dmsg(2,("LSCPServer: GetAudioOutputDevices()\n"));
811        LSCPResultSet result;
812        try {
813            String s;
814            std::map<uint, AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
815            std::map<uint, AudioOutputDevice*>::iterator iter = devices.begin();
816            for (; iter != devices.end(); iter++) {
817                if (s != "") s += ",";
818                s += ToString(iter->first);
819            }
820            result.Add(s);
821        }
822        catch (LinuxSamplerException e) {
823            result.Error(e);
824        }
825        return result.Produce();
826    }
827    
828    String LSCPServer::GetMidiInputDevices() {
829        dmsg(2,("LSCPServer: GetMidiInputDevices()\n"));
830        LSCPResultSet result;
831        try {
832            String s;
833            std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
834            std::map<uint, MidiInputDevice*>::iterator iter = devices.begin();
835            for (; iter != devices.end(); iter++) {
836                if (s != "") s += ",";
837                s += ToString(iter->first);
838            }
839            result.Add(s);
840        }
841        catch (LinuxSamplerException e) {
842            result.Error(e);
843        }
844        return result.Produce();
845    }
846    
847    String LSCPServer::GetAudioOutputDeviceInfo(uint DeviceIndex) {
848        dmsg(2,("LSCPServer: GetAudioOutputDeviceInfo(DeviceIndex=%d)\n",DeviceIndex));
849        LSCPResultSet result;
850        try {
851            std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
852            if (!devices[DeviceIndex]) throw LinuxSamplerException("There is no audio output device with index " + ToString(DeviceIndex) + ".");
853            AudioOutputDevice* pDevice = devices[DeviceIndex];
854            result.Add("driver", pDevice->Driver());
855            std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();
856            std::map<String,DeviceCreationParameter*>::iterator iter = parameters.begin();
857            for (; iter != parameters.end(); iter++) {
858                result.Add(iter->first, iter->second->Value());
859            }
860        }
861        catch (LinuxSamplerException e) {
862            result.Error(e);
863        }
864        return result.Produce();
865    }
866    
867    String LSCPServer::GetMidiInputDeviceInfo(uint DeviceIndex) {
868        dmsg(2,("LSCPServer: GetMidiInputDeviceInfo(DeviceIndex=%d)\n",DeviceIndex));
869        LSCPResultSet result;
870        try {
871            std::map<uint,MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
872            MidiInputDevice* pDevice = devices[DeviceIndex];
873            if (!pDevice) throw LinuxSamplerException("There is no MIDI input device with index " + ToString(DeviceIndex) + ".");
874            result.Add("driver", pDevice->Driver());
875            std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();
876            std::map<String,DeviceCreationParameter*>::iterator iter = parameters.begin();
877            for (; iter != parameters.end(); iter++) {
878                result.Add(iter->first, iter->second->Value());
879            }
880        }
881        catch (LinuxSamplerException e) {
882            result.Error(e);
883        }
884        return result.Produce();
885    }
886    String LSCPServer::GetMidiInputPortInfo(uint DeviceIndex, uint PortIndex) {
887        dmsg(2,("LSCPServer: GetMidiInputPortInfo(DeviceIndex=%d, PortIndex=%d)\n",DeviceIndex, PortIndex));
888        LSCPResultSet result;
889        try {
890            std::map<uint,MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
891            MidiInputDevice* pDevice = devices[DeviceIndex];
892            if (!pDevice) throw LinuxSamplerException("There is no MIDI input device with index " + ToString(DeviceIndex) + ".");
893            MidiInputDevice::MidiInputPort* pMidiInputPort = pDevice->GetPort(PortIndex);
894            if (!pMidiInputPort) throw LinuxSamplerException("There is no MIDI input port with index " + ToString(PortIndex) + ".");
895            std::map<String,DeviceCreationParameter*> parameters = pMidiInputPort->DeviceParameters();
896            std::map<String,DeviceCreationParameter*>::iterator iter = parameters.begin();
897            for (; iter != parameters.end(); iter++) {
898                result.Add(iter->first, iter->second->Value());
899            }
900        }
901        catch (LinuxSamplerException e) {
902            result.Error(e);
903        }
904        return result.Produce();
905    }
906    
907    String LSCPServer::GetAudioOutputChannelInfo(uint DeviceId, uint ChannelId) {
908        dmsg(2,("LSCPServer: GetAudioOutputChannelInfo(DeviceId=%d,ChannelId)\n",DeviceId,ChannelId));
909        LSCPResultSet result;
910        try {
911            // get audio output device
912            std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
913            if (!devices[DeviceId]) throw LinuxSamplerException("There is no audio output device with index " + ToString(DeviceId) + ".");
914            AudioOutputDevice* pDevice = devices[DeviceId];
915    
916            // get audio channel
917            AudioChannel* pChannel = pDevice->Channel(ChannelId);
918            if (!pChannel) throw LinuxSamplerException("Audio ouotput device does not have channel " + ToString(ChannelId) + ".");
919    
920            // return the values of all audio channel parameters
921            std::map<String,DeviceRuntimeParameter*> parameters = pChannel->ChannelParameters();
922            std::map<String,DeviceRuntimeParameter*>::iterator iter = parameters.begin();
923            for (; iter != parameters.end(); iter++) {
924                result.Add(iter->first, iter->second->Value());
925            }
926        }
927        catch (LinuxSamplerException e) {
928            result.Error(e);
929        }
930        return result.Produce();
931    }
932    
933    String LSCPServer::GetMidiInputPortParameterInfo(uint DeviceId, uint PortId, String ParameterName) {
934        dmsg(2,("LSCPServer: GetMidiInputPortParameterInfo(DeviceId=%d,PortId=%d,ParameterName=%s)\n",DeviceId,PortId,ParameterName.c_str()));
935        LSCPResultSet result;
936        try {
937            // get audio output device
938            std::map<uint,MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
939            if (!devices[DeviceId]) throw LinuxSamplerException("There is no midi input device with index " + ToString(DeviceId) + ".");
940            MidiInputDevice* pDevice = devices[DeviceId];
941    
942            // get midi port
943            MidiInputDevice::MidiInputPort* pPort = pDevice->GetPort(PortId);
944            if (!pPort) throw LinuxSamplerException("Midi input device does not have port " + ToString(PortId) + ".");
945    
946            // get desired port parameter
947            std::map<String,DeviceCreationParameter*> parameters = pPort->DeviceParameters();
948            if (!parameters[ParameterName]) throw LinuxSamplerException("Midi port does not provice a parameters '" + ParameterName + "'.");
949            DeviceCreationParameter* pParameter = parameters[ParameterName];
950    
951            // return all fields of this audio channel parameter
952            result.Add("TYPE",         pParameter->Type());
953            result.Add("DESCRIPTION",  pParameter->Description());
954            result.Add("FIX",          pParameter->Fix());
955            result.Add("MULTIPLICITY", pParameter->Multiplicity());
956            if (pParameter->RangeMin())      result.Add("RANGE_MIN",     pParameter->RangeMin());
957            if (pParameter->RangeMax())      result.Add("RANGE_MAX",     pParameter->RangeMax());
958            if (pParameter->Possibilities()) result.Add("POSSIBILITIES", pParameter->Possibilities());
959        }
960        catch (LinuxSamplerException e) {
961            result.Error(e);
962        }
963        return result.Produce();
964    }
965    
966    String LSCPServer::GetAudioOutputChannelParameterInfo(uint DeviceId, uint ChannelId, String ParameterName) {
967        dmsg(2,("LSCPServer: GetAudioOutputChannelParameterInfo(DeviceId=%d,ChannelId=%d,ParameterName=%s)\n",DeviceId,ChannelId,ParameterName.c_str()));
968        LSCPResultSet result;
969        try {
970            // get audio output device
971            std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
972            if (!devices[DeviceId]) throw LinuxSamplerException("There is no audio output device with index " + ToString(DeviceId) + ".");
973            AudioOutputDevice* pDevice = devices[DeviceId];
974    
975            // get audio channel
976            AudioChannel* pChannel = pDevice->Channel(ChannelId);
977            if (!pChannel) throw LinuxSamplerException("Audio output device does not have channel " + ToString(ChannelId) + ".");
978    
979            // get desired audio channel parameter
980            std::map<String,DeviceRuntimeParameter*> parameters = pChannel->ChannelParameters();
981            if (!parameters[ParameterName]) throw LinuxSamplerException("Audio channel does not provide a parameter '" + ParameterName + "'.");
982            DeviceRuntimeParameter* pParameter = parameters[ParameterName];
983    
984            // return all fields of this audio channel parameter
985            result.Add("TYPE",         pParameter->Type());
986            result.Add("DESCRIPTION",  pParameter->Description());
987            result.Add("FIX",          pParameter->Fix());
988            result.Add("MULTIPLICITY", pParameter->Multiplicity());
989            if (pParameter->RangeMin())      result.Add("RANGE_MIN",     pParameter->RangeMin());
990            if (pParameter->RangeMax())      result.Add("RANGE_MAX",     pParameter->RangeMax());
991            if (pParameter->Possibilities()) result.Add("POSSIBILITIES", pParameter->Possibilities());
992        }
993        catch (LinuxSamplerException e) {
994            result.Error(e);
995        }
996        return result.Produce();
997    }
998    
999    String LSCPServer::SetAudioOutputChannelParameter(uint DeviceId, uint ChannelId, String ParamKey, String ParamVal) {
1000        dmsg(2,("LSCPServer: SetAudioOutputChannelParameter(DeviceId=%d,ChannelId=%d,ParamKey=%s,ParamVal=%s)\n",DeviceId,ChannelId,ParamKey.c_str(),ParamVal.c_str()));
1001        LSCPResultSet result;
1002        try {
1003            // get audio output device
1004            std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
1005            if (!devices[DeviceId]) throw LinuxSamplerException("There is no audio output device with index " + ToString(DeviceId) + ".");
1006            AudioOutputDevice* pDevice = devices[DeviceId];
1007    
1008            // get audio channel
1009            AudioChannel* pChannel = pDevice->Channel(ChannelId);
1010            if (!pChannel) throw LinuxSamplerException("Audio output device does not have channel " + ToString(ChannelId) + ".");
1011    
1012            // get desired audio channel parameter
1013            std::map<String,DeviceRuntimeParameter*> parameters = pChannel->ChannelParameters();
1014            if (!parameters[ParamKey]) throw LinuxSamplerException("Audio channel does not provide a parameter '" + ParamKey + "'.");
1015            DeviceRuntimeParameter* pParameter = parameters[ParamKey];
1016    
1017            // set new channel parameter value
1018            pParameter->SetValue(ParamVal);
1019        }
1020        catch (LinuxSamplerException e) {
1021            result.Error(e);
1022        }
1023        return result.Produce();
1024    }
1025    
1026    String LSCPServer::SetAudioOutputDeviceParameter(uint DeviceIndex, String ParamKey, String ParamVal) {
1027        dmsg(2,("LSCPServer: SetAudioOutputDeviceParameter(DeviceIndex=%d,ParamKey=%s,ParamVal=%s)\n",DeviceIndex,ParamKey.c_str(),ParamVal.c_str()));
1028        LSCPResultSet result;
1029        try {
1030            std::map<uint,AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
1031            if (!devices[DeviceIndex]) throw LinuxSamplerException("There is no audio output device with index " + ToString(DeviceIndex) + ".");
1032            AudioOutputDevice* pDevice = devices[DeviceIndex];
1033            std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();
1034            if (!parameters[ParamKey]) throw LinuxSamplerException("Audio output device " + ToString(DeviceIndex) + " does not have a device parameter '" + ParamKey + "'");
1035            parameters[ParamKey]->SetValue(ParamVal);
1036        }
1037        catch (LinuxSamplerException e) {
1038            result.Error(e);
1039        }
1040        return result.Produce();
1041    }
1042    
1043    String LSCPServer::SetMidiInputDeviceParameter(uint DeviceIndex, String ParamKey, String ParamVal) {
1044        dmsg(2,("LSCPServer: SetMidiOutputDeviceParameter(DeviceIndex=%d,ParamKey=%s,ParamVal=%s)\n",DeviceIndex,ParamKey.c_str(),ParamVal.c_str()));
1045        LSCPResultSet result;
1046        try {
1047            std::map<uint,MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
1048            if (!devices[DeviceIndex]) throw LinuxSamplerException("There is no MIDI input device with index " + ToString(DeviceIndex) + ".");
1049            MidiInputDevice* pDevice = devices[DeviceIndex];
1050            std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();
1051            if (!parameters[ParamKey]) throw LinuxSamplerException("MIDI input device " + ToString(DeviceIndex) + " does not have a device parameter '" + ParamKey + "'");
1052            parameters[ParamKey]->SetValue(ParamVal);
1053        }
1054        catch (LinuxSamplerException e) {
1055            result.Error(e);
1056        }
1057        return result.Produce();
1058    }
1059    
1060    String LSCPServer::SetMidiInputPortParameter(uint DeviceIndex, uint PortIndex, String ParamKey, String ParamVal) {
1061        dmsg(2,("LSCPServer: SetMidiOutputDeviceParameter(DeviceIndex=%d,ParamKey=%s,ParamVal=%s)\n",DeviceIndex,ParamKey.c_str(),ParamVal.c_str()));
1062        LSCPResultSet result;
1063        try {
1064            std::map<uint,MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
1065            MidiInputDevice* pDevice = devices[DeviceIndex];
1066            if (!pDevice) throw LinuxSamplerException("There is no MIDI input device with index " + ToString(DeviceIndex) + ".");
1067            MidiInputDevice::MidiInputPort* pMidiInputPort = pDevice->GetPort(PortIndex);
1068            if (!pMidiInputPort) throw LinuxSamplerException("There is no MIDI input port with index " + ToString(PortIndex) + ".");
1069            std::map<String,DeviceCreationParameter*> parameters = pMidiInputPort->DeviceParameters();
1070            if (!parameters[ParamKey]) throw LinuxSamplerException("MIDI input device " + ToString(PortIndex) + " does not have a parameter '" + ParamKey + "'");
1071            parameters[ParamKey]->SetValue(ParamVal);
1072        }
1073        catch (LinuxSamplerException e) {
1074            result.Error(e);
1075        }
1076        return result.Produce();
1077  }  }
1078    
1079  /**  /**
1080   * Will be called by the parser to change the audio output channel for   * Will be called by the parser to change the audio output channel for
1081   * playback on a particular sampler channel.   * playback on a particular sampler channel.
1082   */   */
1083  String LSCPServer::SetAudioOutputChannel(uint AudioOutputChannel, uint SamplerChannel) {  String LSCPServer::SetAudioOutputChannel(uint ChannelAudioOutputChannel, uint AudioOutputDeviceInputChannel, uint uiSamplerChannel) {
1084      dmsg(2,("LSCPServer: SetAudioOutputChannel(AudioOutputChannel=%d, SamplerChannel=%d)\n", AudioOutputChannel, SamplerChannel));      dmsg(2,("LSCPServer: SetAudioOutputChannel(ChannelAudioOutputChannel=%d, AudioOutputDeviceInputChannel=%d, SamplerChannel=%d)\n",ChannelAudioOutputChannel,AudioOutputDeviceInputChannel,uiSamplerChannel));
1085      return "ERR:0:Not implemented yet.\r\n";      return "ERR:0:Not implemented yet.\r\n"; //FIXME: Add support for this in resultset class?
1086  }  }
1087    
1088  /**  String LSCPServer::SetAudioOutputDevice(uint AudioDeviceId, uint uiSamplerChannel) {
1089   * Will be called by the parser to change the MIDI input port on which the      dmsg(2,("LSCPServer: SetAudiotOutputDevice(AudioDeviceId=%d, SamplerChannel=%d)\n",AudioDeviceId,uiSamplerChannel));
1090   * engine of a particular sampler channel should listen to.      LSCPResultSet result;
1091   */      try {
1092  String LSCPServer::SetMIDIInputPort(String MIDIInputPort, uint Samplerchannel) {          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1093      dmsg(2,("LSCPServer: SetMIDIInputPort(MIDIInputPort=%s, Samplerchannel=%d)\n", MIDIInputPort.c_str(), Samplerchannel));          if (!pSamplerChannel) throw LinuxSamplerException("Invalid channel number " + ToString(uiSamplerChannel));
1094      return "ERR:0:Not implemented yet.\r\n";          std::map<uint, AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
1095            AudioOutputDevice* pDevice = devices[AudioDeviceId];
1096            if (!pDevice) throw LinuxSamplerException("There is no audio output device with index " + ToString(AudioDeviceId));
1097            pSamplerChannel->SetAudioOutputDevice(pDevice);
1098        }
1099        catch (LinuxSamplerException e) {
1100             result.Error(e);
1101        }
1102        return result.Produce();
1103    }
1104    
1105    String LSCPServer::SetAudioOutputType(String AudioOutputDriver, uint uiSamplerChannel) {
1106        dmsg(2,("LSCPServer: SetAudioOutputType(String AudioOutputDriver=%s, SamplerChannel=%d)\n",AudioOutputDriver.c_str(),uiSamplerChannel));
1107        LSCPResultSet result;
1108        try {
1109            SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1110            if (!pSamplerChannel) throw LinuxSamplerException("Invalid channel number " + ToString(uiSamplerChannel));
1111            // Driver type name aliasing...
1112            if (AudioOutputDriver == "ALSA") AudioOutputDriver = "Alsa";
1113            if (AudioOutputDriver == "JACK") AudioOutputDriver = "Jack";
1114            // Check if there's one audio output device already created
1115            // for the intended audio driver type (AudioOutputDriver)...
1116            AudioOutputDevice *pDevice = NULL;
1117            std::map<uint, AudioOutputDevice*> devices = pSampler->GetAudioOutputDevices();
1118            std::map<uint, AudioOutputDevice*>::iterator iter = devices.begin();
1119            for (; iter != devices.end(); iter++) {
1120                if ((iter->second)->Driver() == AudioOutputDriver) {
1121                    pDevice = iter->second;
1122                    break;
1123                }
1124            }
1125            // If it doesn't exist, create a new one with default parameters...
1126            if (pDevice == NULL) {
1127                std::map<String,String> params;
1128                pDevice = pSampler->CreateAudioOutputDevice(AudioOutputDriver, params);
1129            }
1130            // Must have a device...
1131            if (pDevice == NULL)
1132                throw LinuxSamplerException("Internal error: could not create audio output device.");
1133            // Set it as the current channel device...
1134            pSamplerChannel->SetAudioOutputDevice(pDevice);
1135        }
1136        catch (LinuxSamplerException e) {
1137             result.Error(e);
1138        }
1139        return result.Produce();
1140    }
1141    
1142    String LSCPServer::SetMIDIInputPort(uint MIDIPort, uint uiSamplerChannel) {
1143        dmsg(2,("LSCPServer: SetMIDIInputPort(MIDIPort=%d, SamplerChannel=%d)\n",MIDIPort,uiSamplerChannel));
1144        LSCPResultSet result;
1145        try {
1146            SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1147            if (!pSamplerChannel) throw LinuxSamplerException("Invalid channel number " + ToString(uiSamplerChannel));
1148            pSamplerChannel->SetMidiInputPort(MIDIPort);
1149        }
1150        catch (LinuxSamplerException e) {
1151             result.Error(e);
1152        }
1153        return result.Produce();
1154    }
1155    
1156    String LSCPServer::SetMIDIInputChannel(uint MIDIChannel, uint uiSamplerChannel) {
1157        dmsg(2,("LSCPServer: SetMIDIInputChannel(MIDIChannel=%d, SamplerChannel=%d)\n",MIDIChannel,uiSamplerChannel));
1158        LSCPResultSet result;
1159        try {
1160            SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1161            if (!pSamplerChannel) throw LinuxSamplerException("Invalid channel number " + ToString(uiSamplerChannel));
1162            pSamplerChannel->SetMidiInputChannel((MidiInputDevice::MidiInputPort::midi_chan_t) MIDIChannel);
1163        }
1164        catch (LinuxSamplerException e) {
1165             result.Error(e);
1166        }
1167        return result.Produce();
1168    }
1169    
1170    String LSCPServer::SetMIDIInputDevice(uint MIDIDeviceId, uint uiSamplerChannel) {
1171        dmsg(2,("LSCPServer: SetMIDIInputDevice(MIDIDeviceId=%d, SamplerChannel=%d)\n",MIDIDeviceId,uiSamplerChannel));
1172        LSCPResultSet result;
1173        try {
1174            SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1175            if (!pSamplerChannel) throw LinuxSamplerException("Invalid channel number " + ToString(uiSamplerChannel));
1176            std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
1177            MidiInputDevice* pDevice = devices[MIDIDeviceId];
1178            if (!pDevice) throw LinuxSamplerException("There is no MIDI input device with index " + ToString(MIDIDeviceId));
1179            pSamplerChannel->SetMidiInputDevice(pDevice);
1180        }
1181        catch (LinuxSamplerException e) {
1182             result.Error(e);
1183        }
1184        return result.Produce();
1185    }
1186    
1187    String LSCPServer::SetMIDIInputType(String MidiInputDriver, uint uiSamplerChannel) {
1188        dmsg(2,("LSCPServer: SetMIDIInputType(String MidiInputDriver=%s, SamplerChannel=%d)\n",MidiInputDriver.c_str(),uiSamplerChannel));
1189        LSCPResultSet result;
1190        try {
1191            SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1192            if (!pSamplerChannel) throw LinuxSamplerException("Invalid channel number " + ToString(uiSamplerChannel));
1193            // Driver type name aliasing...
1194            if (MidiInputDriver == "ALSA") MidiInputDriver = "Alsa";
1195            // Check if there's one MIDI input device already created
1196            // for the intended MIDI driver type (MidiInputDriver)...
1197            MidiInputDevice *pDevice = NULL;
1198            std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices();
1199            std::map<uint, MidiInputDevice*>::iterator iter = devices.begin();
1200            for (; iter != devices.end(); iter++) {
1201                if ((iter->second)->Driver() == MidiInputDriver) {
1202                    pDevice = iter->second;
1203                    break;
1204                }
1205            }
1206            // If it doesn't exist, create a new one with default parameters...
1207            if (pDevice == NULL) {
1208                std::map<String,String> params;
1209                pDevice = pSampler->CreateMidiInputDevice(MidiInputDriver, params);
1210                // Make it with at least one initial port.
1211                std::map<String,DeviceCreationParameter*> parameters = pDevice->DeviceParameters();
1212                parameters["ports"]->SetValue("1");
1213            }
1214            // Must have a device...
1215            if (pDevice == NULL)
1216                throw LinuxSamplerException("Internal error: could not create MIDI input device.");
1217            // Set it as the current channel device...
1218            pSamplerChannel->SetMidiInputDevice(pDevice);
1219        }
1220        catch (LinuxSamplerException e) {
1221             result.Error(e);
1222        }
1223        return result.Produce();
1224  }  }
1225    
1226  /**  /**
1227   * Will be called by the parser to change the MIDI input channel on which the   * Will be called by the parser to change the MIDI input device, port and channel on which
1228   * engine of a particular sampler channel should listen to.   * engine of a particular sampler channel should listen to.
1229   */   */
1230  String LSCPServer::SetMIDIInputChannel(uint MIDIChannel, uint SamplerChannel) {  String LSCPServer::SetMIDIInput(uint MIDIDeviceId, uint MIDIPort, uint MIDIChannel, uint uiSamplerChannel) {
1231      dmsg(2,("LSCPServer: SetMIDIInputChannel(MIDIChannel=%d, SamplerChannel=%d)\n", MIDIChannel, SamplerChannel));      dmsg(2,("LSCPServer: SetMIDIInput(MIDIDeviceId=%d, MIDIPort=%d, MIDIChannel=%d, SamplerChannel=%d)\n", MIDIDeviceId, MIDIPort, MIDIChannel, uiSamplerChannel));
1232      return "ERR:0:Not implemented yet.\r\n";      LSCPResultSet result;
1233        try {
1234            SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1235            if (!pSamplerChannel) throw LinuxSamplerException("Invalid channel number " + ToString(uiSamplerChannel));
1236            std::map<uint, MidiInputDevice*> devices =  pSampler->GetMidiInputDevices();
1237            MidiInputDevice* pDevice = devices[MIDIDeviceId];
1238            if (!pDevice) throw LinuxSamplerException("There is no MIDI input device with index " + ToString(MIDIDeviceId));
1239            pSamplerChannel->SetMidiInput(pDevice, MIDIPort, (MidiInputDevice::MidiInputPort::midi_chan_t) MIDIChannel);
1240        }
1241        catch (LinuxSamplerException e) {
1242             result.Error(e);
1243        }
1244        return result.Produce();
1245  }  }
1246    
1247  /**  /**
1248   * Will be called by the parser to change the global volume factor on a   * Will be called by the parser to change the global volume factor on a
1249   * particular sampler channel.   * particular sampler channel.
1250   */   */
1251  String LSCPServer::SetVolume(double Volume, uint SamplerChannel) {  String LSCPServer::SetVolume(double Volume, uint uiSamplerChannel) {
1252      dmsg(2,("LSCPServer: SetVolume(Volume=%f, SamplerChannel=%d)\n", Volume, SamplerChannel));      dmsg(2,("LSCPServer: SetVolume(Volume=%f, SamplerChannel=%d)\n", Volume, uiSamplerChannel));
1253      pEngine->Volume = Volume;      LSCPResultSet result;
1254      return "OK\r\n";      try {
1255            SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1256            if (!pSamplerChannel) throw LinuxSamplerException("Index out of bounds");
1257            Engine* pEngine = pSamplerChannel->GetEngine();
1258            if (!pEngine) throw LinuxSamplerException("No engine loaded on channel");
1259            pEngine->Volume(Volume);
1260        }
1261        catch (LinuxSamplerException e) {
1262             result.Error(e);
1263        }
1264        return result.Produce();
1265  }  }
1266    
1267  /**  /**
1268   * Will be called by the parser to reset a particular sampler channel.   * Will be called by the parser to reset a particular sampler channel.
1269   */   */
1270  String LSCPServer::ResetChannel(uint SamplerChannel) {  String LSCPServer::ResetChannel(uint uiSamplerChannel) {
1271      dmsg(2,("LSCPServer: ResetChannel(SamplerChannel=%d)\n", SamplerChannel));      dmsg(2,("LSCPServer: ResetChannel(SamplerChannel=%d)\n", uiSamplerChannel));
1272      pEngine->Reset();      LSCPResultSet result;
1273      return "OK\r\n";      try {
1274            SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel);
1275            if (!pSamplerChannel) throw LinuxSamplerException("Index out of bounds");
1276            Engine* pEngine = pSamplerChannel->GetEngine();
1277            if (!pEngine) throw LinuxSamplerException("No engine loaded on channel");
1278            pEngine->Reset();
1279        }
1280        catch (LinuxSamplerException e) {
1281             result.Error(e);
1282        }
1283        return result.Produce();
1284  }  }
1285    
1286  /**  /**
1287   * 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
1288   * server for receiving event messages.   * server for receiving event messages.
1289   */   */
1290  String LSCPServer::SubscribeNotification(uint UDPPort) {  String LSCPServer::SubscribeNotification(LSCPEvent::event_t type) {
1291      dmsg(2,("LSCPServer: SubscribeNotification(UDPPort=%d)\n", UDPPort));      dmsg(2,("LSCPServer: SubscribeNotification(Event=%s)\n", LSCPEvent::Name(type).c_str()));
1292      return "ERR:0:Not implemented yet.\r\n";      LSCPResultSet result;
1293        SubscriptionMutex.Lock();
1294        eventSubscriptions[type].push_back(currentSocket);
1295        SubscriptionMutex.Unlock();
1296        return result.Produce();
1297  }  }
1298    
1299  /**  /**
1300   * Will be called by the parser to unsubscribe a client on the server   * Will be called by the parser to unsubscribe a client on the server
1301   * for not receiving further event messages.   * for not receiving further event messages.
1302   */   */
1303  String LSCPServer::UnsubscribeNotification(String SessionID) {  String LSCPServer::UnsubscribeNotification(LSCPEvent::event_t type) {
1304      dmsg(2,("LSCPServer: UnsubscribeNotification(SessionID=%s)\n", SessionID.c_str()));      dmsg(2,("LSCPServer: UnsubscribeNotification(Event=%s)\n", LSCPEvent::Name(type).c_str()));
1305      return "ERR:0:Not implemented yet.\r\n";      LSCPResultSet result;
1306        SubscriptionMutex.Lock();
1307        eventSubscriptions[type].remove(currentSocket);
1308        SubscriptionMutex.Unlock();
1309        return result.Produce();
1310    }
1311    
1312    /**
1313     * Will be called by the parser to enable or disable echo mode; if echo
1314     * mode is enabled, all commands from the client will (immediately) be
1315     * echoed back to the client.
1316     */
1317    String LSCPServer::SetEcho(yyparse_param_t* pSession, double boolean_value) {
1318        dmsg(2,("LSCPServer: SetEcho(val=%f)\n", boolean_value));
1319        LSCPResultSet result;
1320        try {
1321            if      (boolean_value == 0) pSession->bVerbose = false;
1322            else if (boolean_value == 1) pSession->bVerbose = true;
1323            else throw LinuxSamplerException("Not a boolean value, must either be 0 or 1");
1324        }
1325        catch (LinuxSamplerException e) {
1326             result.Error(e);
1327        }
1328        return result.Produce();
1329    }
1330    
1331    // Instrument loader constructor.
1332    LSCPLoadInstrument::LSCPLoadInstrument(Engine* pEngine, String Filename, uint uiInstrument)
1333        : Thread(false, 0, -4)
1334    {
1335        this->pEngine = pEngine;
1336        this->Filename = Filename;
1337        this->uiInstrument = uiInstrument;
1338    }
1339    
1340    // Instrument loader process.
1341    int LSCPLoadInstrument::Main()
1342    {
1343        try {
1344            pEngine->LoadInstrument(Filename.c_str(), uiInstrument);
1345        }
1346    
1347        catch (LinuxSamplerException e) {
1348            e.PrintMessage();
1349        }
1350    
1351        // Always re-enable the engine.
1352        pEngine->Enable();
1353    
1354        // FIXME: Shoot ourselves on the foot?
1355        delete this;
1356  }  }

Legend:
Removed from v.35  
changed lines
  Added in v.211

  ViewVC Help
Powered by ViewVC