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 */ public 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; } // method to get last node in list (pretty self explainatory) public SongNode last(){ SongNode current; current = this; while (current.next() != null) { current = current.next(); }; return current; } // method for inserting a node into every other space in a list public void weaveInsert(SongNode node){ // intitialize SongNode current; SongNode copy; current = this; // if not at end of list and next is not the last node (i know this is redundant but jut in case) if (current.next() != null && current.next() != node){ copy = node.copyNode(); current.insertAfter(copy);// insert node copy current = current.next().next(); // move to the copy node, then move to the next node current.weaveInsert(node); // do it again } } public void midiPlay(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"); // 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); Play.midi(myScore, false);// play in midi } public void midiWrite(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"); // 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); Write.midi(myScore); // save in midi } }