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
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
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,
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 +
a2z + ... + apz. The FILTER-COEFS array has
#(ap ap-1 ... a3
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.
make-lpanal-iterator(sound, framedur, skiptime, npoles)[SAL]
(make-lpanal-iterator sound framedur skiptime npoles)[LISP]
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
:nextselector by returning a frame as described above.
NILis returned when sound terminates. (Note that one or more of the last analysis windows may be padded with zeros.
NILis only returned when the corresponding window would begin after the termination time of the sound.)
lpc-file-classto access them. Create a file using
(save-lpc-file lpc-iterator filename)[LISP]
show-lpc-data(lpc-iterator, iniframe, endframe [, poles?])[SAL]
(show-lpc-data lpc-iterator iniframe endframe [poles?])[LISP]
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)[LISP]
allpoles-from-lpcto apply this filter to snd, a
SOUND. To obtain lpc-frame, a
LISTcontaining an LPC frame, either send
:nextto an LPC iterator, or use
nth-frame(see below). The result is a
SOUNDwhose duration is the same as that of snd.
lpreson(snd, lpc-iterator, skiptime)[SAL]
(lpreson snd lpc-iterator skiptime)[LISP]
SOUNDto be filtered is snd, and the source of LPC frames is lpc-iterator, typically an instance of
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.
The lowest-level Nyquist functions for LPC are
snd-allpoles, an all-pole filter with fixed coefficients, and
snd-lpreson, an all-pole filter that takes frames from an LPC iterator.
(snd-lpanal samps npoles)[LISP]
FIXNUM) poles from an
ARRAYof samples (
FLONUMS). Note that
snd-fetch-arraycan be used to fetch a sequence of frames from a sound. Ordinarily, you should not use this function. Use
snd-allpoles(snd, lpc-coefs, gain)[SAL]
(snd-allpoles snd lpc-coefs gain)[LISP]
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
SOUNDwhose duration matches that of snd. Ordinarily, you should use
allpoles-from-lpcinstead (see above).
snd-lpreson(snd, lpc-iterator, skiptime)[SAL]
(snd-lpreson snd lpc-iterator skiptime)[LISP]