/[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 1718 - (hide annotations) (download)
Wed Mar 19 10:05:33 2008 UTC (16 years, 1 month ago) by iliev
File size: 178298 byte(s)
* Client: added new method - getMidiInstrumentEntries
* fixed a bug in DB_INSTRUMENTS_JOB_INFO notifications

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

  ViewVC Help
Powered by ViewVC