In [1]:
%load_ext autoreload
%autoreload 2
%matplotlib inline
import matplotlib.pyplot as plt
from IPython.display import Audio #, display
import numpy as np
# from pysas import World, waveread # https://github.com/shunsukeaihara/pysas

from matplotlib import pyplot as plt, colors
hsv = [(i, .8, .8) for i in np.linspace(0,1,12,endpoint=False)]
rgb = colors.hsv_to_rgb(hsv)

samplerate = 44100.
nyquist = samplerate / 2.
π = np.pi
τ = 2*π
In [2]:
import soundfile

def pad2(i):
    return '{0:02d}'.format(i)

# read phoneme WAVs from file
datas = []
path = "/Users/pi/Dev/pythonStuff/VowelGen/4. Analyze my own vowels/vowels/me/"
for i in range(12):
    file = path + pad2(i) + '.aiff'
    print(file)
    data, samplerate = soundfile.read( file )
    data = data[:,0]
    datas.append( data )
/Users/pi/Dev/pythonStuff/VowelGen/4. Analyze my own vowels/vowels/me/00.aiff
/Users/pi/Dev/pythonStuff/VowelGen/4. Analyze my own vowels/vowels/me/01.aiff
/Users/pi/Dev/pythonStuff/VowelGen/4. Analyze my own vowels/vowels/me/02.aiff
/Users/pi/Dev/pythonStuff/VowelGen/4. Analyze my own vowels/vowels/me/03.aiff
/Users/pi/Dev/pythonStuff/VowelGen/4. Analyze my own vowels/vowels/me/04.aiff
/Users/pi/Dev/pythonStuff/VowelGen/4. Analyze my own vowels/vowels/me/05.aiff
/Users/pi/Dev/pythonStuff/VowelGen/4. Analyze my own vowels/vowels/me/06.aiff
/Users/pi/Dev/pythonStuff/VowelGen/4. Analyze my own vowels/vowels/me/07.aiff
/Users/pi/Dev/pythonStuff/VowelGen/4. Analyze my own vowels/vowels/me/08.aiff
/Users/pi/Dev/pythonStuff/VowelGen/4. Analyze my own vowels/vowels/me/09.aiff
/Users/pi/Dev/pythonStuff/VowelGen/4. Analyze my own vowels/vowels/me/10.aiff
/Users/pi/Dev/pythonStuff/VowelGen/4. Analyze my own vowels/vowels/me/11.aiff
In [3]:
from pysas import World

world = World(samplerate, frameperiod=5)

def plot_spectrum(axes, spectrum, **kwargs):
    axes.grid(which='both')
    #axes.xaxis.grid(True)
    axes.set_xticks(np.arange(0, 22.050, 3.000))                                                       
    axes.set_xticks(np.arange(0, 22.050, 1.000), minor=True)                                           
    
    axes.xaxis.grid(which='minor', alpha=0.2)                                                
    axes.xaxis.grid(which='major', alpha=0.5)                                                

    freqs = np.linspace(0, 22.050, 1024+1)
    axes.plot(freqs, np.log(spectrum), **kwargs)

spectra = []
for signal in datas:
    f0, spec_mat, aperiod_mat = world.analyze(signal)
    spec = np.average( spec_mat[f0 > 40][20:-20], axis=0 )
    
    if len(spectra)==0:
        plt.subplots()
        plt.plot(f0, 'b', linewidth=2)
        
        fig, axes = plt.subplots()
        plot_spectrum( axes, spec, color='r', linewidth=2)
        for i,k in enumerate([40,80,120]):
            plot_spectrum( axes, spec_mat[k], color=rgb[3+i], alpha=.5)

    spectra.append(spec)
In [4]:
symbols = ['ɑ', 'a', 'ɛ', 'e', 'i', 'ɔ',  'y', 'u', 'œ', 'ʌ', 'o', 'ɪ̈']
plt.rc('font', family='Arial')
#plt.figure(figsize=(15,8))
fig, axes = plt.subplots(figsize=(15,8))

   
for c,spec,symbol in zip(rgb,spectra,symbols):
    plot_spectrum(axes, spec, color=c, alpha=0.5, label=symbol, linewidth=2)

legend = plt.legend(loc='upper right', shadow=True)

# http://stackoverflow.com/questions/24943991/matplotlib-change-grid-interval-and-specify-tick-labels
fig, ax = plt.subplots(4,3, figsize=(15,6))
for i,(c,spec,symbol) in enumerate(zip(rgb,spectra,symbols)):
    axes = ax[i%4] [int(i/4)]
    plot_spectrum(axes, spec, color=c, label=symbol, linewidth=2)
In [5]:
from collections import deque, namedtuple

formant_data = [ 
    'ɑ',  660, 1, 9,  1090, 1, 9,  2440, 1, 9,
    'a',  660, 1, 9,  1720, 1, 9,  2410, 1, 9,
    'ɛ',  530, 1, 9,  1840, 1, 9,  2480, 1, 9,
    'e',  490, 1, 9,  1350, 1, 9,  1590, 1, 9,
    ]

Formant = namedtuple('Formant', 'freq bandwidth gain')
Vowel = namedtuple('Vowel', 'symbol formants filter')

vowels = deque()

acc = []
for x in reversed(formant_data):
    if isinstance(x,str):
        symbol = x
        freqs, bws, gains = acc[0::3], acc[1::3], acc[2::3]

        formants = [ Formant(f,bw,g) for f,bw,g in zip(freqs, bws, gains) ]
        filters = None # [ formant_filter( f,r,gain) for f,g,bw in formants ]

        v = Vowel(symbol, formants, filters)
        vowels.appendleft(v)
        acc = []
    else:
        acc = [x] + acc
In [6]:
def formant_filter( f_peak, bandwidth, gain ):
    r, θ = np.exp(-π*bandwidth/samplerate), π*f_peak/nyquist
    z = r * np.exp( 1j * θ )
    zeros, poles, tmp_gain = [], [z,z.conjugate()], 1
    Bs, As = zpk2tf( zeros, poles, tmp_gain )

    def gain_at(f):
        _f = np.asarray(f)
        Φ = π * _f/nyquist
        w, h = freqz( Bs, As, Φ )
        return np.abs( h[0] )

    Bs *= gain/gain_at(f_peak)

    def func(Xn):
        Yn = lfilter( Bs, As, Xn )
        return Yn
    return func
In [ ]: