/*
* SuperColliderClient.java
* Eisenkraut
*
* Copyright (c) 2004-2014 Hanns Holger Rutz. All rights reserved.
*
* This software is published under the GNU General Public License v3+
*
*
* For further information, please contact Hanns Holger Rutz at
* contact@sciss.de
*
*
* Changelog:
* 04-Aug-05 created
* 15-Sep-05 added limiter
*/
package de.sciss.eisenkraut.net;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.prefs.BackingStoreException;
import java.util.prefs.PreferenceChangeEvent;
import java.util.prefs.PreferenceChangeListener;
import java.util.prefs.Preferences;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.WindowConstants;
import de.sciss.eisenkraut.io.AudioBoxConfig;
import de.sciss.eisenkraut.io.RoutingConfig;
import de.sciss.eisenkraut.session.DocumentFrame;
import de.sciss.eisenkraut.session.Session;
import de.sciss.eisenkraut.util.PrefsUtil;
import de.sciss.app.AbstractApplication;
import de.sciss.app.Application;
import de.sciss.app.BasicEvent;
import de.sciss.app.DocumentListener;
import de.sciss.app.DynamicPrefChangeManager;
import de.sciss.app.EventManager;
import de.sciss.net.OSCBundle;
import de.sciss.net.OSCChannel;
import de.sciss.net.OSCMessage;
import de.sciss.jcollider.Bus;
import de.sciss.jcollider.Constants;
import de.sciss.jcollider.ContiguousBlockAllocator;
import de.sciss.jcollider.Group;
import de.sciss.jcollider.NodeWatcher;
import de.sciss.jcollider.Server;
import de.sciss.jcollider.ServerEvent;
import de.sciss.jcollider.ServerListener;
import de.sciss.jcollider.ServerOptions;
import de.sciss.jcollider.Synth;
import de.sciss.jcollider.UGenInfo;
import de.sciss.jcollider.gui.NodeTreePanel;
import de.sciss.util.Param;
/**
* @author Hanns Holger Rutz
* @version 0.70, 29-Apr-08
*
* @todo volume should be managed in separate synths pre limiters
* so that pre-fader metering becomes possible
*/
public class SuperColliderClient
implements OSCRouter, Constants, ServerListener, DocumentListener
{
private ServerOptions so;
protected Server server = null;
private boolean serverIsReady = false; // = running + defs have been loaded
protected NodeWatcher nw = null;
private final Preferences audioPrefs;
private static final int DEFAULT_PORT = 57109; // our default server udp port
private final List collListeners = new ArrayList();
protected final List collPlayers = new ArrayList();
private final Map mapDocsToPlayers = new HashMap();
protected RoutingConfig oCfg = null;
private Preferences oCfgNode = null;
private final DynamicPrefChangeManager oCfgDynPrefs;
private Group grpMaster;
private Group grpGain;
private Group grpLimiter;
private boolean limiter = false;
// private boolean chanMeter = false;
// private final javax.swing.Timer meterTimer;
private int dumpMode = kDumpOff;
private float volume = 1.0f;
private final OSCRouterWrapper osc;
private static final String OSC_SUPERCOLLIDER = "sc";
// Busses that have been allocated by OSC clients
// key = Integer( busindex ) ; value = Bus
private final Map mapOSCBusses = new HashMap();
// Buffers that have been allocated by OSC clients
// key = Integer( bufnum ) ; value = Buffer
private final Map mapOSCBuffers = new HashMap();
private boolean reboot = false;
private final MeterManager meterManager;
protected EventManager elmClient = null;
// private final EventManager elmServer;
protected static SuperColliderClient instance;
public SuperColliderClient()
{
super();
if( instance != null ) throw new IllegalStateException( "Only one instance allowed" );
instance = this;
final Application app = AbstractApplication.getApplication();
final Preferences userPrefs = app.getUserPrefs();
final PreferenceChangeListener oCfgListener;
audioPrefs = userPrefs.node( PrefsUtil.NODE_AUDIO );
so = new ServerOptions();
so.setBlockAllocFactory( new ContiguousBlockAllocator.Factory() ); // deals better with fragmentation
oCfgListener = new PreferenceChangeListener() {
public void preferenceChange( PreferenceChangeEvent e )
{
// System.out.println( "DOING " + e.getKey() + " -> " + e.getNewValue() );
outputConfigChanged();
}
};
// note: we are using the DynamicPrefChangeManager instead of direct
// registration with oCfgNode because the sucky Preferences class
// is not using the EventThread
oCfgDynPrefs = new DynamicPrefChangeManager( null, RoutingConfig.KEYS, oCfgListener, false );
new DynamicPrefChangeManager( audioPrefs, new String[] { PrefsUtil.KEY_OUTPUTCONFIG },
oCfgListener, false ).startListening(); // fires change and hence createOutputConfig()
// osc = new OSCRouterWrapper( superRouter, this );
osc = new OSCRouterWrapper( OSCRoot.getInstance(), this );
meterManager = new MeterManager( this );
// elmServer = new EventManager( new EventManager.Processor() {
// public void processEvent( BasicEvent e )
// {
//// serverAction( (ServerEvent) e );
// }
// });
}
public void init()
throws IOException
{
AbstractApplication.getApplication().getDocumentHandler().addDocumentListener( this );
// UGenInfo.readDefinitions();
UGenInfo.readBinaryDefinitions();
}
public static SuperColliderClient getInstance()
{
return instance;
}
public Group getMasterGroup()
{
return grpMaster;
}
public MeterManager getMeterManager()
{
return meterManager;
}
public ServerOptions getServerOptions()
{
return so;
}
public SuperColliderPlayer getPlayerForDocument( Session doc )
{
return (SuperColliderPlayer) mapDocsToPlayers.get( doc );
}
public void addServerListener( ServerListener l )
{
synchronized( collListeners ) {
collListeners.add( l );
}
// if( server != null ) {
// server.addListener( l );
// }
}
public void removeServerListener( ServerListener l )
{
synchronized( collListeners ) {
collListeners.remove( l );
}
// if( server != null ) {
// server.removeListener( l );
// }
}
public void addClientListener( Listener listener )
{
synchronized( this ) {
if( elmClient == null ) {
elmClient = new EventManager( new EventManager.Processor() {
public void processEvent( BasicEvent e )
{
clientAction( (Event) e );
}
});
}
elmClient.addListener( listener );
}
}
public void removeClientListener( Listener listener )
{
if( elmClient != null ) elmClient.removeListener( listener );
}
public void setVolume( Object source, float volume )
{
final float oldVolume = this.volume;
if( oldVolume == volume ) return;
this.volume = volume;
if( (server != null) && server.isRunning() && (grpGain != null) ) {
try {
final OSCBundle bndl = new OSCBundle();
// server.getDefaultGroup().set( "volume", volume ); // all dem subgroups geddid
bndl.addPacket( grpGain.setMsg( "volume", volume ));
if( oldVolume == 1f ) {
bndl.addPacket( grpGain.runMsg( true ));
} else if( volume == 1f ) {
bndl.addPacket( grpGain.runMsg( false ));
}
server.sendBundle( bndl );
}
catch( IOException e1 ) {
printError( "setVolume", e1 );
}
}
if( (source != null) && (elmClient != null) ) {
elmClient.dispatchEvent( new Event( source, Event.VOLUME, System.currentTimeMillis(), this ));
}
}
public float getVolume()
{
return volume;
}
public RoutingConfig getOutputConfig()
{
return oCfg;
}
public void setLimiter( boolean onOff )
{
if( this.limiter != onOff ) {
this.limiter = onOff;
try {
if( grpLimiter != null ) grpLimiter.run( onOff );
}
catch( IOException e1 ) {
limiter = !limiter;
printError( "setLimiter", e1 );
}
}
}
public boolean getLimiter()
{
return limiter;
}
protected void setOutputConfig()
{
if( !serverIsReady || (oCfg == null) ) return;
OSCBundle bndl = new OSCBundle();
Synth synth;
bndl.addPacket( grpGain.freeAllMsg() );
bndl.addPacket( grpLimiter.freeAllMsg() );
for( int ch = 0; ch < oCfg.numChannels; ch++ ) {
if( oCfg.mapping[ ch ] < server.getOptions().getNumOutputBusChannels() ) {
synth = Synth.basicNew( "eisk-limiter", server );
bndl.addPacket( synth.newMsg( grpLimiter, new String[] { "i_aBus" }, new float[] { oCfg.mapping[ ch ]}));
nw.register( synth );
synth = Synth.basicNew( "eisk-gain", server );
bndl.addPacket( synth.newMsg( grpGain, new String[] { "i_aBus", "volume" }, new float[] { oCfg.mapping[ ch ], volume }));
nw.register( synth );
}
}
try {
server.sendBundle( bndl );
}
catch( IOException e1 ) {
printError( "setOutputConfig", e1 );
}
}
protected void outputConfigChanged()
{
SuperColliderPlayer p;
final String cfgID = audioPrefs.get( PrefsUtil.KEY_OUTPUTCONFIG, null );
final Preferences childPrefs = audioPrefs.node( PrefsUtil.NODE_OUTPUTCONFIGS );
RoutingConfig newCfg = null;
// oCfg = null;
if( oCfgNode != null ) {
oCfgDynPrefs.stopListening();
oCfgDynPrefs.setPreferences( null );
oCfgNode = null;
}
try {
if( (cfgID != null) && childPrefs.nodeExists( cfgID )) {
oCfgNode = childPrefs.node( cfgID );
newCfg = new RoutingConfig( oCfgNode );
// oCfgNode.addPreferenceChangeListener( oCfgListener );
oCfgDynPrefs.setPreferences( oCfgNode );
oCfgDynPrefs.startListening();
}
}
catch( BackingStoreException e1 ) {
printError( "createOutputConfig", e1 );
}
if( newCfg == null ) {
newCfg = new RoutingConfig( "none", "none" );
}
if( (oCfg != null) && oCfg.equals( newCfg )) return;
//System.out.println( "CHANGED" );
//System.out.println( oCfg );
//System.out.println( newCfg );
oCfg = newCfg;
setOutputConfig();
for( int i = 0; i < collPlayers.size(); i++ ) {
p = (SuperColliderPlayer) collPlayers.get( i );
// p.setOutputConfig( oCfg, volume );
p.setOutputConfig( oCfg );
}
if( elmClient != null ) {
elmClient.dispatchEvent( new Event( instance, Event.OUTPUTCONFIG, System.currentTimeMillis(), instance ));
}
}
// @synchronization must be called in the event thread!
private void dispose()
{
if( !EventQueue.isDispatchThread() ) throw new IllegalMonitorStateException();
//System.err.println( "//////////// dispose /////////////" );
// throws ConcurrentModificationException !
// for( Iterator iter = mapDocsToPlayers.keySet().iterator(); iter.hasNext(); ) {
// disposePlayer( (Session) iter.next() );
// }
final Object[] docs = mapDocsToPlayers.keySet().toArray();
for( int i = 0; i < docs.length; i++ ) {
disposePlayer( (Session) docs[ i ]);
}
grpLimiter = null;
try {
if( (grpMaster != null) && (server != null) && server.isRunning() ) grpMaster.free();
}
catch( IOException e1 ) {
printError( "dispose", e1 );
}
grpMaster = null;
// nw.clear();
if( nw != null ) {
//System.err.println( "disposing nw " + nw.hashCode() );
nw.dispose();
nw = null;
}
if( server != null ) {
server.dispose();
server = null;
}
serverIsReady = false;
}
public void dumpOSC( int mode )
{
this.dumpMode = mode;
// if( (server != null) && (server.getDumpMode() != mode) ) {
if( server != null ) {
// try {
server.dumpIncomingOSC( mode );
// scsynth's dumpOSC is buggy at the moment
// server.dumpOSC( mode );
server.dumpOutgoingOSC( mode );
// }
// catch( IOException e1 ) {
// printError( "dumpOSC", e1 );
// }
}
}
private String getResourceString( String key )
{
return AbstractApplication.getApplication().getResourceString( key );
}
public Server getServer()
{
return server;
}
public NodeWatcher getNodeWatcher()
{
return nw;
}
/**
* Queries the current server status.
*
* @return the current status or null if the server is not running
*/
public Server.Status getStatus()
{
if( server != null && server.isRunning() ) {
return server.getStatus();
} else {
return null;
}
}
public void quit()
{
Server.quitAll();
}
public void reboot()
{
reboot = true;
stop();
}
public void stop()
{
if( (server != null) && (server.isRunning() || server.isBooting()) ) {
try {
//System.err.println( "//////////// stop /////////////" );
server.quitAndWait();
}
catch( IOException e1 ) {
printError( "stop", e1 );
}
}
}
/**
* @synchronization must be called in the event thread
*/
public boolean boot()
{
if( !EventQueue.isDispatchThread() ) throw new IllegalMonitorStateException();
if( (server != null) && (server.isRunning() || server.isBooting()) ) return false;
//System.err.println( "//////////// boot /////////////" );
dispose();
String val;
int serverPort; // , idx;
Param p;
final String abCfgID = audioPrefs.get( PrefsUtil.KEY_AUDIOBOX, AudioBoxConfig.ID_DEFAULT );
final AudioBoxConfig abCfg = new AudioBoxConfig( audioPrefs.node( PrefsUtil.NODE_AUDIOBOXES ).node( abCfgID ));
p = Param.fromPrefs( audioPrefs, PrefsUtil.KEY_AUDIORATE, null );
if( p != null ) so.setSampleRate( p.val );
so.setNumInputBusChannels( abCfg.numInputChannels );
so.setNumOutputBusChannels( abCfg.numOutputChannels );
p = Param.fromPrefs( audioPrefs, PrefsUtil.KEY_AUDIOBUSSES, null );
if( p != null ) so.setNumAudioBusChannels( Math.max( abCfg.numInputChannels + abCfg.numOutputChannels, (int) p.val ));
p = Param.fromPrefs( audioPrefs, PrefsUtil.KEY_SCMEMSIZE, null );
if( p != null ) so.setMemSize( (int) p.val << 10 );
p = Param.fromPrefs( audioPrefs, PrefsUtil.KEY_SCBLOCKSIZE, null );
if( p != null ) so.setBlockSize( (int) p.val );
if( !abCfg.name.equals( "Default" )) so.setDevice( abCfg.name );
so.setLoadDefs( false );
so.setRendezvous( audioPrefs.getBoolean( PrefsUtil.KEY_SCRENDEZVOUS, true ));
//System.err.println( "abCfgID ="+abCfgID+" ("+abCfgID.equals( AudioBoxConfig.NAME_DEFAULT )+") ; in "+abCfg.numInputChannels+"; out "+abCfg.numOutputChannels );
// udp-port-number
// val = audioPrefs.get( PrefsUtil.KEY_SUPERCOLLIDEROSC, "" );
// idx = val.indexOf( ':' );
// serverPort = DEFAULT_PORT;
// try {
// if( idx >= 0 ) serverPort = Integer.parseInt( val.substring( idx + 1 ));
// }
// catch( NumberFormatException e1 ) {
// printError( "boot", e1 );
// }
p = Param.fromPrefs( audioPrefs, PrefsUtil.KEY_SCPORT, null );
serverPort = p == null ? DEFAULT_PORT : (int) p.val;
val = audioPrefs.get( PrefsUtil.KEY_SCPROTOCOL, OSCChannel.TCP );
so.setProtocol( val );
// so.setEnv( "SC_JACK_NAME", "Eisenkraut" );
val = audioPrefs.get( PrefsUtil.KEY_SUPERCOLLIDERAPP, null );
if( val == null ) {
System.err.println( getResourceString( "errSCSynthAppNotFound" ));
return false;
}
Server.setProgram( val );
// if( server != null ) {
// server.dispose(); // removes listeners as well
// server = null;
// }
// if( nw != null ) {
// nw.dispose();
// nw = null;
// }
try {
// check for automatic port assignment
if( serverPort == 0 ) {
if( so.getProtocol().equals( OSCChannel.TCP )) {
final ServerSocket ss = new ServerSocket( 0 );
serverPort = ss.getLocalPort();
ss.close();
} else if( so.getProtocol().equals( OSCChannel.UDP )) {
final DatagramSocket ds = new DatagramSocket();
serverPort = ds.getLocalPort();
ds.close();
} else {
throw new IllegalArgumentException( "Illegal protocol : " + so.getProtocol() );
}
}
// loopback is sufficient here
server = new Server( AbstractApplication.getApplication().getName(),
new InetSocketAddress( "127.0.0.1", serverPort ), so );
// for( int i = 0; i < collListeners.size(); i++ ) {
// server.addListener( (ServerListener) collListeners.get( i ));
// }
server.addListener( this );
if( dumpMode != kDumpOff ) dumpOSC( dumpMode );
nw = NodeWatcher.newFrom( server );
//System.err.println( "new nw " + nw.hashCode() );
//nw.VERBOSE = true;
// nw.start();
// final List cmdArray = server.getOptions().toOptionList( serverPort );
// for( int i = 0; i < cmdArray.size(); i++ ) {
// System.out.println( i + ": \"" + cmdArray.get( i ) + "\"" );
// }
server.boot();
return true;
}
catch( IOException e1 ) {
printError( "boot", e1 );
}
return false;
}
protected static void printError( String name, Throwable t )
{
//System.err.print( name + " : " );
//t.printStackTrace();
System.err.println( name + " : " + t.getClass().getName() + " : " + t.getLocalizedMessage() );
}
public Action getDebugLoadDefsAction()
{
return new ActionLoadDefs();
}
public Action getDebugNodeTreeAction()
{
return new ActionNodeTree();
}
public Action getDebugKillAllAction()
{
return new ActionKillAll();
}
protected OSCMessage loadDefsMsg()
throws IOException
{
// return new OSCMessage( "/d_loadDir", new Object[] { new File( "synthdefs" ).getAbsolutePath() });
// return new OSCMessage( "/d_load", new Object[] { new File( "synthdefs", "eisk-all.scsyndef" ).getAbsolutePath() });
final InputStream is = getClass().getResourceAsStream( "eisk-all.scsyndef" );
final int size = is.available();
final byte[] data = new byte[ size ];
is.read( data );
is.close();
return new OSCMessage( "/d_recv", new Object[] { data });
}
private void createNewPlayer( Session doc )
throws IOException
{
final SuperColliderPlayer p;
// final MeterListener ml;
// final Bus b;
final DocumentFrame f;
if( !mapDocsToPlayers.containsKey( doc )) {
// p = new SuperColliderPlayer( doc, server, oCfg, volume );
p = new SuperColliderPlayer( doc, server, oCfg );
collPlayers.add( p );
mapDocsToPlayers.put( doc, p );
f = doc.getFrame();
if( f != null ) f.playerCreated( p );
// if( chanMeter && (f != null) ) {
//// p.addMeterListener( doc.getFrame() );
//// meterTimer.restart();
// b = p.getInputBus();
// if( b != null ) {
// meterManager.addMeterListener( f, b, null );
// }
// }
}
}
private void disposePlayer( Session doc )
{
final SuperColliderPlayer p = (SuperColliderPlayer) mapDocsToPlayers.remove( doc );
final DocumentFrame f = doc.getFrame();
if( f != null ) f.playerDestroyed( p );
// if( f != null ) meterManager.removeMeterListener( f );
if( p != null ) {
collPlayers.remove( p );
p.dispose();
// if( chanMeter && collPlayers.isEmpty() ) meterTimer.stop();
}
}
// ------------- EventManager.Processor interface -------------
/*
* This is called by the EventManager
* if new events are to be processed.
*/
protected void clientAction( Event e )
{
Listener listener;
for( int i = 0; i < elmClient.countListeners(); i++ ) {
listener = (Listener) elmClient.getListener( i );
listener.clientAction( e );
}
}
// ------------- ServerListener interface -------------
public void serverAction( ServerEvent e )
{
if( server == null ) return;
switch( e.getID() ) {
case ServerEvent.STOPPED: // --------------------------------------- stopped
dispose();
synchronized( collListeners ) {
for( int i = 0; i < collListeners.size(); i++ ) {
((ServerListener) collListeners.get( i )).serverAction( e );
}
}
if( reboot ) {
reboot = false;
// final javax.swing.Timer timer = new javax.swing.Timer( 2000, new ActionListener() {
// public void actionPerformed( ActionEvent e )
// {
boot();
// }
// });
// timer.setRepeats( false );
// timer.start();
}
break;
case ServerEvent.RUNNING: // --------------------------------------- started
final Group grpRoot = server.getDefaultGroup();
final OSCBundle bndl = new OSCBundle();
nw.register( grpRoot );
try {
if( !server.sendMsgSync( loadDefsMsg(), 4.0f )) {
System.err.println( getResourceString( "errOSCTimeOut" ) + " : /d_loadDir" );
return;
}
grpMaster = Group.basicNew( server );
grpGain = Group.basicNew( server );
grpLimiter = Group.basicNew( server );
grpMaster.setName( "Master" );
grpGain.setName( "Gain" );
grpLimiter.setName( "Limiter" );
nw.register( grpMaster );
nw.register( grpGain );
nw.register( grpLimiter );
bndl.addPacket( grpMaster.addToTailMsg( grpRoot ));
bndl.addPacket( grpGain.addToHeadMsg( grpMaster ));
bndl.addPacket( grpLimiter.addToTailMsg( grpMaster ));
if( !limiter ) bndl.addPacket( grpLimiter.runMsg( false ));
if( volume == 1f ) bndl.addPacket( grpGain.runMsg( false ));
server.sendBundle( bndl );
serverIsReady = true;
setOutputConfig();
final de.sciss.app.DocumentHandler dh = AbstractApplication.getApplication().getDocumentHandler();
for( int i = 0; i < dh.getDocumentCount(); i++ ) {
createNewPlayer( (Session) dh.getDocument( i ));
}
}
catch( IOException e1 ) {
printError( "ServerEvent.RUNNING", e1 );
}
synchronized( collListeners ) {
for( int i = 0; i < collListeners.size(); i++ ) {
((ServerListener) collListeners.get( i )).serverAction( e );
}
}
break;
default: // --------------------------------------- other
synchronized( collListeners ) {
for( int i = 0; i < collListeners.size(); i++ ) {
((ServerListener) collListeners.get( i )).serverAction( e );
}
}
break;
}
}
// ------------ OSCRouter interface ------------
public String oscGetPathComponent()
{
return OSC_SUPERCOLLIDER;
}
public void oscRoute( RoutedOSCMessage rom )
{
osc.oscRoute( rom );
}
public void oscAddRouter( OSCRouter subRouter )
{
osc.oscAddRouter( subRouter );
}
public void oscRemoveRouter( OSCRouter subRouter )
{
osc.oscRemoveRouter( subRouter );
}
public Object oscQuery_port()
{
// schwachsinn, alles laeuft im event thread!
// final Server s = server;
return new Integer( server == null ? 0 : server.getAddr().getPort() );
}
public Object oscQuery_protocol()
{
return( server == null ? (Object) new Integer( 0 ) : (Object) server.getOptions().getProtocol() );
}
public Object oscQuery_running()
{
// final Server s = server;
// return new Integer( (s != null && s.isRunning()) ? 1 : 0 );
return new Integer( serverIsReady ? 1 : 0 );
}
public Object oscQuery_volume()
{
return new Float( getVolume() );
}
public void oscCmd_allocBus( RoutedOSCMessage rom )
{
int argIdx = 1;
try {
final Object rate;
if( rom.msg.getArg( argIdx ).toString().equals( "audio" )) {
rate = kAudioRate;
} else if( rom.msg.getArg( argIdx ).toString().equals( "control" )) {
rate = kControlRate;
} else {
OSCRoot.failedArgValue( rom, argIdx );
return;
}
argIdx++;
final Bus b;
final Server s = server;
if( s != null ) {
b = Bus.alloc( s, rate, rom.msg.getArgCount() > argIdx ?
((Integer) rom.msg.getArg( argIdx )).intValue() : 1 );
} else {
b = null;
}
if( b != null ) {
final Integer idx = new Integer( b.getIndex() );
mapOSCBusses.put( idx, b );
rom.replyDone( 1, new Object[] { idx });
} else {
rom.replyFailed();
}
}
catch( ClassCastException e1 ) {
OSCRoot.failedArgType( rom, argIdx );
}
catch( IndexOutOfBoundsException e1 ) {
OSCRoot.failedArgCount( rom );
}
catch( IOException e1 ) {
OSCRoot.failed( rom, e1 );
}
}
public void oscCmd_freeBus( RoutedOSCMessage rom )
{
try {
final Bus b = (Bus) mapOSCBusses.remove( rom.msg.getArg( 1 ));
if( b != null ) {
b.free();
} else {
OSCRoot.failed( rom.msg, OSCRoot.getResourceString( "errOSCBusNotFound" ));
}
}
catch( IndexOutOfBoundsException e1 ) {
OSCRoot.failedArgCount( rom );
}
}
public void oscCmd_allocBuf( RoutedOSCMessage rom )
{
int argIdx = 1;
try {
final int numFrames = ((Integer) rom.msg.getArg( argIdx )).intValue();
final int numChannels;
argIdx++;
if( rom.msg.getArgCount() > argIdx ) {
numChannels = ((Integer) rom.msg.getArg( argIdx )).intValue();
} else {
numChannels = 1;
}
final de.sciss.jcollider.Buffer b = de.sciss.jcollider.Buffer.alloc( server, numFrames, numChannels );
if( b != null ) {
final Integer num = new Integer( b.getBufNum() );
mapOSCBuffers.put( num, b );
rom.replyDone( 1, new Object[] { num });
} else {
rom.replyFailed();
}
}
catch( ClassCastException e1 ) {
OSCRoot.failedArgType( rom, argIdx );
}
catch( IndexOutOfBoundsException e1 ) {
OSCRoot.failedArgCount( rom );
}
catch( IOException e1 ) {
OSCRoot.failed( rom, e1 );
}
}
public void oscCmd_freeBuf( RoutedOSCMessage rom )
{
try {
final de.sciss.jcollider.Buffer b = (de.sciss.jcollider.Buffer) mapOSCBuffers.remove( rom.msg.getArg( 1 ));
if( b != null ) {
b.free();
} else {
OSCRoot.failed( rom.msg, OSCRoot.getResourceString( "errOSCBufNotFound" ));
}
}
catch( IndexOutOfBoundsException e1 ) {
OSCRoot.failedArgCount( rom );
}
catch( IOException e1 ) {
OSCRoot.failed( rom, e1 );
}
}
public void oscCmd_volume( RoutedOSCMessage rom )
{
try {
setVolume( this, ((Number) rom.msg.getArg( 1 )).floatValue() );
}
catch( ClassCastException e1 ) {
OSCRoot.failedArgType( rom, 1 );
}
catch( IndexOutOfBoundsException e1 ) {
OSCRoot.failedArgCount( rom );
}
}
public void oscCmd_boot( RoutedOSCMessage rom )
{
boot();
}
public void oscCmd_terminate( RoutedOSCMessage rom )
{
stop();
}
// ---------------- DocumentListener interface ----------------
public void documentAdded( de.sciss.app.DocumentEvent e )
{
// if( (server != null) && server.isRunning() ) {
// only create player when graph has been initialized and defs are available
// ; otherwise player will be created in serverAction() anyways!
if( serverIsReady ) {
try {
createNewPlayer( (Session) e.getDocument() );
}
catch( IOException e1 ) {
printError( "documentAdded", e1 );
}
}
}
public void documentRemoved( de.sciss.app.DocumentEvent e )
{
disposePlayer( (Session) e.getDocument() );
}
public void documentFocussed( de.sciss.app.DocumentEvent e ) { /* ignored */ }
// -------------- internal classes --------------
public static class Event
extends BasicEvent
{
// --- ID values ---
public static final int OUTPUTCONFIG = 0;
public static final int VOLUME = 1;
private final SuperColliderClient client;
protected Event( Object source, int id, long when, SuperColliderClient client )
{
super( source, id, when );
this.client = client;
}
public SuperColliderClient getClient()
{
return client;
}
public boolean incorporate( BasicEvent oldEvent )
{
if( oldEvent instanceof Event &&
this.getSource() == oldEvent.getSource() &&
this.getID() == oldEvent.getID() ) {
// XXX beware, when the actionID and actionObj
// are used, we have to deal with them here
return true;
} else return false;
}
}
private class ActionLoadDefs
extends AbstractAction
{
public ActionLoadDefs()
{
super( "Reload Synth Defs" );
}
public void actionPerformed( ActionEvent e )
{
if( server != null ) {
try {
server.sendMsg( new OSCMessage( "/d_loadDir", new Object[] {
new File( "synthdefs" ).getAbsolutePath() }));
}
catch( IOException e1 ) {
printError( getValue( NAME ).toString(), e1 );
}
}
}
}
private class ActionKillAll
extends AbstractAction
{
public ActionKillAll()
{
super( "killall scsynth" );
}
public void actionPerformed( ActionEvent e )
{
try {
Runtime.getRuntime().exec( "killall scsynth" );
}
catch( IOException e1 ) {
e1.printStackTrace();
}
}
}
private class ActionNodeTree
extends AbstractAction
{
public ActionNodeTree()
{
super( "View Node Graph" );
}
public void actionPerformed( ActionEvent e )
{
if( (server != null) && (nw != null) ) {
//System.err.println( "server.hashCode() = "+server.hashCode()+ "; nw.hashCode() = "+nw.hashCode() );
//final List coll = nw.getAllNodes();
//for( int i = 0; i < coll.size(); i++ ) {
// System.err.println( coll.get( i ).toString() );
//}
// nw.setFireAllNodes( true );
// nw.queryAllNodes( 4.0f, null );
final NodeTreePanel ntp = new NodeTreePanel( nw, server.getDefaultGroup() );
ntp.makeWindow().setDefaultCloseOperation( WindowConstants.DISPOSE_ON_CLOSE );
// ntp.getManager().VERBOSE = true;
// nw.VERBOSE = true;
}
}
}
// -------------------------- inner Listener interface --------------------------
public interface Listener
extends EventListener
{
public void clientAction( SuperColliderClient.Event e );
}
}