## 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` for analysis,
• `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)` [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).