CS1316: Representing Structure and Behavior Manipulating Sound CS1316: Representing Structure and Behavior
Story Programming Sampled Sounds in Java Manipulating an array Manipulating sounds in-place Returning a new sound Manipulating an array Inserting a sound Deleting a sound segment
Loading and playing sounds Welcome to DrJava. > Sound s = new Sound("D:/cs1316/MediaSources/thisisatest.wav") > s.increaseVolume(2.0); > s.play();
increaseVolume method /** * Increase the volume of a sound **/ public void increaseVolume(double factor){ SoundSample [] samples = this.getSamples(); SoundSample current = null; for (int i=0; i < samples.length; i++) { current = samples[i]; current.setValue((int) (factor * current.getValue())); }
Issues in increaseVolume SoundSample is the name of the class for samples. There’s something named Sample already in Java, so it would get confusing. getSamples(), getValue(), and setValue() work just the same as in Python.
Methods that return sounds > Sound s = new Sound("D:/cs1316/MediaSources/thisisatest.wav") > s.play() > s.reverse() Sound number of samples: 64513 Why do you think we’re seeing this?
Reverse returns a Sound! /** * Method to reverse a sound. **/ public Sound reverse() { Sound target = new Sound(getLength()); int sampleValue; for (int srcIndex=0,trgIndex=getLength()-1; srcIndex < getLength(); srcIndex++,trgIndex--) sampleValue = this.getSampleValueAt(srcIndex); target.setSampleValueAt(trgIndex,sampleValue); }; return target; }
Methods that cascade nicely in Sound public Sound reverse() public Sound append(Sound appendSound) public Sound mix(Sound mixIn, double ratio) public Sound scale(double factor)
Little sounds in MediaSources -h: Half second -q: Quarter second -1 or -2: 1 or 2 seconds -tenth: 1/10 second -twentieth: 1/20 second
Making collages public class MySoundCollage { public static void main(String [] args){ FileChooser.setMediaPath("D:/cs1316/MediaSources/"); Sound snap = new Sound(FileChooser.getMediaPath("snap-tenth.wav")); Sound drum = new Sound(FileChooser.getMediaPath("drumroll-1.wav")); Sound clink = new Sound(FileChooser.getMediaPath("clink-tenth.wav")); Sound clap = new Sound(FileChooser.getMediaPath("clap-q.wav")); Sound drumRev = drum.reverse().scale(0.5); Sound soundA = snap.append(clink).append(clink).append(clap).append(drumRev); Sound soundB = clink.append(clap).append(clap).append(drum).append(snap).append(snap); Sound collage = soundA.append(soundB).append(soundB).append(soundA).append(soundA).append(soundB); collage.play(); } Making collages
How do we insert and delete sound? Welcome to DrJava. > Sound test = new Sound("D:/cs1316/MediaSources/thisisatest.wav"); > test.getLength() 64513 > Sound clink = new Sound("D:/cs1316/MediaSources/clink-tenth.wav"); > clink.getLength() 2184 > test.insertAfter(clink,40000) > test.play()
Handling the error cases > Sound test2 = new Sound("D:/cs1316/MediaSources/thisisatest.wav"); > test.insertAfter(test2,40000) > test.play()
First, making room … 0 1 2 3 this.getLength() start 0 1 2 3 start 0 1 2 3 this.getLength() start 12 94 -152 -27 11 inSound.getLength() 0 1 2 3 start start+inSound.getLength() 12 94 …
Second, copying in … 0 1 2 3 start start+inSound.getLength() 0 1 2 3 start start+inSound.getLength() 12 94 … inSound.getLength()
insertAfter method /** * insert the input Sound after the nth sample (input integer). * Modifies the given sound * @param insound Sound to insert * @param start index where to start inserting the new sound **/ public void insertAfter(Sound inSound, int start){ SoundSample current=null; // Find how long insound is int amtToCopy = inSound.getLength(); int endOfThis = this.getLength()-1; if (start + amtToCopy > endOfThis) {// If too long, copy only as much as will fit amtToCopy = endOfThis-start-1;} else { // If short enough, need to clear out room. // Copy from endOfThis-amtToCopy;, moving backwards // (toward front of list) to start, // moving UP (toward back) to endOfThis // KEY INSIGHT: How much gets lost off the end of the // array? Same size as what we're inserting -- amtToCopy for (int source=endOfThis-amtToCopy; source >= start ; source--) { // current is the TARGET -- where we're copying to current = this.getSample(source+amtToCopy); current.setValue(this.getSampleValueAt(source)); } // NOW, copy in inSound up to amtToCopy for (int target=start,source=0; source < amtToCopy; target++, source++) { current = this.getSample(target); current.setValue(inSound.getSampleValueAt(source)); insertAfter method
Setting up the variables SoundSample current=null; // Find how long insound is int amtToCopy = inSound.getLength(); int endOfThis = this.getLength()-1;
Checking for room if (start + amtToCopy > endOfThis) {// If too long, copy only as much as will fit amtToCopy = endOfThis-start-1;} else { // If short enough, need to clear out room.
Now, copy down else { // If short enough, need to clear out room. // Copy from endOfThis-amtToCopy;, moving backwards // (toward front of list) to start, // moving UP (toward back) to endOfThis // KEY INSIGHT: How much gets lost off the end of the // array? Same size as what we're inserting -- amtToCopy for (int source=endOfThis-amtToCopy; source >= start ; source--) { // current is the TARGET -- where we're copying to current = this.getSample(source+amtToCopy); current.setValue(this.getSampleValueAt(source)); }
Finally, copy in the new sound //** Second, copy in inSound up to amtToCopy for (int target=start,source=0; source < amtToCopy; target++, source++) { current = this.getSample(target); current.setValue( inSound.getSampleValueAt(source)); }
How do we delete? > Sound test = new Sound("D:/cs1316/MediaSources/thisisatest.wav"); > test.getLength() 64513 > test.delete(2000,30000) > test.play() // We hear “This test”
First, copy from end to getLength, back to start this.getLength() This distance is start-end
Then, clear out the end 00000000… This distance is start-end. this.getLength() 00000000… This distance is start-end. And we’ll go from the length, backwards.
Deleting method /** * Delete from start to end in this sound * @param start where to start deletion * @param end where to stop deletion **/ public void delete(int start, int end){ int value = 0; // Basically, we simply copy from "end" to getLength back to start for (int source=end, target=start; source < this.getLength(); source++, target++) {value = this.getSampleValueAt(source); this.setSampleValueAt(target,value);} // Then clear out the rest. Gap is end-start length int gap = end-start; for (int i=1; i <= gap ; i++) { this.setSampleValueAt(this.getLength()-i,0);} } Deleting method
First, copy up—over the start to end gap // Basically, we simply copy from "end" to getLength back to start for (int source=end, target=start; source < this.getLength(); source++, target++) {value = this.getSampleValueAt(source); this.setSampleValueAt(target,value);}
Then, clear out the gap at the end // Then clear out the rest. Gap is end-start length int gap = end-start; for (int i=1; i <= gap ; i++) { this.setSampleValueAt( this.getLength()-i, 0);}
Arrays: Strengths and weaknesses Easy to understand Very efficient “Static”—it’s always the same length (shape?) Weaknesses: Any change in the middle is hard to do Expensive in complexity and processing