/* * JSampler - a java front-end for LinuxSampler * * Copyright (C) 2005 Grigor Kirilov Iliev * * This file is part of JSampler. * * JSampler is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * JSampler is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with JSampler; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ package org.jsampler; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; import java.util.Vector; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; import java.util.logging.SimpleFormatter; import java.util.logging.StreamHandler; import javax.swing.Timer; import net.sf.juife.Task; import net.sf.juife.TaskQueue; import net.sf.juife.event.TaskEvent; import net.sf.juife.event.TaskListener; import net.sf.juife.event.TaskQueueEvent; import net.sf.juife.event.TaskQueueListener; import org.jsampler.event.OrchestraEvent; import org.jsampler.event.OrchestraListEvent; import org.jsampler.event.OrchestraListListener; import org.jsampler.event.OrchestraListener; import org.jsampler.task.*; import org.jsampler.view.JSMainFrame; import org.jsampler.view.JSProgress; import org.linuxsampler.lscp.Client; import org.linuxsampler.lscp.event.*; import org.w3c.dom.Document; import org.w3c.dom.Node; /** * This class serves as a 'Control Center' of the application. * It also provides some fundamental routines and access to most used objects. * @author Grigor Iliev */ public class CC { private static Handler handler; private static FileOutputStream fos; private static JSMainFrame mainFrame = null; private static JSProgress progress = null; private final static Client lsClient = new Client(); private final static TaskQueue taskQueue = new TaskQueue(); private final static Timer timer = new Timer(2000, null); /** * Returns the logger to be used for logging events. * @return The logger to be used for logging events. */ public static Logger getLogger() { return Logger.getLogger ( "org.jsampler", "org.jsampler.langprops.LogsBundle" ); } /** * Returns the task queue to be used for scheduling tasks * for execution out of the event-dispatching thread. * @return The task queue to be used for scheduling tasks * for execution out of the event-dispatching thread. */ public static TaskQueue getTaskQueue() { return taskQueue; } /** * Returns the main window of this application. * @return The main window of this application. */ public static JSMainFrame getMainFrame() { return mainFrame; } /** * Sets the main window of this application. * @param mainFrame The main window of this application. */ public static void setMainFrame(JSMainFrame mainFrame) { CC.mainFrame = mainFrame; } /** * Gets the progress indicator of this application. * @return The progress indicator of this application. */ public static JSProgress getProgressIndicator() { return progress; } /** * Sets the progress indicator to be used by this application. * @param progress The progress indicator to be used by this application. */ public static void setProgressIndicator(JSProgress progress) { CC.progress = progress; } /** * This method does the initial preparation of the application. */ protected static void initJSampler() { fos = null; try { fos = new FileOutputStream("JSampler.log"); } catch(Exception x) { x.printStackTrace(); } if(fos == null) handler = new StreamHandler(System.out, new SimpleFormatter()); else handler = new StreamHandler(fos, new SimpleFormatter()); handler.setLevel(Level.FINE); getLogger().addHandler(handler); getLogger().setLevel(Level.FINE); Logger.getLogger("org.linuxsampler.lscp").addHandler(handler); Logger.getLogger("org.linuxsampler.lscp").setLevel(Level.FINE); // Flushing logs on every second new java.util.Timer().schedule(new java.util.TimerTask() { public void run() { if(handler != null) handler.flush(); } }, 1000, 1000); CC.getLogger().fine("CC.jsStarted"); HF.setUIDefaultFont(Prefs.getInterfaceFont()); getClient().setServerAddress(Prefs.getLSAddress()); getClient().setServerPort(Prefs.getLSPort()); timer.setRepeats(false); timer.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { CC.getProgressIndicator().start(); } }); taskQueue.addTaskQueueListener(getHandler()); taskQueue.start(); getClient().addChannelCountListener(getHandler()); getClient().addChannelInfoListener(getHandler()); getClient().addStreamCountListener(getHandler()); getClient().addVoiceCountListener(getHandler()); getClient().addTotalVoiceCountListener(getHandler()); loadOrchestras(); for(int i = 0; i < getOrchestras().getOrchestraCount(); i++) { getOrchestras().getOrchestra(i).addOrchestraListener(getHandler()); } getOrchestras().addOrchestraListListener(getHandler()); } private final static OrchestraListModel orchestras = new DefaultOrchestraListModel(); /** * Returns a list containing all available orchestras. * @return A list containing all available orchestras. */ public static OrchestraListModel getOrchestras() { return orchestras; } private static void loadOrchestras() { String s = Prefs.getOrchestras(); if(s == null) return; ByteArrayInputStream bais = new ByteArrayInputStream(s.getBytes()); Document doc = DOMUtils.readObject(bais); try { getOrchestras().readObject(doc.getDocumentElement()); } catch(Exception x) { HF.showErrorMessage(x, "Loading orchestras: "); } } private static void saveOrchestras() { Document doc = DOMUtils.createEmptyDocument(); Node node = doc.createElement("temp"); doc.appendChild(node); getOrchestras().writeObject(doc, doc.getDocumentElement()); doc.replaceChild(node.getFirstChild(), node); ByteArrayOutputStream baos = new ByteArrayOutputStream(); DOMUtils.writeObject(doc, baos); Prefs.setOrchestras(baos.toString()); } /** * The exit point of the application which ensures clean exit with default exit status 0. * @see #cleanExit(int i) */ public static void cleanExit() { cleanExit(0); } /** * The exit point of the application which ensures clean exit. * @param i The exit status. */ public static void cleanExit(int i) { CC.getLogger().fine("CC.jsEnded"); System.exit(i); } /** * Gets the Client object that is used to communicate with the backend. * @return The Client object that is used to communicate with the backend. */ public static Client getClient() { return lsClient; } private static final Vector listeners = new Vector(); /** * Registers the specified listener to be notified when reconnecting to LinuxSampler. * @param l The ActionListener to register. */ public static void addReconnectListener(ActionListener l) { listeners.add(l); } /** * Removes the specified listener. * @param l The ActionListener to remove. */ public static void removeReconnectListener(ActionListener l) { listeners.remove(l); } private static void fireReconnectEvent() { ActionEvent e = new ActionEvent(CC.class, ActionEvent.ACTION_PERFORMED, null); for(ActionListener l : listeners) l.actionPerformed(e); } private static final SamplerModel samplerModel = new DefaultSamplerModel(); /** * Gets the sampler model. * @return The sampler model. */ public static SamplerModel getSamplerModel() { return samplerModel; } /** * Reconnects to LinuxSampler. */ public static void reconnect() { initSamplerModel(); fireReconnectEvent(); } /** * This method updates the information about the backend state. */ public static void initSamplerModel() { final DefaultSamplerModel model = (DefaultSamplerModel)getSamplerModel(); final GetServerInfo gsi = new GetServerInfo(); gsi.addTaskListener(new TaskListener() { public void taskPerformed(TaskEvent e) { if(!gsi.doneWithErrors()) model.setServerInfo(gsi.getResult()); } }); final GetAODrivers gaod = new GetAODrivers(); gaod.addTaskListener(new TaskListener() { public void taskPerformed(TaskEvent e) { if(!gaod.doneWithErrors()) model.setAudioOutputDrivers(gaod.getResult()); } }); final GetEngines ge = new GetEngines(); ge.addTaskListener(new TaskListener() { public void taskPerformed(TaskEvent e) { if(!ge.doneWithErrors()) model.setEngines(ge.getResult()); } }); final GetMIDrivers gmid = new GetMIDrivers(); gmid.addTaskListener(new TaskListener() { public void taskPerformed(TaskEvent e) { if(!gmid.doneWithErrors()) model.setMidiInputDrivers(gmid.getResult()); } }); final Connect cnt = new Connect(); cnt.addTaskListener(new TaskListener() { public void taskPerformed(TaskEvent e) { if(cnt.doneWithErrors()) return; getTaskQueue().add(gsi); getTaskQueue().add(gaod); getTaskQueue().add(gmid); getTaskQueue().add(ge); getTaskQueue().add(new UpdateMidiDevices()); getTaskQueue().add(new UpdateAudioDevices()); getTaskQueue().add(new UpdateChannels()); } }); getTaskQueue().add(cnt); } private final static EventHandler eventHandler = new EventHandler(); private static EventHandler getHandler() { return eventHandler; } private static class EventHandler implements ChannelCountListener, ChannelInfoListener, StreamCountListener, VoiceCountListener, TotalVoiceCountListener, TaskQueueListener, OrchestraListener, OrchestraListListener { /** Invoked when the number of channels has changed. */ public void channelCountChanged( ChannelCountEvent e) { getTaskQueue().add(new UpdateChannels()); } /** Invoked when changes to the sampler channel has occured. */ public void channelInfoChanged(ChannelInfoEvent e) { /* * Because of the rapid notification flow when instrument is loaded * we need to do some optimization to decrease the traffic. */ boolean b = true; Task[] tS = getTaskQueue().getPendingTasks(); for(int i = tS.length - 1; i >= 0; i--) { Task t = tS[i]; if(t instanceof UpdateChannelInfo) { UpdateChannelInfo uci = (UpdateChannelInfo)t; if(uci.getChannelID() == e.getSamplerChannel()) return; } else { b = false; break; } } if(b) { Task t = getTaskQueue().getRunningTask(); if(t instanceof UpdateChannelInfo) { UpdateChannelInfo uci = (UpdateChannelInfo)t; if(uci.getChannelID() == e.getSamplerChannel()) return; } } getTaskQueue().add(new UpdateChannelInfo(e.getSamplerChannel())); } /** * Invoked when the number of active disk * streams in a specific sampler channel has changed. */ public void streamCountChanged(StreamCountEvent e) { SamplerChannelModel scm = getSamplerModel().getChannelModel(e.getSamplerChannel()); if(scm == null) { CC.getLogger().log ( Level.WARNING, "CC.unknownChannel!", e.getSamplerChannel() ); return; } scm.setStreamCount(e.getStreamCount()); } /** * Invoked when the number of active voices * in a specific sampler channel has changed. */ public void voiceCountChanged(VoiceCountEvent e) { SamplerChannelModel scm = getSamplerModel().getChannelModel(e.getSamplerChannel()); if(scm == null) { CC.getLogger().log ( Level.WARNING, "CC.unknownChannel!", e.getSamplerChannel() ); return; } scm.setVoiceCount(e.getVoiceCount()); } /** Invoked when the total number of active voices has changed. */ public void totalVoiceCountChanged(TotalVoiceCountEvent e) { getTaskQueue().add(new UpdateTotalVoiceCount()); } /** * Invoked to indicate that the state of a task queue is changed. * This method is invoked only from the event-dispatching thread. */ public void stateChanged(TaskQueueEvent e) { switch(e.getEventID()) { case TASK_FETCHED: getProgressIndicator().setString ( ((Task)e.getSource()).getDescription() ); break; case TASK_DONE: EnhancedTask t = (EnhancedTask)e.getSource(); if(t.doneWithErrors() && !t.isStopped()) HF.showErrorMessage(t.getErrorMessage()); break; case NOT_IDLE: timer.start(); break; case IDLE: timer.stop(); getProgressIndicator().stop(); break; } } /** Invoked when the name of orchestra is changed. */ public void nameChanged(OrchestraEvent e) { saveOrchestras(); } /** Invoked when the description of orchestra is changed. */ public void descriptionChanged(OrchestraEvent e) { saveOrchestras(); } /** Invoked when an instrument is added to the orchestra. */ public void instrumentAdded(OrchestraEvent e) { saveOrchestras(); } /** Invoked when an instrument is removed from the orchestra. */ public void instrumentRemoved(OrchestraEvent e) { saveOrchestras(); } /** Invoked when the settings of an instrument are changed. */ public void instrumentChanged(OrchestraEvent e) { saveOrchestras(); } /** Invoked when an orchestra is added to the orchestra list. */ public void orchestraAdded(OrchestraListEvent e) { e.getOrchestraModel().addOrchestraListener(getHandler()); saveOrchestras(); } /** Invoked when an orchestra is removed from the orchestra list. */ public void orchestraRemoved(OrchestraListEvent e) { e.getOrchestraModel().removeOrchestraListener(getHandler()); saveOrchestras(); } } }