| COMP 310/510 
		 Fall 2013
 | HW06:  ABC Music 
		Player | 
	
		|              | 
ABC Music Files
An abc music file is a text based transcription of a musical score.  The 
abc music notation is relatively simple, enabling anyone to transcribe music 
into a text file which can be parsed and played by a variety of open source 
software.  There are many pieces of music that have been transcribed into 
abc notation.  You can find out more about abc notation and find many 
simple tunes here.  For this 
assignment, we will deal with a subset of abc music notation.
ABC music files consist of headers and notes.  You will only need to 
handle files that have headers first and then music. You do not need to handle 
headers that are interspersed within notes.  Furthermore, you will not need 
to handle music that has repeats in it. The provided parser ignores repeat 
symbols, so you only need to play the notes once, even if the score says a 
particular phrase should be repeated.
Resources:
 
Music Basics
For this assignment, you will need to learn a little bit about music if you 
do not already know it.  This assignment is about programming using the 
visitor design pattern, not about music.  But you must be at least 
passingly familiar with terms like "tempo", "key signature", "sharp", "quarter 
note", and the like.  Below are a few tutorials.  You can and should 
also discuss anything that is confusing with the staff.  Please don't 
struggle over musical jargon or concepts - ask for help!  Also, Google is 
your friend, use it!
You do not need to read the above sites from start to finish in order to do 
this assignment.  Skim parts of them 
quickly if you feel like you don't know anything about music and refer back to 
them as you do the assignment if you find them helpful.
The Assignment
In this assignment, you will implement visitors to print and play parsed abc 
music files.  We will provide you with a parser for that subset that reads 
abc music files and gives them to you in a data structure that you can work 
with.
Parsed Music
The parser returns the music in the following data structure 
(click here for docs):

As the UML diagram shows, all of the elements of the abc file will be parsed 
into IPhrase elements.  The parsed file will 
therefore yield a single IPhrase object, which you 
can then perform operations on.  Each "phrase" consists of either a header 
element, a sequence of phrases, a collection of notes, or a note:
	- Header: the headers of the abc file are 
	parsed into header objects. There are many headers that provide information 
	(such as the composer's name) that you can ignore when playing back music. 
	The three main headers of interest in playing back music are:
		- L: this header specifies the default length of a note in the file
- K: this header specifies the key signature for the music
- Q: this header specifies the tempo for the piece
 
- NESeqList, MTSeqList: 
	most everything within a phrase is stored inside a sequence list. This is 
	implemented as a standard object-oriented list structure that holds
	IPhrase elements.  These lists can be 
	therefore nested to arbitrary depths (i.e., you can have a list of 
	lists of lists).
- NoteCollection: grouped notes (representing 
	chords or triplets) are stored in NoteCollection 
	objects. The notes in a chord must all be played at the same time.  The 
	duration of each note in a triplet must be scaled by 2/3.
- Note: a Note is 
	the fundamental unit of music.  Within a phrase, groups of notes are 
	contained within collections and sequences to form a piece of music.
Playing Music in Java
We will be using 
MIDI to play music.  MIDI is a somewhat dated standard 
that allows you to play notes using computer generated instrument sounds. Most 
music these days is sampled, but that is slightly harder to deal with for our 
purposes when generating simple music from a score.
The Java MIDI library uses ticks to indicate time.  You specify the 
number of ticks in a quarter note and all note durations are then specified in 
ticks.  A typical number of ticks per quarter note is 16, enabling you to 
play notes are short as 64th notes (which would then be 1 tick long).  Internally, all notes begin 
and end on a timer tick.  The Java MIDI library (and/or your sound card) 
provides a set of instruments that you can use to play your music.  You 
select a particular instrument and notes are played in such a way as to 
(loosely) mimic that instrument.
To simplify the process, we have provided a 
SequencePlayer class.  The following are the important methods of 
the class:
	- Constructor: the constructor takes the number of ticks you want per 
	quarter note and the instrument you want to use.  You can find out the 
	available instruments by calling the getInstruments 
	method which returns a String.  Instruments 
	are specified as a number between 0 and 127. 
	getInstruments shows the mapping from numbers to instruments, one per 
	line.  There is also an init method (which 
	is called by the constructor) that takes the same arguments.  You can 
	reinitialize the sequence player as often as you like by calling the
	init method.
- addNote: the addNote 
	method takes a Note and a starting tick.  
	The note is scheduled to be played at that tick.  The method returns 
	the tick at which the note will stop playing (which you can then use to 
	schedule the next subsequent note).   What does this say about 
	the input parameter and the return value of a visitor to process an 
	IPhrase?
- play: when you have finished scheduling 
	notes to be played using the addNote method, you 
	can call the play method to actually play the 
	music.  The music is played asynchronously, so this method will return 
	immediately. When the music is done playing, it will print "Finished 
	playing" to the console and close all MIDI resources.
- close: you can stop the music at any time by 
	calling the close method.
- There are also getter and setter methods to read and update the tempo 
	and the number of ticks in a "default note". abc files use the notion of a 
	default note length. The Note class specifies 
	the duration of a note in terms of this default (a length of 1.0 means to use 
	the default).  The tempo and ticks per default note must be udpated 
	from the headers of the abc file.  In case the music does not specify 
	these (some abc files do not specify a tempo, for instance), you should 
	initialize the default note length and the tempo to something you find 
	reasonable before processing any music.  If you then process an L 
	(default note) or Q (tempo) header, you would then update these values 
	appropriately.
The sequence player does not currently allow you to change the tempo in the 
middle of the piece. The player uses the last tempo that was set before the
play method is invoked to play back the entire 
piece.
Processing Music
For this assignment, you will be writing two visitors to process the parsed 
music.  You will be using Dr. Wong's extended visitor design pattern 
implementation, whose code will be supplied.
Read the extended visitor documentation 
here. 
UML Diagram of the Extended Visitor Design Pattern 
Implementation

The two visitors you must write will do the following:
	- Convert the entire piece of music into a String 
	so that you can print it.
- Enqueue the entire peice to be played using the provided
	SequencePlayer class and its
	addNote method.
You should perform these tasks in order.  The first visitor is a 
relatively straightforward traversal of the sequence lists and will allow you to 
see and get used to the structure of the parsed music.  The second visitor 
is more complex as it requires you to install many extended visitor commands and 
properly deal with the musical structure.
We have provided several classes to make your task easier:
	- ABCParser: this class is will parse an abc 
	file into an IPhrase data structure.
- SequencePlayer: this class is a wrapper to 
	access MIDI sound in Java.  It enables you to add a sequence of notes 
	to a MIDI track and then play it when you are through.
		- Code notes:
			- The play() method of
			SequencePlayer has been modified to take 
			an input parameter of type 
			ISequencePlayerStatus (a new provided interface).  This 
			enhancement will enable you to know when a track has finished 
			playing nomrally as the 
			ISequencePlayerStatus.finished() method will be called at 
			that time.
			
				- A null object instance, 
				ISequencePlayerStatus.NULL, has been provided that simply 
				prints a message to the console.
 
- An enhanced player, SequencePlayer2, 
			has been provided that can be used instead of the old
			SequencePlayer if desired.  In this 
			player, the play() or
			stop() methods have been replaced with a 
			factory method, makePlayable(), that 
			creates SequencePlayer2.IPlayable 
			objects that are self-contained musics players that can be 
			separately started and stopped.
			
				- This new player enables you to load and parse songs but not 
				play them right away and thus create multi-part harmonies from 
				multiple songs, e.g. rondos.    The individual 
				songs (IPlayable objects) can be 
				started and stopped individually at will. 
- This new player can thus be used to solve the "bug" in the 
				demo application where multiple songs could be played at once 
				but only the last song could be stopped.
 
 
 
- ABCUtil: this class has several static 
	methods that will enable you to parse things a little easier.
		- parseFraction can be used to convert the 
		default note length from a String to a
		double.
- parseTempo can be used to convert the 
		tempo from a String to a
		double.  With the help of the 
		defaultNotesPerQuarter note value, it will 
		convert the default notes per minute specified by the L header into the 
		quarter notes per minute (beats per minute) needed by
		SequencePlayer.setTempo().
- getFileContents can be used to return 
		the contents of a file as a String.
 
- KeySignature: this class keeps track of 
	which notes are sharp/flat for the particular key signature you are using.  
	The adjust method returns a note whose pitch has 
	been properly adjusted for the given key signature.
Your final program 
	should always enqueue notes only after they have been adjusted for the key 
	signature of the piece (simply via a call to KeySignature.adjust on a properly initialized 
KeySignature object).  While you are initially 
developing and debugging your program, if you only play music that is in the key 
of C, you can ignore the key signature (as no notes need to be adjusted in that 
key).
Be sure to call the SequencePlayer's 
init() method beforeprocessing a song or you may hear the previous song 
as well.   The init method will clear out 
any old music in the sequencer.
 
GUI
You may make your GUI operate however you think is appropriate.  
However, you must be able to load, parse, play, and stop abc music files.  
You must also display the currently loaded file and use the toString method to 
display the music after it is parsed.
The demo GUI makes use of a JSplitPane component.  
Each pane then has a JScrollPane which contains a
JTextArea.  However, you may organize things 
differently if you prefer.
If you want the text to wrap inside of the text area, look at the
setLineWrap and 
setWrapStyleWord methods.
Assignment Notes
You should implement a very simple GUI that enables you to parse files, print 
them (using your toString visitor), and play them (using your player visitor). 
You should also add whatever debugging support you desire to your GUI.
In this program, the model is relatively simple, and contains only a few 
things (including a parser, a phrase, and a player).  Similarly, the view is 
also relatively simple.  But, you should still properly use the MVC 
architecture.
We recommend approaching the assignment as follows:
	- Implement the basic GUI and your MVC architecture.  As you work on 
	the following steps, it will be easier if you can easily display your 
	results in the GUI.
- Implement the toString visitor first.   
	Look at the code for the toString() methods of
	MTSeqList and NESeqList 
	and you will see that those two methods comprise the two cases of the main 
	(outer) algorithm of a forward accumulation algorithm to generate a string 
	representation of the list.  What is missing is the recursive forward 
	accumulating helper (inner) algorithm.   A handy,
	setToStringAlgo method is provided in
	NESeqList that enables you to write that helper 
	algorithm and install it into NESeqList.  
	(Why doesn't MTSeqList need this?)
		- Basic extended visitor construction technique:
			- Instantiate the visitor itself using an anonymous inner class, 
			specifying a default case command to the superclass constructor, if 
			needed. (see  the
			
			Anonymous Inner Class Techniques page to see how to do this).
- Instantiate the visitor's commands using anonymous inner 
			classes.   Do this either externally to the visitor or 
			inside the visitor's initialization block (see  the
			
			Anonymous Inner Class Techniques page to see how to do this).    
			In either case,  the commands will close over the visitor 
			itself.   If you are using a local variable for the 
			visitor, the Java compiler may complain that the variable may not be 
			initialized if you try to access it.   To solve this 
			problem, use the technique detailed in in the 
			Accessing Enclosing Anonymous Inner Classes section of the Anonymous 
			Inner Class Techniques page..   
			
- Note: you will need to downcast 
			the host to the sub-type that the command is designed for.  
			
- Add the commands to the visitor with their associated ID values.   
			How can you get multiple hosts to have the same processing without 
			duplicating code? 
 
- Only the helper algorithm is required for 
		this assignment.   However, one should note that the 
		entire toString process is technically an external algorithm to the
		ISeqList and thus could be written as a 
		visitor.    It is highly suggested that you attempt to 
		take the code from the toString() methods of 
		the empty and non-empty lists and adapt them into a fully external
		ToStringAlgo (that utilizes your helper 
		algo) that when executed, will return the string representation of the 
		list. 
- The toStringAglo anonymous inner class (APhraseVisitor 
		subclass) only requires two commands: one for an NESeqList and one for an 
		MTSeqList.  
	All other classes have already been supplied with a properly working
		toString method which these commands will 
		use.  This will refresh your memory on how visitors work and will 
		introduce you to the extended visitor code.
 
- Create an IPhrase object that consists of a 
	single note.  Create a visitor with a command for 
	Note hosts and make sure you can play a single note.  You will 
	need to initialize a SequencePlayer object with 
	some defaults for this to work.  (This was the exercise from
	Lab07.)  Think about what parameters need 
	to be passed to the Note's visitor in order to use the 
	SequencePlayer and the return value of that 
	visitor. 
- Once you can play a Note, add support to 
	play a single Chord or 
	Triplet.
- Create an IPhrase object that is a sequence 
	of notes (ISeqList). Add commands to your visitor to handle sequences and make sure you 
	can play them properly.  
- Finally, add support in your visitor for Header 
	objects. If you are adventurous, try to play a parsed abc file. Otherwise, 
	construct your own IPhrase object that has a 
	sequence that contains a sequence of headers and a sequence of notes. Try to 
	play that musical phrase first.
- There are a lot of classes in the IPhrase 
	hierarchy.   Of these classes, how many of them are 
	distinct extended visitor hosts?  Is it necessary to 
	install commands to handle all of those classes?   Can a 
	visitor even tell if certain classes are serving as its host?  Why? 
- Anonymous inner classes are crucial for this assignment.   To 
	learn about how to do complex initializations of an anonymous inner class, 
	see the 
	Anonymous Inner Class Techniques page in the Java Resources site.  
	Especially pay attention to the discussion on "initialization blocks" 
	and on "Accessing Enclosing Anonymous Inner Classes".
- In order to properly play abc files, you will need to install commands 
	to deal with headers you do not care about.  Consider the following 
	code for that purpose:
String headerString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (int i = 0; i < headerString.length(); i++) {
     myVisitor.addCmd("" + headerString.charAt(i), defaultHeaderCmd);
}
You should install commands for the headers you care about 
after you do this, so that those commands will replace the default command being 
used for a header with an arbitrary letter identifier.
- Tuplets are very difficult to describe concisely, requiring fairly advanced 
musical knowledge.  In such, Tuplets should be treated as an 
unknown host type.  If you think that you can write a reasonable 
tuplet handler, document your work carefully, let the staff know that you are 
attempting this and be sure that you include test songs for it.  You might 
be rewarded with some extra credit points!
Weird Potential Java MIDI bug: 
If your program sounds as if it plays the first note 
of a musical piece twice, try starting adding the notes to the
SequencePlayer starting at tick #1 rather than at 
tick #0.
Another Weird Potential Java MIDI bug: 
Windows users may encounter an error that says that 
there is a "WindowsPreferences" error that cannot 
make a "prefs root node".    Please 
see the discussion below.
Provided Code
The provided code is available via subversion.  You 
should follow the directions to acquire the provided code 
and keep it up to date.  All of the provided code will be contained 
within a package called provided.  Do not 
modify, remove, or add anything in the provided 
package.
Library documentation
Sample ABC music files:   You can 
access several sample abc music files at
https://svn.rice.edu/r/comp310/course/HW06/songs.  You can access these 
files directly via that URL or add them to your project in the same way you 
added the provided package (the 
svn:externals property can have multiple lines, one per external 
repository).
But 
don't limit yourself to your instructors' boring musical tastes, go find your 
own files or make your own music!    If you have problems playing 
a particular file, let the staff know right away to make sure that there isn't a 
problem in the libraries or that the file is using an unsupported feature.
Assignment requirements:
	- All code must be properly commented. This, as always, includes UML 
	diagrams of your system. (10 pts)
- The GUI should support all of the required operations, be intuitive to 
	use, and all buttons should contain tool tips. (10 pts)
- MVC architecture (5 pts)
- You must write an extended visitor to implement 
	toString for music sequence lists.  (15 pts)
- You must write an extended visitor to traverse an 
	IPhrase object and add the appropriate notes to the sequence player 
	so that the music may be played.  Required features (60 pts total): 
		- Key signatures ("K" header) (5 pts)
- Tempo ("Q" header) (5 pts)
- Default note ("L" header)  (5 pts)
- Ignored headers (5 pts)
- Individual notes  (10 pts)
- Chords (5 pts)
- Triplets (5 pts)
- Non-empty sequence list  (10 pts)
- Empty sequence list (end of song)  (5 pts)
- Unknown host   (5 pts)
 
You are NOT required to handle mutiple instrument choices as 
the demo does, though it would be more fun if you did.  ;-)
 
WindowsPreferences 
Error   (Windows only)
Some people's Windows machines have been displaying the 
following error when they play their phrase sequence:
java.util.prefs.WindowsPreferences 
<init>
WARNING: Could not open/create prefs root node 
Software\JavaSoft\Prefs at root 0x80000002. Windows RegCreateKeyEx(...) returned 
error code 5.
It is not clear whree exactly this comes from but here are some links to 
the issues on the web:
 
© 2013 by Stephen Wong