In [ ]:
import os, sys
import numpy as np
from TimeFreqAuditoryScene import *
from IPython.display import Audio, display, clear_output
from IPython.html import widgets
from IPython.html.widgets import interactive
%matplotlib inline
We design a continuous context by defining a time varying shepard tone
More specifically, the base frequency is modulated through time
$\log f_b(t) = log(f_b) + a_m\,\cos(2\pi f_m t) $
$f_b(t) = f_b \exp(a_m\,\cos(2\pi f_m t)) $
To control the range of fluctuation in terms of semitones, one can reparameterize the modulation as follows
$\log f_b(t) = log(f_b) + st_m \log(2^{1/12}) \,\cos(2\pi f_m t) $
then $|\log(f_b(t))-\log(f_b)|<\log(2^{st_m/12})$
Phase is therefore obtained as
$\phi(t) = \int f_b(t)dt$
To further manipulate the context, one manipulation is to rectify the cosine by a non-linearity.
One simple rectifying function is $$r(x) = \frac{1-e^{-a x}}{1+e^{-a x}}$$
In [ ]:
x = np.linspace(-1,1,100)
z = np.linspace(-10,10,100)
def rect(x,a):
return (1-np.exp(-a*x))/(1+np.exp(-a*x))
def rect_(a=1):
plt.subplot(1,2,1)
plt.plot(x,rect(x,a))
plt.subplot(1,2,2)
plt.plot(z,rect(np.cos(z),a))
w = interactive(rect_, a=(0.1,10))
display(w)
In [ ]:
# Parameterization
# Global parameters
fs = 44100
# Shepard tones
delay = 1./8.
duration = 1./8.
fb1 = 1.
# declare gaussian envelope on log frequency
mu_log=np.log(200)
sigma_log=2.
genv = GaussianSpectralEnvelope(mu_log=mu_log, sigma_log=sigma_log)
In [ ]:
ctx_duration =duration*5
def up_or_down(st_m=1, st_shift=1, f_m=10,alpha=1):
scene = Scene()
context = []
run_time=0
def squash(x,alpha):
return (1-np.exp(-alpha*x))/(1+np.exp(-alpha*x))
def inst_freq(i, fc):
return lambda t: (2.**i)*fc*np.exp(st_m/12.*np.log(2)*squash(np.cos(2*np.pi*f_m*t),alpha))
# Constructing the context
for i in range(16):
context.append(InstantaneousFrequency(i_freq=inst_freq(i,fb1*2**(st_shift/12.)),
duration=ctx_duration, env=genv))
# Constructing the test pair
run_time+=delay+ctx_duration
tone1 = ShepardTone(fb=fb1, env=genv, delay=run_time, duration=duration)
run_time += duration + delay
tone2 = ShepardTone(fb=fb1*np.sqrt(2.), env=genv, delay=run_time, duration=duration)
scene.add([context , tone1, tone2])
# draw spectrogram
sd = SceneDrawer()
sd.draw(scene)
plt.show()
# generate sound
x = scene.generate(fs=fs)
display(Audio(x, rate=fs, autoplay=True))
w = interactive(up_or_down, st_m=(0,12), st_shift=(0,12), f_m=(1,50),alpha=(0.1,10))
display(w)
In [ ]: