#wave
waveはpythonでwavファイルを扱うためのモジュールのこと.
wavファイルは,PCM(Pulse Code Modulation)音源と呼ばれ,
標本化した音声をそのまま保存した非圧縮デジタル音源.
圧縮しないからでかい.リファレンスはこちら
##wavの読み込み: wave.open()
wave.open()でWave_readオブジェクトが返される.
wavファイルのサンプルはググれば,フリーでいろいろ出てくる.
import wave
import numpy as np
import matplotlib.pyplot as plt # 波形見るとき使う
import pyaudio # 鳴らすとき使う
import struct # バイナリデータを扱うとき使う
# 'rb'で読み込みモード
wf = wave.open('sample.wav', mode='rb')
print('type: ', type(wf))
type: <class 'wave.Wave_read'>
##Wave_read オブジェクト
wave.open()で返されるオブジェクトのこと.こんなメソッドがある.
print('チャンネル数:', wf.getnchannels()) # モノラルなら1,ステレオなら2
print('サンプル幅:', wf.getsampwidth()) # バイト数 (1byte=8bit)
print('サンプリング周波数:', wf.getframerate()) # CDは44100Hz
print('フレーム数:', wf.getnframes()) # サンプリング周波数で割れば時間
print('パラメータ:', wf.getparams()) # 上記+αのパラメータをタプルで返す
チャンネル数: 1
サンプル幅: 2
サンプリング周波数: 44100
フレーム数: 10289
パラメータ: _wave_params(nchannels=1, sampwidth=2, framerate=44100, nframes=10289, comptype='NONE', compname='not compressed')
中身を見る
メソッドreadframes(n)でnフレーム分のデータを読み込む.
読み込んだデータはバイナリ形式である.
buf1 = wf.readframes(5) # 5フレーム読み込む(-1で全フレーム)
buf2 = wf.readframes(5) # 読み込むたびポインタ位置が更新
print(buf1)
print(buf2)
b'\x18\x00\x1b\x00\x1d\x00\x1d\x00\x1a\x00'
b'\x18\x00\x19\x00\x19\x00\x1e\x00\x1d\x00'
\xの~は16進数表記,つまり4bitのデータ.\x~~が1サンプルを示す.
上記例の場合,サンプル幅2byte,つまり16bitなので,\x
自力で10進数にしたい方は,符号付き16進数とかリトルエンディアンとかググるといい?.
自分が使ったサンプルをnumpy.frombuffer()で10進数にすると...
wf.rewind() # ポインタを先頭に戻す
buf = wf.readframes(-1) # 全部読み込む
# 2なら16bit,4なら32bitごとに10進数化
if wf.getsampwidth() == 2:
data = np.frombuffer(buf, dtype='int16')
elif wf.getsampwidth() == 4:
data = np.frombuffer(buf, dtype='int32')
# ステレオの場合,チャンネルを分離
if wf.getnchannels()==2:
data_l = data[::2]
data_r = data[1::2]
plt.subplot(211)
plt.plot(data_l)
plt.subplot(212)
plt.plot(data_r)
plt.show()
else:
plt.plot(data)
plt.show()
##音を鳴らす
pyaudioを使った.pyaudioはバイナリ形式のデータを読み込んで鳴らすモジュールである.
下に出てくるチャンクは,音源から1回読み込むときのデータサイズのこと.
なぜ1024かはよく知らない.
p = pyaudio.PyAudio()
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
channels=wf.getnchannels(),
rate=wf.getframerate(),
output=True) # このストリームに書き込むと音がなる
chunk = 1024 # チャンク単位でストリームに出力し音声を再生
wf.rewind() # ポインタを先頭にする
data = wf.readframes(chunk)
while data:
stream.write(data)
data = wf.readframes(chunk)
stream.close()
p.terminate()
##numpy配列を音として保存する
「ラ」の音である440Hzの正弦波を作成して,音として保存する.
numpy配列をwaveを使って保存するには,バイナリ形式に変換する必要がある.
バイナリ形式への変換にはstructモジュールを用いた.
f = 440 # 周波数
fs = 44100 # サンプリング周波数(CD)
sec = 3 # 時間
t = np.arange(0, fs * sec) # 時間軸の点をサンプル数用意
sine_wave = np.sin(2 * np.pi * f * t / fs)
max_num = 32767.0 / max(sine_wave) # int16は-32768~32767の範囲
wave16 = [int(x * max_num) for x in sine_wave] # 16bit符号付き整数に変換
# バイナリ化,'h'が2byte整数のフォーマット
bi_wave = struct.pack("h" * len(wave16), *wave16)
# サイン波をwavファイルとして書き出し
w = wave.Wave_write('sine440.wav')
# (チャンネル数(1:モノラル,2:ステレオ))
# サンプルサイズ(バイト)
# サンプリング周波数
# フレーム数
# 圧縮形式(今のところNONEのみ)
# 圧縮形式を人に判読可能な形にしたもの?通常、'NONE'に対して'not compressed'が返される)
p = (1, 2, fs, len(bi_wave), 'NONE', 'not compressed')
w.setparams(p)
w.writeframes(bi_wave)
w.close()