Tuesday, July 26, 2016

JFugue 32. J.S. Bach's Canon No. 1 Goldberg Ground (BWV1087)

Below we have the new Mod class. The function of this class is to modify a pattern, as well as to analyze it.


Also note the names have been shortened. There are 3 functions which may be called:


1. Mod.transpose(pattern, nt) to get pattern with has been transposed in pitch by interval nt.


2. Mod.reverse(pattern) to get pattern with reverse order.


3. Mod.duration(pattern) to get total length in whole notes of a pattern.


package jfugue32;

import org.jfugue.pattern.Pattern;
import org.jfugue.pattern.Token;
import org.jfugue.theory.Note;

class Mod {
    
    public static Pattern transpose(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 ntStr, int flg, int nt) {
        Note note = new Note(ntStr);
        byte value = note.changeValue(nt).getValue();
        String tone = Note.getToneString(value);
        if (flg == 0) return tone;
        else {
            String dur = Note.getDurationString(note.getDuration());
            String vel = note.getVelocityString();
            return tone + dur + vel;
        }
    }
    
    public static Pattern reverse(Pattern pattern) {
        Pattern transpose = new Pattern();
        for (Token token: pattern.getTokens()) 
            transpose.prepend(token);
        return transpose;
    }
    
    public static double duration(Pattern pattern) {
        double dur = 0.0;
        for (Token token: pattern.getTokens()) {
            String val = token.toString();
            if (token.getType() == Token.TokenType.NOTE) {
                if (val.contains("+")) {
                    Note n = new Note(val.replaceAll(".+[+]", ""));
                    dur += n.getDuration();
                } else {
                    Note n = new Note(val);
                    dur += n.getDuration();
                }
            }
        }
        return dur;
    }
}

In this canon, an 8-note pattern, of 2 whole note duration, is added to its reverse and then repeated for 5 more times. The duration of the reverse to total pattern is 1 to 12 as shown in the output.


package jfugue32;

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 JFugue32 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 J.S.\nBach's Canon\nNo. 1");
                
        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 32. J.S. Bach's Canon No. 1"
                + " Goldberg Ground (BWV1087)");
        
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    private void example() {
        
        Player player = new Player();
        
        Pattern pattern = new Pattern();
        pattern.add("G4q F4q E4q D3q B3q C4q D4q G3q");
        
        Pattern patternReverse = new Pattern();
        patternReverse.add(Mod.reverse(pattern));
        
        pattern.add(patternReverse).repeat(6).setTempo(100);
 
        text.appendText("\n\nPattern:\n" + pattern + "\n");
        
        text.appendText("\nDuration of pattern: " + 
                Mod.duration(pattern));
        text.appendText("\nDuration of patternReverse: " + 
                Mod.duration(patternReverse));
        
        player.play(pattern);
        
    }
}

This is the output:


No comments:

Post a Comment