Telecom programs Oscillator and Mixer

Due: Feb 22, 2012

You are to write the following two programs. Use my WavReader.java library, and look at the other programs for ideas on how to proceed. Here are the programs:

WavReader.java: my general library for reading wav files into an array of samples and writing wav files from arrays of samples. Some key methods:


reader.java: Opens a wav file for reading and prints it as a sequence of samples as text numbers, one per line. The sampling rate is lost. Uses WavReader = new WavReader(new File(filename)) and then a loop involving wr.readValue()

stats.java: Opens a wav file as above and then gets wr.getSampleRate, wr.getNumSamples, and prints some other info

play.java: One way to play sound files (the java library often gets "stuck", but win/mac/linux all have other standard utilities for playing wav files.

Oscillator program

The oscillator program should generate a specific sine/sawtooth/etc tone for a specified length of time. All the parameters should be towards the beginning of the program so they can be easily changed. You are to assume that the output format is 16-bit mono. You will need to specify: The frequency should be "exact"; that is, if the wavelength is 15.36 sample times then do not round off to 15 sample times.

Create an array of short (short []) to hold the data, fill it in with a loop (using Math.sin() to create the sine wave), and then use WavReader.writeWav() to create the file.

The formula for a sine wave of frequency f is sin(2𝜋fx). Use 𝜋 = Math.PI. Note, though, that for filling a discrete array short[] samples you will need to express the frequency f in terms of the sampling rate (because the values samples[i] are expressed in terms of the sampling rate). To make this conversion, f should be the original frequency (in Hertz) divided by the sampling rate (in samples per second). Be sure you use floating-point division! (You will also use the array index i instead of x, and multiply the sine result by the volume level.)

Those registered for graduate credit should also generate sawtooth and square waves (using separate programs is fine). Which one sounds the most musically interesting? This is easiest if you write your saw(t)/sqr(t) functions with period 1 (not 2𝜋!), in which case you will set samples[i] = saw(freq*i) (that is, without the 2𝜋). To find saw(t)/sqr(t), first, scale t so that it is in the range [0,1]: t = t - Math.floor(t). Then shift so that t is in the range [-1/2, 1/2]: if (t>1/2) t = t-1. Then saw(t) = 2*t; sqr(t) = 1.0 if t>=0, -1.0 otherwise.

To help you get started, I've given you osc_skel.java.

Mixer program

Write a program to take two .wav files on the command line and combine them into a single output file by adding corresponding components. The third file named on the command line should be the name of the output file.

To mix WavReader objects wr1 and wr2 (constructed from the corresponding files), form the sum
      sample[i] = wr1.readValue() + wr2.readValue();
Note that you'll also have to divide by 2, the number of files, in order to avoid overrunning the 32767 16-bit-maximum-sample-value limit.

You will need to create an array of WavReader objects, one for each file, so you can read from each file in turn, and compute the above sum in a loop.

The files listed on the command line will appear in the String[] args parameter to main. The number of files is args.length, which should be 3;  the input file namess are args[0] and args[1] and the output file name is args[2].

To help you get started, most of the file I/O is done for you in mixer_skel.java.

Demo

Use your oscillator program to generate two sound files 2-5 seconds long that have frequencies differing by 1-2 Hertz (eg 440 and 442). Use your mixer to mix them. Play the result. You should clearly hear the "beat frequency", equal to the difference in the file frequencies (eg 2 Hertz, or 2 beats/sec).