/[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 1719 - (show annotations) (download)
Wed Mar 19 10:07:36 2008 UTC (16 years, 1 month ago) by iliev
File size: 39375 byte(s)
* Optimized the MIDI instrument update process

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

  ViewVC Help
Powered by ViewVC