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

Shepard tones continuous context

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$

Squashed context

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 [ ]: