のこぎり波生成ツールを作る

はじめに

今回は実験用信号としてのこぎり波(sawtooth wave)を生成します。

のこぎり波は倍音成分を無限に含む信号で、人間の有声音に特性が似ています。そのため、のこぎり波にフィルタを施す事で人間の音声を模倣する事ができます。

Audacityのような波形編集ツールには波形生成機能が搭載されているので、GUI操作が手間でなければそちらを使うのが手っ取り早いかもしれません。

一方で自作ツールにしておくと、コマンドラインからバッチ処理化しやすかったり、機能拡張できる利点があります。

のこぎり波の生成式

生成するのこぎり波の周波数をf、サンプリングレートをr、サンプルのインデックス(サンプル単位の時刻)をt、とすると、ある時点での振幅値y(t)は以下の通りで求める事ができます。

y(t) = 2 \times (\frac{t \times f}{r} – floor(\frac{t \times f}{r} + \frac{1}{2}))

floor()は小数点以下を切り捨てる関数です。t0から好きな長さまで入力する事で、好きな長さののこぎり波を生成できます。

のこぎり波生成ツールの実装

pythonで実装します。__make_sawtooth_wave関数がのこぎり波の生成式の実装です。

import argparse
import numpy
import scipy.io.wavfile

def __lpcms_float_to_int16(float_lpcms):
    return (float_lpcms * 32767.0).astype(numpy.int16)

def __write_lpcm_to_wave_file(wave_filepath, rate, lpcm):
    scipy.io.wavfile.write(wave_filepath, rate, lpcm)
    return None

def __make_sawtooth_wave(sampling_rate, length, frequency, amplitude):
    t = numpy.linspace(0, length - 1, length)
    r = sampling_rate
    f = frequency
    a = amplitude
    lpcm = t * f / r - numpy.floor(t * f / r + 1 / 2)
    return 2 * a * lpcm

def __main(output_wave_filepath, sampling_rate, length, frequency, amplitude):
    lpcm = __make_sawtooth_wave(sampling_rate, length, frequency, amplitude)
    lpcm = __lpcms_float_to_int16(lpcm)
    __write_lpcm_to_wave_file(output_wave_filepath, sampling_rate, lpcm)
    return None

if __name__ == "__main__":
    argment_parser = argparse.ArgumentParser()
    argment_parser.add_argument("-o", "--output_wave_filepath", type=str, required=True)
    argment_parser.add_argument("-s", "--sampling_rate", type=int, default=48000)
    argment_parser.add_argument("-l", "--length", type=int)
    argment_parser.add_argument("-f", "--frequency", type=float, default=440.0)
    argment_parser.add_argument("-a", "--amplitude", type=float, default=1.0)
    args = argment_parser.parse_args()

    if args.length is None:
        args.length = args.sampling_rate

    __main(
        args.output_wave_filepath,
        args.sampling_rate, args.length, args.frequency, args.amplitude)

    exit(0)

args.lenghtを必須パラメータとしておらず、デフォルト値もありません。未指定の場合はサンプリングレートと同じ値を設定します。つまり、デフォルトののこぎり波の長さはきっかり1秒になります。

デフォルトで生成した場合ののこぎり波の周波数は440Hzにしていますが、特に意味はありません。人間の声だとすると440Hzはやや高すぎます。80Hzだとやや低すぎるので、80Hz \sim 440Hzの間でデフォルト値を定義すると使いやすいかもしれません。

おわりに

ひとまずのこぎり波をWAVEファイルとして生成するツールを作りました。

一旦WAVEファイルで生成しておく事で、様々なツールに入力して実験信号として利用できます。

正弦波や矩形波なんかも生成するツールがあると色々実験できて良いかもしれません。