/[svn]/jlscp/trunk/src/org/linuxsampler/lscp/Client.java
ViewVC logotype

Annotation of /jlscp/trunk/src/org/linuxsampler/lscp/Client.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1539 - (hide annotations) (download)
Mon Dec 3 22:59:39 2007 UTC (16 years, 4 months ago) by iliev
File size: 174769 byte(s)
* Added new interface - Instrument
* Client: added new methods - getFileInstrumentCount,
  getFileInstrumentInfo,  getFileInstruments

1 iliev 596 /*
2     * jlscp - a java LinuxSampler control protocol API
3     *
4 iliev 1139 * Copyright (C) 2005-2007 Grigor Iliev <grigor@grigoriliev.com>
5 iliev 596 *
6     * This file is part of jlscp.
7     *
8     * jlscp is free software; you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License version 2
10     * as published by the Free Software Foundation.
11     *
12     * jlscp is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with jlscp; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20     * MA 02111-1307 USA
21     */
22    
23     package org.linuxsampler.lscp;
24    
25     import java.io.IOException;
26 iliev 1139 import java.io.OutputStream;
27 iliev 596
28     import java.net.InetSocketAddress;
29     import java.net.Socket;
30     import java.net.SocketTimeoutException;
31     import java.net.UnknownHostException;
32    
33     import java.util.Vector;
34     import java.util.logging.Level;
35     import java.util.logging.Logger;
36    
37     import org.linuxsampler.lscp.event.*;
38    
39 iliev 1351 import static org.linuxsampler.lscp.Parser.*;
40 iliev 596
41 iliev 1351
42 iliev 596 /**
43     * This class is the abstraction representing a client endpoint for communication with LinuxSampler
44 iliev 1139 * instance. Since it implements all commands specified in the LSCP protocol v1.1, for more
45 iliev 671 * information look at the
46 iliev 1139 * <a href=http://www.linuxsampler.org/api/lscp-1.1.html>LSCP</a> specification.
47 iliev 596 *
48     * <p> The following code establishes connection to LinuxSampler instance and gets the
49     * LinuxSampler version:
50     * <pre>
51     * try {
52     * Client client = new Client();
53     * client.connect();
54     *
55     * String version = client.getServerInfo().getVersion();
56     * System.out.println(version);
57     *
58     * client.disconnect();
59     * } catch(Exception x) { x.printStackTrace(); }
60     * </pre>
61     * </p>
62     *
63     * <p>For more examples look at the <code>examples</code> directory
64     * located in the <b>jlscp</b> distribution.</p>
65     *
66     * All methods are thread safe.
67     * @author Grigor Iliev
68     */
69     public class Client {
70     private String address;
71     private int port;
72     private Socket sock = null;
73 iliev 1202 private int soTimeout = 20000;
74 iliev 596
75     private LscpInputStream in = null;
76     private LscpOutputStream out = null;
77    
78     private EventThread eventThread;
79    
80 iliev 1139 private boolean printOnlyMode = false;
81    
82 iliev 596 class EventThread extends Thread {
83 iliev 1202 private Vector<String> queue = new Vector<String>();
84 iliev 596 private boolean terminate = false;
85    
86     EventThread() { super("LSCP-Event-Thread"); }
87    
88     public void
89     run() {
90     while(!mustTerminate()) {
91 iliev 1202 try {
92     processQueue();
93     processNotifications();
94     } catch(Exception x) {
95 iliev 596 getLogger().log(Level.FINE, x.getMessage(), x);
96     }
97     try { synchronized(this) { wait(100); } }
98     catch(Exception x) {
99     getLogger().log(Level.FINE, x.getMessage(), x);
100     }
101     }
102     }
103    
104     private synchronized boolean
105     mustTerminate() { return terminate; }
106    
107     public synchronized void
108     terminate() {
109     terminate = true;
110     this.notifyAll();
111     }
112 iliev 1202
113     public synchronized void
114     scheduleNotification(String s) { queue.add(s); }
115    
116     private void
117     processQueue() {
118     String[] notifications = popAllNotifications();
119     for(String n : notifications) fireEvent(n);
120     }
121    
122     private synchronized String[]
123     popAllNotifications() {
124     String[] notifications = queue.toArray(new String[queue.size()]);
125     queue.removeAllElements();
126     return notifications;
127     }
128 iliev 596 }
129    
130     /**
131     * Creates a new instance of Client with default server address and port.
132     * The default server address and port are 127.0.0.1:8888.
133     */
134     public
135     Client() { this("127.0.0.1"); }
136    
137     /**
138     * Creates a new instance of Client with the specified address and default port.
139     * The default port is 8888.
140     * @param address The address of linux sampler server.
141     */
142     public
143     Client(String address) { this(address, 8888); }
144    
145     /**
146     * Creates a new instance of Client with the specified address and port.
147     * @param address The address of the Linux Sampler.
148     * @param port The Linux Sampler port number.
149     */
150     public
151     Client(String address, int port) {
152     setServerAddress(address);
153     setServerPort(port);
154    
155     eventThread = new EventThread();
156     }
157    
158     /**
159 iliev 1139 * Creates a new instance of Client.
160     * @param printOnlyMode Determines whether the client will be in print-only mode.
161     */
162     public
163     Client(boolean printOnlyMode) {
164     if(printOnlyMode) setPrintOnlyMode(true);
165     }
166    
167     /**
168     * Determines whether the client is in print-only mode.
169     * Print-only mode means that the client will just print all
170     * LSCP commands to the specified output stream or to the standard output stream
171     * (<code>java.lang.System.out</code>) if no output stream is specified,
172     * without taking any further actions. Thus, in print-only mode all returned
173     * values by <code>Client</code>'s methods are meaningless and should be discarded.
174     * @return <code>true</code> if the client is in
175     * print-only mode, <code>false</code> otherwise.
176     * @see #setPrintOnlyModeOutputStream
177     */
178     public synchronized boolean
179     getPrintOnlyMode() { return printOnlyMode; }
180    
181     /**
182     * Sets the print-only mode. Note that in print-only mode all returned
183     * values by <code>Client</code>'s methods are meaningless and should be discarded.
184     * The default output stream in print-only mode is <code>java.lang.System.out</code>.
185     * @param b If <code>true</code> all LSCP commands will be sent
186     * to the specified output stream or to the standard output stream
187     * (<code>java.lang.System.out</code>) if no output stream is specified,
188     * and no further actions will be taken.
189     * @throws IllegalStateException If the client is connected.
190     * @see #setPrintOnlyModeOutputStream
191     */
192     public synchronized void
193     setPrintOnlyMode(boolean b) {
194     if(printOnlyMode == b) return;
195     if(isConnected()) throw new IllegalStateException();
196    
197     printOnlyMode = b;
198     if(b) out = new LscpOutputStream(System.out);
199     }
200    
201     /**
202     * Sets the output stream to be used in print-only mode.
203     * @param out The output stream to be used in print-only mode.
204     * @throws IllegalStateException If the client is not in print-only mode.
205     * @throws IllegalArgumentException if <code>out</code> is <code>null</code>.
206     * @see #setPrintOnlyMode
207     */
208     public synchronized void
209     setPrintOnlyModeOutputStream(OutputStream out) {
210     if(!getPrintOnlyMode()) throw new IllegalStateException("Not in print-only mode");
211     if(out == null) throw new IllegalArgumentException("out must be non-null");
212     this.out = new LscpOutputStream(out);
213     }
214    
215     /**
216 iliev 596 * Specifies the jlscp version.
217     * @return The jlscp version.
218     */
219     public static String
220 iliev 671 getClientVersion() {
221     return Package.getPackage("org.linuxsampler.lscp").getImplementationVersion();
222     }
223 iliev 596
224     /**
225     * Gets the Linux Sampler address.
226     * @return The Linux Sampler address.
227     */
228     public synchronized String
229     getServerAddress() { return address; }
230    
231     /**
232     * Sets the Linux Sampler address.
233     * @param address The Linux Sampler address.
234     * If <code>address</code> is <code>null</code> sets to default address - 127.0.0.1.
235     */
236     public synchronized void
237     setServerAddress(String address) {
238     this.address = (address == null ? "127.0.0.1" : address);
239     }
240    
241     /**
242     * Gets the Linux Sampler port number.
243     * @return The Linux Sampler port number.
244     */
245     public synchronized int
246     getServerPort() { return port; }
247    
248     /**
249     * Sets the Linux Sampler port number.
250     * @param port The Linux Sampler port number.
251     */
252     public synchronized void
253     setServerPort(int port) { this.port = port; }
254    
255     /**
256     * Connects to the LinuxSampler. If there is already established connection then
257     * the currently available connection is closed berfore connecting.
258     * @throws LscpException If timeout occurs or any other I/O exception.
259     */
260     public synchronized void
261     connect() throws LscpException {
262     if(sock != null) disconnect();
263 iliev 1139 if(getPrintOnlyMode()) return;
264 iliev 596
265     // Initializing LSCP event thread
266     if(eventThread.isAlive()) {
267     getLogger().warning("LSCP event thread already running!");
268     eventThread.terminate();
269     }
270    
271     if(eventThread.getState() != Thread.State.NEW) eventThread = new EventThread();
272     ///////
273    
274     InetSocketAddress sockAddr = null;
275    
276     try { sockAddr = new InetSocketAddress(address, port); }
277     catch(IllegalArgumentException x) {
278     String s = String.valueOf(port);
279     throw new LscpException(LscpI18n.getLogMsg("Client.invalidPort!", s), x);
280     }
281    
282     if(sockAddr.isUnresolved()) throw new LscpException (
283     LscpI18n.getLogMsg("Client.unknownHost!", address)
284     );
285    
286     try {
287     sock = new Socket();
288     sock.bind(null);
289     sock.connect(sockAddr, soTimeout);
290     sock.setSoTimeout(soTimeout);
291 iliev 784 sock.setTcpNoDelay(true);
292 iliev 596
293     in = new LscpInputStream(sock.getInputStream());
294     out = new LscpOutputStream(sock.getOutputStream());
295     } catch(SocketTimeoutException x) {
296     throw new LscpException(LscpI18n.getLogMsg("Client.conTimeout!"), x);
297     } catch(Exception x) {
298     throw new LscpException (
299     LscpI18n.getLogMsg("Client.connectionFailed!"), x
300     );
301     }
302    
303 iliev 671 String s = Package.getPackage("org.linuxsampler.lscp").getSpecificationVersion();
304     String s2, sv, sv2;
305    
306     try {
307     s2 = s.substring(0, s.indexOf('.'));
308     sv = getServerInfo().getProtocolVersion();
309     sv2 = sv.substring(0, sv.indexOf('.'));
310     } catch(Exception x) {
311     disconnect();
312    
313     throw new LscpException (
314     LscpI18n.getLogMsg("Client.connectionFailed!"), x
315     );
316     }
317    
318     if(!sv2.equals(s2)) {
319     disconnect();
320    
321     throw new LscpException (
322     LscpI18n.getLogMsg("Client.incompatibleLscpVersion!", sv)
323     );
324     }
325    
326     s2 = s.substring(s.indexOf('.'));
327     sv2 = sv.substring(sv.indexOf('.'));
328    
329     if(sv2.compareToIgnoreCase(s2) < 0) getLogger().info (
330     LscpI18n.getLogMsg("Client.incompatibleLscpMinVersion!", sv)
331     );
332    
333 iliev 596 if(hasSubscriptions()) eventThread.start();
334    
335     if(!llM.isEmpty()) subscribe("MISCELLANEOUS");
336 iliev 1139 if(!llAODC.isEmpty()) subscribe("AUDIO_OUTPUT_DEVICE_COUNT");
337     if(!llAODI.isEmpty()) subscribe("AUDIO_OUTPUT_DEVICE_INFO");
338     if(!llMIDC.isEmpty()) subscribe("MIDI_INPUT_DEVICE_COUNT");
339     if(!llMIDI.isEmpty()) subscribe("MIDI_INPUT_DEVICE_INFO");
340 iliev 596 if(!llBF.isEmpty()) subscribe("BUFFER_FILL");
341     if(!llCC.isEmpty()) subscribe("CHANNEL_COUNT");
342     if(!llCI.isEmpty()) subscribe("CHANNEL_INFO");
343 iliev 1139 if(!llFSC.isEmpty()) subscribe("FX_SEND_COUNT");
344     if(!llFSI.isEmpty()) subscribe("FX_SEND_INFO");
345 iliev 596 if(!llSC.isEmpty()) subscribe("STREAM_COUNT");
346     if(!llVC.isEmpty()) subscribe("VOICE_COUNT");
347 iliev 784 if(!llTVC.isEmpty()) subscribe("TOTAL_VOICE_COUNT");
348 iliev 1139 if(!llMIMC.isEmpty()) subscribe("MIDI_INSTRUMENT_MAP_COUNT");
349     if(!llMIMI.isEmpty()) subscribe("MIDI_INSTRUMENT_MAP_INFO");
350     if(!llMIC.isEmpty()) subscribe("MIDI_INSTRUMENT_COUNT");
351     if(!llMII.isEmpty()) subscribe("MIDI_INSTRUMENT_INFO");
352 iliev 1202 if(!llID.isEmpty()) {
353     subscribe("DB_INSTRUMENT_DIRECTORY_COUNT");
354     subscribe("DB_INSTRUMENT_DIRECTORY_INFO");
355     subscribe("DB_INSTRUMENT_COUNT");
356     subscribe("DB_INSTRUMENT_INFO");
357     }
358 iliev 1139 if(!llGI.isEmpty()) subscribe("GLOBAL_INFO");
359 iliev 596 }
360    
361     /**
362     * Closes the connection to LinuxSampler.
363     */
364     public synchronized void
365     disconnect() {
366 iliev 1139 if(getPrintOnlyMode()) return;
367 iliev 596 try { if(sock != null) sock.close(); }
368     catch(Exception x) { getLogger().log(Level.FINE, x.getMessage(), x); }
369     sock = null;
370    
371     if(eventThread.getState() != Thread.State.NEW) {
372     eventThread.terminate();
373     eventThread = new EventThread();
374     }
375     }
376    
377     /**
378     * Determines whether the client is connected.
379     * @return <code>true</code> if there is established connection,
380     * <code>false</code> otherwise.
381     */
382     public synchronized boolean
383     isConnected() {
384     if(sock == null) return false;
385     else return sock.isConnected();
386     }
387    
388     /**
389     * Verifies that there is established connection.
390     * @throws IOException If the connection is not established.
391     */
392     private void
393     verifyConnection() throws IOException {
394 iliev 1139 if(getPrintOnlyMode()) return;
395    
396 iliev 596 if(!isConnected())
397     throw new IOException(LscpI18n.getLogMsg("Client.notConnected!"));
398     }
399    
400     private String
401     getLine() throws IOException, LscpException {
402     String s;
403     for(;;) {
404     s = in.readLine();
405 iliev 1202 if(s.startsWith("NOTIFY:")) {
406     eventThread.scheduleNotification(s.substring("NOTIFY:".length()));
407     }
408 iliev 596 else break;
409     }
410     return s;
411     }
412    
413 iliev 1139 /** Processes the notifications sent by LinuxSampler */
414 iliev 596 private synchronized void
415     processNotifications() throws IOException, LscpException {
416     while(in.available() > 0) {
417     String s = in.readLine();
418     if(s.startsWith("NOTIFY:")) fireEvent(s.substring("NOTIFY:".length()));
419     else getLogger().severe("Unknown notification format: " + s);
420     }
421     }
422    
423     /**
424     * Gets empty result set.
425     * @return <code>ResultSet</code> instance.
426     */
427     private ResultSet
428     getEmptyResultSet() throws IOException, LscpException, LSException {
429     return parseEmptyResultSet(getLine());
430     }
431    
432     private ResultSet
433     getSingleLineResultSet() throws IOException, LscpException, LSException {
434     ResultSet rs = new ResultSet();
435     String ln = getLine();
436    
437     if(ln.startsWith("WRN")) {
438     parseWarning(ln, rs);
439     getLogger().warning(rs.getMessage());
440     return rs;
441     } else if(ln.startsWith("ERR")) {
442     parseError(ln, rs);
443     throw new LSException(rs.getCode(), rs.getMessage());
444     } else {
445     rs.setResult(ln);
446     return rs;
447     }
448     }
449    
450     private ResultSet
451     getMultiLineResultSet() throws IOException, LscpException, LSException {
452     ResultSet rs = new ResultSet();
453     String ln = getLine();
454    
455     if(ln.startsWith("WRN")) {
456     parseWarning(ln, rs);
457     getLogger().warning(rs.getMessage());
458     return rs;
459     } else if(ln.startsWith("ERR")) {
460     parseError(ln, rs);
461     throw new LSException(rs.getCode(), rs.getMessage());
462     }
463    
464     while(!ln.equals(".")) {
465     rs.addLine(ln);
466     ln = getLine();
467     }
468    
469     return rs;
470     }
471    
472 iliev 1139 /** Audio output device count listeners */
473     private final Vector<ItemCountListener> llAODC = new Vector<ItemCountListener>();
474     /** Audio output device info listeners */
475     private final Vector<ItemInfoListener> llAODI = new Vector<ItemInfoListener>();
476 iliev 596 private final Vector<BufferFillListener> llBF = new Vector<BufferFillListener>();
477     private final Vector<ChannelCountListener> llCC = new Vector<ChannelCountListener>();
478     private final Vector<ChannelInfoListener> llCI = new Vector<ChannelInfoListener>();
479 iliev 1139 private final Vector<FxSendCountListener> llFSC = new Vector<FxSendCountListener>();
480     private final Vector<FxSendInfoListener> llFSI = new Vector<FxSendInfoListener>();
481 iliev 596 private final Vector<MiscellaneousListener> llM = new Vector<MiscellaneousListener>();
482 iliev 1139 /** MIDI input device count listeners */
483     private final Vector<ItemCountListener> llMIDC = new Vector<ItemCountListener>();
484     /** MIDI input device info listeners */
485     private final Vector<ItemInfoListener> llMIDI = new Vector<ItemInfoListener>();
486 iliev 596 private final Vector<StreamCountListener> llSC = new Vector<StreamCountListener>();
487     private final Vector<VoiceCountListener> llVC = new Vector<VoiceCountListener>();
488 iliev 784 private final Vector<TotalVoiceCountListener> llTVC = new Vector<TotalVoiceCountListener>();
489 iliev 596
490 iliev 1139 /** MIDI instrument map count listeners */
491     private final Vector<ItemCountListener> llMIMC = new Vector<ItemCountListener>();
492     /** MIDI instrument map info listeners */
493     private final Vector<ItemInfoListener> llMIMI = new Vector<ItemInfoListener>();
494     /** MIDI instrument count listeners */
495     private final Vector<MidiInstrumentCountListener> llMIC =
496     new Vector<MidiInstrumentCountListener>();
497     /** MIDI instrument info listeners */
498     private final Vector<MidiInstrumentInfoListener> llMII =
499     new Vector<MidiInstrumentInfoListener>();
500 iliev 1202 private final Vector<InstrumentsDbListener> llID = new Vector<InstrumentsDbListener>();
501 iliev 1139 private final Vector<GlobalInfoListener> llGI = new Vector<GlobalInfoListener>();
502    
503    
504 iliev 596 /**
505     * Determines whether there is at least one subscription for notification events.
506     * Do not forget to check for additional listeners if the LSCP specification
507 iliev 784 * is extended in the future.
508 iliev 596 * @return <code>true</code> if there is at least one subscription for notification events,
509     * <code>false</code> otherwise.
510     */
511     private boolean
512     hasSubscriptions() {
513 iliev 1139 return !llAODC.isEmpty() ||
514     !llAODI.isEmpty() ||
515     !llBF.isEmpty() ||
516     !llCC.isEmpty() ||
517     !llCI.isEmpty() ||
518     !llFSC.isEmpty() ||
519     !llFSI.isEmpty() ||
520     !llM.isEmpty() ||
521     !llMIDC.isEmpty() ||
522     !llMIDI.isEmpty() ||
523     !llSC.isEmpty() ||
524     !llVC.isEmpty() ||
525     !llTVC.isEmpty() ||
526     !llMIMC.isEmpty() ||
527     !llMIMI.isEmpty() ||
528     !llMIC.isEmpty() ||
529     !llMII.isEmpty() ||
530 iliev 1202 !llID.isEmpty() ||
531 iliev 1139 !llGI.isEmpty();
532 iliev 596 }
533    
534 iliev 1202 private synchronized void
535 iliev 596 fireEvent(String s) {
536 iliev 1202 if(s.startsWith("DB_INSTRUMENT_DIRECTORY_COUNT:")) {
537     s = s.substring("DB_INSTRUMENT_DIRECTORY_COUNT:".length());
538     InstrumentsDbEvent e = new InstrumentsDbEvent(this, s);
539     for(InstrumentsDbListener l : llID) l.directoryCountChanged(e);
540     } else if(s.startsWith("DB_INSTRUMENT_DIRECTORY_INFO:")) {
541     InstrumentsDbEvent e;
542     s = s.substring("DB_INSTRUMENT_DIRECTORY_INFO:".length());
543     if(s.startsWith("NAME ")) {
544     String[] list;
545     try {
546 iliev 1346 s = s.substring("NAME ".length());
547     list = parseEscapedStringList(s, ' ');
548 iliev 1202 if(list.length != 2) throw new LscpException();
549 iliev 1351 list[1] = toNonEscapedString(list[1]);
550 iliev 1202 e = new InstrumentsDbEvent(this, list[0], list[1]);
551     for(InstrumentsDbListener l : llID) {
552     l.directoryNameChanged(e);
553     }
554     } catch(LscpException x) {
555     getLogger().log (
556     Level.WARNING,
557     LscpI18n.getLogMsg("CommandFailed!"),
558     x
559     );
560     }
561     } else {
562     e = new InstrumentsDbEvent(this, s);
563     for(InstrumentsDbListener l : llID) l.directoryInfoChanged(e);
564     }
565     } else if(s.startsWith("DB_INSTRUMENT_COUNT:")) {
566     s = s.substring("DB_INSTRUMENT_COUNT:".length());
567     InstrumentsDbEvent e = new InstrumentsDbEvent(this, s);
568     for(InstrumentsDbListener l : llID) l.instrumentCountChanged(e);
569     } else if(s.startsWith("DB_INSTRUMENT_INFO:")) {
570     InstrumentsDbEvent e;
571     s = s.substring("DB_INSTRUMENT_INFO:".length());
572     if(s.startsWith("NAME ")) {
573     String[] list;
574     try {
575 iliev 1346 s = s.substring("NAME ".length());
576     list = parseEscapedStringList(s, ' ');
577 iliev 1202 if(list.length != 2) throw new LscpException();
578 iliev 1351 list[1] = toNonEscapedString(list[1]);
579 iliev 1202 e = new InstrumentsDbEvent(this, list[0], list[1]);
580     for(InstrumentsDbListener l : llID) {
581     l.instrumentNameChanged(e);
582     }
583     } catch(LscpException x) {
584     getLogger().log (
585     Level.WARNING,
586     LscpI18n.getLogMsg("CommandFailed!"),
587     x
588     );
589     }
590     } else {
591     e = new InstrumentsDbEvent(this, s);
592     for(InstrumentsDbListener l : llID) l.instrumentInfoChanged(e);
593     }
594     } else if(s.startsWith("DB_INSTRUMENTS_JOB_INFO:")) {
595     s = s.substring("DB_INSTRUMENTS_JOB_INFO:".length());
596 iliev 596 try {
597 iliev 1202 int i = Integer.parseInt(s);
598     InstrumentsDbEvent e = new InstrumentsDbEvent(this, i);
599     for(InstrumentsDbListener l : llID) l.jobStatusChanged(e);
600     } catch(NumberFormatException x) {
601     s = "Unknown DB_INSTRUMENTS_JOB_INFO format";
602     getLogger().log(Level.WARNING, s, x);
603     }
604    
605     } else if(s.startsWith("CHANNEL_COUNT:")) {
606     try {
607 iliev 596 int i = Integer.parseInt(s.substring("CHANNEL_COUNT:".length()));
608     ChannelCountEvent e = new ChannelCountEvent(this, i);
609     for(ChannelCountListener l : llCC) l.channelCountChanged(e);
610     } catch(NumberFormatException x) {
611     getLogger().log (
612     Level.WARNING, LscpI18n.getLogMsg("CommandFailed!"), x
613     );
614     }
615     } else if(s.startsWith("VOICE_COUNT:")) {
616     try {
617     s = s.substring("VOICE_COUNT:".length());
618 iliev 1139 Integer[] i = parseIntList(s, ' ');
619     if(i.length != 2) {
620 iliev 596 getLogger().warning("Unknown VOICE_COUNT format");
621     return;
622     }
623 iliev 1139 VoiceCountEvent e = new VoiceCountEvent(this, i[0], i[1]);
624 iliev 596 for(VoiceCountListener l : llVC) l.voiceCountChanged(e);
625 iliev 1139 } catch(Exception x) {
626 iliev 596 getLogger().log(Level.WARNING, "Unknown VOICE_COUNT format", x);
627     }
628     } else if(s.startsWith("STREAM_COUNT:")) {
629     try {
630     s = s.substring("STREAM_COUNT:".length());
631 iliev 1139 Integer[] i = parseIntList(s, ' ');
632     if(i.length != 2) {
633 iliev 596 getLogger().warning("Unknown STREAM_COUNT format");
634     return;
635     }
636 iliev 1139 StreamCountEvent e = new StreamCountEvent(this, i[0], i[1]);
637 iliev 596 for(StreamCountListener l : llSC) l.streamCountChanged(e);
638 iliev 1139 } catch(Exception x) {
639 iliev 596 getLogger().log(Level.WARNING, "Unknown STREAM_COUNT format", x);
640     }
641     } else if(s.startsWith("BUFFER_FILL:")) {
642     try {
643     s = s.substring("BUFFER_FILL:".length());
644     int i = s.indexOf(' ');
645     if(i == -1) {
646 iliev 1139 getLogger().warning("Unknown BUFFER_FILL format");
647 iliev 596 return;
648     }
649     int j = Integer.parseInt(s.substring(0, i));
650     Vector<BufferFill> v =
651     getChannelBufferFillPercentage(s.substring(i + 1));
652     BufferFillEvent e = new BufferFillEvent(this, j, v);
653     for(BufferFillListener l : llBF) l.bufferFillChanged(e);
654     } catch(Exception x) {
655 iliev 1139 getLogger().log(Level.WARNING, "Unknown BUFFER_FILL format", x);
656 iliev 596 }
657     } else if(s.startsWith("CHANNEL_INFO:")) {
658     try {
659     int i = Integer.parseInt(s.substring("CHANNEL_INFO:".length()));
660     ChannelInfoEvent e = new ChannelInfoEvent(this, i);
661     for(ChannelInfoListener l : llCI) l.channelInfoChanged(e);
662     } catch(NumberFormatException x) {
663 iliev 1139 getLogger().log(Level.WARNING, "Unknown CHANNEL_INFO format", x);
664 iliev 596 }
665 iliev 784 } else if(s.startsWith("TOTAL_VOICE_COUNT:")) {
666     try {
667     s = s.substring("TOTAL_VOICE_COUNT:".length());
668     int i = Integer.parseInt(s);
669     TotalVoiceCountEvent e = new TotalVoiceCountEvent(this, i);
670     for(TotalVoiceCountListener l : llTVC) l.totalVoiceCountChanged(e);
671     } catch(NumberFormatException x) {
672     getLogger().log (
673     Level.WARNING, "Unknown TOTAL_VOICE_COUNT format", x
674     );
675     }
676 iliev 1139 } else if(s.startsWith("AUDIO_OUTPUT_DEVICE_COUNT:")) {
677     try {
678     s = s.substring("AUDIO_OUTPUT_DEVICE_COUNT:".length());
679     int i = Integer.parseInt(s);
680     ItemCountEvent e = new ItemCountEvent(this, i);
681     for(ItemCountListener l : llAODC) l.itemCountChanged(e);
682     } catch(NumberFormatException x) {
683     getLogger().log (
684     Level.WARNING, "Unknown AUDIO_OUTPUT_DEVICE_COUNT format", x
685     );
686     }
687     } else if(s.startsWith("AUDIO_OUTPUT_DEVICE_INFO:")) {
688     try {
689     s = s.substring("AUDIO_OUTPUT_DEVICE_INFO:".length());
690     int i = Integer.parseInt(s);
691     ItemInfoEvent e = new ItemInfoEvent(this, i);
692     for(ItemInfoListener l : llAODI) l.itemInfoChanged(e);
693     } catch(NumberFormatException x) {
694     getLogger().log (
695     Level.WARNING, "Unknown AUDIO_OUTPUT_DEVICE_INFO format", x
696     );
697     }
698     } else if(s.startsWith("MIDI_INPUT_DEVICE_COUNT:")) {
699     try {
700     s = s.substring("MIDI_INPUT_DEVICE_COUNT:".length());
701     int i = Integer.parseInt(s);
702     ItemCountEvent e = new ItemCountEvent(this, i);
703     for(ItemCountListener l : llMIDC) l.itemCountChanged(e);
704     } catch(NumberFormatException x) {
705     getLogger().log (
706     Level.WARNING, "Unknown MIDI_INPUT_DEVICE_COUNT format", x
707     );
708     }
709     } else if(s.startsWith("MIDI_INPUT_DEVICE_INFO:")) {
710     try {
711     s = s.substring("MIDI_INPUT_DEVICE_INFO:".length());
712     int i = Integer.parseInt(s);
713     ItemInfoEvent e = new ItemInfoEvent(this, i);
714     for(ItemInfoListener l : llMIDI) l.itemInfoChanged(e);
715     } catch(NumberFormatException x) {
716     getLogger().log (
717     Level.WARNING, "Unknown MIDI_INPUT_DEVICE_INFO format", x
718     );
719     }
720     } else if(s.startsWith("MIDI_INSTRUMENT_MAP_COUNT:")) {
721     try {
722     s = s.substring("MIDI_INSTRUMENT_MAP_COUNT:".length());
723     int i = Integer.parseInt(s);
724     ItemCountEvent e = new ItemCountEvent(this, i);
725     for(ItemCountListener l : llMIMC) l.itemCountChanged(e);
726     } catch(NumberFormatException x) {
727     getLogger().log (
728     Level.WARNING, "Unknown MIDI_INSTRUMENT_MAP_COUNT format", x
729     );
730     }
731     } else if(s.startsWith("MIDI_INSTRUMENT_MAP_INFO:")) {
732     try {
733     s = s.substring("MIDI_INSTRUMENT_MAP_INFO:".length());
734     int i = Integer.parseInt(s);
735     ItemInfoEvent e = new ItemInfoEvent(this, i);
736     for(ItemInfoListener l : llMIMI) l.itemInfoChanged(e);
737     } catch(NumberFormatException x) {
738     getLogger().log (
739     Level.WARNING, "Unknown MIDI_INSTRUMENT_MAP_INFO format", x
740     );
741     }
742     } else if(s.startsWith("MIDI_INSTRUMENT_COUNT:")) {
743     try {
744     s = s.substring("MIDI_INSTRUMENT_COUNT:".length());
745     Integer[] i = parseIntList(s, ' ');
746     if(i.length != 2) {
747     getLogger().warning("Unknown MIDI_INSTRUMENT_COUNT format");
748     return;
749     }
750    
751     MidiInstrumentCountEvent e =
752     new MidiInstrumentCountEvent(this, i[0], i[1]);
753    
754     for(MidiInstrumentCountListener l : llMIC) {
755     l.instrumentCountChanged(e);
756     }
757     } catch(Exception x) {
758     getLogger().log (
759     Level.WARNING, "Unknown MIDI_INSTRUMENT_COUNT format", x
760     );
761     }
762     } else if(s.startsWith("MIDI_INSTRUMENT_INFO:")) {
763     try {
764     s = s.substring("MIDI_INSTRUMENT_INFO:".length());
765     Integer[] i = parseIntList(s, ' ');
766     if(i.length != 3) {
767     getLogger().warning("Unknown MIDI_INSTRUMENT_INFO format");
768     return;
769     }
770    
771     MidiInstrumentInfoEvent e =
772     new MidiInstrumentInfoEvent(this, i[0], i[1], i[2]);
773     for(MidiInstrumentInfoListener l : llMII) {
774     l.instrumentInfoChanged(e);
775     }
776     } catch(Exception x) {
777     getLogger().log (
778     Level.WARNING, "Unknown MIDI_INSTRUMENT_INFO format", x
779     );
780     }
781     } else if(s.startsWith("FX_SEND_COUNT:")) {
782     try {
783     s = s.substring("FX_SEND_COUNT:".length());
784     Integer[] i = parseIntList(s, ' ');
785     if(i.length != 2) {
786     getLogger().warning("Unknown FX_SEND_COUNT format");
787     return;
788     }
789    
790     FxSendCountEvent e = new FxSendCountEvent(this, i[0], i[1]);
791    
792     for(FxSendCountListener l : llFSC) l.fxSendCountChanged(e);
793     } catch(Exception x) {
794     getLogger().log(Level.WARNING, "Unknown FX_SEND_COUNT format", x);
795     }
796     } else if(s.startsWith("FX_SEND_INFO:")) {
797     try {
798     s = s.substring("FX_SEND_INFO:".length());
799     Integer[] i = parseIntList(s, ' ');
800     if(i.length != 2) {
801     getLogger().warning("Unknown FX_SEND_INFO format");
802     return;
803     }
804    
805     FxSendInfoEvent e = new FxSendInfoEvent(this, i[0], i[1]);
806     for(FxSendInfoListener l : llFSI) {
807     l.fxSendInfoChanged(e);
808     }
809     } catch(Exception x) {
810     getLogger().log(Level.WARNING, "Unknown FX_SEND_INFO format", x);
811     }
812     } else if(s.startsWith("GLOBAL_INFO:")) {
813     handleGlobalInfoEvent(s.substring("GLOBAL_INFO:".length()));
814 iliev 596 } else if(s.startsWith("MISCELLANEOUS:")) {
815     s = s.substring("MISCELLANEOUS:".length());
816     MiscellaneousEvent e = new MiscellaneousEvent(this, s);
817     for(MiscellaneousListener l : llM) l.miscEventOccured(e);
818     }
819     }
820    
821     private void
822 iliev 1139 handleGlobalInfoEvent(String s) {
823     try {
824     if(s.startsWith("VOLUME ")) {
825     float f = Float.parseFloat(s.substring("VOLUME ".length()));
826     GlobalInfoEvent e = new GlobalInfoEvent(this, f);
827     for(GlobalInfoListener l : llGI) l.volumeChanged(e);
828     }
829     } catch(NumberFormatException x) {
830     getLogger().log(Level.WARNING, "Unknown GLOBAL_INFO format", x);
831     }
832     }
833    
834     private void
835 iliev 596 subscribe(String event) {
836 iliev 1139 if(!getPrintOnlyMode()) {
837     if(!isConnected()) return;
838 iliev 596
839 iliev 1139 if(!eventThread.isAlive()) eventThread.start();
840     }
841 iliev 596
842     try {
843     out.writeLine("SUBSCRIBE " + event);
844 iliev 1139 if(!getPrintOnlyMode()) getEmptyResultSet();
845 iliev 596 } catch(Exception x) {
846     getLogger().log (
847     Level.WARNING,
848     LscpI18n.getLogMsg("Client.subscriptionFailed!", event),
849     x
850     );
851     }
852     }
853    
854     private void
855     unsubscribe(String event) {
856 iliev 1139 if(!getPrintOnlyMode() && !isConnected()) return;
857 iliev 596
858     try {
859     out.writeLine("UNSUBSCRIBE " + event);
860 iliev 1139 if(!getPrintOnlyMode()) getEmptyResultSet();
861 iliev 596 } catch(Exception x) {
862     getLogger().log (
863     Level.WARNING,
864     LscpI18n.getLogMsg("Client.unsubscriptionFailed!", event),
865     x
866     );
867     }
868     }
869    
870     /**
871     * Registers the specified listener for receiving event messages.
872 iliev 1139 * Listeners can be registered regardless of the connection state.
873     * @param l The <code>ItemCountListener</code> to register.
874     */
875     public synchronized void
876     addAudioDeviceCountListener(ItemCountListener l) {
877     if(llAODC.isEmpty()) subscribe("AUDIO_OUTPUT_DEVICE_COUNT");
878     llAODC.add(l);
879     }
880    
881     /**
882     * Removes the specified listener.
883 iliev 596 * Listeners can be removed regardless of the connection state.
884 iliev 1139 * @param l The <code>ItemCountListener</code> to remove.
885     */
886     public synchronized void
887     removeAudioDeviceCountListener(ItemCountListener l) {
888     boolean b = llAODC.remove(l);
889     if(b && llAODC.isEmpty()) unsubscribe("AUDIO_OUTPUT_DEVICE_COUNT");
890     }
891    
892     /**
893     * Registers the specified listener for receiving event messages.
894     * Listeners can be registered regardless of the connection state.
895     * @param l The <code>ItemInfoListener</code> to register.
896     */
897     public synchronized void
898     addAudioDeviceInfoListener(ItemInfoListener l) {
899     if(llAODI.isEmpty()) subscribe("AUDIO_OUTPUT_DEVICE_INFO");
900     llAODI.add(l);
901     }
902    
903     /**
904     * Removes the specified listener.
905     * Listeners can be removed regardless of the connection state.
906     * @param l The <code>ItemInfoListener</code> to remove.
907     */
908     public synchronized void
909     removeAudioDeviceInfoListener(ItemInfoListener l) {
910     boolean b = llAODI.remove(l);
911     if(b && llAODI.isEmpty()) unsubscribe("AUDIO_OUTPUT_DEVICE_INFO");
912     }
913    
914     /**
915     * Registers the specified listener for receiving event messages.
916     * Listeners can be removed regardless of the connection state.
917 iliev 596 * @param l The <code>BufferFillListener</code> to register.
918     */
919     public synchronized void
920     addBufferFillListener(BufferFillListener l) {
921     if(llBF.isEmpty()) subscribe("BUFFER_FILL");
922     llBF.add(l);
923     }
924    
925     /**
926     * Removes the specified listener.
927     * Listeners can be removed regardless of the connection state.
928     * @param l The <code>BufferFillListener</code> to remove.
929     */
930     public synchronized void
931     removeBufferFillListener(BufferFillListener l) {
932     boolean b = llBF.remove(l);
933     if(b && llBF.isEmpty()) unsubscribe("BUFFER_FILL");
934     }
935    
936     /**
937     * Registers the specified listener for receiving event messages.
938     * Listeners can be registered regardless of the connection state.
939     * @param l The <code>ChannelCountListener</code> to register.
940     */
941     public synchronized void
942     addChannelCountListener(ChannelCountListener l) {
943     if(llCC.isEmpty()) subscribe("CHANNEL_COUNT");
944     llCC.add(l);
945     }
946    
947     /**
948     * Removes the specified listener.
949     * Listeners can be removed regardless of the connection state.
950     * @param l The <code>ChannelCountListener</code> to remove.
951     */
952     public synchronized void
953     removeChannelCountListener(ChannelCountListener l) {
954     boolean b = llCC.remove(l);
955     if(b && llCC.isEmpty()) unsubscribe("CHANNEL_COUNT");
956     }
957    
958     /**
959     * Registers the specified listener for receiving event messages.
960     * Listeners can be registered regardless of the connection state.
961     * @param l The <code>ChannelInfoListener</code> to register.
962     */
963     public synchronized void
964     addChannelInfoListener(ChannelInfoListener l) {
965     if(llCI.isEmpty()) subscribe("CHANNEL_INFO");
966     llCI.add(l);
967     }
968    
969     /**
970     * Removes the specified listener.
971     * Listeners can be removed regardless of the connection state.
972     * @param l The <code>ChannelInfoListener</code> to remove.
973     */
974     public synchronized void
975     removeChannelInfoListener(ChannelInfoListener l) {
976     boolean b = llCI.remove(l);
977     if(b && llCI.isEmpty()) unsubscribe("CHANNEL_INFO");
978     }
979    
980     /**
981     * Registers the specified listener for receiving event messages.
982     * Listeners can be registered regardless of the connection state.
983 iliev 1139 * @param l The <code>FxSendCountListener</code> to register.
984     */
985     public synchronized void
986     addFxSendCountListener(FxSendCountListener l) {
987     if(llFSC.isEmpty()) subscribe("FX_SEND_COUNT");
988     llFSC.add(l);
989     }
990    
991     /**
992     * Removes the specified listener.
993     * Listeners can be removed regardless of the connection state.
994     * @param l The <code>FxSendCountListener</code> to remove.
995     */
996     public synchronized void
997     removeFxSendCountListener(FxSendCountListener l) {
998     boolean b = llFSC.remove(l);
999     if(b && llFSC.isEmpty()) unsubscribe("FX_SEND_COUNT");
1000     }
1001    
1002     /**
1003     * Registers the specified listener for receiving event messages.
1004     * Listeners can be registered regardless of the connection state.
1005     * @param l The <code>FxSendInfoListener</code> to register.
1006     */
1007     public synchronized void
1008     addFxSendInfoListener(FxSendInfoListener l) {
1009     if(llFSI.isEmpty()) subscribe("FX_SEND_INFO");
1010     llFSI.add(l);
1011     }
1012    
1013     /**
1014     * Removes the specified listener.
1015     * Listeners can be removed regardless of the connection state.
1016     * @param l The <code>FxSendInfoListener</code> to remove.
1017     */
1018     public synchronized void
1019     removeFxSendInfoListener(FxSendInfoListener l) {
1020     boolean b = llFSI.remove(l);
1021     if(b && llFSI.isEmpty()) unsubscribe("FX_SEND_INFO");
1022     }
1023    
1024     /**
1025     * Registers the specified listener for receiving event messages.
1026     * Listeners can be registered regardless of the connection state.
1027     * @param l The <code>ItemCountListener</code> to register.
1028     */
1029     public synchronized void
1030     addMidiDeviceCountListener(ItemCountListener l) {
1031     if(llMIDC.isEmpty()) subscribe("MIDI_INPUT_DEVICE_COUNT");
1032     llMIDC.add(l);
1033     }
1034    
1035     /**
1036     * Removes the specified listener.
1037     * Listeners can be removed regardless of the connection state.
1038     * @param l The <code>ItemCountListener</code> to remove.
1039     */
1040     public synchronized void
1041     removeMidiDeviceCountListener(ItemCountListener l) {
1042     boolean b = llMIDC.remove(l);
1043     if(b && llMIDC.isEmpty()) unsubscribe("MIDI_INPUT_DEVICE_COUNT");
1044     }
1045    
1046     /**
1047     * Registers the specified listener for receiving event messages.
1048     * Listeners can be registered regardless of the connection state.
1049     * @param l The <code>ItemInfoListener</code> to register.
1050     */
1051     public synchronized void
1052     addMidiDeviceInfoListener(ItemInfoListener l) {
1053     if(llMIDI.isEmpty()) subscribe("MIDI_INPUT_DEVICE_INFO");
1054     llMIDI.add(l);
1055     }
1056    
1057     /**
1058     * Removes the specified listener.
1059     * Listeners can be removed regardless of the connection state.
1060     * @param l The <code>ItemInfoListener</code> to remove.
1061     */
1062     public synchronized void
1063     removeMidiDeviceInfoListener(ItemInfoListener l) {
1064     boolean b = llMIDI.remove(l);
1065     if(b && llMIDI.isEmpty()) unsubscribe("MIDI_INPUT_DEVICE_INFO");
1066     }
1067    
1068     /**
1069     * Registers the specified listener for receiving event messages.
1070     * Listeners can be registered regardless of the connection state.
1071 iliev 596 * @param l The <code>MiscellaneousListener</code> to register.
1072     */
1073     public synchronized void
1074     addMiscellaneousListener(MiscellaneousListener l) {
1075     if(llM.isEmpty()) subscribe("MISCELLANEOUS");
1076     llM.add(l);
1077     }
1078    
1079     /**
1080     * Removes the specified listener.
1081     * Listeners can be removed regardless of the connection state.
1082     * @param l The <code>MiscellaneousListener</code> to remove.
1083     */
1084     public synchronized void
1085     removeMiscellaneousListener(MiscellaneousListener l) {
1086     boolean b = llM.remove(l);
1087     if(b && llM.isEmpty()) unsubscribe("MISCELLANEOUS");
1088     }
1089    
1090     /**
1091     * Registers the specified listener for receiving event messages.
1092     * Listeners can be registered regardless of the connection state.
1093     * @param l The <code>StreamCountListener</code> to register.
1094     */
1095     public synchronized void
1096     addStreamCountListener(StreamCountListener l) {
1097     if(llSC.isEmpty()) subscribe("STREAM_COUNT");
1098     llSC.add(l);
1099     }
1100    
1101     /**
1102     * Removes the specified listener.
1103     * Listeners can be removed regardless of the connection state.
1104     * @param l The <code>StreamCountListener</code> to remove.
1105     */
1106     public synchronized void
1107     removeStreamCountListener(StreamCountListener l) {
1108     boolean b = llSC.remove(l);
1109     if(b && llSC.isEmpty()) unsubscribe("STREAM_COUNT");
1110     }
1111    
1112     /**
1113     * Registers the specified listener for receiving event messages.
1114     * Listeners can be registered regardless of the connection state.
1115     * @param l The <code>VoiceCountListener</code> to register.
1116     */
1117     public synchronized void
1118     addVoiceCountListener(VoiceCountListener l) {
1119     if(llVC.isEmpty()) subscribe("VOICE_COUNT");
1120     llVC.add(l);
1121     }
1122    
1123     /**
1124     * Removes the specified listener.
1125     * Listeners can be removed regardless of the connection state.
1126     * @param l The <code>VoiceCountListener</code> to remove.
1127     */
1128     public synchronized void
1129     removeVoiceCountListener(VoiceCountListener l) {
1130     boolean b = llVC.remove(l);
1131     if(b && llVC.isEmpty()) unsubscribe("VOICE_COUNT");
1132     }
1133    
1134     /**
1135 iliev 784 * Registers the specified listener for receiving event messages.
1136     * Listeners can be registered regardless of the connection state.
1137     * @param l The <code>TotalVoiceCountListener</code> to register.
1138     */
1139     public synchronized void
1140     addTotalVoiceCountListener(TotalVoiceCountListener l) {
1141     if(llTVC.isEmpty()) subscribe("TOTAL_VOICE_COUNT");
1142     llTVC.add(l);
1143     }
1144    
1145     /**
1146     * Removes the specified listener.
1147     * Listeners can be removed regardless of the connection state.
1148     * @param l The <code>TotalVoiceCountListener</code> to remove.
1149     */
1150     public synchronized void
1151     removeTotalVoiceCountListener(TotalVoiceCountListener l) {
1152     boolean b = llTVC.remove(l);
1153     if(b && llTVC.isEmpty()) unsubscribe("TOTAL_VOICE_COUNT");
1154     }
1155    
1156     /**
1157 iliev 1139 * Registers the specified listener for receiving event messages.
1158     * Listeners can be registered regardless of the connection state.
1159     * @param l The <code>ItemCountListener</code> to register.
1160     */
1161     public synchronized void
1162     addMidiInstrumentMapCountListener(ItemCountListener l) {
1163     if(llMIMC.isEmpty()) subscribe("MIDI_INSTRUMENT_MAP_COUNT");
1164     llMIMC.add(l);
1165     }
1166    
1167     /**
1168     * Removes the specified listener.
1169     * Listeners can be removed regardless of the connection state.
1170     * @param l The <code>ItemCountListener</code> to remove.
1171     */
1172     public synchronized void
1173     removeMidiInstrumentMapCountListener(ItemCountListener l) {
1174     boolean b = llMIMC.remove(l);
1175     if(b && llMIMC.isEmpty()) unsubscribe("MIDI_INSTRUMENT_MAP_COUNT");
1176     }
1177    
1178     /**
1179     * Registers the specified listener for receiving event messages.
1180     * Listeners can be registered regardless of the connection state.
1181     * @param l The <code>ItemInfoListener</code> to register.
1182     */
1183     public synchronized void
1184     addMidiInstrumentMapInfoListener(ItemInfoListener l) {
1185     if(llMIMI.isEmpty()) subscribe("MIDI_INSTRUMENT_MAP_INFO");
1186     llMIMI.add(l);
1187     }
1188    
1189     /**
1190     * Removes the specified listener.
1191     * Listeners can be removed regardless of the connection state.
1192     * @param l The <code>ItemInfoListener</code> to remove.
1193     */
1194     public synchronized void
1195     removeMidiInstrumentMapInfoListener(ItemInfoListener l) {
1196     boolean b = llMIMI.remove(l);
1197     if(b && llMIMI.isEmpty()) unsubscribe("MIDI_INSTRUMENT_MAP_INFO");
1198     }
1199    
1200     /**
1201     * Registers the specified listener for receiving event messages.
1202     * Listeners can be registered regardless of the connection state.
1203     * @param l The <code>MidiInstrumentCountListener</code> to register.
1204     */
1205     public synchronized void
1206     addMidiInstrumentCountListener(MidiInstrumentCountListener l) {
1207     if(llMIC.isEmpty()) subscribe("MIDI_INSTRUMENT_COUNT");
1208     llMIC.add(l);
1209     }
1210    
1211     /**
1212     * Removes the specified listener.
1213     * Listeners can be removed regardless of the connection state.
1214     * @param l The <code>MidiInstrumentCountListener</code> to remove.
1215     */
1216     public synchronized void
1217     removeMidiInstrumentCountListener(MidiInstrumentCountListener l) {
1218     boolean b = llMIC.remove(l);
1219     if(b && llMIC.isEmpty()) unsubscribe("MIDI_INSTRUMENT_COUNT");
1220     }
1221    
1222     /**
1223     * Registers the specified listener for receiving event messages.
1224     * Listeners can be registered regardless of the connection state.
1225     * @param l The <code>MidiInstrumentInfoListener</code> to register.
1226     */
1227     public synchronized void
1228     addMidiInstrumentInfoListener(MidiInstrumentInfoListener l) {
1229     if(llMII.isEmpty()) subscribe("MIDI_INSTRUMENT_INFO");
1230     llMII.add(l);
1231     }
1232    
1233     /**
1234     * Removes the specified listener.
1235     * Listeners can be removed regardless of the connection state.
1236     * @param l The <code>MidiInstrumentInfoListener</code> to remove.
1237     */
1238     public synchronized void
1239     removeMidiInstrumentInfoListener(MidiInstrumentInfoListener l) {
1240     boolean b = llMII.remove(l);
1241     if(b && llMII.isEmpty()) unsubscribe("MIDI_INSTRUMENT_INFO");
1242     }
1243    
1244     /**
1245     * Registers the specified listener for receiving event messages.
1246     * Listeners can be registered regardless of the connection state.
1247 iliev 1202 * @param l The <code>InstrumentsDbListener</code> to register.
1248     */
1249     public synchronized void
1250     addInstrumentsDbListener(InstrumentsDbListener l) {
1251     if(llID.isEmpty()) {
1252     subscribe("DB_INSTRUMENT_DIRECTORY_COUNT");
1253     subscribe("DB_INSTRUMENT_DIRECTORY_INFO");
1254     subscribe("DB_INSTRUMENT_COUNT");
1255     subscribe("DB_INSTRUMENT_INFO");
1256     subscribe("DB_INSTRUMENTS_JOB_INFO");
1257     }
1258     llID.add(l);
1259     }
1260    
1261     /**
1262     * Removes the specified listener.
1263     * Listeners can be removed regardless of the connection state.
1264     * @param l The <code>InstrumentsDbListener</code> to remove.
1265     */
1266     public synchronized void
1267     removeInstrumentsDbListener(InstrumentsDbListener l) {
1268     boolean b = llID.remove(l);
1269     if(b && llID.isEmpty()) {
1270     unsubscribe("DB_INSTRUMENT_DIRECTORY_COUNT");
1271     unsubscribe("DB_INSTRUMENT_DIRECTORY_INFO");
1272     unsubscribe("DB_INSTRUMENT_COUNT");
1273     unsubscribe("DB_INSTRUMENT_INFO");
1274     unsubscribe("DB_INSTRUMENTS_JOB_INFO");
1275     }
1276     }
1277    
1278     /**
1279     * Registers the specified listener for receiving event messages.
1280     * Listeners can be registered regardless of the connection state.
1281 iliev 1139 * @param l The <code>GlobalInfoListener</code> to register.
1282     */
1283     public synchronized void
1284     addGlobalInfoListener(GlobalInfoListener l) {
1285     if(llGI.isEmpty()) subscribe("GLOBAL_INFO");
1286     llGI.add(l);
1287     }
1288    
1289     /**
1290     * Removes the specified listener.
1291     * Listeners can be removed regardless of the connection state.
1292     * @param l The <code>GlobalInfoListener</code> to remove.
1293     */
1294     public synchronized void
1295     removeGlobalInfoListener(GlobalInfoListener l) {
1296     boolean b = llGI.remove(l);
1297     if(b && llGI.isEmpty()) unsubscribe("GLOBAL_INFO");
1298     }
1299    
1300     /**
1301 iliev 596 * Gets the number of all audio output drivers currently
1302     * available for the LinuxSampler instance.
1303     * @return The number of all audio output drivers currently
1304     * available for the LinuxSampler instance.
1305     * @throws IOException If some I/O error occurs.
1306     * @throws LscpException If LSCP protocol corruption occurs.
1307     * @throws LSException If some other error occurs.
1308     */
1309     public synchronized int
1310     getAudioOutputDriverCount() throws IOException, LscpException, LSException {
1311     verifyConnection();
1312     out.writeLine("GET AVAILABLE_AUDIO_OUTPUT_DRIVERS");
1313 iliev 1139
1314     if(getPrintOnlyMode()) return -1;
1315    
1316 iliev 596 String s = getSingleLineResultSet().getResult();
1317     return parseInt(s);
1318     }
1319 iliev 671
1320 iliev 596 /**
1321     * Gets all audio output drivers currently available for the LinuxSampler instance.
1322     *
1323 iliev 671 * @return <code>AudioOutputDriver</code> array containing all audio output drivers
1324     * currently available for the LinuxSampler instance.
1325 iliev 596 *
1326     * @throws IOException If an I/O error occurs.
1327     * @throws LscpException If LSCP protocol corruption occurs.
1328     * @throws LSException If some other error occurs.
1329     */
1330 iliev 671 public synchronized AudioOutputDriver[]
1331 iliev 596 getAudioOutputDrivers() throws IOException, LscpException, LSException {
1332 iliev 671 String[] drivers = getAudioOutputDriverNames();
1333 iliev 1139 if(getPrintOnlyMode()) return null;
1334    
1335 iliev 671 AudioOutputDriver[] aod = new AudioOutputDriver[drivers.length];
1336    
1337     for(int i = 0; i < aod.length; i++) aod[i] = getAudioOutputDriverInfo(drivers[i]);
1338    
1339     return aod;
1340     }
1341    
1342     /**
1343     * Gets all audio output drivers currently available for the LinuxSampler instance.
1344     *
1345     * @return <code>String</code> array containing all audio output drivers currently
1346     * available for the LinuxSampler instance.
1347     *
1348     * @throws IOException If an I/O error occurs.
1349     * @throws LscpException If LSCP protocol corruption occurs.
1350     * @throws LSException If some other error occurs.
1351     */
1352     private synchronized String[]
1353     getAudioOutputDriverNames() throws IOException, LscpException, LSException {
1354 iliev 596 verifyConnection();
1355     out.writeLine("LIST AVAILABLE_AUDIO_OUTPUT_DRIVERS");
1356 iliev 1139 if(getPrintOnlyMode()) return null;
1357 iliev 596 return parseList(getSingleLineResultSet().getResult());
1358     }
1359    
1360     /**
1361     * Gets detailed information about a specific audio output driver.
1362     * @param driverName The name of the audio output driver.
1363 iliev 1326 * @param depList An optional list of dependences parameters.
1364 iliev 596 * @return An <code>AudioOutputDriver</code> object containing
1365     * information about the specified audio output driver.
1366     *
1367     * @throws IOException If an I/O error occurs.
1368     * @throws LscpException If LSCP protocol corruption occurs.
1369     * @throws LSException If there is no driver with name <code>driverName</code>.
1370     *
1371 iliev 671 * @see #getAudioOutputDriverNames
1372 iliev 596 */
1373 iliev 1326 public synchronized AudioOutputDriver
1374     getAudioOutputDriverInfo(String driverName, Parameter... depList)
1375     throws IOException, LscpException, LSException {
1376    
1377 iliev 596 verifyConnection();
1378     out.writeLine("GET AUDIO_OUTPUT_DRIVER INFO " + driverName);
1379 iliev 1139 if(getPrintOnlyMode()) return null;
1380    
1381 iliev 596 ResultSet rs = getMultiLineResultSet();
1382     AudioOutputDriver aod = new AudioOutputDriver(rs.getMultiLineResult());
1383     aod.setName(driverName);
1384    
1385     for(String s : aod.getParameterNames())
1386 iliev 1326 aod.addParameter(getAudioOutputDriverParameterInfo(driverName, s, depList));
1387 iliev 596
1388     return aod;
1389     }
1390    
1391     /**
1392     * Gets detailed information about a specific audio output driver parameter.
1393     *
1394     * @param driver The name of the audio output driver.
1395     * @param param A specific parameter name for which information should be obtained.
1396     * @param deplist An optional list of parameters on which the sought parameter
1397     * <code>param</code> depends on. <code>Parameter</code> instances can be
1398     * easily created using {@link ParameterFactory} factory.
1399     *
1400     * @return <code>Parameter</code> object containing
1401     * information about the specified audio output driver parameter.
1402     *
1403     * @throws IOException If an I/O error occurs.
1404     * @throws LscpException If LSCP protocol corruption occurs.
1405     * @throws LSException If <code>driver</code> is not a valid driver name
1406     * or <code>param</code> is not a valid parameter for the specified driver.
1407     *
1408     * @see #getAudioOutputDrivers
1409     * @see #getAudioOutputDriverInfo
1410     * @see ParameterFactory
1411     */
1412     public synchronized Parameter
1413     getAudioOutputDriverParameterInfo(String driver, String param, Parameter... deplist)
1414     throws IOException, LscpException, LSException {
1415    
1416     verifyConnection();
1417     StringBuffer args = new StringBuffer(driver);
1418     args.append(' ').append(param);
1419    
1420 iliev 1326 for(Parameter p : deplist) {
1421     if(p.getValue() == null) continue;
1422 iliev 596 args.append(' ').append(p.getName()).append('=').append(p.getStringValue());
1423 iliev 1326 }
1424 iliev 596
1425     out.writeLine("GET AUDIO_OUTPUT_DRIVER_PARAMETER INFO " + args.toString());
1426 iliev 1139 if(getPrintOnlyMode()) return null;
1427 iliev 596
1428     ResultSet rs = getMultiLineResultSet();
1429    
1430     String[] lnS = rs.getMultiLineResult();
1431     ParameterType type = parseType(lnS);
1432     boolean multi = parseMultiplicity(lnS);
1433     Parameter prm;
1434    
1435     switch(type) {
1436     case BOOL:
1437     if(!multi) prm = new BoolParameter(lnS);
1438     else prm = new BoolListParameter(lnS);
1439     prm.setName(param);
1440 iliev 784 prm.setValue(prm.getDefault());
1441 iliev 596 return prm;
1442     case INT:
1443     if(!multi) prm = new IntParameter(lnS);
1444     else prm = new IntListParameter(lnS);
1445     prm.setName(param);
1446 iliev 784 prm.setValue(prm.getDefault());
1447 iliev 596 return prm;
1448     case FLOAT:
1449     if(!multi) prm = new FloatParameter(lnS);
1450     else prm = new FloatListParameter(lnS);
1451     prm.setName(param);
1452 iliev 784 prm.setValue(prm.getDefault());
1453 iliev 596 return prm;
1454     case STRING:
1455     if(!multi) prm = new StringParameter(lnS);
1456     else prm = new StringListParameter(lnS);
1457     prm.setName(param);
1458 iliev 784 prm.setValue(prm.getDefault());
1459 iliev 596 return prm;
1460     default: throw new LscpException(LscpI18n.getLogMsg("Client.unknownPrmType!"));
1461     }
1462     }
1463    
1464     /**
1465     * Creates a new audio output device for the desired audio output system.
1466     * @param aoDriver The desired audio output system.
1467     * @param paramList An optional list of driver specific parameters. <code>Parameter</code>
1468     * instances can be easily created using {@link ParameterFactory} factory.
1469     * @return The numerical ID of the newly created device.
1470     * @throws IOException If some I/O error occurs.
1471     * @throws LSException If the creation of the new audio output device failed.
1472     * @throws LscpException If LSCP protocol corruption occurs.
1473     * @see #getAudioOutputDrivers
1474     * @see #getAudioOutputDriverInfo
1475     * @see ParameterFactory
1476     */
1477     public synchronized int
1478     createAudioOutputDevice(String aoDriver, Parameter... paramList)
1479     throws IOException, LSException, LscpException {
1480    
1481     verifyConnection();
1482     StringBuffer args = new StringBuffer(aoDriver);
1483    
1484 iliev 1326 for(Parameter p : paramList) {
1485     if(p.getValue() == null) continue;
1486 iliev 596 args.append(' ').append(p.getName()).append('=').append(p.getStringValue());
1487 iliev 1326 }
1488 iliev 596
1489     out.writeLine("CREATE AUDIO_OUTPUT_DEVICE " + args.toString());
1490 iliev 1139 if(getPrintOnlyMode()) return -1;
1491    
1492 iliev 596 ResultSet rs = getEmptyResultSet();
1493    
1494     return rs.getIndex();
1495     }
1496    
1497     /**
1498     * Destroys already created audio output device.
1499 iliev 1139 * @param deviceId The ID of the audio output device to be destroyed.
1500 iliev 596 * @throws IOException If some I/O error occurs.
1501     * @throws LSException If the destroying of the audio output device failed.
1502     * @throws LscpException If LSCP protocol corruption occurs.
1503     * @see #getAudioOutputDevices
1504     */
1505     public synchronized void
1506 iliev 1139 destroyAudioOutputDevice(int deviceId) throws IOException, LSException, LscpException {
1507 iliev 596 verifyConnection();
1508 iliev 1139 out.writeLine("DESTROY AUDIO_OUTPUT_DEVICE " + deviceId);
1509     if(getPrintOnlyMode()) return;
1510    
1511 iliev 596 ResultSet rs = getEmptyResultSet();
1512     }
1513    
1514 iliev 784 /**
1515     * Enables/disables the specified audio output device.
1516 iliev 1139 * @param deviceId The ID of the audio output device to be enabled/disabled.
1517 iliev 784 * @param enable If <code>true</code> the audio output device is enabled,
1518     * else the device is disabled.
1519     * @throws IOException If some I/O error occurs.
1520     * @throws LSException If there is no audio output
1521 iliev 1139 * device with numerical ID <code>deviceId</code>.
1522 iliev 784 * @throws LscpException If LSCP protocol corruption occurs.
1523     */
1524     public void
1525 iliev 1139 enableAudioOutputDevice(int deviceId, boolean enable)
1526 iliev 784 throws IOException, LSException, LscpException {
1527    
1528 iliev 1139 setAudioOutputDeviceParameter(deviceId, new BoolParameter("ACTIVE", enable));
1529 iliev 784 }
1530    
1531 iliev 596 /**
1532     * Gets the current number of all created audio output devices.
1533     * @return The current number of all created audio output devices.
1534     * @throws IOException If some I/O error occurs.
1535     * @throws LscpException If LSCP protocol corruption occurs.
1536     * @throws LSException If some other error occurs.
1537     */
1538     public synchronized int
1539     getAudioOutputDeviceCount() throws IOException, LscpException, LSException {
1540     verifyConnection();
1541     out.writeLine("GET AUDIO_OUTPUT_DEVICES");
1542 iliev 1139 if(getPrintOnlyMode()) return -1;
1543    
1544 iliev 596 String s = getSingleLineResultSet().getResult();
1545     return parseInt(s);
1546     }
1547    
1548     /**
1549 iliev 784 * Gets a list of all created audio output devices.
1550     * @return An <code>AudioOutputDevice</code> array
1551     * providing all created audio output devices.
1552     * @throws IOException If some I/O error occurs.
1553     * @throws LscpException If LSCP protocol corruption occurs.
1554     * @throws LSException If some other error occurs.
1555     */
1556     public synchronized AudioOutputDevice[]
1557     getAudioOutputDevices() throws IOException, LscpException, LSException {
1558     Integer[] idS = getAudioOutputDeviceIDs();
1559 iliev 1139 if(getPrintOnlyMode()) return null;
1560    
1561 iliev 784 AudioOutputDevice[] devices = new AudioOutputDevice[idS.length];
1562    
1563     for(int i = 0; i < devices.length; i++)
1564     devices[i] = getAudioOutputDeviceInfo(idS[i]);
1565    
1566     return devices;
1567     }
1568    
1569     /**
1570 iliev 596 * Gets a list of numerical IDs of all created audio output devices.
1571 iliev 784 * @return An <code>Integer</code> array providing the numerical IDs of
1572 iliev 596 * all created audio output devices.
1573     * @throws IOException If some I/O error occurs.
1574     * @throws LscpException If LSCP protocol corruption occurs.
1575     * @throws LSException If some other error occurs.
1576     */
1577     public synchronized Integer[]
1578 iliev 784 getAudioOutputDeviceIDs() throws IOException, LscpException, LSException {
1579 iliev 596 verifyConnection();
1580     out.writeLine("LIST AUDIO_OUTPUT_DEVICES");
1581 iliev 1139 if(getPrintOnlyMode()) return null;
1582    
1583 iliev 596 return parseIntList(getSingleLineResultSet().getResult());
1584     }
1585    
1586     /**
1587     * Gets the current settings of a specific, already created audio output device.
1588     *
1589 iliev 1139 * @param deviceId Specifies the numerical ID of the audio output device.
1590 iliev 596 *
1591     * @return An <code>AudioOutputDevice</code> instance containing information
1592     * about the specified device.
1593     *
1594     * @throws IOException If some I/O error occurs.
1595     * @throws LscpException If LSCP protocol corruption occurs.
1596     * @throws LSException If there is no audio output device
1597 iliev 1139 * with device id <code>deviceId</code>.
1598 iliev 596 *
1599     * @see #getAudioOutputDevices
1600     */
1601     public synchronized AudioOutputDevice
1602 iliev 1139 getAudioOutputDeviceInfo(int deviceId) throws IOException, LscpException, LSException {
1603 iliev 596 verifyConnection();
1604 iliev 1139 out.writeLine("GET AUDIO_OUTPUT_DEVICE INFO " + deviceId);
1605     if(getPrintOnlyMode()) return null;
1606 iliev 596
1607     ResultSet rs = getMultiLineResultSet();
1608    
1609     String[] lnS = rs.getMultiLineResult();
1610    
1611     AudioOutputDevice aod = new AudioOutputDevice();
1612 iliev 1139 aod.setDeviceId(deviceId);
1613 iliev 596 Parameter<Integer> channels;
1614     Parameter<Integer> samplerate;
1615    
1616     String drv = getCategoryInfo(lnS, "DRIVER");
1617     aod.setDriverName(drv);
1618    
1619     for(String s : lnS) {
1620     if(s.startsWith("CHANNELS: ")) {
1621     channels = (Parameter<Integer>)
1622     getAudioOutputDriverParameterInfo(drv, "CHANNELS");
1623    
1624     s = s.substring("CHANNELS: ".length(), s.length());
1625     channels.parseValue(s);
1626     aod.setChannelsParameter(channels);
1627 iliev 784 int count = channels.getValue() > 0 ? channels.getValue() : 0;
1628     AudioOutputChannel[] aoc = new AudioOutputChannel[count];
1629     for(int i = 0; i < count; i++) {
1630 iliev 1139 aoc[i] = getAudioOutputChannelInfo(deviceId, i);
1631 iliev 784 }
1632     aod.setAudioChannels(aoc);
1633 iliev 596 } else if(s.startsWith("SAMPLERATE: ")) {
1634     samplerate = (Parameter<Integer>)
1635     getAudioOutputDriverParameterInfo(drv, "SAMPLERATE");
1636    
1637     s = s.substring("SAMPLERATE: ".length(), s.length());
1638     samplerate.parseValue(s);
1639     aod.setSampleRateParameter(samplerate);
1640     } else if(s.startsWith("ACTIVE: ")) {
1641     s = s.substring("ACTIVE: ".length(), s.length());
1642     aod.setActive(Boolean.parseBoolean(s));
1643     } else if(s.startsWith("DRIVER: ")) {
1644    
1645     } else {
1646     int i = s.indexOf(": ");
1647     if(i == -1) throw new LscpException (
1648     LscpI18n.getLogMsg("CommandFailed!")
1649     );
1650    
1651     Parameter prm =
1652     getAudioOutputDriverParameterInfo(drv, s.substring(0, i));
1653    
1654     s = s.substring(i + 2);
1655     prm.parseValue(s);
1656    
1657     aod.addParameter(prm);
1658     }
1659     }
1660    
1661     return aod;
1662     }
1663    
1664     /**
1665     * Alters a specific setting of a created audio output device.
1666     *
1667 iliev 1139 * @param deviceId The numerical ID of the audio output device.
1668 iliev 596 * @param prm A <code>Parameter</code> instance containing the name of the parameter
1669     * and the new value for this parameter.
1670     *
1671     * @throws IOException If some I/O error occurs.
1672     * @throws LscpException If LSCP protocol corruption occurs.
1673     * @throws LSException If
1674     * <ul>
1675 iliev 1139 * <li>There is no audio output device with numerical ID <code>deviceId</code>;
1676 iliev 596 * <li>There is no device parameter with the specified name;
1677     * <li>The device parameter is readonly;
1678     * <li>The device parameter is from different type.
1679     * </ul>
1680     *
1681     * @see #getAudioOutputDevices
1682     * @see #getAudioOutputDeviceInfo
1683     */
1684     public synchronized void
1685 iliev 1139 setAudioOutputDeviceParameter(int deviceId, Parameter prm)
1686 iliev 596 throws IOException, LscpException, LSException {
1687    
1688     verifyConnection();
1689     String kv = prm.getName() + '=' + prm.getStringValue();
1690 iliev 1139 out.writeLine("SET AUDIO_OUTPUT_DEVICE_PARAMETER " + deviceId + ' ' + kv);
1691     if(getPrintOnlyMode()) return;
1692 iliev 596
1693     ResultSet rs = getEmptyResultSet();
1694     }
1695    
1696     /**
1697 iliev 1139 * Changes the channel number of the speicifed audio output device.
1698     * @param deviceId The numerical ID of the audio output device.
1699 iliev 784 * @param channels The new number of audio output channels.
1700     *
1701     * @throws IOException If an I/O error occurs.
1702     * @throws LscpException If LSCP protocol corruption occurs.
1703 iliev 1139 * @throws LSException If there is no device with ID <code>deviceId</code> or
1704 iliev 784 * if <code>channels</code> number is out of range.
1705     *
1706     * @see #getAudioOutputChannelInfo
1707     */
1708     public synchronized void
1709 iliev 1139 setAudioOutputChannelCount(int deviceId, int channels)
1710 iliev 784 throws IOException, LscpException, LSException {
1711    
1712 iliev 1139 setAudioOutputDeviceParameter(deviceId, new IntParameter("CHANNELS", channels));
1713 iliev 784 }
1714    
1715     /**
1716 iliev 596 * Gets information about an audio channel.
1717     *
1718 iliev 1139 * @param deviceId The numerical ID of the audio output device.
1719 iliev 596 * @param audioChn The audio channel number.
1720     *
1721     * @return An <code>AudioOutputChannel</code> instance containing the
1722     * information about the specified audio output channel.
1723     *
1724     * @throws IOException If some I/O error occurs.
1725     * @throws LscpException If LSCP protocol corruption occurs.
1726     * @throws LSException If
1727     * <ul>
1728 iliev 1139 * <li>There is no audio output device with numerical ID <code>deviceId</code>;
1729 iliev 596 * <li><code>audioChn</code> is not a valid channel number;
1730     * </ul>
1731     *
1732     * @see #getAudioOutputDevices
1733     * @see #getAudioOutputDeviceInfo
1734     */
1735     public synchronized AudioOutputChannel
1736 iliev 1139 getAudioOutputChannelInfo(int deviceId, int audioChn)
1737 iliev 596 throws IOException, LscpException, LSException {
1738    
1739     verifyConnection();
1740 iliev 1139 out.writeLine("GET AUDIO_OUTPUT_CHANNEL INFO " + deviceId + ' ' + audioChn);
1741     if(getPrintOnlyMode()) return null;
1742 iliev 596
1743     ResultSet rs = getMultiLineResultSet();
1744    
1745     AudioOutputChannel aoc = new AudioOutputChannel();
1746    
1747     String[] lnS = rs.getMultiLineResult();
1748     for(String s : lnS) {
1749     if(s.startsWith("NAME: ")) {
1750 iliev 784 s = s.substring("NAME: ".length());
1751     Parameter<String> prm = getAudioOutputChannelParameterInfo (
1752 iliev 1139 deviceId, audioChn, "NAME"
1753 iliev 784 );
1754     prm.setValue(removeQuotation(s));
1755     aoc.setNameParameter(prm);
1756 iliev 596 } else if(s.startsWith("IS_MIX_CHANNEL: ")) {
1757     s = s.substring("IS_MIX_CHANNEL: ".length());
1758 iliev 784 Parameter<Boolean> prm = getAudioOutputChannelParameterInfo (
1759 iliev 1139 deviceId, audioChn, "IS_MIX_CHANNEL"
1760 iliev 784 );
1761     prm.setValue(Boolean.parseBoolean(s));
1762     aoc.setMixChannelParameter(prm);
1763 iliev 596 } else if(s.startsWith("MIX_CHANNEL_DESTINATION: ")) {
1764     s = s.substring("MIX_CHANNEL_DESTINATION: ".length());
1765 iliev 784 Parameter<Integer> prm = getAudioOutputChannelParameterInfo (
1766 iliev 1139 deviceId, audioChn, "MIX_CHANNEL_DESTINATION"
1767 iliev 784 );
1768     prm.setValue(parseInt(s));
1769     aoc.setMixChannelDestParameter(prm);
1770 iliev 596 } else {
1771     int i = s.indexOf(": ");
1772     if(i == -1) throw new LscpException (
1773     LscpI18n.getLogMsg("CommandFailed!")
1774     );
1775    
1776     Parameter prm = getAudioOutputChannelParameterInfo (
1777 iliev 1139 deviceId, audioChn, s.substring(0, i)
1778 iliev 596 );
1779    
1780     s = s.substring(i + 2);
1781     prm.parseValue(s);
1782    
1783     aoc.addParameter(prm);
1784     }
1785     }
1786    
1787     return aoc;
1788     }
1789    
1790     /**
1791     * Gets detailed information about a specific audio output channel parameter.
1792     *
1793 iliev 1139 * @param devId The numerical ID of the audio output device.
1794 iliev 596 * @param chan The audio channel number.
1795     * @param param a specific channel parameter name for which information should be obtained.
1796     *
1797     * @return An <code>Parameter</code> instance containing
1798     * information about the specified audio output channel parameter.
1799     *
1800     * @throws IOException If an I/O error occurs.
1801     * @throws LscpException If LSCP protocol corruption occurs.
1802     * @throws LSException If
1803     * <ul>
1804 iliev 1139 * <li><code>devId</code> is not a valid device ID;
1805 iliev 596 * <li><code>chan</code> is not a valid channel number;
1806     * <li>There is no channel parameter with the specified name.
1807     * </ul>
1808     *
1809     * @see #getAudioOutputDevices
1810     * @see #getAudioOutputChannelInfo
1811     */
1812     public synchronized Parameter
1813 iliev 1139 getAudioOutputChannelParameterInfo(int devId, int chan, String param)
1814 iliev 596 throws IOException, LscpException, LSException {
1815    
1816     verifyConnection();
1817 iliev 1139 String args = devId + " " + chan + " " + param;
1818 iliev 596 out.writeLine("GET AUDIO_OUTPUT_CHANNEL_PARAMETER INFO " + args);
1819 iliev 1139 if(getPrintOnlyMode()) return null;
1820 iliev 596
1821     ResultSet rs = getMultiLineResultSet();
1822    
1823     String[] lnS = rs.getMultiLineResult();
1824     ParameterType type = parseType(lnS);
1825     boolean multi = parseMultiplicity(lnS);
1826     Parameter prm;
1827    
1828     switch(type) {
1829     case BOOL:
1830     if(!multi) prm = new BoolParameter(lnS);
1831     else prm = new BoolListParameter(lnS);
1832     prm.setName(param);
1833     return prm;
1834     case INT:
1835     if(!multi) prm = new IntParameter(lnS);
1836     else prm = new IntListParameter(lnS);
1837     prm.setName(param);
1838     return prm;
1839     case FLOAT:
1840     if(!multi) prm = new FloatParameter(lnS);
1841     else prm = new FloatListParameter(lnS);
1842     prm.setName(param);
1843     return prm;
1844     case STRING:
1845     if(!multi) prm = new StringParameter(lnS);
1846     else prm = new StringListParameter(lnS);
1847     prm.setName(param);
1848     return prm;
1849     default: throw new LscpException(LscpI18n.getLogMsg("Client.unknownPrmType!"));
1850     }
1851     }
1852    
1853     /**
1854     * Alters a specific setting of an audio output channel.
1855     *
1856 iliev 1139 * @param devId The numerical ID of the audio device.
1857 iliev 596 * @param chn The audio channel number.
1858     * @param prm A <code>Parameter</code> instance containing the name of the parameter
1859     * and the new value for this parameter.
1860     *
1861     * @throws IOException If some I/O error occurs.
1862     * @throws LscpException If LSCP protocol corruption occurs.
1863     * @throws LSException If
1864     * <ul>
1865 iliev 1139 * <li>There is no audio output device with numerical ID <code>devId</code>;
1866 iliev 596 * <li><code>chn</code> is not a valid channel number;
1867     * <li>There is no channel parameter with the specified name;
1868     * <li>The channel parameter is readonly;
1869     * <li>The channel parameter is from different type.
1870     * </ul>
1871     *
1872     * @see #getAudioOutputDevices
1873     * @see #getAudioOutputChannelInfo
1874     */
1875     public synchronized void
1876 iliev 1139 setAudioOutputChannelParameter(int devId, int chn, Parameter prm)
1877 iliev 596 throws IOException, LscpException, LSException {
1878    
1879     verifyConnection();
1880 iliev 1139 String args = devId + " " + chn + " " + prm.getName() + '=' + prm.getStringValue();
1881 iliev 596 out.writeLine("SET AUDIO_OUTPUT_CHANNEL_PARAMETER " + args);
1882 iliev 1139 if(getPrintOnlyMode()) return;
1883 iliev 596
1884     ResultSet rs = getEmptyResultSet();
1885     }
1886    
1887     /**
1888     * Gets the current number of all MIDI input drivers.
1889     * @return The current number of all MIDI input drivers.
1890     * @throws IOException If some I/O error occurs.
1891     * @throws LscpException If LSCP protocol corruption occurs.
1892     * @throws LSException If some other error occurs.
1893     */
1894     public synchronized int
1895     getMidiInputDriverCount() throws IOException, LscpException, LSException {
1896     verifyConnection();
1897     out.writeLine("GET AVAILABLE_MIDI_INPUT_DRIVERS");
1898 iliev 1139 if(getPrintOnlyMode()) return -1;
1899    
1900 iliev 596 String s = getSingleLineResultSet().getResult();
1901     return parseInt(s);
1902     }
1903    
1904     /**
1905     * Gets all MIDI input drivers currently available for the LinuxSampler instance.
1906     *
1907 iliev 671 * @return <code>MidiInputDriver</code> array containing all MIDI input drivers currently
1908     * available for the LinuxSampler instance.
1909 iliev 596 *
1910     * @throws IOException If an I/O error occurs.
1911     * @throws LscpException If LSCP protocol corruption occurs.
1912     * @throws LSException If some other error occurs.
1913     */
1914 iliev 671 public synchronized MidiInputDriver[]
1915 iliev 596 getMidiInputDrivers() throws IOException, LscpException, LSException {
1916 iliev 671 String[] drivers = getMidiInputDriverNames();
1917 iliev 1139 if(getPrintOnlyMode()) return null;
1918    
1919 iliev 671 MidiInputDriver[] mid = new MidiInputDriver[drivers.length];
1920    
1921     for(int i = 0; i < mid.length; i++) mid[i] = getMidiInputDriverInfo(drivers[i]);
1922    
1923     return mid;
1924     }
1925    
1926     /**
1927     * Gets all MIDI input drivers currently available for the LinuxSampler instance.
1928     *
1929     * @return <code>String</code> array containing all MIDI input drivers currently available
1930     * for the LinuxSampler instance.
1931     *
1932     * @throws IOException If an I/O error occurs.
1933     * @throws LscpException If LSCP protocol corruption occurs.
1934     * @throws LSException If some other error occurs.
1935     */
1936     private synchronized String[]
1937     getMidiInputDriverNames() throws IOException, LscpException, LSException {
1938 iliev 596 verifyConnection();
1939     out.writeLine("LIST AVAILABLE_MIDI_INPUT_DRIVERS");
1940 iliev 1139 if(getPrintOnlyMode()) return null;
1941    
1942 iliev 596 return parseList(getSingleLineResultSet().getResult());
1943     }
1944    
1945     /**
1946     * Gets detailed information about a specific MIDI input driver.
1947     * @param driverName The name of the MIDI input driver.
1948 iliev 1326 * @param depList An optional list of dependences parameters.
1949 iliev 671 * @return A <code>MidiInputDriver</code> object containing
1950 iliev 596 * information about the specified MIDI input driver.
1951     *
1952     * @throws IOException If an I/O error occurs.
1953     * @throws LscpException If LSCP protocol corruption occurs.
1954     * @throws LSException If there is no driver with name <code>driverName</code>.
1955     *
1956 iliev 671 * @see #getMidiInputDriverNames
1957 iliev 596 */
1958 iliev 1326 public synchronized MidiInputDriver
1959     getMidiInputDriverInfo(String driverName, Parameter... depList)
1960     throws IOException, LscpException, LSException {
1961    
1962 iliev 596 verifyConnection();
1963     out.writeLine("GET MIDI_INPUT_DRIVER INFO " + driverName);
1964 iliev 1139 if(getPrintOnlyMode()) return null;
1965    
1966 iliev 596 ResultSet rs = getMultiLineResultSet();
1967    
1968     MidiInputDriver mid = new MidiInputDriver(rs.getMultiLineResult());
1969     mid.setName(driverName);
1970    
1971     for(String s : mid.getParameterNames())
1972 iliev 1326 mid.addParameter(getMidiInputDriverParameterInfo(driverName, s, depList));
1973 iliev 596
1974     return mid;
1975     }
1976    
1977     /**
1978     * Gets detailed information about a specific MIDI input driver parameter.
1979     *
1980     * @param driver The name of the MIDI input driver.
1981     * @param param a specific parameter name for which information should be obtained.
1982     * @param deplist An optional list of parameters on which the sought parameter
1983     * <code>param</code> depends on. <code>Parameter</code> instances can be
1984     * easily created using {@link ParameterFactory} factory.
1985     *
1986 iliev 671 * @return A <code>Parameter</code> object containing
1987 iliev 596 * information about the specified MIDI input driver parameter.
1988     *
1989     * @throws IOException If an I/O error occurs.
1990     * @throws LscpException If LSCP protocol corruption occurs.
1991     * @throws LSException If <code>driver</code> is not a valid driver name
1992     * or <code>param</code> is not a valid parameter for the specified driver.
1993     *
1994     * @see #getMidiInputDrivers
1995     * @see #getMidiInputDriverInfo
1996     * @see ParameterFactory
1997     */
1998     public synchronized Parameter
1999     getMidiInputDriverParameterInfo(String driver, String param, Parameter... deplist)
2000     throws IOException, LscpException, LSException {
2001    
2002     verifyConnection();
2003     StringBuffer args = new StringBuffer(driver);
2004     args.append(' ').append(param);
2005    
2006 iliev 1326 for(Parameter p : deplist) {
2007     if(p.getValue() == null) continue;
2008 iliev 596 args.append(' ').append(p.getName()).append('=').append(p.getStringValue());
2009 iliev 1326 }
2010 iliev 596
2011     out.writeLine("GET MIDI_INPUT_DRIVER_PARAMETER INFO " + args.toString());
2012 iliev 1139 if(getPrintOnlyMode()) return null;
2013 iliev 596
2014     ResultSet rs = getMultiLineResultSet();
2015    
2016     String[] lnS = rs.getMultiLineResult();
2017     ParameterType type = parseType(lnS);
2018     boolean multi = parseMultiplicity(lnS);
2019     Parameter prm;
2020    
2021     switch(type) {
2022     case BOOL:
2023     if(!multi) prm = new BoolParameter(lnS);
2024     else prm = new BoolListParameter(lnS);
2025     prm.setName(param);
2026 iliev 784 prm.setValue(prm.getDefault());
2027 iliev 596 return prm;
2028     case INT:
2029     if(!multi) prm = new IntParameter(lnS);
2030     else prm = new IntListParameter(lnS);
2031     prm.setName(param);
2032 iliev 784 prm.setValue(prm.getDefault());
2033 iliev 596 return prm;
2034     case FLOAT:
2035     if(!multi) prm = new FloatParameter(lnS);
2036     else prm = new FloatListParameter(lnS);
2037     prm.setName(param);
2038 iliev 784 prm.setValue(prm.getDefault());
2039 iliev 596 return prm;
2040     case STRING:
2041     if(!multi) prm = new StringParameter(lnS);
2042     else prm = new StringListParameter(lnS);
2043     prm.setName(param);
2044 iliev 784 prm.setValue(prm.getDefault());
2045 iliev 596 return prm;
2046     default: throw new LscpException(LscpI18n.getLogMsg("Client.unknownPrmType!"));
2047     }
2048     }
2049    
2050     /**
2051     * Creates a new MIDI input device.
2052     * @param miDriver The desired MIDI input system.
2053     * @param paramList An optional list of driver specific parameters. <code>Parameter</code>
2054     * instances can be easily created using {@link ParameterFactory} factory.
2055     * @return The numerical ID of the newly created device.
2056     * @throws IOException If some I/O error occurs.
2057     * @throws LSException If the creation of the new MIDI input device failed.
2058     * @throws LscpException If LSCP protocol corruption occurs.
2059     *
2060     * @see #getMidiInputDrivers
2061     * @see #getMidiInputDriverInfo
2062     * @see ParameterFactory
2063     */
2064     public synchronized int
2065     createMidiInputDevice(String miDriver, Parameter... paramList)
2066     throws IOException, LSException, LscpException {
2067    
2068     verifyConnection();
2069     StringBuffer args = new StringBuffer(miDriver);
2070    
2071 iliev 1326 for(Parameter p : paramList) {
2072     if(p.getValue() == null) continue;
2073 iliev 596 args.append(' ').append(p.getName()).append('=').append(p.getStringValue());
2074 iliev 1326 }
2075 iliev 596
2076     out.writeLine("CREATE MIDI_INPUT_DEVICE " + args.toString());
2077 iliev 1139 if(getPrintOnlyMode()) return -1;
2078    
2079 iliev 596 ResultSet rs = getEmptyResultSet();
2080    
2081     return rs.getIndex();
2082     }
2083    
2084     /**
2085     * Destroys already created MIDI input device.
2086 iliev 1139 * @param deviceId The numerical ID of the MIDI input device to be destroyed.
2087 iliev 596 * @throws IOException If some I/O error occurs.
2088     * @throws LSException If the destroying of the MIDI input device failed.
2089     * @throws LscpException If LSCP protocol corruption occurs.
2090     * @see #createMidiInputDevice
2091     * @see #getMidiInputDevices
2092     */
2093     public synchronized void
2094 iliev 1139 destroyMidiInputDevice(int deviceId) throws IOException, LSException, LscpException {
2095 iliev 596 verifyConnection();
2096 iliev 1139 out.writeLine("DESTROY MIDI_INPUT_DEVICE " + deviceId);
2097     if(getPrintOnlyMode()) return;
2098    
2099 iliev 596 ResultSet rs = getEmptyResultSet();
2100     }
2101    
2102 iliev 784 /**
2103     * Enables/disables the specified MIDI input device.
2104 iliev 1139 * @param deviceId The ID of the MIDI input device to be enabled/disabled.
2105 iliev 784 * @param enable If <code>true</code> the MIDI input device is enabled,
2106     * else the device is disabled.
2107     * @throws IOException If some I/O error occurs.
2108     * @throws LSException If there is no MIDI input
2109 iliev 1139 * device with numerical ID <code>deviceId</code>.
2110 iliev 784 * @throws LscpException If LSCP protocol corruption occurs.
2111     */
2112     public void
2113 iliev 1139 enableMidiInputDevice(int deviceId, boolean enable)
2114 iliev 784 throws IOException, LSException, LscpException {
2115    
2116 iliev 1139 setMidiInputDeviceParameter(deviceId, new BoolParameter("ACTIVE", enable));
2117 iliev 784 }
2118    
2119 iliev 596 /**
2120     * Gets the current number of all created MIDI input devices.
2121     * @return The current number of all created MIDI input devices.
2122     * @throws IOException If some I/O error occurs.
2123     * @throws LscpException If LSCP protocol corruption occurs.
2124     * @throws LSException If some other error occurs.
2125     */
2126     public synchronized int
2127     getMidiInputDeviceCount() throws IOException, LscpException, LSException {
2128     verifyConnection();
2129     out.writeLine("GET MIDI_INPUT_DEVICES");
2130 iliev 1139 if(getPrintOnlyMode()) return -1;
2131    
2132 iliev 596 String s = getSingleLineResultSet().getResult();
2133     return parseInt(s);
2134     }
2135    
2136     /**
2137 iliev 784 * Gets a list of all created MIDI input devices.
2138     * @return A <code>MidiInputDevice</code> array
2139     * providing all created MIDI input devices.
2140     * @throws IOException If some I/O error occurs.
2141     * @throws LscpException If LSCP protocol corruption occurs.
2142     * @throws LSException If some other error occurs.
2143     *
2144     * @see #createMidiInputDevice
2145     * @see #destroyMidiInputDevice
2146     */
2147     public synchronized MidiInputDevice[]
2148     getMidiInputDevices() throws IOException, LscpException, LSException {
2149     Integer[] idS = getMidiInputDeviceIDs();
2150 iliev 1139 if(getPrintOnlyMode()) return null;
2151    
2152 iliev 784 MidiInputDevice[] devices = new MidiInputDevice[idS.length];
2153    
2154     for(int i = 0; i < devices.length; i++)
2155     devices[i] = getMidiInputDeviceInfo(idS[i]);
2156    
2157     return devices;
2158     }
2159    
2160     /**
2161 iliev 596 * Gets a list of numerical IDs of all created MIDI input devices.
2162 iliev 784 * @return An <code>Integer</code> array providing the numerical IDs of
2163 iliev 596 * all created MIDI input devices.
2164     * @throws IOException If some I/O error occurs.
2165     * @throws LscpException If LSCP protocol corruption occurs.
2166     * @throws LSException If some other error occurs.
2167     *
2168     * @see #createMidiInputDevice
2169     * @see #destroyMidiInputDevice
2170     */
2171     public synchronized Integer[]
2172 iliev 784 getMidiInputDeviceIDs() throws IOException, LscpException, LSException {
2173 iliev 596 verifyConnection();
2174     out.writeLine("LIST MIDI_INPUT_DEVICES");
2175 iliev 1139 if(getPrintOnlyMode()) return null;
2176    
2177 iliev 596 return parseIntList(getSingleLineResultSet().getResult());
2178     }
2179    
2180     /**
2181     * Gets the current settings of a specific, already created MIDI input device.
2182     *
2183 iliev 1139 * @param deviceId Specifies the numerical ID of the MIDI input device.
2184 iliev 596 *
2185 iliev 1139 * @return A <code>MidiInputDevice</code> instance containing information
2186 iliev 596 * about the specified device.
2187     *
2188     * @throws IOException If some I/O error occurs.
2189     * @throws LscpException If LSCP protocol corruption occurs.
2190     * @throws LSException If there is no MIDI input device
2191 iliev 1139 * with device id <code>deviceId</code>.
2192 iliev 596 *
2193     * @see #getMidiInputDevices
2194     */
2195     public synchronized MidiInputDevice
2196 iliev 1139 getMidiInputDeviceInfo(int deviceId) throws IOException, LscpException, LSException {
2197 iliev 596 verifyConnection();
2198 iliev 1139 out.writeLine("GET MIDI_INPUT_DEVICE INFO " + deviceId);
2199     if(getPrintOnlyMode()) return null;
2200 iliev 596
2201     ResultSet rs = getMultiLineResultSet();
2202    
2203     String[] lnS = rs.getMultiLineResult();
2204    
2205     MidiInputDevice mid = new MidiInputDevice();
2206 iliev 1139 mid.setDeviceId(deviceId);
2207 iliev 596
2208     String drv = getCategoryInfo(lnS, "DRIVER");
2209     mid.setDriverName(drv);
2210    
2211     for(String s : lnS) {
2212     if(s.startsWith("DRIVER: ")) {
2213    
2214     } else if(s.startsWith("ACTIVE: ")) {
2215     s = s.substring("ACTIVE: ".length());
2216     mid.setActive(Boolean.parseBoolean(s));
2217 iliev 784 } else if(s.startsWith("PORTS: ")) {
2218     s = s.substring("PORTS: ".length());
2219    
2220 iliev 1494 Parameter<Integer> ports = (Parameter<Integer>)
2221     getMidiInputDriverParameterInfo(drv, "PORTS");
2222    
2223     ports.parseValue(s);
2224     mid.setPortsParameter(ports);
2225    
2226     int j = ports.getValue();
2227     MidiPort[] midiPorts = new MidiPort[j > 0 ? j : 0];
2228    
2229 iliev 784 for(int i = 0; i < midiPorts.length; i++)
2230 iliev 1139 midiPorts[i] = getMidiInputPortInfo(deviceId, i);
2231 iliev 784
2232     mid.setMidiPorts(midiPorts);
2233 iliev 596 } else {
2234     int i = s.indexOf(": ");
2235     if(i == -1) throw new LscpException (
2236     LscpI18n.getLogMsg("CommandFailed!")
2237     );
2238    
2239     Parameter prm =
2240     getMidiInputDriverParameterInfo(drv, s.substring(0, i));
2241    
2242     s = s.substring(i + 2);
2243     prm.parseValue(s);
2244    
2245     mid.addParameter(prm);
2246     }
2247     }
2248    
2249     return mid;
2250     }
2251    
2252     /**
2253     * Alters a specific setting of a created MIDI input device.
2254     *
2255 iliev 1139 * @param deviceId The numerical ID of the MIDI input device.
2256 iliev 596 * @param prm A <code>Parameter</code> instance containing the name of the parameter
2257     * and the new value for this parameter.
2258     *
2259     * @throws IOException If some I/O error occurs.
2260     * @throws LscpException If LSCP protocol corruption occurs.
2261     * @throws LSException If
2262     * <ul>
2263 iliev 1139 * <li>There is no MIDI input device with numerical ID <code>deviceId</code>;
2264 iliev 596 * <li>There is no device parameter with the specified name;
2265     * <li>The device parameter is readonly;
2266     * <li>The device parameter is from different type.
2267     * </ul>
2268     *
2269     * @see #getMidiInputDevices
2270     * @see #getMidiInputDeviceInfo
2271     */
2272     public synchronized void
2273 iliev 1139 setMidiInputDeviceParameter(int deviceId, Parameter prm)
2274 iliev 596 throws IOException, LscpException, LSException {
2275    
2276     verifyConnection();
2277     String kv = prm.getName() + '=' + prm.getStringValue();
2278 iliev 1139 out.writeLine("SET MIDI_INPUT_DEVICE_PARAMETER " + deviceId + ' ' + kv);
2279     if(getPrintOnlyMode()) return;
2280 iliev 596
2281     ResultSet rs = getEmptyResultSet();
2282     }
2283    
2284 iliev 784
2285 iliev 596 /**
2286 iliev 1139 * Changes the port number of the speicified MIDI input device.
2287     * @param deviceId The numerical ID of the MIDI input device.
2288 iliev 784 * @param ports The new number of MIDI input ports.
2289     *
2290     * @throws IOException If an I/O error occurs.
2291     * @throws LscpException If LSCP protocol corruption occurs.
2292 iliev 1139 * @throws LSException If there is no device with ID <code>deviceId</code> or
2293 iliev 784 * if <code>ports</code> number is out of range.
2294     *
2295     * @see #getMidiInputPortInfo
2296     */
2297     public synchronized void
2298 iliev 1139 setMidiInputPortCount(int deviceId, int ports)
2299 iliev 784 throws IOException, LscpException, LSException {
2300    
2301 iliev 1139 setMidiInputDeviceParameter(deviceId, new IntParameter("PORTS", ports));
2302 iliev 784 }
2303    
2304     /**
2305 iliev 596 * Gets detailed information about a specific MIDI input port.
2306 iliev 1139 * @param deviceId The numerical ID of the MIDI input device.
2307 iliev 596 * @param midiPort The MIDI input port number.
2308     *
2309     * @return A <code>MidiPort</code> instance containing
2310     * information about the specified MIDI input port.
2311     *
2312     * @throws IOException If an I/O error occurs.
2313     * @throws LscpException If LSCP protocol corruption occurs.
2314 iliev 1139 * @throws LSException If there is no device with ID <code>deviceId</code> or
2315 iliev 596 * if <code>midiPort</code> is not a valid MIDI port number.
2316     *
2317     * @see #getMidiInputDevices
2318     */
2319     public synchronized MidiPort
2320 iliev 1139 getMidiInputPortInfo(int deviceId, int midiPort)
2321 iliev 596 throws IOException, LscpException, LSException {
2322    
2323     verifyConnection();
2324 iliev 1139 out.writeLine("GET MIDI_INPUT_PORT INFO " + deviceId + " " + midiPort);
2325     if(getPrintOnlyMode()) return null;
2326    
2327 iliev 596 ResultSet rs = getMultiLineResultSet();
2328    
2329     MidiPort mp = new MidiPort();
2330     String[] lnS = rs.getMultiLineResult();
2331    
2332     for(String s : lnS) {
2333     if(s.startsWith("NAME: ")) {
2334 iliev 784 s = s.substring("NAME: ".length());
2335     Parameter prm = getMidiInputPortParameterInfo (
2336 iliev 1139 deviceId, midiPort, "NAME"
2337 iliev 784 );
2338     prm.setValue(removeQuotation(s));
2339     mp.setNameParameter(prm);
2340 iliev 596 } else {
2341     int i = s.indexOf(": ");
2342     if(i == -1) throw new LscpException (
2343     LscpI18n.getLogMsg("CommandFailed!")
2344     );
2345    
2346     Parameter prm = getMidiInputPortParameterInfo (
2347 iliev 1139 deviceId, midiPort, s.substring(0, i)
2348 iliev 596 );
2349    
2350     s = s.substring(i + 2);
2351     prm.parseValue(s);
2352    
2353     mp.addParameter(prm);
2354     }
2355     }
2356    
2357     return mp;
2358     }
2359    
2360     /**
2361     * Gets detailed information about a specific MIDI input port parameter.
2362     *
2363 iliev 1139 * @param deviceId The numerical ID of the MIDI input device.
2364 iliev 596 * @param port The MIDI port number.
2365     * @param param A specific parameter name for which information should be obtained.
2366     *
2367     * @return A <code>Parameter</code> instance containing
2368     * information about the specified MIDI input port parameter.
2369     *
2370     * @throws IOException If an I/O error occurs.
2371     * @throws LscpException If LSCP protocol corruption occurs.
2372     * @throws LSException If
2373     * <ul>
2374 iliev 1139 * <li>There is no MIDI input device with numerical ID <code>deviceId</code>;
2375 iliev 596 * <li> <code>port</code> is not a valid MIDI port number;
2376     * <li><code>param</code> is not a valid parameter for the specified MIDI port.
2377     * </ul>
2378     *
2379     * @see #getMidiInputDevices
2380     * @see #getMidiInputPortInfo
2381     */
2382     public synchronized Parameter
2383 iliev 1139 getMidiInputPortParameterInfo(int deviceId, int port, String param)
2384 iliev 596 throws IOException, LscpException, LSException {
2385    
2386     verifyConnection();
2387 iliev 1139 String args = deviceId + " " + port + " " + param;
2388 iliev 596 out.writeLine("GET MIDI_INPUT_PORT_PARAMETER INFO " + args);
2389 iliev 1139 if(getPrintOnlyMode()) return null;
2390 iliev 596
2391     ResultSet rs = getMultiLineResultSet();
2392    
2393     String[] lnS = rs.getMultiLineResult();
2394     ParameterType type = parseType(lnS);
2395     boolean multi = parseMultiplicity(lnS);
2396     Parameter prm;
2397    
2398     switch(type) {
2399     case BOOL:
2400     if(!multi) prm = new BoolParameter(lnS);
2401     else prm = new BoolListParameter(lnS);
2402     prm.setName(param);
2403     return prm;
2404     case INT:
2405     if(!multi) prm = new IntParameter(lnS);
2406     else prm = new IntListParameter(lnS);
2407     prm.setName(param);
2408     return prm;
2409     case FLOAT:
2410     if(!multi) prm = new FloatParameter(lnS);
2411     else prm = new FloatListParameter(lnS);
2412     prm.setName(param);
2413     return prm;
2414     case STRING:
2415     if(!multi) prm = new StringParameter(lnS);
2416     else prm = new StringListParameter(lnS);
2417     prm.setName(param);
2418     return prm;
2419     default: throw new LscpException(LscpI18n.getLogMsg("Client.unknownPrmType!"));
2420     }
2421     }
2422    
2423     /**
2424     * Alters a specific setting of a MIDI input port.
2425     *
2426 iliev 1139 * @param deviceId The numerical ID of the MIDI device.
2427 iliev 596 * @param port The MIDI port number.
2428     * @param prm A <code>Parameter</code> instance containing the name of the parameter
2429     * and the new value for this parameter.
2430     *
2431     * @throws IOException If some I/O error occurs.
2432     * @throws LscpException If LSCP protocol corruption occurs.
2433     * @throws LSException If
2434     * <ul>
2435 iliev 1139 * <li>There is no MIDI device with numerical ID <code>deviceId</code>;
2436 iliev 596 * <li><code>port</code> is not a valid MIDI port number;
2437     * <li><code>prm</code> is not a valid parameter;
2438     * <li>The parameter is readonly;
2439     * <li>The parameter is from different type.
2440     * </ul>
2441     *
2442     * @see #getMidiInputDevices
2443     * @see #getMidiInputPortInfo
2444     */
2445     public synchronized void
2446 iliev 1139 setMidiInputPortParameter(int deviceId, int port, Parameter prm)
2447 iliev 596 throws IOException, LscpException, LSException {
2448    
2449     verifyConnection();
2450 iliev 1139 String args = deviceId + " " + port + " " +
2451 iliev 596 prm.getName() + '=' + prm.getStringValue();
2452     out.writeLine("SET MIDI_INPUT_PORT_PARAMETER " + args);
2453 iliev 1139 if(getPrintOnlyMode()) return;
2454 iliev 596
2455     ResultSet rs = getEmptyResultSet();
2456     }
2457    
2458     /**
2459 iliev 1139 * Adds a new MIDI instrument map.
2460     * @param name The name of this MIDI instrument map.
2461     * @return The number of the newly MIDI instrument map.
2462     * @throws IOException If some I/O error occurs.
2463     * @throws LSException If the creation of the new MIDI instrument map failed.
2464     * @throws LscpException If LSCP protocol corruption occurs.
2465     * @see #removeMidiInstrumentMap
2466     */
2467     public synchronized int
2468     addMidiInstrumentMap(String name) throws IOException, LSException, LscpException {
2469     verifyConnection();
2470 iliev 1393 out.writeLine("ADD MIDI_INSTRUMENT_MAP '" + toEscapedString(name) + "'");
2471 iliev 1139 if(getPrintOnlyMode()) return -1;
2472    
2473     ResultSet rs = getEmptyResultSet();
2474    
2475     return rs.getIndex();
2476     }
2477    
2478     /**
2479     * Removes the specified MIDI instrument map.
2480     * @param mapId The numerical ID of the MIDI instrument map to be removed.
2481     * @throws IOException If some I/O error occurs.
2482     * @throws LscpException If LSCP protocol corruption occurs.
2483     * @throws LSException If the removing of the MIDI instrument map failed.
2484     * @see #addMidiInstrumentMap
2485     * @see #getMidiInstrumentMapIDs
2486     */
2487     public synchronized void
2488     removeMidiInstrumentMap(int mapId) throws IOException, LscpException, LSException {
2489     verifyConnection();
2490     out.writeLine("REMOVE MIDI_INSTRUMENT_MAP " + mapId);
2491     if(getPrintOnlyMode()) return;
2492    
2493     ResultSet rs = getEmptyResultSet();
2494     }
2495    
2496     /**
2497     * Removes the all MIDI instrument maps.
2498     * @throws IOException If some I/O error occurs.
2499     * @throws LscpException If LSCP protocol corruption occurs.
2500     * @throws LSException If the removing of the MIDI instrument maps failed.
2501     */
2502     public synchronized void
2503     removeAllMidiInstrumentMaps() throws IOException, LscpException, LSException {
2504     verifyConnection();
2505     out.writeLine("REMOVE MIDI_INSTRUMENT_MAP ALL");
2506     if(getPrintOnlyMode()) return;
2507    
2508     ResultSet rs = getEmptyResultSet();
2509     }
2510    
2511     /**
2512     * Gets the current number of all MIDI instrument maps.
2513     * @return The current number of all MIDI instrument maps.
2514     * @throws IOException If some I/O error occurs.
2515     * @throws LscpException If LSCP protocol corruption occurs.
2516     * @throws LSException If some other error occurs.
2517     */
2518     public synchronized int
2519     getMidiInstrumentMapCount() throws IOException, LscpException, LSException {
2520     verifyConnection();
2521     out.writeLine("GET MIDI_INSTRUMENT_MAPS");
2522     if(getPrintOnlyMode()) return -1;
2523    
2524     String s = getSingleLineResultSet().getResult();
2525     return parseInt(s);
2526     }
2527    
2528     /**
2529     * Gets a list of numerical IDs of all created MIDI instrument maps.
2530     * @return An <code>Integer</code> array providing the numerical IDs of
2531     * all created MIDI instrument maps.
2532     * @throws IOException If some I/O error occurs.
2533     * @throws LscpException If LSCP protocol corruption occurs.
2534     * @throws LSException If some other error occurs.
2535     * @see #addMidiInstrumentMap
2536     * @see #removeMidiInstrumentMap
2537     */
2538     public synchronized Integer[]
2539     getMidiInstrumentMapIDs() throws IOException, LscpException, LSException {
2540     verifyConnection();
2541     out.writeLine("LIST MIDI_INSTRUMENT_MAPS");
2542     if(getPrintOnlyMode()) return null;
2543    
2544     return parseIntList(getSingleLineResultSet().getResult());
2545     }
2546    
2547     /**
2548     * Gets the current settings of a specific, already created MIDI instrument map.
2549     * @param mapId Specifies the numerical ID of the MIDI instrument map.
2550     * @return A <code>MidiInstrumentMapInfo</code> instance containing information
2551     * about the specified device.
2552     * @throws IOException If some I/O error occurs.
2553     * @throws LscpException If LSCP protocol corruption occurs.
2554     * @throws LSException If there is no MIDI instrument map
2555     * with map id <code>mapId</code>.
2556     * @see #getMidiInstrumentMaps
2557     */
2558     public synchronized MidiInstrumentMapInfo
2559     getMidiInstrumentMapInfo(int mapId) throws IOException, LscpException, LSException {
2560     verifyConnection();
2561     out.writeLine("GET MIDI_INSTRUMENT_MAP INFO " + mapId);
2562     if(getPrintOnlyMode()) return null;
2563    
2564     ResultSet rs = getMultiLineResultSet();
2565    
2566     String[] lnS = rs.getMultiLineResult();
2567    
2568     String name = "";
2569     boolean b = false;
2570    
2571     for(String s : lnS) {
2572     if(s.startsWith("NAME: ")) {
2573 iliev 1421 name = toNonEscapedString(s.substring("NAME: ".length()));
2574 iliev 1139 } else if(s.startsWith("DEFAULT: ")) {
2575     b = Boolean.parseBoolean(s.substring("DEFAULT: ".length()));
2576     } else {
2577     getLogger().info(LscpI18n.getLogMsg("unknownLine", s));
2578     }
2579     }
2580    
2581     return new MidiInstrumentMapInfo(mapId, name, b);
2582     }
2583    
2584     /**
2585     * Gets an information of all created MIDI instrument maps.
2586     * @return A <code>MidiInstrumentMap</code> array
2587     * providing information for all created MIDI instrument maps.
2588     * @throws IOException If some I/O error occurs.
2589     * @throws LscpException If LSCP protocol corruption occurs.
2590     * @throws LSException If some other error occurs.
2591     * @see #addMidiInstrumentMap
2592     * @see #removeMidiInstrumentMap
2593     */
2594     public synchronized MidiInstrumentMapInfo[]
2595     getMidiInstrumentMaps() throws IOException, LscpException, LSException {
2596     Integer[] idS = getMidiInstrumentMapIDs();
2597     if(getPrintOnlyMode()) return null;
2598    
2599     MidiInstrumentMapInfo[] maps = new MidiInstrumentMapInfo[idS.length];
2600    
2601     for(int i = 0; i < maps.length; i++)
2602     maps[i] = getMidiInstrumentMapInfo(idS[i]);
2603    
2604     return maps;
2605     }
2606    
2607     /**
2608     * Sets the name of the specified MIDI instrument map.
2609     * @param mapId The numerical ID of the MIDI instrument map.
2610     * @param name The new name for the specified MIDI instrument map.
2611     * @throws IOException If some I/O error occurs.
2612     * @throws LscpException If LSCP protocol corruption occurs.
2613     * @throws LSException If <code>mapId</code> is not a valid MIDI
2614     * instrument map number or <code>name</code> is not a valid name;
2615     */
2616     public synchronized void
2617     setMidiInstrumentMapName(int mapId, String name)
2618     throws IOException, LscpException, LSException {
2619    
2620     verifyConnection();
2621 iliev 1393 name = toEscapedString(name);
2622 iliev 1139 out.writeLine("SET MIDI_INSTRUMENT_MAP NAME " + + mapId + " '" + name + "'");
2623     if(getPrintOnlyMode()) return;
2624    
2625     ResultSet rs = getEmptyResultSet();
2626     }
2627    
2628 iliev 1202
2629    
2630 iliev 1139 /**
2631     * Creates or replaces a MIDI instrument map entry.
2632     * @param mapId The ID of the map, where this instrument should be mapped.
2633     * @param entry Specifies the position of the MIDI instrument in the MIDI instrument map.
2634     * @param info Provides the needed information of the
2635     * MIDI instrument, which will be mapped to the specified MIDI instrument map.
2636     * @throws IOException If some I/O error occurs.
2637     * @throws LSException If the mapping failed.
2638     * @throws LscpException If LSCP protocol corruption occurs.
2639     * @see #unmapMidiInstrument
2640     */
2641     public synchronized void
2642     mapMidiInstrument(int mapId, MidiInstrumentEntry entry, MidiInstrumentInfo info)
2643     throws IOException, LSException, LscpException {
2644 iliev 1202 mapMidiInstrument(mapId, entry, info, false);
2645     }
2646    
2647     /**
2648     * Creates or replaces a MIDI instrument map entry.
2649     * @param mapId The ID of the map, where this instrument should be mapped.
2650     * @param entry Specifies the position of the MIDI instrument in the MIDI instrument map.
2651     * @param info Provides the needed information of the
2652     * MIDI instrument, which will be mapped to the specified MIDI instrument map.
2653     * @param nonModal If <code>true</code> the function returns immediately
2654     * and the mapping is established in the background.
2655     * @throws IOException If some I/O error occurs.
2656     * @throws LSException If the mapping failed.
2657     * @throws LscpException If LSCP protocol corruption occurs.
2658     * @see #unmapMidiInstrument
2659     */
2660     public synchronized void
2661     mapMidiInstrument(int mapId, MidiInstrumentEntry entry, MidiInstrumentInfo info, boolean nonModal)
2662     throws IOException, LSException, LscpException {
2663 iliev 1139
2664     verifyConnection();
2665     StringBuffer cmd = new StringBuffer("MAP MIDI_INSTRUMENT ");
2666 iliev 1202 if(nonModal) cmd.append("NON_MODAL ");
2667 iliev 1139 cmd.append(mapId).append(' ');
2668     cmd.append(entry.getMidiBank()).append(' ');
2669     cmd.append(entry.getMidiProgram()).append(' ');
2670     cmd.append(info.getEngine()).append(" '");
2671 iliev 1202 cmd.append(info.getFilePath()).append("' ");
2672 iliev 1139 cmd.append(info.getInstrumentIndex()).append(' ');
2673     cmd.append(info.getVolume());
2674     if(!info.getLoadMode().name().equals("DEFAULT")) {
2675     cmd.append(' ').append(info.getLoadMode().name());
2676     }
2677    
2678 iliev 1393 if(info.getName() != null) {
2679     String s = toEscapedString(info.getName());
2680     cmd.append(" '").append(s).append("'");
2681     }
2682    
2683 iliev 1139 out.writeLine(cmd.toString());
2684     if(getPrintOnlyMode()) return;
2685    
2686     ResultSet rs = getEmptyResultSet();
2687     }
2688    
2689     /**
2690     * Removes an entry MIDI instrument map.
2691     * @param mapId The ID of the map, from which
2692     * the specified MIDI instrument should be removed.
2693     * @param entry The entry to remove from the specified MIDI instrument map.
2694     * @throws IOException If some I/O error occurs.
2695     * @throws LSException If the unmapping failed.
2696     * @throws LscpException If LSCP protocol corruption occurs.
2697     * @see #mapMidiInstrument
2698     */
2699     public synchronized void
2700     unmapMidiInstrument(int mapId, MidiInstrumentEntry entry)
2701     throws IOException, LSException, LscpException {
2702    
2703     verifyConnection();
2704     StringBuffer cmd = new StringBuffer("UNMAP MIDI_INSTRUMENT ");
2705     cmd.append(mapId).append(' ');
2706     cmd.append(entry.getMidiBank()).append(' ');
2707     cmd.append(entry.getMidiProgram());
2708    
2709     out.writeLine(cmd.toString());
2710     if(getPrintOnlyMode()) return;
2711    
2712     ResultSet rs = getEmptyResultSet();
2713     }
2714    
2715     /**
2716     * Gets the current number of all MIDI instrument in all maps.
2717     * @return The current number of all MIDI instrument in all maps.
2718     * @throws IOException If some I/O error occurs.
2719     * @throws LscpException If LSCP protocol corruption occurs.
2720     * @throws LSException If some other error occurs.
2721     */
2722     public synchronized int
2723     getMidiInstrumentCount() throws IOException, LscpException, LSException {
2724     verifyConnection();
2725     out.writeLine("GET MIDI_INSTRUMENTS ALL");
2726     if(getPrintOnlyMode()) return -1;
2727    
2728     String s = getSingleLineResultSet().getResult();
2729     return parseInt(s);
2730     }
2731    
2732     /**
2733     * Gets the current number of MIDI instrument in the specified map.
2734     * @param mapId The ID of the map.
2735     * @return The current number of MIDI instrument in the specified map.
2736     * @throws IOException If some I/O error occurs.
2737     * @throws LscpException If LSCP protocol corruption occurs.
2738     * @throws LSException If some other error occurs.
2739     */
2740     public synchronized int
2741     getMidiInstrumentCount(int mapId) throws IOException, LscpException, LSException {
2742     verifyConnection();
2743     out.writeLine("GET MIDI_INSTRUMENTS " + String.valueOf(mapId));
2744     if(getPrintOnlyMode()) return -1;
2745    
2746     String s = getSingleLineResultSet().getResult();
2747     return parseInt(s);
2748     }
2749    
2750     /**
2751     * Gets all MIDI instrument from all maps.
2752     * @return A <code>MidiInstrumentInfo</code> array providing
2753     * all MIDI instruments from all MIDI instrument maps.
2754     * @throws IOException If some I/O error occurs.
2755     * @throws LscpException If LSCP protocol corruption occurs.
2756     * @throws LSException If some other error occurs.
2757     */
2758     public synchronized MidiInstrumentInfo[]
2759     getMidiInstruments() throws IOException, LscpException, LSException {
2760     verifyConnection();
2761     out.writeLine("LIST MIDI_INSTRUMENTS ALL");
2762     if(getPrintOnlyMode()) return null;
2763    
2764     String[] entries = parseArray(getSingleLineResultSet().getResult());
2765    
2766     return getMidiInstruments(entries);
2767     }
2768    
2769     /**
2770     * Gets all MIDI instrument contained int the specified MIDI instrument map.
2771     * @param mapId The ID of the map, which instruments should be obtained.
2772     * @return A <code>MidiInstrumentInfo</code> array providing
2773     * all MIDI instruments from all MIDI instrument maps.
2774     * @throws IOException If some I/O error occurs.
2775     * @throws LscpException If LSCP protocol corruption occurs.
2776     * @throws LSException If some other error occurs.
2777     */
2778     public synchronized MidiInstrumentInfo[]
2779     getMidiInstruments(int mapId) throws IOException, LscpException, LSException {
2780     verifyConnection();
2781     out.writeLine("LIST MIDI_INSTRUMENTS " + String.valueOf(mapId));
2782     if(getPrintOnlyMode()) return null;
2783    
2784     String[] entries = parseArray(getSingleLineResultSet().getResult());
2785    
2786     return getMidiInstruments(entries);
2787     }
2788    
2789     private MidiInstrumentInfo[]
2790     getMidiInstruments(String[] entries) throws IOException, LscpException, LSException {
2791     Vector<MidiInstrumentInfo> v = new Vector<MidiInstrumentInfo>();
2792    
2793     for(String s : entries) {
2794     Integer[] vals = parseIntList(s);
2795     if(vals.length != 3) {
2796     throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
2797     }
2798    
2799     v.add(getMidiInstrumentInfo(vals[0], vals[1], vals[2]));
2800     }
2801    
2802     return v.toArray(new MidiInstrumentInfo[v.size()]);
2803     }
2804    
2805     /**
2806     * Gets the current settings of the specified MIDI instrument.
2807     * @param mapId The ID of the map.
2808     * @param bank The index of the MIDI bank.
2809     * @param program The MIDI program number of the instrument.
2810     * @return <code>MidiInstrumentInfo</code> instance containing
2811     * the current settings of the specified MIDI instrument.
2812     * @throws IOException If an I/O error occurs.
2813     * @throws LscpException If LSCP protocol corruption occurs.
2814     * @throws LSException If the specified MIDI instrument is missing.
2815     */
2816     public synchronized MidiInstrumentInfo
2817     getMidiInstrumentInfo(int mapId, int bank, int program)
2818     throws IOException, LscpException, LSException {
2819    
2820     verifyConnection();
2821     StringBuffer cmd = new StringBuffer("GET MIDI_INSTRUMENT INFO ");
2822     cmd.append(mapId).append(' ');
2823     cmd.append(bank).append(' ');
2824     cmd.append(program);
2825    
2826     out.writeLine(cmd.toString());
2827     if(getPrintOnlyMode()) return null;
2828    
2829     ResultSet rs = getMultiLineResultSet();
2830     MidiInstrumentEntry entry = new MidiInstrumentEntry(bank, program);
2831     return new MidiInstrumentInfo(mapId, entry, rs.getMultiLineResult());
2832     }
2833    
2834     /**
2835 iliev 596 * Loads and assigns an instrument to a sampler channel. Notice that this function will
2836     * return after the instrument is fully loaded and the channel is ready to be used.
2837     * @param filename The name of the instrument file
2838     * on the LinuxSampler instance's host system.
2839     * @param instrIdx The index of the instrument in the instrument file.
2840     * @param samplerChn The number of the sampler channel the instrument should be assigned to.
2841     * @throws IOException If some I/O error occurs.
2842     * @throws LscpException If LSCP protocol corruption occurs.
2843     * @throws LSException If the loading of the instrument failed.
2844     * @see #loadInstrument(String, int, int, boolean)
2845     * @see #getSamplerChannels
2846     */
2847     public synchronized void
2848     loadInstrument(String filename, int instrIdx, int samplerChn)
2849     throws IOException, LscpException, LSException {
2850    
2851     verifyConnection();
2852     loadInstrument(filename, instrIdx, samplerChn, false);
2853     }
2854    
2855     /**
2856     * Loads and assigns an instrument to a sampler channel.
2857     *
2858     * @param filename The name of the instrument file
2859     * on the LinuxSampler instance's host system.
2860     * @param instrIdx The index of the instrument in the instrument file.
2861     * @param samplerChn The number of the sampler channel the instrument should be assigned to.
2862     * @param nonModal If <code>false</code> the function will return after the instrument
2863     * has been fully loaded and the channel is ready to be used. If <code>true</code>
2864     * the function returns immediately.
2865     *
2866     * @throws IOException If some I/O error occurs.
2867     * @throws LscpException If LSCP protocol corruption occurs.
2868     * @throws LSException If the loading of the instrument failed.
2869     *
2870     * @see #loadInstrument(String, int, int)
2871     * @see #getSamplerChannels
2872     */
2873     public synchronized void
2874     loadInstrument(String filename, int instrIdx, int samplerChn, boolean nonModal)
2875     throws IOException, LscpException, LSException {
2876    
2877     String cmd = nonModal ? "LOAD INSTRUMENT NON_MODAL " : "LOAD INSTRUMENT ";
2878     String args = '\'' + filename + "' " + instrIdx + ' ' + samplerChn;
2879    
2880     out.writeLine(cmd + args);
2881 iliev 1139 if(getPrintOnlyMode()) return;
2882 iliev 596
2883     ResultSet rs = getEmptyResultSet();
2884     }
2885    
2886     /**
2887     * Loads a sampler engine to a specific sampler channel.
2888     * @param engineName The name of the engine.
2889     * @param samplerChn The number of the sampler channel
2890     * the deployed engine should be assigned to.
2891     *
2892     * @throws IOException If some I/O error occurs.
2893     * @throws LscpException If LSCP protocol corruption occurs.
2894     * @throws LSException If the loading of the sampler engine failed.
2895     * @see #getEngines
2896     * @see #getSamplerChannels
2897     */
2898     public synchronized void
2899     loadSamplerEngine(String engineName, int samplerChn)
2900     throws IOException, LscpException, LSException {
2901    
2902     verifyConnection();
2903     out.writeLine("LOAD ENGINE " + engineName + ' ' + samplerChn);
2904 iliev 1139 if(getPrintOnlyMode()) return;
2905 iliev 596
2906     ResultSet rs = getEmptyResultSet();
2907     }
2908    
2909     /**
2910     * Gets the current number of all created sampler channels.
2911     * @return The current number of all created sampler channels.
2912     * @throws IOException If some I/O error occurs.
2913     * @throws LscpException If LSCP protocol corruption occurs.
2914     * @throws LSException If some other error occurs.
2915     */
2916     public synchronized int
2917     getSamplerChannelCount() throws IOException, LscpException, LSException {
2918     verifyConnection();
2919     out.writeLine("GET CHANNELS");
2920 iliev 1139 if(getPrintOnlyMode()) return -1;
2921    
2922 iliev 596 String s = getSingleLineResultSet().getResult();
2923     return parseInt(s);
2924     }
2925    
2926     /**
2927 iliev 784 * Gets a list of all created sampler channels.
2928     * @return A <code>SamplerChannel</code> array providing all created sampler channels.
2929     * @throws IOException If some I/O error occurs.
2930     * @throws LscpException If LSCP protocol corruption occurs.
2931     * @throws LSException If some other error occurs.
2932     * @see #addSamplerChannel
2933     * @see #removeSamplerChannel
2934     */
2935     public synchronized SamplerChannel[]
2936     getSamplerChannels() throws IOException, LscpException, LSException {
2937     Integer[] idS = getSamplerChannelIDs();
2938 iliev 1139 if(getPrintOnlyMode()) return null;
2939    
2940 iliev 784 SamplerChannel[] channels = new SamplerChannel[idS.length];
2941    
2942     for(int i = 0; i < channels.length; i++)
2943     channels[i] = getSamplerChannelInfo(idS[i]);
2944    
2945     return channels;
2946     }
2947    
2948     /**
2949 iliev 596 * Gets a list with numerical IDs of all created sampler channels.
2950 iliev 784 * @return An <code>Integer</code> array providing
2951     * the numerical IDs of all created sampler channels.
2952 iliev 596 * @throws IOException If some I/O error occurs.
2953     * @throws LscpException If LSCP protocol corruption occurs.
2954     * @throws LSException If some other error occurs.
2955     * @see #addSamplerChannel
2956     * @see #removeSamplerChannel
2957     */
2958     public synchronized Integer[]
2959 iliev 784 getSamplerChannelIDs() throws IOException, LscpException, LSException {
2960 iliev 596 verifyConnection();
2961     out.writeLine("LIST CHANNELS");
2962 iliev 1139 if(getPrintOnlyMode()) return null;
2963    
2964 iliev 596 return parseIntList(getSingleLineResultSet().getResult());
2965     }
2966    
2967     /**
2968     * Adds a new sampler channel. This method will increment the sampler channel count by one
2969     * and the new sampler channel will be appended to the end of the sampler channel list.
2970     *
2971     * @return The number of the newly created sampler channel.
2972     * @throws IOException If some I/O error occurs.
2973     * @throws LSException If the creation of the new sampler channel failed.
2974     * @throws LscpException If LSCP protocol corruption occurs.
2975     * @see #removeSamplerChannel
2976     */
2977     public synchronized int
2978     addSamplerChannel() throws IOException, LSException, LscpException {
2979     verifyConnection();
2980     out.writeLine("ADD CHANNEL");
2981 iliev 1139 if(getPrintOnlyMode()) return -1;
2982    
2983 iliev 596 ResultSet rs = getEmptyResultSet();
2984    
2985     return rs.getIndex();
2986     }
2987    
2988     /**
2989     * Removes the specified sampler channel.
2990     *
2991     * @param samplerChn The numerical ID of the sampler channel to be removed.
2992     *
2993     * @throws IOException If some I/O error occurs.
2994     * @throws LscpException If LSCP protocol corruption occurs.
2995     * @throws LSException If the removing of the sampler channel failed.
2996     * @see #addSamplerChannel
2997     * @see #getSamplerChannels
2998     */
2999     public synchronized void
3000     removeSamplerChannel(int samplerChn) throws IOException, LscpException, LSException {
3001     verifyConnection();
3002     out.writeLine("REMOVE CHANNEL " + samplerChn);
3003 iliev 1139 if(getPrintOnlyMode()) return;
3004 iliev 596
3005     ResultSet rs = getEmptyResultSet();
3006     }
3007    
3008     /**
3009     * Gets the number of all available engines.
3010     * @return The number of all available engines.
3011     * @throws IOException If some I/O error occurs.
3012     * @throws LscpException If LSCP protocol corruption occurs.
3013     * @throws LSException If some other error occurs.
3014     */
3015     public synchronized int
3016     getEngineCount() throws IOException, LscpException, LSException {
3017     verifyConnection();
3018     out.writeLine("GET AVAILABLE_ENGINES");
3019 iliev 1139 if(getPrintOnlyMode()) return -1;
3020    
3021 iliev 596 String s = getSingleLineResultSet().getResult();
3022     return parseInt(s);
3023     }
3024    
3025     /**
3026 iliev 671 * Gets a list of all available engines.
3027     *
3028     * @return <code>SamplerEngine</code> array containing all available engines.
3029     * @throws IOException If some I/O error occurs.
3030     * @throws LscpException If LSCP protocol corruption occurs.
3031     * @throws LSException If some other error occurs.
3032     */
3033     public synchronized SamplerEngine[]
3034     getEngines() throws IOException, LscpException, LSException {
3035     String[] engines = getEngineNames();
3036 iliev 1139 if(getPrintOnlyMode()) return null;
3037    
3038 iliev 671 SamplerEngine[] se = new SamplerEngine[engines.length];
3039    
3040     for(int i = 0; i < engines.length; i++) se[i] = getEngineInfo(engines[i]);
3041    
3042     return se;
3043     }
3044    
3045     /**
3046 iliev 596 * Gets a list of all available engines' names.
3047     *
3048     * @return <code>String</code> array with all available engines' names.
3049     * @throws IOException If some I/O error occurs.
3050     * @throws LscpException If LSCP protocol corruption occurs.
3051     * @throws LSException If some other error occurs.
3052     */
3053 iliev 671 private synchronized String[]
3054     getEngineNames() throws IOException, LscpException, LSException {
3055 iliev 596 verifyConnection();
3056     out.writeLine("LIST AVAILABLE_ENGINES");
3057 iliev 1139 if(getPrintOnlyMode()) return null;
3058    
3059 iliev 1393 return parseStringList(getSingleLineResultSet().getResult());
3060 iliev 596 }
3061    
3062     /**
3063     * Gets information about a specific sampler engine.
3064     * @param engineName The name of the sampler engine.
3065     *
3066     * @return <code>SamplerEngine</code> instance containing
3067     * information about the specified sampler engine.
3068     *
3069     * @throws IOException If an I/O error occurs.
3070     * @throws LscpException If LSCP protocol corruption occurs.
3071     * @throws LSException If there is no sampler engine with name <code>engineName</code>.
3072 iliev 671 * @see #getEngineNames
3073 iliev 596 */
3074 iliev 671 private synchronized SamplerEngine
3075 iliev 596 getEngineInfo(String engineName) throws IOException, LscpException, LSException {
3076     verifyConnection();
3077     out.writeLine("GET ENGINE INFO " + engineName);
3078 iliev 1139 if(getPrintOnlyMode()) return null;
3079    
3080 iliev 596 ResultSet rs = getMultiLineResultSet();
3081     SamplerEngine se = new SamplerEngine(rs.getMultiLineResult());
3082     se.setName(engineName);
3083     return se;
3084     }
3085    
3086     /**
3087     * Gets the current settings of the specified sampler channel.
3088     * @param samplerChn The sampler channel number.
3089     *
3090     * @return <code>SamplerChannel</code> instance containing
3091     * the current settings of the specified sampler channel.
3092     *
3093     * @throws IOException If an I/O error occurs.
3094     * @throws LscpException If LSCP protocol corruption occurs.
3095     * @throws LSException If there is no sampler channel with <code>samplerChn</code> number.
3096     * @see #getSamplerChannels
3097     */
3098     public synchronized SamplerChannel
3099     getSamplerChannelInfo(int samplerChn) throws IOException, LscpException, LSException {
3100     verifyConnection();
3101     out.writeLine("GET CHANNEL INFO " + samplerChn);
3102 iliev 1139 if(getPrintOnlyMode()) return null;
3103    
3104 iliev 596 ResultSet rs = getMultiLineResultSet();
3105     SamplerChannel sc = new SamplerChannel(rs.getMultiLineResult());
3106 iliev 1139 sc.setChannelId(samplerChn);
3107 iliev 784 if(sc.getEngine() != null) sc.setEngine(getEngineInfo(sc.getEngine().getName()));
3108 iliev 596
3109     return sc;
3110     }
3111    
3112     /**
3113     * Gets the current number of active voices on the specified sampler channel.
3114     *
3115     * @param samplerChn The sampler channel number.
3116     * @return The current number of active voices on the specified sampler channel.
3117     * @throws IOException If some I/O error occurs.
3118     * @throws LscpException If LSCP protocol corruption occurs.
3119     * @throws LSException If there is no sampler channel with number <code>samplerChn</code>.
3120     * @see #getSamplerChannels
3121     */
3122     public synchronized int
3123     getChannelVoiceCount(int samplerChn) throws IOException, LscpException, LSException {
3124     verifyConnection();
3125     out.writeLine("GET CHANNEL VOICE_COUNT " + samplerChn);
3126 iliev 1139 if(getPrintOnlyMode()) return -1;
3127    
3128 iliev 596 ResultSet rs = getSingleLineResultSet();
3129    
3130     return parseInt(rs.getResult());
3131     }
3132    
3133     /**
3134     * Gets the current number of active disk streams on the specified sampler channel.
3135     *
3136     * @param samplerChn The sampler channel number.
3137     * @return The current number of active disk streams on the specified sampler channel
3138     * or -1 if the engine doesn't support disk streaming.
3139     * @throws IOException If some I/O error occurs.
3140     * @throws LscpException If LSCP protocol corruption occurs.
3141     * @throws LSException If there is no sampler channel with number <code>samplerChn</code>.
3142     * @see #getSamplerChannels
3143     */
3144     public synchronized int
3145     getChannelStreamCount(int samplerChn) throws IOException, LscpException, LSException {
3146     verifyConnection();
3147     out.writeLine("GET CHANNEL STREAM_COUNT " + samplerChn);
3148 iliev 1139 if(getPrintOnlyMode()) return -1;
3149    
3150 iliev 596 ResultSet rs = getSingleLineResultSet();
3151    
3152     if(rs.getResult().equals("NA")) return -1;
3153    
3154     return parseInt(rs.getResult());
3155     }
3156    
3157     /**
3158     * Gets the current fill state of all disk streams on the specified sampler channel
3159     * in bytes.
3160     *
3161     * @param samplerChn The sampler channel number.
3162     * @return The current fill state of all disk streams on the specified sampler channel
3163     * or <code>null</code> if the engine which is deployed doesn't support disk streaming.
3164     * @throws IOException If some I/O error occurs.
3165     * @throws LscpException If LSCP protocol corruption occurs.
3166     * @throws LSException If there is no sampler channel with number <code>samplerChn</code>.
3167     * @see #getChannelBufferFillPercentage
3168     * @see #getSamplerChannels
3169     */
3170     public synchronized Vector<BufferFill>
3171     getChannelBufferFillBytes(int samplerChn) throws IOException, LscpException, LSException {
3172     verifyConnection();
3173     out.writeLine("GET CHANNEL BUFFER_FILL BYTES " + samplerChn);
3174 iliev 1139 if(getPrintOnlyMode()) return null;
3175    
3176 iliev 596 ResultSet rs = getSingleLineResultSet();
3177    
3178     if(rs.getResult().equals("NA")) return null;
3179    
3180     Vector<BufferFill> v = new Vector<BufferFill>();
3181     String[] args = parseList(rs.getResult());
3182    
3183     for(String s : args) {
3184     if(s.charAt(0) != '[')
3185     throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
3186    
3187     int i = s.indexOf(']');
3188     if(i == -1) throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
3189    
3190     BufferFill bf = new BufferFill();
3191 iliev 1139 bf.setStreamId(parseInt(s.substring(1, i)));
3192 iliev 596 bf.setValue(parseInt(s.substring(i + 1)));
3193     v.add(bf);
3194     }
3195    
3196     return v;
3197     }
3198    
3199     /**
3200     * Gets the current fill state of all disk streams on the specified sampler channel
3201     * in percent.
3202     *
3203     * @param samplerChn The sampler channel number.
3204     * @return The current fill state of all disk streams on the specified sampler channel
3205     * or <code>null</code> if the engine which is deployed doesn't support disk streaming.
3206     * @throws IOException If some I/O error occurs.
3207     * @throws LscpException If LSCP protocol corruption occurs.
3208     * @throws LSException If there is no sampler channel with number <code>samplerChn</code>.
3209     * @see #getChannelBufferFillBytes
3210     * @see #getSamplerChannels
3211     */
3212     public synchronized Vector<BufferFill>
3213     getChannelBufferFillPercentage(int samplerChn)
3214     throws IOException, LscpException, LSException {
3215    
3216     verifyConnection();
3217     out.writeLine("GET CHANNEL BUFFER_FILL PERCENTAGE " + samplerChn);
3218 iliev 1139 if(getPrintOnlyMode()) return null;
3219    
3220 iliev 596 ResultSet rs = getSingleLineResultSet();
3221    
3222     return getChannelBufferFillPercentage(rs.getResult());
3223     }
3224    
3225     private Vector<BufferFill>
3226     getChannelBufferFillPercentage(String ln) throws LscpException {
3227     if(ln.equals("NA")) return null;
3228    
3229     Vector<BufferFill> v = new Vector<BufferFill>();
3230     String[] args = parseList(ln);
3231    
3232     for(String s : args) {
3233     if(s.charAt(0) != '[')
3234     throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
3235    
3236     int i = s.indexOf(']');
3237     if(i == -1) throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
3238    
3239     if(s.charAt(s.length() - 1) != '%')
3240     throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
3241    
3242     BufferFill bf = new BufferFill();
3243 iliev 1139 bf.setStreamId(parseInt(s.substring(1, i)));
3244 iliev 596 bf.setValue(parseInt(s.substring(i + 1, s.length() - 1)));
3245     v.add(bf);
3246     }
3247    
3248     return v;
3249     }
3250    
3251     /**
3252     * Sets the audio output device on the specified sampler channel.
3253     *
3254     * @param samplerChn The sampler channel number.
3255 iliev 1139 * @param devId The numerical ID of the audio output device.
3256 iliev 596 *
3257     * @throws IOException If some I/O error occurs.
3258     * @throws LscpException If LSCP protocol corruption occurs.
3259     * @throws LSException If
3260     * <ul>
3261     * <li><code>samplerChn</code> is not a valid channel number;
3262 iliev 1139 * <li><code>devId</code> is not a valid audio output device ID;
3263 iliev 596 * </ul>
3264     *
3265     * @see #getSamplerChannels
3266     * @see #getAudioOutputDevices
3267     */
3268     public synchronized void
3269 iliev 1139 setChannelAudioOutputDevice(int samplerChn, int devId)
3270 iliev 596 throws IOException, LscpException, LSException {
3271    
3272     verifyConnection();
3273 iliev 1139 out.writeLine("SET CHANNEL AUDIO_OUTPUT_DEVICE " + samplerChn + ' ' + devId);
3274     if(getPrintOnlyMode()) return;
3275 iliev 596
3276     ResultSet rs = getEmptyResultSet();
3277     }
3278    
3279     /**
3280     * Sets the audio output channel on the specified sampler channel.
3281     *
3282     * @param samplerChn The sampler channel number.
3283     * @param audioOut The sampler channel's audio output channel which should be rerouted.
3284     * @param audioIn The audio channel of the selected audio output device
3285     * where <code>audioOut</code> should be routed to.
3286     *
3287     * @throws IOException If some I/O error occurs.
3288     * @throws LscpException If LSCP protocol corruption occurs.
3289     * @throws LSException If
3290     * <ul>
3291     * <li><code>samplerChn</code> is not a valid channel number;
3292     * <li>There is no engine assigned yet to the specified sampler channel.
3293     * <li> There is no audio output device connected to the specified sampler channel.
3294     * </ul>
3295     *
3296     * @see #getSamplerChannels
3297     */
3298     public synchronized void
3299     setChannelAudioOutputChannel(int samplerChn, int audioOut, int audioIn)
3300     throws IOException, LscpException, LSException {
3301    
3302     verifyConnection();
3303     String args = " " + samplerChn + ' ' + audioOut + ' ' + audioIn;
3304     out.writeLine("SET CHANNEL AUDIO_OUTPUT_CHANNEL" + args);
3305 iliev 1139 if(getPrintOnlyMode()) return;
3306 iliev 596
3307     ResultSet rs = getEmptyResultSet();
3308     }
3309    
3310     /**
3311     * Sets the MIDI input device on the specified sampler channel.
3312     *
3313     * @param samplerChn The sampler channel number.
3314 iliev 1139 * @param devId The numerical ID of the MIDI input device.
3315 iliev 596 *
3316     * @throws IOException If some I/O error occurs.
3317     * @throws LscpException If LSCP protocol corruption occurs.
3318     * @throws LSException If
3319     * <ul>
3320     * <li><code>samplerChn</code> is not a valid channel number;
3321 iliev 1139 * <li><code>devId</code> is not a valid MIDI input device ID;
3322 iliev 596 * </ul>
3323     *
3324     * @see #getSamplerChannels
3325     * @see #getMidiInputDevices
3326     */
3327     public synchronized void
3328 iliev 1139 setChannelMidiInputDevice(int samplerChn, int devId)
3329 iliev 596 throws IOException, LscpException, LSException {
3330    
3331     verifyConnection();
3332 iliev 1139 out.writeLine("SET CHANNEL MIDI_INPUT_DEVICE " + samplerChn + ' ' + devId);
3333     if(getPrintOnlyMode()) return;
3334 iliev 596
3335     ResultSet rs = getEmptyResultSet();
3336     }
3337    
3338     /**
3339     * Sets the MIDI input port on the specified sampler channel.
3340     *
3341     * @param samplerChn The sampler channel number.
3342     * @param port The MIDI input port number of
3343     * the MIDI input device connected to the specified sampler channel.
3344     *
3345     * @throws IOException If some I/O error occurs.
3346     * @throws LscpException If LSCP protocol corruption occurs.
3347     * @throws LSException If <code>samplerChn</code> is not a valid channel number.
3348     * @see #getSamplerChannels
3349     */
3350     public synchronized void
3351     setChannelMidiInputPort(int samplerChn, int port)
3352     throws IOException, LscpException, LSException {
3353    
3354     verifyConnection();
3355     out.writeLine("SET CHANNEL MIDI_INPUT_PORT " + samplerChn + ' ' + port);
3356 iliev 1139 if(getPrintOnlyMode()) return;
3357 iliev 596
3358     ResultSet rs = getEmptyResultSet();
3359     }
3360    
3361     /**
3362     * Sets the MIDI input channel the specified sampler channel should listen to.
3363     *
3364     * @param samplerChn The sampler channel number.
3365     * @param midiChn The number of the new MIDI input channel where
3366     * <code>samplerChn</code> should listen to or -1 to listen on all 16 MIDI channels.
3367     *
3368     * @throws IOException If some I/O error occurs.
3369     * @throws LscpException If LSCP protocol corruption occurs.
3370     * @throws LSException If <code>samplerChn</code> is not a valid channel number.
3371     * @see #getSamplerChannels
3372     */
3373     public synchronized void
3374     setChannelMidiInputChannel(int samplerChn, int midiChn)
3375     throws IOException, LscpException, LSException {
3376    
3377     verifyConnection();
3378     String args = String.valueOf(samplerChn) + ' ';
3379     args += (midiChn == -1 ? "ALL" : String.valueOf(midiChn));
3380     out.writeLine("SET CHANNEL MIDI_INPUT_CHANNEL " + args);
3381 iliev 1139 if(getPrintOnlyMode()) return;
3382 iliev 596
3383     ResultSet rs = getEmptyResultSet();
3384     }
3385    
3386     /**
3387 iliev 1139 * Sets the MIDI instrument map to be used on the specified sampler channel.
3388     *
3389     * @param samplerChn The sampler channel number.
3390     * @param mapId Specifies the numerical ID of the MIDI instrument
3391     * map to assign. To remove the current map binding use <code>-1</code>.
3392     * To set the current map to be the default map use <code>-2</code>.
3393     *
3394     * @throws IOException If some I/O error occurs.
3395     * @throws LscpException If LSCP protocol corruption occurs.
3396     * @throws LSException If
3397     * <ul>
3398     * <li><code>samplerChn</code> is not a valid channel number;
3399     * <li><code>mapId</code> is not a valid MIDI instrument map ID;
3400     * </ul>
3401     *
3402     * @see #getSamplerChannels
3403     * @see #getMidiInstrumentMaps
3404     */
3405     public synchronized void
3406     setChannelMidiInstrumentMap(int samplerChn, int mapId)
3407     throws IOException, LscpException, LSException {
3408    
3409     verifyConnection();
3410     String s;
3411     if(mapId == -1) {
3412     s = " NONE";
3413     } else if(mapId == -2) {
3414     s = " DEFAULT";
3415     } else {
3416     s = " " + String.valueOf(mapId);
3417     }
3418     out.writeLine("SET CHANNEL MIDI_INSTRUMENT_MAP " + samplerChn + s);
3419     if(getPrintOnlyMode()) return;
3420    
3421     ResultSet rs = getEmptyResultSet();
3422     }
3423    
3424     /**
3425 iliev 596 * Sets the volume of the specified sampler channel.
3426     *
3427     * @param samplerChn The sampler channel number.
3428     * @param volume The new volume value.
3429     *
3430     * @throws IOException If some I/O error occurs.
3431     * @throws LscpException If LSCP protocol corruption occurs.
3432     * @throws LSException If <code>samplerChn</code> is not a valid channel number or if
3433     * there is no engine assigned yet to the specified sampler channel.
3434     * @see #getSamplerChannels
3435     */
3436     public synchronized void
3437     setChannelVolume(int samplerChn, float volume)
3438     throws IOException, LscpException, LSException {
3439    
3440     verifyConnection();
3441     out.writeLine("SET CHANNEL VOLUME " + samplerChn + ' ' + volume);
3442 iliev 1139 if(getPrintOnlyMode()) return;
3443 iliev 596
3444     ResultSet rs = getEmptyResultSet();
3445     }
3446    
3447     /**
3448 iliev 784 * Mute/unmute the specified sampler channel.
3449     *
3450     * @param samplerChn The sampler channel number.
3451     * @param mute If <code>true</code> the specified channel is muted, else the channel
3452     * is unmuted.
3453     *
3454     * @throws IOException If some I/O error occurs.
3455     * @throws LscpException If LSCP protocol corruption occurs.
3456     * @throws LSException If <code>samplerChn</code> is not a valid channel number or if
3457     * there is no engine assigned yet to the specified sampler channel.
3458     * @see #getSamplerChannels
3459     */
3460     public synchronized void
3461     setChannelMute(int samplerChn, boolean mute)
3462     throws IOException, LscpException, LSException {
3463    
3464     verifyConnection();
3465     out.writeLine("SET CHANNEL MUTE " + samplerChn + ' ' + (mute ? 1 : 0));
3466 iliev 1139 if(getPrintOnlyMode()) return;
3467 iliev 784
3468     ResultSet rs = getEmptyResultSet();
3469     }
3470    
3471     /**
3472     * Solo/unsolo the specified sampler channel.
3473     *
3474     * @param samplerChn The sampler channel number.
3475     * @param solo <code>true</code> to solo the specified channel, <code>false</code>
3476     * otherwise.
3477     *
3478     * @throws IOException If some I/O error occurs.
3479     * @throws LscpException If LSCP protocol corruption occurs.
3480     * @throws LSException If <code>samplerChn</code> is not a valid channel number or if
3481     * there is no engine assigned yet to the specified sampler channel.
3482     * @see #getSamplerChannels
3483     */
3484     public synchronized void
3485     setChannelSolo(int samplerChn, boolean solo)
3486     throws IOException, LscpException, LSException {
3487    
3488     verifyConnection();
3489     out.writeLine("SET CHANNEL SOLO " + samplerChn + ' ' + (solo ? 1 : 0));
3490 iliev 1139 if(getPrintOnlyMode()) return;
3491 iliev 784
3492     ResultSet rs = getEmptyResultSet();
3493     }
3494    
3495     /**
3496 iliev 1139 * Creates an additional effect send on the specified sampler channel.
3497     * @param channel The sampler channel, on which a new effect send should be added.
3498     * @param midiCtrl Defines the MIDI controller, which
3499     * will be able alter the effect send level.
3500     * @return The unique ID of the newly created effect send entity.
3501     * @throws IOException If some I/O error occurs.
3502     * @throws LSException If the creation of the effect send failed.
3503     * @throws LscpException If LSCP protocol corruption occurs.
3504     * @see #destroyFxSend
3505     */
3506     public synchronized int
3507     createFxSend(int channel, int midiCtrl)
3508     throws IOException, LSException, LscpException {
3509    
3510     return createFxSend(channel, midiCtrl, null);
3511     }
3512    
3513     /**
3514     * Creates an additional effect send on the specified sampler channel.
3515     * @param channel The sampler channel, on which the effect send should be created on.
3516     * @param midiCtrl Defines the MIDI controller, which can alter the effect send level.
3517     * @param name The name of the effect send entity. The name does not have to be unique.
3518     * @return The unique ID of the newly created effect send entity.
3519     * @throws IOException If some I/O error occurs.
3520     * @throws LSException If the creation of the effect send failed.
3521     * @throws LscpException If LSCP protocol corruption occurs.
3522     * @see #destroyFxSend
3523     */
3524     public synchronized int
3525     createFxSend(int channel, int midiCtrl, String name)
3526     throws IOException, LSException, LscpException {
3527    
3528     verifyConnection();
3529     String s = String.valueOf(channel) + " " + String.valueOf(midiCtrl);
3530 iliev 1393 if(name != null) s += " '" + toEscapedString(name) + "'";
3531 iliev 1139 out.writeLine("CREATE FX_SEND " + s);
3532     if(getPrintOnlyMode()) return -1;
3533    
3534     ResultSet rs = getEmptyResultSet();
3535    
3536     return rs.getIndex();
3537     }
3538    
3539     /**
3540     * Destroys the specified effect send on the specified sampler channel.
3541     * @param channel The sampler channel, from which
3542     * the specified effect send should be removed.
3543     * @param fxSend The ID of the effect send that should be removed.
3544     * @throws LSException If some other error occurs.
3545     * @throws LscpException If LSCP protocol corruption occurs.
3546     * @see #createFxSend
3547     */
3548     public synchronized void
3549     destroyFxSend(int channel, int fxSend)
3550     throws IOException, LSException, LscpException {
3551    
3552     verifyConnection();
3553     String s = String.valueOf(channel) + " " + String.valueOf(fxSend);
3554     out.writeLine("DESTROY FX_SEND " + s);
3555     if(getPrintOnlyMode()) return;
3556    
3557     ResultSet rs = getEmptyResultSet();
3558     }
3559    
3560     /**
3561     * Gets the current number of effect sends on the specified sampler channel.
3562     * @param channel The ID of the sampler channel.
3563     * @return The current number of effect sends on the specified sampler channels.
3564     * @throws IOException If some I/O error occurs.
3565     * @throws LscpException If LSCP protocol corruption occurs.
3566     * @throws LSException If some other error occurs.
3567     */
3568     public synchronized int
3569     getFxSoundCount(int channel) throws IOException, LscpException, LSException {
3570     verifyConnection();
3571     out.writeLine("GET FX_SENDS " + String.valueOf(channel));
3572     if(getPrintOnlyMode()) return -1;
3573    
3574     String s = getSingleLineResultSet().getResult();
3575     return parseInt(s);
3576     }
3577    
3578     /**
3579     * Gets a list of all created effect sends on the specified sampler channel.
3580     * @param channel The sampler channel number.
3581     * @return A <code>FxSend</code> array providing all created
3582     * effect sends on the specified sampler channel.
3583     * @throws IOException If some I/O error occurs.
3584     * @throws LscpException If LSCP protocol corruption occurs.
3585     * @throws LSException If <code>channel</code> is not a valid sampler channel ID.
3586     * @see #createFxSend
3587     * @see #destroyFxSend
3588     */
3589     public synchronized FxSend[]
3590     getFxSends(int channel) throws IOException, LscpException, LSException {
3591     Integer[] idS = getFxSendIDs(channel);
3592     if(getPrintOnlyMode()) return null;
3593    
3594     FxSend[] fxSends = new FxSend[idS.length];
3595    
3596     for(int i = 0; i < fxSends.length; i++)
3597     fxSends[i] = getFxSendInfo(channel, idS[i]);
3598    
3599     return fxSends;
3600     }
3601    
3602     /**
3603     * Gets a list of effect sends on the specified sampler channel.
3604     * @param channel The sampler channel number.
3605     * @return An <code>Integer</code> array providing
3606     * the numerical IDs of all effect sends on the specified sampler channel.
3607     * @throws IOException If some I/O error occurs.
3608     * @throws LscpException If LSCP protocol corruption occurs.
3609     * @throws LSException If <code>channel</code> is not a valid sampler channel ID.
3610     * @see #createFxSend
3611     * @see #destroyFxSend
3612     */
3613     public synchronized Integer[]
3614     getFxSendIDs(int channel) throws IOException, LscpException, LSException {
3615     verifyConnection();
3616     out.writeLine("LIST FX_SENDS " + channel);
3617     if(getPrintOnlyMode()) return null;
3618    
3619     return parseIntList(getSingleLineResultSet().getResult());
3620     }
3621    
3622     /**
3623     * Gets the current settings of the specified effect send entity.
3624     * @param channel The sampler channel number.
3625     * @param fxSend The numerical ID of the effect send entity.
3626     * @return <code>FxSend</code> instance containing
3627     * the current settings of the specified effect send entity.
3628     * @throws IOException If an I/O error occurs.
3629     * @throws LscpException If LSCP protocol corruption occurs.
3630     * @throws LSException If the sampler channel and/or the effect send number are invalid.
3631     */
3632     public synchronized FxSend
3633     getFxSendInfo(int channel, int fxSend) throws IOException, LscpException, LSException {
3634     verifyConnection();
3635     String s = String.valueOf(channel) + " " + String.valueOf(fxSend);
3636     out.writeLine("GET FX_SEND INFO " + s);
3637     if(getPrintOnlyMode()) return null;
3638    
3639     ResultSet rs = getMultiLineResultSet();
3640     FxSend fxs = new FxSend(rs.getMultiLineResult());
3641     fxs.setFxSendId(fxSend);
3642    
3643     return fxs;
3644     }
3645    
3646     /**
3647     * Sets the name of the specified effect send.
3648     * @param channel The sampler channel number.
3649     * @param fxSend The numerical ID of the effect send entity.
3650     * @param name The new name for the specified effect send.
3651     * @throws IOException If some I/O error occurs.
3652     * @throws LscpException If LSCP protocol corruption occurs.
3653     * @throws LSException If <code>channel</code> is not a valid channel
3654     * number or <code>fxSend</code> is not a valid effect send ID;
3655     */
3656     public synchronized void
3657     setFxSendName(int channel, int fxSend, String name)
3658     throws IOException, LscpException, LSException {
3659    
3660     verifyConnection();
3661 iliev 1393 String args = " " + channel + " " + fxSend + " '" + toEscapedString(name) + "'";
3662 iliev 1139 out.writeLine("SET FX_SEND NAME" + args);
3663     if(getPrintOnlyMode()) return;
3664    
3665     ResultSet rs = getEmptyResultSet();
3666     }
3667    
3668     /**
3669     * Sets the destination of an effect send's audio channel in the specified sampler channel.
3670     * @param channel The sampler channel number.
3671     * @param fxSend The numerical ID of the effect send entity to be rerouted.
3672     * @param audioSrc The numerical ID of the effect send's audio output channel,
3673     * which should be rerouted.
3674     * @param audioDst The audio channel of the selected audio output device
3675     * where <code>audioSrc</code> should be routed to.
3676     * @throws IOException If some I/O error occurs.
3677     * @throws LscpException If LSCP protocol corruption occurs.
3678     * @throws LSException If
3679     * <ul>
3680     * <li><code>channel</code> is not a valid channel number;
3681     * <li><code>fxSend</code> is not a valid effect send ID;
3682     * <li>There is no engine assigned yet to the specified sampler channel;
3683     * <li>There is no audio output device connected to the specified sampler channel.
3684     * </ul>
3685     */
3686     public synchronized void
3687     setFxSendAudioOutputChannel(int channel, int fxSend, int audioSrc, int audioDst)
3688     throws IOException, LscpException, LSException {
3689    
3690     verifyConnection();
3691     String args = " " + channel + " " + fxSend + " " + audioSrc + " " + audioDst;
3692     out.writeLine("SET FX_SEND AUDIO_OUTPUT_CHANNEL" + args);
3693     if(getPrintOnlyMode()) return;
3694    
3695     ResultSet rs = getEmptyResultSet();
3696     }
3697    
3698     /**
3699     * Sets the MIDI controller, which will be able to modify
3700     * the send level of the specified effect send in the specified sampler channel.
3701     * @param channel The sampler channel number.
3702     * @param fxSend The numerical ID of the effect send entity.
3703     * @param midiCtrl The MIDI controller which shall be
3704     * able to modify the effect send's send level.
3705     * @throws IOException If some I/O error occurs.
3706     * @throws LscpException If LSCP protocol corruption occurs.
3707     * @throws LSException If
3708     * <ul>
3709     * <li><code>channel</code> is not a valid channel number;
3710     * <li><code>fxSend</code> is not a valid effect send ID;
3711     * <li><code>midiCtrl</code> is not a valid controller;
3712     * </ul>
3713     */
3714     public synchronized void
3715     setFxSendMidiController(int channel, int fxSend, int midiCtrl)
3716     throws IOException, LscpException, LSException {
3717    
3718     verifyConnection();
3719     String args = " " + channel + " " + fxSend + " " + midiCtrl;
3720     out.writeLine("SET FX_SEND MIDI_CONTROLLER" + args);
3721     if(getPrintOnlyMode()) return;
3722    
3723     ResultSet rs = getEmptyResultSet();
3724     }
3725    
3726     /**
3727     * Sets the current send level of the specified
3728     * effect send entity in the specified sampler channel.
3729     * @param channel The sampler channel number.
3730     * @param fxSend The numerical ID of the effect send entity.
3731     * @param volume The new volume value (a value smaller than 1.0 means
3732     * attenuation, whereas a value greater than 1.0 means amplification).
3733     * @throws IOException If some I/O error occurs.
3734     * @throws LscpException If LSCP protocol corruption occurs.
3735     * @throws LSException If some other error occurs.
3736     */
3737     public synchronized void
3738     setFxSendLevel(int channel, int fxSend, float volume)
3739     throws IOException, LscpException, LSException {
3740    
3741     verifyConnection();
3742     String args = " " + channel + " " + fxSend + " " + String.valueOf(volume);
3743     out.writeLine("SET FX_SEND LEVEL" + args);
3744     if(getPrintOnlyMode()) return;
3745    
3746     ResultSet rs = getEmptyResultSet();
3747     }
3748    
3749 iliev 1340 /**
3750     * Starts an instrument editor for editing the loaded instrument
3751     * on the specified sampler channel.
3752     * @param samplerChn The sampler channel number.
3753     * @throws IOException If some I/O error occurs.
3754     * @throws LscpException If LSCP protocol corruption occurs.
3755     * @throws LSException If <code>samplerChn</code> is not a valid channel number or if
3756     * there is no instrument loaded on the specified sampler channel.
3757     * @see #getSamplerChannels
3758     */
3759     public synchronized void
3760 iliev 1421 editChannelInstrument(int samplerChn) throws IOException, LscpException, LSException {
3761 iliev 1340 verifyConnection();
3762 iliev 1421 out.writeLine("EDIT CHANNEL INSTRUMENT " + samplerChn);
3763 iliev 1340 if(getPrintOnlyMode()) return;
3764    
3765     ResultSet rs = getEmptyResultSet();
3766     }
3767 iliev 1202
3768    
3769 iliev 1340
3770 iliev 1139 /**
3771 iliev 1202 * Adds the specified directory to the instruments database.
3772 iliev 1346 * @param dir The absolute (escaped) path name of the directory to add.
3773 iliev 1202 * @throws IOException If some I/O error occurs.
3774     * @throws LSException If the creation of the directory failed.
3775     * @throws LscpException If LSCP protocol corruption occurs.
3776     */
3777     public synchronized void
3778     addDbDirectory(String dir) throws IOException, LSException, LscpException {
3779     verifyConnection();
3780     out.writeLine("ADD DB_INSTRUMENT_DIRECTORY '" + dir + "'");
3781     if(getPrintOnlyMode()) return;
3782    
3783     ResultSet rs = getEmptyResultSet();
3784     }
3785    
3786     /**
3787     * Removes the specified directory from the instruments database.
3788 iliev 1346 * @param dir The absolute (escaped) path name of the directory to remove.
3789 iliev 1202 * @throws IOException If some I/O error occurs.
3790     * @throws LscpException If LSCP protocol corruption occurs.
3791     * @throws LSException If the specified directory is not
3792     * empty or if the removal of the directory failed.
3793     */
3794     public synchronized void
3795     removeDbDirectory(String dir) throws IOException, LscpException, LSException {
3796     removeDbDirectory(dir, false);
3797     }
3798    
3799     /**
3800     * Removes the specified directory from the instruments database.
3801     * @param dir The absolute path name of the directory to remove.
3802     * @param force If <code>true</code> forces the removal of non-empty
3803     * directory and all its content.
3804     * @throws IOException If some I/O error occurs.
3805     * @throws LscpException If LSCP protocol corruption occurs.
3806     * @throws LSException If the removing of the directory failed.
3807     */
3808     public synchronized void
3809     removeDbDirectory(String dir, boolean force)
3810     throws IOException, LscpException, LSException {
3811    
3812     verifyConnection();
3813     String s = "REMOVE DB_INSTRUMENT_DIRECTORY ";
3814     if(force) s += "FORCE ";
3815     out.writeLine(s + "'" + dir + "'");
3816     if(getPrintOnlyMode()) return;
3817    
3818     ResultSet rs = getEmptyResultSet();
3819     }
3820    
3821     /**
3822     * Removes the specified directories from the instruments database.
3823 iliev 1346 * @param dirs The absolute (escaped) path names of the directories to remove.
3824 iliev 1202 * @param force If <code>true</code> forces the removal of non-empty
3825     * directories.
3826     * @throws IOException If some I/O error occurs.
3827     * @throws LscpException If LSCP protocol corruption occurs.
3828     * @throws LSException If the removing of the directores failed.
3829     */
3830     public synchronized void
3831     removeDbDirectories(String[] dirs, boolean force)
3832     throws IOException, LscpException, LSException {
3833    
3834     verifyConnection();
3835     String cmd = "REMOVE DB_INSTRUMENT_DIRECTORY ";
3836     if(force) cmd += "FORCE ";
3837    
3838     for(String s : dirs) out.writeLine(cmd + "'" + s + "'");
3839    
3840     if(getPrintOnlyMode()) return;
3841    
3842     getEmptyResultSets(dirs.length, "Client.dirDeletionFailed!");
3843     }
3844    
3845     /**
3846     * Gets the number of directories in the specified directory.
3847     * @return The current number of directories in the specified directory.
3848     * @param dir The absolute path name of the directory.
3849     * @throws IOException If some I/O error occurs.
3850     * @throws LscpException If LSCP protocol corruption occurs.
3851     * @throws LSException If some other error occurs.
3852     */
3853     public synchronized int
3854     getDbDirectoryCount(String dir) throws IOException, LscpException, LSException {
3855     return getDbDirectoryCount(dir, false);
3856     }
3857    
3858     /**
3859     * Gets the number of directories in the specified directory.
3860     * @return The current number of directories in the specified directory.
3861     * @param dir The absolute path name of the directory.
3862     * @param recursive If <code>true</code>, the number of all directories
3863     * in the specified subtree will be returned.
3864     * @throws IOException If some I/O error occurs.
3865     * @throws LscpException If LSCP protocol corruption occurs.
3866     * @throws LSException If some other error occurs.
3867     */
3868     public synchronized int
3869     getDbDirectoryCount(String dir, boolean recursive)
3870     throws IOException, LscpException, LSException {
3871    
3872     verifyConnection();
3873     String s;
3874     if(recursive) s = "GET DB_INSTRUMENT_DIRECTORIES RECURSIVE '";
3875     else s = "GET DB_INSTRUMENT_DIRECTORIES '";
3876     out.writeLine(s + dir + "'");
3877     if(getPrintOnlyMode()) return -1;
3878    
3879     s = getSingleLineResultSet().getResult();
3880     return parseInt(s);
3881     }
3882    
3883     /**
3884     * Gets the list of directories in the specified directory.
3885     * @param dir The absolute path name of the directory.
3886     * @return A <code>String</code> array providing the names of
3887     * all directories in the specified directory.
3888     * @throws IOException If some I/O error occurs.
3889     * @throws LscpException If LSCP protocol corruption occurs.
3890     * @throws LSException If the specified path name is invalid.
3891     */
3892     public synchronized String[]
3893     getDbDirectoryNames(String dir) throws IOException, LscpException, LSException {
3894     verifyConnection();
3895     out.writeLine("LIST DB_INSTRUMENT_DIRECTORIES '" + dir + "'");
3896     if(getPrintOnlyMode()) return null;
3897    
3898 iliev 1346 String[] names = parseEscapedStringList(getSingleLineResultSet().getResult());
3899     for(int i = 0; i < names.length; i++) {
3900 iliev 1351 names[i] = toNonEscapedString(names[i]);
3901 iliev 1346 }
3902     return names;
3903 iliev 1202 }
3904    
3905     /**
3906     * Gets information about the specified directory.
3907     * @param dir The absolute path name of the directory.
3908     * @return A <code>DbDirectoryInfo</code> instance providing information
3909     * about the specified directory.
3910     * @throws IOException If some I/O error occurs.
3911     * @throws LscpException If LSCP protocol corruption occurs.
3912     * @throws LSException If the specified directory is not found.
3913     */
3914     public synchronized DbDirectoryInfo
3915     getDbDirectoryInfo(String dir) throws IOException, LscpException, LSException {
3916     verifyConnection();
3917     out.writeLine("GET DB_INSTRUMENT_DIRECTORY INFO '" + dir + "'");
3918     if(getPrintOnlyMode()) return null;
3919    
3920     ResultSet rs = getMultiLineResultSet();
3921     DbDirectoryInfo info = new DbDirectoryInfo(rs.getMultiLineResult());
3922     if(dir.equals("/")) {
3923     info.setName("/");
3924 iliev 1346 } else {
3925     dir = removeEndingFileSeparator(dir);
3926 iliev 1202 }
3927 iliev 1346 String s = getFileName(dir);
3928     if(s != null) info.setName(toNonEscapedFileName(s));
3929     s = getParentDirectory(dir);
3930     if(s != null) info.setParentDirectoryPath(s);
3931 iliev 1202
3932     return info;
3933     }
3934    
3935     /**
3936     * Gets the list of directories in the specified directory.
3937     * @param dir The absolute path name of the directory.
3938     * @return A <code>DbDirectoryInfo</code> array providing
3939     * information about all directories in the specified directory.
3940     * @throws IOException If some I/O error occurs.
3941     * @throws LscpException If LSCP protocol corruption occurs.
3942     * @throws LSException If the specified path name is invalid.
3943     */
3944     public synchronized DbDirectoryInfo[]
3945     getDbDirectories(String dir) throws IOException, LscpException, LSException {
3946     String[] dirS = getDbDirectoryNames(dir);
3947 iliev 1346 if(!hasEndingFileSeparator(dir)) dir += "/";
3948 iliev 1202 DbDirectoryInfo[] infoS = new DbDirectoryInfo[dirS.length];
3949 iliev 1346 for(int i = 0; i < dirS.length; i++) {
3950     infoS[i] = getDbDirectoryInfo(dir + toEscapedFileName(dirS[i]));
3951     }
3952 iliev 1202 return infoS;
3953     }
3954    
3955     /**
3956     * Gets the list of directories in the specified directory.
3957     * @param dir The absolute path name of the directory.
3958     * @return A <code>DbDirectoryInfo</code> array providing
3959     * information about all directories in the specified directory.
3960     * @throws IOException If some I/O error occurs.
3961     * @throws LscpException If LSCP protocol corruption occurs.
3962     * @throws LSException If the specified path name is invalid.
3963     *
3964     public synchronized DbDirectoryInfo[]
3965     getDbDirectories(String dir) throws IOException, LscpException, LSException {
3966     String[] dirS = getDbDirectoryNames(dir);
3967     if(dirS.length == 0) return new DbDirectoryInfo[0];
3968    
3969     if(dir.charAt(dir.length() - 1) != '/') dir += "/";
3970    
3971     for(int i = 0; i < dirS.length; i++) {
3972     out.writeLine("GET DB_INSTRUMENT_DIRECTORY INFO '" + dir + dirS[i] + "'");
3973     }
3974    
3975     if(getPrintOnlyMode()) return null;
3976    
3977     if(dir.length() > 1) dir = dir.substring(0, dir.length() - 1);
3978     StringBuffer sb = new StringBuffer();
3979     DbDirectoryInfo[] infoS = new DbDirectoryInfo[dirS.length];
3980     for(int i = 0; i < dirS.length; i++) {
3981     try {
3982     ResultSet rs = getMultiLineResultSet();
3983     infoS[i] = new DbDirectoryInfo(rs.getMultiLineResult());
3984     infoS[i].setName(dirS[i]);
3985     infoS[i].setParentDirectoryPath(dir);
3986     } catch (SocketTimeoutException e) {
3987     getLogger().log(Level.FINE, e.getMessage(), e);
3988     sb.append(e.getMessage()).append("\n");
3989     break;
3990     } catch (Exception e) {
3991     getLogger().log(Level.FINE, e.getMessage(), e);
3992     sb.append(e.getMessage()).append("\n");
3993     }
3994     }
3995    
3996     String details = sb.toString();
3997     if(details.length() > 0) {
3998     String err = LscpI18n.getLogMsg("Client.getInstrsInfoFailed!");
3999     throw new LSException(0, err, details);
4000     }
4001    
4002     return infoS;
4003     }*/
4004    
4005     /**
4006     * Renames the specified directory.
4007     * @param dir The absolute path name of the directory to rename.
4008     * @param name The new name for the directory.
4009     * @throws IOException If some I/O error occurs.
4010     * @throws LSException If the renaming of the directory failed.
4011     * @throws LscpException If LSCP protocol corruption occurs.
4012     */
4013     public synchronized void
4014     renameDbDirectory(String dir, String name) throws IOException, LSException, LscpException {
4015     verifyConnection();
4016 iliev 1346 name = toEscapedString(name);
4017 iliev 1202 out.writeLine("SET DB_INSTRUMENT_DIRECTORY NAME '" + dir + "' '" + name + "'");
4018     if(getPrintOnlyMode()) return;
4019    
4020     ResultSet rs = getEmptyResultSet();
4021     }
4022    
4023     /**
4024     * Moves the specified directory into the specified location.
4025     * @param dir The absolute path name of the directory to move.
4026     * @param dst The location where the directory will be moved to.
4027     * @throws IOException If some I/O error occurs.
4028     * @throws LSException If the operation failed.
4029     * @throws LscpException If LSCP protocol corruption occurs.
4030     */
4031     public synchronized void
4032     moveDbDirectory(String dir, String dst) throws IOException, LSException, LscpException {
4033     verifyConnection();
4034     out.writeLine("MOVE DB_INSTRUMENT_DIRECTORY '" + dir + "' '" + dst + "'");
4035     if(getPrintOnlyMode()) return;
4036    
4037     ResultSet rs = getEmptyResultSet();
4038     }
4039    
4040     /**
4041     * Moves the specified directories into the specified location.
4042     * @param dirs The absolute path names of the directories to move.
4043     * @param dst The location where the directories will be moved to.
4044     * @throws IOException If some I/O error occurs.
4045     * @throws LSException If the operation failed.
4046     * @throws LscpException If LSCP protocol corruption occurs.
4047     */
4048     public synchronized void
4049     moveDbDirectories(String dirs[], String dst) throws IOException, LSException, LscpException {
4050     verifyConnection();
4051     for(String s : dirs) {
4052     out.writeLine("MOVE DB_INSTRUMENT_DIRECTORY '" + s + "' '" + dst + "'");
4053     }
4054     if(getPrintOnlyMode()) return;
4055    
4056     getEmptyResultSets(dirs.length, "Client.dirMovingFailed!");
4057     }
4058    
4059     /**
4060     * Copies the specified directory into the specified location.
4061     * @param dir The absolute path name of the directory to copy.
4062     * @param dst The location where the directory will be copied to.
4063     * @throws IOException If some I/O error occurs.
4064     * @throws LSException If the operation failed.
4065     * @throws LscpException If LSCP protocol corruption occurs.
4066     */
4067     public synchronized void
4068     copyDbDirectory(String dir, String dst) throws IOException, LSException, LscpException {
4069     verifyConnection();
4070     out.writeLine("COPY DB_INSTRUMENT_DIRECTORY '" + dir + "' '" + dst + "'");
4071     if(getPrintOnlyMode()) return;
4072    
4073     ResultSet rs = getEmptyResultSet();
4074     }
4075    
4076     /**
4077     * Copies the specified directories into the specified location.
4078     * @param dirs The absolute path names of the directories to copy.
4079     * @param dst The location where the directories will be copied to.
4080     * @throws IOException If some I/O error occurs.
4081     * @throws LSException If the operation failed.
4082     * @throws LscpException If LSCP protocol corruption occurs.
4083     */
4084     public synchronized void
4085     copyDbDirectories(String[] dirs, String dst) throws IOException, LSException, LscpException {
4086     verifyConnection();
4087     for(String s : dirs) {
4088     out.writeLine("COPY DB_INSTRUMENT_DIRECTORY '" + s + "' '" + dst + "'");
4089     }
4090     if(getPrintOnlyMode()) return;
4091    
4092     getEmptyResultSets(dirs.length, "Client.dirCopyingFailed!");
4093     }
4094    
4095     /**
4096     * Changes the description of the specified directory.
4097     * @param dir The absolute path name of the directory.
4098     * @param desc The new description for the directory.
4099     * @throws IOException If some I/O error occurs.
4100     * @throws LSException If failed to change the description.
4101     * @throws LscpException If LSCP protocol corruption occurs.
4102     */
4103     public synchronized void
4104     setDbDirectoryDescription(String dir, String desc)
4105     throws IOException, LSException, LscpException {
4106    
4107     verifyConnection();
4108     String s = "SET DB_INSTRUMENT_DIRECTORY DESCRIPTION '";
4109 iliev 1346 out.writeLine(s + dir + "' '" + toEscapedString(desc) + "'");
4110 iliev 1202 if(getPrintOnlyMode()) return;
4111    
4112     ResultSet rs = getEmptyResultSet();
4113     }
4114    
4115     public static enum ScanMode {
4116     RECURSIVE, NON_RECURSIVE, FLAT
4117     }
4118    
4119     /**
4120     * Adds the specified instrument to the specified instruments database directory.
4121     * @param dbDir The absolute path name of the database directory in which the
4122     * specified instrument will be added.
4123     * @param filePath The absolute path name of the instrument file.
4124     * @param instrIndex The index of the instrument (in the given instrument file) to add.
4125     * @throws IOException If some I/O error occurs.
4126     * @throws LSException If the operation failed.
4127     * @throws LscpException If LSCP protocol corruption occurs.
4128     */
4129     public synchronized void
4130     addDbInstrument(String dbDir, String filePath, int instrIndex)
4131     throws IOException, LSException, LscpException {
4132    
4133     addDbInstrument(dbDir, filePath, instrIndex, false);
4134     }
4135    
4136     /**
4137     * Adds the specified instrument to the specified instruments database directory.
4138     * @param dbDir The absolute path name of the database directory in which the
4139     * specified instrument will be added.
4140     * @param filePath The absolute path name of the instrument file.
4141     * @param instrIndex The index of the instrument (in the given instrument file) to add.
4142     * @param background If <code>true</code>, the scan will be done
4143     * in background and this method may return before the job is finished.
4144     * @return If <code>background</code> is <code>true</code>, the ID
4145     * of the scan job.
4146     * @throws IOException If some I/O error occurs.
4147     * @throws LSException If the operation failed.
4148     * @throws LscpException If LSCP protocol corruption occurs.
4149     * @see #addInstrumentsDbListener
4150     */
4151     public synchronized int
4152     addDbInstrument(String dbDir, String filePath, int instrIndex, boolean background)
4153     throws IOException, LSException, LscpException {
4154    
4155     verifyConnection();
4156     String s = "ADD DB_INSTRUMENTS";
4157     if(background) s += " NON_MODAL";
4158 iliev 1351 s += " '" + dbDir + "' '" + filePath + "' ";
4159 iliev 1202 out.writeLine(s + String.valueOf(instrIndex));
4160     if(getPrintOnlyMode()) return -1;
4161    
4162     ResultSet rs = getEmptyResultSet();
4163     return rs.getIndex();
4164     }
4165    
4166     /**
4167     * Adds the instruments in the specified file to the specified
4168     * instruments database directory.
4169     * @param dbDir The absolute path name of the database directory
4170     * in which the the supported instruments will be added.
4171     * @param filePath The absolute path name of the file to scan for instruments.
4172     * @throws IOException If some I/O error occurs.
4173     * @throws LSException If the operation failed.
4174     * @throws LscpException If LSCP protocol corruption occurs.
4175     */
4176     public synchronized void
4177     addDbInstruments(String dbDir, String filePath)
4178     throws IOException, LSException, LscpException {
4179    
4180     addDbInstruments(dbDir, filePath, false);
4181     }
4182    
4183     /**
4184     * Adds the instruments in the specified file to the specified
4185     * instruments database directory.
4186     * @param dbDir The absolute path name of the database directory
4187     * in which the the supported instruments will be added.
4188     * @param filePath The absolute path name of the file to scan for instruments.
4189     * @param background If <code>true</code>, the scan will be done
4190     * in background and this method may return before the job is finished.
4191     * @return If <code>background</code> is <code>true</code>, the ID
4192     * of the scan job.
4193     * @throws IOException If some I/O error occurs.
4194     * @throws LSException If the operation failed.
4195     * @throws LscpException If LSCP protocol corruption occurs.
4196     * @see #addInstrumentsDbListener
4197     */
4198     public synchronized int
4199     addDbInstruments(String dbDir, String filePath, boolean background)
4200     throws IOException, LSException, LscpException {
4201    
4202     verifyConnection();
4203     String s = "ADD DB_INSTRUMENTS";
4204     if(background) s += " NON_MODAL";
4205 iliev 1351 out.writeLine(s + " '" + dbDir + "' '" + filePath + "'");
4206 iliev 1202 if(getPrintOnlyMode()) return -1;
4207    
4208     ResultSet rs = getEmptyResultSet();
4209     return rs.getIndex();
4210     }
4211    
4212     /**
4213     * Adds the instruments in the specified file system directory
4214     * to the specified instruments database directory.
4215     * @param mode Determines the scanning mode. If RECURSIVE is
4216     * specified, all supported instruments in the specified file system
4217     * direcotry will be added to the specified instruments database
4218     * directory, including the instruments in subdirectories
4219     * of the supplied directory. If NON_RECURSIVE is specified,
4220     * the instruments in the subdirectories will not be processed.
4221     * If FLAT is specified, all supported instruments in the specified
4222     * file system direcotry will be added, including the instruments in
4223     * subdirectories of the supplied directory, but the respective
4224     * subdirectory structure will not be recreated in the instruments
4225     * database and all instruments will be added directly in the
4226     * specified database directory.
4227     * @param dbDir The absolute path name of the database directory
4228     * in which the supported instruments will be added.
4229     * @param fsDir The absolute path name of the file system directory.
4230     * @throws IOException If some I/O error occurs.
4231     * @throws LSException If the operation failed.
4232     * @throws LscpException If LSCP protocol corruption occurs.
4233     */
4234     public synchronized void
4235     addDbInstruments(ScanMode mode, String dbDir, String fsDir)
4236     throws IOException, LSException, LscpException {
4237    
4238     addDbInstruments(mode, dbDir, fsDir, false);
4239     }
4240    
4241     /**
4242     * Adds the instruments in the specified file system directory
4243     * to the specified instruments database directory.
4244     * @param mode Determines the scanning mode. If RECURSIVE is
4245     * specified, all supported instruments in the specified file system
4246     * direcotry will be added to the specified instruments database
4247     * directory, including the instruments in subdirectories
4248     * of the supplied directory. If NON_RECURSIVE is specified,
4249     * the instruments in the subdirectories will not be processed.
4250     * If FLAT is specified, all supported instruments in the specified
4251     * file system direcotry will be added, including the instruments in
4252     * subdirectories of the supplied directory, but the respective
4253     * subdirectory structure will not be recreated in the instruments
4254     * database and all instruments will be added directly in the
4255     * specified database directory.
4256     * @param dbDir The absolute path name of the database directory
4257     * in which the supported instruments will be added.
4258     * @param fsDir The absolute path name of the file system directory.
4259     * @param background If <code>true</code>, the scan will be done
4260     * in background and this method may return before the job is finished.
4261     * @return If <code>background</code> is <code>true</code>, the ID
4262     * of the scan job.
4263     * @throws IOException If some I/O error occurs.
4264     * @throws LSException If the operation failed.
4265     * @throws LscpException If LSCP protocol corruption occurs.
4266     * @see #addInstrumentsDbListener
4267     */
4268     public synchronized int
4269     addDbInstruments(ScanMode mode, String dbDir, String fsDir, boolean background)
4270     throws IOException, LSException, LscpException {
4271    
4272     verifyConnection();
4273     StringBuffer sb = new StringBuffer("ADD DB_INSTRUMENTS");
4274     if(background) sb.append(" NON_MODAL");
4275    
4276     switch(mode) {
4277     case RECURSIVE:
4278     sb.append(" RECURSIVE");
4279     break;
4280     case NON_RECURSIVE:
4281     sb.append(" NON_RECURSIVE");
4282     break;
4283     case FLAT:
4284     sb.append(" FLAT");
4285     break;
4286     }
4287    
4288 iliev 1346 sb.append(" '").append(dbDir).append("' '");
4289 iliev 1351 sb.append(fsDir).append("'");
4290 iliev 1202 out.writeLine(sb.toString());
4291     if(getPrintOnlyMode()) return -1;
4292    
4293     ResultSet rs = getEmptyResultSet();
4294     return rs.getIndex();
4295     }
4296    
4297     /**
4298     * Removes the specified instrument from the instruments database.
4299     * @param instr The absolute path name of the instrument to remove.
4300     * @throws IOException If some I/O error occurs.
4301     * @throws LscpException If LSCP protocol corruption occurs.
4302     * @throws LSException If the removing of the instrument failed.
4303     */
4304     public synchronized void
4305     removeDbInstrument(String instr) throws IOException, LscpException, LSException {
4306    
4307     verifyConnection();
4308     out.writeLine("REMOVE DB_INSTRUMENT '" + instr + "'");
4309     if(getPrintOnlyMode()) return;
4310    
4311     ResultSet rs = getEmptyResultSet();
4312     }
4313    
4314     /**
4315     * Removes the specified instruments from the instruments database.
4316     * @param instrs The absolute path names of the instruments to remove.
4317     * @throws IOException If some I/O error occurs.
4318     * @throws LscpException If LSCP protocol corruption occurs.
4319     * @throws LSException If the removing of the instruments failed.
4320     */
4321     public synchronized void
4322     removeDbInstruments(String[] instrs) throws IOException, LscpException, LSException {
4323     verifyConnection();
4324     for(String s : instrs) {
4325     out.writeLine("REMOVE DB_INSTRUMENT '" + s + "'");
4326     }
4327     if(getPrintOnlyMode()) return;
4328    
4329     getEmptyResultSets(instrs.length, "Client.instrDeletionFailed!");
4330     }
4331    
4332     /**
4333     * Gets the number of instruments in the specified directory.
4334     * @return The current number of instruments in the specified directory.
4335     * @param dir The absolute path name of the directory.
4336     * @throws IOException If some I/O error occurs.
4337     * @throws LscpException If LSCP protocol corruption occurs.
4338     * @throws LSException If some other error occurs.
4339     */
4340     public synchronized int
4341     getDbInstrumentCount(String dir) throws IOException, LscpException, LSException {
4342     return getDbInstrumentCount(dir, false);
4343     }
4344    
4345     /**
4346     * Gets the number of instruments in the specified directory.
4347     * @return The current number of instruments in the specified directory.
4348     * @param dir The absolute path name of the directory.
4349     * @param recursive If <code>true</code>, the number of all instruments
4350     * in the specified subtree will be returned.
4351     * @throws IOException If some I/O error occurs.
4352     * @throws LscpException If LSCP protocol corruption occurs.
4353     * @throws LSException If some other error occurs.
4354     */
4355     public synchronized int
4356     getDbInstrumentCount(String dir, boolean recursive)
4357     throws IOException, LscpException, LSException {
4358    
4359     verifyConnection();
4360     String s;
4361     if(recursive) s = "GET DB_INSTRUMENTS RECURSIVE '";
4362     else s = "GET DB_INSTRUMENTS '";
4363     out.writeLine(s + dir + "'");
4364     if(getPrintOnlyMode()) return -1;
4365    
4366     s = getSingleLineResultSet().getResult();
4367     return parseInt(s);
4368     }
4369    
4370     /**
4371     * Gets the list of instruments in the specified directory.
4372     * @param dir The absolute path name of the directory.
4373     * @return A <code>String</code> array providing the names of
4374     * all instruments in the specified directory.
4375     * @throws IOException If some I/O error occurs.
4376     * @throws LscpException If LSCP protocol corruption occurs.
4377     * @throws LSException If the specified path name is invalid.
4378     */
4379     public synchronized String[]
4380     getDbInstrumentNames(String dir) throws IOException, LscpException, LSException {
4381     verifyConnection();
4382     out.writeLine("LIST DB_INSTRUMENTS '" + dir + "'");
4383     if(getPrintOnlyMode()) return null;
4384    
4385 iliev 1346 String[] names = parseEscapedStringList(getSingleLineResultSet().getResult());
4386     for(int i = 0; i < names.length; i++) {
4387 iliev 1351 names[i] = toNonEscapedString(names[i]);
4388 iliev 1346 }
4389     return names;
4390 iliev 1202 }
4391    
4392     /**
4393     * Gets information about the specified instrument.
4394     * @param instr The absolute path name of the instrument.
4395     * @return A <code>DbInstrumentInfo</code> instance providing information
4396     * about the specified instrument.
4397     * @throws IOException If some I/O error occurs.
4398     * @throws LscpException If LSCP protocol corruption occurs.
4399     * @throws LSException If the specified instrument is not found.
4400     */
4401     public synchronized DbInstrumentInfo
4402     getDbInstrumentInfo(String instr) throws IOException, LscpException, LSException {
4403     verifyConnection();
4404     out.writeLine("GET DB_INSTRUMENT INFO '" + instr + "'");
4405     if(getPrintOnlyMode()) return null;
4406    
4407     ResultSet rs = getMultiLineResultSet();
4408     DbInstrumentInfo info = new DbInstrumentInfo(rs.getMultiLineResult());
4409 iliev 1346 String s = getParentDirectory(instr);
4410     if(s != null) info.setDirectoryPath(s);
4411     s = getFileName(instr);
4412     if(s != null) info.setName(toNonEscapedFileName(s));
4413 iliev 1202
4414     return info;
4415     }
4416    
4417     /**
4418     * Gets the list of instruments in the specified directory.
4419     * @param dir The absolute path name of the directory.
4420     * @return A <code>DbInstrumentInfo</code> array providing
4421     * information about all instruments in the specified directory.
4422     * @throws IOException If some I/O error occurs.
4423     * @throws LscpException If LSCP protocol corruption occurs.
4424     * @throws LSException If the specified path name is invalid.
4425     */
4426     public synchronized DbInstrumentInfo[]
4427     getDbInstruments(String dir) throws IOException, LscpException, LSException {
4428     String[] instrS = getDbInstrumentNames(dir);
4429 iliev 1346 if(!hasEndingFileSeparator(dir)) dir += "/";
4430 iliev 1202
4431     DbInstrumentInfo[] infoS = new DbInstrumentInfo[instrS.length];
4432     for(int i = 0; i < instrS.length; i++) {
4433 iliev 1346 infoS[i] = getDbInstrumentInfo(dir + toEscapedFileName(instrS[i]));
4434 iliev 1202 }
4435     return infoS;
4436     }
4437    
4438     /**
4439     * Gets the list of instruments in the specified directory.
4440     * @param dir The absolute path name of the directory.
4441     * @return A <code>DbInstrumentInfo</code> array providing
4442     * information about all instruments in the specified directory.
4443     * @throws IOException If some I/O error occurs.
4444     * @throws LscpException If LSCP protocol corruption occurs.
4445     * @throws LSException If the specified path name is invalid.
4446     *
4447     public synchronized DbInstrumentInfo[]
4448     getDbInstruments(String dir) throws IOException, LscpException, LSException {
4449     String[] instrS = getDbInstrumentNames(dir);
4450     if(instrS.length == 0) return new DbInstrumentInfo[0];
4451    
4452     if(dir.charAt(dir.length() - 1) != '/') dir += "/";
4453    
4454     for(int i = 0; i < instrS.length; i++) {
4455     out.writeLine("GET DB_INSTRUMENT INFO '" + dir + instrS[i] + "'");
4456     }
4457    
4458     if(getPrintOnlyMode()) return null;
4459    
4460     if(dir.length() > 1) dir = dir.substring(0, dir.length() - 1);
4461     StringBuffer sb = new StringBuffer();
4462     DbInstrumentInfo[] infoS = new DbInstrumentInfo[instrS.length];
4463     for(int i = 0; i < instrS.length; i++) {
4464     try {
4465     ResultSet rs = getMultiLineResultSet();
4466     infoS[i] = new DbInstrumentInfo(rs.getMultiLineResult());
4467     infoS[i].setName(instrS[i]);
4468     infoS[i].setDirectoryPath(dir);
4469     } catch (SocketTimeoutException e) {
4470     getLogger().log(Level.FINE, e.getMessage(), e);
4471     sb.append(e.getMessage()).append("\n");
4472     break;
4473     } catch (Exception e) {
4474     getLogger().log(Level.FINE, e.getMessage(), e);
4475     sb.append(e.getMessage()).append("\n");
4476     }
4477     }
4478    
4479     String details = sb.toString();
4480     if(details.length() > 0) {
4481     String err = LscpI18n.getLogMsg("Client.getInstrsInfoFailed!");
4482     throw new LSException(0, err, details);
4483     }
4484    
4485     return infoS;
4486     }*/
4487    
4488     /**
4489     * Renames the specified instrument.
4490     * @param instr The absolute path name of the instrument to rename.
4491     * @param name The new name for the instrument.
4492     * @throws IOException If some I/O error occurs.
4493     * @throws LSException If the renaming of the instrument failed.
4494     * @throws LscpException If LSCP protocol corruption occurs.
4495     */
4496     public synchronized void
4497     renameDbInstrument(String instr, String name)
4498     throws IOException, LSException, LscpException {
4499    
4500     verifyConnection();
4501 iliev 1346 name = toEscapedString(name);
4502 iliev 1202 out.writeLine("SET DB_INSTRUMENT NAME '" + instr + "' '" + name + "'");
4503     if(getPrintOnlyMode()) return;
4504    
4505     ResultSet rs = getEmptyResultSet();
4506     }
4507    
4508     /**
4509     * Moves the specified instrument into the specified location.
4510     * @param instr The absolute path name of the instrument to move.
4511     * @param dst The directory where the specified instrument will be moved to.
4512     * @throws IOException If some I/O error occurs.
4513     * @throws LSException If the operation failed.
4514     * @throws LscpException If LSCP protocol corruption occurs.
4515     */
4516     public synchronized void
4517     moveDbInstrument(String instr, String dst) throws IOException, LSException, LscpException {
4518     verifyConnection();
4519     out.writeLine("MOVE DB_INSTRUMENT '" + instr + "' '" + dst + "'");
4520     if(getPrintOnlyMode()) return;
4521    
4522     ResultSet rs = getEmptyResultSet();
4523     }
4524    
4525     /**
4526     * Moves the specified instruments into the specified location.
4527     * @param instrs The absolute path names of the instruments to move.
4528     * @param dst The directory where the specified instruments will be moved to.
4529     * @throws IOException If some I/O error occurs.
4530     * @throws LSException If the operation failed.
4531     * @throws LscpException If LSCP protocol corruption occurs.
4532     */
4533     public synchronized void
4534     moveDbInstruments(String[] instrs, String dst) throws IOException, LSException, LscpException {
4535     verifyConnection();
4536     for(String s : instrs) {
4537     out.writeLine("MOVE DB_INSTRUMENT '" + s + "' '" + dst + "'");
4538     }
4539     if(getPrintOnlyMode()) return;
4540    
4541     getEmptyResultSets(instrs.length, "Client.instrMovingFailed!");
4542     }
4543    
4544     /**
4545     * Copies the specified instrument into the specified location.
4546     * @param instr The absolute path name of the instrument to copy.
4547     * @param dst The directory where the specified instrument will be copied to.
4548     * @throws IOException If some I/O error occurs.
4549     * @throws LSException If the operation failed.
4550     * @throws LscpException If LSCP protocol corruption occurs.
4551     */
4552     public synchronized void
4553     copyDbInstrument(String instr, String dst) throws IOException, LSException, LscpException {
4554     verifyConnection();
4555     out.writeLine("COPY DB_INSTRUMENT '" + instr + "' '" + dst + "'");
4556     if(getPrintOnlyMode()) return;
4557    
4558     ResultSet rs = getEmptyResultSet();
4559     }
4560    
4561     /**
4562     * Copies the specified instruments into the specified location.
4563     * @param instrs The absolute path name of the instruments to copy.
4564     * @param dst The directory where the specified instruments will be copied to.
4565     * @throws IOException If some I/O error occurs.
4566     * @throws LSException If the operation failed.
4567     * @throws LscpException If LSCP protocol corruption occurs.
4568     */
4569     public synchronized void
4570     copyDbInstruments(String[] instrs, String dst) throws IOException, LSException, LscpException {
4571     verifyConnection();
4572     for(String s : instrs) {
4573     out.writeLine("COPY DB_INSTRUMENT '" + s + "' '" + dst + "'");
4574     }
4575     if(getPrintOnlyMode()) return;
4576    
4577     getEmptyResultSets(instrs.length, "Client.instrCopyingFailed!");
4578     }
4579    
4580     /**
4581     * Changes the description of the specified instrument.
4582     * @param instr The absolute path name of the instrument.
4583     * @param desc The new description for the instrument.
4584     * @throws IOException If some I/O error occurs.
4585     * @throws LSException If failed to change the description.
4586     * @throws LscpException If LSCP protocol corruption occurs.
4587     */
4588     public synchronized void
4589     setDbInstrumentDescription(String instr, String desc)
4590     throws IOException, LSException, LscpException {
4591    
4592     verifyConnection();
4593 iliev 1346 desc = toEscapedString(desc);
4594 iliev 1202 out.writeLine("SET DB_INSTRUMENT DESCRIPTION '" + instr + "' '" + desc + "'");
4595     if(getPrintOnlyMode()) return;
4596    
4597     ResultSet rs = getEmptyResultSet();
4598     }
4599    
4600     /**
4601     * Finds all directories in the specified directory
4602     * that corresponds to the specified search criterias.
4603     * @param dir The absolute path name of the directory to search.
4604     * @param query Provides the search criterias.
4605     * @return A <code>DbDirectoryInfo</code> array providing
4606     * information about all directories that are found in the specified directory.
4607     * @throws IOException If some I/O error occurs.
4608     * @throws LscpException If LSCP protocol corruption occurs.
4609     * @throws LSException If the specified path name is invalid.
4610     */
4611     public synchronized DbDirectoryInfo[]
4612     findDbDirectories(String dir, DbSearchQuery query)
4613     throws IOException, LscpException, LSException {
4614    
4615     return findDbDirectories(dir, query, false);
4616     }
4617    
4618     /**
4619     * Finds all directories in the specified directory
4620     * that corresponds to the specified search criterias.
4621     * @param dir The absolute path name of the directory to search.
4622     * @param query Provides the search criterias.
4623     * @param nonRecursive If <code>true</code>, the search will be non-recursive.
4624     * @return A <code>DbDirectoryInfo</code> array providing
4625     * information about all directories that are found in the specified directory.
4626     * @throws IOException If some I/O error occurs.
4627     * @throws LscpException If LSCP protocol corruption occurs.
4628     * @throws LSException If the specified path name is invalid.
4629     */
4630     public synchronized DbDirectoryInfo[]
4631     findDbDirectories(String dir, DbSearchQuery query, boolean nonRecursive)
4632     throws IOException, LscpException, LSException {
4633    
4634     verifyConnection();
4635     StringBuffer sb = new StringBuffer();
4636     sb.append("FIND DB_INSTRUMENT_DIRECTORIES");
4637     if(nonRecursive) sb.append(" NON_RECURSIVE");
4638     sb.append(" '").append(dir).append("'");
4639    
4640     if(query.name != null && query.name.length() > 0) {
4641 iliev 1346 sb.append(" NAME='").append(toEscapedString(query.name)).append("'");
4642 iliev 1202 }
4643    
4644     String s = query.getCreatedAfter();
4645     String s2 = query.getCreatedBefore();
4646     if(s != null || s2 != null) {
4647     sb.append(" CREATED='");
4648     if(s != null) sb.append(s);
4649     sb.append("..");
4650     if(s2 != null) sb.append(s2);
4651     sb.append("'");
4652     }
4653    
4654     s = query.getModifiedAfter();
4655     s2 = query.getModifiedBefore();
4656     if(s != null || s2 != null) {
4657     sb.append(" MODIFIED='");
4658     if(s != null) sb.append(s);
4659     sb.append("..");
4660     if(s2 != null) sb.append(s2);
4661     sb.append("'");
4662     }
4663    
4664     if(query.description != null && query.description.length() > 0) {
4665 iliev 1346 sb.append(" DESCRIPTION='");
4666     sb.append(toEscapedString(query.description)).append("'");
4667 iliev 1202 }
4668    
4669     out.writeLine(sb.toString());
4670     if(getPrintOnlyMode()) return null;
4671    
4672 iliev 1346 String[] dirS = parseEscapedStringList(getSingleLineResultSet().getResult());
4673 iliev 1202
4674     DbDirectoryInfo[] infoS = new DbDirectoryInfo[dirS.length];
4675     for(int i = 0; i < dirS.length; i++) {
4676     infoS[i] = getDbDirectoryInfo(dirS[i]);
4677     }
4678     return infoS;
4679     }
4680    
4681     /**
4682     * Finds all instruments in the specified directory
4683     * that corresponds to the specified search criterias.
4684     * @param dir The absolute path name of the directory to search.
4685     * @param query Provides the search criterias.
4686     * @return A <code>DbInstrumentInfo</code> array providing
4687     * information about all instruments that are found in the specified directory.
4688     * @throws IOException If some I/O error occurs.
4689     * @throws LscpException If LSCP protocol corruption occurs.
4690     * @throws LSException If the specified path name is invalid.
4691     */
4692     public synchronized DbInstrumentInfo[]
4693     findDbInstruments(String dir, DbSearchQuery query)
4694     throws IOException, LscpException, LSException {
4695    
4696     return findDbInstruments(dir, query, false);
4697     }
4698    
4699     /**
4700     * Finds all instruments in the specified directory
4701     * that corresponds to the specified search criterias.
4702     * @param dir The absolute path name of the directory to search.
4703     * @param query Provides the search criterias.
4704     * @param nonRecursive If <code>true</code>, the search will be non-recursive.
4705     * @return A <code>DbInstrumentInfo</code> array providing
4706     * information about all instruments that are found in the specified directory.
4707     * @throws IOException If some I/O error occurs.
4708     * @throws LscpException If LSCP protocol corruption occurs.
4709     * @throws LSException If the specified path name is invalid.
4710     */
4711     public synchronized DbInstrumentInfo[]
4712     findDbInstruments(String dir, DbSearchQuery query, boolean nonRecursive)
4713     throws IOException, LscpException, LSException {
4714    
4715     verifyConnection();
4716     StringBuffer sb = new StringBuffer();
4717     sb.append("FIND DB_INSTRUMENTS");
4718     if(nonRecursive) sb.append(" NON_RECURSIVE");
4719     sb.append(" '").append(dir).append("'");
4720    
4721     if(query.name != null && query.name.length() > 0) {
4722 iliev 1346 sb.append(" NAME='").append(toEscapedString(query.name)).append("'");
4723 iliev 1202 }
4724    
4725     if(query.formatFamilies.size() > 0) {
4726     sb.append(" FORMAT_FAMILIES='").append(query.formatFamilies.get(0));
4727     for(int i = 1; i < query.formatFamilies.size(); i++) {
4728     sb.append(',').append(query.formatFamilies.get(i));
4729     }
4730     sb.append("'");
4731     }
4732    
4733     if(query.minSize != -1 || query.maxSize != -1) {
4734     sb.append(" SIZE='");
4735     if(query.minSize != -1) sb.append(query.minSize);
4736     sb.append("..");
4737     if(query.maxSize != -1) sb.append(query.maxSize);
4738     sb.append("'");
4739     }
4740    
4741     String s = query.getCreatedAfter();
4742     String s2 = query.getCreatedBefore();
4743     if(s != null || s2 != null) {
4744     sb.append(" CREATED='");
4745     if(s != null) sb.append(s);
4746     sb.append("..");
4747     if(s2 != null) sb.append(s2);
4748     sb.append("'");
4749     }
4750    
4751     s = query.getModifiedAfter();
4752     s2 = query.getModifiedBefore();
4753     if(s != null || s2 != null) {
4754     sb.append(" MODIFIED='");
4755     if(s != null) sb.append(s);
4756     sb.append("..");
4757     if(s2 != null) sb.append(s2);
4758     sb.append("'");
4759     }
4760    
4761     if(query.description != null && query.description.length() > 0) {
4762 iliev 1346 sb.append(" DESCRIPTION='");
4763     sb.append(toEscapedString(query.description)).append("'");
4764 iliev 1202 }
4765    
4766     if(query.instrumentType != DbSearchQuery.InstrumentType.BOTH) {
4767     sb.append(" IS_DRUM=");
4768     if(query.instrumentType == DbSearchQuery.InstrumentType.DRUM) {
4769     sb.append("'true'");
4770     } else {
4771     sb.append("'false'");
4772     }
4773     }
4774    
4775     if(query.product != null && query.product.length() > 0) {
4776 iliev 1346 sb.append(" PRODUCT='").append(toEscapedString(query.product)).append("'");
4777 iliev 1202 }
4778    
4779     if(query.artists != null && query.artists.length() > 0) {
4780 iliev 1346 sb.append(" ARTISTS='").append(toEscapedString(query.artists)).append("'");
4781 iliev 1202 }
4782    
4783     if(query.keywords != null && query.keywords.length() > 0) {
4784 iliev 1346 sb.append(" KEYWORDS='");
4785     sb.append(toEscapedString(query.keywords)).append("'");
4786 iliev 1202 }
4787    
4788     out.writeLine(sb.toString());
4789     if(getPrintOnlyMode()) return null;
4790    
4791 iliev 1346 String[] instrS = parseEscapedStringList(getSingleLineResultSet().getResult());
4792 iliev 1202
4793     DbInstrumentInfo[] infoS = new DbInstrumentInfo[instrS.length];
4794     for(int i = 0; i < instrS.length; i++) {
4795     infoS[i] = getDbInstrumentInfo(instrS[i]);
4796     }
4797     return infoS;
4798     }
4799    
4800     /**
4801     * Gets status information about the specified job.
4802     * @param jobId The ID of the job.
4803     * @return A <code>ScanJobInfo</code> instance providing information
4804     * about the specified job.
4805     * @throws IOException If some I/O error occurs.
4806     * @throws LscpException If LSCP protocol corruption occurs.
4807     * @throws LSException If the specified job is not found.
4808     */
4809     public synchronized ScanJobInfo
4810     getDbInstrumentsJobInfo(int jobId) throws IOException, LscpException, LSException {
4811     verifyConnection();
4812     out.writeLine("GET DB_INSTRUMENTS_JOB INFO " + String.valueOf(jobId));
4813     if(getPrintOnlyMode()) return null;
4814    
4815     ResultSet rs = getMultiLineResultSet();
4816     ScanJobInfo info = new ScanJobInfo(rs.getMultiLineResult());
4817    
4818     return info;
4819     }
4820    
4821     /**
4822 iliev 1354 * Removes all instruments and directories and re-creates
4823     * the instruments database structure.
4824     * @throws IOException If some I/O error occurs.
4825     * @throws LscpException If LSCP protocol corruption occurs.
4826     * @throws LSException If the formatting of the instruments database failed.
4827     */
4828     public synchronized void
4829     formatInstrumentsDb() throws IOException, LscpException, LSException {
4830     verifyConnection();
4831     out.writeLine("FORMAT INSTRUMENTS_DB");
4832     if(getPrintOnlyMode()) return;
4833    
4834     ResultSet rs = getEmptyResultSet();
4835     }
4836    
4837     /**
4838 iliev 596 * Resets the specified sampler channel.
4839     *
4840     * @param samplerChn The sampler channel number.
4841     *
4842     * @throws IOException If some I/O error occurs.
4843     * @throws LscpException If LSCP protocol corruption occurs.
4844     * @throws LSException If <code>samplerChn</code> is not a valid channel number or if
4845     * there is no engine assigned yet to the specified sampler channel.
4846     * @see #getSamplerChannels
4847     */
4848     public synchronized void
4849     resetChannel(int samplerChn) throws IOException, LscpException, LSException {
4850     verifyConnection();
4851     out.writeLine("RESET CHANNEL " + samplerChn);
4852 iliev 1139 if(getPrintOnlyMode()) return;
4853 iliev 596
4854     ResultSet rs = getEmptyResultSet();
4855     }
4856    
4857     /**
4858     * Resets the whole sampler.
4859     *
4860     * @throws IOException If some I/O error occurs.
4861     * @throws LscpException If LSCP protocol corruption occurs.
4862     */
4863     public synchronized void
4864     resetSampler() throws IOException, LscpException {
4865     verifyConnection();
4866     out.writeLine("RESET");
4867 iliev 1139 if(getPrintOnlyMode()) return;
4868    
4869 iliev 596 try { ResultSet rs = getEmptyResultSet(); }
4870     catch(LSException x) { getLogger().warning(x.getMessage()); }
4871     }
4872    
4873     /**
4874 iliev 784 * Gets the current number of all active voices.
4875     * @return The current number of all active voices.
4876     * @throws IOException If some I/O error occurs.
4877     * @throws LscpException If LSCP protocol corruption occurs.
4878     * @throws LSException If some other error occurs.
4879     */
4880     public synchronized int
4881     getTotalVoiceCount() throws IOException, LscpException, LSException {
4882     verifyConnection();
4883     out.writeLine("GET TOTAL_VOICE_COUNT");
4884 iliev 1139 if(getPrintOnlyMode()) return -1;
4885    
4886 iliev 784 String s = getSingleLineResultSet().getResult();
4887     return parseInt(s);
4888     }
4889    
4890     /**
4891     * Gets the maximum number of active voices.
4892     * @return The maximum number of active voices.
4893     * @throws IOException If some I/O error occurs.
4894     * @throws LscpException If LSCP protocol corruption occurs.
4895     * @throws LSException If some other error occurs.
4896     */
4897     public synchronized int
4898     getTotalVoiceCountMax() throws IOException, LscpException, LSException {
4899     verifyConnection();
4900     out.writeLine("GET TOTAL_VOICE_COUNT_MAX");
4901 iliev 1139 if(getPrintOnlyMode()) return -1;
4902    
4903 iliev 784 String s = getSingleLineResultSet().getResult();
4904     return parseInt(s);
4905     }
4906    
4907     /**
4908 iliev 596 * Gets information about the LinuxSampler instance.
4909     *
4910     * @return <code>ServerInfo</code> instance containing
4911     * information about the LinuxSampler instance.
4912     *
4913     * @throws IOException If an I/O error occurs.
4914     * @throws LscpException If LSCP protocol corruption occurs.
4915     * @throws LSException If some other error occurs.
4916     */
4917     public synchronized ServerInfo
4918     getServerInfo() throws IOException, LscpException, LSException {
4919     verifyConnection();
4920     out.writeLine("GET SERVER INFO");
4921 iliev 1139 if(getPrintOnlyMode()) return null;
4922    
4923 iliev 596 ResultSet rs = getMultiLineResultSet();
4924     return new ServerInfo(rs.getMultiLineResult());
4925     }
4926    
4927     /**
4928 iliev 1139 * Gets the golobal volume of the sampler.
4929     * @return The golobal volume of the sampler.
4930     * @throws IOException If some I/O error occurs.
4931     * @throws LscpException If LSCP protocol corruption occurs.
4932     * @throws LSException If some other error occurs.
4933     */
4934     public synchronized float
4935     getVolume() throws IOException, LscpException, LSException {
4936     verifyConnection();
4937     out.writeLine("GET VOLUME");
4938     if(getPrintOnlyMode()) return -1;
4939    
4940     String s = getSingleLineResultSet().getResult();
4941     return parseFloat(s);
4942     }
4943    
4944     /**
4945     * Sets the global volume of the sampler.
4946     * @param volume The new volume value.
4947     * @throws IOException If some I/O error occurs.
4948     * @throws LscpException If LSCP protocol corruption occurs.
4949     * @throws LSException If some other error occurs.
4950     * @see #getVolume
4951     */
4952     public synchronized void
4953     setVolume(float volume) throws IOException, LscpException, LSException {
4954    
4955     verifyConnection();
4956     out.writeLine("SET VOLUME " + volume);
4957     if(getPrintOnlyMode()) return;
4958    
4959     ResultSet rs = getEmptyResultSet();
4960     }
4961    
4962 iliev 1539 /**
4963     * Gets the number of instruments in the specified instrument file.
4964     * @param filename The absolute path name of the instrument file.
4965     * @return The number of instruments in the specified instrument file.
4966     * @throws IOException If some I/O error occurs.
4967     * @throws LscpException If LSCP protocol corruption occurs.
4968     * @throws LSException If the file is not found, or other error occur.
4969     */
4970     public synchronized int
4971     getFileInstrumentCount(String filename) throws IOException, LscpException, LSException {
4972     verifyConnection();
4973     out.writeLine("GET FILE INSTRUMENTS '" + filename +"'");
4974     if(getPrintOnlyMode()) return -1;
4975    
4976     String s = getSingleLineResultSet().getResult();
4977     return parseInt(s);
4978     }
4979    
4980     /**
4981     * Gets information about the instrument with index
4982     * <code>instrIdx</code> in the specified instrument file.
4983     * @param filename The absolute path name of the instrument file.
4984     * @param instrIdx The index of the instrument in the specified instrument file.
4985     * @throws IOException If some I/O error occurs.
4986     * @throws LscpException If LSCP protocol corruption occurs.
4987     * @throws LSException If failed to retrieve information.
4988     */
4989     public synchronized Instrument
4990     getFileInstrumentInfo(String filename, int instrIdx)
4991     throws IOException, LscpException, LSException {
4992    
4993     verifyConnection();
4994     out.writeLine("GET FILE INSTRUMENT INFO '" + filename + "' " + String.valueOf(instrIdx));
4995     if(getPrintOnlyMode()) return null;
4996    
4997     ResultSet rs = getMultiLineResultSet();
4998     Instrument instr = new FileInstrument(rs.getMultiLineResult()) { };
4999    
5000     return instr;
5001     }
5002    
5003     /**
5004     * Gets the list of instruments in the specified instrument file.
5005     * @param filename The absolute path name of the instrument file.
5006     * @return An <code>Instrument</code> array providing
5007     * information about all instruments in the specified instrument file.
5008     * @throws IOException If some I/O error occurs.
5009     * @throws LscpException If LSCP protocol corruption occurs.
5010     * @throws LSException If the specified file name is invalid.
5011     */
5012     public synchronized Instrument[]
5013     getFileInstruments(String filename) throws IOException, LscpException, LSException {
5014     int l = getFileInstrumentCount(filename);
5015     if(l < 0) return null;
5016     Instrument[] instrS = new FileInstrument[l];
5017    
5018     for(int i = 0; i < instrS.length; i++) {
5019     instrS[i] = getFileInstrumentInfo(filename, i);
5020     }
5021     return instrS;
5022     }
5023    
5024     private static class FileInstrument extends AbstractInstrument {
5025     FileInstrument(String[] resultSet) throws LscpException {
5026     super(resultSet);
5027     }
5028    
5029     public String
5030     getEngine() {
5031     // TODO: engine lookup?
5032     return getFormatFamily();
5033     }
5034    
5035     public boolean
5036     parse(String s) throws LscpException {
5037     if(s.startsWith("PRODUCT: ") || s.startsWith("ARTISTS: ")) return true;
5038     return super.parse(s);
5039     }
5040     }
5041    
5042 iliev 1202 private void
5043     getEmptyResultSets(int count, String err) throws LSException {
5044     StringBuffer sb = new StringBuffer();
5045     for(int i = 0; i < count; i++) {
5046     try { getEmptyResultSet(); }
5047     catch (SocketTimeoutException e) {
5048     getLogger().log(Level.FINE, e.getMessage(), e);
5049     sb.append(e.getMessage()).append("\n");
5050     break;
5051     } catch (Exception e) {
5052     getLogger().log(Level.FINE, e.getMessage(), e);
5053     sb.append(e.getMessage()).append("\n");
5054     }
5055     }
5056    
5057     String details = sb.toString();
5058     if(details.length() > 0) {
5059     String s = LscpI18n.getLogMsg(err);
5060     throw new LSException(0, s, details);
5061     }
5062     }
5063    
5064 iliev 1139 /**
5065 iliev 596 * Returns the logger for this library.
5066     * @return The logger for this library.
5067     */
5068     protected static Logger
5069     getLogger() { return Logger.getLogger("org.linuxsampler.lscp"); }
5070     }

  ViewVC Help
Powered by ViewVC