/[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 2195 - (show annotations) (download)
Tue Jun 28 22:44:39 2011 UTC (12 years, 9 months ago) by iliev
File size: 38759 byte(s)
* Sampler Browser (work in progress): initial implementation of main pane

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

  ViewVC Help
Powered by ViewVC