/[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 2193 - (hide annotations) (download)
Tue Jun 28 20:35:21 2011 UTC (12 years, 9 months ago) by iliev
File size: 210144 byte(s)
* minor refactoring

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

  ViewVC Help
Powered by ViewVC