/[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 2287 - (hide annotations) (download)
Wed Nov 23 18:58:46 2011 UTC (12 years, 5 months ago) by iliev
File size: 210658 byte(s)
* Client: added new method - getProtocolVersion

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

  ViewVC Help
Powered by ViewVC