Structuring Sounds CS 1316 Representing Structure and Behavior
Structuring Sounds CS 1316: Representing Structure and Behavior
Story l l l Structuring sounds into songs (? Collections? ) • Version 1: Representing linearity through elements order. • Repeating and weaving with sounds • Finding and replacing sounds in a list How do trace and debug what we’re doing with sounds and lists? Structuring sounds into songs • Version 2: Creating trees of sounds. • Traversing in a tree • Pre-order and post-order
Sound. Element: Creating a linked list of sounds /** * Sounds for a linked list **/ public class Sound. Element { /** * The sound this element is associated with **/ Sound my. Sound; /** * The next element to process **/ public Sound. Element next;
Constructing an element /** * Constructor sets next to null * and references the input sound. **/ public Sound. Element(Sound a. Sound){ next = null; my. Sound = a. Sound; }
Linked List blah-blah /** * Methods to set and get next elements * @param next. One next element in list **/ public void set. Next(Sound. Element next. One){ this. next = next. One; } public Sound. Element get. Next(){ return this. next; }
Methods for Playing /** * Play the list of sound elements * after me **/ public void play. From. Me. On(){ this. collect(). play(); } /** * Collect all the sounds from me on, * recursively. **/ public Sound collect(){ if (this. get. Next() == null) {return my. Sound; } else {return my. Sound. append(this. get. Next(). collect()); } }
Starting to explore > Sound s = new Sound("D: /cs 1316/mediasources/shh-a-h. wav"); > Sound t = new Sound("D: /cs 1316/mediasources/croak-h. wav"); > Sound u = new Sound("D: /cs 1316/mediasources/clap-q. wav"); > Sound. Element e 1 = new Sound. Element(s); > Sound. Element e 2 = new Sound. Element(t); > Sound. Element e 3 = new Sound. Element(u); > e 1. play. From. Me. On(); > e 1 Sound. Element with sound: Sound file: D: /cs 1316/mediasources/shh-ah. wav number of samples: 11004 (and next: null).
How did that happen? l l l How were we able to get that string from typing in e 1? By defining the method to. String() on a class, we can define how it should appear. VERY useful in debugging!
to. String() for Sound. Element /** * Provide a printable representation of me **/ public String to. String(){ return "Sound. Element with sound: "+my. Sound+" (and next: "+next+"). "; }
Growing the list > e 1. set. Next(e 2) > e 1 Sound. Element with sound: Sound file: D: /cs 1316/mediasources/shh-ah. wav number of samples: 11004 (and next: Sound. Element with sound: Sound file: D: /cs 1316/mediasources/croak-h. wav number of samples: 8808 (and next: null). ). > e 2. set. Next(e 3) > e 1 Sound. Element with sound: Sound file: D: /cs 1316/mediasources/shh-ah. wav number of samples: 11004 (and next: Sound. Element with sound: Sound file: D: /cs 1316/mediasources/croak-h. wav number of samples: 8808 (and next: Sound. Element with sound: Sound file: D: /cs 1316/mediasources/clap-q. wav number of samples: 4584 (and next: null). ). ). Where’s all that coming from? !? When we add in next to our to. String(), it calls next’s to. String()
e 1. play. From. Me. On() e 1 e 2 e 3 my. Sound: shh-ah. wav my. Sound: croakh. wav my. Sound: clapq. wav next: null public void play. From. Me. On(){ this. collect(). play(); }
public Sound collect(){ if (this. get. Next() == null) {return my. Sound; } e 1 e 2 e 3 my. Sound: shh-ah. wav my. Sound: croakh. wav my. Sound: clapq. wav next: null this
else {return my. Sound. append(this. get. Next(). collect()); } e 1 e 2 e 3 my. Sound: shh-ah. wav my. Sound: croakh. wav my. Sound: clapq. wav next: null this We “freeze” this call to e 1. collect()
public Sound collect(){ if (this. get. Next() == null) {return my. Sound; } e 2 e 3 Where’s e 1? What e 1? my. Sound: croakh. wav my. Sound: clapq. wav From e 2’s view, there is no e 1 next: null this
else {return my. Sound. append(this. get. Next(). collect()); } e 2 e 3 my. Sound: croakh. wav my. Sound: clapq. wav next: null this We “freeze” this call to e 2. collect()
public Sound collect(){ if (this. get. Next() == null) {return my. Sound; } e 3 my. Sound: clapq. wav next: null this We return clap-q. wav
else {return my. Sound. append(this. get. Next(). collect()); } e 2 e 3 my. Sound: croakh. wav my. Sound: clapq. wav next: null this Back in e 2. collect(), We return croakh. wav appended with clap-q. wav
else {return my. Sound. append(this. get. Next(). collect()); } e 1 e 2 e 3 my. Sound: shh-ah. wav my. Sound: croakh. wav my. Sound: clapq. wav next: null this Back in e 2. collect(), We return shh-ah. wav appended with croak-h. wav appended with clap-q. wav
e 1. play. From. Me. On() e 1 e 2 public void play. From. Me. On(){ this. collect(). play(); } e 3 my. Sound: shh-ah. wav my. Sound: croakh. wav my. Sound: clapq. wav next: null Now we play shha-h. wav appended with croak-h. wav appended with clap-q. wav
Testing Sound Lists public class Sound. List. Test { Sound. Element root; public Sound. Element root(){ return root; } public void set. Up(){ Sound s = new Sound(File. Chooser. get. Media. Path( "scratch-h. wav")); root = new Sound. Element(s); s = new Sound(File. Chooser. get. Media. Path( "gonga 2. wav")); Sound. Element one = new Sound. Element(s); root. repeat. Next(one, 10); s = new Sound(File. Chooser. get. Media. Path( "scritchq. wav")); Sound. Element two = new Sound. Element(s); root. weave(two, 3, 3); s = new Sound(File. Chooser. get. Media. Path( "clapq. wav")); Sound. Element three = new Sound. Element(s); root. weave(three, 5, 2); root. play. From. Me. On(); }
Repeating Shockingly similar to what we saw before! /** * Repeat the input phrase for the number of times specified. * It always appends to the current node, NOT insert. * @param next. One node to be copied in to list * @param count number of times to copy it in. */ public void repeat. Next(Sound. Element next. One, int count) { Sound. Element current = this; // Start from here Sound. Element copy; // Where we keep the current copy for (int i=1; i <= count; i++) { copy = next. One. copy. Node(); // Make a copy current. set. Next(copy); // Set as next current = copy; // Now append to copy } }
Copying by filename /** * copy. Node returns a copy of this element * @return another element with the same sound */ public Sound. Element copy. Node(){ Sound copy. Sound; if (this. my. Sound. get. File. Name() == null) {copy. Sound = this. my. Sound. scale(1. 0); } // Does nothing -- copies else {copy. Sound = new Sound(this. my. Sound. get. File. Name()); } // Copy from file Sound. Element return. Me = new Sound. Element(copy. Sound); return. Me; }
Weaving /** * Weave the input sound count times every skip. Amount elements * @param next. One Sound. Element to be copied into the list * @param count how many times to copy * @param skip. Amount how many nodes to skip per weave */ public void weave(Sound. Element next. One, int count, int skip. Amount) { Sound. Element current = this; // Start from here Sound. Element copy; // Where we keep the one to be weaved in Sound. Element old. Next; // Need this to insert properly int skipped; // Number skipped currently for (int i=1; i <= count; i++) { copy = next. One. copy. Node(); // Make a copy Again, shockingly similar to what we saw before! //Skip skip. Amount nodes skipped = 1; while ((current. get. Next() != null) && (skipped < skip. Amount)) { current = current. get. Next(); Should we skipped++; }; break before old. Next = current. get. Next(); // Save its next current. insert. After(copy); // Insert the copy after this one current = old. Next; // Continue on with the rest if (current == null) // Did we actually get to the end early? break; // Leave the loop } } the last insert (when we get to the end) or after?
What? You don’t like gongs? l l So, what happens when you have umpteen copies of gong, but you don’t like gongs? Yes, we can remake the list, but what if you couldn’t? • Imagine a huge data structure that was too • expensive (time-consuming) to recreate. How could you fix it in place?
Degong-ing the Sound. List. Test public void degong(){ Sound gong = new Sound(File. Chooser. get. Media. Path( "gonga 2. wav")); Sound snap = new Sound(File. Chooser. get. Media. Path( "snaptenth. wav")); root. replace(gong, snap); }
Replacing one sound by another in the list (recursively) /** * Replace the one sound with the other sound * in all the elements from me on. * Decide two sounds are equal if come from same filename * @param old. Sound sound to be replaced * @param new. SOund sound to put in its place **/ public void replace(Sound old. Sound, Sound new. Sound){ if (my. Sound. get. File. Name() != null) {if (my. Sound. get. File. Name(). equals(old. Sound. get. File. Name())) {my. Sound = new. Sound; }} if (next != null) {next. replace(old. Sound, new. Sound); } }
Imagine: e 1. replace(croak, clap) e 1 e 2 e 3 my. Sound: shh-ah. wav my. Sound: croakh. wav my. Sound: clapq. wav next: null
public void replace(Sound old. Sound, Sound new. Sound){ if (my. Sound. get. File. Name() != null) {if (my. Sound. get. File. Name(). equals(old. Sound. get. File. Name())) {my. Sound = new. Sound; }} e 1 e 2 e 3 my. Sound: shh-ah. wav my. Sound: croakh. wav my. Sound: clapq. wav next: null this
if (next != null) {next. replace(old. Sound, new. Sound); } e 1 e 2 e 3 my. Sound: shh-ah. wav my. Sound: croakh. wav my. Sound: clapq. wav next: null this
public void replace(Sound old. Sound, Sound new. Sound){ if (my. Sound. get. File. Name() != null) {if (my. Sound. get. File. Name(). equals(old. Sound. get. File. Name())) {my. Sound = new. Sound; }} e 2 This is a match! e 3 my. Sound: croakh. wav my. Sound: clapq. wav next: null next: this
if (next != null) {next. replace(old. Sound, new. Sound); } e 2 e 3 my. Sound: croakh. wav my. Sound: clapq. wav next: null next: this
public void replace(Sound old. Sound, Sound new. Sound){ if (my. Sound. get. File. Name() != null) {if (my. Sound. get. File. Name(). equals(old. Sound. get. File. Name())) {my. Sound = new. Sound; }} e 3 my. Sound: clapq. wav next: null this
if (next != null) {next. replace(old. Sound, new. Sound); } e 3 my. Sound: clapq. wav next: null this And we’re done! We do return all the way back up again, but there’s nothing else to be done.
Tracing what’s happening l l l Use “Debug Mode” from Debugger menu Type in variable names to trace. Set Breakpoints (Control-B) on the lines you want to stop in. • Step over—skips to the next line • Step in—skips in to that method call • Resume—go to the next breakpoint
Version 2: When lists aren’t good enough l Do we think about music as a linear list of sounds? • l l That is how we experience it. Or do we tend to cluster the sounds? • • Verse, chorus, verse? This motif, that motif, this motif? And what about this cool idea of embedding operations into the data structure?
Creating a tree of sounds Sound. Branch Clap, rest, snap Aah, snap, rest children next Scale. Branch Clink, clave, gong Is, chirp, clap Sound. Branch Clap, snap Bassoon, snap, clap
Creating and playing our tree of sounds Welcome to Dr. Java. > Sound. Tree. Example tree = new Sound. Tree. Example(); tree. set. Up(); > tree. play() > tree. play. Scaled(2. 0); > tree. play();
Sound. Tree. Example public class Sound. Tree. Example { Scale. Branch scaled. Branch; // Needed between methods Sound. Branch root; public Sound. Branch root() {return root; }
Setting up the basic sounds public void set. Up() { Sound clap = new Sound(File. Chooser. get. Media. Path("clap-q. wav")); Sound chirp = new Sound(File. Chooser. get. Media. Path("chirp-2. wav")); Sound rest = new Sound(File. Chooser. get. Media. Path("rest-1. wav")); Sound snap = new Sound(File. Chooser. get. Media. Path("snap-tenth. wav")); Sound clink = new Sound(File. Chooser. get. Media. Path("clink-tenth. wav")); Sound clave = new Sound(File. Chooser. get. Media. Path("clave-twentieth. wav")); Sound gong = new Sound(File. Chooser. get. Media. Path("gongb-2. wav")); Sound bassoon = new Sound(File. Chooser. get. Media. Path("bassoon-c 4. wav")); Sound is = new Sound(File. Chooser. get. Media. Path("is. wav")); Sound aah = new Sound(File. Chooser. get. Media. Path("aah. wav"));
Build the root and first branch root = new Sound. Branch(); Sound. Node sn; Sound. Branch branch 1 = new Sound. Branch(); sn = new Sound. Node(clap. append(rest). append(snap)); branch 1. add. Child(sn); sn = new Sound. Node(aah. append(snap). append(rest)); branch 1. add. Child(sn);
A Scale. Branch and last Branch scaled. Branch = new Scale. Branch(1. 0); sn = new Sound. Node(clink. append(clave). append(gong)); scaled. Branch. add. Child(sn); sn = new Sound. Node(is. append(chirp). append(clap)); scaled. Branch. add. Child(sn); Sound. Branch branch 2 = new Sound. Branch(); sn = new Sound. Node(clap. append(snap)); branch 2. add. Child(sn); sn = new Sound. Node(bassoon. append(snap). append(clap)); branch 2. add. Child(sn);
Building the whole tree root. add. Child(branch 1); root. add. Child(scaled. Branch); root. add. Child(branch 2); }
Playing the tree, and changing the scale public void play(){ root. play. From. Me. On(); } public void play. Scaled(double factor){ scaled. Branch. set. Factor(factor); root. play. From. Me. On(); }
What a tree “looks like” (printed, e. g. , to. String()) > tree Obviously, this doesn’t Sound. Tree. Example@92 b 1 a 1 help us much, but the root() does > tree. root() Sound. Branch (with child: Sound. Node (with sound: Sound number of samples: 28568 and next: Sound. Node (with sound: Sound number of samples: 46034 and next: null and next: Scale. Branch (1. 0) Sound. Branch (with child: Sound. Node (with sound: Sound number of samples: 47392 and next: Sound. Node (with sound: Sound number of samples: 32126 and next: null and next: Sound. Branch (with child: Sound. Node (with sound: Sound number of samples: 8452 and next: Sound. Node (with sound: Sound number of samples: 28568 and next: null and next: No next))) and next: No next)
Going deeper: How’d we do that? l How we build a tree of sounds is very much like a tree of pictures. • • Set up a general node abstract class that all other nodes inherit from. Create a leaf node that will store our data of interest (sounds). Create a branch node that will store collections of leaves and references to other branches. Create (as we wish) branch nodes with operations that do things to the children of this branch.
Our Sound. Tree Class Structure abstract Collectable. Node Knows next Knows How to do basic list operations, and defines abstract sound operations (can collect() its sound(s)) The subclasses extend Collectable. Node Sound. Branch Sound. Node Knows children Knows my. Sound Knows How add children, and collect all the sounds from its children and next Knows How collect itself and its next
Our Sound. Tree Class Structure (a little further) abstract Collectable. Node Knows next Knows How to do basic list operations, and collect() Sound. Branch Knows children Knows How add children, and collect() Sound. Node Knows my. Sound Knows How collect() Scale. Branch Knows a scaling factor Knows How to access scaling factor, and to collect from children then scale the resultant sound
Collectable. Node /** * Stuff that all nodes and branches in the * sound tree know. **/ abstract public class Collectable. Node { /** * The next branch/node/whatever to process **/ public Collectable. Node next; /** * Constructor for Collectable. Node just sets * next to null **/ public Collectable. Node(){ next = null; }
Collectable. Node’s know about linked lists /** * Methods to set and get next elements * @param next. One next element in list **/ public void set. Next(Collectable. Node next. One){ this. next = next. One; The rest of it is } public Collectable. Node get. Next(){ return this. next; } there, too: add(), last(), insert. After(), remove()… But you’ve seen that all before.
Collectable. Nodes know only a little about sound /** * Play the list of sound elements * after me **/ public void play. From. Me. On(){ this. collect(). play(); } /** * Collect all the sounds from me on **/ abstract public Sound collect(); /** * Collect all the sounds from me on, * but if there's processing, do it after. **/ abstract public Sound collect. After();
Sound. Nodes know sounds /* * Sound. Node is a class representing a drawn picture * node in a scene tree. **/ public class Sound. Node extends Collectable. Node { /** * The sound I'm associated with **/ Sound my. Sound; /* * Make me with this sound * @param sound the Sound I'm associated with **/ public Sound. Node(Sound sound){ super(); // Call superclass constructor my. Sound = sound; }
What happens if you print a Sound. Node /** * Method to return a string with informaiton * about this node */ public String to. String() { return "Sound. Node (with sound: "+my. Sound+" and next: "+next; }
How Sound. Nodes collect their sounds /** * Collect all the sounds from me on, “Hang on, how does that work? !? ” * recursively. **/ Wait until we see the rest, then we’ll public Sound collect(){ trace it. if (this. get. Next() == null) {return my. Sound; } else {return my. Sound. append(this. get. Next(). collect()); } }
Sound. Branches know about children public class Sound. Branch extends Collectable. Node { /* * A list of children to draw Notice: Children */ could be public Collectable. Node children; Sound. Nodes or /* * Construct a branch with children and * next as null **/ public Sound. Branch(){ super(); // Call superclass constructor children = null; } other branches— any kind of Collectable. Node
Sound. Branches know about children (contd. ) /** * Method to add nodes to children **/ public void add. Child(Collectable. Node child){ if (children != null) {children. add(child); } else {children = child; } }
How Sound. Branches print /** * Method to return a string with informaiton * about this branch */ public String to. String() { String child. String = "No children", next. String="No next"; if (children != null) {child. String = children. to. String(); } if (next != null) {next. String = next. to. String(); } return "Sound. Branch (with child: "+child. String+" and next: "+ next. String+")"; }
Collecting sounds from Sound. Branches /** * Collect all the sound from our children, * then collect from next. * @param pen Turtle to draw with **/ public Sound collect(){ Sound child. Sound; if (children != null) {child. Sound = children. collect(); } else {child. Sound = new Sound(1); } // Collect from my next if (this. get. Next() != null) {child. Sound=child. Sound. append(this. get. Next(). collect()); } return child. Sound; } This collects from the children (or creates a default sound), then from the next’s, and returns them all together
Scale. Branches know about scaling (and a factor) public class Scale. Branch extends Sound. Branch { /** Amount to scale **/ double factor; /** * Construct a branch with this factor **/ public Scale. Branch(double nufactor){ super(); // Call superclass constructor this. factor = nufactor; } /** Accessors **/ public double get. Factor() {return this. factor; } public void set. Factor(double nufactor) {this. factor = nufactor; }
Scaling the children in a Scale. Branch /** * Collect all the sound from our children, * then collect from next. Scale the children * @param pen Turtle to draw with **/ public Sound collect(){ Sound child. Sound; if (children != null) {child. Sound = children. collect(). scale(factor); } else {child. Sound = new Sound(1); } // Collect from my next if (this. get. Next() != null) {Sound next. Sound=this. get. Next(). collect(); child. Sound = child. Sound. append(next. Sound); } return child. Sound; }
Printing a Scale. Branch /** * Method to return a string with informaiton * about this branch */ public String to. String() { return "Scale. Branch ("+factor+") "+super. to. String(); }
Walking the data structure: At the root > tree. root() Sound. Branch (with child: Sound. Node (with sound: Sound number of samples: 28568 and next: Sound. Node (with sound: Sound number of samples: 46034 and next: null and next: Scale. Branch (1. 0) Sound. Branch (with child: Sound. Node (with sound: Sound number of samples: 47392 and next: Sound. Node (with sound: Sound number of samples: 32126 and next: null and next: Sound. Branch (with child: Sound. Node (with sound: Sound number of samples: 8452 and next: Sound. Node (with sound: Sound number of samples: 28568 and next: null and next: No next))) and next: No next)
Down the children’s next path > tree. root(). children Sound. Branch (with child: Sound. Node (with sound: Sound number of samples: 28568 and next: Sound. Node (with sound: Sound number of samples: 46034 and next: null and next: Scale. Branch (1. 0) Sound. Branch (with child: Sound. Node (with sound: Sound number of samples: 47392 and next: Sound. Node (with sound: Sound number of samples: 32126 and next: null and next: Sound. Branch (with child: Sound. Node (with sound: Sound number of samples: 8452 and next: Sound. Node (with sound: Sound number of samples: 28568 and next: null and next: No next))) > tree. root(). children. get. Next() Scale. Branch (1. 0) Sound. Branch (with child: Sound. Node (with sound: Sound number of samples: 47392 and next: Sound. Node (with sound: Sound number of samples: 32126 and next: null and next: Sound. Branch (with child: Sound. Node (with sound: Sound number of samples: 8452 and next: Sound. Node (with sound: Sound number of samples: 28568 and next: null and next: No next)) > tree. root(). children. get. Next() Sound. Branch (with child: Sound. Node (with sound: Sound number of samples: 8452 and next: Sound. Node (with sound: Sound number of samples: 28568 and next: null and next: No next) > tree. root(). children. get. Next() null
Tracing a tree traversal Welcome to Dr. Java. > Sound. Tree. Example tree = new Sound. Tree. Example(); tree. set. Up(); > tree. root(). collect(). play() This code: (1) Creates a tree object. (2) Fills it up. (3) Then gets the root, collects the sound from the whole tree (traverses the tree), then plays the collected sound.
Tracing the traversal: tree. root(). collect(). play Sound. Branch tree. root() Sound. Branch Clap, rest, snap Aah, snap, rest children next Scale. Branch Clink, clave, gong Is, chirp, clap Sound. Branch Clap, snap Bassoon, snap, clap
public Sound collect(){ Sound child. Sound; if (children != null) {child. Sound = children. collect(); } else {child. Sound = new Sound(1); } Sound. Branch this Sound. Branch Clap, rest, snap Aah, snap, rest Scale. Branch Sound. Branch Clink, clave, gong Is, chirp, clap Clap, snap Bassoon, snap, clap Yes, the root has children, so we ask the first of our children to collect()
public Sound collect(){ Sound child. Sound; if (children != null) {child. Sound = children. collect(); } else {child. Sound = new Sound(1); } Sound. Branch this Clap, rest, snap Aah, snap, rest The call to root(). collect() is now paused… Scale. Branch Sound. Branch Clink, clave, gong Is, chirp, clap Clap, snap Bassoon, snap, clap Yes, we’re in the same method, but now with a new this. It’s really a new call.
public Sound collect(){ if (this. get. Next() == null) {return my. Sound; } else {return my. Sound. append(this. get. Next(). collect()); } } Now, we’re in Sound. Node’s collect() Sound. Branch Scale. Branch Clap, rest, snap this Aah, snap, rest The call to root(). children. collect() is now paused… Clink, clave, gong Is, chirp, clap Sound. Branch Clap, snap Bassoon, snap, clap We have a next, so we collect from there, too.
public Sound collect(){ if (this. get. Next() == null) {return my. Sound; } else {return my. Sound. append(this. get. Next(). collect()); } } We’re in Sound. Node’s collect(), with a new Sound. Node Sound. Branch Scale. Branch Clap, rest, snap this Aah, snap, rest The call to root(). children. collect() is now paused… Clink, clave, gong Is, chirp, clap Sound. Branch Clap, snap Bassoon, snap, clap We have no next here, so we return “Aah, snap, rest”
We’re back in Sound. Node’s collect() Sound. Branch Clap, rest, snap this Aah, snap, rest public Sound collect(){ if (this. get. Next() == null) {return my. Sound; } else {return my. Sound. append(this. get. Next(). collect()); } } Scale. Branch Sound. Branch Clink, clave, gong Is, chirp, clap Clap, snap Bassoon, snap, clap We now return “Clap, rest, snap” appended with “aah, snap, rest”
We’re now in the second half of Sound. Branch’s collect() // Collect from my next if (this. get. Next() != null) {Sound next. Sound=this. get. Next(). collect(); child. Sound = child. Sound. append(next. Sound); } } return child. Sound; Sound. Branch this Clap, rest, snap Aah, snap, rest Scale. Branch Sound. Branch Clink, clave, gong Is, chirp, clap Clap, snap Bassoon, snap, clap We have a next, so we move on to call collect() on that.
Now we’re in Scale. Branch’s collect() public Sound collect(){ Sound child. Sound; if (children != null) {child. Sound = children. collect(). scale(factor); } else {child. Sound = new Sound(1); } Sound. Branch this Sound. Branch Clap, rest, snap Aah, snap, rest Scale. Branch Clink, clave, gong Is, chirp, clap Sound. Branch Clap, snap Bassoon, snap, clap Let’s skip the path down the children. child. Sound will become “Clink, clave, gong, is, chirp, clap” scaled by the factor
Second half of Scale. Branch— we get the sounds from next // Collect from my next if (this. get. Next() != null) {Sound next. Sound=this. get. Next(). collect(); child. Sound = child. Sound. append(next. Sound); } return child. Sound; } Sound. Branch this Sound. Branch Clap, rest, snap Aah, snap, rest Scale. Branch Clink, clave, gong Is, chirp, clap Sound. Branch Clap, snap Bassoon, snap, clap
We’re in the first half of Sound. Branch public Sound collect(){ Sound child. Sound; if (children != null) {child. Sound = children. collect(); } else {child. Sound = new Sound(1); } Sound. Branch this Sound. Branch Clap, rest, snap Aah, snap, rest Scale. Branch Clink, clave, gong Is, chirp, clap Sound. Branch Clap, snap Bassoon, snap, clap child. Sound will become “Clap, snap, bassoon, snap, clap”
We’re in the second half of Sound. Branch // Collect from my next if (this. get. Next() != null) {Sound next. Sound=this. get. Next(). collect(); child. Sound = child. Sound. append(next. Sound); } return child. Sound; } Sound. Branch this Sound. Branch Clap, rest, snap Aah, snap, rest Scale. Branch Clink, clave, gong Is, chirp, clap Sound. Branch Clap, snap Bassoon, snap, clap There is no next so we return “Clap, snap, bassoon, snap, clap”
// Collect from my next if (this. get. Next() != null) {Sound next. Sound=this. get. Next(). collect(); child. Sound = child. Sound. append(next. Sound); } return child. Sound; } Back to second half of Scale. Branch Sound. Branch this Sound. Branch Scale. Branch Clap, rest, snap aah, snap, rest get. Next(). collect() returned “Clap, snap, bassoon, snap, clap” Clink, clave, gong is, chirp, clap Sound. Branch Clap, snap bassoon, snap, clap This returns “Clink, clave, gong, is, chirp, clap” scaled by the factor, plus “Clap, snap, bassoon, snap, clap”
Back in the second half of Sound. Branch’s collect() // Collect from my next if (this. get. Next() != null) {Sound next. Sound=this. get. Next(). collect(); child. Sound = child. Sound. append(next. Sound); } } return child. Sound; Sound. Branch this Clap, rest, snap Scale. Branch Clink, clave, gong Sound. Branch Clap, snap Bassoon, snap, clap Aah, snap, rest Is, chirp, clap This returns “Clap, rest, snap, aah, snap, rest”, plus “Clink, clave, gong, is, chirp, clap” scaled by the factor, plus “Clap, snap, bassoon, snap, clap”
// Collect from my next if (this. get. Next() != null) {Sound next. Sound=this. get. Next(). collect(); child. Sound = child. Sound. append(next. Sound); } Now we’re back to the second half of this. There is no next Sound. Branch } return child. Sound; this Sound. Branch Clap, rest, snap Aah, snap, rest Scale. Branch Clink, clave, gong Is, chirp, clap Sound. Branch Clap, snap Bassoon, snap, clap FINAL RETURN: “Clap, rest, snap, aah, snap, rest”, plus “Clink, clave, gong, is, chirp, clap” scaled by the factor, plus “Clap, snap, bassoon, snap, clap”
That was one kind of tree traversal l There are other ways of thinking about traversing a tree! • • l l Go down the next before going to the children? Maybe do the scaling to the next instead of to the children? What we’ve been doing (children-branchnext) is called in-order traversal. There are other kinds, like pre-order traversal and post-order traversal.
Sound. Branch’s collect. After() /** * Collect all the sound from our children, * then collect from next. * If there's processing, do to Next, not to Children * @param pen Turtle to draw with **/ public Sound collect. After(){ Sound child. Sound; if (children != null) {child. Sound = children. collect. After(); } else {child. Sound = new Sound(1); } // Collect from my next if (this. get. Next() != null) {child. Sound=child. Sound. append(this. get. Next(). collect. After()); } return child. Sound; }
Scale. Branch’s collect. After() /** * Collect all the sound from our children, * then collect from next. * Scale the next list, not the children * @param pen Turtle to draw with **/ public Sound collect. After(){ Sound child. Sound; if (children != null) {child. Sound = children. collect(); } else {child. Sound = new Sound(1); } Notice that we’re scaling what get. Next(). collect() returns, not what children. collect() returns // Collect from my next if (this. get. Next() != null) {Sound next. Sound=this. get. Next(). collect(); child. Sound = child. Sound. append(next. Sound. scale(factor)); } return child. Sound; }
Trying this in Sound. Tree. List public void play. After(){ root. collect. After(). play(); } > tree. play. After()
Where else could we go with this? l l l How about a kind of Sound. Branch that knows how to repeat its children a certain number of time? How about a kind of Sound. Branch that can mix its children with the next, with a certain percentage of each? Back with pictures: • • How about a kind of branch that can rotate its children? Or scale them, so you could zoom in or out, or grow/shrink the monster, across frames?
Arrays, and Lists, and Trees, oh my! l Where we’re going next: • • • l We’ve explored lists and trees in a good deal of depth now! You obviously saw lots of similarities between these implementations. “Couldn’t we do this once, instead of duplicating all this code? !? ” YES! Let me show you… “Man, what I really want to do is user interfaces with Java—real applications! What does this all have to do with that? !? ” • A user interface is a tree. Let me show you…
- Slides: 84