import jm.music.data.*; import jm.JMC; import jm.util.*; import jm.music.tools.*; public class SongNode { /** * the next SongNode in the list */ private SongNode next; /** * the Phrase containing the notes and durations associated with this node */ private Phrase myPhrase; /** * When we make a new element, the next part is empty, and ours is a blank new part */ public SongNode(){ this.next = null; this.myPhrase = new Phrase(); } /** * setPhrase takes a Phrase and makes it the one for this node * @param thisPhrase the phrase for this node */ public void setPhrase(Phrase thisPhrase){ this.myPhrase = thisPhrase; } /** * Creates a link between the current node and the input node * @param nextOne the node to link to */ public void setNext(SongNode nextOne){ this.next = nextOne; } /** * copyNode returns a copy of this node * @return another song node with the same notes */ public SongNode copyNode(){ SongNode returnMe = new SongNode(); returnMe.setPhrase(this.getPhrase()); return returnMe; } /** * Repeat the input phrase for the number of times specified. * But do an insertion, to save the rest of the list. * @param nextOne node to be copied into the list * @param count number of times to copy it in. **/ public void repeatNextInserting(SongNode nextOne, int count){ SongNode current = this; // Start from here SongNode copy; // Where we keep the current copy for (int i=1; i <= count; i++) { copy = nextOne.copyNode(); // Make a copy current.insertAfter(copy); // INSERT after current current = copy; // Now append to copy } } /** * Repeat the input phrase for the number of times specified. * It always appends to the current node, NOT insert. * @param nextOne node to be copied in to list * @param count number of times to copy it in. */ public void repeatNext(SongNode nextOne,int count) { SongNode current = this; // Start from here SongNode copy; // Where we keep the current copy for (int i=1; i <= count; i++) { copy = nextOne.copyNode(); // Make a copy current.setNext(copy); // Set as next current = copy; // Now append to copy } } /** * Insert the input SongNode AFTER this node, * and make whatever node comes NEXT become the next of the input node. * @param nextOne SongNode to insert after this one */ public void insertAfter(SongNode nextOne) { SongNode oldNext = this.next(); // Save its next this.setNext(nextOne); // Insert the copy nextOne.setNext(oldNext); // Make the copy point on to the rest } /** * Weave the input phrase count times every skipAmount nodes * @param nextOne node to be copied into the list * @param count how many times to copy * @param skipAmount how many nodes to skip per weave */ public void weave(SongNode nextOne, int count, int skipAmount) { SongNode current = this; // Start from here SongNode copy; // Where we keep the one to be weaved in SongNode oldNext; // Need this to insert properly int skipped; // Number skipped currently for (int i=1; i <= count; i++) { copy = nextOne.copyNode(); // Make a copy //Skip skipAmount nodes skipped = 1; while ((current.next() != null) && (skipped < skipAmount)) { current = current.next(); skipped++; }; //if (current.next() == null) // Did we actually get to the end early? //break; // Leave the loop oldNext = current.next(); // Save its next current.insertAfter(copy); // Insert the copy after this one current = oldNext; // Continue on with the rest if (current == null) // Did we actually get to the end early? break; // Leave the loop } } /** * Provides public access to the next node. * @return a SongNode instance (or null) */ public SongNode next(){ return this.next; } /** * Accessor for the node's Phrase * @return internal phrase */ private Phrase getPhrase(){ return this.myPhrase; } /** * Accessor for the notes inside the node's phrase * @return array of notes and durations inside the phrase */ private Note [] getNotes(){ return this.myPhrase.getNoteArray(); } /** * Collect all the notes from this node on * in an part (then a score) and open it up for viewing. * @param instrument MIDI instrument (program) to be used in playing this list */ public void showFromMeOn(int instrument){ // Make the Score that we'll assemble the elements into // We'll set it up with a default time signature and tempo we like // (Should probably make it possible to change these -- maybe with inputs?) Score myScore = new Score("My Song"); myScore.setTimeSignature(3,4); myScore.setTempo(120.0); // Make the Part that we'll assemble things into Part myPart = new Part(instrument); // Make a new Phrase that will contain the notes from all the phrases Phrase collector = new Phrase(); // Start from this element (this) SongNode current = this; // While we're not through... while (current != null) { collector.addNoteList(current.getNotes()); // Now, move on to the next element current = current.next(); }; // Now, construct the part and the score. myPart.addPhrase(collector); myScore.addPart(myPart); // At the end, let's see it! View.notate(myScore); } /** * Collect all nodes in this SongPart and return the composite Phrase */ public Phrase collect(){ // Make a new Phrase that will contain the notes from all the phrases Phrase collector = new Phrase(); // Start from this element (this) SongNode current = this; // While we're not through... while (current != null) { collector.addNoteList(current.getNotes()); // Now, move on to the next element current = current.next(); }; return collector; } /** * Collect all the notes from this node on * in an part (then a score) and returns the score * @param instrument MIDI instrument (program) to be used in playing this list * @returns a score with all of the notes placed into it **/ public Score makeMyScore(int instrument){ // Make the Score that we'll assemble the elements into // We'll set it up with a default time signature and tempo we like Score myScore = new Score("My Song"); myScore.setTimeSignature(3,4); myScore.setTempo(120.0); // Make the Part that we'll assemble things into Part myPart = new Part(instrument); // Make a new Phrase that will contain the notes from all the phrases Phrase collector = new Phrase(); // Start from this element (this) SongNode current = this; // While we're not through... while (current != null){ collector.addNoteList(current.getNotes()); // Now, move on to the next element current = current.next(); } // Now, construct the part and the score. myPart.addPhrase(collector); myScore.addPart(myPart); return myScore; } /** * Collect all the notes from this node on * in an part (then a score) and then returns the score. * Written from modified code by Dawn Finney * @param songName name of the Score * @param tempo tempo for the score * @param timeSignatureTop the top part of the time signature * @param timeSignatureBottom the bottom part of the time signature * @param instrument MIDI instrument (program) to be used in playing this list * @returns a score with all of the notes placed into it **/ public Score makeMyScore(String songName, double tempo, int timeSignatureTop, int timeSignatureBottom, int instrument){ // Make the Score that we'll assemble the elements into Score myScore = new Score(songName); //Set the timeSignature according to the inputs myScore.setTimeSignature(timeSignatureTop,timeSignatureBottom); //Set the tempo according the input myScore.setTempo(tempo); // Make the Part that we'll assemble things into Part myPart = new Part(instrument); // Make a new Phrase that will contain the notes from all the phrases Phrase collector = new Phrase(); // Start from this element (this) SongNode current = this; // While we're not through... while (current != null){ collector.addNoteList(current.getNotes()); // Now, move on to the next element current = current.next(); } // Now, construct the part and the score. myPart.addPhrase(collector); myScore.addPart(myPart); return myScore; } /** * Collect all the notes from this node on * in an part (then a score) and play. The * name of the score defaults to "My Song." * The time signature defaults to 3,4. The * tempo dafaults to 120.0. * Written from modified code by Dawn Finney * @param instrument MIDI instrument (program) to be used in playing this list */ public void playFromMeOn(int instrument){ //Create the score Score myScore = makeMyScore(instrument); //Play the score Play.midi(myScore, false); } /** * Collect all the notes from this node on * in an part (then a score) and then play it. * Written from modified code by Dawn Finney * @param songName name of the Score * @param tempo tempo for the score * @param timeSignatureTop the top part of the time signature * @param timeSignatureBottom the bottom part of the time signature * @param instrument MIDI instrument (program) to be used in playing this list */ public void playFromMeOn(String songName, double tempo, int timeSignatureTop, int timeSignatureBottom, int instrument){ //Create the score Score myScore = makeMyScore(songName, tempo, timeSignatureTop, timeSignatureBottom, instrument); //Play the score Play.midi(myScore, false); } /** * Collect all the notes from this node on * in an part (then a score) and plays * blocking all other events so that * only the score plays. After the score * is finished, all other events will resume. * The name of the score defaults to "My Song." * The time signature defaults to 3,4. * The tempo dafaults to 120.0. * Written from modified code by Dawn Finney * @param instrument MIDI instrument (program) to be used in playing this list */ public void blockingPlayFromMeOn(int instrument){ //Create the score Score myScore = makeMyScore(instrument); //Play the score Play.midi(myScore, false); //Pause for the length of the score Play.waitCycle(myScore); } /** * Collect all the notes from this node on * in an part (then a score) and then plays * blocking all other events so that only * the score plays. After the score is finished, * all other events will resume. * Written from modified code by Dawn Finney * @param songName name of the Score * @param tempo tempo for the score * @param timeSignatureTop the top part of the time signature * @param timeSignatureBottom the bottom part of the time signature * @param instrument MIDI instrument (program) to be used in playing this list */ public void blockingPlayFromMeOn(String songName, double tempo, int timeSignatureTop, int timeSignatureBottom, int instrument){ //Create the score Score myScore = makeMyScore(songName, tempo, timeSignatureTop, timeSignatureBottom, instrument); //Play the score Play.midi(myScore, false); //Pause for the length of the score Play.waitCycle(myScore); } }