Created
October 11, 2013 18:59
-
-
Save danilobellini/6940208 to your computer and use it in GitHub Desktop.
A Hard Day's Night first chord with AudioLazy + PyAudio
(Based on an example from the Coursera DSP course)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
# Created on Thu Oct 10 15:29:33 2013 | |
# @author: Danilo J. S. Bellini | |
""" | |
A Hard Day's Night first chord with AudioLazy + PyAudio | |
""" | |
from audiolazy import (white_noise, rint, freq_to_lag, zeros, comb, sHz, | |
str2freq, AudioIO) | |
def truncated_karplus_strong(freq, tau, memory=white_noise): | |
""" | |
Karplus-Strong algorithm. | |
Parameters | |
---------- | |
freq: | |
Frequency, in rad/sample. | |
tau: | |
Time, in samples, until decaying from 1 to 1/e in amplitude (approx. | |
-8.686 dB). You can find ``tau`` from half-power decay duration with | |
``tau = halfpower_decay * dB20(1/e) / dB10(.5)``. | |
memory: | |
Past memory in the Karplus-Strong comb filter. Original algorithm | |
proposes random data (white noise). Defaults to uniformly distributed | |
white noise from -1 to 1. | |
Returns | |
------- | |
A Stream object with the played tune. | |
Note | |
---- | |
This function truncates the frequency to the nearest integer lag. Decay | |
time (in samples) doesn't need to be integer. | |
""" | |
rounded_lag = rint(freq_to_lag(freq)) | |
filt = comb.tau(rounded_lag, tau) | |
return filt(zeros(), memory=memory) | |
# Initialization | |
rate = 48000 | |
s, Hz = sHz(rate) | |
ms = 1e-3 * s | |
# Synth model parameters | |
tau = 626.7 * ms # 217.2 * ms half-power decay | |
# Original tau was approx. 626.698490797 * ms | |
memory = white_noise(low=0, high=1) # No negative value: DC level isn't zero | |
ks = lambda freq: truncated_karplus_strong(freq, tau=tau, memory=memory) | |
# Synthesizes the chord | |
pitches = "D2 D3 F3 G3 F4 A4 C5 G5" | |
gains = [1.2, 3.0, 1.0, 2.2, 1.0, 1.0, 1.0, 3.5] # Per note | |
freqs = str2freq(pitches.split()) | |
notes = (gain * ks(freq * Hz) for freq, gain in zip(freqs, gains)) | |
snd = sum(notes) / sum(gains) | |
# Plays it for some seconds | |
with AudioIO(True) as player: | |
player.play(snd.take(4 * s), rate=rate) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment