We have two java files.
Below is Mod, where transposeFromPattern must be public to be called. However getNote can be private since only this class can call it. Again we have the limit that chords must be in the + format. This can be overcome but code will become more complex. The methods are static so they may be simply called without creating an instance.
package jfugue29;
import org.jfugue.pattern.Pattern;
import org.jfugue.pattern.Token;
import org.jfugue.theory.Note;
class Mod {
public static Pattern transposeFromPattern(Pattern pattern, int nt) {
Pattern transpose = new Pattern();
for (Token token: pattern.getTokens()) {
if (token.getType() != Token.TokenType.NOTE) {
transpose.add(token.getPattern());
}
else {
String val = token.toString();
if (val.substring(0,1).equalsIgnoreCase("r")) { // Rest
transpose.add(token.toString());
}
else if (val.contains("+")) { // Chord (C+E+G format)
String newValue = "";
String[] notes = val.split("[+]");
int i;
for (i = 0; i<(notes.length-1); i++) {
newValue += (getNote(notes[i], 0, nt) + "+");
}
i = notes.length-1;
newValue += getNote(notes[i], 1, nt);
transpose.add(newValue);
}
else { // Single note
transpose.add(getNote(token.toString(), 1, nt));
}
}
}
return transpose;
}
private static String getNote(String noteString, int flag, int nt) {
Note note = new Note(noteString);
byte value = note.changeValue(nt).getValue();
String tone = Note.getToneString(value);
if (flag==0) return tone;
else {
String dur = Note.getDurationString(note.getDuration());
String vel = note.getVelocityString();
return tone + dur + vel;
}
}
}
The main class plays Deep Purple Smoke On the Water using the new Mod class. The sound is same as example 28, since the pattern is identical.
package jfugue29;
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 org.jfugue.pattern.Pattern;
import org.jfugue.player.Player;
public class JFugue29 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("Play Deep Purple\nSmoke On the\n\tWater");
button.setOnAction(e->example());
button.setFont(Font.font("Verdana", 16));
button.setPrefSize(200, 100);
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 29. Smoke On the Water" +
" by Deep Purple using Mod class.");
primaryStage.setScene(scene);
primaryStage.show();
}
private void example() {
Player player = new Player();
String g1 = "G3q A#3q C4q. G3q A#3q C#4i C4h G3q A#3q C4q. A#3q "
+ "G3ih.";
Pattern guitar1 = new Pattern(g1);
Pattern guitar2 = Mod.transposeFromPattern(guitar1, -12);
guitar1.repeat(8);
guitar1.setInstrument("OVERDRIVEN_GUITAR").setVoice(0);
guitar2.repeat(6);
guitar2.prepend("R/8.0"); // start at 8 beat
guitar2.setInstrument("OVERDRIVEN_GUITAR").setVoice(1);
Pattern bass1 = new Pattern("G3i").repeat(10);
Pattern bass2 = new Pattern("G3i").repeat(8);
Pattern bass3 =
new Pattern("A#3i A#3i C4i C4i C4i A#3i A#3i G3i G3i");
Pattern bass4 = new Pattern("G3i").repeat(5);
Pattern bass = new Pattern(bass1, bass2, bass3, bass4);
bass.repeat(4);
bass.prepend("R/16.0"); // start at 16 beat
bass.setInstrument("ELECTRIC_BASS_FINGER").setVoice(2);
Pattern drum = new Pattern("Rq [ACOUSTIC_SNARE]q").repeat(16);
drum.prepend("R/24.0"); // start at beat 24
drum.setVoice(9); // percussion
Pattern pattern =
new Pattern(guitar1, guitar2, bass, drum);
pattern.setTempo(110);
text.appendText("\n\nPattern:\n" + pattern + "\n\n");
player.play(pattern);
}
}
This is the output: