/[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 2240 - (hide annotations) (download)
Tue Aug 16 14:50:01 2011 UTC (12 years, 8 months ago) by iliev
File size: 210530 byte(s)
* Cache engines' info to speed up the sampler channels' info retrieval

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

  ViewVC Help
Powered by ViewVC