And now, for completeness, let's have an IIR (infinite Impulse Response) filter. Those digital filters calculate the output signal based not only on past input signals, but also on past output signals.
In other words, there is a feedback component on IIR output. This filter may generate output forever, even if the input signal is cut, hence the "infinite" quality.
An IIR filter can be expressed by a difference equation, which defines output in terms of previous outputs, as well as inputs. A very popular example of difference equation is the Fibonacci sequence:
Fib(n) = Fib(n-1) + Fib(n-2)
In digital filtering, we are more interested in difference equations that are stable, that is, tend to zero as the input fades away.
Since a functional IIR filter can be defined by a very simple difference equation, like the Fibonacci series above, it can do a lot using little computational power. In this sense, IIR is much more powerful than FIR.
The following example is a kind of resonator that enhances frequency response around 2000Hz (any other value could be chosen just by changing the source code).
The "r" factor is the resonance power. If you make r=1, it becomes an oscilator tuned to 2000Hz. If you make r > 1, it becomes exponential and useless.
#!/usr/bin/env python
import wave, struct, math
SAMPLE_RATE = 44100
original = wave.open("NubiaCantaDalva.wav", "r")
filtered = wave.open("NubiaFilteredIIR.wav", "w")
filtered.setnchannels(1)
filtered.setsampwidth(2)
filtered.setframerate(SAMPLE_RATE)
# IIR filter coefficients
freq = 2000 # Hz
r = 0.98
a1 = -2.0 * r * math.cos(freq / (SAMPLE_RATE / 2.0) * math.pi)
a2 = r * r
filter = [a1, a2]
print filter
n = original.getnframes()
original = struct.unpack('%dh' % n, original.readframes(n))
original = [s / 2.0**15 for s in original]
result = [ 0 for i in range(0, len(filter)) ]
biggest = 1
for sample in original:
for cpos in range(0, len(filter)):
sample -= result[len(result) - 1 - cpos] * filter[cpos]
result.append(sample)
biggest = max(abs(sample), biggest)
result = [ sample / biggest for sample in result ]
result = [ int(sample * (2.0**15 - 1)) for sample in result ]
filtered.writeframes(struct.pack('%dh' % len(result), *result))
Let's see how it sounds. First the original content, then the filtered version: