/[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 1767 - (show annotations) (download)
Mon Sep 8 00:19:27 2008 UTC (15 years, 7 months ago) by iliev
File size: 40337 byte(s)
* Added `Copy To' and `Move To' commands to the MIDI bank context menu
  and to the MIDI instrument context menu
* Added commands to the MIDI instrument context menu for moving
  a MIDI instrument to another program
  (right-click on a MIDI instrument and choose `Change Program')
* Added option to choose between zero-based and one-based
  MIDI bank/program numbering
  (choose Edit/Preferences, then click the `Advanced' button)
* Added option to choose whether to include MIDI instrument
  mappings when exporting a sampler configuration to LSCP script.
  (choose Edit/Preferences, then click the `Advanced' button)
* Added option to set the MIDI instrument loading in background
  when exporting MIDI instrument mappings to LSCP script.
  (choose Edit/Preferences, then click the `Advanced' button)
* Implemented an option to change the socket read timeout
  (choose Edit/Preferences, then click the `Backend' tab)
* Updated LscpTree
* Fantasia: Added option to hide the active stream/voice count statistic
  in the sampler channel's small view
  (choose Edit/Preferences, then click the `Channels' tab)
* Fantasia: `Turn off animation effects' checkbox moved to the `View' tab

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

  ViewVC Help
Powered by ViewVC