Previous Section | Next Section | Table of Contents | Index | Title Page

Linear Prediction Analysis and Synthesis

Nyquist provides functions to perform Linear Prediction Coding (LPC) analysis and synthesis. In simple terms, LPC analysis assumes that a sound is the result of an all-pole filter applied to a source with a flat spectrum. LPC is good for characterizing the general spectral shape of a signal, which may be time-varying as in speech sounds. For synthesis, any source can be filtered, allowing the general spectral shape of one signal (used in analysis) to be applied to any source (used in synthesis). A popular effect is to give vowel-like spectra to musical tones, creating an artificial (or sometimes natural) singing voice.

Examples of LPC analysis and synthesis can be found in the file nyquist/lib/lpc/lpc_tutorial.html, which is part of the standard Nyquist release.

As with FFT processing, LPC analysis takes a sound as input and returns a stream of frames. Frames are returned from an object using the :next selector just as with FFT frames. An LPC frame is a list consisting of: RMS1, the energy of the input signal, RMS2, the energy of the residual signal, ERR, the square root of RMS1/RMS2, and FILTER-COEFS, an array of filter coefficients. To make code more readable and to avoid code dependence on the exact format of a frame, the functions lpc-frame-rms1, lpc-frame-rms2, lpc-frame-err, and lpc-frame-filter-coefs can be applied to a frame to obtain the respective fields.

The z transform of the filter is H(z) = 1/A(z), where A(z) is a polynomial of the form A(z) = 1 + a1z-1 + a2z-2 + ... + apz-p. The FILTER-COEFS array has the form #(ap ap-1 ... a3 a2 a1).

The file lpc.lsp defines some useful classes and functions. The file is not automatically loaded with Nyquist, so you must execute (load "lpc") before using them.

LPC Classes and Functions

make-lpanal-iterator(sound, framedur, skiptime, npoles) [SAL]
(make-lpanal-iterator sound framedur skiptime npoles) [LISP]
Makes an iterator object, an instance of lpanal-class, that returns LPC frames from successive frames of samples in sound. The duration (in seconds) of each frame is given by framedur, a FLONUM. The skip size (in seconds) between successive frames is given by skiptime, a FLONUM. Typical values for framedur and skiptime are 0.08 and 0.04, giving 25 frames per second and a 50% frame overlap. The number of poles is given by npoles, a FIXNUM. The result is an object that responds to the :next selector by returning a frame as described above. NIL is returned when sound terminates. (Note that one or more of the last analysis windows may be padded with zeros. NIL is only returned when the corresponding window would begin after the termination time of the sound.)

make-lpc-file-iterator(filename) [SAL]
(make-lpc-file-iterator filename) [LISP]
Another way to get LPC frames is to read them from a file. This function opens an ASCII file containing LPC frames and creates an iterator object, an instance of class lpc-file-class to access them. Create a file using save-lpc-file (see below).

save-lpc-file(lpc-iterator, filename) [SAL]
(save-lpc-file lpc-iterator filename) [LISP]
Create a file containing LPC frames. This file can be read by make-lpc-file-iterator (see above).

show-lpc-data(lpc-iterator, iniframe, endframe [, poles?]) [SAL]
(show-lpc-data lpc-iterator iniframe endframe [poles?]) [LISP]
Print values of LPC frames from an LPC iterator object. The object is lpc-iterator, which is typically an instance of lpanal-class or lpc-file-class. Frames are numbered from zero, and only files starting at iniframe (a FIXNUM) and ending before endframe (also a FIXNUM) are printed. By default, only the values for RMS1, RMS2, and ERR are printed, but if optional parameter poles? is non-NIL, then the LPC coefficients are also printed.

allpoles-from-lpc(snd, lpc-frame) [SAL]
(allpoles-from-lpc snd lpc-frame) [LISP]
A single LPC frame defines a filter. Use allpoles-from-lpc to apply this filter to snd, a SOUND. To obtain lpc-frame, a LIST containing an LPC frame, either send :next to an LPC iterator, or use nth-frame (see below). The result is a SOUND whose duration is the same as that of snd.

nth-frame(lpc-iterator, numframe) [SAL]
(nth-frame lpc-iterator numframe) [LISP]
Get the nth frame from an lpc iterator by skipping n frames and getting the next one. Typical use is to construct a filter using the nth frame from an LPC data file using something like this to filter snd: allpoles-from-lpc(snd, nth-frame(make-lpc-file-iterator(filename), n)).

lpreson(snd, lpc-iterator, skiptime) [SAL]
(lpreson snd lpc-iterator skiptime) [LISP]
Implements a time-varying all-pole filter controlled by a sequence of LPC frames from an iterator. The SOUND to be filtered is snd, and the source of LPC frames is lpc-iterator, typically an instance of lpanal-class or lpc-file-class. The frame period (in seconds) is given by skiptime (a FLONUM). This number does not have to agree with the skiptime used to analyze the frames. (Greater values will cause the filter evolution slow down, and smaller values will cause it to speed up.) The result is a SOUND. The duration of the result is the minimum of the duration of snd and that of the sequence of frames.

lpc-frame-rms1(frame) [SAL]
(lpc-frame-rms1 frame) [LISP]
Get the energy of the input signal from a frame.

lpc-frame-rms2(frame) [SAL]
(lpc-frame-rms2 frame) [LISP]
Get the energy of the residual from a frame.

lpc-frame-err(frame) [SAL]
(lpc-frame-err frame) [LISP]
Get the square root of RMS1/RMS2 from a frame.

lpc-frame-filter-coefs(frame) [SAL]
(lpc-frame-filter-coefs frame) [LISP]
Get the filter coefficients from a frame.

Low-level LPC Functions

The lowest-level Nyquist functions for LPC are

snd-lpanal(samps, npoles) [SAL]
(snd-lpanal samps npoles) [LISP]
Compute an LPC frame with npoles (a FIXNUM) poles from an ARRAY of samples (FLONUMS). Note that snd-fetch-array can be used to fetch a sequence of frames from a sound. Ordinarily, you should not use this function. Use make-lpanal-iterator instead.

snd-allpoles(snd, lpc-coefs, gain) [SAL]
(snd-allpoles snd lpc-coefs gain) [LISP]
A fixed all-pole filter. The input is snd, a SOUND. The filter coefficients are given by lpc-coefs (an ARRAY), and the filter gain is given by gain, a FLONUM. The result is a SOUND whose duration matches that of snd. Ordinarily, you should use allpoles-from-lpc instead (see above).

snd-lpreson(snd, lpc-iterator, skiptime) [SAL]
(snd-lpreson snd lpc-iterator skiptime) [LISP]
This function is identical to lpreson (see above).

Previous Section | Next Section | Table of Contents | Index | Title Page