jm.music.data.Score Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jmusic Show documentation
Show all versions of jmusic Show documentation
JMusic - Java Music Library
The newest version!
/*
Copyright (C) 2000 Andrew Sorensen, Andrew Brown, Adam Kirby
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or any
later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package jm.music.data;
import jm.JMC;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.Vector;
/**
* The Score class is used to hold score data. Score data includes
* is primarily made up of a vector of Part objects. Commonly score
* data is algorithmically generated or read from a standard MIDI file, but can also be read and saved to
* file using Java's object serialization. In this way a Score's data can
* be saved in a more native context.
* To find out how to read from and write to standard MIDI files
* or to use object serializationcheck out
* the jm.util.Read and km.util.Write classes.
*
* @author Andrew Sorensen, Andrew Brown, Adam Kirby
* @version 1.0, Sun Feb 25 18:43:33 2001
* @see Part
* @see jm.midi.SMF
*/
public class Score implements JMC, Cloneable, Serializable {
//----------------------------------------------
// Defaults
//----------------------------------------------
public static final String DEFAULT_TITLE = "Untitled Score";
public static final double DEFAULT_TEMPO = 60.0;
public static final int DEFAULT_KEY_SIGNATURE = 0;
public static final int DEFAULT_KEY_QUALITY = 0;
public static final int DEFAULT_NUMERATOR = 4;
public static final int DEFAULT_DENOMINATOR = 4;
//----------------------------------------------
// Attributes
//----------------------------------------------
/**
* the name assigned to a Score
*/
private String title = "Unnamed Score";
/**
* a Vector containing the Part objects associated with this score
*/
private Vector partList;
/**
* the speed for this score
*/
private double tempo;
// Possible Alternative:
// Consider using the jm.music.data.KeySignature class and modifying
// it to support the keyQuality field.
/**
* the number of accidentals this score
* negative numbers are Flats, positive numbers are Sharps
*/
private int keySignature;
/**
* 0 = major, 1 = minor, others modes not specified
*/
private int keyQuality;
// Possible Alternative:
// Consider making a TimeSignature class, containing the following
// two fields.
/**
* the top number of the time signature
*/
private int numerator;
/**
* the bottom number of the time signature
*/
private int denominator;
//----------------------------------------------
// Constructors
//----------------------------------------------
/**
* Constructs an empty score with a default name
*/
public Score() {
this(DEFAULT_TITLE);
}
/**
* Constructs an empty score.
*
* @param title Give the score a name
*/
public Score(String title) {
this(title, DEFAULT_TEMPO);
}
/**
* Constructs an empty score at the specified tempo
*
* @param tempo The speed for this score in beats per minute
*/
public Score(double tempo) {
this(DEFAULT_TITLE, tempo);
}
/**
* Constructs an empty score.
*
* @param title Give the score a name
* @param tempo Define speed of playback in bpm
*/
public Score(String title, double tempo) {
this.title = title;
this.tempo = tempo;
this.partList = new Vector();
this.keySignature = DEFAULT_KEY_SIGNATURE;
this.keyQuality = DEFAULT_KEY_QUALITY;
this.numerator = DEFAULT_NUMERATOR;
this.denominator = DEFAULT_DENOMINATOR;
}
/**
* Constructs a Score containing the specified part
.
*
* @param Part to be contained in the Score
*/
public Score(Part part) {
this();
if (part.getTempo() > 0) {
this.tempo = part.getTempo();
} else this.tempo = tempo;
this.addPart(part);
}
/**
* Constructs a Score containing the specified part
.
*
* @param title Give the score a name
* @param tempo Define speed of playback in bpm
* @param part The Part to be contained in the Score
*/
public Score(String title, double tempo, Part part) {
this(title, tempo);
this.addPart(part);
}
/**
* Constructs a Score containing the specified parts
.
*
* @param parts - array of Parts to be contained in the Score
*/
public Score(Part[] parts) {
this();
addPartList(parts);
}
/**
* Constructs a Score containing the specified part
with
* the specified title
.
*
* @param part Part to be contained in the Score
* @param title String describing the title of the Score
*/
public Score(Part part, String title) {
this(title, part.getTempo());
addPart(part);
}
/**
* Constructs a Score containing the specified parts
with
* the specified title
.
*
* @param parts Array of Parts to be contained in the Score
* @param title String describing the title of the Score
*/
public Score(Part[] parts, String title) {
this(title);
addPartList(parts);
}
/**
* Constructs a Score containing the specified part
with
* the specified title
and the specified tempo
.
*
* @param part Part to be contained in the Score
* @param title String describing the title of the Score
* @param tempo A double describing the tempo of the Score
*/
public Score(Part part, String title, double tempo) {
this(title, tempo);
addPart(part);
}
/**
* Constructs a Score containing the specified parts
with
* the specified title
and the specified tempo
.
*
* @param parts array of Parts to be contained in the Score
* @param title String describing the title of the Score
* @param tempo double describing the tempo of the Score
*/
public Score(Part[] parts, String title, double tempo) {
this(title, tempo);
addPartList(parts);
}
//----------------------------------------------
// Data Methods
//----------------------------------------------
/**
* Add a Track object to this Score
*/
public void add(Part part) {
this.addPart(part);
}
/**
* Add a Track object to this Score
*/
public void addPart(Part part) {
part.setMyScore(this);
this.partList.addElement(part);
}
/**
* Inserts part
at the specified position, shifting all parts
* with indices greater than or equal to index
up one position.
*
* @param part Part to be added
* @param index where it is to be inserted
* @throws ArrayIndexOutOfBoundsException when index
is beyond the range of current
* parts.
*/
public void insertPart(Part part, int index)
throws ArrayIndexOutOfBoundsException {
this.partList.insertElementAt(part, index);
part.setMyScore(this);
}
/**
* Adds multiple parts to the score from an array of parts
*
* @param partArray
*/
public void addPartList(Part[] partArray) {
for (int i = 0; i < partArray.length; i++) {
this.addPart(partArray[i]);
}
}
/**
* Deletes the specified Part in the Score
*
* @param int partNumb the index of the part to be deleted
*/
public void removePart(int partNumb) {
Vector vct = (Vector) this.partList;
try {
vct.removeElement(vct.elementAt(partNumb));
} catch (RuntimeException re) {
System.err.println("The Part index to be deleted must be within the score.");
}
}
/**
* Deletes the first occurence of the specified part in the Score.
*
* @param part the Part object to be deleted.
*/
public void removePart(Part part) {
this.partList.removeElement(part);
}
/**
* Deletes the last Part added to the Score
*/
public void removeLastPart() {
Vector vct = (Vector) this.partList;
vct.removeElement(vct.lastElement());
}
/**
* Deletes all the parts previously added to the score
*/
public void removeAllParts() {
this.partList.removeAllElements();
}
/**
* Returns the Scores List of Tracks
*/
public Vector getPartList() {
return partList;
}
/**
* Returns the all Parts in this Score as a array
*
* @return Part[] An array containing all Part objects in this score
*/
public Part[] getPartArray() {
Vector vct = (Vector) this.partList.clone();
Part[] partArray = new Part[vct.size()];
for (int i = 0; i < partArray.length; i++) {
partArray[i] = (Part) vct.elementAt(i);
}
return partArray;
}
/**
* Get an individual Track object from its title
*
* @param String title - the name of the Track to return
* @return Track answer - the Track to return
*/
public Part getPart(String title) {
Enumeration enum1 = partList.elements();
while (enum1.hasMoreElements()) {
Part part = (Part) enum1.nextElement();
if (part.getTitle().equalsIgnoreCase(title)) {
return part;
}
}
return null;
}
/**
* Get an individual Track object from its number
*
* @param int number - the number of the Track to return
* @return Track answer - the Track to return
*/
public Part getPart(int number) {
Enumeration enum1 = partList.elements();
int counter = 0;
while (enum1.hasMoreElements()) {
Part part = (Part) enum1.nextElement();
if (counter == number) {
return part;
}
counter++;
}
return null;
}
//----------------------------------------------
// Utility Methods
//----------------------------------------------
/**
* Return the title of this Score
*
* @return String title - the name of this Score
*/
public String getTitle() {
return title;
}
/**
* Assign a title to this Score
*
* @param String title - the name of this Score
*/
public void setTitle(String title) {
this.title = title;
}
/**
* Returns the Score's tempo
*
* @return double tempo
*/
public double getTempo() {
return this.tempo;
}
/**
* Sets the Score's tempo
*
* @param double tempo
*/
public void setTempo(double tempo) {
this.tempo = tempo;
}
/**
* '
* Returns the Score's key signature
* The number of sharps (+) or flats (-)
*
* @return int key signature
*/
public int getKeySignature() {
return this.keySignature;
}
/**
* Specifies the Score's key signature
* The number of sharps (+) or flats (-)
*
* @param int key signature
*/
public void setKeySignature(int newSig) {
this.keySignature = newSig;
}
/**
* Returns the Score's key quality
* 0 is Major, 1 is minor
*
* @return int key quality
*/
public int getKeyQuality() {
return this.keyQuality;
}
/**
* Specifies the Score's key quality
* 0 is Major, 1 is minor
*
* @param int key quality (modality)
*/
public void setKeyQuality(int newQual) {
this.keyQuality = newQual;
}
/**
* Specifies the Score's time signature
*
* @param num - Time signature numerator
* @param dem - Time signature denominator
*/
public void setTimeSignature(int num, int dem) {
this.numerator = num;
this.denominator = dem;
}
/**
* Returns the Score's time signature elements.
*
* @return Point The Time Signature elements packaged together with the
* numerator as'x' and denominator as 'y'. You may prefer to use the
* getNumerator and getDenomintor methods directly, rather than use
* this convenience method which requires importing the java.awt package
* to extract the elements : )
*/
public java.awt.Point getTimeSignature() {
return new java.awt.Point(this.numerator, this.denominator);
}
/**
* Retrieves the numerator element of the Score's time signature.
*
* @return num - Time signature numerator
*/
public int getNumerator() {
return this.numerator;
}
/**
* Specifies the Score's time signature numerator
*
* @param int time signature numerator
*/
public void setNumerator(int num) {
this.numerator = num;
}
/**
* Retrieves the denominator element of the Score's time signature.
*
* @return int Time signature denominator
*/
public int getDenominator() {
return this.denominator;
}
/**
* Specifies the Score's time signature denominator
*
* @param int time signature denominator
*/
public void setDenominator(int dem) {
this.denominator = dem;
}
/**
* Make a copy of this Score object
*
* @return Score - return a new Score Object
*/
public Score copy() {
Score newScore = new Score(title + " copy");
newScore.setTempo(this.tempo);
newScore.setTimeSignature(this.numerator, this.denominator);
Enumeration enum1 = this.partList.elements();
while (enum1.hasMoreElements()) {
Part oldPart = (Part) enum1.nextElement();
newScore.addPart((Part) oldPart.copy());
}
return (Score) newScore;
}
public Score copy(final double startTime, final double endTime) {
Score score = this.copy();
score.removeAllParts();
score.setTempo(this.tempo);
score.setTimeSignature(this.numerator, this.denominator);
int scoresize = this.size();
for (int i = 0; i < scoresize; i++) {
score.addPart(this.getPart(i).copy(startTime, endTime));
}
return score;
}
/**
* Return the beat where score ends. Where it's last Part ends.
*
* @return double the Parts endTime
*/
public double getEndTime() {
double endTime = 0.0;
Enumeration enum1 = this.partList.elements();
while (enum1.hasMoreElements()) {
Part nextPart = (Part) enum1.nextElement();
double partEnd = nextPart.getEndTime();
if (partEnd > endTime) endTime = partEnd;
}
return endTime;
}
/**
* Print the titles of all tracks to stdout
*/
public String toString() {
String scoreData = new String("***** jMusic SCORE: '" + title +
"' contains " + this.size() + " parts. ****" + '\n');
scoreData += "Score Tempo = " + this.tempo + " bpm" + '\n';
Enumeration enum1 = partList.elements();
while (enum1.hasMoreElements()) {
Part part = (Part) enum1.nextElement();
scoreData = scoreData + part.toString() + '\n';
}
return scoreData;
}
/**
* Empty removes all elements in the vector
*/
public void empty() {
this.empty(false);
}
/**
* Empty removes all elements in the vector.
*
* @param nullObjects If ture this sets all jMusic data objects to null
* priot to removing. This facilitates garbage collection.
*/
public void empty(boolean nullObjects) {
if (nullObjects) {
Enumeration enum1 = getPartList().elements();
while (enum1.hasMoreElements()) {
Part part = (Part) enum1.nextElement();
Enumeration enum2 = part.getPhraseList().elements();
while (enum2.hasMoreElements()) {
Phrase phrase = (Phrase) enum2.nextElement();
Enumeration enum3 = part.getPhraseList().elements();
while (enum3.hasMoreElements()) {
Note note = (Note) enum3.nextElement();
note = null;
}
phrase = null;
}
part = null;
}
}
partList.removeAllElements();
}
/**
* Get the number of Parts in this score
*
* @return int The number of parts
*/
public int length() {
return size();
}
/**
* Get the number of Parts in this score
*
* @return int length - the number of parts
*/
public int size() {
return (partList.size());
}
/**
* Get the number of Parts in this score
*
* @return int length - the number of parts
*/
public int getSize() {
return (partList.size());
}
/**
* Remove any empty Parts or phrases from the Score.
*/
public void clean() {
Enumeration enum1 = getPartList().elements();
while (enum1.hasMoreElements()) {
Part part = (Part) enum1.nextElement();
// pass on the part to have phases cleaned
part.clean();
// check if part is empty
if (part.getPhraseList().size() == 0) {
this.removePart(part);
}
}
}
/**
* Return the value of the highest note in the Score.
*/
public int getHighestPitch() {
int max = 0;
Enumeration enum1 = getPartList().elements();
while (enum1.hasMoreElements()) {
Part part = (Part) enum1.nextElement();
if (part.getHighestPitch() > max) max = part.getHighestPitch();
}
return max;
}
/**
* Return the value of the lowest note in the Score.
*/
public int getLowestPitch() {
int min = 127;
Enumeration enum1 = getPartList().elements();
while (enum1.hasMoreElements()) {
Part part = (Part) enum1.nextElement();
if (part.getLowestPitch() < min) min = part.getLowestPitch();
}
return min;
}
/**
* Return the value of the longest rhythm value in the Score.
*/
public double getLongestRhythmValue() {
double max = 0.0;
Enumeration enum1 = getPartList().elements();
while (enum1.hasMoreElements()) {
Part part = (Part) enum1.nextElement();
if (part.getLongestRhythmValue() > max) max = part.getLongestRhythmValue();
}
return max;
}
/**
* Return the value of the shortest rhythm value in the Score.
*/
public double getShortestRhythmValue() {
double min = 1000.0;
Enumeration enum1 = getPartList().elements();
while (enum1.hasMoreElements()) {
Part part = (Part) enum1.nextElement();
if (part.getShortestRhythmValue() < min) min = part.getShortestRhythmValue();
}
return min;
}
/**
* Determine the pan position for all notes in this Score.
*
* @param double the phrase's pan setting
*/
public void setPan(double pan) {
Enumeration enum1 = partList.elements();
while (enum1.hasMoreElements()) {
Part part = (Part) enum1.nextElement();
part.setPan(pan);
}
}
/**
* Generates and returns a new empty part
* and adds it to the score.
*/
public Part createPart() {
Part p = new Part();
this.addPart(p);
return p;
}
}