/[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 2194 - (hide annotations) (download)
Tue Jun 28 22:08:23 2011 UTC (12 years, 9 months ago) by iliev
File size: 210216 byte(s)
* added three new methods to EffectParameter class -
  getEffectInstanceId, getIndex, toString

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

  ViewVC Help
Powered by ViewVC