Computer Science 245: Data Structures and Algorithms

Programming Assignment 1: Playing with Sound

Sound

Sound waves are compressions of air.


Sound waves are an inherently analog phenomena, to represent them in a digital domain, we need to sample them. We choose a sampling rate (say, 10000 samples a second) and then every 1/1000th of a second, we record the value of the wave at that point. We then save all of these samples, and that is our internal representaion of the sound.


Sometimes we want to record multiple channels of sound. For instance, stereo headphones have 2 separate channels of sound (one for the left ear, and one for the right). Surround sound systems can have even more channels -- 5.1 has 6 channels: Front-Left, center, Front-Right, back-left, back-right, subwoofer.

Linked Lists

For the first project, You will implement a data structure that stores and manipulates sound clips using a linked-list structure. Speficially, sounds will be stored as a linked list of samples, where each sample is a linked list of the sampled values for each channel. For example, a SoundList for a 3-channel sound containing 4 samples would look something like the following:


Note that your are NOT ALLOWED to use ArrayList, java.util.LinkedLists, or any other element from the Java collection framework to create you SoundList -- you need to create your own Linked List ENTIRELY FROM SCRATCH. Also, you should NOT use arrays of any kind to store your SoundList (though you will need to use arrays as parameters / return values of some of your methods

But ... But ...

I can already hear you saying:

All valid points, however:

Implementation

You will implement the following interface:
SoundList.java
import java.util.Iterator;

public interface SoundList {
	
	/**
	 * The number of channels in the SoundList
	 * @return The number f channels in the SoundList
	 */
	public int getNumChannels();
	
	/**
	 * Returns the sample rate, in samples per second
	 * @return The sample rate, in samples per second
	 */
	public float getSampleRate();
	
	
	/**
	 * Returns the number of samples in the SoundList
	 * @return The number of samples in the SoundList.
	 */
	public int getNumSamples();
	
	/**
	 * Returns The duration of the sound, in seconds.
	 * @return  the duration of the sound, in seconds.
	 */
	public float getDuration();
	
	/**
	 * Fade in.  Smoothly ramp the volume up for fadeDuration sections. 
	 * @param fadeDuration The time (in seconds) to fade in.
	 */
	public void fadeIn(float fadeDuration);
	
	/**
	 * Fade out.  Smoothly ramp the volume down for fadeDuration sections. 
	 * @param fadeDuration The time (in seconds) to fade in.
	 */
	public void fadeOut(float fadeDuration, float startTime);
	
	/**
	 * Remove the silence at the front and back of the clip.  All samples at the beginning of the clip 
	 * whose absolute value is less than or equal to maxLevel are removed, until a sample whose absolute value
	 * is that is > maxLevel appears.  Then retain all samples until the end, at which point all samples 
	 * whose absolute value is <= maxLevel are removed.
	 * Note that a value > maxLevel on any channel is sufficient to keep the sample.
	 * @param maxLevel The level at which the sample is kept.
	 */
	public void trimSilence(float maxLevel);
	
	/**
	 * Add an echo effect to the SoundList.  
	 * @param delay The time (in seconds) before the echo starts
	 * @param percent The percent falloff of the echo (0.5 is 50 percent volume, 0.25 is
	 *        25 percent volume, and so on.  All samples should be clipped to the range -1 .. 1
	 */
	public void addEcho(float delay, float percent);
	
	/**
	 * Reverse the SoundList.  
	 */
	public void reverse();
	
	/**
	 * Change the speed of the sound.   
	 * @param percentChange  How much to change the speed.  1.0 is no change, 2.0 doubles the speed (and the pitch), 0.5 
	 * cuts the speed in half (and lowers the pitch)  The sample rate should remain unchanged!  This is probably the hardest
	 * function to implement in the entire project.
	 */
	public void changeSpeed(float percentChange);
	
	/**
	 * Add a single sample to the end of the SoundList.  Throws an exception if the soundlist has more than 1 channel 
	 * @param sample The sample to add
	 */
	public void addSample(float sample);
	
	/**
	 * Adds a single sample for each channel to the end of the SoundList.  Throws an exception if the size of the sample 
	 * array is not the same as the number of channels in the sound list
	 * @param sample Array of samples (one for each channel) to add to the end of the SoundList
	 */
	public void addSample(float sample[]);
	
	/**
	 * Return an iterator that traverses the entire sample, returning an array floats (one for each channel)
	 * @return iterator
	 */
	public Iterator iterator();
	
	
	/**
	 * Change the volume of all tracks in the sound list, by multiplying every value by the percent to change.  
	 * If allowClipping is true, values greater than 1.0 are set to 1.0, and values less than -1.0 are set to -1.0
	 * If allowClipping is false, then if any values are greater than 1.0 or less than -1.0 in any clip, the entire sample
	 * is rescaled to fit in the range.
	 * @param percentToChange The percent to increase the volume.  A value of 1 will leave the clip unchanged, 2.0 
	 * will make the volume twice as loud, and 0.5 will make the volume 50% as loud.  
	 * @param allowClipping If allowClipping is true, then values greater than 1.0 or less than -1.0 after the 
	 * volume change are clipped to fit in the range.  If allowClipping is false, then if any values are greater than 1.0
	 * or less than -1.0, the entire sample is rescaled  to fit in the range.
	 */
	public void changeVolume(float percentToChange, boolean allowClipping);
	
	
	/**
	 * Return an iterator that traverses a single channel of the list
	 * @param channel The channel to traverse
	 * @return the iterator to traverse the list
	 */
	public Iterator iterator(int channel);
	
	/**
	 * Trim the SoundList, by removing all samples before the startTime, and all samples past the end time.
	 * Note that if a SoundList represents an 8 second sound, and we call clip(4,7), the new SoundList will be
	 * a 3-second sound (from seconds 4-7 in the old SoundList)
	 * @param startTime Time to start (in seconds)
	 * @param endTime Time to end clip (as measured from the front of the original clip, in seconds)
	 */
	public void clip(float startTime, float endTime);
	
	/**
	 * Splice a new SoundList into this soundList.  Both SoundLists will be modified.  If the sampleRate of the
	 * clipToSplice is not the same as this SoundList, an exception is thrown.
	 * @param startSpliceTime Time to start the splice
	 * @param clipToSplice The other SoundClip to splice in.  
	 */
	public void spliceIn(float startSpliceTime, SoundList clipToSplice);
	
	/**
	 * Combine all channels into a single channel, by adding together all channels into a single channel.
	 * @param allowClipping If allowClipping is true, then values greater than 1.0 or less than -1.0 after the 
	 * addition are clipped to fit in the range.  If allowClipping is false, then if any values are greater than 1.0
	 * or less than -1.0, the entire sample is rescaled  to fit in the range.
	 */
	public void makeMono(boolean allowClipping);

	/**
	 * Combines this SoundList with a new SoundList, by adding the samples together.  This SoundList
	 * is modified.   If the sampleRate of the clipTocombine is not the same as this SoundList, an exception is thrown.
	 * If a SoundList of length 3 seconds and a SoundList of length 7 seconds are combined, the result will be a
	 * SoundList of 7 seconds.
	 * @param clipToCombine  The clip to combine with this clip
	 * @param allowClipping  If allowClipping is true, then values greater than 1.0 or less than -1.0 after the 
	 * addition are clipped to fit in the range.  If allowClipping is false, then the entire sample is rescaled  
	 */
	public void combine(SoundList clipToCombine, boolean allowClipping);
	
	/**
	 * Returns a clone of this SoundList
	 * @return The cloned SoundList
	 */
	public SoundList clone();
}
Where:

Test Files

We have provided the file TestMain.java to help you test your SoundList implementation.

Assignment

For your first assignemnt, you will

Due Date

Your SoundList class should be checked into subversion by Wednesday, Feb 22nd, 2017 Feb 24th, 2017.

Submission

Submit your files using subversion. Your files should be stored in the subversion In fact, I recommmend that you don't wait until you program is done to get it into subversion, start right away to protect yourself. The subverion directory you should use for this proect is https://www.cs.usfca.edu/svn/username/cs245/project1/, where username is your cs username.

Collaboration

It is OK for you to discuss solutions to this program with your classmates. However, no collaboration should ever involve looking at one of your classmate's source programs! It is usually extremely easy to determine that someone has copied a program, even when the individual doing the copying has changed identifier names and comments.

Provided Files

The following files are provided. Note that you need to use the interfaces as they are given, so that you program will work correctly with the testing code that we will provide.
x`_