[jmsl] Reverb tweaked for use in JSyn and JMSL

jmsl at music.columbia.edu jmsl at music.columbia.edu
Sat Jan 10 23:41:17 EST 2009


Here's a revision of Reverb2 I posted earlier.
This wraps Phil's Reverb1 wrapped up in a SynthNote, which addresses a 
few issues, so that now this works fine with JMSL.
main() has two tests in it: one pure JSyn and another for JMSL
Thanks
Nick Didkovsky


package com.punosmusic.circuitgrabbag;

/**
 * SynthNote Reverb
 *
 * This is a SynthNote wrapper around Phil Burk's Reverb1 SynthCircuit
 *
 * This is suitable for use in JMSL's signal processing 
SynthNoteAllPortsInstrumentSP, which therefore also works in JMSL Score.
 *
 * See main() for testing as pure JSyn or JMSL test
 *  
 * @author Nick Didkovsky 1/10/09
 *
 */
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import com.softsynth.jmsl.*;
import com.softsynth.jmsl.jsyn.*;
import com.softsynth.jsyn.*;
import com.softsynth.jsyn.circuits.FilteredSawtoothBL;
import com.softsynth.jsyn.circuits.Reverb1;

public class Reverb2 extends SynthNote {

    private Reverb1 reverb1;
    private BusWriter busWriter;
    public SynthInput input;
    public SynthInput dryGain;
    public SynthInput rate;

    SynthEnvelope env;
    EnvelopePlayer envPlayer;
    MultiplyUnit mult;

    public Reverb2() {
        add(reverb1 = new Reverb1());
        add(envPlayer = new EnvelopePlayer());

        add(busWriter = new BusWriter());
        add(mult = new MultiplyUnit());

        reverb1.busInput.connect(0, busWriter.busOutput, 0);
        envPlayer.output.connect(mult.inputA);
        reverb1.output.connect(mult.inputB);

        addPort(input = busWriter.input, "input");
        addPort(dryGain = reverb1.dryGain);
        addPort(rate = envPlayer.rate, "envRate");

        addPort(output = mult.output, "output");
        addPort(amplitude = envPlayer.amplitude, "amplitude");

        rate.setup(0.1, 1.0, 2.0);
        dryGain.setup(0, 0.15, 1.0);

        double[] envData = { 0.1, 1.0, 0.1, 0 };
        env = new SynthEnvelope(envData);

    }

    public void setStage(int time, int stage) {
        switch (stage) {
        case 0:
            start(time);
            envPlayer.envelopePort.queue(time, env, 0, 1);
            break;
        case 1:
            envPlayer.envelopePort.queue(time, env, 1, 1, 
Synth.FLAG_AUTO_STOP);
            break;
        default:
            break;
        }
    }

    public static void main(String[] args) {
        boolean TEST_JSYN = true;
        if (TEST_JSYN) {
            System.out.println("Test Reverb2 with JSyn only");
            Synth.startEngine(0);
            SynthObject.enableTracking(true);

            LineOut out = new LineOut();
            out.start();

            // sine for dry signal in left channel
            SineOscillator osc = new SineOscillator();
            osc.amplitude.set(0.5);
            osc.start();
            MultiplyUnit mult = new MultiplyUnit();
            mult.start();
            // toss a multiplier in to reduce dry signal level, cheap 
mixing...
            mult.inputA.set(0.5);
            osc.output.connect(mult.inputB);
            mult.output.connect(0, out.input, 0);

            // lag to sweep sine's frequency around so we can hear reverb
            ExponentialLag lag = new ExponentialLag();
            lag.input.set(100);
            lag.halfLife.set(0.2);
            lag.output.connect(osc.frequency);
            lag.input.set(1000);
            lag.start();

            // connect our reverb to right channel
            Reverb2 reverb2 = new Reverb2();
            reverb2.output.connect(0, out.input, 1);
            reverb2.setStage(0);

            // connect dry signal to reverb
            osc.output.connect(reverb2.input);

            Frame f = new Frame();
            f.addWindowListener(new WindowAdapter() {
                public void windowClosing(WindowEvent e) {
                    Synth.stopEngine();
                    System.exit(0);
                }
            });
            f.setSize(320, 200);
            f.setVisible(true);

            // wake up every so often and sweep to a new frequency
            while (true) {
                try {
                    Thread.sleep((long) (Math.random() * 3000 + 500));
                } catch (InterruptedException e1) {
                }

                double freq = Math.random() * 2000;
                lag.input.set(freq);

                System.out.println("Sweeping to " + freq + " Hz");

            }
        } else {
            System.out.println("Test Reverb2 with JMSL");
            java.awt.Frame f = new java.awt.Frame("Test Reverb2 with JMSL");
            f.setLayout(new java.awt.BorderLayout());
            f.addWindowListener(new java.awt.event.WindowAdapter() {
                public void windowClosing(java.awt.event.WindowEvent e) {
                    JMSL.closeMusicDevices();
                    System.exit(0);
                }
            });
            f.setSize(300, 200);
            f.setVisible(true);

            JSynMusicDevice.instance().edit(f);
            JSynMusicDevice.instance().open();

            JMSL.clock.setAdvance(0.5);
            JMSLRandom.randomize();

            // create two instruments, one to play dry melody and 
another to play reverb
            SynthNoteAllPortsInstrumentSP reverbIns = new 
SynthNoteAllPortsInstrumentSP(8, Reverb2.class.getName());
            SynthNoteAllPortsInstrument melodicIns = new 
SynthNoteAllPortsInstrument(8, FilteredSawtoothBL.class.getName());
            // patch output of melodic ins to input of reverb
            reverbIns.addSignalSource(melodicIns.getOutput());

            // add instruments to mixer and pan them hard left/right
            JMSLMixerContainer mixer = new JMSLMixerContainer();
            mixer.start();
            mixer.addInstrument(melodicIns);
            mixer.addInstrument(reverbIns);
            mixer.panAmpChange(0, 0, 0.35);
            mixer.panAmpChange(1, 1, 0.75);
            f.add(java.awt.BorderLayout.NORTH, 
mixer.getPanAmpControlPanel());

            // melody playing MusicShape
            MusicShape melodicShape = new 
MusicShape(melodicIns.getDimensionNameSpace());
            melodicShape.setName("melody");
            melodicShape.setInstrument(melodicIns);
            melodicShape.prefab();
            melodicShape.setRepeats(1000);

            // reverb playing MusicShape
            MusicShape reverbMusicShape = new 
MusicShape(reverbIns.getDimensionNameSpace());
            reverbMusicShape.setName("reverb");
            reverbMusicShape.setInstrument(reverbIns);
            reverbMusicShape.setRepeats(1000);
            // stuff reverb shape with long durations
            double[] defaultData = 
MusicShape.getDefaultArray(reverbMusicShape);
            defaultData[0]=8;  // long durations
            defaultData[2]=0.8; // amp
            defaultData[3]=7;  // long hold time for reverb
            
            for (int i = 0; i < 5; i++) {
                reverbMusicShape.add(defaultData);
            }
            
            
            final com.softsynth.jmsl.view.MusicShapeEditor se = new 
com.softsynth.jmsl.view.MusicShapeEditor();
            se.addMusicShape(reverbMusicShape);
            se.addMusicShape(melodicShape);
            f.add(java.awt.BorderLayout.SOUTH, se.getComponent());
            f.pack();

            melodicShape.addRepeatPlayable(new Playable() {
                public double play(double time, Composable parent) 
throws InterruptedException {
                    MusicShape m = (MusicShape) parent;
                    m.scramble(0, m.size() - 1, 0);
                    m.scramble(0, m.size() - 1, 1);
                    se.refresh();
                    return time;
                }

            });

            ParallelCollection col = new 
ParallelCollection(melodicShape, reverbMusicShape);
            col.launch(JMSL.now() + 3);

        }
    }
}



More information about the jmsl mailing list