Reading and modifying .jm files

jMusic has the ability to save scores in its own file format, by convention written with the suffix '.jm'. This format may not seem very useful, but in this tutorial we'll see how to read in an existing jm file then make further changes to it. A jm file keeps all jMusic data attributes ( a MIDI file does not) such as the phrase structure, difference between rhythmic value and duration, and so on. . . The reading of jm files also means than a composition can use existing material from one section for further development in another section.

There are three files in this tutorial. The first one generates a jm score and saves it to disk. The second reads back that file, modifies it, and resaves it to disk as a second jm file. The third file writes and reads each of the score, a part, and a phrase, within the one file as an exercise.

Click here to view source of JmGenerate.java

Click here to view source of JmMod.java

Click here to view source of JmGenerateTest.java

Lets have a closer look at the important bit only. By now you should be well versed in the jMusic basics : ).
		Write.jm(score, "generate.jm");
The generate class simply creates a score of two parts with one phrase each. Each phrase has randomly distributed notes. The above line of code above saves the score as a file to disk with the name 'generate.jm' The importing of the jm.util package is necessary to use the Read and Write classes.

import jm.JMC;
import jm.music.data.*;
import jm.midi.*;
import jm.music.tools.*;
import jm.util.*;
 

/**
* An example which reads in, accesses, and then modifies an
* existing jm score file
* @author Andrew Brown and Alistair Riddel
*/

public final class JmMod implements JMC{
 
public static void main(String[] args){
Score score = new Score("JMDemo - Modify a jm file");
Part inst = new Part("Flute", FLUTE, 0);
Part inst2 = new Part("Piano", PIANO, 1);
Phrase phr = new Phrase(0.0);
Phrase phr2 = new Phrase(0.0);
 

//read in the jm file to be modified

Read.jm(score, "generate.jm");

//extract out the score bits to work on

inst = score.getPart(0);
inst2 = score.getPart(1);
phr = inst.getPhrase(0);
phr2 = inst2.getPhrase(0);

//make the modification
//make the phrases sequential rather than simultaneous

phr2.setStartTime(phr.getEndTime());

//Show the result

View.show(score);
 

//write a JM Score file to disk

Write.jm(score, "generateMod.jm");
 

//write a MIDI file to disk of the result

Write.midi(score, "generateMod.mid");
}
}
This code fragment is from the JmMod.java file. The first line reads in the jm file created by the previous class. It then accesses the parts and phrases within it using the getPart() and getPhrase() methods. These methods take a number as an argument which is the nth element of that type.

The final line makes a modification to the second phrase by changing its start time. It gets the length of the first phrase and uses that as its start time. Thereby making the two phrases follow one after the other in time.

import jm.JMC;
import jm.music.data.*;
import jm.midi.*;
import jm.music.tools.*;
import jm.util.*;
 

/**
* An example which generates the writing of two phrases
* and saving as a jm file.
* For use with JmMod.java which edits the jm file
* @author Andrew Brown and Alistair Riddel
*/

public final class JmGenerateTest implements JMC{
public static void main(String[] args){
Score score = new Score("JMDemo - jm Generate test");
Part part1 = new Part("part 1", 1, 0);
Part part2 = new Part("part 2", 1, 1);
Phrase phr = new Phrase(0.0);
Phrase phr2 = new Phrase(0.0);

double beat = Math.random() * 1.0;
phr = note_density(beat);
beat = Math.random() * 1.0;
phr2 = note_density(beat);

part1.addPhrase(phr);
part2.addPhrase(phr2);
score.addPart(part1);
score.addPart(part2);

// view the result
View.show(score);

//write a MIDI file to disk
Write.midi(score, "generateTest.mid");

//save as a jm file to disk
Write.jm(score, "generateTest.jm");
//save the part to disk
Write.jm(part1, "generateTest.prt");
//save the phrase to disk
Write.jm(phr, "generateTest.phr");

//Create, or emty and refill. View to show it's back
Score scoreCopy = new Score();
Read.jm(scoreCopy, "generateTest.jm");
scoreCopy.setTitle("Score Copy");
View.show(scoreCopy, 10, 10);

part1.empty();
Read.jm(part1, "generateTest.prt");
View.show(part1, 20, 20);

phr.empty();
Read.jm(phr, "generateTest.phr");
View.show(phr, 40, 40);

System.out.println("Done!");
}


private static Phrase note_density(double beat) {
Phrase phrase = new Phrase();
int cnt;
int dyn = 100;
long dur = 350;
int pitch;

cnt = (int)(Math.random() * 100);
System.out.println(cnt);

for(short i=0;i<cnt;i++){
pitch = (int)(Math.random() * 127);
Note note = new Note(pitch, beat, dyn, dur);
phrase.addNote(note);
}
return phrase;
}
}
This code fragment is from the third class of this example, the JmGenerateTest.java class. After generating the score in the same way as above, this class writes the score, the first part, and the first phrase to disk. Following this a new score object is declared and the jm file read into it. The part and phrase objects previously used are emptied in turn and the appropriate files read into them. Each of the old and new scores, part, and phrase is displayed in a pseudo notation window so you can compare the outputs and see the results.



J Music Tutorial Index