"""
05-convolution-filters.py - Circular convolution.

A circular convolution is defined as the integral of the
product of two functions after one is reversed and shifted.

Circular convolution allows to implement very complex FIR
filters, at a CPU cost that is related to the filter impulse
response (kernel) length.

Within pyo, there is a family of IR* filter objects using
circular convolution with predefined kernel:

- IRAverage : moving average filter
- IRFM : FM-like filter
- IRPulse : comb-like filter
- RWinSinc : break wall filters (lp, hp, hp, br)

For general circular convolution, use the Convolve object
with a PyoTableObject as the kernel, as in this example:

A white noise is filtered by four impulses taken from the input mic. 

Call r1.play(), r2.play(), r3.play() or r4.play() in the Interpreter 
field while making some noise in the mic to fill the impulse response 
tables. The slider handles the morphing between the four kernels.

Call t1.view(), t2.view(), t3.view() or t4.view() to view impulse 
response tables.

Because circular convolution is very expensive, TLEN (in samples) 
should be keep small.

"""
from pyo import *

# duplex=1 to tell the Server we need both input and output sounds.
s = Server(duplex=1).boot()

# Length of the impulse response in samples.
TLEN = 512

# Conversion to seconds for NewTable objects.
DUR = sampsToSec(TLEN)

# Excitation signal for the filters.
sf = Noise(.5)

# Signal from the mic to record the kernels.
inmic = Input()

# Four tables and recorders.
t1 = NewTable(length=DUR, chnls=1)
r1 = TableRec(inmic, table=t1, fadetime=.001)

t2 = NewTable(length=DUR, chnls=1)
r2 = TableRec(inmic, table=t2, fadetime=.001)

t3 = NewTable(length=DUR, chnls=1)
r3 = TableRec(inmic, table=t3, fadetime=.001)

t4 = NewTable(length=DUR, chnls=1)
r4 = TableRec(inmic, table=t4, fadetime=.001)

# Interpolation control between the tables.
pha = Sig(0)
pha.ctrl(title="Impulse responses morphing")

# Morphing between the four impulse responses.
res = NewTable(length=DUR, chnls=1)
morp = TableMorph(pha, res, [t1,t2,t3,t4])

# Circular convolution between the excitation and the morphed kernel.
a = Convolve(sf, table=res, size=res.getSize(), mul=.1).mix(2).out()

s.gui(locals())
