ScipyでLPC


LPCによってAR係数を取得後ホワイトノイズで駆動させてみた.
いい感じに声がロボット(?)っぽくなった気がする.
あと,駆動するノイズを変更すればまた違った声質になるはず.

lpc.py
#!/usr/bin/env python

import sys
import wave
import urllib2
import getopt
import scipy as sp
import matplotlib.pyplot as plt
from scipy import linalg, signal
from scikits.talkbox.linpred.levinson_lpc import lpc

if __name__ == "__main__":
    optlist, argv = getopt.getopt( sys.argv[1:], 's:l:o:w:')

    frameLength = 512
    stepWidth = 256
    lpcOrder = 32
    chunk = 44100 * 5
    for opt, val in optlist:
        if( opt == '-s' ):
            chunk = int( val )
        elif( opt == '-w' ):
            stepWidth = int( val )
        elif( opt == '-l'):
            frameLength = int( val )
        elif( opt == '-o' ):
            lpcOrder = int( val )

    argc = len( argv )
    if( 0 < argc ):
        if( argc == 2 ):
            inFileName, outFileName = argv
        elif( argc == 1 ):
            inFileName = argv[0]
            outFileName = 'out.wav'
        wo = wave.open( inFileName, 'rb' )
    else:
        outFileName = 'out.wav'
        url = 'http://www.it.ice.uec.ac.jp/SRV-DB/archive/HENSHU00_PF00/HENSHU00_PF00_0951.wav'
        wo = wave.openfp( urllib2.urlopen( url ).fp,  'rb' )

    data = sp.fromstring( wo.readframes( chunk ), sp.int16 )
    blockData = sp.linalg.toeplitz( data[ frameLength:], data[:frameLength] )[::stepWidth, :]

    lpcCoef, lpcError, k = lpc( blockData,  lpcOrder )
    excitationSignal = sp.random.randn( frameLength )

    rows, cols = lpcCoef.shape
    responseSignal = sp.zeros( ( rows,  frameLength ) )
    synthesisSignal = sp.array( [0] * ( rows  * stepWidth + frameLength ) )
    weight = sp.sin( 2 * sp.pi * sp.r_[0:frameLength] / frameLength )
    for i in range( rows ):
        G = sp.sqrt( lpcError[ i ] )
        responseSignal[i, :] = sp.signal.lfilter( [G], lpcCoef[ i, :], excitationSignal )
        synthesisSignal[ i * stepWidth:i * stepWidth + frameLength ] +=  weight * responseSignal[ i, :]

    outputSignal = sp.int16( synthesisSignal ).tostring()
    wo = wave.open( outFileName, 'wb')
    params = ( 1, 2, 44100, len( synthesisSignal),'NONE','none')
    wo.setparams( params )
    wo.writeframes( outputSignal )
    wo.close()