/[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 1737 - (show annotations) (download)
Thu May 8 17:26:19 2008 UTC (15 years, 11 months ago) by iliev
File size: 39780 byte(s)
* Major memory optimizations when too many sampler channels are present

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.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 private 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 CC.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 CC.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(CC.getSamplerModel().getServerInfo() == null) return null;
413 if(!CC.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 CC.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 * This method updates the information about the backend state.
679 */
680 private static void
681 initSamplerModel() {
682 Server srv = getMainFrame().getServer();
683 if(srv == null) return;
684 initSamplerModel(srv);
685 }
686
687 /**
688 * This method updates the information about the backend state.
689 */
690 private static void
691 initSamplerModel(Server srv) {
692 setCurrentServer(srv);
693 final SetServerAddress ssa = new SetServerAddress(srv.getAddress(), srv.getPort());
694
695 final DefaultSamplerModel model = (DefaultSamplerModel)getSamplerModel();
696
697 final Global.GetServerInfo gsi = new Global.GetServerInfo();
698 gsi.addTaskListener(new TaskListener() {
699 public void
700 taskPerformed(TaskEvent e) {
701 if(gsi.doneWithErrors()) return;
702
703 model.setServerInfo(gsi.getResult());
704
705 if(CC.getViewConfig().getInstrumentsDbSupport()) {
706 getInstrumentsDbTreeModel();
707 }
708 }
709 });
710
711 final Audio.GetDrivers gaod = new Audio.GetDrivers();
712 gaod.addTaskListener(new TaskListener() {
713 public void
714 taskPerformed(TaskEvent e) {
715 if(!gaod.doneWithErrors())
716 model.setAudioOutputDrivers(gaod.getResult());
717 }
718 });
719
720 final GetEngines ge = new GetEngines();
721 ge.addTaskListener(new TaskListener() {
722 public void
723 taskPerformed(TaskEvent e) {
724 if(!ge.doneWithErrors()) model.setEngines(ge.getResult());
725 }
726 });
727
728 final Midi.GetDrivers gmid = new Midi.GetDrivers();
729 gmid.addTaskListener(new TaskListener() {
730 public void
731 taskPerformed(TaskEvent e) {
732 if(!gmid.doneWithErrors())
733 model.setMidiInputDrivers(gmid.getResult());
734 }
735 });
736
737 final Global.GetVolume gv = new Global.GetVolume();
738 gv.addTaskListener(new TaskListener() {
739 public void
740 taskPerformed(TaskEvent e) {
741 if(!gv.doneWithErrors())
742 model.setVolume(gv.getResult());
743 }
744 });
745
746 final Midi.GetInstrumentMaps mgim = new Midi.GetInstrumentMaps();
747 mgim.addTaskListener(new TaskListener() {
748 public void
749 taskPerformed(TaskEvent e) {
750 if(mgim.doneWithErrors()) return;
751 model.removeAllMidiInstrumentMaps();
752
753 for(MidiInstrumentMap map : mgim.getResult()) {
754 model.addMidiInstrumentMap(map);
755 }
756 }
757 });
758
759 final UpdateChannels uc = new UpdateChannels();
760 uc.addTaskListener(new TaskListener() {
761 public void
762 taskPerformed(TaskEvent e) {
763 for(SamplerChannelModel c : model.getChannels()) {
764 if(c.getChannelInfo().getEngine() == null) continue;
765
766 Channel.GetFxSends gfs = new Channel.GetFxSends();
767 gfs.setChannel(c.getChannelId());
768 gfs.addTaskListener(new GetFxSendsListener());
769 getTaskQueue().add(gfs);
770 }
771
772 // TODO: This should be done after the fx sends are set
773 //CC.getSamplerModel().setModified(false);
774 }
775 });
776
777
778 final Connect cnt = new Connect();
779 cnt.addTaskListener(new TaskListener() {
780 public void
781 taskPerformed(TaskEvent e) {
782 if(cnt.doneWithErrors()) {
783 setCurrentServer(null);
784 retryToConnect();
785 return;
786 }
787
788 getTaskQueue().add(gsi);
789 getTaskQueue().add(gaod);
790 getTaskQueue().add(gmid);
791 getTaskQueue().add(ge);
792 getTaskQueue().add(gv);
793 getTaskQueue().add(mgim);
794 getTaskQueue().add(new Midi.UpdateDevices());
795 getTaskQueue().add(new Audio.UpdateDevices());
796 addTask(uc);
797 }
798 });
799
800 ssa.addTaskListener(new TaskListener() {
801 public void
802 taskPerformed(TaskEvent e) {
803 CC.getTaskQueue().add(cnt);
804 }
805 });
806
807 getSamplerModel().reset();
808 if(instrumentsDbTreeModel != null) {
809 instrumentsDbTreeModel.reset();
810 instrumentsDbTreeModel = null;
811 }
812
813 getTaskQueue().removePendingTasks();
814 getTaskQueue().add(ssa);
815
816 fireReconnectEvent();
817 }
818
819 private static void
820 retryToConnect() {
821 javax.swing.SwingUtilities.invokeLater(new Runnable() {
822 public void
823 run() { changeBackend(); }
824 });
825 }
826
827 public static void
828 changeBackend() {
829 Server s = getMainFrame().getServer(true);
830 if(s != null) initSamplerModel(s);
831 }
832
833 private static class GetFxSendsListener implements TaskListener {
834 public void
835 taskPerformed(TaskEvent e) {
836 Channel.GetFxSends gfs = (Channel.GetFxSends)e.getSource();
837 if(gfs.doneWithErrors()) return;
838 SamplerChannelModel m = getSamplerModel().getChannelById(gfs.getChannel());
839 m.removeAllFxSends();
840
841 for(FxSend fxs : gfs.getResult()) m.addFxSend(fxs);
842 }
843 }
844
845 public static String
846 exportInstrMapsToLscpScript() {
847 StringBuffer sb = new StringBuffer("# Exported by: ");
848 sb.append("JSampler - a java front-end for LinuxSampler\r\n# Version: ");
849 sb.append(JSampler.VERSION).append("\r\n");
850 sb.append("# Date: ").append(new java.util.Date().toString()).append("\r\n\r\n");
851
852 Client lscpClient = new Client(true);
853 ByteArrayOutputStream out = new ByteArrayOutputStream();
854 lscpClient.setPrintOnlyModeOutputStream(out);
855
856 exportInstrMapsToLscpScript(lscpClient);
857 sb.append(out.toString());
858 out.reset();
859
860 return sb.toString();
861 }
862
863 private static void
864 exportInstrMapsToLscpScript(Client lscpClient) {
865 try {
866 lscpClient.removeAllMidiInstrumentMaps();
867 MidiInstrumentMap[] maps = CC.getSamplerModel().getMidiInstrumentMaps();
868 for(int i = 0; i < maps.length; i++) {
869 lscpClient.addMidiInstrumentMap(maps[i].getName());
870 exportInstrumentsToLscpScript(i, maps[i], lscpClient);
871 }
872 } catch(Exception e) {
873 CC.getLogger().log(Level.FINE, HF.getErrorMessage(e), e);
874 HF.showErrorMessage(e);
875 }
876 }
877
878 private static void
879 exportInstrumentsToLscpScript(int mapId, MidiInstrumentMap map, Client lscpClient)
880 throws Exception {
881
882 for(MidiInstrument i : map.getAllMidiInstruments()) {
883 lscpClient.mapMidiInstrument(mapId, i.getInfo().getEntry(), i.getInfo());
884 }
885 }
886
887 public static String
888 exportSessionToLscpScript() {
889 CC.getSamplerModel().setModified(false);
890
891 StringBuffer sb = new StringBuffer("# Exported by: ");
892 sb.append("JSampler - a java front-end for LinuxSampler\r\n# Version: ");
893 sb.append(JSampler.VERSION).append("\r\n");
894 sb.append("# Date: ").append(new java.util.Date().toString()).append("\r\n\r\n");
895
896 Client lscpClient = new Client(true);
897 ByteArrayOutputStream out = new ByteArrayOutputStream();
898 lscpClient.setPrintOnlyModeOutputStream(out);
899
900 try {
901 lscpClient.resetSampler();
902 sb.append(out.toString());
903 out.reset();
904 sb.append("\r\n");
905 lscpClient.setVolume(CC.getSamplerModel().getVolume());
906 sb.append(out.toString());
907 out.reset();
908 sb.append("\r\n");
909 } catch(Exception e) { CC.getLogger().log(Level.FINE, HF.getErrorMessage(e), e); }
910
911 MidiDeviceModel[] mDevs = getSamplerModel().getMidiDevices();
912 for(int i = 0; i < mDevs.length; i++) {
913 exportMidiDeviceToLscpScript(mDevs[i].getDeviceInfo(), i, lscpClient);
914 sb.append(out.toString());
915 out.reset();
916 sb.append("\r\n");
917 }
918
919 AudioDeviceModel[] aDevs = getSamplerModel().getAudioDevices();
920 for(int i = 0; i < aDevs.length; i++) {
921 exportAudioDeviceToLscpScript(aDevs[i].getDeviceInfo(), i, lscpClient);
922 sb.append(out.toString());
923 out.reset();
924 sb.append("\r\n");
925 }
926
927 exportInstrMapsToLscpScript(lscpClient);
928 sb.append(out.toString());
929 out.reset();
930 sb.append("\r\n");
931
932 SamplerChannelModel[] channels = getSamplerModel().getChannels();
933
934 for(int i = 0; i < channels.length; i++) {
935 SamplerChannelModel scm = channels[i];
936 exportChannelToLscpScript(scm.getChannelInfo(), i, lscpClient);
937 sb.append(out.toString());
938 out.reset();
939
940 sb.append("\r\n");
941
942 exportFxSendsToLscpScript(scm, i, lscpClient);
943 sb.append(out.toString());
944 out.reset();
945
946 sb.append("\r\n");
947 }
948
949 return sb.toString();
950 }
951
952 private static void
953 exportMidiDeviceToLscpScript(MidiInputDevice mid, int devId, Client lscpCLient) {
954 try {
955 String s = mid.getDriverName();
956 lscpCLient.createMidiInputDevice(s, mid.getAdditionalParameters());
957
958 MidiPort[] mPorts = mid.getMidiPorts();
959 int l = mPorts.length;
960 if(l != 1) lscpCLient.setMidiInputPortCount(devId, l);
961
962 for(int i = 0; i < l; i++) {
963 Parameter[] prms = mPorts[i].getAllParameters();
964 for(Parameter p : prms) {
965 if(!p.isFixed() && p.getStringValue().length() > 0)
966 lscpCLient.setMidiInputPortParameter(devId, i, p);
967 }
968 }
969 } catch(Exception e) {
970 CC.getLogger().log(Level.FINE, HF.getErrorMessage(e), e);
971 }
972 }
973
974 private static void
975 exportAudioDeviceToLscpScript(AudioOutputDevice aod, int devId, Client lscpCLient) {
976 try {
977 String s = aod.getDriverName();
978 lscpCLient.createAudioOutputDevice(s, aod.getAllParameters());
979
980 AudioOutputChannel[] chns = aod.getAudioChannels();
981
982 for(int i = 0; i < chns.length; i++) {
983 Parameter[] prms = chns[i].getAllParameters();
984 for(Parameter p : prms) {
985 if(p.isFixed() || p.getStringValue().length() == 0);
986 else lscpCLient.setAudioOutputChannelParameter(devId, i, p);
987 }
988 }
989 } catch(Exception e) {
990 CC.getLogger().log(Level.FINE, HF.getErrorMessage(e), e);
991 }
992 }
993
994 private static void
995 exportChannelToLscpScript(SamplerChannel chn, int chnId, Client lscpCLient) {
996 try {
997 lscpCLient.addSamplerChannel();
998
999 SamplerModel sm = CC.getSamplerModel();
1000 int id = chn.getMidiInputDevice();
1001 if(id != -1) {
1002 for(int i = 0; i < sm.getMidiDeviceCount(); i++) {
1003 if(sm.getMidiDevice(i).getDeviceId() == id) {
1004 lscpCLient.setChannelMidiInputDevice(chnId, i);
1005 break;
1006 }
1007 }
1008 lscpCLient.setChannelMidiInputPort(chnId, chn.getMidiInputPort());
1009 lscpCLient.setChannelMidiInputChannel(chnId, chn.getMidiInputChannel());
1010 }
1011
1012 if(chn.getEngine() != null) {
1013 lscpCLient.loadSamplerEngine(chn.getEngine().getName(), chnId);
1014 lscpCLient.setChannelVolume(chnId, chn.getVolume());
1015 int mapId = chn.getMidiInstrumentMapId();
1016 lscpCLient.setChannelMidiInstrumentMap(chnId, mapId);
1017 }
1018
1019 id = chn.getAudioOutputDevice();
1020 if(id != -1) {
1021 for(int i = 0; i < sm.getAudioDeviceCount(); i++) {
1022 if(sm.getAudioDevice(i).getDeviceId() == id) {
1023 lscpCLient.setChannelAudioOutputDevice(chnId, i);
1024 break;
1025 }
1026 }
1027
1028 Integer[] routing = chn.getAudioOutputRouting();
1029
1030 for(int j = 0; j < routing.length; j++) {
1031 int k = routing[j];
1032 if(k == j) continue;
1033
1034 lscpCLient.setChannelAudioOutputChannel(chnId, j, k);
1035 }
1036 }
1037
1038 String s = chn.getInstrumentFile();
1039 int i = chn.getInstrumentIndex();
1040 if(s != null) lscpCLient.loadInstrument(s, i, chnId, true);
1041
1042 if(chn.isMuted()) lscpCLient.setChannelMute(chnId, true);
1043 if(chn.isSoloChannel()) lscpCLient.setChannelSolo(chnId, true);
1044 } catch(Exception e) {
1045 CC.getLogger().log(Level.FINE, HF.getErrorMessage(e), e);
1046 }
1047 }
1048
1049 private static void
1050 exportFxSendsToLscpScript(SamplerChannelModel scm, int chnId, Client lscpClient) {
1051 try {
1052 FxSend[] fxSends = scm.getFxSends();
1053
1054 for(int i = 0; i < fxSends.length; i++) {
1055 FxSend f = fxSends[i];
1056 lscpClient.createFxSend(chnId, f.getMidiController(), f.getName());
1057
1058 Integer[] r = f.getAudioOutputRouting();
1059 for(int j = 0; j < r.length; j++) {
1060 lscpClient.setFxSendAudioOutputChannel(chnId, i, j, r[j]);
1061 }
1062 }
1063 } catch(Exception e) {
1064 CC.getLogger().log(Level.FINE, HF.getErrorMessage(e), e);
1065 }
1066 }
1067
1068 public static void
1069 scheduleInTaskQueue(final Runnable r) {
1070 Task dummy = new Global.DummyTask();
1071 dummy.addTaskListener(new TaskListener() {
1072 public void
1073 taskPerformed(TaskEvent e) {
1074 javax.swing.SwingUtilities.invokeLater(r);
1075 }
1076 });
1077
1078 CC.getTaskQueue().add(dummy);
1079 }
1080
1081 public static boolean
1082 verifyConnection() {
1083 if(getCurrentServer() == null) {
1084 HF.showErrorMessage(i18n.getError("CC.notConnected"));
1085 return false;
1086 }
1087
1088 return true;
1089 }
1090
1091
1092 private final static EventHandler eventHandler = new EventHandler();
1093
1094 private static EventHandler
1095 getHandler() { return eventHandler; }
1096
1097 private static class EventHandler implements ChannelCountListener, ChannelInfoListener,
1098 FxSendCountListener, FxSendInfoListener, StreamCountListener, VoiceCountListener,
1099 TotalStreamCountListener, TotalVoiceCountListener, TaskQueueListener,
1100 OrchestraListener, ListListener<OrchestraModel>, MidiInstrumentCountListener,
1101 MidiInstrumentInfoListener, GlobalInfoListener {
1102
1103 /** Invoked when the number of channels has changed. */
1104 public void
1105 channelCountChanged( ChannelCountEvent e) {
1106 addTask(new UpdateChannels());
1107 }
1108
1109 /** Invoked when changes to the sampler channel has occured. */
1110 public void
1111 channelInfoChanged(ChannelInfoEvent e) {
1112 /*
1113 * Because of the rapid notification flow when instrument is loaded
1114 * we need to do some optimization to decrease the traffic.
1115 */
1116 boolean b = true;
1117 Task[] tS = getTaskQueue().getPendingTasks();
1118
1119 for(int i = tS.length - 1; i >= 0; i--) {
1120 Task t = tS[i];
1121
1122 if(t instanceof Channel.UpdateInfo) {
1123 Channel.UpdateInfo cui = (Channel.UpdateInfo)t;
1124 if(cui.getChannelId() == e.getSamplerChannel()) return;
1125 } else {
1126 b = false;
1127 break;
1128 }
1129 }
1130
1131 if(b) {
1132 Task t = getTaskQueue().getRunningTask();
1133 if(t instanceof Channel.UpdateInfo) {
1134 Channel.UpdateInfo cui = (Channel.UpdateInfo)t;
1135 if(cui.getChannelId() == e.getSamplerChannel()) return;
1136 }
1137 }
1138
1139
1140 getTaskQueue().add(new Channel.UpdateInfo(e.getSamplerChannel()));
1141 }
1142
1143 /**
1144 * Invoked when the number of effect sends
1145 * on a particular sampler channel has changed.
1146 */
1147 public void
1148 fxSendCountChanged(FxSendCountEvent e) {
1149 getTaskQueue().add(new Channel.UpdateFxSends(e.getChannel()));
1150 }
1151
1152 /**
1153 * Invoked when the settings of an effect sends are changed.
1154 */
1155 public void
1156 fxSendInfoChanged(FxSendInfoEvent e) {
1157 Task t = new Channel.UpdateFxSendInfo(e.getChannel(), e.getFxSend());
1158 getTaskQueue().add(t);
1159 }
1160
1161 /**
1162 * Invoked when the number of active disk
1163 * streams in a specific sampler channel has changed.
1164 */
1165 public void
1166 streamCountChanged(StreamCountEvent e) {
1167 SamplerChannelModel scm =
1168 getSamplerModel().getChannelById(e.getSamplerChannel());
1169
1170 if(scm == null) {
1171 CC.getLogger().log (
1172 Level.WARNING,
1173 "CC.unknownChannel!",
1174 e.getSamplerChannel()
1175 );
1176
1177 return;
1178 }
1179
1180 scm.setStreamCount(e.getStreamCount());
1181 }
1182
1183 /**
1184 * Invoked when the number of active voices
1185 * in a specific sampler channel has changed.
1186 */
1187 public void
1188 voiceCountChanged(VoiceCountEvent e) {
1189 SamplerChannelModel scm =
1190 getSamplerModel().getChannelById(e.getSamplerChannel());
1191
1192 if(scm == null) {
1193 CC.getLogger().log (
1194 Level.WARNING,
1195 "CC.unknownChannel!",
1196 e.getSamplerChannel()
1197 );
1198
1199 return;
1200 }
1201
1202 scm.setVoiceCount(e.getVoiceCount());
1203 }
1204
1205 /** Invoked when the total number of active streams has changed. */
1206 public void
1207 totalStreamCountChanged(TotalStreamCountEvent e) {
1208 getSamplerModel().updateActiveStreamsInfo(e.getTotalStreamCount());
1209 }
1210
1211 /** Invoked when the total number of active voices has changed. */
1212 public void
1213 totalVoiceCountChanged(TotalVoiceCountEvent e) {
1214 getTaskQueue().add(new UpdateTotalVoiceCount());
1215 }
1216
1217 /** Invoked when the number of MIDI instruments in a MIDI instrument map is changed. */
1218 public void
1219 instrumentCountChanged(MidiInstrumentCountEvent e) {
1220 scheduleTask(new Midi.UpdateInstruments(e.getMapId()));
1221 }
1222
1223 /** Invoked when a MIDI instrument in a MIDI instrument map is changed. */
1224 public void
1225 instrumentInfoChanged(MidiInstrumentInfoEvent e) {
1226 Task t = new Midi.UpdateInstrumentInfo (
1227 e.getMapId(), e.getMidiBank(), e.getMidiProgram()
1228 );
1229 getTaskQueue().add(t);
1230
1231 }
1232
1233 /** Invoked when the global volume of the sampler is changed. */
1234 public void
1235 volumeChanged(GlobalInfoEvent e) {
1236 getSamplerModel().setVolume(e.getVolume());
1237 }
1238
1239 /**
1240 * Invoked to indicate that the state of a task queue is changed.
1241 * This method is invoked only from the event-dispatching thread.
1242 */
1243 public void
1244 stateChanged(TaskQueueEvent e) {
1245 switch(e.getEventID()) {
1246 case TASK_FETCHED:
1247 getProgressIndicator().setString (
1248 ((Task)e.getSource()).getDescription()
1249 );
1250 break;
1251 case TASK_DONE:
1252 EnhancedTask t = (EnhancedTask)e.getSource();
1253 if(t.doneWithErrors() && !t.isStopped()) {
1254 showError(t);
1255 }
1256 break;
1257 case NOT_IDLE:
1258 timer.start();
1259 break;
1260 case IDLE:
1261 timer.stop();
1262 getProgressIndicator().stop();
1263 break;
1264 }
1265 }
1266
1267 private void
1268 showError(final Task t) {
1269 javax.swing.SwingUtilities.invokeLater(new Runnable() {
1270 public void
1271 run() {
1272 if(t.getErrorDetails() == null) {
1273 HF.showErrorMessage(t.getErrorMessage());
1274 } else {
1275 getMainFrame().showDetailedErrorMessage (
1276 getMainFrame(),
1277 t.getErrorMessage(),
1278 t.getErrorDetails()
1279 );
1280 }
1281 }
1282 });
1283 }
1284
1285 /** Invoked when the name of orchestra is changed. */
1286 public void
1287 nameChanged(OrchestraEvent e) { saveOrchestras(); }
1288
1289 /** Invoked when the description of orchestra is changed. */
1290 public void
1291 descriptionChanged(OrchestraEvent e) { saveOrchestras(); }
1292
1293 /** Invoked when an instrument is added to the orchestra. */
1294 public void
1295 instrumentAdded(OrchestraEvent e) { saveOrchestras(); }
1296
1297 /** Invoked when an instrument is removed from the orchestra. */
1298 public void
1299 instrumentRemoved(OrchestraEvent e) { saveOrchestras(); }
1300
1301 /** Invoked when the settings of an instrument are changed. */
1302 public void
1303 instrumentChanged(OrchestraEvent e) { saveOrchestras(); }
1304
1305 /** Invoked when an orchestra is added to the orchestra list. */
1306 public void
1307 entryAdded(ListEvent<OrchestraModel> e) {
1308 e.getEntry().addOrchestraListener(getHandler());
1309 saveOrchestras();
1310 }
1311
1312 /** Invoked when an orchestra is removed from the orchestra list. */
1313 public void
1314 entryRemoved(ListEvent<OrchestraModel> e) {
1315 e.getEntry().removeOrchestraListener(getHandler());
1316 saveOrchestras();
1317 }
1318 }
1319
1320 private static final AudioDeviceCountListener audioDeviceCountListener =
1321 new AudioDeviceCountListener();
1322
1323 private static class AudioDeviceCountListener implements ItemCountListener {
1324 /** Invoked when the number of audio output devices has changed. */
1325 public void
1326 itemCountChanged(ItemCountEvent e) {
1327 getTaskQueue().add(new Audio.UpdateDevices());
1328 }
1329 }
1330
1331 private static final AudioDeviceInfoListener audioDeviceInfoListener =
1332 new AudioDeviceInfoListener();
1333
1334 private static class AudioDeviceInfoListener implements ItemInfoListener {
1335 /** Invoked when the audio output device's settings are changed. */
1336 public void
1337 itemInfoChanged(ItemInfoEvent e) {
1338 getTaskQueue().add(new Audio.UpdateDeviceInfo(e.getItemID()));
1339 }
1340 }
1341
1342 private static final MidiDeviceCountListener midiDeviceCountListener =
1343 new MidiDeviceCountListener();
1344
1345 private static class MidiDeviceCountListener implements ItemCountListener {
1346 /** Invoked when the number of MIDI input devices has changed. */
1347 public void
1348 itemCountChanged(ItemCountEvent e) {
1349 getTaskQueue().add(new Midi.UpdateDevices());
1350 }
1351 }
1352
1353 private static final MidiDeviceInfoListener midiDeviceInfoListener =
1354 new MidiDeviceInfoListener();
1355
1356 private static class MidiDeviceInfoListener implements ItemInfoListener {
1357 /** Invoked when the MIDI input device's settings are changed. */
1358 public void
1359 itemInfoChanged(ItemInfoEvent e) {
1360 getTaskQueue().add(new Midi.UpdateDeviceInfo(e.getItemID()));
1361 }
1362 }
1363
1364 private static final MidiInstrMapCountListener midiInstrMapCountListener =
1365 new MidiInstrMapCountListener();
1366
1367 private static class MidiInstrMapCountListener implements ItemCountListener {
1368 /** Invoked when the number of MIDI instrument maps is changed. */
1369 public void
1370 itemCountChanged(ItemCountEvent e) {
1371 getTaskQueue().add(new Midi.UpdateInstrumentMaps());
1372 }
1373 }
1374
1375 private static final MidiInstrMapInfoListener midiInstrMapInfoListener =
1376 new MidiInstrMapInfoListener();
1377
1378 private static class MidiInstrMapInfoListener implements ItemInfoListener {
1379 /** Invoked when the MIDI instrument map's settings are changed. */
1380 public void
1381 itemInfoChanged(ItemInfoEvent e) {
1382 getTaskQueue().add(new Midi.UpdateInstrumentMapInfo(e.getItemID()));
1383 }
1384 }
1385 }

  ViewVC Help
Powered by ViewVC