title: Getting a sequencer to play in JavaSound (Java SE7)
body: <p>This is my first attempt to write a program other than an exercise in a book.  When I'm done, it will be a piano roll editor MIDI sequencer.  The user types in a set of lyrics.  The program converts the words into notes on the piano roll editor which the user can then move around and construct a melody.  I've got the GUI for lyric submission and a basic piano roll panel.  I've got the notes appearing on the panel with the lyrics printed on them.  Now I'm in the phase of trying to construct a sequencer/synth that will play these notes.  The complexity is a bit overwhelming at this point, so I'm trying to take this in baby steps.  I have studied the music beat box in the book Head First Java, and the MIDI chapters in the book Killer Game Programming.  I've been over and over the Java API on JavaSound.  Taking all of this in, I constructed a class containing the sequencer and the synth, and I'm trying to simply create a series of notes and play them (not even worrying about connecting them to the graphical note shapes on the screen).  But nothing is playing yet.  I've got four classes going right now (one for the GUI, one for the piano roll panel, one for the graphical note objects, and one for the music engine).  I'll try to post some of this code below.  If someone can help me figure out why nothing is playing, I'd be grateful.</p>
  
  <p>Here is the music engine class.  Hopefully, I'm posting the code on here correctly:</p>
  
  <pre><code>import javax.sound.midi.*;
  
  public class MusicEngine {
  private Sequencer sequencer;
  private Sequence sequence;
  private Synthesizer synthesizer;
  private Track track;
  MidiEvent event;
  
  // Constructor
  public MusicEngine() {
      createMidi();
  }
  
  // Get sequencer and sequence and track
  public void createMidi() {
      try {
          sequencer =  MidiSystem.getSequencer();
          if (sequencer == null) {
              System.out.println("Cannot get a sequencer");
              System.exit(0);
          }
          sequencer.open();
  
          // If sequencer is not the same as synthesizer, link the two 
          // (required in J2SE 5.0)
          if (!(sequencer instanceof Synthesizer)) {
              System.out.println("Linking the sequencer to the synthesizer");
              synthesizer = MidiSystem.getSynthesizer();
              synthesizer.open();
              Receiver synthReceiver = synthesizer.getReceiver();
              Transmitter seqTransmitter = sequencer.getTransmitter();
              seqTransmitter.setReceiver(synthReceiver);
          } else 
              synthesizer = (Synthesizer)sequencer;
          sequence = new Sequence(Sequence.PPQ, 4);
          track = sequence.createTrack();
          sequencer.setTempoInBPM(120);
      } catch(MidiUnavailableException e) {
          System.out.println("No sequencer available");
          System.exit(0);
      } catch(Exception e) {
          e.printStackTrace();
          System.exit(0);
      }
  
  }
  
  // Create an individual MIDI event
  public MidiEvent createEvent(int command, int channel, int one, int two, int tick) {
      event = null;
      try {
          ShortMessage a = new ShortMessage();
          a.setMessage(command, channel, one, two);
          event = new MidiEvent(a, tick);
      } catch(InvalidMidiDataException e) {
          e.printStackTrace();
      }
      return event;
  }
  
      public void add(MidiEvent event) {
      track.add(event);
  }
  
  public void playSong(int tempo) {
      try {
          sequencer.setSequence(sequence);
      }
      catch (InvalidMidiDataException e) {
          e.printStackTrace();
      }
  
      sequencer.start();
  }
  
  }
  </code></pre>
  
  <p>And here is the piano roll panel that tries to play some notes:</p>
  
  <pre><code>import javax.sound.midi.ShortMessage;
  import javax.swing.*;
  import javax.swing.event.MouseInputAdapter;
  import javax.swing.border.*;
  import java.awt.*;
  import java.awt.event.*;
  import java.util.ArrayList;
  
  public class MelodyPanel extends JPanel {
  private String[] lyricList;
  private ArrayList&lt;MovableNote&gt; noteList = new ArrayList&lt;&gt;();
  private int xCoord = 1;
  private int yCoord = 50;
  private int startX, startY, stopX, stopY, diffX, diffY;
  private int lyricPosition;
  private int noteWidth = 40;
  private static final int DEFAULT_NOTE_HEIGHT = 15;
  private static final int SIXTEENTH_BEAT_WIDTH = 50;
  private MusicEngine musicEngine;
  
  private String[] noteNames = {"C1","C#1/Db1","D1","D#1/Eb1","E1","F1","F#1/Gb1","G1","G#/Ab1","A1","A#1/Bb1","B1",
          "C2","C#2/Db2","D2","D#2/Eb2","E2","F2","F#2/Gb2","G2","G#2/Ab2","A2","A#2/Bb2","B2",
          "C3","C#3/Db3","D3","D#3/Eb3","E3","F3","F#3/Gb3","G3","G#3/Ab3","A3","A#3/Bb3","B3",
          "C4","C#4/Db4","D4","D#4/Eb4","E4","F4","F#4/Gb4","G4","G#4/Ab4","A4","A#4/Bb4","B4",
          "C5","C#5/Db5","D5","D#5/Eb5","E5","F5","F#5/Gb5","G5","G#5/Ab5","A5","A#5/Bb5","B5",
          "C6","C#6/Db6","D6","D#6/Eb6","E6","F6","F#6/Gb6","G6","G#6/Ab6","A6","A#6/Bb6","B6",
          "C7","C#7/Db7","D7","D#7/Eb7","E7","F7","F#7/Gb7","G7","G#7/Ab7","A7","A#7/Bb7","B7"};
  
  // Measure length = default note length x number of beats
  private static final int FOUR_FOUR_MEASURE_LENGTH = SIXTEENTH_BEAT_WIDTH * 16;
  private static final int THREE_FOUR_MEASURE_LENGTH = SIXTEENTH_BEAT_WIDTH * 12;
  private static final int SIX_EIGHT_MEASURE_LENGTH = SIXTEENTH_BEAT_WIDTH * 24;
  
  private Font f = new Font("SansSerif", Font.BOLD, 14);
  private MovableNote mNote;
  private MovableNote selectedNote = null;
  private boolean dragging = false;
  
  // Create an INITIAL MelodyPanel with lyrics, RESET to flatline melody
  public void showMelodyPanel(String[] lyricList) {
      setBackground(Color.BLACK);
      this.lyricList = lyricList;
  
      // Create the MusicEngine sequencer and synth
      musicEngine = new MusicEngine();
  
      // For every syllable in the lyricList, create a MovableNote and put it in the ArrayList
      for (int i = 0; i &lt; lyricList.length; i++) {
          lyricPosition = i;
          mNote = new MovableNote((SIXTEENTH_BEAT_WIDTH * lyricPosition) + 2, DEFAULT_NOTE_HEIGHT * 10, noteWidth, DEFAULT_NOTE_HEIGHT, lyricList[i]);
          noteList.add(mNote);
          // try adding a musical note to the track
          musicEngine.add(musicEngine.createEvent(ShortMessage.NOTE_ON, 0, 60, 100, i * 16));
          musicEngine.add(musicEngine.createEvent(ShortMessage.NOTE_OFF, 0, 60, 100, i * 16 + 4));
      }
  
      // try to play the song
      musicEngine.playSong(120);
  
      // The panel responds when you click on it
      addMouseListener(new NoteListener());
  
      // The panel responds when you drag the mouse on it
      addMouseMotionListener(new NoteListener());
  }
  
  @Override /** Paint the melodyPanel */
  protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      // Draw the note rows, iterating backwards through the noteNames array
      int counter1 = 1;
      int counter2 = 6;
      NoteRow row;
      for (int i = 83; i &gt;= 0; i--) {
          row = new NoteRow(0, i * DEFAULT_NOTE_HEIGHT, SIXTEENTH_BEAT_WIDTH * 16 * lyricList.length, DEFAULT_NOTE_HEIGHT, noteNames[i]);
          row.draw(g);
  
          // Place horizontal lines to separate rows representing adjacent white piano keys
          if (counter1 % 12 == 0 || counter2 % 12 == 0) 
              g.setColor(Color.DARK_GRAY);
              g.drawLine(0, i * DEFAULT_NOTE_HEIGHT, this.getWidth(), i * DEFAULT_NOTE_HEIGHT);
          counter1++;
          counter2++;
      }
  
      // Draw the sixteenth note lines
      for (int i = 0; i &lt; this.getWidth(); i += FOUR_FOUR_MEASURE_LENGTH / 16) {
          g.setColor(new Color(112,128,144));
          g.drawLine(i, 0, i, this.getHeight());
      }
  
      // Draw the eighth note lines
      for (int i = 0; i &lt; this.getWidth(); i += FOUR_FOUR_MEASURE_LENGTH / 8) {
          g.setColor(new Color(95,158,160));
          g.drawLine(i, 0, i, this.getHeight());
      }
  
      // Draw the quarter note lines
      for (int i = 0; i &lt; this.getWidth(); i += FOUR_FOUR_MEASURE_LENGTH / 4) {
          g.setColor(new Color(70,130,180));
          g.drawLine(i, 0, i, this.getHeight());
      }
  
      // Draw the measure lines
      for (int i = 0; i &lt; this.getWidth(); i += FOUR_FOUR_MEASURE_LENGTH) {
          g.setColor(Color.WHITE);
          g.drawLine(i, 0, i, this.getHeight());
      }
  
      // For every MovableNote in the ArrayList draw a note on the MelodyPanel
      for (int i = 0; i &lt; noteList.size(); i++) {
          if (noteList != null) {
              noteList.get(i).draw(g);
  
              // Paint the current syllable or word onto the current note
              g.setColor(Color.BLACK);
              g.setFont(f);
              g.drawString(noteList.get(i).getSyllable(), (int)noteList.get(i).getX() + 2, (int)noteList.get(i).getY() + 13);
  
          } else {
              // Code that informs user they need to submit some lyrics
              // Or something else if the user wishes to not use lyrics
          }
      }
  }
  
  private class NoteListener extends MouseInputAdapter {
  
      @Override
      public void mousePressed(MouseEvent e) {
          startX = e.getX();
          startY = e.getY();
          dragging = true;
          for (MovableNote n: noteList) {
              if (n.isHit(startX, startY)) {
                  if (selectedNote != null) {
                      selectedNote = n;
                      System.out.println("You have selected a note");
                      selectedNote.setNoteColor(Color.BLACK);
                      repaint();
                  } else {
                      selectedNote.setNoteColor(Color.YELLOW);
                      repaint();
                      selectedNote = null;
                  }
              }
          }
          testPress(e.getX(), e.getY());
      }
  
      @Override public void mouseReleased(MouseEvent e) {
          dragging = false;
      }
  
      @Override
      public void mouseDragged(MouseEvent e) {
          stopX = e.getX();
          stopY = e.getY();
  
          for (MovableNote n: noteList) {
              if (n.isHit(e.getX(), e.getY())) {
                  System.out.println("You tried to drag a note");
                  diffX = stopX - startX;
                  diffY = stopY - startY;
                  n.translate(diffX, diffY);
                  repaint();
              }
          }
  
          // code to reset the the old x, y values
          startX += diffX;
          startY += diffY;
  
          testDrag(e.getX(), e.getY());
      }
  
  }
  
  // When mouse is pressed on panel, a note is created without any connection to a lyric
  private void testPress(int x, int y) {
      // Test to see if mouse listener works
      System.out.println("The mouse was clicked on coordinates " + x + ", " + y);
  }
  
  // When mouse drags a note, the note moves
  private void testDrag(int x, int y) {
      // Test to see if mouse listener works
      System.out.println("The mouse dragged to this location: " + x + ", " + y);
  }
  
  // Individual row that represents a single pitch horizontally
  private class NoteRow extends Rectangle {
      Color color = (Color.GRAY);
      private String pitch;
  
      // Constructor
      public NoteRow(int x, int y, int width, int height, String pitch) {
          super(x, y, width, height);
          this.x = x;
          this.y = y;
          this.width = width;
          this.height = height;
          this.pitch = pitch;
  
          // Set color of the row according to if it's a black keyboard key or a white keyboard key
          if (pitch.startsWith("C#") || pitch.startsWith("Db") || pitch.startsWith("D#") || 
                  pitch.startsWith("Eb") || pitch.startsWith("F#") || pitch.startsWith("Gb") || pitch.startsWith("G#") || 
                  pitch.startsWith("Ab") || pitch.startsWith("A#") || pitch.startsWith("Bb")) {
              this.color = (Color.DARK_GRAY);
          } else {
              this.color = (Color.LIGHT_GRAY);
          }
      }
  
      // Method for the note to draw itself
      void draw(Graphics gr) {
          Graphics2D g = (Graphics2D)gr;
          g.setColor(color);
          g.fill(this);
      }
  }
  
  }
  </code></pre>