Pythonで行う音楽ファイルのノイズ除去と可視化

![スクリーンショット 2024-01-20 151353.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/d452d080-326d-7c85-7bc3-20c82fc7202c.png)

# 最初に
音楽ファイルからノイズを除去することは、オーディオ信号処理における重要なスキルです。今回は、https://www.music-note.jp/bgm/fantasy.html
のフリーBGMのファイル "adventurers.wav" を使って、高速フーリエ変換でのノイズ除去とそのプロセスを紹介します。
# フーリエ変換とは？
フーリエ変換は、信号を時間領域から周波数領域に変換するための数学的な手法です。これにより、信号を構成するさまざまな周波数成分を分析できます。フーリエ変換の基本式は以下のようになります：

高速フーリエ変換(FFT)
![スクリーンショット 2024-01-20 131551.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/4ad07e18-d45b-3361-5ba7-6d252ca009f0.png)
逆フーリエ変換(IFFT)
![スクリーンショット 2024-01-20 134513.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/e32877a6-08c9-6b0a-d1bc-8c740c13f0dd.png)



ここで F(ω) は周波数領域の信号、f(t) は時間領域の信号、ω は角周波数、j は虚数単位です。

この変換を用いることで、信号の周波数的な特性を把握し、特定の周波数成分に対して操作を行うことが可能になります。
# ノイズ除去のプロセス
必要なライブラリをインポートしていきます。
```py
import numpy as np
import matplotlib.pyplot as plt
from scipy.io import wavfile
from scipy.fft import fft, ifft
```
numpy: 数値計算用のライブラリ。配列操作や数学関数を提供します。
matplotlib.pyplot: データ可視化ライブラリ。波形のグラフ表示に使用します。
scipy.io.wavfile: WAVファイルの読み書きに使用します。
scipy.fft: 高速フーリエ変換 (FFT) とその逆変換 (IFFT) を行うための関数を提供します。
## 音楽ファイルの読み込み
```py
filename = 'adventurers.wav'
sample_rate, data = wavfile.read(filename)
if len(data.shape) > 1:
    data = data[:, 0]
```
wavfile.read: 指定されたファイルを読み込み、サンプルレートとオーディオデータを返します。
data.shape: データがステレオ（2チャンネル）の場合、左チャンネルのみを使用します。
## 元の信号の波形をプロット
```py
plt.figure(figsize=(12, 4))
plt.plot(data)
plt.title("オリジナルの波形")
plt.xlabel("サンプル")
plt.ylabel("振幅")
plt.show()
```
オリジナルのオーディオ信号の波形をグラフにプロットします。これにより、ノイズ除去前の信号を視覚的に確認できます。
![スクリーンショット 2024-01-20 131913.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/62b205c5-061f-aeaa-9609-255c507e10ae.png)


# FFTによる周波数領域への変換
```
data_fft = fft(data)
frequencies = np.fft.fftfreq(len(data_fft), 1/sample_rate)
```
fft: オーディオデータを周波数領域に変換します。
fftfreq: FFTによって生成された周波数成分の周波数を計算します。
# ノイズの除去
ここでは、1000Hzから3000Hzの間の周波数成分をノイズとして扱い、これらの成分をゼロに設定して除去します。
```
threshold_frequency_low = 1000
threshold_frequency_high = 3000
noise_indices = (np.abs(frequencies) > threshold_frequency_low) & (np.abs(frequencies) < threshold_frequency_high)
data_fft[noise_indices] = 0
```

# ノイズ部分のみ色を変えて可視化
```py
# 逆FFT（IFFT）を適用して時間領域のデータに戻す
noise_signal = np.real(ifft(data_fft * noise_indices))

plt.figure(figsize=(12, 4))
plt.plot(data, label='Original', alpha=0.5)
plt.plot(np.real(ifft(data_fft)), label='Cleaned', alpha=0.5)
plt.plot(noise_signal, label='Noise', color='red')
plt.title("ノイズ除去後の波形")
plt.xlabel("サンプル")
plt.ylabel("振幅")
plt.legend()
plt.show()
```
ノイズ除去後の波形と、除去されたノイズ部分を別々の色でプロットしています。これにより、ノイズ除去の効果が視覚的に明確になります。
![スクリーンショット 2024-01-20 132022.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/6b5c6abf-222d-f1f9-051f-49c019f21af6.png)
ノイズ除去前と除去後の音楽を保存して聞き比べてみます。
```py
from IPython.display import Audio
# 元の音声データをファイルとして保存
original_file = 'original_adventurers.wav'
wavfile.write(original_file, sample_rate, data)
# ノイズ除去後の音声データをファイルとして保存
cleaned_file = 'cleaned_adventurers.wav'
wavfile.write(cleaned_file, sample_rate, np.real(ifft(data_fft)).astype(np.int16))

Audio(original_file)
Audio(cleaned_file)
```
オリジナル版：
https://d.kuku.lu/xg6vggx5g
ノイズ除去版：
https://d.kuku.lu/my7h7umny


# まとめ
この記事では、Pythonを使用して音楽ファイルからノイズを除去し、そのプロセスを可視化する方法を説明しました。フーリエ変換は、信号の周波数成分を分析し、特定の周波数範囲のノイズを効果的に除去するための強力なツールです。この基本的な技術は、オーディオ編集、音響分析、さらには多くの科学技術分野で応用されています。ぜひ皆さんも好きな音を使って遊んでみてください！