260 likes | 423 Views
Manipulating Sound. CS1316: Representing Structure and Behavior. Story. Programming Sampled Sounds in Java 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.
E N D
Manipulating Sound CS1316: Representing Structure and Behavior
Story • Programming Sampled Sounds in Java • 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(“C:/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())); } }
increaseVolume: How it works • 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 CS1315 Python. • They (respectively) return an array of all the samples, get the value of a given sample object, and set the value of a given sample object.
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){ 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(); } }
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 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() 12 94 … inSound.getLength()
insertAftermethod /** * 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)); } }
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 start end this.getLength() This distance is start-end
Then, clear out the end 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);} }
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 • Strengths: • 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 • “Static”—it’s always the same length (shape?)