The reason we use JFugue, rather than dealing with MIDI messages, is so we can let JFugue deal with the low-level details of MIDI file structure. We create a pattern of four notes: C (quarter note), D (quarter note), E (half note), F (half note) each with a Rest of quarter-note between them.
The resulting MIDI file (JFugue10.mid) is 65 bytes. This is broken down as:
1. header (14 bytes). 'MThd' (4 bytes of ASCII), length of 00 00 00 06 (4 bytes), format (2 byte), ntrks (2 byte), division (2 bytes). The format = 00 00 = 0, ntrks = 00 01 = 1 track, division = 00 80 = 128 Pulses per Quarter Note
2. Track 1 header (8 bytes) 'MTrk' (4 bytes of ASCII code), and length of 00 00 00 2b (4 bytes). The length indicates that there will be 2b (hex) = 43 (dec) bytes of data to follow.
3. 43 bytes of Channel 1. The MIDI messages are printed by program (27 bytes). The other (16 bytes) are delta time signals. There are distinct values here, besides 0-time, 81 00 (VLQ) = 128, and 82 00 (VLQ) = 256. VLQ stands for Variable Length Quantity. Here 128 will denote quarter-note duration and 256 denotes half-note duration.
This is shown in this hex dump (I used Notepad++ with the Hex plug in). The annotations refer to the MIDI messages of Note on and Note off. The note off velocity is usually ignored. The last 3 bytes are end of track message FF 2F 00 or 255, 47, 0 (decimal).
package jfugue10;
import java.io.File;
import java.io.IOException;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javax.sound.midi.Sequence;
import javax.sound.midi.Track;
import org.jfugue.midi.MidiFileManager;
import org.jfugue.pattern.Pattern;
import org.jfugue.player.Player;
public class JFugue10 extends Application {
public static void main(String[] args) {
launch(args);
}
TextArea text;
Button button;
@Override
public void start(Stage primaryStage) throws Exception {
button = new Button("MIDI Messages");
button.setOnAction(e->example());
VBox examples = new VBox(10, button);
examples.setPadding(new Insets(10));
text = new TextArea();
text.setPrefRowCount(20);
text.setPrefColumnCount(32);
text.setFont(Font.font("Verdana", 20));
text.setEditable(false);
text.setWrapText(true);
HBox root = new HBox(50,examples,text);
Scene scene = new Scene(root, 900, 600);
primaryStage.setTitle("JFugue 10. MIDI Messages");
primaryStage.setScene(scene);
primaryStage.show();
}
private void example() {
Player player = new Player();
Pattern pattern =
new Pattern("Cqa80 R Dqa90 R Eha100 R Fha110d99");
text.setText("\n\npattern: " + pattern +
"\n\n\tChannel 1 MIDI Messages");
Sequence sequence = player.getSequence(pattern);
Track[] track = sequence.getTracks();
String status;
int c = 0;
int value;
for (int i = 0; i<track[0].size(); i++) {
byte[] bArr = track[0].get(i).getMessage().getMessage();
for (int j = 0; j<bArr.length; j++) {
value = 0xff & (int) bArr[j];
switch (value) {
case 128:
status = "\tNone Off, "
+ "Pitch and Velocity Off Follow";
break;
case 144:
status = "\tNote On, "
+ "Pitch and Velocity On Follow";
break;
default:
status = "";
}
text.appendText("\n " + c + ". " + value + status);
c++;
}
}
try {
MidiFileManager
.savePatternToMidi(pattern,
new File("JFugue10.mid"));
} catch (IOException ex) {
}
player.play(pattern);
}
}
This is the output:
No comments:
Post a Comment