0% found this document useful (0 votes)
97 views9 pages

Lab 2 - Wavetable Generators, AM/FM Modulation

This document describes wavetable generators and AM/FM modulation through examples and code. Key points: 1. Wavetable generators store one period of a waveform (e.g. sinusoid) and cycle through the table to generate different frequencies. AM modulation combines two wavetables - one for the carrier signal and one for the amplitude envelope. 2. Example code generates a 1kHz sinusoid from a wavetable and allows adjusting the frequency. FM modulation varies the frequency of a carrier signal using another wavetable as the modulating signal. 3. Running the AM modulation example produces a carrier signal whose amplitude is modulated by an envelope signal. Changing the envelope frequency alters the modulation effect.

Uploaded by

Jenkin WInston
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
97 views9 pages

Lab 2 - Wavetable Generators, AM/FM Modulation

This document describes wavetable generators and AM/FM modulation through examples and code. Key points: 1. Wavetable generators store one period of a waveform (e.g. sinusoid) and cycle through the table to generate different frequencies. AM modulation combines two wavetables - one for the carrier signal and one for the amplitude envelope. 2. Example code generates a 1kHz sinusoid from a wavetable and allows adjusting the frequency. FM modulation varies the frequency of a carrier signal using another wavetable as the modulating signal. 3. Running the AM modulation example produces a carrier signal whose amplitude is modulated by an envelope signal. Changing the envelope frequency alters the modulation effect.

Uploaded by

Jenkin WInston
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 9

20

Lab 2 Wavetable Generators, AM/FM Modulation


2.1. Lab Tasks
The concept of a wavetable is introduced and applied first to the generation of sinusoidal signals of
different frequencies and then to square waves. AM and FM examples are constructed by combining two
wavetables. Ring modulation and tremolo audio effects are studied as special cases of AM modulation.

2.2. Wavetable Generators


Wavetable generators are discussed in detail in Sect. 8.1.3 of the text [1]. A wavetable is defined by a
circular buffer w whose dimension D is chosen such that the smallest frequency to be generated is:

fmin =

fs
D

D=

fs
fmin

For example, if fs = 8 kHz and the smallest desired frequency is fmin = 10 Hz, then one must choose
D = 8000/10 = 800. The D-dimensional buffer holds one period at the frequency fmin of the desired
waveform to be generated. The shape of the stored waveform is arbitrary, and can be a sinusoid, a square
wave, sawtooth, etc. For example, if it is sinusoidal, then the buffer contents will be:


w[n]= sin

2fmin

fs


n


= sin

2n

n = 0, 1, . . . , D 1

Similarly, a square wave whose first half is +1 and its second half, 1, will be defined as:


w[n]=

+1 ,

if

0 n < D/2

1 ,

if

D/2 n < D

To generate higher frequencies (with the Nyquist frequency fs /2 being the highest), the wavetable is
cycled in steps of c samples, where c is related to the desired frequency by:

f = c fmin = c

fs
D

c=D

f
DF,
fs

F=

f
fs

where F = f /fs is the frequency in units of [cycles/sample]. The generated signal of frequency f and
amplitude A is obtained by the loop:
repeat forever:

y = A w[q]
q = (q + c)mod(D)

(2.1)

The shift c need not be an integer. In such case, the quantity q + c must be truncated to the integer
just below it. The text [1] discusses alternative methods, for example, rounding to the nearest integer,
or, linearly interpolating. For the purposes of this lab, the truncation method will suffice.
The following function, wavgen(), based on Ref. [1], implements this algorithm. The mod-operation
is carried out with the help of the function qwrap():
//
//
//
//

------------------------------------------------wavgen.c - wavetable generator


Usage: y = wavgen(D,w,A,F,&q);
------------------------------------------------

int qwrap(int, int);


float wavgen(int D, float *w, float A, float F, int *q)
{
float y, c=D*F;

2 WAVETABLE GENERATORS, AM/FM MODULATION

21

y = A * w[*q];
*q = qwrap(D-1, (int) (*q+c));
return y;
}
// -------------------------------------------------

We note that the circular index q is declared as a pointer to int, and therefore, must be passed by
address in the calling program. Before using the function, the buffer w must be loaded with one period
of length D of the desired waveform. This function differs from the one in Ref. [1] in that it loads the
buffer in forward order and cycles the index q forward.

2.3. Sinusoidal Wavetable


The following program, sinex.c, generates a 1 kHz sinusoid from a wavetable of length D = 4000. At a
sampling rate of 8 kHz, the smallest frequency that can be generated is fmin = fs /D = 8000/4000 = 2
Hz. In order to generate f = 1 kHz, the step size will be c = D f /fs = 4000 1/8 = 500 samples.
In this example, we will not use the function wavgen but rather apply the generation algorithm of
Eq. (2.1) explicitly. In addition, we will save the output samples in a buffer array of length N = 128 and
inspect the generated waveform both in the time and frequency domains using CCSs graphing capabilities.
// sinex.c - sine wavetable example
//
// 332:348 DSP Lab - Spring 2012 - S. J. Orfanidis
// ---------------------------------------------------------------------------------#include "dsplab.h"
// DSK initialization declarations and function prototypes
#include <math.h>
//#define PI 3.141592653589793
short xL, xR, yL, yR;

// left and right input and output samples from/to codec

#define D 4000
#define N 128

// fmin = fs/D = 8000/4000 = 2 Hz


// buffer length

short fs=8;
float c, A=5000, f=1;
float w[D];
float buffer[N];
int q=0, k=0;

//
//
//
//

fs = 8 kHz
f = 1 kHz
wavetable buffer
buffer for plotting with CCS

// ---------------------------------------------------------------------------------void main()
{
int n;
float PI = 4*atan(1);

// main program executed first

for (n=0; n<D; n++) w[n] = sin(2*PI*n/D);


c = D*f/fs;

// step into wavetable buffer

initialize();

// initialize DSK board and codec, define interrupts

sampling_rate(fs);
// audio_source(LINE);
while(1);
}

// load wavetable with one period

// possible sampling rates: 8, 16, 24, 32, 44, 48, 96 kHz


// LINE or MIC for line or microphone input

// wait for interrupts

2 WAVETABLE GENERATORS, AM/FM MODULATION

22

// ---------------------------------------------------------------------------------interrupt void isr()


{
yL = (short) (A * w[q]);
q = (int) (q+c); if (q >= D) q = 0;

// generate sinusoidal output


// cycle over wavetable in steps c

buffer[k] = (float) yL;


if (++k >= N) k=0;

// save into buffer for plotting


// cycle over buffer

write_outputs(yL,yL);

// audio output

}
// ----------------------------------------------------------------------------------

The wavetable is loaded with the sinusoid in main(). At each sampling instant, the program does
nothing with the codec inputs, rather, it generates a sample of the sinusoid and sends it to the codec,
and saves the sample into a buffer (only the last N generated samples will be in present in that buffer).
Lab Procedure
a. Create a project for this program and run it. The amplitude was chosen to be A = 5000 in order to
make the wavetable output audible. Hold the processor after a couple of seconds (SHIFT-F5).
b. Using the keyboard shortcut, ALT-V RT, or the menu commands View -> Graph -> Time/Frequency,
open a graph-properties window as that shown below:

Select the starting address to be, buffer, set the sampling rate to 8 and look at the time waveform.
Count the number of cycles displayed. Can you predict that number from the fact that N samples
are contained in that buffer? Next right-click on the graph and select Properties, and choose FFT
Magnitude as the plot-type. Verify that the peak is at f = 1 kHz.
c. Reset the frequency to 500 Hz. Repeat parts (a,b).
d. Create a GEL file with a slider for the value of the frequency over the interval 0 f 1 kHz in steps
of 100 Hz. Open the slider and run the program while changing the frequency with the slider.
e. Set the frequency to 30 Hz and run the program. Keep decreasing the frequency by 5 Hz at a time and
determine the lowest frequency that you can hear (but, to be fair dont increase the speaker volume;
that would compensate the attenuation introduced by your ears.)
f. Replace the following two lines in the isr() function:
yL = (short) (A * w[q]);
q = (int) (q+c); if (q >= D) q = 0;

2 WAVETABLE GENERATORS, AM/FM MODULATION

23

by a single call to the function wavgen, and repeat parts (a,b).


g. Replace the sinusoidal table of part (f) with a square wavetable that has period 4000 and is equal to
+1 for the first half of the period and 1 for the second half. Run the program with frequency f = 1
kHz and f = 200 Hz.
h. Next, select the sampling rate to be fs = 96 kHz and for the sinusoid case, start with the frequency
f = 8 kHz and keep increasing it by 2 kHz at a time till about 20 kHz to determine the highest frequency
that you can heareach time repeating parts (a,b).

2.4. AM Modulation
Here, we use two wavetables to illustrate AM modulation. The picture below shows how one wavetable
is used to generate a modulating amplitude signal, which is fed into the amplitude input of a second
wavetable.

Aenv

A(n)

wenv

Fenv

y(n)

F
The AM-modulated signal is of the form:

x(t)= A(t)sin(2f t),

where

A(t)= Aenv sin(2fenv t)

The following program, amex.c, shows how to implement this with the function wavgen(). The
envelope frequency is chosen to be 2 Hz and the signal frequency 200 Hz. A common sinusoidal wavetable
sinusoidal buffer is used to generate both the signal and its sinusoidal envelope.
// amex.c - AM example
// -----------------------------------------------------------------------------------#include "dsplab.h"
// DSK initialization declarations and function prototypes
#include <math.h>
//#define PI 3.141592653589793
short xL, xR, yL, yR;

// left and right input and output samples from/to codec

#define D 8000
float w[D];

// fmin = fs/D = 8000/8000 = 1 Hz


// wavetable buffer

short fs=8;
float A, f=0.2;
float Ae=10000, fe=0.002;
int q, qe;
float wavgen(int, float *, float, float, int *);
// -----------------------------------------------------------------------------------void main()
{
int i;
float PI = 4*atan(1);
q=qe=0;
for (i=0; i<D; i++) w[i] = sin(2*PI*i/D);
initialize();
sampling_rate(fs);
audio_source(LINE);
while(1);

// fill sinusoidal wavetable

2 WAVETABLE GENERATORS, AM/FM MODULATION

24

}
// ------------------------------------------------------------------------------------interrupt void isr()
{
float y;
// read_inputs(&xL, &xR);

// inputs not used

A = wavgen(D, w, Ae, fe/fs, &qe);


y = wavgen(D, w, A, f/fs, &q);
yL = yR = (short) y;
write_outputs(yL,yR);
return;
}
// ------------------------------------------------------------------------------------

Although the buffer is the same for the two wavetables, two different circular indices, q, qe are used
for the generation of the envelope amplitude signal and the carrier signal.
Lab Procedure
a. Run and listen to this program with the initial signal frequency of f = 200 Hz and envelope frequency
of fenv = 2 Hz. Repeat for f = 2000 Hz. Repeat the previous two cases with fenv = 20 Hz.
b. Repeat and explain what you hear for the cases:

f = 200 Hz,
f = 200 Hz,
f = 200 Hz,

fenv = 100 Hz
fenv = 190 Hz
fenv = 200 Hz

2.5. FM Modulation
The third program, fmex.c, illustrates FM modulation in which the frequency of a sinusoid is timevarying. The generated signal is of the form:



x(t)= sin 2f (t)t
The frequency f (t) is itself varying sinusoidally with frequency fm :

f (t)= f0 + Am sin(2fm t)
Its variation is over the interval f0 Am f (t) f0 +Am . In this experiment, we choose the modulation
depth Am = 0.3f0 , so that 0.7f0 f (t) 1.3f0 . The center frequency is chosen as f0 = 500 Hz and the
modulation frequency as fm = 1 Hz. Again two wavetables are used as shown below, with the first one
generating f (t), which then drives the frequency input of the second generator.

2 WAVETABLE GENERATORS, AM/FM MODULATION

25

// fmex.c - FM example
// -----------------------------------------------------------------------------------#include "dsplab.h"
// DSK initialization declarations and function prototypes
#include <math.h>
//#define PI 3.141592653589793
short xL, xR, yL, yR;

// left and right input and output samples from/to codec

#define D 8000
float w[D];

// fmin = fs/D = 8000/8000 = 1 Hz


// wavetable buffer

short fs=8;
float A=5000, f=0.5;
float Am=0.3, fm=0.001;
int q, qm;
float wavgen(int, float *, float, float, int *);
// -----------------------------------------------------------------------------------void main()
{
int i;
float PI = 4*atan(1);
q = qm = 0;
for (i=0; i<D; i++) w[i] = sin(2*PI*i/D);
//for (i=0; i<D; i++) w[i] = (i<D/2)? 1 : -1;

// load sinusoidal wavetable


// square wavetable

initialize();
sampling_rate(fs);
audio_source(LINE);
while(1);
}
// ------------------------------------------------------------------------------------interrupt void isr()
{
float y, F;
// read_inputs(&xL, &xR);

// inputs not used

F = (1 + wavgen(D, w, Am, fm/fs, &qm)) * f/fs;

// modulated frequency

y = wavgen(D, w, A, F, &q);

// FM signal

yL = yR = (short) y;
write_outputs(yL,yR);
return;
}
// ------------------------------------------------------------------------------------

Lab Procedure
a. Compile, run, and hear the program with the following three choices of the modulation depth: Am =
0.3f0 , Am = 0.8f0 , Am = f0 , Am = 0.1f0 . Repeat these cases when the center frequency is changed to
f0 = 1000 Hz.
b. Replace the sinusoidal wavetable with a square one and repeat the case f0 = 500 Hz, Am = 0.3f0 . You

2 WAVETABLE GENERATORS, AM/FM MODULATION

26

will hear a square wave whose frequency switches between a high and a low value in each second.
c. Keep the square wavetable that generates the alternating frequency, but generate the signal by a sinusoidal wavetable. To do this, generate a second sinusoidal wavetable and define a circular buffer for
it in main(). Then generate your FM-modulated sinusoid using this table. The generated signal will
be of the form:


x(t)= sin 2f (t)t ,
f (t)= 1 Hz square wave

2.6. Ring Modulators and Tremolo


Interesting audio effects can be obtained by feeding the audio input to the amplitude of a wavetable
generator and combining the resulting output with the input, as shown below:

For example, for a sinusoidal generator of frequency F0 = f0 /fs , we have:



y(n)= x(n)+x(n)cos(2F0 n)= x(n) + cos(2F0 n)

(2.2)

The ring modulator effect is obtained by setting = 0 and = 1, so that

y(n)= x(n)cos(2F0 n)

(2.3)

whereas, the tremolo effect corresponds to = 1 and = 0



y(n)= x(n)+x(n)cos(2F0 n)= x(n) 1 + cos(2F0 n)

(2.4)

The following ISR function implements either effect:


// ------------------------------------------------------------------------------------interrupt void isr()
{
float x, y;
read_inputs(&xL, &xR);
x = (float) xL;
y = alpha * x + beta * wavgen(D, w, x, f/fs, &q);
yL = yR = (short) y;
write_outputs(yL,yR);
return;
}
// ------------------------------------------------------------------------------------

Lab Procedure
a. Modify the amex.c project to implement the ring modulator/tremolo effect. Set the carrier frequency
to f0 = 400 Hz and = = 1. Compile, run, and play a wavefile with voice in it (e.g., dsummer.)
b. Experiment with higher and lower values of f0 .
c. Repeat part (a) when = 0 and = 1 to hear the ring-modulator effect.

2 WAVETABLE GENERATORS, AM/FM MODULATION

27

2.7. Scrambler as Ring Modulator


In the frequency domain, Eq. (2.3) is equivalent to frequency translation:

Y(f )=

1
X(f f0 )+X(f + f0 )
2

(2.5)

As f0 is chosen closer and closer to the Nyquist frequency fs /2, the shifted replicas begin to resemble
the inverted spectrum of X(f ). In particular, if f0 = fs /2, then,

Y(f )=

1
X(f fs /2)+X(f + fs /2)
2

Using the periodicity property X(f fs )= X(f ), we then obtain the equivalent expressions:

Y(f ) =

0f

1
X(f fs /2 + fs )+X(f + fs /2) = X(f + fs /2) ,
2

Y(f ) =

1
X(f fs /2)+X(f + fs /2 fs ) = X(f fs /2) ,
2

fs
2

fs
2

f 0

which imply that the positive (negative) frequency part of Y(f ) is equal to the negative (positive) frequency part of X(f ), in other words, Y(f ) is the inverted version of X(f ). This is depicted below.

Because in this case F0 = f0 /fs = (fs /2)/fs = 1/2, the carrier waveform is simply the alternating
sequence of 1:
cos(2F0 n)= cos(n)= (1)n
and the modulator output becomes

y(n)= (1)n x(n)

(2.6)

Lab Procedure
Modify the template.c program to implement the frequency-inversion or scrambling operation of
Eq. (2.6). This can be done easily by introducing a global index:
int q = 1;
and keep changing its sign at each interrupt call, i.e., after reading the left/right codec inputs, define the
corresponding codec outputs by:
yL = q * xL;
yR = q * xR;
q = -q;

2 WAVETABLE GENERATORS, AM/FM MODULATION

28

Compile and run this program. Send the wave file JB.wav into it. First comment out the line q = -q,
and hear the file as pass through. Then, enable the line, recompile, and hear the scrambled version of
the file.
The scrambled version was recorded with MATLAB and saved into another wave file, JBm.wav. If you
play that through the scrambler program, it will get unscrambled. In Labs 3 & 4, we will implement the
frequency inversion in alternative ways.

2.8. References
[1] S. J. Orfanidis, Introduction to Signal Processing, online book, 2010, available from:
http://www.ece.rutgers.edu/~orfanidi/intro2sp/
[2] R. Chassaing and D. Reay, Digital Signal Processing and Applications with the TMS320C6713 and
TMS320C6416 DSK, 2nd ed., Wiley, Hoboken, NJ, 2008.
[3] F. R. Moore, Elements of Computer Music, Prentice Hall, Englewood Cliffs, NJ, 1990.
[4] C. Dodge and T. A. Jerse, Computer Music, Schirmer/Macmillan, New York, 1985.
[5] J. M. Chowning, The Synthesis of Complex Audio Spectra by Means of Frequency Modulation, J.
Audio Eng. Soc., 21, 526 (1973).
[6] M. Kahrs and K. Brandenburg, eds., Applications of Digital Signal Processing to Audio and Acoustics,
Kluwer, Boston, 1998.
[7] Udo Z
olzer, ed., DAFX Digital Audio Effects, Wiley, Chichester, England, 2003. See also the DAFX
Conference web page: http://www.dafx.de/.

You might also like