Time Varying Signal Generator

Due Date: 02/23/06

Purpose: The purpose of this assignment is to write a C program which generates a signal and writes it as an AIF file or text file.  The signal will be synthesized according to the parameters passed to the program on the terminal command line. 

Usage: The program will use the following syntax when called from the command line.  dstApp is the name of the program.
dstApp srate frqHz durSecs otCnt type octDev0 octDev1 ...

Arguments:
Name Type Units Notes
srate int Samples/Sec. Sample rate of the output signal.  Note that if the value si 44100 or 48000 an AIF file is created otherwise a text fiel is created.
frqHz float Hertz Fundamental frequency of the audio signal.  Range: 0 to 20000
durSecs float seconds Length of the output signal in seconds.
otCnt int Number of overtones to synthesize for the square, triangle and sawtooth waveform.
type int
  1. Sine
  2. Cosine
  3. Square
  4. Triangle
  5. Sawtooth
  6. White Noise
  7. Impulse Train
otDev0 float Octaves Starting frequency break point.  This value sets the  frequency deviation from the fundamental for the start of the sound.  All the frequency deviation break points represent an octave deviation from the fundamental frequency.  For example:
  • -2 = 2 octaves down
  • -1 = 1 octave down
  •  0 = No frequency change
  •  1 = 1 octave up
  •  2 = 2 octaves up
otDev1 float Octaves Second octave deviation break  point
... float more octave deviation break points.  Read the Requirements to see how the octave deviation values are used to form a frequency break point envelope.

Output: The output from the program depends on the sample rate paramter.  If the sample rate is set to 44100 or 48000 then a 16 bit AIF file is written to the terminals current directory.  If the sample rate is any other value then a text file is written.  Note that if the program is run from XCode then the output file (audio or text) is written to dst/assignmentts/tvSiggen/build/Debug.

Requirements:
  1. Before you begin working on this project you should create a folder named dst in your Documents folder.  Then create a folder in the dst folder named: assignments. If you haven't already you should then download dstlib,  de-archive it and copy it into your dst folder. Finally you should download the tvSiggen folder, de-archive it and copy it into dst/assignments.

  2. As shown in the argument table above the program may receive two or more octave deviations values. The first octave deviation value (together with the fundamental frequency (frqHz) )  is used to determine the starting frequency of the signal. The last octave deviation value is used to determine the ending frequency of the signal. Note that there always must be at least two octave deviation value. The octave deviation values represent a frequency break point envelope. The number of segments in the envelope is always one less than the total number of break points.  

  3. Note that the frequency of the signal should change smoothly from one break point to the next.  In other words you should linearly interpolate from one frequency break point to the next so that the signal performs a glissando between break points.

  4. The program should normalize the signal into the range -1.0 to 1.0 prior to writing the audio file.

  5. Check the frequencies of the the overtones to be sure they always remain below the Nyquist rate.

  6. The impulse train should be band-limited.  In other words use a sum of cosines rather than a list of zero's and one's.

  7. To turn in the project main.cpp to me.  

Notes:
  1. Begin working from the suppled tvSiggen project. This project contains the shell of the code you will need to write your program. Note that many of the details of handling the break point envelope have already been worked out for you.  As it is the program synthesizes a sine and cosine signal and uses the octave deviation values to form an amplitude envelope. Needless to say you will need to remove this functionality from the program when you insert the code necessary to implement the frequency break point envelope.

  2. Before you make any changes to the tvSiggen be sure it builds and you can successfully run it from the terminal.  If you want to run the program from inside XCode then you will also want to be able to change the arguments XCode gives it.  To do this Control-Click on the dstApp icon in the Executables section of the Groups and Files pane.  Select Get Info from the the context menu.  Select the Arguments tab.  The arguments are then listed in the order that they would appear on the command line.  (The top argument in the list is the left-most argument on the command line.).  Be sure you can successfully generate both a text file ooutput and an audio file output before changing any code.

  3. The frequency break point values are given as octave differences from the fundamental.  You will need to convert these values into Hertz.  The easiest way to do this is using the pow() function.  Raising 2 to the power of the octave deviation value will provide the right ratio to calculate the pitch bend from the fundamental.  For example frqHz * pow(2,1) == 2 * frqHz and frqHz * pow(2,-1) == 0.5 * frqHz.

  4. The trick to making a signal change frequency is recognizing that instantaneous frequency is a function of the change in phase.  There is a similar relationship between the position of a moving object and its velocity; phase is like position; frequency is like velocity.  The best way to convince yourself of this is to plot out the phase values for two fixed frequency sines in octave.
    plot( 2*pi*1/25 .* [0:99])
    hold on;
    plot( 2*pi*4/25 .* [0:99])
    hold off;
     Notice the slope of the 4 Hz signal is greater than the 1 Hz signal.  To increase the frequency of a signal you must increate the rate of change of the phase.  To decrease the frequency you must  decrease the rate of change of the phase.

  5. Until you have successfully created a sine of varying frequency in octave don't bother trying write the C program.  You will find it much easier to work out the conceptual issues in octave where you can easily view and plot the vectors.

  6. Once you have a time varying sine in octave  begin modifying the tvSiggen program to transfer what you learned in octave to the C implementation.  As always make very small and predictable changes to the tvSiggen code then build and run the program. This way when you encounter an error you will know exactly what you did to produce it.

  7. Print out lots of intermediate values when you run your incremental tests.  The only way to know what the program is doing is to print out the calculations as you make them.  In order to make the array sizes manageable test the program with a low sample rate and examine the resulting text file.  Download and use the readMtx octave function to read the text file into an octave vector so you can plot it.  
    x = readMtx("/Users/kevin/Documents/dst/assignments/tvSiggen/build/Debug/test.txt");
    plot(x);

  8. When you examine the main() function you will notice that it calls two functions: synthSine() and synthCosine().  You should take the same approach to writing your function. Each waveform should have it's own synthesizer function which synthesizes  the samples between 2 breakpoints.  You might even structure the program so  the complex periodic waveform functions (square,triangle,sawtooth,pulse) call synthSine() or synthCosine(). Keep in mind that you will need to change the arguments and return values for synthSine() and synthCosine() when you modify them to ramp frequency instead of amplitude. In particular you will need to keep track of the phase of the signal between calls to each function. (The phase of the last sample in a break point segment will need to match up with the phase of the first sample in the next break point envelope otherwise their will be clicks in the signal.)