Toshusai blog

知識の保管庫

【Python】音声を離散フーリエ変換して周波数帯ごとにビジュアライズする

はじめに

toshusai.hatenablog.com

この記事の時点で音声に関してあやふやだったことが多いので改めて書くことにした。今回はwavファイルを読み込んでフーリエ変換し、周波数ごとに振幅を表示したい。

wavファイルを読み込む

import wave
import numpy as np
#Wave_readオブジェクトとして得る
wf = wave.open("440Hz.wav", "rb")
#チャンネルの番号、1:モノラル、2:ステレオ
channels_no = wf.getnchannels()
#サンプルサイズ、2ならバイト?
sample_width = wf.getsampwidth()
#サンプリング周波数
sampling_frequency = wf.getframerate()
#全体のフレーム数
frames = wf.getnframes()

#bytesオブジェクトとして最大[引数]フレーム取得する。
buf = wf.readframes(wf.getnframes())
data = np.frombuffer(buf, dtype = "int16")
#ステレオだとdataには[左, 右, 左, 右, ...]のように入っているので、スライスして右だけ取り出す。別に左でもいいけどなんとなく。
if(channels_no == 2):
    data = data[::2]

print("Channel No:", channels_no)
print("Sample Width:", sample_width)
print("Sampling Frequency:", sampling_frequency)
print("Frames:", frames)
"""Standart output
Channel No: 1
Sample Width: 2
Sampling Frequency: 44100
Frames: 220500
"""

周波数ごとに表示する

import os
import time
#コンソールクリアのラムダ式
cclear = lambda : os.system('cls' if os.name=='nt' else 'clear')
#表示する行数
line = 50
#離散フーリエするデータの幅(1/24秒)
delta = int(sampling_frequency / 24)
fft_data = []
for i in range(int(len(data) / delta)):
    #deltaでスライスして高速離散フーリエ変換
    fft_data.append(np.fft.fft(data[i * delta:(i + 1) * delta]))
    #周波数帯ごとに振幅を表示する。
    for j in range(line):
        #まとめる周波数帯をスライスで取得
        width = fft_data[i][j * int(delta / line):(j + 1) * int(delta / line)]
        #振幅の絶対値の平均をとる
        s = 0
        for w in width:
            s += abs(w)
        y = s / len(width)
        #大きすぎるので小さくするため定数で割る
        length = int(y / 30000)
        #それでも大きい場合制限する
        if(length > 100):
            length = 100
        #その周波数帯の先頭と振幅を視覚的に表示する
        print({0:05d}.format(int(j * delta / line * 24)) + "*" * length))
    #0.2秒待機
    time.sleep(0.2)
    #コンソールクリア
    cclear()

実行結果

440Hzが流れるwavファイルを読み込んだ様子
f:id:toshusai:20171114234952g:plain 10kHzが流れるwavファイルを読み込んだ様子
f:id:toshusai:20171114235007g:plain 2つ目のfor文の中のdeltaを100とかにすれば100区切りで表示できる。

参考

PythonでWAVファイルを読み込む - 音楽プログラミングの超入門(仮)

22.4. wave — Read and write WAV files — Python 3.6.3 documentation