高速フーリエ変換(FFT)を使って音の解析および特定の周波数の除く

開発環境

音の解析 

以下で sample.wav に対する周波数別の解析をします

import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
from scipy.io import wavfile

# WAVファイルの読み込み
sample_rate, data = wavfile.read('sample.wav')

# データがステレオ(2チャンネル)の場合、モノラルに変換
if data.ndim == 2:
    data = data.mean(axis=1)

# FFTの実行
N = len(data)
fft_data = np.fft.fft(data)
fft_freq = np.fft.fftfreq(N, 1/sample_rate)

# 正の周波数成分のみを抽出
positive_freqs = fft_freq[:N // 2]
positive_fft_data = np.abs(fft_data[:N // 2])

# プロット
plt.figure(figsize=(10, 6))
plt.plot(positive_freqs, positive_fft_data)
plt.xlabel('周波数 [Hz]', fontsize=10)
plt.ylabel('振幅', fontsize=10)
plt.title('FFTによる周波数スペクトル', fontsize=12)
plt.grid(True)
plt.show()

特定の周波数のみの音にする

以下で特定の周波数のみににした後に、逆フーリエ変換で元に戻します

import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
from scipy.io import wavfile
from IPython.display import Audio, display

# WAVファイルの読み込み
sample_rate, data = wavfile.read('sample.wav')

# データがステレオ(2チャンネル)の場合、モノラルに変換
if data.ndim == 2:
    data = data.mean(axis=1)

# FFTの実行
N = len(data)
fft_data = np.fft.fft(data)
fft_freq = np.fft.fftfreq(N, 1/sample_rate)

# 正の周波数成分のみを抽出
positive_freqs = fft_freq[:N // 2]
positive_fft_data = np.abs(fft_data[:N // 2])

filtered_indices = (positive_freqs >= 500) & (positive_freqs <= 2500)

# フィルタリングを元のFFTデータに反映
filtered_fft_full = np.zeros_like(fft_data)
filtered_fft_full[:N // 2][filtered_indices] = fft_data[:N // 2][filtered_indices]
filtered_fft_full[-(N // 2):][filtered_indices] = fft_data[-(N // 2):][filtered_indices]

# 逆FFTで音声信号を再構築
filtered_data = np.fft.ifft(filtered_fft_full).real

# WAVファイルとして保存
filtered_filename = 'sample_remove1.wav'
wavfile.write(filtered_filename, sample_rate, filtered_data.astype(np.int16))

# フィルタリングしたFFTデータの正の周波数成分のみを抽出
filtered_positive_fft_data = np.abs(filtered_fft_full[:N // 2])

# プロット
plt.figure(figsize=(10, 6))
plt.plot(positive_freqs[filtered_indices], filtered_positive_fft_data[filtered_indices])
plt.xlabel('周波数 [Hz]', fontsize=10)
plt.ylabel('振幅 (Amplitude)', fontsize=10)  # 振幅を明確にするためのラベル
plt.title('FFTによる周波数スペクトル(特定の範囲の成分)', fontsize=12)
plt.grid(True)
plt.show()

# 作成された音声を再生
display(Audio(filtered_filename))