Skip to content

Commit ddfe104

Browse files
committed
Working clarinet example
1 parent 9f8a4db commit ddfe104

File tree

4 files changed

+457
-1
lines changed

4 files changed

+457
-1
lines changed

Filters.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,43 @@ def freqz(self):
4040
return freqz(self.b, self.a)
4141

4242

43+
class OneZeroFilter:
44+
def __init__(self, zero=-1.0):
45+
self.in1 = self.in2 = self.out1 = 0.0
46+
self.set_zero(zero)
47+
48+
def tick(self, in_sample):
49+
self.in1 = in_sample
50+
self.out1 = self.b1 * self.in2 + self.b0 * self.in1
51+
self.in2 = self.in1
52+
53+
return self.out1
54+
55+
def set_zero(self, zero):
56+
# Normalize coefficients for unity gain
57+
self.b0 = 1.0 / (1.0 + zero) if zero > 0 else 1.0 / (1.0 - zero)
58+
self.b1 = -zero * self.b0
59+
60+
# TODO could be broken
61+
def phase_delay(self, frequency, fs=44100):
62+
omega_t = 2 * np.pi * frequency / fs
63+
real = 0.0
64+
imag = 0.0
65+
real += self.b0 * np.cos(0)
66+
imag -= self.b0 * np.sin(0)
67+
real += self.b1 * np.cos(omega_t)
68+
imag += self.b1 * np.sin(omega_t)
69+
phase = np.arctan2(imag, real)
70+
phase = -phase % (2 * np.pi)
71+
return phase / omega_t
72+
73+
def set_coefficients(self, b0, b1):
74+
self.b0 = b0
75+
self.b1 = b1
76+
77+
def clear(self):
78+
self.in1 = self.in2 = self.out1 = 0.0
79+
4380
# One-pole lowpass with feedback coefficient of 0.5
4481
class OnePoleFilter:
4582
def __init__(self, g=0.5, p=0.5):
@@ -52,6 +89,8 @@ def tick(self, in_sample):
5289
self.z_1 = out_sample
5390
return out_sample
5491

92+
def clear(self):
93+
self.z_1 = 0.0
5594

5695
class TwoZeroFilter:
5796
def __init__(self):

Generators.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import numpy as np
2+
13
class ImpulseGenerator:
24
def __init__(self):
35
self.is_first_sample = True
@@ -11,8 +13,27 @@ def reset(self):
1113
self.is_first_sample = True
1214

1315
class NoiseGenerator:
16+
def __init__(self, gain=1.0):
17+
self.gain = gain
18+
1419
def tick(self):
15-
return np.random.uniform(low=-1.0, high=1.0)
20+
return self.gain * np.random.uniform(low=-1.0, high=1.0)
1621

1722
def reset(self):
1823
return self
24+
25+
# Very naive implementation
26+
class SineGenerator:
27+
def __init__(self, fs=44100):
28+
self.fs = fs
29+
self.frequency = 1.0
30+
self.amplitude = 1.0
31+
self.t_radians = 0.0
32+
33+
def tick(self):
34+
out_sample = self.amplitude * np.sin(self.t_radians)
35+
self.t_radians += 2 * np.pi * self.frequency / self.fs
36+
return out_sample
37+
38+
def set_frequency(self, frequency):
39+
self.frequency = frequency

physical_audio_signal_processing/chapter_9_virtual_musical_instruments_part_3.ipynb

Lines changed: 396 additions & 0 deletions
Large diffs are not rendered by default.
Binary file not shown.

0 commit comments

Comments
 (0)