/[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 1688 - (show annotations) (download)
Thu Feb 14 16:52:36 2008 UTC (16 years, 2 months ago) by iliev
File size: 39370 byte(s)
* Implemented a backend list with option to manually choose a backend
  to connect on startup(Edit/Preferences, then click the `Backend' tab)
  and option to change the backend without restarting JSampler
  (Actions/Change Backend or Ctrl + B)

* Added confirmation messages for removing sampler channels and
  audio/MIDI devices (Edit/Preferences, then click the `View' tab)

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

  ViewVC Help
Powered by ViewVC