|
|
|
@@ -8,7 +8,7 @@ from itertools import izip |
|
|
|
import numpy as np |
|
|
|
from scipy.signal import lfilter |
|
|
|
|
|
|
|
__all__ = ['YSynth', 'Sin', 'Cos', 'Saw', 'RevSaw', 'Square', 'Pulse'] |
|
|
|
__all__ = ['YSynth', 'Sin', 'Cos', 'Saw', 'RevSaw', 'Square', 'Pulse', 'WhiteNoise'] |
|
|
|
|
|
|
|
class YSynth(object): |
|
|
|
""" |
|
|
|
@@ -269,14 +269,35 @@ class Divisor(YAudioGraphNode): |
|
|
|
yield a / b |
|
|
|
|
|
|
|
# Sample delay |
|
|
|
# Currently uses a fixed buffer of 4096 samples |
|
|
|
# should support dynamic buffer size in the future |
|
|
|
class Delay(YAudioGraphNode): |
|
|
|
def __call__(self, l): |
|
|
|
buf = [0.0] * 4096 |
|
|
|
buf = None |
|
|
|
samples = 0 |
|
|
|
|
|
|
|
for sig, delay in l: |
|
|
|
buf[samples] = sig |
|
|
|
yield buf[(samples - delay) % 4096] |
|
|
|
samples = (samples + 1) % 4096 |
|
|
|
if buf is None: |
|
|
|
if len(sig.shape) == 2: |
|
|
|
buf = np.zeros((4096, sig.shape[1])) |
|
|
|
else: |
|
|
|
buf = np.zeros((4096,)) |
|
|
|
|
|
|
|
# Update delay buffer |
|
|
|
if samples + self.synth.chunk_size > buf.shape[0]: |
|
|
|
s_left = buf.shape[0] - samples |
|
|
|
buf[samples:] = sig[:s_left] |
|
|
|
buf[:self.synth.chunk_size - s_left] = sig[s_left:] |
|
|
|
else: |
|
|
|
buf[samples:samples + self.synth.chunk_size] = sig |
|
|
|
|
|
|
|
# Construct delayed signal from delay input |
|
|
|
delayed_idx = np.array((np.arange(samples, samples + |
|
|
|
self.synth.chunk_size) - delay) % buf.shape[0], dtype=int) |
|
|
|
yield buf[delayed_idx] |
|
|
|
|
|
|
|
# Finally update sample pointer |
|
|
|
samples = (samples + self.synth.chunk_size) % buf.shape[0] |
|
|
|
|
|
|
|
# Base oscillator class |
|
|
|
class YOscillator(YAudioGraphNode): |
|
|
|
@@ -319,6 +340,14 @@ class YOscillator(YAudioGraphNode): |
|
|
|
def oscillate(self, l): |
|
|
|
raise NotImplementedError("Inherit this class") |
|
|
|
|
|
|
|
# Noise signals |
|
|
|
# XXX: I am probably not White Noise, fix me |
|
|
|
# up at a later time. |
|
|
|
class WhiteNoise(YAudioGraphNode): |
|
|
|
def __call__(self, l): |
|
|
|
while True: |
|
|
|
yield np.random.rand(self.synth.chunk_size) |
|
|
|
|
|
|
|
# Basic oscillators |
|
|
|
class Sin(YOscillator): |
|
|
|
""" |
|
|
|
@@ -372,3 +401,10 @@ class Pulse(YOscillator): |
|
|
|
pos, zi = lfilter([-1, 1], [1], pos, zi=zi) |
|
|
|
yield np.array(pos > 0, dtype=float) |
|
|
|
|
|
|
|
# Flanger effect |
|
|
|
class Flanger(YAudioGraphNode): |
|
|
|
""" |
|
|
|
Perform virtual tape flange by mixing the |
|
|
|
input signal with a delayed version. |
|
|
|
""" |
|
|
|
|