/[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 2192 - (show annotations) (download)
Fri Jun 24 21:34:51 2011 UTC (12 years, 10 months ago) by iliev
File size: 38445 byte(s)
* Initial implementation of Sampler Browser
  (choose Window/Sampler Browser) - another way to view/edit
  the sampler configuration (work in progress - for now only
  support for viewing/editing send effects)

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 CC.addConnectionEstablishedListener(new ActionListener() {
316 public void
317 actionPerformed(ActionEvent e) {
318 connectionFailureCount = 0;
319 }
320 });
321 }
322
323 private final static OrchestraListModel orchestras = new DefaultOrchestraListModel();
324
325 /**
326 * Returns a list containing all available orchestras.
327 * @return A list containing all available orchestras.
328 */
329 public static OrchestraListModel
330 getOrchestras() { return orchestras; }
331
332 private final static ServerList servers = new ServerList();
333
334 /** Returns the server list. */
335 public static ServerList
336 getServerList() { return servers; }
337
338 private static ServerListListener serverListListener = new ServerListListener();
339
340 private static class ServerListListener implements ChangeListener {
341 @Override
342 public void
343 stateChanged(ChangeEvent e) {
344 saveServerList();
345 }
346 }
347
348 private static final Vector<ChangeListener> idtmListeners = new Vector<ChangeListener>();
349 private static InstrumentsDbTreeModel instrumentsDbTreeModel = null;
350
351 /**
352 * Gets the tree model of the instruments database.
353 * If the currently used view doesn't have instruments
354 * database support the tree model is initialized on first use.
355 * @return The tree model of the instruments database or
356 * <code>null</code> if the backend doesn't have instruments database support.
357 * @see org.jsampler.view.JSViewConfig#getInstrumentsDbSupport
358 */
359 public static InstrumentsDbTreeModel
360 getInstrumentsDbTreeModel() {
361 if(getSamplerModel().getServerInfo() == null) return null;
362 if(!getSamplerModel().getServerInfo().hasInstrumentsDbSupport()) return null;
363
364 if(instrumentsDbTreeModel == null) {
365 instrumentsDbTreeModel = new InstrumentsDbTreeModel();
366 for(ChangeListener l : idtmListeners) l.stateChanged(null);
367 }
368
369 return instrumentsDbTreeModel;
370 }
371
372 public static void
373 addInstrumentsDbChangeListener(ChangeListener l) {
374 idtmListeners.add(l);
375 }
376
377 public static void
378 removeInstrumentsDbChangeListener(ChangeListener l) {
379 idtmListeners.remove(l);
380 }
381
382 private static final LostFilesModel lostFilesModel = new LostFilesModel();
383
384 public static LostFilesModel
385 getLostFilesModel() { return lostFilesModel; }
386
387 /**
388 * Loads the orchestras described in <code>&lt;jsampler_home&gt;/orchestras.xml</code>.
389 * If file with name <code>orchestras.xml.bkp</code> exist in the JSampler's home
390 * directory, this means that the last save has failed. In that case a recovery file
391 * <code>orchestras.xml.rec</code> is created and a recovery procedure
392 * will be initiated.
393 */
394 public static void
395 loadOrchestras() {
396 if(getJSamplerHome() == null) return;
397
398 try {
399 String s = getJSamplerHome();
400
401 File f = new File(s + File.separator + "orchestras.xml.bkp");
402 if(f.isFile()) HF.createBackup("orchestras.xml.bkp", "orchestras.xml.rec");
403
404 FileInputStream fis;
405 fis = new FileInputStream(s + File.separator + "orchestras.xml");
406
407 loadOrchestras(fis);
408 fis.close();
409 } catch(Exception x) {
410 getLogger().log(Level.INFO, HF.getErrorMessage(x), x);
411 }
412
413 getOrchestras().addOrchestraListListener(getHandler());
414 }
415
416
417 private static void
418 loadOrchestras(InputStream in) {
419 Document doc = DOMUtils.readObject(in);
420
421 try { getOrchestras().readObject(doc.getDocumentElement()); }
422 catch(Exception x) {
423 HF.showErrorMessage(x, "Loading orchestras: ");
424 return;
425 }
426
427 for(int i = 0; i < getOrchestras().getOrchestraCount(); i++) {
428 getOrchestras().getOrchestra(i).addOrchestraListener(getHandler());
429 }
430 }
431
432 private static void
433 saveOrchestras() {
434 try {
435 String s = getJSamplerHome();
436 if(s == null) return;
437
438 HF.createBackup("orchestras.xml", "orchestras.xml.bkp");
439
440 FileOutputStream fos2;
441 fos2 = new FileOutputStream(s + File.separator + "orchestras.xml", false);
442
443 Document doc = DOMUtils.createEmptyDocument();
444
445 Node node = doc.createElement("temp");
446 doc.appendChild(node);
447
448 getOrchestras().writeObject(doc, doc.getDocumentElement());
449
450 doc.replaceChild(node.getFirstChild(), node);
451
452 DOMUtils.writeObject(doc, fos2);
453
454 fos2.close();
455
456 HF.deleteFile("orchestras.xml.bkp");
457 } catch(Exception x) {
458 HF.showErrorMessage(x, "Saving orchestras: ");
459 return;
460 }
461 }
462
463 /**
464 * Loads the servers' info described in <code>&lt;jsampler_home&gt;/servers.xml</code>.
465 * If file with name <code>servers.xml.bkp</code> exist in the JSampler's home
466 * directory, this means that the last save has failed. In that case a recovery file
467 * <code>servers.xml.rec</code> is created and a recovery procedure
468 * will be initiated.
469 */
470 public static void
471 loadServerList() {
472 if(getJSamplerHome() == null) return;
473
474 try {
475 String s = getJSamplerHome();
476
477 File f = new File(s + File.separator + "servers.xml.bkp");
478 if(f.isFile()) HF.createBackup("servers.xml.bkp", "servers.xml.rec");
479
480 FileInputStream fis;
481 fis = new FileInputStream(s + File.separator + "servers.xml");
482
483 loadServerList(fis);
484 fis.close();
485 } catch(Exception x) {
486 getLogger().log(Level.INFO, HF.getErrorMessage(x), x);
487 }
488
489 getServerList().addChangeListener(serverListListener);
490
491 /* We should have at least one server to connect. */
492 if(getServerList().getServerCount() == 0) {
493 Server server = new Server();
494 server.setName("127.0.0.1:8888");
495 server.setAddress("127.0.0.1");
496 server.setPort(8888);
497 getServerList().addServer(server);
498 }
499 }
500
501
502 private static void
503 loadServerList(InputStream in) {
504 Document doc = DOMUtils.readObject(in);
505
506 try { getServerList().readObject(doc.getDocumentElement()); }
507 catch(Exception x) {
508 HF.showErrorMessage(x, "Loading server list: ");
509 return;
510 }
511 }
512
513 private static void
514 saveServerList() {
515 try {
516 String s = getJSamplerHome();
517 if(s == null) return;
518
519 HF.createBackup("servers.xml", "servers.xml.bkp");
520
521 FileOutputStream fos2;
522 fos2 = new FileOutputStream(s + File.separator + "servers.xml", false);
523
524 Document doc = DOMUtils.createEmptyDocument();
525
526 Node node = doc.createElement("temp");
527 doc.appendChild(node);
528
529 getServerList().writeObject(doc, doc.getDocumentElement());
530
531 doc.replaceChild(node.getFirstChild(), node);
532
533 DOMUtils.writeObject(doc, fos2);
534
535 fos2.close();
536
537 HF.deleteFile("servers.xml.bkp");
538 } catch(Exception x) {
539 HF.showErrorMessage(x, "Saving server list: ");
540 return;
541 }
542 }
543
544 /**
545 * The exit point of the application which ensures clean exit with default exit status 0.
546 * @see #cleanExit(int i)
547 */
548 public static void
549 cleanExit() { cleanExit(0); }
550
551 /**
552 * The exit point of the application which ensures clean exit.
553 * @param i The exit status.
554 */
555 public static void
556 cleanExit(int i) {
557 getLogger().fine("CC.jsEnded");
558 try { getClient().disconnect(); } // FIXME: this might block the EDT
559 catch(Exception x) { x.printStackTrace(); }
560 if(backendProcess != null) backendProcess.destroy();
561 backendProcess = null;
562 fireBackendProcessEvent();
563 System.exit(i);
564 }
565
566 /**
567 * Gets the <code>Client</code> object that is used to communicate with the backend.
568 * @return The <code>Client</code> object that is used to communicate with the backend.
569 */
570 public static Client
571 getClient() { return lsClient; }
572
573 private static final Vector<ActionListener> listeners = new Vector<ActionListener>();
574
575 /**
576 * Registers the specified listener to be notified when reconnecting to LinuxSampler.
577 * @param l The <code>ActionListener</code> to register.
578 */
579 public static void
580 addReconnectListener(ActionListener l) { listeners.add(l); }
581
582 /**
583 * Removes the specified listener.
584 * @param l The <code>ActionListener</code> to remove.
585 */
586 public static void
587 removeReconnectListener(ActionListener l) { listeners.remove(l); }
588
589 private static void
590 fireReconnectEvent() {
591 ActionEvent e = new ActionEvent(CC.class, ActionEvent.ACTION_PERFORMED, null);
592 for(ActionListener l : listeners) l.actionPerformed(e);
593 }
594
595 private static final Vector<ActionListener> ceListeners = new Vector<ActionListener>();
596
597 /**
598 * Registers the specified listener to be notified when
599 * jsampler is connected successfully to LinuxSampler.
600 * @param l The <code>ActionListener</code> to register.
601 */
602 public static void
603 addConnectionEstablishedListener(ActionListener l) { ceListeners.add(l); }
604
605 /**
606 * Removes the specified listener.
607 * @param l The <code>ActionListener</code> to remove.
608 */
609 public static void
610 removeConnectionEstablishedListener(ActionListener l) { ceListeners.remove(l); }
611
612 private static void
613 fireConnectionEstablishedEvent() {
614 ActionEvent e = new ActionEvent(CC.class, ActionEvent.ACTION_PERFORMED, null);
615 for(ActionListener l : ceListeners) l.actionPerformed(e);
616 }
617
618 private static final SamplerModel samplerModel = new DefaultSamplerModel();
619
620 /**
621 * Gets the sampler model.
622 * @return The sampler model.
623 */
624 public static SamplerModel
625 getSamplerModel() { return samplerModel; }
626
627 /**
628 * Connects to LinuxSampler.
629 */
630 public static void
631 connect() { initSamplerModel(); }
632
633 /**
634 * Reconnects to LinuxSampler.
635 */
636 public static void
637 reconnect() { initSamplerModel(getCurrentServer()); }
638
639 private static Server currentServer = null;
640
641 /**
642 * Gets the server, to which the frontend is going to connect
643 * or is already connected.
644 */
645 public static Server
646 getCurrentServer() { return currentServer; }
647
648 /**
649 * Sets the current server.
650 */
651 public static void
652 setCurrentServer(Server server) {
653 if(server == currentServer) return;
654 connectionFailureCount = 0;
655 currentServer = server;
656 }
657
658 /**
659 * Sets the LSCP client's read timeout.
660 * @param timeout The new timeout value (in seconds).
661 */
662 public static void
663 setClientReadTimeout(int timeout) {
664 getTaskQueue().add(new Global.SetClientReadTimeout(timeout));
665 }
666
667 /**
668 * This method updates the information about the backend state.
669 */
670 private static void
671 initSamplerModel() {
672 Server srv = getMainFrame().getServer();
673 if(srv == null) return;
674 initSamplerModel(srv);
675 }
676
677 /**
678 * This method updates the information about the backend state.
679 */
680 private static void
681 initSamplerModel(Server srv) {
682 setCurrentServer(srv);
683 final SetServerAddress ssa = new SetServerAddress(srv.getAddress(), srv.getPort());
684
685 final DefaultSamplerModel model = (DefaultSamplerModel)getSamplerModel();
686
687 final Global.GetServerInfo gsi = new Global.GetServerInfo();
688 gsi.addTaskListener(new TaskListener() {
689 public void
690 taskPerformed(TaskEvent e) {
691 if(gsi.doneWithErrors()) return;
692
693 model.setServerInfo(gsi.getResult());
694
695 if(CC.getViewConfig().getInstrumentsDbSupport()) {
696 getInstrumentsDbTreeModel();
697 }
698 }
699 });
700
701 final Audio.GetDrivers gaod = new Audio.GetDrivers();
702 gaod.addTaskListener(new TaskListener() {
703 public void
704 taskPerformed(TaskEvent e) {
705 if(!gaod.doneWithErrors())
706 model.setAudioOutputDrivers(gaod.getResult());
707 }
708 });
709
710 final Global.GetEngines ge = new Global.GetEngines();
711 ge.addTaskListener(new TaskListener() {
712 public void
713 taskPerformed(TaskEvent e) {
714 if(!ge.doneWithErrors()) model.setEngines(ge.getResult());
715 }
716 });
717
718 final Midi.GetDrivers gmid = new Midi.GetDrivers();
719 gmid.addTaskListener(new TaskListener() {
720 public void
721 taskPerformed(TaskEvent e) {
722 if(!gmid.doneWithErrors())
723 model.setMidiInputDrivers(gmid.getResult());
724 }
725 });
726
727 final Global.GetVolume gv = new Global.GetVolume();
728 gv.addTaskListener(new TaskListener() {
729 public void
730 taskPerformed(TaskEvent e) {
731 if(!gv.doneWithErrors())
732 model.setVolume(gv.getResult());
733 }
734 });
735
736 final Midi.GetInstrumentMaps mgim = new Midi.GetInstrumentMaps();
737 mgim.addTaskListener(new TaskListener() {
738 public void
739 taskPerformed(TaskEvent e) {
740 if(mgim.doneWithErrors()) return;
741 model.removeAllMidiInstrumentMaps();
742
743 for(MidiInstrumentMap map : mgim.getResult()) {
744 model.addMidiInstrumentMap(map);
745 }
746 }
747 });
748
749 final Global.GetEffects gfx = new Global.GetEffects();
750 gfx.addTaskListener(new TaskListener() {
751 public void
752 taskPerformed(TaskEvent e) {
753 if(!gfx.doneWithErrors()) model.getEffects().setEffects(gfx.getResult());
754 }
755 });
756
757 final UpdateChannels uc = new UpdateChannels();
758 uc.addTaskListener(new TaskListener() {
759 public void
760 taskPerformed(TaskEvent e) {
761 for(SamplerChannelModel c : model.getChannels()) {
762 if(c.getChannelInfo().getEngine() == null) continue;
763
764 Channel.GetFxSends gfs = new Channel.GetFxSends();
765 gfs.setChannel(c.getChannelId());
766 gfs.addTaskListener(new GetFxSendsListener());
767 getTaskQueue().add(gfs);
768 }
769
770 // TODO: This should be done after the fx sends are set
771 //CC.getSamplerModel().setModified(false);
772 }
773 });
774
775
776 final Global.Connect cnt = new Global.Connect();
777 boolean b = preferences().getBoolProperty(JSPrefs.LAUNCH_BACKEND_LOCALLY);
778 if(b && srv.isLocal() && backendProcess == null) cnt.setSilent(true);
779 cnt.addTaskListener(new TaskListener() {
780 public void
781 taskPerformed(TaskEvent e) {
782 if(cnt.doneWithErrors()) {
783 onConnectFailure();
784 return;
785 }
786
787 // Don't change order!!!
788 getTaskQueue().add(gsi);
789 getTaskQueue().add(gaod);
790 getTaskQueue().add(gmid);
791 getTaskQueue().add(ge);
792 getTaskQueue().add(gv);
793 getTaskQueue().add(mgim);
794 getTaskQueue().add(gfx);
795 getTaskQueue().add(new Midi.UpdateDevices());
796 getTaskQueue().add(new Audio.UpdateDevices());
797 addTask(uc);
798 getTaskQueue().add(new Global.UpdateSendEffectChains());
799
800 int vl = preferences().getIntProperty(JSPrefs.GLOBAL_VOICE_LIMIT);
801 int sl = preferences().getIntProperty(JSPrefs.GLOBAL_STREAM_LIMIT);
802
803 getTaskQueue().add(new Global.SetPolyphony(vl, sl));
804
805 fireConnectionEstablishedEvent();
806 }
807 });
808
809 ssa.addTaskListener(new TaskListener() {
810 public void
811 taskPerformed(TaskEvent e) {
812 int t = preferences().getIntProperty(JSPrefs.SOCKET_READ_TIMEOUT);
813 CC.setClientReadTimeout(t * 1000);
814 CC.getTaskQueue().add(cnt);
815 }
816 });
817
818 getSamplerModel().reset();
819 if(instrumentsDbTreeModel != null) {
820 instrumentsDbTreeModel.reset();
821 instrumentsDbTreeModel = null;
822 }
823
824 getTaskQueue().removePendingTasks();
825 getTaskQueue().add(ssa);
826
827 fireReconnectEvent();
828 }
829
830 private static void
831 onConnectFailure() {
832 connectionFailureCount++;
833 if(connectionFailureCount > 50) { // to prevent eventual infinite loop
834 getLogger().warning("Reached maximum number of connection failures");
835 return;
836 }
837
838 try {
839 if(launchBackend()) {
840 int i = preferences().getIntProperty(JSPrefs.BACKEND_LAUNCH_DELAY);
841 if(i < 1) {
842 initSamplerModel(getCurrentServer());
843 return;
844 }
845
846 LaunchBackend lb = new LaunchBackend(i, getBackendMonitor());
847 //CC.getTaskQueue().add(lb);
848 new Thread(lb).start();
849 return;
850 }
851 } catch(Exception x) {
852 final String s = JSI18n.i18n.getError("CC.failedToLaunchBackend");
853 CC.getLogger().log(Level.INFO, s, x);
854
855 SwingUtilities.invokeLater(new Runnable() {
856 public void
857 run() { HF.showErrorMessage(s); }
858 });
859 return;
860 }
861
862 retryToConnect();
863 }
864
865 private static void
866 retryToConnect() {
867 javax.swing.SwingUtilities.invokeLater(new Runnable() {
868 public void
869 run() { changeBackend(); }
870 });
871 }
872
873 public static void
874 changeBackend() {
875 Server s = getMainFrame().getServer(true);
876 if(s != null) {
877 connectionFailureCount = 0; // cleared because this change due to user interaction
878 initSamplerModel(s);
879 }
880 }
881
882 private static final Vector<ActionListener> pListeners = new Vector<ActionListener>();
883
884 /**
885 * Registers the specified listener to be notified when
886 * backend process is created/terminated.
887 * @param l The <code>ActionListener</code> to register.
888 */
889 public static void
890 addBackendProcessListener(ActionListener l) { pListeners.add(l); }
891
892 /**
893 * Removes the specified listener.
894 * @param l The <code>ActionListener</code> to remove.
895 */
896 public static void
897 removeBackendProcessListener(ActionListener l) { pListeners.remove(l); }
898
899 private static void
900 fireBackendProcessEvent() {
901 ActionEvent e = new ActionEvent(CC.class, ActionEvent.ACTION_PERFORMED, null);
902 for(ActionListener l : pListeners) l.actionPerformed(e);
903 }
904
905 private static Process backendProcess = null;
906
907 public static Process
908 getBackendProcess() { return backendProcess; }
909
910 private static final Object backendMonitor = new Object();
911
912 public static Object
913 getBackendMonitor() { return backendMonitor; }
914
915 private static boolean
916 launchBackend() throws Exception {
917 if(backendProcess != null) {
918 try {
919 int i = backendProcess.exitValue();
920 getLogger().info("Backend exited with exit value " + i);
921 backendProcess = null;
922 fireBackendProcessEvent();
923 } catch(IllegalThreadStateException x) { return false; }
924 }
925
926 if(!preferences().getBoolProperty(JSPrefs.LAUNCH_BACKEND_LOCALLY)) return false;
927 if(connectionFailureCount > 1) return false;
928
929 Server s = getCurrentServer();
930 if(s != null && s.isLocal()) {
931 String cmd = preferences().getStringProperty(JSPrefs.BACKEND_LAUNCH_COMMAND);
932 backendProcess = Runtime.getRuntime().exec(cmd);
933 fireBackendProcessEvent();
934 return true;
935 }
936
937 return false;
938 }
939
940 private static class GetFxSendsListener implements TaskListener {
941 @Override
942 public void
943 taskPerformed(TaskEvent e) {
944 Channel.GetFxSends gfs = (Channel.GetFxSends)e.getSource();
945 if(gfs.doneWithErrors()) return;
946 SamplerChannelModel m = getSamplerModel().getChannelById(gfs.getChannel());
947 m.removeAllFxSends();
948
949 for(FxSend fxs : gfs.getResult()) m.addFxSend(fxs);
950 }
951 }
952
953 public static void
954 scheduleInTaskQueue(final Runnable r) {
955 Task dummy = new Global.DummyTask();
956 dummy.addTaskListener(new TaskListener() {
957 public void
958 taskPerformed(TaskEvent e) {
959 javax.swing.SwingUtilities.invokeLater(r);
960 }
961 });
962
963 getTaskQueue().add(dummy);
964 }
965
966 public static boolean
967 verifyConnection() {
968 if(getCurrentServer() == null) {
969 HF.showErrorMessage(i18n.getError("CC.notConnected"));
970 return false;
971 }
972
973 return true;
974 }
975
976 public static boolean
977 isMacOS() {
978 return System.getProperty("os.name").toLowerCase().startsWith("mac os x");
979 }
980
981
982 private final static EventHandler eventHandler = new EventHandler();
983
984 private static EventHandler
985 getHandler() { return eventHandler; }
986
987 private static class EventHandler implements ChannelCountListener, ChannelInfoListener,
988 FxSendCountListener, FxSendInfoListener, StreamCountListener, VoiceCountListener,
989 TotalStreamCountListener, TotalVoiceCountListener, TaskQueueListener,
990 OrchestraListener, ListListener<OrchestraModel>, MidiInstrumentCountListener,
991 MidiInstrumentInfoListener, GlobalInfoListener, ChannelMidiDataListener,
992 SendEffectChainCountListener, SendEffectChainInfoListener {
993
994 /** Invoked when the number of channels has changed. */
995 @Override
996 public void
997 channelCountChanged( ChannelCountEvent e) {
998 if(e.getChannelCount() == 0) {
999 /*
1000 * This special case is handled because this might be due to
1001 * loading a lscp script containing sampler view configuration.
1002 */
1003 CC.getSamplerModel().removeAllChannels();
1004 return;
1005 }
1006 addTask(new UpdateChannels());
1007 }
1008
1009 /** Invoked when changes to the sampler channel has occured. */
1010 @Override
1011 public void
1012 channelInfoChanged(ChannelInfoEvent e) {
1013 /*
1014 * Because of the rapid notification flow when instrument is loaded
1015 * we need to do some optimization to decrease the traffic.
1016 */
1017 boolean b = true;
1018 Task[] tS = getTaskQueue().getPendingTasks();
1019
1020 for(int i = tS.length - 1; i >= 0; i--) {
1021 Task t = tS[i];
1022
1023 if(t instanceof Channel.UpdateInfo) {
1024 Channel.UpdateInfo cui = (Channel.UpdateInfo)t;
1025 if(cui.getChannelId() == e.getSamplerChannel()) return;
1026 } else {
1027 b = false;
1028 break;
1029 }
1030 }
1031
1032 if(b) {
1033 Task t = getTaskQueue().getRunningTask();
1034 if(t instanceof Channel.UpdateInfo) {
1035 Channel.UpdateInfo cui = (Channel.UpdateInfo)t;
1036 if(cui.getChannelId() == e.getSamplerChannel()) return;
1037 }
1038 }
1039
1040
1041 getTaskQueue().add(new Channel.UpdateInfo(e.getSamplerChannel()));
1042 }
1043
1044 /**
1045 * Invoked when the number of effect sends
1046 * on a particular sampler channel has changed.
1047 */
1048 @Override
1049 public void
1050 fxSendCountChanged(FxSendCountEvent e) {
1051 getTaskQueue().add(new Channel.UpdateFxSends(e.getChannel()));
1052 }
1053
1054 /**
1055 * Invoked when the settings of an effect sends are changed.
1056 */
1057 @Override
1058 public void
1059 fxSendInfoChanged(FxSendInfoEvent e) {
1060 Task t = new Channel.UpdateFxSendInfo(e.getChannel(), e.getFxSend());
1061 getTaskQueue().add(t);
1062 }
1063
1064 /**
1065 * Invoked when the number of active disk
1066 * streams in a specific sampler channel has changed.
1067 */
1068 @Override
1069 public void
1070 streamCountChanged(StreamCountEvent e) {
1071 SamplerChannelModel scm =
1072 getSamplerModel().getChannelById(e.getSamplerChannel());
1073
1074 if(scm == null) {
1075 CC.getLogger().log (
1076 Level.WARNING,
1077 "CC.unknownChannel!",
1078 e.getSamplerChannel()
1079 );
1080
1081 return;
1082 }
1083
1084 scm.setStreamCount(e.getStreamCount());
1085 }
1086
1087 /**
1088 * Invoked when the number of active voices
1089 * in a specific sampler channel has changed.
1090 */
1091 @Override
1092 public void
1093 voiceCountChanged(VoiceCountEvent e) {
1094 SamplerChannelModel scm =
1095 getSamplerModel().getChannelById(e.getSamplerChannel());
1096
1097 if(scm == null) {
1098 CC.getLogger().log (
1099 Level.WARNING,
1100 "CC.unknownChannel!",
1101 e.getSamplerChannel()
1102 );
1103
1104 return;
1105 }
1106
1107 scm.setVoiceCount(e.getVoiceCount());
1108 }
1109
1110 /** Invoked when the total number of active streams has changed. */
1111 @Override
1112 public void
1113 totalStreamCountChanged(TotalStreamCountEvent e) {
1114 getSamplerModel().updateActiveStreamsInfo(e.getTotalStreamCount());
1115 }
1116
1117 /** Invoked when the total number of active voices has changed. */
1118 @Override
1119 public void
1120 totalVoiceCountChanged(TotalVoiceCountEvent e) {
1121 scheduleTask(new Global.UpdateTotalVoiceCount());
1122 }
1123
1124 /** Invoked when the number of MIDI instruments in a MIDI instrument map is changed. */
1125 @Override
1126 public void
1127 instrumentCountChanged(MidiInstrumentCountEvent e) {
1128 scheduleTask(new Midi.UpdateInstruments(e.getMapId()));
1129 }
1130
1131 /** Invoked when a MIDI instrument in a MIDI instrument map is changed. */
1132 @Override
1133 public void
1134 instrumentInfoChanged(MidiInstrumentInfoEvent e) {
1135 Task t = new Midi.UpdateInstrumentInfo (
1136 e.getMapId(), e.getMidiBank(), e.getMidiProgram()
1137 );
1138 getTaskQueue().add(t);
1139
1140 }
1141
1142 /** Invoked when the global volume of the sampler is changed. */
1143 @Override
1144 public void
1145 volumeChanged(GlobalInfoEvent e) {
1146 getSamplerModel().setVolume(e.getVolume());
1147 }
1148
1149 @Override
1150 public void
1151 voiceLimitChanged(GlobalInfoEvent e) { }
1152
1153 @Override
1154 public void
1155 streamLimitChanged(GlobalInfoEvent e) { }
1156
1157 /**
1158 * Invoked to indicate that the state of a task queue is changed.
1159 * This method is invoked only from the event-dispatching thread.
1160 */
1161 @Override
1162 public void
1163 stateChanged(TaskQueueEvent e) {
1164 switch(e.getEventID()) {
1165 case TASK_FETCHED:
1166 getProgressIndicator().setString (
1167 ((Task)e.getSource()).getDescription()
1168 );
1169 break;
1170 case TASK_DONE:
1171 EnhancedTask t = (EnhancedTask)e.getSource();
1172 if(t.doneWithErrors() && !t.isSilent()) {
1173 if(t.getErrorCode() == t.SOCKET_ERROR) {
1174 getMainFrame().handleConnectionFailure();
1175 } else if(!t.isStopped()) {
1176 showError(t);
1177 }
1178 }
1179 break;
1180 case NOT_IDLE:
1181 timer.start();
1182 break;
1183 case IDLE:
1184 timer.stop();
1185 getProgressIndicator().stop();
1186 break;
1187 }
1188 }
1189
1190 private void
1191 showError(final Task t) {
1192 javax.swing.SwingUtilities.invokeLater(new Runnable() {
1193 public void
1194 run() {
1195 if(t.getErrorDetails() == null) {
1196 HF.showErrorMessage(t.getErrorMessage());
1197 } else {
1198 getMainFrame().showDetailedErrorMessage (
1199 getMainFrame(),
1200 t.getErrorMessage(),
1201 t.getErrorDetails()
1202 );
1203 }
1204 }
1205 });
1206 }
1207
1208 /** Invoked when the name of orchestra is changed. */
1209 @Override
1210 public void
1211 nameChanged(OrchestraEvent e) { saveOrchestras(); }
1212
1213 /** Invoked when the description of orchestra is changed. */
1214 @Override
1215 public void
1216 descriptionChanged(OrchestraEvent e) { saveOrchestras(); }
1217
1218 /** Invoked when an instrument is added to the orchestra. */
1219 @Override
1220 public void
1221 instrumentAdded(OrchestraEvent e) { saveOrchestras(); }
1222
1223 /** Invoked when an instrument is removed from the orchestra. */
1224 @Override
1225 public void
1226 instrumentRemoved(OrchestraEvent e) { saveOrchestras(); }
1227
1228 /** Invoked when the settings of an instrument are changed. */
1229 @Override
1230 public void
1231 instrumentChanged(OrchestraEvent e) { saveOrchestras(); }
1232
1233 /** Invoked when an orchestra is added to the orchestra list. */
1234 @Override
1235 public void
1236 entryAdded(ListEvent<OrchestraModel> e) {
1237 e.getEntry().addOrchestraListener(getHandler());
1238 saveOrchestras();
1239 }
1240
1241 /** Invoked when an orchestra is removed from the orchestra list. */
1242 @Override
1243 public void
1244 entryRemoved(ListEvent<OrchestraModel> e) {
1245 e.getEntry().removeOrchestraListener(getHandler());
1246 saveOrchestras();
1247 }
1248
1249 /**
1250 * Invoked when MIDI data arrives.
1251 */
1252 @Override
1253 public void
1254 midiDataArrived(final ChannelMidiDataEvent e) {
1255 try {
1256 javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
1257 public void
1258 run() { fireChannelMidiDataEvent(e); }
1259 });
1260 } catch(Exception x) {
1261 CC.getLogger().log(Level.INFO, "Failed!", x);
1262 }
1263 }
1264
1265 @Override
1266 public void
1267 sendEffectChainCountChanged(SendEffectChainCountEvent e) {
1268 getTaskQueue().add(new Audio.UpdateSendEffectChains(e.getAudioDeviceId()));
1269 }
1270
1271 public void sendEffectChainInfoChanged(SendEffectChainInfoEvent e) {
1272 if(e.getInstanceCount() == -1) return;
1273
1274 getTaskQueue().add (
1275 new Audio.UpdateEffectInstances(e.getAudioDeviceId(), e.getChainId())
1276 );
1277 }
1278 }
1279
1280 private static void
1281 fireChannelMidiDataEvent(ChannelMidiDataEvent e) {
1282 SamplerChannelModel chn;
1283 chn = getSamplerModel().getChannelById(e.getChannelId());
1284 if(chn == null) {
1285 CC.getLogger().info("Unknown channel ID: " + e.getChannelId());
1286 }
1287
1288 ((DefaultSamplerChannelModel)chn).fireMidiDataEvent(e);
1289 }
1290
1291 private static final AudioDeviceCountListener audioDeviceCountListener =
1292 new AudioDeviceCountListener();
1293
1294 private static class AudioDeviceCountListener implements ItemCountListener {
1295 /** Invoked when the number of audio output devices has changed. */
1296 @Override
1297 public void
1298 itemCountChanged(ItemCountEvent e) {
1299 getTaskQueue().add(new Audio.UpdateDevices());
1300 }
1301 }
1302
1303 private static final AudioDeviceInfoListener audioDeviceInfoListener =
1304 new AudioDeviceInfoListener();
1305
1306 private static class AudioDeviceInfoListener implements ItemInfoListener {
1307 /** Invoked when the audio output device's settings are changed. */
1308 @Override
1309 public void
1310 itemInfoChanged(ItemInfoEvent e) {
1311 getTaskQueue().add(new Audio.UpdateDeviceInfo(e.getItemID()));
1312 }
1313 }
1314
1315 private static final MidiDeviceCountListener midiDeviceCountListener =
1316 new MidiDeviceCountListener();
1317
1318 private static class MidiDeviceCountListener implements ItemCountListener {
1319 /** Invoked when the number of MIDI input devices has changed. */
1320 @Override
1321 public void
1322 itemCountChanged(ItemCountEvent e) {
1323 getTaskQueue().add(new Midi.UpdateDevices());
1324 }
1325 }
1326
1327 private static final MidiDeviceInfoListener midiDeviceInfoListener =
1328 new MidiDeviceInfoListener();
1329
1330 private static class MidiDeviceInfoListener implements ItemInfoListener {
1331 /** Invoked when the MIDI input device's settings are changed. */
1332 @Override
1333 public void
1334 itemInfoChanged(ItemInfoEvent e) {
1335 getTaskQueue().add(new Midi.UpdateDeviceInfo(e.getItemID()));
1336 }
1337 }
1338
1339 private static final MidiInstrMapCountListener midiInstrMapCountListener =
1340 new MidiInstrMapCountListener();
1341
1342 private static class MidiInstrMapCountListener implements ItemCountListener {
1343 /** Invoked when the number of MIDI instrument maps is changed. */
1344 @Override
1345 public void
1346 itemCountChanged(ItemCountEvent e) {
1347 getTaskQueue().add(new Midi.UpdateInstrumentMaps());
1348 }
1349 }
1350
1351 private static final MidiInstrMapInfoListener midiInstrMapInfoListener =
1352 new MidiInstrMapInfoListener();
1353
1354 private static class MidiInstrMapInfoListener implements ItemInfoListener {
1355 /** Invoked when the MIDI instrument map's settings are changed. */
1356 @Override
1357 public void
1358 itemInfoChanged(ItemInfoEvent e) {
1359 getTaskQueue().add(new Midi.UpdateInstrumentMapInfo(e.getItemID()));
1360 }
1361 }
1362 }

  ViewVC Help
Powered by ViewVC