Skip to content

Commit

Permalink
Working clarinet example
Browse files Browse the repository at this point in the history
  • Loading branch information
khiner committed Dec 15, 2019
1 parent 9f8a4db commit ddfe104
Show file tree
Hide file tree
Showing 4 changed files with 457 additions and 1 deletion.
39 changes: 39 additions & 0 deletions Filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,43 @@ def freqz(self):
return freqz(self.b, self.a)


class OneZeroFilter:
def __init__(self, zero=-1.0):
self.in1 = self.in2 = self.out1 = 0.0
self.set_zero(zero)

def tick(self, in_sample):
self.in1 = in_sample
self.out1 = self.b1 * self.in2 + self.b0 * self.in1
self.in2 = self.in1

return self.out1

def set_zero(self, zero):
# Normalize coefficients for unity gain
self.b0 = 1.0 / (1.0 + zero) if zero > 0 else 1.0 / (1.0 - zero)
self.b1 = -zero * self.b0

# TODO could be broken
def phase_delay(self, frequency, fs=44100):
omega_t = 2 * np.pi * frequency / fs
real = 0.0
imag = 0.0
real += self.b0 * np.cos(0)
imag -= self.b0 * np.sin(0)
real += self.b1 * np.cos(omega_t)
imag += self.b1 * np.sin(omega_t)
phase = np.arctan2(imag, real)
phase = -phase % (2 * np.pi)
return phase / omega_t

def set_coefficients(self, b0, b1):
self.b0 = b0
self.b1 = b1

def clear(self):
self.in1 = self.in2 = self.out1 = 0.0

# One-pole lowpass with feedback coefficient of 0.5
class OnePoleFilter:
def __init__(self, g=0.5, p=0.5):
Expand All @@ -52,6 +89,8 @@ def tick(self, in_sample):
self.z_1 = out_sample
return out_sample

def clear(self):
self.z_1 = 0.0

class TwoZeroFilter:
def __init__(self):
Expand Down
23 changes: 22 additions & 1 deletion Generators.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import numpy as np

class ImpulseGenerator:
def __init__(self):
self.is_first_sample = True
Expand All @@ -11,8 +13,27 @@ def reset(self):
self.is_first_sample = True

class NoiseGenerator:
def __init__(self, gain=1.0):
self.gain = gain

def tick(self):
return np.random.uniform(low=-1.0, high=1.0)
return self.gain * np.random.uniform(low=-1.0, high=1.0)

def reset(self):
return self

# Very naive implementation
class SineGenerator:
def __init__(self, fs=44100):
self.fs = fs
self.frequency = 1.0
self.amplitude = 1.0
self.t_radians = 0.0

def tick(self):
out_sample = self.amplitude * np.sin(self.t_radians)
self.t_radians += 2 * np.pi * self.frequency / self.fs
return out_sample

def set_frequency(self, frequency):
self.frequency = frequency

Large diffs are not rendered by default.

Binary file not shown.

0 comments on commit ddfe104

Please sign in to comment.