|
| import jm.music.rt.RTLine; import jm.audio.Instrument; import jm.music.data.Note; import javax.swing.*; public class BassLine extends RTLine { private Note n = new Note(36, 0.5); private int pitch = 36; private int[] intervals = {0, 0, 0, 4, 7, 10, 12}; private double panPosition = 0.5; /** Constructor */ public BassLine (Instrument[] instArray) { super(instArray); } /** * Generate the next note when requested. */ public synchronized Note getNote() { n.setPitch(pitch + intervals[(int)(Math.random() * intervals.length)]); n.setDynamic((int)(Math.random()* 80 + 45)); n.setPan(panPosition); n.setRhythmValue((int)(Math.random() * 2 + 1) * 0.25); n.setDuration(n.getRhythmValue() * 0.9); return n; } /** Allow other classes to set the notes pan value */ public void setPanValue(double p) { this.panPosition = p; } // added for control change public synchronized void externalAction(Object obj, int actionNumber){ if(actionNumber == 1){ JSlider slider = (JSlider)obj; double filterCutoff = (double)(slider.getValue() * 100); for(int i=0;i<inst.length;i++){ double[] values = {filterCutoff}; inst[i].setController(values); } } } } |
In this example the RTComposition class
creates a graphical user interface and sends commands to the RTMixer
for broadcasting tot he RTLines when the interface is updated, by a
user moving a slider.
import jm.JMC;
|
To make this all work, we need to have an instrumnet class that will
respond to the control change messages being passed around. The key to
this is havin the instrument implement a setController() method that is
called by the RTLine sub
class. An important consideration is that the audio object, in this
case the Filter instance called filt,
needs to be declared as an instance variable so that is it visible to
the setController() method.
An array is passed to this method which allows for a group of parameter
changes to be passed at one time. In this case there is only one value,
so it is accessed as the zeroth index in the array.
| import jm.audio.Instrument; import jm.audio.io.*; import jm.audio.synth.*; import jm.music.data.Note; import jm.audio.AudioObject; /** * A monophonic sawtooth waveform instrument implementation * which includes a static low pass filter. * @author Andrew Brown */ public final class SawLPFInstRT2 extends Instrument{ //---------------------------------------------- // Instance variables //---------------------------------------------- private int sampleRate; private int filterCutoff; private int channels; private Filter filt; //---------------------------------------------- // Constructor //---------------------------------------------- public SawLPFInstRT2(){ this(44100); } /** * Basic default constructor to set an initial * sampling rate and use a default cutoff. * @param sampleRate */ public SawLPFInstRT2(int sampleRate){ this(sampleRate, 1000); } /** * Constructor that sets sample rate and the filter cutoff frequency. * @param sampleRate The number of samples per second (quality) * @param filterCutoff The frequency above which overtones are cut */ public SawLPFInstRT2(int sampleRate, int filterCutoff){ this(sampleRate, filterCutoff, 1); } /** * Constructor that sets sample rate, filter cutoff frequency, and channels. * @param sampleRate The number of samples per second (quality) * @param filterCutoff The frequency above which overtones are cut * @param channels 1 = mono, 2 = stereo. */ public SawLPFInstRT2(int sampleRate, int filterCutoff, int channels){ this.sampleRate = sampleRate; this.filterCutoff = filterCutoff; this.channels = channels; } //---------------------------------------------- // Methods //---------------------------------------------- /** * Initialisation method used to build the objects that * this instrument will use and specify thier interconnections. */ public void createChain(){ Oscillator wt = new Oscillator(this, Oscillator.SAWTOOTH_WAVE, this.sampleRate, this.channels); filt = new Filter(wt, this.filterCutoff, Filter.LOW_PASS); Envelope env = new Envelope(filt, new double[] {0.0, 0.0, 0.02, 1.0, 0.2, 0.5, 0.8, 0.3, 1.0, 0.0}); Volume vol = new Volume(env); StereoPan pan = new StereoPan(vol); } /** Changes the specified controller when called */ public void setController(double[] controlValues){ filt.setCutOff(controlValues[0]); } } |
While this message passing process is somewhat complicated to
start with you will find that it is very flexible and should allow for
quite sophisticated real time control of audio parameters.
|
© 2004 Andrew Brown |
|
|
|
|
|
|