Skip to content

Commit a682b42

Browse files
committed
fir filtering demo
1 parent 32e5d9e commit a682b42

2 files changed

Lines changed: 122 additions & 68 deletions

File tree

tests/circuitpython-manual/synthio/note/fir.py

Lines changed: 17 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -9,96 +9,45 @@
99
import synthio
1010
from ulab import numpy as np
1111
import adafruit_wave as wave
12+
import mkfilter
1213

1314
random.seed(9)
1415

1516
envelope = synthio.Envelope(
1617
attack_time=0.1, decay_time=0.05, release_time=0.2, attack_level=0.8, sustain_level=0.8
1718
)
1819

19-
h = np.array(
20-
[
21-
-0.001229734800309099,
22-
-0.008235561806605458,
23-
-0.015082497016061390,
24-
-0.020940136918319988,
25-
-0.024981800822463429,
26-
-0.026464233332370746,
27-
-0.024803890156806906,
28-
-0.019642276775473012,
29-
-0.010893620860173042,
30-
0.001230341899766145,
31-
0.016221637398855598,
32-
0.033304135659230648,
33-
0.051486665261155681,
34-
0.069636961761409016,
35-
0.086570197432542767,
36-
0.101144354207918147,
37-
0.112353938422488253,
38-
0.119413577288191297,
39-
0.121823886314051028,
40-
0.119413577288191297,
41-
0.112353938422488253,
42-
0.101144354207918147,
43-
0.086570197432542767,
44-
0.069636961761409016,
45-
0.051486665261155681,
46-
0.033304135659230648,
47-
0.016221637398855598,
48-
0.001230341899766145,
49-
-0.010893620860173042,
50-
-0.019642276775473012,
51-
-0.024803890156806906,
52-
-0.026464233332370746,
53-
-0.024981800822463429,
54-
-0.020940136918319988,
55-
-0.015082497016061390,
56-
-0.008235561806605458,
57-
-0.001229734800309099,
58-
]
59-
)
60-
61-
filter_coeffs = np.array(h[::-1] * 32768, dtype=np.int16)
20+
SAMPLE_SIZE = 1024
21+
bend_out = np.linspace(0, 32767, num=SAMPLE_SIZE, endpoint=True, dtype=np.int16)
6222

63-
synth = synthio.Synthesizer(sample_rate=48000, filter=filter_coeffs)
23+
filter_rectangular = mkfilter.LPF(48000, 800, 13)
24+
filter_rectangular_big = mkfilter.LPF(48000, 800, 59)
25+
filter_blackman = mkfilter.LPF(48000, 800, 59, win=mkfilter.blackman)
26+
print(filter_blackman)
6427

6528

6629
def synthesize(synth):
6730
n = synthio.Note(
6831
frequency=120,
6932
envelope=envelope,
70-
filter=False,
33+
filter=True,
34+
bend=synthio.LFO(bend_out, once=True, rate=1 / 2, scale=5),
7135
)
7236

37+
synth.press(n)
7338
print(synth, n)
74-
synth.press((n,))
75-
for _ in range(20):
76-
n.frequency *= 1.0595
77-
yield 36
39+
yield 2 * 48000 // 256
7840
synth.release_all()
7941
yield 36
8042

81-
n.filter = True
82-
n.frequency = 120
83-
synth.press((n,))
84-
for _ in range(20):
85-
n.frequency *= 1.0595
86-
yield 36
87-
synth.release_all()
88-
yield 36
89-
90-
91-
def chain(*args):
92-
for a in args:
93-
yield from a
94-
9543

96-
# sox -r 48000 -e signed -b 16 -c 1 tune.raw tune.wav
9744
with wave.open("fir.wav", "w") as f:
9845
f.setnchannels(1)
9946
f.setsampwidth(2)
10047
f.setframerate(48000)
101-
for n in chain(synthesize(synth)):
102-
for i in range(n):
103-
result, data = audiocore.get_buffer(synth)
104-
f.writeframes(data)
48+
for filter_coeffs in [None, filter_rectangular, filter_rectangular_big, filter_blackman]:
49+
synth = synthio.Synthesizer(sample_rate=48000, filter=filter_coeffs)
50+
for n in synthesize(synth):
51+
for i in range(n):
52+
result, data = audiocore.get_buffer(synth)
53+
f.writeframes(data)
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
try:
2+
from ulab import numpy as np
3+
except ImportError:
4+
import numpy as np
5+
6+
7+
def lpf(fS, f, N, win=lambda N: 1):
8+
if not (N & 1):
9+
raise ValueError("filter length must be odd")
10+
h = np.sinc(2 * f / fS * (np.arange(N) - (N - 1) / 2))
11+
h = h * win(N)
12+
return h * (1 / np.sum(h))
13+
14+
15+
def hpf(fS, f, N, win=lambda N: 1):
16+
if not (N & 1):
17+
raise ValueError("filter length must be odd")
18+
h = -lpf(fS, f, N)
19+
h = h * win(N)
20+
h[(N - 1) // 2] += 1
21+
return h
22+
23+
24+
def brf(fS, fL, NL, fH, NH, win=lambda N: 1):
25+
hlpf = lpf(fS, fL, NL, win)
26+
hhpf = hpf(fS, fH, NH, win)
27+
28+
if NH > NL:
29+
h = hhpf
30+
h[(NH - NL) // 2 : (NH - NL) // 2 + NL] += hlpf
31+
else:
32+
h = hlpf
33+
h[(NL - NH) // 2 : (NL - NH) // 2 + NH] += hhpf
34+
35+
return h
36+
37+
38+
def bpf(fS, fL, NL, fH, NH, win=lambda N: 1):
39+
hlpf = lpf(fS, fL, NL, win)
40+
hhpf = hpf(fS, fH, NH, win)
41+
return np.convolve(hlpf, hhpf)
42+
43+
44+
def blackman(M):
45+
n = np.arange(1 - M, M, 2)
46+
return 0.42 + 0.5 * np.cos(np.pi * n / (M - 1)) + 0.08 * np.cos(2.0 * np.pi * n / (M - 1))
47+
48+
49+
def tosynthio(coeffs):
50+
result = np.array(coeffs * 32767, dtype=np.int16)
51+
return trim_zeros(result)
52+
53+
54+
def trim_zeros(arr):
55+
i = 0
56+
j = len(arr) - 1
57+
while i < len(arr) and arr[i] == 0:
58+
i += 1
59+
while j > i and arr[j] == 0:
60+
j -= 1
61+
return arr[i : j + 1]
62+
63+
64+
# fiiir.com uses factor 4.6 for blackman window, 0.91 for rectangular
65+
def ntaps(fS, fB, factor=4.6):
66+
b = fB / fS
67+
return round(factor / b) | 1
68+
69+
70+
def LPF(*args, **kw):
71+
return tosynthio(lpf(*args, **kw))
72+
73+
74+
def HPF(*args, **kw):
75+
return tosynthio(hpf(*args, **kw))
76+
77+
78+
def BRF(*args, **kw):
79+
return tosynthio(brf(*args, **kw))
80+
81+
82+
def BPF(*args, **kw):
83+
return tosynthio(bpf(*args, **kw))
84+
85+
86+
if __name__ == "__main__":
87+
print("lpf(24000, 2040, 13) # 1920Hz transition window")
88+
print(list(lpf(24000, 2040, 13)))
89+
90+
print("hpf(24000, 9600, 13) # 960Hz transition window")
91+
print(list(hpf(24000, 9600, 23)))
92+
93+
print("bpf(24000, 1200, 11, 3960, 15) # 2400Hz, 1600Hz transition windows")
94+
print(list(bpf(24000, 1200, 11, 3960, 15)))
95+
96+
print("brf(24000, 960, 19, 2400, 13) # 1200, 1800Hz transition windows")
97+
brf_tst = brf(24000, 960, 19, 2400, 13)
98+
print(brf_tst)
99+
100+
print("brf(24000, 960, 13, 2400, 19) # 1200, 1800Hz transition windows")
101+
brf_tst = brf(24000, 960, 13, 2400, 19)
102+
print(brf_tst)
103+
104+
print("lpf(1, 0.1, 59, blackman) # 1920Hz transition window, blackman")
105+
print(lpf(1, 0.1, 59, blackman))

0 commit comments

Comments
 (0)