CS 190C, Spring 2009: Project 1

Manipulating Digital Audio

Posted: February 6, 2009

Due dates:

  • Part 1: Friday, February 13, 10pm
  • Part 2: Wednesday, February 25, 10pm


In this project you will explore the generation and manipulation of digital sound. You will write basic functions that generate, alter and transform sounds waves based on specified principles. You will then use the functions to generate new sounds. In particular, choosing a characteristic sound snippet (clap, cough, bark, etc), you will generate a “massive response” sound of the same type. For example, generating applause from a single clap.


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

  • 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

In addition, the project requires that you write function which 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 can be saved 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 most 40000Hz. Sampling at a higher frequency is not necessary and only results in more samples that capture sounds that are inaudible to humans. In addition, the higher the sampling frequency, the more memory is required to store the same duration of sound.

For this project we will use 22050Hz signals, which will allow us to capture many frequencies in the audible range. As you generate and input sound waves, keep in mind that one second corresponds to 22050 samples.

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:

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

We also provide a skeleton program for the functions you will write in part 1 and sample sound files. Links to the provided resources re given below.

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.

Part 2 of the project asks you to write at least two functions from the list of additional primitives and to then use all functions you have written to generate a “massive response” sound. This is described in more detail further below.

Required Functions

Complete each of the following functions, also referred to as “audio primitives”. Some may have been completed in Lab 5. Include either the code as seen in the lab or your own.

  • scale_volume(data, factor) - Scale the volume of a sound wave
  • normalize(data) - Normalize (maximize volume of) a sound wave
  • sin_sample(freq, amp, dur) - Generate a sine wave
  • half_speed(data) - generates a new array containing the same sound, but at half of the original speed
  • echo(data, delay, level) - Add an echo effect to a sound
  • combine_mean(wavs) - Combine a given list of sound waves into one of the same length using means
  • combine_interleave(wavs) - Combine a given list of sound waves into one by interleaving samples
  • silence(dur) - Generate a silence

These functions are described in more detail. Make sure to follow the parameter conventions and understand what each function returns.

To assist in testing your code, you may want to check these example files. This example uses the 8 primitives from the required list together. Output can be heard .

Additional Functions

Implement at least two of the following audio functions. If you decide to implement splatter, you only need to do one function (splatter is the most involved function).

  • equal_scale(freq, amp, dur, sampler=sin_sample) - generates an ascending chromatic scale
  • ring_modulate(s1, s2) - calculate the product of two signals
  • fade_out(data, amount=0.1) - linearly scale a sound over its duration making it fade out
  • repeat(data, count, scale_func=None) - repeat data count times, each time scale with function func
  • sweep(mono_data, start) - pan from side 'start' to the other side, adjusting the pan linearly throughout the sample
  • splatter(mono_data, count, duration) - repeat mono_data count times over duration seconds, inserting the sound at random delays and pan

The additional functions are specified in detail here. This file also include additional primitives (clone, pan, pan_sequence) you can use. A brief discussion on stereo is given here. Make sure to read this if you decide to implement functions sweep or splatter.

Generating a "massive response"

Part 2 of the project asks you to design a function that takes as input one of a specified sound snippets and which generates a “massive response” sound of the same type. Below are a few examples of what initial sounds can generate as massive responses.

sound snippetmassive response
one clap applause
one step footsteps
one thunder thunderstorm
dog barking pack of dogs barking

The complete list of sound snippets can be found in folder fx downloaded from Sample WAV files . If you want to use sounds snippets not in the file, please check with the TA or the instructor.

You need to include a brief description on how you generated the massive response sound and why you feel it serves the stated purpose. 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 and anything else needed to run your functions. Do not change the files snd_io.py and snd_utils.py. Any additional functions you write and need should be in the folder your submit.

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 following files in one folder: the eight required functions in file primitives.py (yes, again), the additional primitives in a file add_primitives.py, and file my_massive_response.py creating the massive response. Make sure to include all .wav files used by your programs. Also include a text file describing how the massive response is created, what you tried, and why you like (or don't like) the sound your produced.

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, All Python files need start with comment files containing your name and a project identifier.

cs190c/project1_09.txt · Last modified: 2009/02/13 01:17 (external edit)
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki