Skip to content

nlalp

Filters an audio signal with a nonlinear first-order all-pass structure.

Use nlalp to add harmonics or change a signal's phase with a small feedback filter. Its controls are coefficients, not frequencies in Hz.

Syntax

aout = nlalp(ain, klinear, knonlinear [, istor])
aout nlalp ain, klinear, knonlinear [, istor]

Initialization

istor is optional and defaults to 0. Zero clears the internal filter state at initialization. A nonzero value skips that clearing.

Performance

ain is the audio input and aout is the audio output.

klinear scales the signed internal signal. knonlinear scales its absolute value. Both coefficients run at control rate. The absolute-value term treats positive and negative values differently and can add harmonics to the input.

With knonlinear set to 0 and a fixed klinear between -1 and 1, the filter is a linear first-order all-pass filter. It changes phase while preserving the magnitude of each frequency in steady state. With a nonzero nonlinear coefficient, do not expect that flat magnitude response or unchanged peak levels.

Keep abs(klinear) + abs(knonlinear) < 1 as a sufficient condition for stable feedback. This keeps both internal slopes, klinear + knonlinear and klinear - knonlinear, strictly between -1 and 1. The opcode does not enforce this limit. Coefficients near the boundary can produce large internal values and long transients.

The nonlinear path is an absolute-value calculation, not a saturating clipper. Raising the input level alone does not act like increasing a distortion drive control. Use knonlinear to change the nonlinear effect and leave room for output peaks. The opcode does not remove harmonics above half the sample rate, so strong nonlinear settings can cause aliasing.

Filter calculation

For each input sample, the filter computes an internal value v and a feedback value f. The subscript previous means the value from the preceding sample.

v = input - f_previous
f = klinear*v + knonlinear*abs(v)
output = v_previous + f

When knonlinear is 0 and klinear is constant, this gives the usual first-order all-pass transfer function.

H(z) = (klinear + z^-1) / (1 + klinear*z^-1)

Examples

The example plays a 1000 Hz sine tone twice. The first note uses the linear filter. The second keeps the same linear coefficient and adds a nonlinear coefficient of 0.6, which adds overtones. An output envelope avoids clicks at the start and end of each note.

It uses nlalp.csd.

Compare linear and nonlinear filtering
<CsoundSynthesizer>
<CsOptions>
-d -odac
</CsOptions>
<CsInstruments>
sr = 48000
ksmps = 32
nchnls = 1
0dbfs = 1

instr CompareFilter
  aInput = oscili(0.15, 1000)
  kLinear = -0.2
  kNonlinear = p4

  ; The sum of the coefficient magnitudes stays below 1.
  aFiltered = nlalp(aInput, kLinear, kNonlinear)
  aEnvelope = linseg(0, 0.02, 1, p3 - 0.04, 1, 0.02, 0)
  out(aFiltered * aEnvelope)
endin
</CsInstruments>
<CsScore>
; First hear the linear case, then the added nonlinear term.
i "CompareFilter" 0   2 0
i "CompareFilter" 2.5 2 0.6
e
</CsScore>
</CsoundSynthesizer>

See also

phaser1, alpass, nlfilt, Specialized filters, Waveshaping

Credits

Author Jens Groh.