/[svn]/jlscp/trunk/src/org/linuxsampler/lscp/Client.java
ViewVC logotype

Contents of /jlscp/trunk/src/org/linuxsampler/lscp/Client.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2287 - (show annotations) (download)
Wed Nov 23 18:58:46 2011 UTC (12 years, 4 months ago) by iliev
File size: 210658 byte(s)
* Client: added new method - getProtocolVersion

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

  ViewVC Help
Powered by ViewVC