/*
* MotoRevCtrl
*
* Created by Hanns Holger Rutz on 29.07.06.
*/
package de.sciss.jcollider.test;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import de.sciss.jcollider.*;
import de.sciss.jcollider.gui.*;
import de.sciss.net.*;
/**
* Provides a control enabled version of MotoRev with simple GUI.
* <p>
* To compile, be sure to add JCollider.jar to your classpath.
*
* @author Hanns Holger Rutz
* @version 0.32, 25-Feb-08
*/
public class MotoRevCtrl
implements ServerListener
{
protected Server server = null;
protected Synth synth = null;
private static final String[] ctrlNames = { "pulseModFreq", "pulseFreqMin", "pulseFreqMax", "pulseWidth", "lowPassFreq", "amp" };
private static final float[] ctrlLags = { 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f };
private static final ControlSpec[] ctrlSpecs = { new ControlSpec( 0.01, 100.0, Warp.exp, 0.0, 0.2, "Hz" ), // pulseModFreq
new ControlSpec( 0.1, 1000.0, Warp.exp, 0.0, 10.0, "Hz" ), // pulseFreqMin
new ControlSpec( 0.1, 1000.0, Warp.exp, 0.0, 30.0, "Hz" ), // pulseFreqMax
new ControlSpec( 0.01, 0.99, Warp.lin, 0.0, 0.5, null ), // pulseWidth
new ControlSpec( 20.0, 20000.0, Warp.exp, 0.0, 100.0, "Hz" ), // lowPassFreq
new ControlSpec( 0.0, 1.0, Warp.lin, 0.0, 0.4, null ), // amp
};
private EZSlider[] ezs;
private boolean defSent = false;
// public static void main( String args[] )
// {
// SwingUtilities.invokeLater( new Runnable() {
// public void run()
// {
// new MotoRevCtrl();
// }
// });
// }
public MotoRevCtrl()
{
final String fs = File.separator;
createControlWindow();
try {
// UGenInfo.readDefinitions(); // necessary if we build our own synth defs
UGenInfo.readBinaryDefinitions(); // necessary if we build our own synth defs
server = new Server( "myServer" );
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 ) Server.setProgram( f.getAbsolutePath() );
server.addListener( this );
try {
// detect server that was started from outside (e.g. sclang)
server.start();
server.startAliveThread();
}
catch( IOException e1 ) { /* ignored */ }
}
catch( IOException e1 ) {
e1.printStackTrace();
// reportError( e1 );
System.exit( 1 );
}
createServerWindow();
}
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;
}
private void createServerWindow()
{
final JFrame spf = ServerPanel.makeWindow( server, ServerPanel.MIMIC | ServerPanel.CONSOLE | ServerPanel.DUMP );
spf.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE );
}
private void createControlWindow()
{
final JFrame win;
final Container cp;
final JPanel p;
final GridBagLayout lay = new GridBagLayout();
final GridBagConstraints con = new GridBagConstraints();
final JToolBar tb;
final JToggleButton ggPlay;
win = new JFrame( "Moto Rev Ctrl" );
win.setDefaultCloseOperation( WindowConstants.DISPOSE_ON_CLOSE );
win.addWindowListener( new WindowAdapter() {
public void windowClosed( WindowEvent e )
{
if( server != null ) {
try {
if( server.didWeBootTheServer() ) server.quitAndWait();
else if( synth != null ) synth.free();
}
catch( IOException e1 ) {
System.err.println( e1 );
}
synth = null;
}
System.exit( 0 );
}
});
cp = win.getContentPane();
p = new JPanel( lay );
p.setBorder( BorderFactory.createEmptyBorder( 4, 4, 4, 4 ));
ezs = new EZSlider[ ctrlNames.length ];
con.gridwidth = GridBagConstraints.REMAINDER;
con.weightx = 1.0;
con.fill = GridBagConstraints.HORIZONTAL;
con.insets = new Insets( 2, 2, 2, 2 );
for( int i = 0; i < ctrlNames.length; i++ ) {
ezs[ i ] = new EZSlider();
ezs[ i ].setControlSpec( ctrlSpecs[ i ]);
ezs[ i ].setLabel( ctrlNames[ i ]);
ezs[ i ].setValue( ctrlSpecs[ i ].getDefaultVal() );
lay.setConstraints( ezs[ i ], con );
p.add( ezs[ i ]);
new ControlListener( ezs[ i ]);
}
tb = new JToolBar();
tb.setBorderPainted( false );
tb.setFloatable( false );
ggPlay = new JToggleButton( ">" );
ggPlay.setFont( new Font( "SansSerif", Font.PLAIN, 36 ));
tb.add( ggPlay );
ggPlay.addActionListener( new ActionListener() {
public void actionPerformed( ActionEvent e )
{
if( server != null ) {
if( synth != null ) {
try {
synth.free();
}
catch( IOException e1 ) {
reportError( e1 );
}
synth = null;
}
if( ggPlay.isSelected() ) {
createSynth();
}
}
}
});
cp.add( p, BorderLayout.CENTER );
cp.add( tb, BorderLayout.WEST );
EZSlider.align( ezs );
win.pack();
win.setLocationRelativeTo( null ); // center on screen
win.setVisible( true );
}
protected void createSynth()
{
final Control lagCtrl;
final GraphElem out, pulseModFreq, pulseFreqMin, pulseFreqMax, pulseWidth, lowPassFreq, amp;
final GraphElem pulseFreqMul, pulseFreqAdd;
final GraphElem pulseFreq, pulse, filter, clip, ugenGraph;
final SynthDef def;
final String defName;
final OSCMessage newMsg;
final float[] ctrlDefaults;
final float[] ctrlValues;
try {
defName = "MotoRevCtrl";
ctrlValues = new float[ ezs.length ];
for( int i = 0; i < ctrlValues.length; i++ ) {
ctrlValues[ i ] = (float) ezs[ i ].getValue();
}
synth = Synth.basicNew( defName, server );
newMsg = synth.newMsg( server.asTarget(), ctrlNames, ctrlValues );
if( !defSent ) {
ctrlDefaults = new float[ ctrlSpecs.length ];
for( int i = 0; i < ctrlDefaults.length; i++ ) {
ctrlDefaults[ i ] = (float) ctrlSpecs[ i ].getDefaultVal();
}
out = Control.kr( "out", 0f );
lagCtrl = LagControl.kr( ctrlNames, ctrlDefaults, ctrlLags );
pulseModFreq = lagCtrl.getOutput( 0 );
pulseFreqMin = UGen.kr( "min", lagCtrl.getOutput( 1 ), lagCtrl.getOutput( 2 ));
pulseFreqMax = UGen.kr( "max", lagCtrl.getOutput( 1 ), lagCtrl.getOutput( 2 ));
pulseWidth = lagCtrl.getOutput( 3 );
lowPassFreq = lagCtrl.getOutput( 4 );
amp = lagCtrl.getOutput( 5 );
pulseFreqMul = UGen.kr( "*", UGen.kr( "-", pulseFreqMax, pulseFreqMin ), UGen.ir( 0.5f ));
pulseFreqAdd = UGen.kr( "+", pulseFreqMin, pulseFreqMul );
pulseFreq = UGen.kr( "MulAdd", UGen.kr( "SinOsc", pulseModFreq ), pulseFreqMul, pulseFreqAdd );
pulse = UGen.ar( "LFPulse", pulseFreq, UGen.ir( 0.1f ), pulseWidth );
filter = UGen.ar( "RLPF", pulse, lowPassFreq, UGen.ir( 0.1f ));
clip = UGen.ar( "clip2", filter, amp );
ugenGraph = UGen.ar( "Out", out, clip );
def = new SynthDef( defName, ugenGraph );
def.send( server, newMsg );
defSent = true;
} else {
server.sendMsg( newMsg );
}
}
catch( IOException e1 ) {
reportError( e1 );
}
}
private void initServer()
throws IOException
{
if( !server.didWeBootTheServer() ) {
server.initTree();
}
defSent = false;
}
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();
// NodeWatcher nw = NodeWatcher.newFor(
}
catch( IOException e1 ) {
reportError( e1 );
}
break;
case ServerEvent.STOPPED:
synth = null;
// have to call startAliveThread to keep watching for server starts
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;
}
}
// ------------- internal classes -------------
private class ControlListener
implements ActionListener
{
private final EZSlider ez;
protected ControlListener( EZSlider ez )
{
this.ez = ez;
ez.addActionListener( this );
}
public void actionPerformed( ActionEvent e )
{
if( synth != null ) {
try {
synth.set( ez.getLabel(), (float) ez.getValue() );
}
catch( IOException e1 ) {
reportError( e1 );
}
}
}
}
}