36
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[備忘録]pythonのwaveモジュール

Last updated at Posted at 2019-05-23

#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のデータ.
上記例の場合,サンプル幅2byte,つまり16bitなので,\x
\x~~が1サンプルを示す.
自力で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()
36
31
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
36
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?