Dynamic Instrument Parameters
This tutorial shows how audio objects can
have variations built into them.
Hear the result of this tutorial's music
below.
Gongs3.mp3 [416K]
View
/ Download source - Instrument
class
View / Download
source - Composition class
Lets have a closer look.
import jm.audio.io.*;
import jm.audio.synth.*;
import jm.music.data.Note;
import jm.audio.AudioObject;
public final class VaryDecaySineInst extends jm.audio.Instrument{
private EnvPoint[] pointArray = new EnvPoint[10];
private int channels;
private int sampleRate;
*/
public VaryDecaySineInst(int sampleRate){
this(sampleRate, 2);
}
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;
}
*
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);
}
}
|
Dynamic Envelope Change
The dynamic part of this instrument is in
the declaration of envelope points.
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))
};
Notice that the last two EnvPoint's and have a randomised value, this
will be calculated when the instrument is constructed.
Therefore each instance of the instrument will be slightly different.
We use this characteristic in the following piece to create an additive
timbre where each partial has a slightly different envelope
and so the timbre changes over the duration of each note.
Compositional Example
This composition extends the Gong concept of the previous two tutorials.
the pitch of notes is used to determine the overtone series for each
gong.
There is plenty of randomness in both the setting of the fundamental
pitch, the overtone intervals, and overtone loudness - thus some gong
sounds
will be more convincing than others.
The score creates 5 gong tones (chords) each
with 8 partials (parts). This imbedded loop struture takes up most of
the code.
Instrument[] ensemble = new Instrument[partCounter];
for (int k = 0; k < partCounter; k++) {
ensemble[k] = new VaryDecaySineInst(sampleRate);
}
The VaryDecayinstrument described earlier is used for each part. In
order to minimise code repetition the instrument array is created in
a loop which
declares an instrument each iteration.
We are using multiple instances of the same instrument (rather than
just one) because the envelopes of each instance will vary thus giving
us
a dynamic timbrel result.
import jm.music.data.*;
import jm.music.tools.*;
import jm.JMC;
import jm.audio.*;
import jm.util.*;
public class Gongs3 implements JMC {
public static void main(String[] args) {
new Gongs3();
}
public Gongs3() {
Score score = new Score("Gongs 3");
int partCounter = 0;
double startTime = 0.0;
for (int j = 0; j < 5; j++) {
startTime = score.getEndTime();
int fundPitch = (int)(Math.random() * 12 + C2);
int pitch = 60;
double length = Math.random() * 10.0 + 4.0;
for (int i = 0; i < 8; i++) {
Part p = new Part("Part" + partCounter, partCounter);
partCounter ++;
Phrase phrase = new Phrase(startTime);
if (i == 0 ) {
pitch = fundPitch;
phrase.addNote(new Note(pitch, length + 2.0,
127 + C2 - pitch - (int) (Math.random() * 20)));
} else {
pitch = (int)(Math.random() * 16 + fundPitch + 8);
phrase.addNote(new Note(pitch, length,
127 + C2 - pitch - (int) (Math.random() * 20)));
}
p.addPhrase(phrase);
score.addPart(p);
}
}
View.show(score);
int sampleRate = 11000;
Instrument[] ensemble = new Instrument[partCounter];
for (int k = 0; k < partCounter; k++) {
ensemble[k] = new VaryDecaySineInst(sampleRate);
}
Write.au(score, "Gongs3.au", ensemble);
}
}
|