audio MIDI Music Algorithms Interfaces Programming Acoustics Context
> Audio > Synthesis > Signal Flow    
 
   

Signal Flow

This tutorial explains the standard way of indicating signal flow and how to create an jMusic instrument from a signal flow diagram.

Hear the result of this tutorial's music below.

Gongs2.mp3 [60K]

View / Download source - Instrument source code

View / Download source - Composition source code

Lets have a closer look. 
import jm.audio.io.*;
import jm.audio.synth.*;
import jm.music.data.Note;
import jm.audio.AudioObject;
 
/**
 * A basic sine instrument implementation
 * which changes the decay envelope on each instantiation.
 * @author Andrew Sorensen and Andrew R. Brown
 */
 
public final class VaryDecaySineInst extends jm.audio.Instrument{
	//----------------------------------------------
	// Attributes
	//----------------------------------------------
	/** The points to use in the construction of Envelopes */
	private EnvPoint[] pointArray = new EnvPoint[10];
	/** The number of channels */
	private int channels;
	/** the sample rate passed to the instrument */
	private int sampleRate;
 
	//----------------------------------------------
	// Constructor
	//----------------------------------------------
	/**
	 * Basic default constructor to set an initial 
	 * sampling rate.
	 * @param sampleRate 
	 */
	public VaryDecaySineInst(int sampleRate){
	    this(sampleRate, 2);
	}
	/**
	 * A constructor to set an initial 
	 * sampling rate and number of channels.
	 * @param sampleRate 
	 */
		EnvPoint[] tempArray = {
			new EnvPoint((float)0.0, (float)0.0),
			new EnvPoint((float)1.0, (float)0.001),
			new EnvPoint((float)0.5, (float)0.1),
			new EnvPoint((float)0.05, (float)(Math.random() * 0.4 + 0.3)),
			new EnvPoint((float)0.0, (float)(Math.random() * 0.3 + 0.7))
		};
		pointArray = tempArray;
	}
 
	//----------------------------------------------
	// Methods 
	//----------------------------------------------
	   
	/**
	 * Initialisation method used to build the objects that
	 * this instrument will use
	 */
	public void createChain(){
		WaveTable wt = new WaveTable(this, this.sampleRate, 
			Oscillator.getSineWave(this.sampleRate), channels);
		Envelope env = new Envelope(wt, pointArray);
		Volume vol = new Volume(env,(float)1.0);
		StereoPan span = new StereoPan(vol);
		SampleOut sout = new SampleOut( span, "jmusic.tmp");
	}	
}

Music V

One of the earliest computer music langauges was Music V (five) written by Max Matthews at Bell Labs in the USA. This language established the convention of using flow diagrams to depict signal flow, and this tradition is continued in jMusic in the audio chain structure.

The SimpleSineInst class (previous tutorial) would be depicted by the Music V signal flow diagram shown to the right. The top object is a break-point envelope generator that take two attributes, the time and amplitude of the points. The output of this modifies the aplitude of a sine wave oscillator, which also takes a frequency (pitch) attribute.

While this diagram is the traditional representation a more accurate representaion of the jMusic chain of events is depicted below.

SimpleSineInstMV.

In jMusic this process would be articulated in an Instrument as:

public void createChain(){
	WaveTable wt = new WaveTable(this, this.sampleRate, 
		Oscillator.getSineWave(this.sampleRate), channels);
	Envelope env = new Envelope(wt, pointArray);
	SampleOut sout = new SampleOut(env);
}

The jMusic chain order operates from the sample origin onward, that is, the samples are first created by the oscillator which is why it is first in the chain,
THEN the sample amplitide is adjusted by the envelope object.

You will see the Music V style diagrams in many books (and in these tutorials) so it is useful to understand how to translate them into a jMusic instrument.

Audio Object chains

The SineInst class is represented below as a flow diagram and code.

	public void createChain(){
		WaveTable wt = new WaveTable(this, this.sampleRate, 
			Oscillator.getSineWave(this.sampleRate), channels);
		Envelope env = new Envelope(wt, pointArray);
		Volume vol = new Volume(env,(float)1.0);
		StereoPan span = new StereoPan(vol);
		SampleOut sout = new SampleOut( span, "jmusic.tmp");

}

The difference is that this class adds more functionality to the instrument, implied but not specified by the diagram.
The Volume object allows the Instrument to respond to a Note's dynamic values and the StereoPan object enables the Instrument
(given that it has two channels) to respond to a Note's pan value.

The MusicV diagram can been seen as a somewhat abstract representation of the audio process.
it indicates the major synthesis components an omits details such as wheather the signal is mono or stereo.

Variable Sine Instrument

For this tutorial's composition (Gong2) we've created a variation on the SineInst class that allows for some randomness in the envelope settings.
This means that each instance of the instrument will be slightly different - thus providing some timbral variety in the rendered file.

The createChain() method of VaryDecaySineInst is identicale to the SineInst class.
The interest is in the specifying of the Envelope points in the constructor, as shown below.

	public VaryDecaySineInst(int sampleRate, int channels){
		this.sampleRate = sampleRate;
		this.channels = channels;
		EnvPoint[] tempArray = {
			new EnvPoint((float)0.0, (float)0.0),
			new EnvPoint((float)1.0, (float)0.001),
			new EnvPoint((float)0.5, (float)0.1),
			new EnvPoint((float)0.05, (float)(Math.random() * 0.4 + 0.3)),
			new EnvPoint((float)0.0, (float)(Math.random() * 0.3 + 0.7))
		};
		pointArray = tempArray;
	}
 
The decay and release portions of the envelope are set to random positions within certain constraints.

		new EnvPoint((float)0.05, (float)(Math.random() * 0.4 + 0.3)),
		new EnvPoint((float)0.0, (float)(Math.random() * 0.3 + 0.7))

The varying decay rates of the sine waves will mean that the timbral belnd between harmonis will change throughout the notes duration,
creating a more dynamic timbre and (hopefully) a more insteresting sound. as you can see the instrument definition in jMusic is quite flexible and,
with some imagination, can result in novel sounds.

Gong2 Composition

This class elaborates on the previous Gong composition by plaing each note in a different part, and therefore with a different instrument.
T his is required to exploit the variations in envelope discussed above.

import jm.music.data.*;
import jm.music.tools.*;
import jm.JMC;
import jm.audio.*;
import jm.util.*;
 
// Gong-like timbres inspired by 
//Claude Risset's early computer music pieces
 
public class Gongs2 implements JMC {
	
	public static void main(String[] args) {
		new Gongs2();
	}
	
	public Gongs2() {
		// musical score construction
		Score score = new Score();
		
		Part part0 = new Part("zero", 0);
		part0.addPhrase(new Phrase(new Note(CS4, 8.0)));
		Part part1 = new Part("one", 1);
		part1.addPhrase(new Phrase(new Note(BF4, 8.0)));
		Part part2 = new Part("two", 2);
		part2.addPhrase(new Phrase(new Note(D5, 8.0)));
		Part part3 = new Part("three", 3);
		part3.addPhrase(new Phrase(new Note(E5, 8.0)));
		Part part4 = new Part("four", 4);
		part4.addPhrase(new Phrase(new Note(A5, 8.0)));
		
		score.addPart(part0);
		score.addPart(part1);
		score.addPart(part2);
		score.addPart(part3);
		score.addPart(part4);
		
		
		View.show(score);
		
		// instrument declaration
		int sampleRate = 22000;
		Instrument variableSine1 = new VaryDecaySineInst(sampleRate);
		Instrument variableSine2 = new VaryDecaySineInst(sampleRate);
		Instrument variableSine3 = new VaryDecaySineInst(sampleRate);
		Instrument variableSine4 = new VaryDecaySineInst(sampleRate);
		Instrument variableSine5 = new VaryDecaySineInst(sampleRate);
		
		Instrument[] ensemble = {variableSine1, variableSine2, variableSine3, 
			variableSine4, variableSine5};
			
		// render
		Write.au(score, "Gongs2.au", ensemble);
	}
}

Note that in decalring new parts, a different instrument number is assigned to each:

Part part3 = new Part("three", 3); 

To accomodate several instruments an instrument array (called ensemble) is constructed and then passed to the rendering method.

	Instrument[] ensemble = {variableSine1, variableSine2, variableSine3, 
			variableSine4, variableSine5};
	Write.au(score, "Gongs2.au", ensemble);

 

 

jMusic Australia Council Queensland University of Technology Sitemap Contact Home Home http://www.qut.com http://explodingart.com/jmusic http://www.ozco.gov.au

Digital Instrument making Home