LoginSignup
1
1

More than 1 year has passed since last update.

【Python】sin波を作成し、wave形式で出力する

Last updated at Posted at 2022-05-29

音声処理をするときに、基準となる音声データが欲しくなります。

自分の場合、"ラ"の音に該当する440 Hzの音を作成して、音声データを比較をすることが多いです。

その音を周波数領域などで可視化するだけでなく、耳で聞くと、体感しながら音声処理が可能になります。

今回は、Pythonで440 Hzの音をデータ配列上で作成するだけでなく、waveファイルを作成してみます。

実行環境は次の通りです。

Python 3.8.1
Ubuntu 20.04.4 LTS

sin波のデータ配列を作成

今回は上記でも書いたように"ラ"の基本周波数となる$ f$ = 440 Hzの音を1秒間作成します。
振幅を$A$、サンプリングレートを$f_o$、サンプルデータ番号を$n = 1,2,...,N$とすると、sin波の数列は、

A\sin\left(\frac{2\pi f}{f_o}n\right)

で与えられます。

プログラムでは次のようにしてデータ配列を作成します。

import numpy as np
import wave 
import struct

A = 1 #振幅 
fs = 44100 #サンプリングレート 
f0 = 440 #基本周波数 
sec = 1 #再生時間
nframe = np.arange(0, fs*sec) 
sin_wave = A*np.sin(nframe*2*np.pi*f0/fs) #sin波を生成 
sin_wave = np.array(sin_wave * (2**15-1)).astype(np.int16) #16bit符号付き整数に変換

インポートしている、wave, structのモジュールは次のwavファイルを作成するのに扱います。

再生時間は、サンプリングレート×時間で求められます。その値を最大値として、np.arangeでデータ番号の配列を作成します。

今回は16bit符号付き整数型でwaveファイルを作成するので、-1から1まで正規化されているsin波に2^15-1を掛けます。その後に、型をint16に変換します。

waveファイルを作成する

今回のwaveファイル名は"440Hz.wav"とします。

プログラムは次の通りです。

wave_fname = "440Hz.wav"

binary_sin_wave = struct.pack("h"*len(nframe), *sin_wave)
wave_write = wave.Wave_write(wave_fname) 
params = (1, 2, fs, len(nframe), 'NONE', 'not compressed') 

使うのは、組込みwaveモジュールと、バイナリを取り扱うことができるstrcutモジュールです。

初めての場合、バイナリの作成に苦労すると思います。

解説すると次の通りです。
・sin波のデータ配列をバイナリに変換する。
・今回は16bit符号付き整数型なので、struct.pack()の第1引数を"h"とする。また、データサンプルの数だけこの"h"の文字列の引数が必要なため、生成する配列の長さの分だけかけて文字列を生成する。
・第2引数以降は、sin波の配列をアンパックする。

次に、ファイル名を指定し、Wave_writeオブジェクトを作成します。

wave_write.setparams(params) 
wave_write.writeframes(binary_sin_wave) 
wave_write.close()

waveファイルを作成するために、ファイルパラメータを指定する必要があります。今回は次の通りです。

チャネル数:モノラル
1サンプルあたりのバイト数:2 byte
サンプリングレート:44100 Hz
サンプルサイズ:44100
圧縮形式:NONE #NONEしか取り扱いなし。

このファイルパラメータをsetparams()で設定します。

上記で作成したsin波のバイナリデータをwriteframes()で書き込んで作成されました。
最後にclose()してwaveファイルを閉じます。

こうして、440 Hzが収録されたwaveファイルの完成しました。Windows標準で再生が可能です。

周波数領域で440Hzのみが検出されるか確認する

自作した440Hzのwaveファイルだが、本当に440Hzの成分のみになっているか確認してみましょう。

次のコードで確認します。今回は簡易のためsoundfileライブラリで、音声データを抽出します。

※ここでの詳細は本記事の本質とは異なるので、割愛します。

import soundfile 
import numpy as np 
import matplotlib.pyplot as plt 
fname = '440Hz.wav' 
data, fs = soundfile.read(fname) 
PowerDFT = np.abs(np.fft.fft(data))**2 
fscale = np.fft.fftfreq(len(data), d=1.0/fs) 
print("最大値を取る周波数成分: {0} [Hz]".format(np.argmax(PowerDFT[:int(fs/2)]))) 
plt.plot(fscale, PowerDFT) 
plt.xlim(0, fs/2) 
plt.xlabel("frequency [Hz]") 
plt.show()

実行結果は次のようになる。

最大値を取る周波数成分: 440 [Hz]

440Hz_powerDFT.png

プログラム上でも、グラフ上でも440Hzで音声データが構成されていることが確認できました。

自作したsin波を自分で聞いてみて、音声処理の基準として進めていっていただければ幸いです。

公式ドキュメント

  1. wave --- WAVファイルの読み書き
  2. struct --- バイト列をパックされたバイナリデータとして解釈する
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1