CS 190C, Spring 2008: Project 1

Manipulating Digital Audio

Posted: February 1, 2008

Due dates:

  • Part 1: Friday, February 8, 10pm
  • Part 2: Friday, February 15, 10pm


In this project you will explore the generation and manipulation of digital sound. You will write basic functions that generate sounds, read/write .wav files, and alter and transform sounds waves based on common principles. You will then use the functions to generate interesting sounds serving certain needs.


The objective of the project is to design and implement functions that

  • demonstrate basic principles of digital sound
  • manipulate a digital representation of sound in the form of an array of integers
  • use and manipulate arrays with numeric data
  • employ different uses of loop structures
  • are described by detailed specifications

Background Material

In the physical world, sounds exist as fluctuations in pressure in the air around us. These fluctuations are continuous functions of time that take on a continuous range of values, which is referred to as an analog signal. Any periodic analog signal can be decomposed into (and is thus the sum of) a (possibly infinite) number of sine waves. Computers, however, cannot easily represent such functions. Instead, sample values are taken at discrete time intervals. Thus, although we don't have the original wave, we have samples of where the wave was for a number of points in time. This is referred to as a digital signal. A digital-to-analog converter can reconstruct the original wave from the samples, which can in turn be played on speakers.

The rate at which samples are taken is known as the sampling frequency. It is measured in Hertz (Hz), or samples per second. The sample size is the number of digits used in the digital representation of each sample. Higher sampling frequency and higher sample size lead to higher quality sound.

An analog-to-digital converter (ADC) takes an analog signal as input and produces a digital signal as output. You may encounter such a device when using a microphone. As you speak or play into a microphone, your voice causes a membrane to vibrate. Many times per second, it is recorded how far the membrane has been displaced in either direction. These samples may be saved easily for playback at a later time. Naturally, a digital-to-analog converter (DAC) is the counterpart of the ADC. A DAC takes discrete samples in time and constructs a continuous wave from them. You may find such a device in your sound card. Whenever you listen to a sound on your computer, these discrete samples are converted to a continuous signal that can be fed to your speakers.

It is possible to exactly reconstruct an analog signal from digital samples subject to a few conditions. When recording an analog signal it is important to know the highest frequency that will be captured. This is known as the Nyquist frequency. The Nyquist-Shannon theorem states that it is possible to exactly reconstruct a wave consisting of frequencies up to the Nyquist frequency if the sampling frequency is at least twice as large.

The most common sampling frequencies found on audio hardware are currently 11025Hz, 22050Hz, and 44100Hz. Since the average human ear can only hear a maximum frequency of up to 20000Hz, we should set our sampling frequency to at least 40000Hz. Sampling at a higher frequency is not necessary and only results in more samples that capture sounds that are inaudible to humans. However, this comes at a cost. The higher the sampling frequency, the more memory is required to store the same duration of sound. As a compromise, for this project we will use 22050Hz signals, which will allow us to capture many frequencies in the audible range while still using less memory.

Provided Utility Code

In order to let you focus on key concepts related to the generation and manipulation of sound, you will be given a utility module that contains a set of basic capabilities. These functions include the ability to

  • read a WAV file into an array; write array data as a WAV file - in file snd_io.py
  • view wave output using a Matplotlib - in file snd_utils.py; example output ex_show.pdf


Project Tasks

Part 1 of the project focuses on developing a series of functions we call audio primitives. The description below lists the audio primitives every student is required to implement. Note that the primitives fall into two categories: (i) functions that generate new audio data from a given set of parameters, and (ii) functions that modify existing audio data (either a given .wav file or a file generated by a primitive).

Part 2 of the project asks you to write one function from the list of additional primitives and to then use all nine functions you have written in creative and interesting ways. This is described in more detail further below.

To assist in testing your code, you may want to check these example files.

Required Functions

You need to complete each of the following functions, also referred to as “audio primitives”:

  • scale_volume(data, factor) - Scale the volume of a sound wave
  • normalize(data) - Normalize (maximize volume of) a sound wave
  • echo(data, delay, level) - Add an echo effect to a sound wave
  • sin_sample(freq, amp, dur) - Generate a sine wave
  • combine(wavs) - Combine a given list of sound waves into one
  • silence(dur) - Generate a silence
  • equal_scale(freq, amp, dur, sampler=sin_sample) - Generate a chromatic scale in equal temperament
  • split_on_silences(data, len_thresh=.25, vol_thresh=.1) - Split a sound at silences

These functions are described in more detail.

Additional Functions

You need to implement at least one of the following audio functions:

  • square_sample(freq, amp, dur) - Generate a square wave
  • sawtooth_sample(freq, amp, dur) - Generate a sawtooth wave
  • ring_modulate(s1, s2) - Ring modulate two waves
  • just_scale(freq, amp, dur, sampler=sin_sample) - Generate a chromatic scale in just temperament
  • partch_scale(freq, amp, dur, sampler=sin_sample) - Generate a Partch 43 tone scale
  • fade_out(data, amount=.1) - Generate a fading out effect

The additional functions are specified in detail here.

Using the Primitives to create your own sounds

Part 2 of the project asks you to design two functions generating sounds from the audio functions you have written:

  • Function my_sound_1: This function cannot use a sound file as input, but needs to create a sound file. The function needs to contain at least one loop and use at two of the audio function you wrote (excluding sin_sample). The output generated should be written to a file. It should be usable as your cell phone ringer, sound to listen to before falling asleep, or your alarm clock sound. You need to include a brief description on how you generated the sound and why you feel it serves the stated purpose.
  • Function my_sound_2: This function must use as input a .wav file (more than one file is allowed). The .wav file can be one of the files we provide or you can use your own. The function needs to contain at least one loop and use use at two of the audio function you wrote (excluding sin_sample). The input file is to be altered in an interesting way and you need to explain what is happening to the input sounds.

Think about interesting ways to use the functions you wrote in part 1 and how they could be adapted. Examples include using your music background in a creative way, doubling the speed of the sound by, for example, deleting every other sample, rearranging words in a sentence (using split_on_silence). You want to experiment before making your decision. You may also find the graphing routine helpful in understanding how you are changing the sound wave.

Submission Instructions

Part 1: Submit the eight required functions. Put the eight functions into one file (primitives.py) and submit a folder containing primitives.py, snd_util.py (even if you did not change it) and anything else needed to run your functions.

After the deadline for part 1, we will make the code of the required function available to you. You can continue in part 2 with your own functions or the ones provided by us.

Part 2: Submit the eight required functions (yes, again) and the additional primitive in a file primitives.py, files my_sound_1.py and my_sound_2.py as well as a discussion on your created sounds describing what they are supposed to be and why you consider them interesting.

Note: For all projects you will be asked to submit one folder containing all files needed by your program. This includes the files you have written and well as files we supplied and you are using, This folder should also include a file (text) containing your discussion/evaluation as asked for. Please remember include your name in a comment in all files.

After part 1 is completed, we will post code for the eight required primitives. For part 2, you can use your code or the one we provide. Any code you use must be submitted.

Extra Credit Options

Implement more than one of the additional functions for extra credit (if the code is working correctly).

cs190c/project1.txt · Last modified: 2008/02/06 13:05 (external edit)
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki