Melody and Accompaniment

This tutorial will look at a file which uses two different synthesis instruments. One for a stochastic melody and the other for an chordal accompaniment.

If yo have not already gone through the tutorial Audio 101, now would be a good time, as this tutorial will build upon it.

This is what the result of this tutorial file can sound like:

Click here to view the source file..

Let's have a closer look:
/**
* An example of simple audio rendering of a non-trivial jMusic score
* @author Andrew Brown
*/

 
import jm.JMC;
import jm.music.data.*;
import jm.util.*;
import jm.audio.*;
 
public class MelodyAndAccomp implements JMC{
//----------------
// Class Attributes
//----------------

private Score s = new Score("AU demo");
private Part p1 = new Part("Melody", 0);
private Part p2 = new Part("Chords", 1);
private int sampleRate = 8000;
private Instrument[] insts = {new SineInst(sampleRate),
new TriangleInst(sampleRate)};
private int bars = 4; //measures in American
//---------------------
// required main method
//---------------------

private static void main(String[] args) {
new MelodyAndAccomp();
}

Here we see import statements and variables very similar to what we saw in AudioScale (from the Audio 101 tutorial).   The main obvious difference is that we have defined two different instruments this time: the TriangleInst we used in AudioScale, and the SineInst.  This is because we are going to use a different sound for each of the two parts (SineInst for the melody and TriangleInst for the chords).  When we declare these, we store them in an Instrument array called insts.  This will be used later.

Note also that the Part constructors are different - they do not specify a channel.  This is because we are not using MIDI in this program (if we were using both MIDI as well as audio we could leave them in there. Infact, even if we aren't using MIDI at all, there's not difference in the output if you specify a channel - it's irrelevant!).  The instrument numbers for these parts are relative to the insts array - the SineInst being instrument 0, and the TriangleInst being instrument 1.  We tell the audio render to use this array to define the instruments later (when we actually 'render' ut, of course - see the last section of this tutorial).

	//------------------
// Constructor
//------------------

public MelodyAndAccomp() {
makeMelody();
makeChords();
completeScore();
renderAudio();
}
The constructor is extremely simple - it simply runs the following methods in the appropriate order.

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

// Create the stochastic melodic phrase
private void makeMelody() {
Phrase phr = new Phrase();
int temp, newPitch; //variable to store random number
int[] mode = {0,2,4,5,7,9,11,12}; //major scale degrees
int prevPitch = 60; //start on middle C

// create a melody of 25 randomly pitched quavers
// within C major

for(short i=0;i<bars*8-3;){
// generate a random number up to two octaves
// (or so) above middle C

temp = (int)(Math.random()*14 - 7);
// smooth the melodic contour
newPitch = prevPitch + temp;
// check that it is a note in the mode
// (C major in this case)

for (short j=0; j< mode.length; j++) {
if ( newPitch%12 == mode[j]) {
// if it is then add it to the
// phrase and move to the next
// note in the phrase

if(i == bars*8-4) {
Note n = new Note(newPitch, M,
(int)(Math.random()*50+60));
phr.addNote(n);
} else {
Note n = new Note(newPitch, Q,
(int)(Math.random()*50+60));
phr.addNote(n);
}
prevPitch = newPitch;
i++;
}
}
}
// add the phrase to part 1
p1.addPhrase(phr);
}

//make the chordal accompaniment
private void makeChords() {
// create a CPhrase
CPhrase cp = new CPhrase(0.0);
// Choose one of three minum chords at random, 5 times
for(short i=0;i<bars*2;i++) {
int x = (int)(Math.random()*3);
System.out.println("chord var x is " + x);
if (x==0) {
int[] pitchArray = {c3,e3,g3};
cp.addChord(pitchArray, SQ);
cp.addChord(pitchArray, Q);
cp.addChord(pitchArray, C);
cp.addChord(pitchArray, SQ);
} else if (x==1) {
int[] pitchArray = {d3,f3,a3};
cp.addChord(pitchArray, M);
} else {
int[] pitchArray = {b2,d3,g3};
cp.addChord(pitchArray, C);
cp.addChord(pitchArray, C);
}
}
// add the phrase to part 2
p2.addCPhrase(cp);
}

// combine parts into a score

private void completeScore() {
s.addPart(p1);
s.addPart(p2);
}

The above methods should be relatively easy to understand (assuming you have already covered the workings of the jMusic data representations such as Score and CPhrase, tutorials for which are found elsewhere - try the Dot tutorials), and are fairly well commented.   After running these methods we will have a completed score....

//save as an au audio file
private void renderAudio() {
Write.au(s, "Melody_and_Accomp.au", insts);
}
}

 ...which we can then send to Write.au(), specifying that it should use the Instruments in inststo render the appropriate sounds.  This successfully gives us an .au file of our piece!  Simple!



J Music Tutorial Index