// // Demo.java // // This demonstrates some features of JCollider. This demo // class is absolutely free and comes with absolutely no // warranties. JColider itself is released under the GNU GPL // (see separate license file). // // To launch the compiled class, CD into the JColider folder // and run the JSuperColiderDemo.sh shell script. // // Created by Hanns Holger Rutz on 10.09.05. // package de.sciss.jcollider.test; import java.awt.BorderLayout; import java.awt.Container; import java.awt.Font; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.TransferHandler; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import de.sciss.jcollider.*; import de.sciss.jcollider.gui.*; /** * This class demonstrates some * of JCollider's features, namely * loading and building synth defs, * along with instantiating and * controlling a server, showing * GUI elements like a server window * and a synthdef diagram. * <p> * A frame is opened with three tables, * the leftmost showing all synthdefs * found in the folder "synthdefs" * inside the cwd. The middle table * shows a list of synthdefs that have * been internally build using JCollider. * The right most table will carry defs * which have been drag-and-dropped from * the finder. * <p> * A GUI server window is opened for the localhost, * using default server options. Before booting, * check that the application path to scsynth is * correctly specified in the main frame. * <p> * Buttons at the bottom of the main frame will * create a synth for the selected def, stop all * synths, open a synthdef diagram and print the * def to the system console. A tree view of the node graph * can be created. * * @version 0.32, 25-Feb-08 * @author Hanns Holger Rutz * * @todo the demo and the NodeWatcher get irritated if * a server is already running and containing * nodes when the demo is launched * @todo quitting the application from the apple menu * will not perform clean-ups, notably the server * will not be shut down. please use main window's * close gadget for now * @todo should be possible to drag + drop nodes in * the tree panel, create subgroups etc. */ public class Demo extends JFrame implements FileFilter, ServerListener, Constants { public static Font fntGUI = ServerPanel.fntGUI; protected final SynthDefTable[] defTables; protected SynthDefTable selectedTable = null; protected static final Comparator synthDefNameComp = new SynthDefNameComp(); protected Server server = null; protected NodeWatcher nw = null; protected Group grpAll; private static final String[] tableNames = { "JCollider", "Drop Zone" }; protected final Demo enc_this = this; public Demo() { super( "JCollider Demo" ); final Box b = Box.createHorizontalBox(); final Box b2 = Box.createHorizontalBox(); final Container cp = getContentPane(); final JTextField ggAppPath = new JTextField( 32 ); final String fs = File.separator; JScrollPane ggScroll; JLabel lb; JFrame spf = null; defTables = new SynthDefTable[ 2 ]; for( int i = 0; i < 2; i++ ) { defTables[ i ] = new SynthDefTable( tableNames[ i ]); ggScroll = new JScrollPane( defTables[ i ]); b.add( ggScroll ); defTables[ i ].getSelectionModel().addListSelectionListener( new TableSelListener( i )); if( i == 1 ) { ggScroll.setTransferHandler( new SynthDefFileTransferHandler( 1 )); ggScroll.setToolTipText( "Drop SynthDef Files from the Finder here" ); } } try { cp.setLayout( new BorderLayout() ); cp.add( b, BorderLayout.CENTER ); server = new Server( "localhost" ); // loadDefs(); createDefs(); File f = findFile( JCollider.isWindows ? "scsynth.exe" : "scsynth", new String[] { fs + "Applications" + fs + "SuperCollider_f", fs + "Applications" + fs + "SC3", fs + "usr" + fs + "local" + fs + "bin", fs + "usr" + fs + "bin", "C:\\Program Files\\SC3", "C:\\Program Files\\SuperCollider_f" }); // if( (f == null) && JCollider.isMacOS ) { // try { // f = MRJAdapter.findApplication( "SCjm" ); // if( f != null ) f = new File( f.getParentFile(), "scsynth" ); // } // catch( IOException e1 ) {} // } if( f != null ) Server.setProgram( f.getAbsolutePath() ); ggAppPath.setText( Server.getProgram() ); ggAppPath.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { Server.setProgram( ggAppPath.getText() ); } }); lb = new JLabel( "Server App Path :" ); lb.setBorder( BorderFactory.createEmptyBorder( 2, 6, 2, 4 )); b2.add( lb ); b2.add( ggAppPath ); cp.add( b2, BorderLayout.NORTH ); cp.add( createButtons(), BorderLayout.SOUTH ); server.addListener( this ); try { server.start(); server.startAliveThread(); } catch( IOException e1 ) { /* ignored */ } // if( server.isRunning() ) initServer(); spf = ServerPanel.makeWindow( server, ServerPanel.MIMIC | ServerPanel.CONSOLE | ServerPanel.DUMP ); } catch( IOException e1 ) { JOptionPane.showMessageDialog( this, "Failed to create a server :\n" + e1.getClass().getName() + e1.getLocalizedMessage(), this.getTitle(), JOptionPane.ERROR_MESSAGE ); } JCollider.setDeepFont( cp, fntGUI ); addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { if( nw != null ) { nw.dispose(); nw = null; } if( server != null ) { try { if( server.didWeBootTheServer() ) server.quitAndWait(); else if( grpAll != null ) grpAll.free(); server = null; } catch( IOException e1 ) { reportError( e1 ); } } setVisible( false ); dispose(); System.exit( 0 ); } }); setDefaultCloseOperation( DO_NOTHING_ON_CLOSE ); // pack(); if( spf != null ) setLocation( spf.getX() + spf.getWidth() + 24, spf.getY() ); setSize( 512, 512 ); setVisible( true ); toFront(); } // private void loadDefs() // { // final File[] defFiles = new File( "synthdefs" ).listFiles( this ); // SynthDef[] defs; // final List collDefs = new ArrayList(); // // for( int i = 0; i < defFiles.length; i++ ) { // try { // defs = SynthDef.readDefFile( defFiles[ i ]); // for( int j = 0; j < defs.length; j++ ) { // collDefs.add( defs[ j ]); // } // } // catch( IOException e1 ) { // System.err.println( defFiles[ i ].getName() + " : " + e1.getClass().getName() + // " : " + e1.getLocalizedMessage() ); // } // } // // Collections.sort( collDefs, synthDefNameComp ); // defTables[ 0 ].addDefs( collDefs ); // } private JComponent createButtons() { final Box b = Box.createHorizontalBox(); JButton but; but = new JButton( new ActionPlay() ); but.setToolTipText( "Play Selected SynthDef" ); b.add( but ); but = new JButton( new ActionStop() ); but.setToolTipText( "Stop All Synths" ); b.add( but ); but = new JButton( new ActionDiagram() ); but.setToolTipText( "Open Diagram For Selected SynthDef" ); b.add( but ); but = new JButton( new ActionDump() ); but.setToolTipText( "Dump Selected SynthDef To The System Console" ); b.add( but ); but = new JButton( new ActionSynthDefApiEx() ); but.setToolTipText( "Demo code from SynthDef API doc" ); b.add( but ); but = new JButton( new ActionNodeTree() ); but.setToolTipText( "View a Tree of all Nodes" ); b.add( but ); return b; } private void createDefs() { try { // UGenInfo.readDefinitions(); UGenInfo.readBinaryDefinitions(); final List collDefs = DemoDefs.create(); Collections.sort( collDefs, synthDefNameComp ); // defTables[ 1 ].addDefs( collDefs ); defTables[ 0 ].addDefs( collDefs ); } catch( IOException e1 ) { e1.printStackTrace(); // reportError( e1 ); } } private void initServer() throws IOException { sendDefs(); if( !server.didWeBootTheServer() ) { server.initTree(); server.notify( true ); } // if( nw != null ) nw.dispose(); nw = NodeWatcher.newFrom( server ); grpAll = Group.basicNew( server ); nw.register( server.getDefaultGroup() ); nw.register( grpAll ); server.sendMsg( grpAll.newMsg() ); } private void sendDefs() { List defs; SynthDef def; for( int i = 0; i < defTables.length; i++ ) { defs = defTables[ i ].getDefs(); for( int j = 0; j < defs.size(); j++ ) { def = (SynthDef) defs.get( j ); try { def.send( server ); } catch( IOException e1 ) { System.err.println( "Sending Def " + def.getName() + " : " + e1.getClass().getName() + " : " + e1.getLocalizedMessage() ); } } } } private static File findFile( String fileName, String[] folders ) { File f; for( int i = 0; i < folders.length; i++ ) { f = new File( folders[ i ], fileName ); if( f.exists() ) return f; } return null; } public static void main( String args[] ) { SwingUtilities.invokeLater( new Runnable() { public void run() { new Demo(); } }); } protected static void reportError( Exception e ) { System.err.println( e.getClass().getName() + " : " + e.getLocalizedMessage() ); } // ------------- ServerListener interface ------------- public void serverAction( ServerEvent e ) { switch( e.getID() ) { case ServerEvent.RUNNING: try { initServer(); } catch( IOException e1 ) { reportError( e1 ); } break; case ServerEvent.STOPPED: // re-run alive thread final javax.swing.Timer t = new javax.swing.Timer( 1000, new ActionListener() { public void actionPerformed( ActionEvent e ) { try { if( server != null ) server.startAliveThread(); } catch( IOException e1 ) { reportError( e1 ); } } }); t.setRepeats( false ); t.start(); break; default: break; } } // ------------- FileFilter interface ------------- public boolean accept( File f ) { try { return SynthDef.isDefFile( f ); } catch( IOException e1 ) { return false; } } // ------------- internal classes ------------- private static class SynthDefTable extends JTable { private final SynthDefTableModel tm; protected SynthDefTable( String name ) { super(); tm = new SynthDefTableModel( name ); setModel( tm ); getColumnModel().getColumn( 0 ).setPreferredWidth( 128 ); setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); } // private void addDef( SynthDef def ) // { // tm.addDef( def ); // } protected void addDefs( List defs ) { tm.addDefs( defs ); } protected SynthDef getSelectedDef() { final int row = getSelectedRow(); if( row >= 0 ) return tm.getDef( row ); else return null; } protected List getDefs() { return tm.getDefs(); } } private static class SynthDefTableModel extends AbstractTableModel { private final List collDefs = new ArrayList(); private final String name; protected SynthDefTableModel( String name ) { super(); this.name = name; } public String getColumnName( int col ) { return name; } public int getRowCount() { return collDefs.size(); } public int getColumnCount() { return 1; } public Object getValueAt( int row, int column ) { if( row < collDefs.size() ) { return ((SynthDef) collDefs.get( row )).getName(); } else { return null; } } // private void addDef( SynthDef def ) // { // collDefs.add( def ); // fireTableRowsInserted( collDefs.size() - 1, collDefs.size() - 1 ); // } protected void addDefs( List defs ) { if( defs.isEmpty() ) return; final int startRow = collDefs.size(); collDefs.addAll( defs ); fireTableRowsInserted( startRow, collDefs.size() - 1 ); } protected SynthDef getDef( int idx ) { return (SynthDef) collDefs.get( idx ); } // private int getNumDefs() // { // return collDefs.size(); // } protected List getDefs() { return new ArrayList( collDefs ); } } private class ActionPlay extends AbstractAction { protected ActionPlay() { super( "Play" ); } public void actionPerformed( ActionEvent e ) { if( selectedTable == null ) return; final SynthDef def = selectedTable.getSelectedDef(); final Synth synth; if( (def != null) && (grpAll != null) && (server != null) ) { try { synth = Synth.basicNew( def.getName(), server ); if( nw != null ) nw.register( synth ); server.sendMsg( synth.newMsg( grpAll )); } catch( IOException e1 ) { JCollider.displayError( enc_this, e1, "Play" ); } } } } private class ActionStop extends AbstractAction { protected ActionStop() { super( "Stop All" ); } public void actionPerformed( ActionEvent e ) { if( grpAll != null ) { try { grpAll.freeAll(); } catch( IOException e1 ) { JCollider.displayError( enc_this, e1, "Stop" ); } } } } private class TableSelListener implements ListSelectionListener { int idx; protected TableSelListener( int idx ) { this.idx = idx; } public void valueChanged( ListSelectionEvent e ) { if( defTables[ idx ].getSelectedRowCount() > 0 ) { selectedTable = defTables[ idx ]; for( int i = 0; i < defTables.length; i++ ) { if( (i != idx) && defTables[ i ].getSelectedRowCount() > 0 ) { defTables[ i ].clearSelection(); } } } } } private class ActionDiagram extends AbstractAction { protected ActionDiagram() { super( "Def Diagram" ); } public void actionPerformed( ActionEvent e ) { if( selectedTable == null ) return; final SynthDef def = selectedTable.getSelectedDef(); if( def != null ) { new SynthDefDiagram( def ); } } } private class ActionDump extends AbstractAction { protected ActionDump() { super( "Def Dump" ); } public void actionPerformed( ActionEvent e ) { if( selectedTable == null ) return; final SynthDef def = selectedTable.getSelectedDef(); if( def != null ) { def.printOn( System.out ); } } } private class ActionSynthDefApiEx extends AbstractAction { protected ActionSynthDefApiEx() { super( "API Ex" ); } public void actionPerformed( ActionEvent e ) { DemoDefs.synthDefApiExample( server ); // doesn't inform nodewatcher though } } private class ActionNodeTree extends AbstractAction { protected ActionNodeTree() { super( "Node Tree" ); } public void actionPerformed( ActionEvent e ) { if( (server == null) || (nw == null) || (grpAll == null) ) return; final NodeTreePanel ntp = new NodeTreePanel( nw, grpAll ); final JFrame treeFrame = ntp.makeWindow(); treeFrame.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { treeFrame.setVisible( false ); treeFrame.dispose(); ntp.dispose(); } }); } } private static class SynthDefNameComp implements Comparator { protected SynthDefNameComp() { /* empty */ } public int compare( Object def1, Object def2 ) { return( ((SynthDef) def1).getName().compareTo( ((SynthDef) def2).getName() )); } } private class SynthDefFileTransferHandler extends TransferHandler { private final int idx; protected SynthDefFileTransferHandler( int idx ) { this.idx = idx; } /** * Overridden to import a Pathname if it is available. */ public boolean importData( JComponent c, Transferable t ) { final Object o; final List fileList; final List collDefs; File f; SynthDef[] defs; try { if( t.isDataFlavorSupported( DataFlavor.javaFileListFlavor )) { o = t.getTransferData( DataFlavor.javaFileListFlavor ); if( o instanceof List ) { fileList = (List) o; collDefs = new ArrayList(); for( int i = 0; i < fileList.size(); i++ ) { f = (File) fileList.get( i ); try { if( SynthDef.isDefFile( f )) { defs = SynthDef.readDefFile( f ); for( int j = 0; j < defs.length; j++ ) { collDefs.add( defs[ j ]); } } else { System.err.println( "Not a synth def file : " + f.getName() ); } } catch( IOException e1 ) { JCollider.displayError( enc_this, e1, "Drop File" ); } } if( !collDefs.isEmpty() ) { Collections.sort( collDefs, synthDefNameComp ); defTables[ idx ].addDefs( collDefs ); return true; } } } } catch( UnsupportedFlavorException e1 ) { /* ignored */ } catch( IOException e2 ) { JCollider.displayError( enc_this, e2, "Drop File" ); } return false; } public boolean canImport( JComponent c, DataFlavor[] flavors ) { for( int i = 0; i < flavors.length; i++ ) { if( flavors[i].equals( DataFlavor.javaFileListFlavor )) return true; } return false; } } // class PathTransferHandler }