/[svn]/jsampler/trunk/src/org/jsampler/CC.java
ViewVC logotype

Contents of /jsampler/trunk/src/org/jsampler/CC.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1867 - (show annotations) (download)
Mon Mar 16 22:12:32 2009 UTC (15 years, 1 month ago) by iliev
File size: 46640 byte(s)
* proper handling of connection failures
* renamed Channels Panels to Channel Lanes
* code cleanup

1 /*
2 * JSampler - a java front-end for LinuxSampler
3 *
4 * Copyright (C) 2005-2009 Grigor Iliev <grigor@grigoriliev.com>
5 *
6 * This file is part of JSampler.
7 *
8 * JSampler 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 * JSampler 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 JSampler; 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.jsampler;
24
25 import java.awt.event.ActionEvent;
26 import java.awt.event.ActionListener;
27
28 import java.io.ByteArrayOutputStream;
29 import java.io.File;
30 import java.io.FileInputStream;
31 import java.io.FileOutputStream;
32 import java.io.InputStream;
33
34 import java.util.Vector;
35
36 import java.util.logging.Handler;
37 import java.util.logging.Level;
38 import java.util.logging.Logger;
39 import java.util.logging.SimpleFormatter;
40 import java.util.logging.StreamHandler;
41
42 import javax.swing.SwingUtilities;
43 import javax.swing.Timer;
44
45 import javax.swing.event.ChangeEvent;
46 import javax.swing.event.ChangeListener;
47
48 import net.sf.juife.Task;
49 import net.sf.juife.TaskQueue;
50
51 import net.sf.juife.event.TaskEvent;
52 import net.sf.juife.event.TaskListener;
53 import net.sf.juife.event.TaskQueueEvent;
54 import net.sf.juife.event.TaskQueueListener;
55
56 import org.jsampler.event.ListEvent;
57 import org.jsampler.event.ListListener;
58 import org.jsampler.event.OrchestraEvent;
59 import org.jsampler.event.OrchestraListener;
60
61 import org.jsampler.task.*;
62
63 import org.jsampler.view.JSMainFrame;
64 import org.jsampler.view.JSProgress;
65 import org.jsampler.view.JSViewConfig;
66 import org.jsampler.view.InstrumentsDbTreeModel;
67
68 import org.linuxsampler.lscp.AudioOutputChannel;
69 import org.linuxsampler.lscp.AudioOutputDevice;
70 import org.linuxsampler.lscp.Client;
71 import org.linuxsampler.lscp.FxSend;
72 import org.linuxsampler.lscp.MidiInputDevice;
73 import org.linuxsampler.lscp.MidiPort;
74 import org.linuxsampler.lscp.Parameter;
75 import org.linuxsampler.lscp.SamplerChannel;
76
77 import org.linuxsampler.lscp.event.*;
78
79 import org.w3c.dom.Document;
80 import org.w3c.dom.Node;
81
82 import static org.jsampler.JSI18n.i18n;
83
84
85 /**
86 * This class serves as a 'Control Center' of the application.
87 * It also provides some fundamental routines and access to most used objects.
88 * @author Grigor Iliev
89 */
90 public class CC {
91 private static Handler handler;
92 private static FileOutputStream fos;
93
94 private static JSViewConfig viewConfig = null;
95 private static JSMainFrame mainFrame = null;
96 private static JSProgress progress = null;
97
98 private final static Client lsClient = new Client();
99
100 private static String jSamplerHome = null;
101
102 private final static TaskQueue taskQueue = new TaskQueue();
103 private final static Timer timer = new Timer(2000, null);
104
105 private static int connectionFailureCount = 0;
106
107 /** Forbits the instantiation of this class. */
108 private
109 CC() { }
110
111 /**
112 * Returns the logger to be used for logging events.
113 * @return The logger to be used for logging events.
114 */
115 public static Logger
116 getLogger() {
117 return Logger.getLogger (
118 "org.jsampler",
119 "org.jsampler.langprops.LogsBundle"
120 );
121 }
122
123 /**
124 * Returns the task queue to be used for scheduling tasks
125 * for execution out of the event-dispatching thread.
126 * @return The task queue to be used for scheduling tasks
127 * for execution out of the event-dispatching thread.
128 */
129 public static synchronized TaskQueue
130 getTaskQueue() { return taskQueue; }
131
132 /**
133 * Adds the specified task to the task queue. All task in the
134 * queue equal to the specified task are removed from the queue.
135 */
136 public static synchronized void
137 scheduleTask(Task t) {
138 while(getTaskQueue().removeTask(t)) { }
139
140 getTaskQueue().add(t);
141 }
142
143 /**
144 * Adds the specified task to the task queue only if the last
145 * task in the queue is not equal to <code>t</code>.
146 */
147 public static synchronized void
148 addTask(Task t) {
149 Task[] tasks = getTaskQueue().getPendingTasks();
150 if(tasks.length > 0 && tasks[tasks.length - 1].equals(t)) return;
151 getTaskQueue().add(t);
152 }
153
154 /**
155 * Gets the configuration of the current view.
156 */
157 public static JSViewConfig
158 getViewConfig() { return viewConfig; }
159
160 public static JSPrefs
161 preferences() { return getViewConfig().preferences(); }
162
163 /**
164 * Sets the configuration of the current view.
165 */
166 public static void
167 setViewConfig(JSViewConfig viewConfig) { CC.viewConfig = viewConfig; }
168
169 /**
170 * Returns the main window of this application.
171 * @return The main window of this application.
172 */
173 public static JSMainFrame
174 getMainFrame() { return mainFrame; }
175
176 /**
177 * Sets the main window of this application.
178 * @param mainFrame The main window of this application.
179 */
180 public static void
181 setMainFrame(JSMainFrame mainFrame) { CC.mainFrame = mainFrame; }
182
183 /**
184 * Gets the progress indicator of this application.
185 * @return The progress indicator of this application.
186 */
187 public static JSProgress
188 getProgressIndicator() { return progress; }
189
190 /**
191 * Sets the progress indicator to be used by this application.
192 * @param progress The progress indicator to be used by this application.
193 */
194 public static void
195 setProgressIndicator(JSProgress progress) { CC.progress = progress; }
196
197 /**
198 * Gets the absolute path to the JSampler's home location.
199 * @return The absolute path to the JSampler's home location
200 * or <code>null</code> if the JSampler's home location is not specified yet.
201 */
202 public static String
203 getJSamplerHome() { return jSamplerHome; }
204
205 /**
206 * Sets the location of the JSampler's home.
207 * @param path The new absolute path to the JSampler's home location.
208 */
209 public static void
210 setJSamplerHome(String path) {
211 jSamplerHome = path;
212 Prefs.setJSamplerHome(jSamplerHome);
213 }
214
215 /**
216 * This method does the initial preparation of the application.
217 */
218 protected static void
219 initJSampler() {
220 fos = null;
221 setJSamplerHome(Prefs.getJSamplerHome());
222 String s = getJSamplerHome();
223 try {
224 if(s != null) {
225 s += File.separator + "jsampler.log";
226 File f = new File(s);
227 if(f.isFile()) HF.createBackup("jsampler.log", "jsampler.log.0");
228 fos = new FileOutputStream(s);
229 }
230 } catch(Exception x) { x.printStackTrace(); }
231
232 if(fos == null) handler = new StreamHandler(System.out, new SimpleFormatter());
233 else handler = new StreamHandler(fos, new SimpleFormatter());
234
235 handler.setLevel(Level.FINE);
236 getLogger().addHandler(handler);
237 getLogger().setLevel(Level.FINE);
238 Logger.getLogger("org.linuxsampler.lscp").setLevel(Level.FINE);
239 Logger.getLogger("org.linuxsampler.lscp").addHandler(handler);
240
241 // Flushing logs on every second
242 new java.util.Timer().schedule(new java.util.TimerTask() {
243 public void
244 run() { if(handler != null) handler.flush(); }
245 }, 1000, 1000);
246
247 getLogger().fine("CC.jsStarted");
248
249 HF.setUIDefaultFont(Prefs.getInterfaceFont());
250
251 timer.setRepeats(false);
252
253 timer.addActionListener(new ActionListener() {
254 public void
255 actionPerformed(ActionEvent e) { CC.getProgressIndicator().start(); }
256 });
257
258 getTaskQueue().addTaskQueueListener(getHandler());
259
260 getTaskQueue().start();
261
262 getClient().removeChannelCountListener(getHandler());
263 getClient().addChannelCountListener(getHandler());
264
265 getClient().removeChannelInfoListener(getHandler());
266 getClient().addChannelInfoListener(getHandler());
267
268 getClient().removeFxSendCountListener(getHandler());
269 getClient().addFxSendCountListener(getHandler());
270
271 getClient().removeFxSendInfoListener(getHandler());
272 getClient().addFxSendInfoListener(getHandler());
273
274 getClient().removeStreamCountListener(getHandler());
275 getClient().addStreamCountListener(getHandler());
276
277 getClient().removeVoiceCountListener(getHandler());
278 getClient().addVoiceCountListener(getHandler());
279
280 getClient().removeTotalStreamCountListener(getHandler());
281 getClient().addTotalStreamCountListener(getHandler());
282
283 getClient().removeTotalVoiceCountListener(getHandler());
284 getClient().addTotalVoiceCountListener(getHandler());
285
286 getClient().removeAudioDeviceCountListener(audioDeviceCountListener);
287 getClient().addAudioDeviceCountListener(audioDeviceCountListener);
288
289 getClient().removeAudioDeviceInfoListener(audioDeviceInfoListener);
290 getClient().addAudioDeviceInfoListener(audioDeviceInfoListener);
291
292 getClient().removeMidiDeviceCountListener(midiDeviceCountListener);
293 getClient().addMidiDeviceCountListener(midiDeviceCountListener);
294
295 getClient().removeMidiDeviceInfoListener(midiDeviceInfoListener);
296 getClient().addMidiDeviceInfoListener(midiDeviceInfoListener);
297
298 getClient().removeMidiInstrumentMapCountListener(midiInstrMapCountListener);
299 getClient().addMidiInstrumentMapCountListener(midiInstrMapCountListener);
300
301 getClient().removeMidiInstrumentMapInfoListener(midiInstrMapInfoListener);
302 getClient().addMidiInstrumentMapInfoListener(midiInstrMapInfoListener);
303
304 getClient().removeMidiInstrumentCountListener(getHandler());
305 getClient().addMidiInstrumentCountListener(getHandler());
306
307 getClient().removeMidiInstrumentInfoListener(getHandler());
308 getClient().addMidiInstrumentInfoListener(getHandler());
309
310 getClient().removeGlobalInfoListener(getHandler());
311 getClient().addGlobalInfoListener(getHandler());
312
313 getClient().removeChannelMidiDataListener(getHandler());
314 getClient().addChannelMidiDataListener(getHandler());
315
316 CC.addConnectionEstablishedListener(new ActionListener() {
317 public void
318 actionPerformed(ActionEvent e) {
319 connectionFailureCount = 0;
320 }
321 });
322 }
323
324 /**
325 * Checks whether the JSampler home directory is specified and exist.
326 * If the JSampler home directory is not specifed, or is specified
327 * but doesn't exist, a procedure of specifying a JSampler home
328 * directory is initiated.
329 * @see org.jsampler.view.JSMainFrame#installJSamplerHome
330 */
331 public static void
332 checkJSamplerHome() {
333 if(getJSamplerHome() != null) {
334 File f = new File(getJSamplerHome());
335 if(f.exists() && f.isDirectory()) {
336 return;
337 }
338 }
339
340 getMainFrame().installJSamplerHome();
341 }
342
343 /**
344 * Changes the JSampler's home directory and moves all files from
345 * the old JSampler's home directory to the new one. If all files are
346 * moved succesfully, the old directory is deleted.
347 * @param path The location of the new JSampler's home directory. If
348 * the last directory in the path doesn't exist, it is created.
349 */
350 public static void
351 changeJSamplerHome(String path) {
352 File fNew = new File(path);
353 if(fNew.exists() && fNew.isFile()) {
354 HF.showErrorMessage(i18n.getError("CC.JSamplerHomeIsNotDir!"));
355 return;
356 }
357
358 if(!fNew.exists()) {
359 if(!fNew.mkdir()) {
360 String s = fNew.getAbsolutePath();
361 HF.showErrorMessage(i18n.getError("CC.mkdirFailed", s));
362 return;
363 }
364 }
365
366 if(getJSamplerHome() == null || path.equals(getJSamplerHome())) {
367 setJSamplerHome(fNew.getAbsolutePath());
368 return;
369 }
370
371 File fOld = new File(getJSamplerHome());
372 if(!fOld.exists() || !fOld.isDirectory()) {
373 setJSamplerHome(fNew.getAbsolutePath());
374 return;
375 }
376
377 File[] files = fOld.listFiles();
378 boolean b = true;
379 if(files != null) {
380 String s = fNew.getAbsolutePath() + File.separator;
381 for(File f : files) if(!f.renameTo(new File(s + f.getName()))) b = false;
382 }
383
384 if(b) fOld.delete();
385 setJSamplerHome(fNew.getAbsolutePath());
386 }
387
388 private final static OrchestraListModel orchestras = new DefaultOrchestraListModel();
389
390 /**
391 * Returns a list containing all available orchestras.
392 * @return A list containing all available orchestras.
393 */
394 public static OrchestraListModel
395 getOrchestras() { return orchestras; }
396
397 private final static ServerList servers = new ServerList();
398
399 /** Returns the server list. */
400 public static ServerList
401 getServerList() { return servers; }
402
403 private static ServerListListener serverListListener = new ServerListListener();
404
405 private static class ServerListListener implements ChangeListener {
406 @Override
407 public void
408 stateChanged(ChangeEvent e) {
409 saveServerList();
410 }
411 }
412
413 private static final Vector<ChangeListener> idtmListeners = new Vector<ChangeListener>();
414 private static InstrumentsDbTreeModel instrumentsDbTreeModel = null;
415
416 /**
417 * Gets the tree model of the instruments database.
418 * If the currently used view doesn't have instruments
419 * database support the tree model is initialized on first use.
420 * @return The tree model of the instruments database or
421 * <code>null</code> if the backend doesn't have instruments database support.
422 * @see org.jsampler.view.JSViewConfig#getInstrumentsDbSupport
423 */
424 public static InstrumentsDbTreeModel
425 getInstrumentsDbTreeModel() {
426 if(getSamplerModel().getServerInfo() == null) return null;
427 if(!getSamplerModel().getServerInfo().hasInstrumentsDbSupport()) return null;
428
429 if(instrumentsDbTreeModel == null) {
430 instrumentsDbTreeModel = new InstrumentsDbTreeModel();
431 for(ChangeListener l : idtmListeners) l.stateChanged(null);
432 }
433
434 return instrumentsDbTreeModel;
435 }
436
437 public static void
438 addInstrumentsDbChangeListener(ChangeListener l) {
439 idtmListeners.add(l);
440 }
441
442 public static void
443 removeInstrumentsDbChangeListener(ChangeListener l) {
444 idtmListeners.remove(l);
445 }
446
447 private static final LostFilesModel lostFilesModel = new LostFilesModel();
448
449 public static LostFilesModel
450 getLostFilesModel() { return lostFilesModel; }
451
452 /**
453 * Loads the orchestras described in <code>&lt;jsampler_home&gt;/orchestras.xml</code>.
454 * If file with name <code>orchestras.xml.bkp</code> exist in the JSampler's home
455 * directory, this means that the last save has failed. In that case a recovery file
456 * <code>orchestras.xml.rec</code> is created and a recovery procedure
457 * will be initiated.
458 */
459 public static void
460 loadOrchestras() {
461 if(getJSamplerHome() == null) return;
462
463 try {
464 String s = getJSamplerHome();
465
466 File f = new File(s + File.separator + "orchestras.xml.bkp");
467 if(f.isFile()) HF.createBackup("orchestras.xml.bkp", "orchestras.xml.rec");
468
469 FileInputStream fis;
470 fis = new FileInputStream(s + File.separator + "orchestras.xml");
471
472 loadOrchestras(fis);
473 fis.close();
474 } catch(Exception x) {
475 getLogger().log(Level.INFO, HF.getErrorMessage(x), x);
476 }
477
478 getOrchestras().addOrchestraListListener(getHandler());
479 }
480
481
482 private static void
483 loadOrchestras(InputStream in) {
484 Document doc = DOMUtils.readObject(in);
485
486 try { getOrchestras().readObject(doc.getDocumentElement()); }
487 catch(Exception x) {
488 HF.showErrorMessage(x, "Loading orchestras: ");
489 return;
490 }
491
492 for(int i = 0; i < getOrchestras().getOrchestraCount(); i++) {
493 getOrchestras().getOrchestra(i).addOrchestraListener(getHandler());
494 }
495 }
496
497 private static void
498 saveOrchestras() {
499 try {
500 String s = getJSamplerHome();
501 if(s == null) return;
502
503 HF.createBackup("orchestras.xml", "orchestras.xml.bkp");
504
505 FileOutputStream fos2;
506 fos2 = new FileOutputStream(s + File.separator + "orchestras.xml", false);
507
508 Document doc = DOMUtils.createEmptyDocument();
509
510 Node node = doc.createElement("temp");
511 doc.appendChild(node);
512
513 getOrchestras().writeObject(doc, doc.getDocumentElement());
514
515 doc.replaceChild(node.getFirstChild(), node);
516
517 DOMUtils.writeObject(doc, fos2);
518
519 fos2.close();
520
521 HF.deleteFile("orchestras.xml.bkp");
522 } catch(Exception x) {
523 HF.showErrorMessage(x, "Saving orchestras: ");
524 return;
525 }
526 }
527
528 /**
529 * Loads the servers' info described in <code>&lt;jsampler_home&gt;/servers.xml</code>.
530 * If file with name <code>servers.xml.bkp</code> exist in the JSampler's home
531 * directory, this means that the last save has failed. In that case a recovery file
532 * <code>servers.xml.rec</code> is created and a recovery procedure
533 * will be initiated.
534 */
535 public static void
536 loadServerList() {
537 if(getJSamplerHome() == null) return;
538
539 try {
540 String s = getJSamplerHome();
541
542 File f = new File(s + File.separator + "servers.xml.bkp");
543 if(f.isFile()) HF.createBackup("servers.xml.bkp", "servers.xml.rec");
544
545 FileInputStream fis;
546 fis = new FileInputStream(s + File.separator + "servers.xml");
547
548 loadServerList(fis);
549 fis.close();
550 } catch(Exception x) {
551 getLogger().log(Level.INFO, HF.getErrorMessage(x), x);
552 }
553
554 getServerList().addChangeListener(serverListListener);
555
556 /* We should have at least one server to connect. */
557 if(getServerList().getServerCount() == 0) {
558 Server server = new Server();
559 server.setName("127.0.0.1:8888");
560 server.setAddress("127.0.0.1");
561 server.setPort(8888);
562 getServerList().addServer(server);
563 }
564 }
565
566
567 private static void
568 loadServerList(InputStream in) {
569 Document doc = DOMUtils.readObject(in);
570
571 try { getServerList().readObject(doc.getDocumentElement()); }
572 catch(Exception x) {
573 HF.showErrorMessage(x, "Loading server list: ");
574 return;
575 }
576 }
577
578 private static void
579 saveServerList() {
580 try {
581 String s = getJSamplerHome();
582 if(s == null) return;
583
584 HF.createBackup("servers.xml", "servers.xml.bkp");
585
586 FileOutputStream fos2;
587 fos2 = new FileOutputStream(s + File.separator + "servers.xml", false);
588
589 Document doc = DOMUtils.createEmptyDocument();
590
591 Node node = doc.createElement("temp");
592 doc.appendChild(node);
593
594 getServerList().writeObject(doc, doc.getDocumentElement());
595
596 doc.replaceChild(node.getFirstChild(), node);
597
598 DOMUtils.writeObject(doc, fos2);
599
600 fos2.close();
601
602 HF.deleteFile("servers.xml.bkp");
603 } catch(Exception x) {
604 HF.showErrorMessage(x, "Saving server list: ");
605 return;
606 }
607 }
608
609 /**
610 * The exit point of the application which ensures clean exit with default exit status 0.
611 * @see #cleanExit(int i)
612 */
613 public static void
614 cleanExit() { cleanExit(0); }
615
616 /**
617 * The exit point of the application which ensures clean exit.
618 * @param i The exit status.
619 */
620 public static void
621 cleanExit(int i) {
622 getLogger().fine("CC.jsEnded");
623 try { getClient().disconnect(); } // FIXME: this might block the EDT
624 catch(Exception x) { x.printStackTrace(); }
625 if(backendProcess != null) backendProcess.destroy();
626 backendProcess = null;
627 fireBackendProcessEvent();
628 System.exit(i);
629 }
630
631 /**
632 * Gets the <code>Client</code> object that is used to communicate with the backend.
633 * @return The <code>Client</code> object that is used to communicate with the backend.
634 */
635 public static Client
636 getClient() { return lsClient; }
637
638 private static final Vector<ActionListener> listeners = new Vector<ActionListener>();
639
640 /**
641 * Registers the specified listener to be notified when reconnecting to LinuxSampler.
642 * @param l The <code>ActionListener</code> to register.
643 */
644 public static void
645 addReconnectListener(ActionListener l) { listeners.add(l); }
646
647 /**
648 * Removes the specified listener.
649 * @param l The <code>ActionListener</code> to remove.
650 */
651 public static void
652 removeReconnectListener(ActionListener l) { listeners.remove(l); }
653
654 private static void
655 fireReconnectEvent() {
656 ActionEvent e = new ActionEvent(CC.class, ActionEvent.ACTION_PERFORMED, null);
657 for(ActionListener l : listeners) l.actionPerformed(e);
658 }
659
660 private static final Vector<ActionListener> ceListeners = new Vector<ActionListener>();
661
662 /**
663 * Registers the specified listener to be notified when
664 * jsampler is connected successfully to LinuxSampler.
665 * @param l The <code>ActionListener</code> to register.
666 */
667 public static void
668 addConnectionEstablishedListener(ActionListener l) { ceListeners.add(l); }
669
670 /**
671 * Removes the specified listener.
672 * @param l The <code>ActionListener</code> to remove.
673 */
674 public static void
675 removeConnectionEstablishedListener(ActionListener l) { ceListeners.remove(l); }
676
677 private static void
678 fireConnectionEstablishedEvent() {
679 ActionEvent e = new ActionEvent(CC.class, ActionEvent.ACTION_PERFORMED, null);
680 for(ActionListener l : ceListeners) l.actionPerformed(e);
681 }
682
683 private static final SamplerModel samplerModel = new DefaultSamplerModel();
684
685 /**
686 * Gets the sampler model.
687 * @return The sampler model.
688 */
689 public static SamplerModel
690 getSamplerModel() { return samplerModel; }
691
692 /**
693 * Connects to LinuxSampler.
694 */
695 public static void
696 connect() { initSamplerModel(); }
697
698 /**
699 * Reconnects to LinuxSampler.
700 */
701 public static void
702 reconnect() { initSamplerModel(getCurrentServer()); }
703
704 private static Server currentServer = null;
705
706 /**
707 * Gets the server, to which the frontend is going to connect
708 * or is already connected.
709 */
710 public static Server
711 getCurrentServer() { return currentServer; }
712
713 /**
714 * Sets the current server.
715 */
716 public static void
717 setCurrentServer(Server server) {
718 if(server == currentServer) return;
719 connectionFailureCount = 0;
720 currentServer = server;
721 }
722
723 /**
724 * Sets the LSCP client's read timeout.
725 * @param timeout The new timeout value (in seconds).
726 */
727 public static void
728 setClientReadTimeout(int timeout) {
729 getTaskQueue().add(new Global.SetClientReadTimeout(timeout));
730 }
731
732 /**
733 * This method updates the information about the backend state.
734 */
735 private static void
736 initSamplerModel() {
737 Server srv = getMainFrame().getServer();
738 if(srv == null) return;
739 initSamplerModel(srv);
740 }
741
742 /**
743 * This method updates the information about the backend state.
744 */
745 private static void
746 initSamplerModel(Server srv) {
747 setCurrentServer(srv);
748 final SetServerAddress ssa = new SetServerAddress(srv.getAddress(), srv.getPort());
749
750 final DefaultSamplerModel model = (DefaultSamplerModel)getSamplerModel();
751
752 final Global.GetServerInfo gsi = new Global.GetServerInfo();
753 gsi.addTaskListener(new TaskListener() {
754 public void
755 taskPerformed(TaskEvent e) {
756 if(gsi.doneWithErrors()) return;
757
758 model.setServerInfo(gsi.getResult());
759
760 if(CC.getViewConfig().getInstrumentsDbSupport()) {
761 getInstrumentsDbTreeModel();
762 }
763 }
764 });
765
766 final Audio.GetDrivers gaod = new Audio.GetDrivers();
767 gaod.addTaskListener(new TaskListener() {
768 public void
769 taskPerformed(TaskEvent e) {
770 if(!gaod.doneWithErrors())
771 model.setAudioOutputDrivers(gaod.getResult());
772 }
773 });
774
775 final Global.GetEngines ge = new Global.GetEngines();
776 ge.addTaskListener(new TaskListener() {
777 public void
778 taskPerformed(TaskEvent e) {
779 if(!ge.doneWithErrors()) model.setEngines(ge.getResult());
780 }
781 });
782
783 final Midi.GetDrivers gmid = new Midi.GetDrivers();
784 gmid.addTaskListener(new TaskListener() {
785 public void
786 taskPerformed(TaskEvent e) {
787 if(!gmid.doneWithErrors())
788 model.setMidiInputDrivers(gmid.getResult());
789 }
790 });
791
792 final Global.GetVolume gv = new Global.GetVolume();
793 gv.addTaskListener(new TaskListener() {
794 public void
795 taskPerformed(TaskEvent e) {
796 if(!gv.doneWithErrors())
797 model.setVolume(gv.getResult());
798 }
799 });
800
801 final Midi.GetInstrumentMaps mgim = new Midi.GetInstrumentMaps();
802 mgim.addTaskListener(new TaskListener() {
803 public void
804 taskPerformed(TaskEvent e) {
805 if(mgim.doneWithErrors()) return;
806 model.removeAllMidiInstrumentMaps();
807
808 for(MidiInstrumentMap map : mgim.getResult()) {
809 model.addMidiInstrumentMap(map);
810 }
811 }
812 });
813
814 final UpdateChannels uc = new UpdateChannels();
815 uc.addTaskListener(new TaskListener() {
816 public void
817 taskPerformed(TaskEvent e) {
818 for(SamplerChannelModel c : model.getChannels()) {
819 if(c.getChannelInfo().getEngine() == null) continue;
820
821 Channel.GetFxSends gfs = new Channel.GetFxSends();
822 gfs.setChannel(c.getChannelId());
823 gfs.addTaskListener(new GetFxSendsListener());
824 getTaskQueue().add(gfs);
825 }
826
827 // TODO: This should be done after the fx sends are set
828 //CC.getSamplerModel().setModified(false);
829 }
830 });
831
832
833 final Global.Connect cnt = new Global.Connect();
834 boolean b = preferences().getBoolProperty(JSPrefs.LAUNCH_BACKEND_LOCALLY);
835 if(b && srv.isLocal() && backendProcess == null) cnt.setSilent(true);
836 cnt.addTaskListener(new TaskListener() {
837 public void
838 taskPerformed(TaskEvent e) {
839 if(cnt.doneWithErrors()) {
840 onConnectFailure();
841 return;
842 }
843
844 getTaskQueue().add(gsi);
845 getTaskQueue().add(gaod);
846 getTaskQueue().add(gmid);
847 getTaskQueue().add(ge);
848 getTaskQueue().add(gv);
849 getTaskQueue().add(mgim);
850 getTaskQueue().add(new Midi.UpdateDevices());
851 getTaskQueue().add(new Audio.UpdateDevices());
852 addTask(uc);
853
854 int vl = preferences().getIntProperty(JSPrefs.GLOBAL_VOICE_LIMIT);
855 int sl = preferences().getIntProperty(JSPrefs.GLOBAL_STREAM_LIMIT);
856
857 getTaskQueue().add(new Global.SetPolyphony(vl, sl));
858
859 fireConnectionEstablishedEvent();
860 }
861 });
862
863 ssa.addTaskListener(new TaskListener() {
864 public void
865 taskPerformed(TaskEvent e) {
866 int t = preferences().getIntProperty(JSPrefs.SOCKET_READ_TIMEOUT);
867 CC.setClientReadTimeout(t * 1000);
868 CC.getTaskQueue().add(cnt);
869 }
870 });
871
872 getSamplerModel().reset();
873 if(instrumentsDbTreeModel != null) {
874 instrumentsDbTreeModel.reset();
875 instrumentsDbTreeModel = null;
876 }
877
878 getTaskQueue().removePendingTasks();
879 getTaskQueue().add(ssa);
880
881 fireReconnectEvent();
882 }
883
884 private static void
885 onConnectFailure() {
886 connectionFailureCount++;
887 if(connectionFailureCount > 50) { // to prevent eventual infinite loop
888 getLogger().warning("Reached maximum number of connection failures");
889 return;
890 }
891
892 try {
893 if(launchBackend()) {
894 int i = preferences().getIntProperty(JSPrefs.BACKEND_LAUNCH_DELAY);
895 if(i < 1) {
896 initSamplerModel(getCurrentServer());
897 return;
898 }
899
900 LaunchBackend lb = new LaunchBackend(i, getBackendMonitor());
901 //CC.getTaskQueue().add(lb);
902 new Thread(lb).start();
903 return;
904 }
905 } catch(Exception x) {
906 final String s = JSI18n.i18n.getError("CC.failedToLaunchBackend");
907 CC.getLogger().log(Level.INFO, s, x);
908
909 SwingUtilities.invokeLater(new Runnable() {
910 public void
911 run() { HF.showErrorMessage(s); }
912 });
913 return;
914 }
915
916 retryToConnect();
917 }
918
919 private static void
920 retryToConnect() {
921 javax.swing.SwingUtilities.invokeLater(new Runnable() {
922 public void
923 run() { changeBackend(); }
924 });
925 }
926
927 public static void
928 changeBackend() {
929 Server s = getMainFrame().getServer(true);
930 if(s != null) {
931 connectionFailureCount = 0; // cleared because this change due to user interaction
932 initSamplerModel(s);
933 }
934 }
935
936 private static final Vector<ActionListener> pListeners = new Vector<ActionListener>();
937
938 /**
939 * Registers the specified listener to be notified when
940 * backend process is created/terminated.
941 * @param l The <code>ActionListener</code> to register.
942 */
943 public static void
944 addBackendProcessListener(ActionListener l) { pListeners.add(l); }
945
946 /**
947 * Removes the specified listener.
948 * @param l The <code>ActionListener</code> to remove.
949 */
950 public static void
951 removeBackendProcessListener(ActionListener l) { pListeners.remove(l); }
952
953 private static void
954 fireBackendProcessEvent() {
955 ActionEvent e = new ActionEvent(CC.class, ActionEvent.ACTION_PERFORMED, null);
956 for(ActionListener l : pListeners) l.actionPerformed(e);
957 }
958
959 private static Process backendProcess = null;
960
961 public static Process
962 getBackendProcess() { return backendProcess; }
963
964 private static final Object backendMonitor = new Object();
965
966 public static Object
967 getBackendMonitor() { return backendMonitor; }
968
969 private static boolean
970 launchBackend() throws Exception {
971 if(backendProcess != null) {
972 try {
973 int i = backendProcess.exitValue();
974 getLogger().info("Backend exited with exit value " + i);
975 backendProcess = null;
976 fireBackendProcessEvent();
977 } catch(IllegalThreadStateException x) { return false; }
978 }
979
980 if(!preferences().getBoolProperty(JSPrefs.LAUNCH_BACKEND_LOCALLY)) return false;
981 if(connectionFailureCount > 1) return false;
982
983 Server s = getCurrentServer();
984 if(s != null && s.isLocal()) {
985 String cmd = preferences().getStringProperty(JSPrefs.BACKEND_LAUNCH_COMMAND);
986 backendProcess = Runtime.getRuntime().exec(cmd);
987 fireBackendProcessEvent();
988 return true;
989 }
990
991 return false;
992 }
993
994 private static class GetFxSendsListener implements TaskListener {
995 @Override
996 public void
997 taskPerformed(TaskEvent e) {
998 Channel.GetFxSends gfs = (Channel.GetFxSends)e.getSource();
999 if(gfs.doneWithErrors()) return;
1000 SamplerChannelModel m = getSamplerModel().getChannelById(gfs.getChannel());
1001 m.removeAllFxSends();
1002
1003 for(FxSend fxs : gfs.getResult()) m.addFxSend(fxs);
1004 }
1005 }
1006
1007 public static String
1008 exportInstrMapsToLscpScript() {
1009 StringBuffer sb = new StringBuffer("# Exported by: ");
1010 sb.append("JSampler - a java front-end for LinuxSampler\r\n# Version: ");
1011 sb.append(JSampler.VERSION).append("\r\n");
1012 sb.append("# Date: ").append(new java.util.Date().toString()).append("\r\n\r\n");
1013
1014 Client lscpClient = new Client(true);
1015 ByteArrayOutputStream out = new ByteArrayOutputStream();
1016 lscpClient.setPrintOnlyModeOutputStream(out);
1017
1018 exportInstrMapsToLscpScript(lscpClient);
1019 sb.append(out.toString());
1020 out.reset();
1021
1022 return sb.toString();
1023 }
1024
1025 private static void
1026 exportInstrMapsToLscpScript(Client lscpClient) {
1027 try {
1028 lscpClient.removeAllMidiInstrumentMaps();
1029 MidiInstrumentMap[] maps = getSamplerModel().getMidiInstrumentMaps();
1030 for(int i = 0; i < maps.length; i++) {
1031 lscpClient.addMidiInstrumentMap(maps[i].getName());
1032 exportInstrumentsToLscpScript(i, maps[i], lscpClient);
1033 }
1034 } catch(Exception e) {
1035 getLogger().log(Level.FINE, HF.getErrorMessage(e), e);
1036 HF.showErrorMessage(e);
1037 }
1038 }
1039
1040 private static void
1041 exportInstrumentsToLscpScript(int mapId, MidiInstrumentMap map, Client lscpClient)
1042 throws Exception {
1043
1044 boolean b = preferences().getBoolProperty(JSPrefs.LOAD_MIDI_INSTRUMENTS_IN_BACKGROUND);
1045
1046 for(MidiInstrument i : map.getAllMidiInstruments()) {
1047 lscpClient.mapMidiInstrument(mapId, i.getInfo().getEntry(), i.getInfo(), b);
1048 }
1049 }
1050
1051 public static String
1052 exportSessionToLscpScript() {
1053 getSamplerModel().setModified(false);
1054
1055 StringBuffer sb = new StringBuffer("# Exported by: ");
1056 sb.append("JSampler - a java front-end for LinuxSampler\r\n# Version: ");
1057 sb.append(JSampler.VERSION).append("\r\n");
1058 sb.append("# Date: ").append(new java.util.Date().toString()).append("\r\n\r\n");
1059
1060 Client lscpClient = new Client(true);
1061 ByteArrayOutputStream out = new ByteArrayOutputStream();
1062 lscpClient.setPrintOnlyModeOutputStream(out);
1063
1064 try {
1065 lscpClient.resetSampler();
1066 sb.append(out.toString());
1067 out.reset();
1068 sb.append("\r\n");
1069 lscpClient.setVolume(getSamplerModel().getVolume());
1070 sb.append(out.toString());
1071 out.reset();
1072 sb.append("\r\n");
1073 } catch(Exception e) { getLogger().log(Level.FINE, HF.getErrorMessage(e), e); }
1074
1075 MidiDeviceModel[] mDevs = getSamplerModel().getMidiDevices();
1076 for(int i = 0; i < mDevs.length; i++) {
1077 exportMidiDeviceToLscpScript(mDevs[i].getDeviceInfo(), i, lscpClient);
1078 sb.append(out.toString());
1079 out.reset();
1080 sb.append("\r\n");
1081 }
1082
1083 AudioDeviceModel[] aDevs = getSamplerModel().getAudioDevices();
1084 for(int i = 0; i < aDevs.length; i++) {
1085 exportAudioDeviceToLscpScript(aDevs[i].getDeviceInfo(), i, lscpClient);
1086 sb.append(out.toString());
1087 out.reset();
1088 sb.append("\r\n");
1089 }
1090
1091 boolean b = preferences().getBoolProperty(JSPrefs.EXPORT_MIDI_MAPS_TO_SESSION_SCRIPT);
1092 if(b) {
1093 exportInstrMapsToLscpScript(lscpClient);
1094 sb.append(out.toString());
1095 out.reset();
1096 sb.append("\r\n");
1097 }
1098
1099 SamplerChannelModel[] channels = getSamplerModel().getChannels();
1100
1101 for(int i = 0; i < channels.length; i++) {
1102 SamplerChannelModel scm = channels[i];
1103 exportChannelToLscpScript(scm.getChannelInfo(), i, lscpClient);
1104 sb.append(out.toString());
1105 out.reset();
1106
1107 sb.append("\r\n");
1108
1109 exportFxSendsToLscpScript(scm, i, lscpClient);
1110 sb.append(out.toString());
1111 out.reset();
1112
1113 sb.append("\r\n");
1114 }
1115
1116 sb.append(getViewConfig().exportSessionViewConfig());
1117
1118 return sb.toString();
1119 }
1120
1121 private static void
1122 exportMidiDeviceToLscpScript(MidiInputDevice mid, int devId, Client lscpCLient) {
1123 try {
1124 String s = mid.getDriverName();
1125 lscpCLient.createMidiInputDevice(s, mid.getAdditionalParameters());
1126
1127 MidiPort[] mPorts = mid.getMidiPorts();
1128 int l = mPorts.length;
1129 if(l != 1) lscpCLient.setMidiInputPortCount(devId, l);
1130
1131 for(int i = 0; i < l; i++) {
1132 Parameter[] prms = mPorts[i].getAllParameters();
1133 for(Parameter p : prms) {
1134 if(!p.isFixed() && p.getStringValue().length() > 0)
1135 lscpCLient.setMidiInputPortParameter(devId, i, p);
1136 }
1137 }
1138 } catch(Exception e) {
1139 getLogger().log(Level.FINE, HF.getErrorMessage(e), e);
1140 }
1141 }
1142
1143 private static void
1144 exportAudioDeviceToLscpScript(AudioOutputDevice aod, int devId, Client lscpCLient) {
1145 try {
1146 String s = aod.getDriverName();
1147 lscpCLient.createAudioOutputDevice(s, aod.getAllParameters());
1148
1149 AudioOutputChannel[] chns = aod.getAudioChannels();
1150
1151 for(int i = 0; i < chns.length; i++) {
1152 Parameter[] prms = chns[i].getAllParameters();
1153 for(Parameter p : prms) {
1154 if(p.isFixed() || p.getStringValue().length() == 0);
1155 else lscpCLient.setAudioOutputChannelParameter(devId, i, p);
1156 }
1157 }
1158 } catch(Exception e) {
1159 getLogger().log(Level.FINE, HF.getErrorMessage(e), e);
1160 }
1161 }
1162
1163 private static void
1164 exportChannelToLscpScript(SamplerChannel chn, int chnId, Client lscpCLient) {
1165 try {
1166 lscpCLient.addSamplerChannel();
1167
1168 SamplerModel sm = getSamplerModel();
1169 int id = chn.getMidiInputDevice();
1170 if(id != -1) {
1171 for(int i = 0; i < sm.getMidiDeviceCount(); i++) {
1172 if(sm.getMidiDevice(i).getDeviceId() == id) {
1173 lscpCLient.setChannelMidiInputDevice(chnId, i);
1174 break;
1175 }
1176 }
1177 lscpCLient.setChannelMidiInputPort(chnId, chn.getMidiInputPort());
1178 lscpCLient.setChannelMidiInputChannel(chnId, chn.getMidiInputChannel());
1179 }
1180
1181 if(chn.getEngine() != null) {
1182 lscpCLient.loadSamplerEngine(chn.getEngine().getName(), chnId);
1183 lscpCLient.setChannelVolume(chnId, chn.getVolume());
1184 int mapId = chn.getMidiInstrumentMapId();
1185 lscpCLient.setChannelMidiInstrumentMap(chnId, mapId);
1186 }
1187
1188 id = chn.getAudioOutputDevice();
1189 if(id != -1) {
1190 for(int i = 0; i < sm.getAudioDeviceCount(); i++) {
1191 if(sm.getAudioDevice(i).getDeviceId() == id) {
1192 lscpCLient.setChannelAudioOutputDevice(chnId, i);
1193 break;
1194 }
1195 }
1196
1197 Integer[] routing = chn.getAudioOutputRouting();
1198
1199 for(int j = 0; j < routing.length; j++) {
1200 int k = routing[j];
1201 if(k == j) continue;
1202
1203 lscpCLient.setChannelAudioOutputChannel(chnId, j, k);
1204 }
1205 }
1206
1207 String s = chn.getInstrumentFile();
1208 int i = chn.getInstrumentIndex();
1209 if(s != null) lscpCLient.loadInstrument(s, i, chnId, true);
1210
1211 if(chn.isMuted()) lscpCLient.setChannelMute(chnId, true);
1212 if(chn.isSoloChannel()) lscpCLient.setChannelSolo(chnId, true);
1213 } catch(Exception e) {
1214 getLogger().log(Level.FINE, HF.getErrorMessage(e), e);
1215 }
1216 }
1217
1218 private static void
1219 exportFxSendsToLscpScript(SamplerChannelModel scm, int chnId, Client lscpClient) {
1220 try {
1221 FxSend[] fxSends = scm.getFxSends();
1222
1223 for(int i = 0; i < fxSends.length; i++) {
1224 FxSend f = fxSends[i];
1225 lscpClient.createFxSend(chnId, f.getMidiController(), f.getName());
1226 lscpClient.setFxSendLevel(chnId, i, f.getLevel());
1227
1228 Integer[] r = f.getAudioOutputRouting();
1229 for(int j = 0; j < r.length; j++) {
1230 lscpClient.setFxSendAudioOutputChannel(chnId, i, j, r[j]);
1231 }
1232 }
1233 } catch(Exception e) {
1234 getLogger().log(Level.FINE, HF.getErrorMessage(e), e);
1235 }
1236 }
1237
1238 public static void
1239 scheduleInTaskQueue(final Runnable r) {
1240 Task dummy = new Global.DummyTask();
1241 dummy.addTaskListener(new TaskListener() {
1242 public void
1243 taskPerformed(TaskEvent e) {
1244 javax.swing.SwingUtilities.invokeLater(r);
1245 }
1246 });
1247
1248 getTaskQueue().add(dummy);
1249 }
1250
1251 public static boolean
1252 verifyConnection() {
1253 if(getCurrentServer() == null) {
1254 HF.showErrorMessage(i18n.getError("CC.notConnected"));
1255 return false;
1256 }
1257
1258 return true;
1259 }
1260
1261 public static boolean
1262 isMacOS() {
1263 return System.getProperty("os.name").toLowerCase().startsWith("mac os x");
1264 }
1265
1266
1267 private final static EventHandler eventHandler = new EventHandler();
1268
1269 private static EventHandler
1270 getHandler() { return eventHandler; }
1271
1272 private static class EventHandler implements ChannelCountListener, ChannelInfoListener,
1273 FxSendCountListener, FxSendInfoListener, StreamCountListener, VoiceCountListener,
1274 TotalStreamCountListener, TotalVoiceCountListener, TaskQueueListener,
1275 OrchestraListener, ListListener<OrchestraModel>, MidiInstrumentCountListener,
1276 MidiInstrumentInfoListener, GlobalInfoListener, ChannelMidiDataListener {
1277
1278 /** Invoked when the number of channels has changed. */
1279 @Override
1280 public void
1281 channelCountChanged( ChannelCountEvent e) {
1282 if(e.getChannelCount() == 0) {
1283 /*
1284 * This special case is handled because this might be due to
1285 * loading a lscp script containing sampler view configuration.
1286 */
1287 CC.getSamplerModel().removeAllChannels();
1288 return;
1289 }
1290 addTask(new UpdateChannels());
1291 }
1292
1293 /** Invoked when changes to the sampler channel has occured. */
1294 @Override
1295 public void
1296 channelInfoChanged(ChannelInfoEvent e) {
1297 /*
1298 * Because of the rapid notification flow when instrument is loaded
1299 * we need to do some optimization to decrease the traffic.
1300 */
1301 boolean b = true;
1302 Task[] tS = getTaskQueue().getPendingTasks();
1303
1304 for(int i = tS.length - 1; i >= 0; i--) {
1305 Task t = tS[i];
1306
1307 if(t instanceof Channel.UpdateInfo) {
1308 Channel.UpdateInfo cui = (Channel.UpdateInfo)t;
1309 if(cui.getChannelId() == e.getSamplerChannel()) return;
1310 } else {
1311 b = false;
1312 break;
1313 }
1314 }
1315
1316 if(b) {
1317 Task t = getTaskQueue().getRunningTask();
1318 if(t instanceof Channel.UpdateInfo) {
1319 Channel.UpdateInfo cui = (Channel.UpdateInfo)t;
1320 if(cui.getChannelId() == e.getSamplerChannel()) return;
1321 }
1322 }
1323
1324
1325 getTaskQueue().add(new Channel.UpdateInfo(e.getSamplerChannel()));
1326 }
1327
1328 /**
1329 * Invoked when the number of effect sends
1330 * on a particular sampler channel has changed.
1331 */
1332 @Override
1333 public void
1334 fxSendCountChanged(FxSendCountEvent e) {
1335 getTaskQueue().add(new Channel.UpdateFxSends(e.getChannel()));
1336 }
1337
1338 /**
1339 * Invoked when the settings of an effect sends are changed.
1340 */
1341 @Override
1342 public void
1343 fxSendInfoChanged(FxSendInfoEvent e) {
1344 Task t = new Channel.UpdateFxSendInfo(e.getChannel(), e.getFxSend());
1345 getTaskQueue().add(t);
1346 }
1347
1348 /**
1349 * Invoked when the number of active disk
1350 * streams in a specific sampler channel has changed.
1351 */
1352 @Override
1353 public void
1354 streamCountChanged(StreamCountEvent e) {
1355 SamplerChannelModel scm =
1356 getSamplerModel().getChannelById(e.getSamplerChannel());
1357
1358 if(scm == null) {
1359 CC.getLogger().log (
1360 Level.WARNING,
1361 "CC.unknownChannel!",
1362 e.getSamplerChannel()
1363 );
1364
1365 return;
1366 }
1367
1368 scm.setStreamCount(e.getStreamCount());
1369 }
1370
1371 /**
1372 * Invoked when the number of active voices
1373 * in a specific sampler channel has changed.
1374 */
1375 @Override
1376 public void
1377 voiceCountChanged(VoiceCountEvent e) {
1378 SamplerChannelModel scm =
1379 getSamplerModel().getChannelById(e.getSamplerChannel());
1380
1381 if(scm == null) {
1382 CC.getLogger().log (
1383 Level.WARNING,
1384 "CC.unknownChannel!",
1385 e.getSamplerChannel()
1386 );
1387
1388 return;
1389 }
1390
1391 scm.setVoiceCount(e.getVoiceCount());
1392 }
1393
1394 /** Invoked when the total number of active streams has changed. */
1395 @Override
1396 public void
1397 totalStreamCountChanged(TotalStreamCountEvent e) {
1398 getSamplerModel().updateActiveStreamsInfo(e.getTotalStreamCount());
1399 }
1400
1401 /** Invoked when the total number of active voices has changed. */
1402 @Override
1403 public void
1404 totalVoiceCountChanged(TotalVoiceCountEvent e) {
1405 scheduleTask(new Global.UpdateTotalVoiceCount());
1406 }
1407
1408 /** Invoked when the number of MIDI instruments in a MIDI instrument map is changed. */
1409 @Override
1410 public void
1411 instrumentCountChanged(MidiInstrumentCountEvent e) {
1412 scheduleTask(new Midi.UpdateInstruments(e.getMapId()));
1413 }
1414
1415 /** Invoked when a MIDI instrument in a MIDI instrument map is changed. */
1416 @Override
1417 public void
1418 instrumentInfoChanged(MidiInstrumentInfoEvent e) {
1419 Task t = new Midi.UpdateInstrumentInfo (
1420 e.getMapId(), e.getMidiBank(), e.getMidiProgram()
1421 );
1422 getTaskQueue().add(t);
1423
1424 }
1425
1426 /** Invoked when the global volume of the sampler is changed. */
1427 @Override
1428 public void
1429 volumeChanged(GlobalInfoEvent e) {
1430 getSamplerModel().setVolume(e.getVolume());
1431 }
1432
1433 @Override
1434 public void
1435 voiceLimitChanged(GlobalInfoEvent e) { }
1436
1437 @Override
1438 public void
1439 streamLimitChanged(GlobalInfoEvent e) { }
1440
1441 /**
1442 * Invoked to indicate that the state of a task queue is changed.
1443 * This method is invoked only from the event-dispatching thread.
1444 */
1445 @Override
1446 public void
1447 stateChanged(TaskQueueEvent e) {
1448 switch(e.getEventID()) {
1449 case TASK_FETCHED:
1450 getProgressIndicator().setString (
1451 ((Task)e.getSource()).getDescription()
1452 );
1453 break;
1454 case TASK_DONE:
1455 EnhancedTask t = (EnhancedTask)e.getSource();
1456 if(t.doneWithErrors() && !t.isSilent()) {
1457 if(t.getErrorCode() == t.SOCKET_ERROR) {
1458 getMainFrame().handleConnectionFailure();
1459 } else if(!t.isStopped()) {
1460 showError(t);
1461 }
1462 }
1463 break;
1464 case NOT_IDLE:
1465 timer.start();
1466 break;
1467 case IDLE:
1468 timer.stop();
1469 getProgressIndicator().stop();
1470 break;
1471 }
1472 }
1473
1474 private void
1475 showError(final Task t) {
1476 javax.swing.SwingUtilities.invokeLater(new Runnable() {
1477 public void
1478 run() {
1479 if(t.getErrorDetails() == null) {
1480 HF.showErrorMessage(t.getErrorMessage());
1481 } else {
1482 getMainFrame().showDetailedErrorMessage (
1483 getMainFrame(),
1484 t.getErrorMessage(),
1485 t.getErrorDetails()
1486 );
1487 }
1488 }
1489 });
1490 }
1491
1492 /** Invoked when the name of orchestra is changed. */
1493 @Override
1494 public void
1495 nameChanged(OrchestraEvent e) { saveOrchestras(); }
1496
1497 /** Invoked when the description of orchestra is changed. */
1498 @Override
1499 public void
1500 descriptionChanged(OrchestraEvent e) { saveOrchestras(); }
1501
1502 /** Invoked when an instrument is added to the orchestra. */
1503 @Override
1504 public void
1505 instrumentAdded(OrchestraEvent e) { saveOrchestras(); }
1506
1507 /** Invoked when an instrument is removed from the orchestra. */
1508 @Override
1509 public void
1510 instrumentRemoved(OrchestraEvent e) { saveOrchestras(); }
1511
1512 /** Invoked when the settings of an instrument are changed. */
1513 @Override
1514 public void
1515 instrumentChanged(OrchestraEvent e) { saveOrchestras(); }
1516
1517 /** Invoked when an orchestra is added to the orchestra list. */
1518 @Override
1519 public void
1520 entryAdded(ListEvent<OrchestraModel> e) {
1521 e.getEntry().addOrchestraListener(getHandler());
1522 saveOrchestras();
1523 }
1524
1525 /** Invoked when an orchestra is removed from the orchestra list. */
1526 @Override
1527 public void
1528 entryRemoved(ListEvent<OrchestraModel> e) {
1529 e.getEntry().removeOrchestraListener(getHandler());
1530 saveOrchestras();
1531 }
1532
1533 /**
1534 * Invoked when MIDI data arrives.
1535 */
1536 @Override
1537 public void
1538 midiDataArrived(final ChannelMidiDataEvent e) {
1539 try {
1540 javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
1541 public void
1542 run() { fireChannelMidiDataEvent(e); }
1543 });
1544 } catch(Exception x) {
1545 CC.getLogger().log(Level.INFO, "Failed!", x);
1546 }
1547 }
1548 }
1549
1550 private static void
1551 fireChannelMidiDataEvent(ChannelMidiDataEvent e) {
1552 SamplerChannelModel chn;
1553 chn = CC.getSamplerModel().getChannelById(e.getChannelId());
1554 if(chn == null) {
1555 CC.getLogger().info("Unknown channel ID: " + e.getChannelId());
1556 }
1557
1558 ((DefaultSamplerChannelModel)chn).fireMidiDataEvent(e);
1559 }
1560
1561 private static final AudioDeviceCountListener audioDeviceCountListener =
1562 new AudioDeviceCountListener();
1563
1564 private static class AudioDeviceCountListener implements ItemCountListener {
1565 /** Invoked when the number of audio output devices has changed. */
1566 @Override
1567 public void
1568 itemCountChanged(ItemCountEvent e) {
1569 getTaskQueue().add(new Audio.UpdateDevices());
1570 }
1571 }
1572
1573 private static final AudioDeviceInfoListener audioDeviceInfoListener =
1574 new AudioDeviceInfoListener();
1575
1576 private static class AudioDeviceInfoListener implements ItemInfoListener {
1577 /** Invoked when the audio output device's settings are changed. */
1578 @Override
1579 public void
1580 itemInfoChanged(ItemInfoEvent e) {
1581 getTaskQueue().add(new Audio.UpdateDeviceInfo(e.getItemID()));
1582 }
1583 }
1584
1585 private static final MidiDeviceCountListener midiDeviceCountListener =
1586 new MidiDeviceCountListener();
1587
1588 private static class MidiDeviceCountListener implements ItemCountListener {
1589 /** Invoked when the number of MIDI input devices has changed. */
1590 @Override
1591 public void
1592 itemCountChanged(ItemCountEvent e) {
1593 getTaskQueue().add(new Midi.UpdateDevices());
1594 }
1595 }
1596
1597 private static final MidiDeviceInfoListener midiDeviceInfoListener =
1598 new MidiDeviceInfoListener();
1599
1600 private static class MidiDeviceInfoListener implements ItemInfoListener {
1601 /** Invoked when the MIDI input device's settings are changed. */
1602 @Override
1603 public void
1604 itemInfoChanged(ItemInfoEvent e) {
1605 getTaskQueue().add(new Midi.UpdateDeviceInfo(e.getItemID()));
1606 }
1607 }
1608
1609 private static final MidiInstrMapCountListener midiInstrMapCountListener =
1610 new MidiInstrMapCountListener();
1611
1612 private static class MidiInstrMapCountListener implements ItemCountListener {
1613 /** Invoked when the number of MIDI instrument maps is changed. */
1614 @Override
1615 public void
1616 itemCountChanged(ItemCountEvent e) {
1617 getTaskQueue().add(new Midi.UpdateInstrumentMaps());
1618 }
1619 }
1620
1621 private static final MidiInstrMapInfoListener midiInstrMapInfoListener =
1622 new MidiInstrMapInfoListener();
1623
1624 private static class MidiInstrMapInfoListener implements ItemInfoListener {
1625 /** Invoked when the MIDI instrument map's settings are changed. */
1626 @Override
1627 public void
1628 itemInfoChanged(ItemInfoEvent e) {
1629 getTaskQueue().add(new Midi.UpdateInstrumentMapInfo(e.getItemID()));
1630 }
1631 }
1632 }

  ViewVC Help
Powered by ViewVC