/[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 1817 - (hide annotations) (download)
Wed Dec 24 16:55:54 2008 UTC (15 years, 3 months ago) by iliev
File size: 190412 byte(s)
* Added support for controlling the global sampler-wide limit of
  maximum voices and disk streams

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

  ViewVC Help
Powered by ViewVC