1 / 36

Problem Solving with Data Structures using Java: A Multimedia Approach

Problem Solving with Data Structures using Java: A Multimedia Approach. Chapter 5: Arrays: A Static Data Structure for Sounds . Chapter Objectives. Representing sounds. Sounds are vibrations in the air (increases and decreases in air pressure) changing very rapidly.

fidelio
Download Presentation

Problem Solving with Data Structures using Java: A Multimedia Approach

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. Problem Solving with Data Structures using Java: A Multimedia Approach Chapter 5: Arrays: A Static Data Structure for Sounds

  2. Chapter Objectives

  3. Representing sounds • Sounds are vibrations in the air (increases and decreases in air pressure) changing very rapidly. • We can hear between 20 vibrations to 20,000 vibrations per second. • The pitch A above middle C is 440 vibrations per second (Hertz, Hz, CPS, Cycles Per Second) • We record the air pressure (samples) at regular intervals (sampling rate) in order to digitize the sound. • CD quality sound samples 44,100 times per second. • Each sample is 16 bits, for a range of +/- 32,000 (roughly).

  4. Contrasting WAV and MIDI • WAV files are sampled (recorded) sound. • So is MP3, but that’s compressed. • MIDI is a format that represents music. • Literally, it records instruments and when a note is started and ended.

  5. Loading and playing sounds Welcome to DrJava. > Sound s = new Sound("D:/cs1316/MediaSources/thisisatest.wav") > s.play() //Hear it normal > s.increaseVolume(2.0); > s.play();

  6. 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())); } }

  7. 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.

  8. 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?

  9. 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; }

  10. 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)

  11. 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

  12. Making sound effects > Sound s = new Sound(FileChooser.getMediaPath("gonga-2.wav")); > Sound s2 = new Sound(FileChooser.getMediaPath("gongb-2.wav")); > s.play(); // create the first sound > s2.play(); // create the second sound > s.reverse().play(); // Play first sound in reverse > s.append(s2).play(); // Play first then second sound > // Mix in the second sound, so you can hear part of each > s.mix(s2,0.25).play(); > // Mix in the second sound sped up > s.mix(s2.scale(0.5),0.25).play(); > s2.scale(0.5).play(); // Play the second sound sped up > s2.scale(2.0).play(); // Play the second sound slowed down > s.mix(s2.scale(2.0),0.25).play();

  13. 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(); } }

  14. How append() works /** * Return this sound appended with the input sound * @param appendSound sound to append to this **/ public Sound append(Sound appendSound) { Sound target = new Sound(getLength() + appendSound.getLength()); int sampleValue; // Copy this sound in for (int srcIndex=0,trgIndex=0; srcIndex < getLength(); srcIndex++,trgIndex++) { sampleValue = this.getSampleValueAt(srcIndex); target.setSampleValueAt(trgIndex,sampleValue); }

  15. End of append() // Copy appendSound in to target for (int srcIndex=0,trgIndex=getLength(); srcIndex < appendSound.getLength(); srcIndex++,trgIndex++) { sampleValue = appendSound.getSampleValueAt(srcIndex); target.setSampleValueAt(trgIndex,sampleValue); } return target; }

  16. Mixing two sounds together public Sound mix(Sound mixIn, double ratio) { Sound target = new Sound(getLength()); int sampleValue, mixValue,newValue; // Copy this sound in for (int srcIndex=0,trgIndex=0; srcIndex < getLength() && srcIndex < mixIn.getLength(); srcIndex++,trgIndex++) { sampleValue = this.getSampleValueAt(srcIndex); mixValue = mixIn.getSampleValueAt(srcIndex); newValue = (int)(ratio*mixValue) + (int)((1.0-ratio)*sampleValue); target.setSampleValueAt(trgIndex,newValue); } return target; } /** * Mix the input sound with this sound, with percent ratio of input. * Use mixIn sound up to length of this sound. * Return mixed sound. * @parammixIn sound to mix in * @param ratio how much of input mixIn to mix in **/

  17. Scale() public Sound scale(double factor) { Sound target = new Sound((int)(factor *(1 + getLength()))); int sampleValue; // Copy this sound in for (double srcIndex=0.0,trgIndex=0; srcIndex < getLength(); srcIndex+=(1/factor),trgIndex++) { sampleValue = getSampleValueAt((int)srcIndex); target.setSampleValueAt((int) trgIndex,sampleValue); } return target; } /** * Scale up or down a sound by the given factor * (1.0 returns the same, 2.0 doubles the length, * and 0.5 halves the length) * @param factor ratio to increase or decrease **/

  18. 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()

  19. Handling the error cases > Sound test2 = new Sound("D:/cs1316/MediaSources/thisisatest.wav"); > test.insertAfter(test2,40000) > test.play()

  20. 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 …

  21. Second, copying in 0 1 2 3 start start+inSound.getLength() 12 94 … inSound.getLength()

  22. insertAftermethod /** * Insert the input Sound after the specified start * 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;

  23. if (start + amtToCopy - 1 > 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+1;, 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)); } }

  24. Setting up the variables SoundSample current=null; // Find how long insound is int amtToCopy = inSound.getLength(); int endOfThis = this.getLength()-1;

  25. Checking for room if (start + amtToCopy - 1 > endOfThis) {// If too long, copy only as much as will fit amtToCopy = endOfThis-start+1;} else { // If short enough, need to clear out room.

  26. 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)); } }

  27. 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)); }

  28. 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”

  29. First, copy from end to getLength, back to start start end this.getLength() This distance is start-end

  30. Then, clear out the end start end this.getLength() 00000000… This distance is start-end. And we’ll go from the length, backwards.

  31. 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+1 length int gap = end-start+1; for (int i=1; i <= gap ; i++) { this.setSampleValueAt(this.getLength()-i,0);} }

  32. 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);}

  33. Then, clear out the gap at the end // Then clear out the rest. Gap is end-start+1 length int gap = end-start+1; for (int i=1; i <= gap ; i++) { this.setSampleValueAt( this.getLength()-i, 0);}

  34. 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?)

  35. Think about the timing • How long does it take to insert or delete? • Depends on the number of elements n • We call that O(n): The speed of execution changes depending on n • That’s linear time. • We call O() “Big-O” • That’s the upper bound of how long an algorithm will take. • “Big-Omega” is the lower bound, the fastest possible execution. • “Big-Theta” describes the upper bound = lower bound.

  36. Other complexities of algorithms • O(n) is linear time. • O(1) is constant time. • Execution time is same, no matter how much data. • A good sorting algorithm is O(n log(n)). • Simple sorting algorithms are O(n2) • There are slower algorithms. • Optimization algorithms can be O(n!)

More Related