/[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 1781 - (hide annotations) (download)
Mon Sep 29 18:21:21 2008 UTC (15 years, 7 months ago) by iliev
File size: 187615 byte(s)
* Implemented option for adding instruments in separate directories
  in the instruments database
  (patch by Chris Cherrett & Andrew Williams, a bit adjusted)

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

  ViewVC Help
Powered by ViewVC