/[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 1542 - (hide annotations) (download)
Tue Dec 4 18:14:31 2007 UTC (16 years, 3 months ago) by iliev
File size: 176657 byte(s)
* Added support for monitoring the total number of active disk streams

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

  ViewVC Help
Powered by ViewVC