Parallel Oscillators

This tutorial provides an example of how waveforms, other than sine waves, can be tuned to musically (rather than timbrally) interesting ratios. Techniques shown here are useful for people interested in exploring intervallic relationships.

View / Download source - Instrument source code

View / Download source - Composition source code

Instrument class overview


import jm.audio.Instrument;
import jm.audio.io.*;
import jm.audio.synth.*;
import jm.music.data.Note;
import jm.audio.AudioObject;

/**
* A basic pulsewave waveform instrument implementation
* which has two tones a perfect fifth apart
* @author Andrew Brown
*/

public final class PulseFifthsInst extends Instrument{
//----------------------------------------------
// Attributes
//----------------------------------------------

/** The points to use in the construction of Envelopes */
private EnvPoint[] pointArray = new EnvPoint[10];

private int sampleRate;

//----------------------------------------------
// Constructor
//----------------------------------------------
/**
* Basic default constructor to set an initial
* sampling rate
* @param sampleRate
*/
public PulseFifthsInst(int sampleRate){
this.sampleRate = sampleRate;
EnvPoint[] tempArray = {
new EnvPoint((float)0.0, (float)0.0),
new EnvPoint((float)0.02, (float)1.0),
new EnvPoint((float)0.15, (float)0.6),
new EnvPoint((float)0.9, (float)0.4),
new EnvPoint((float)1.0, (float)0.0)
};
pointArray = tempArray;
}

//----------------------------------------------
// Methods
//----------------------------------------------

/**
* Initialisation method used to build the objects that
* this instrument will use
*/
public void createChain(){
// tonic
Oscillator wt = new Oscillator(this, Oscillator.PULSE_WAVE,
this.sampleRate, 2);
wt.setPulseWidth(0.15);
StereoPan span = new StereoPan(wt, (float)0.2);
// fifth
Oscillator wt2 = new Oscillator(this, Oscillator.PULSE_WAVE,
this.sampleRate, 2);
wt2.setPulseWidth(0.15);
wt2.setFrqRatio((float)(3.0/2.0));
StereoPan span2 = new StereoPan(wt2, (float)0.8);
// add together
AudioObject[] waves = {span, span2};
Add add = new Add(waves);
// continue to process
Envelope env = new Envelope(add, pointArray);
Volume vol = new Volume(env);
SampleOut sout = new SampleOut(vol);
}
}





The creatChain method holds the interesting stuff. Here we are setting up two pulse wave oscillators.

A pulse wave consists of two parts: a flat (negative) part and a raised (positive) part - the pulse. The frequency of the pulse wave increases as the pulses become closer together. The method setPulseWidth sets the width of the raised area (the pulse). If the pulse width is set to 0.5 (50%), a square wave is created.

The first oscillator is "normal" in that it has the default frequency. It produces the tonic.

The second oscillator has the same frequency, but a different frequency ratio: 3/2 (1.5)

Q: Why not just make the frequency 1.5 times the first one?
A: Adjusting the frequency ratio is an easy method for people interested in intervalic relationships. As well as this, it is easy for the frequency to be readjusted while maintaining the same ratio.

Here is a table that has the various ratios for the pythagorean tuning system. Try them out and see what you get!

Interval Ratio Derivation

Unison 1:1 Unison 1:1
Minor Second 256:243 Octave - M7
Major Second 9:8 (3:2)^2
Minor Third 32:27 Octave - M6
Major Third 81:64 (3:2)^4
Fourth 4:3 Octave - 5
Augmented Fourth 729:512 (3:2)^6
Fifth 3:2 (3:2)^1
Minor Sixth 128:81 Octave - M3
Major Sixth 27:16 (3:2)^3
Minor Seventh 16:9 Octave - M2
Major Seventh 243:128 (3:2)^5
Octave 2:1 Octave 2:

Below is the code that generates the music used in the example. Usual stuff like adding the Note to the Phrase to the Part to the Score. The Instrument that was created above (PulseFifthInst) is used (
new PulseFifthInst(sampleRate); ) to play the score ( Write.au(score, "PulseFifthsTest.au", inst); )


Musical Example

import jm.JMC;
import jm.music.data.*;
import jm.audio.*;
import jm.util.*;

/**
* @author Andrew Brown
*/
public final class PulseFifthsTest implements JMC{
public static void main(String[] args){
Score score = new Score("JMDemo - Audio test");
Part part = new Part("wave", 0);
Phrase phr = new Phrase(0.0);

for(int i = 0; i < 65; i++ ) {
Note note = new Note((int)(Math.random() * 18) + 60,
0.25,
(int)(Math.random() * 75) + 50);
phr.addNote(note);
}
part.addPhrase(phr);
score.addPart(part);

int sampleRate = 44100;
Instrument inst = new PulseFifthsInst(sampleRate);
Write.au(score, "PulseFifthsTest.au", inst);
View.au("PulseFifthsTest.au");
}
}





© 2001 Andrew Brown