teaching machines

CS 145 Lecture 38 – Sequencer

December 3, 2014 by . Filed under cs145, fall 2014, lectures.

Agenda

TODO

Compose This

A musician friend asks you to write a sequencer application so that he can walk across campus. Without a steady beat in his ear, his legs don’t move. He’d like to have a graphical user interface that shows a bunch of percussive instruments and lets him choose on which beats a particular instrument plays. Once a measure or two is composed, he’d like to generate an audio file that repeats the sequence many times.

What actors/objects might you call upon to compose this application? What state do they manage? What behaviors are needed for other actors to interact with them? Think of at least 4.

Code

Vector2D.java

package lecture1203;

public class Vector2D {
  private double x;
  private double y;
  
  public static final Vector2D X = new Vector2D(1, 0);
  public static final Vector2D Y = new Vector2D(0, 1);

  
  public Vector2D() {
    x = y = 0.0;
  }
  
  public Vector2D(double x, double y) {
    this.x = x;
    this.y = y;
  }
  
  public double getLength() {
    return Math.hypot(x, y);
  }
  
  public void normalize() {
    double length = getLength();
    x /= length;
    y /= length;
  }
  
  public String toString() {
    return String.format("%f %f -> %f", x, y, getLength());
  }
  
  public static void main(String[] args) {
    Vector2D v = new Vector2D(10, 10);
    v.normalize();
    System.out.println(v);
  }
}

Main.java

package lecture1203;

public class Main {
  public static void main(String[] args) {
    System.out.println(Vector2D.X);
  }
}

Instrument.java

package lecture1203;

public class Instrument {
  private String name;
  private int id;
  
  public Instrument(String name,
                    int id) {
    this.name = name;
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public int getId() {
    return id;
  }
}

Sequencer.java

package lecture1203;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import jm.constants.Durations;
import jm.constants.Pitches;
import jm.music.data.Note;
import jm.music.data.Part;
import jm.music.data.Phrase;
import jm.music.data.Rest;
import jm.music.data.Score;
import jm.music.tools.Mod;
import jm.util.Write;

public class Sequencer extends JFrame {
  private JCheckBox[][] checkboxes;
  private ArrayList<Instrument> instruments;

  public Sequencer(ArrayList<Instrument> instruments,
                   int nBeats) {
    this.instruments = instruments;
    checkboxes = new JCheckBox[instruments.size()][nBeats];
    
    // Layout
    JPanel panel = new JPanel();
    panel.setLayout(new GridLayout(instruments.size(), nBeats + 1));
    
    for (int r = 0; r < instruments.size(); ++r) {
      panel.add(new JLabel(instruments.get(r).getName()));
      for (int c = 0; c < nBeats; ++c) {
        checkboxes[r][c] = new JCheckBox();
        panel.add(checkboxes[r][c]);
      }
    }
    
    add(panel, BorderLayout.CENTER);
    
    JButton button = new JButton("Compose");
    add(button, BorderLayout.SOUTH);
    button.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        Write.midi(compose(), "/Users/johnch/Desktop/foo.midi");
      }
    });
    
    pack();
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setVisible(true);
  }
  
  private Score compose() {
    Score score = new Score("Walking Beat");
    
    for (int r = 0; r < instruments.size(); ++r) {
      Phrase phrase = new Phrase();
      
      // Create phrase.
      for (int c = 0; c < checkboxes[r].length; ++c) {
        if (checkboxes[r][c].isSelected()) {
          phrase.add(new Note(Pitches.A4, Durations.SIXTEENTH_NOTE));
        } else {
          phrase.add(new Rest(Durations.SIXTEENTH_NOTE));
        }
      }
      
      Mod.repeat(phrase, 10);
      
      Part part = new Part(instruments.get(r).getId(), r);
      part.addPhrase(phrase);
      
      score.add(part);
    }
    
    return score;
  }
}

SequencerMain.java

package lecture1203;

import java.util.ArrayList;
import jm.constants.Instruments;

public class SequencerMain {
  public static void main(String[] args) {
    ArrayList<Instrument> instruments = new ArrayList<>();
    
    instruments.add(new Instrument("Cowbell", Instruments.BELL));
    instruments.add(new Instrument("Timpani", Instruments.TIMPANI));
    instruments.add(new Instrument("Bird", Instruments.BIRD));
    
    new Sequencer(instruments, 8);
  }
}

Haiku

on composition:
I’m a bunch of stuff
Liver, feet, lungs, clavicle
I feel like more though