1 / 84

Structuring Sounds

Learn to structure sounds into songs, represent linearity, repeat and weave sounds, debug lists, and traverse in trees. Build a linked list of sounds and play them from a starting point. Understand how to grow the list and debug effectively.

davissandra
Download Presentation

Structuring Sounds

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Structuring Sounds CS1316: Representing Structure and Behavior

  2. Story • 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

  3. SoundElement:Creating a linked list of sounds /** * Sounds for a linked list **/ public class SoundElement { /** * The sound this element is associated with **/ Sound mySound; /** * The next element to process **/ public SoundElement next;

  4. Constructing an element /** * Constructor sets next to null * and references the input sound. **/ public SoundElement(Sound aSound){ next = null; mySound = aSound; }

  5. Linked List blah-blah-blah /** * Methods to set and get next elements * @param nextOne next element in list **/ public void setNext(SoundElement nextOne){ this.next = nextOne; } public SoundElement getNext(){ return this.next; }

  6. Methods for Playing /** * Play the list of sound elements * after me **/ public void playFromMeOn(){ this.collect().play(); } /** * Collect all the sounds from me on, * recursively. **/ public Sound collect(){ if (this.getNext() == null) {return mySound;} else {return mySound.append(this.getNext().collect());} }

  7. Starting to explore > Sound s = new Sound("D:/cs1316/mediasources/shh-a-h.wav"); > Sound t = new Sound("D:/cs1316/mediasources/croak-h.wav"); > Sound u = new Sound("D:/cs1316/mediasources/clap-q.wav"); > SoundElement e1 = new SoundElement(s); > SoundElement e2 = new SoundElement(t); > SoundElement e3 = new SoundElement(u); > e1.playFromMeOn(); > e1 SoundElement with sound: Sound file: D:/cs1316/mediasources/shh-a-h.wav number of samples: 11004 (and next: null).

  8. How did that happen? • How were we able to get that string from typing in e1? • By defining the method toString() on a class, we can define how it should appear. • VERY useful in debugging!

  9. toString() for SoundElement /** * Provide a printable representation of me **/ public String toString(){ return "SoundElement with sound: "+mySound+" (and next: "+next+")."; }

  10. Growing the list > e1.setNext(e2) > e1 SoundElement with sound: Sound file: D:/cs1316/mediasources/shh-a-h.wav number of samples: 11004 (and next: SoundElement with sound: Sound file: D:/cs1316/mediasources/croak-h.wav number of samples: 8808 (and next: null).). > e2.setNext(e3) > e1 SoundElement with sound: Sound file: D:/cs1316/mediasources/shh-a-h.wav number of samples: 11004 (and next: SoundElement with sound: Sound file: D:/cs1316/mediasources/croak-h.wav number of samples: 8808 (and next: SoundElement with sound: Sound file: D:/cs1316/mediasources/clap-q.wav number of samples: 4584 (and next: null).).). Where’s all that coming from?!?When we add in next to our toString(), it calls next’s toString()

  11. e1.playFromMeOn() public void playFromMeOn(){ this.collect().play(); } e1 e2 e3 mySound: shh-a-h.wav next: mySound: croak-h.wav next: mySound: clap-q.wav next: null

  12. public Sound collect(){ if (this.getNext() == null) {return mySound;} e1 e2 e3 mySound: shh-a-h.wav next: mySound: croak-h.wav next: mySound: clap-q.wav next:null this

  13. else {return mySound.append(this.getNext().collect());} e1 e2 e3 mySound: shh-a-h.wav next: mySound: croak-h.wav next: mySound: clap-q.wav next:null We “freeze” this call to e1.collect() this

  14. public Sound collect(){ if (this.getNext() == null) {return mySound;} e2 e3 mySound: croak-h.wav next: mySound: clap-q.wav next:null Where’s e1? What e1? From e2’s view, there is no e1 this

  15. else {return mySound.append(this.getNext().collect());} e2 e3 mySound: croak-h.wav next: mySound: clap-q.wav next:null We “freeze” this call to e2.collect() this

  16. public Sound collect(){ if (this.getNext() == null) {return mySound;} e3 mySound: clap-q.wav next:null We return clap-q.wav this

  17. else {return mySound.append(this.getNext().collect());} e2 e3 Back in e2.collect(), We return croak-h.wav appended with clap-q.wav mySound: croak-h.wav next: mySound: clap-q.wav next:null this

  18. else {return mySound.append(this.getNext().collect());} e1 e2 e3 Back in e2.collect(), We return shh-a-h.wav appended with croak-h.wav appended with clap-q.wav mySound: shh-a-h.wav next: mySound: croak-h.wav next: mySound: clap-q.wav next:null this

  19. e1.playFromMeOn() public void playFromMeOn(){ this.collect().play(); } e1 e2 e3 Now we play shh-a-h.wav appended with croak-h.wav appended with clap-q.wav mySound: shh-a-h.wav next: mySound: croak-h.wav next: mySound: clap-q.wav next: null

  20. Testing Sound Lists public class SoundListTest { SoundElement root; public SoundElement root(){ return root;} public void setUp(){ FileChooser.setMediaPath("D:/cs1316/MediaSources/"); Sound s = new Sound(FileChooser.getMediaPath( "scratch-h.wav")); root = new SoundElement(s); s = new Sound(FileChooser.getMediaPath( "gonga-2.wav")); SoundElement one = new SoundElement(s); root.repeatNext(one,10); s = new Sound(FileChooser.getMediaPath( "scritch-q.wav")); SoundElement two = new SoundElement(s); root.weave(two,3,3); s = new Sound(FileChooser.getMediaPath( "clap-q.wav")); SoundElement three = new SoundElement(s); root.weave(three,5,2); root.playFromMeOn(); }

  21. Repeating /** * 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(SoundElement nextOne,int count) { SoundElement current = this; // Start from here SoundElement 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 } } Shockingly similar to what we saw before!

  22. Copying by filename /** * copyNode returns a copy of this element * @return another element with the same sound */ public SoundElement copyNode(){ Sound copySound; if (this.mySound.getFileName() == null) {copySound = this.mySound.scale(1.0);} // Does nothing -- copies else {copySound = new Sound(this.mySound.getFileName());} // Copy from file SoundElement returnMe = new SoundElement(copySound); return returnMe; }

  23. Weaving /** * Weave the input sound count times every skipAmount elements * @param nextOne SoundElement 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(SoundElement nextOne, int count, int skipAmount) { SoundElement current = this; // Start from here SoundElement copy; // Where we keep the one to be weaved in SoundElement 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.getNext() != null) && (skipped < skipAmount)) { current = current.getNext(); skipped++; }; if (current.getNext() == null) // Did we actually get to the end early? break; // Leave the loop oldNext = current.getNext(); // Save its next current.insertAfter(copy); // Insert the copy after this one current = oldNext; // Continue on with the rest } } Again, shockingly similar to what we saw before!

  24. What? You don’t like gongs? • 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?

  25. Degong-ing the SoundListTest public void degong(){ Sound gong = new Sound(FileChooser.getMediaPath( "gonga-2.wav")); Sound snap = new Sound(FileChooser.getMediaPath( "snap-tenth.wav")); root.replace(gong,snap); }

  26. 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 oldSound sound to be replaced * @param newSOund sound to put in its place **/ public void replace(Sound oldSound, Sound newSound){ if (mySound.getFileName() != null) {if (mySound.getFileName().equals(oldSound.getFileName())) {mySound = newSound;}} if (next != null) {next.replace(oldSound,newSound);} }

  27. Imagine: e1.replace(croak,clap) e1 e2 e3 mySound: shh-a-h.wav next: mySound: croak-h.wav next: mySound: clap-q.wav next: null

  28. public void replace(Sound oldSound, Sound newSound){ if (mySound.getFileName() != null) {if (mySound.getFileName().equals(oldSound.getFileName())) {mySound = newSound;}} e1 e2 e3 mySound: shh-a-h.wav next: mySound: croak-h.wav next: mySound: clap-q.wav next: null this

  29. if (next != null) {next.replace(oldSound,newSound);} e1 e2 e3 mySound: shh-a-h.wav next: mySound: croak-h.wav next: mySound: clap-q.wav next: null this

  30. public void replace(Sound oldSound, Sound newSound){ if (mySound.getFileName() != null) {if (mySound.getFileName().equals(oldSound.getFileName())) {mySound = newSound;}} e2 e3 This is a match! mySound: croak-h.wav clap-q.wav next: mySound: clap-q.wav next: null this

  31. if (next != null) {next.replace(oldSound,newSound);} e2 e3 mySound: croak-h.wav clap-q.wav next: mySound: clap-q.wav next: null this

  32. public void replace(Sound oldSound, Sound newSound){ if (mySound.getFileName() != null) {if (mySound.getFileName().equals(oldSound.getFileName())) {mySound = newSound;}} e3 mySound: clap-q.wav next: null this

  33. if (next != null) {next.replace(oldSound,newSound);} e3 And we’re done! We do return all the way back up again, but there’s nothing else to be done. mySound: clap-q.wav next: null this

  34. Tracing what’s happening • 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

  35. Version 2: When lists aren’t good enough • Do we think about music as a linear list of sounds? • 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?

  36. Creating a tree of sounds SoundBranch SoundBranch ScaleBranch SoundBranch Clap, rest, snap Clap,snap,snap Clink,clave, gong Rest, snap, clap Rest, chirp, clap Rest, snap, rest children next

  37. Creating and playing our tree of sounds Welcome to DrJava. > SoundTreeExample tree = new SoundTreeExample(); tree.setUp(); > tree.play() > tree.playScaled(2.0); > tree.play();

  38. SoundTreeExample public class SoundTreeExample { ScaleBranch scaledBranch; // Needed between methods SoundBranch root; public SoundBranch root() {return root;}

  39. Setting up the basic sounds public void setUp() { FileChooser.setMediaPath("D:/cs1316/MediaSources/"); Sound clap = new Sound(FileChooser.getMediaPath("clap-q.wav")); Sound chirp = new Sound(FileChooser.getMediaPath("chirp-2.wav")); Sound rest = new Sound(FileChooser.getMediaPath("rest-1.wav")); Sound snap = new Sound(FileChooser.getMediaPath("snap-tenth.wav")); Sound clink = new Sound(FileChooser.getMediaPath("clink-tenth.wav")); Sound clave = new Sound(FileChooser.getMediaPath("clave-twentieth.wav")); Sound gong = new Sound(FileChooser.getMediaPath("gongb-2.wav"));

  40. Build the root and first branch root = new SoundBranch(); SoundNode sn; SoundBranch branch1 = new SoundBranch(); sn = new SoundNode(clap.append(rest).append(snap)); branch1.addChild(sn); sn = new SoundNode(rest.append(snap).append(rest)); branch1.addChild(sn);

  41. A ScaleBranch and last Branch scaledBranch = new ScaleBranch(1.0); sn = new SoundNode(clink.append(clave).append(gong)); scaledBranch.addChild(sn); sn = new SoundNode(rest.append(chirp).append(clap)); scaledBranch.addChild(sn); SoundBranch branch2 = new SoundBranch(); sn = new SoundNode(clap.append(snap).append(snap)); branch2.addChild(sn); sn = new SoundNode(rest.append(snap).append(clap)); branch2.addChild(sn);

  42. Building the whole tree root.addChild(branch1); root.addChild(scaledBranch); root.addChild(branch2); }

  43. Playing the tree, and changing the scale public void play(){ root.playFromMeOn(); } public void playScaled(double factor){ scaledBranch.setFactor(factor); root.playFromMeOn(); }

  44. What a tree “looks like” (printed, e.g., toString()) > tree SoundTreeExample@92b1a1 > tree.root() SoundBranch (with child: SoundBranch (with child: SoundNode (with sound: Sound number of samples: 28568 and next: SoundNode (with sound: Sound number of samples: 46034 and next: null and next: ScaleBranch (1.0) SoundBranch (with child: SoundNode (with sound: Sound number of samples: 47392 and next: SoundNode (with sound: Sound number of samples: 32126 and next: null and next: SoundBranch (with child: SoundNode (with sound: Sound number of samples: 8452 and next: SoundNode (with sound: Sound number of samples: 28568 and next: null and next: No next))) and next: No next) Obviously, this doesn’t help us much, but the root() does

  45. Going deeper: How’d we do that? • 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.

  46. Our SoundTree Class Structure abstract CollectableNode Knows next Knows How to do basic list operations, and defines abstract sound operations (can collect() its sound(s)) The subclasses extendCollectableNode SoundBranch Knows children Knows How add children, and collect all the sounds from its children and next SoundNode Knows mySound Knows How collect itself and its next

  47. Our SoundTree Class Structure (a little further) abstract CollectableNode Knows next Knows How to do basic list operations, and collect() SoundBranch Knows children Knows How add children, and collect() SoundNode Knows mySound Knows Howcollect() ScaleBranch Knows a scaling factor Knows How to access scaling factor, and to collect from children then scale the resultant sound

  48. CollectableNode /** * Stuff that all nodes and branches in the * sound tree know. **/ abstract public class CollectableNode { /** * The next branch/node/whatever to process **/ public CollectableNode next; /** * Constructor for CollectableNode just sets * next to null **/ public CollectableNode(){ next = null; }

  49. CollectableNode’s know about linked lists /** * Methods to set and get next elements * @param nextOne next element in list **/ public void setNext(CollectableNode nextOne){ this.next = nextOne; } public CollectableNode getNext(){ return this.next; } The rest of it is there, too: add(), last(), insertAfter(), remove()… But you’ve seen that all before.

More Related