音声に雑音をのせる方法(python版)

音声

音声データを用いた機械学習や音声認識の研究では、雑音が含まれる環境でのモデルの性能を評価することが重要です。特に、雑音耐性を向上させるためには、訓練データや評価データに様々な種類の雑音を加える「データ拡張」が効果的です。この記事では、Pythonを使って音声データに雑音を加える方法を紹介します。

まずは、基本的な「ホワイトノイズ」を加える方法から始め、次に、自然界の音やダウンロードした音声ファイルを利用して雑音を追加する方法まで、具体的な手順を解説します。これらの手法を活用することで、より実用的な音声認識モデルを構築する足がかりとなるでしょう。

音声処理に興味のある方や、雑音環境下での精度向上を目指している方は、ぜひこの記事を参考にしてみてください!

音声データの準備

まずは、ホワイトノイズを追加するプログラムを考えたいのですが、
その前に、ノイズをのせるメインの音声を準備しましょう。

ノイズをのせるメインの音声が準備できていない方は
こちらからご準備ください。

https://voice-statistics.github.io/


「日本声優統計学会」が配布しているwavファイルです。
高品質な音声に加えて、ラベルが準備されているので
今回はこちらを使用していきます。

「土谷麻貴様」の下にある「通常」といところクリックしてください。
「tsuchiya_normal」というフォルダのダウンロードが始まると思うので、
ダウンロード後はお好きなフォルダに保存してください。
※この記事では、「ノイズ追加」というフォルダを作成し、そこに保存します。

「ノイズ追加」に「tsuchiya_normal」が準備できたら、
ホワイトノイズをのせていきたいと思います。

wavファイルを使用する際の注意点

wavファイルを読み込む「pydub」モジュールをインストールするだけでは、
wavファイルは読み込めません。

「pydub」で内部使用する「FFmpeg」をインストールする必要があります。
また、インストール後パスを指定する必要があります。

↓のサイトで、「FFmpeg」のインストールとパス通しが丁寧に解説されていますので、
せひ参考にしてみてください。

WindowsにFFmpegをインストールして利用できるようにパスを通す | taziku / AI × クリエイティブ | 東京・名古屋

ホワイトノイズの追加

「ノイズ追加」というフォルダに
こちらのプログラム「with_whitenoise.py」という名前で保存してください。

「with_whitenoise.py」
※実行前に必要なモジュールをインストールしてください。

import os
import random
import numpy as np
import soundfile as sf

# 入力フォルダと出力フォルダを設定(相対パス)
input_folder = "tsuchiya_normal"
output_folder = "tsuchiya_normal_with_noise"
os.makedirs(output_folder, exist_ok=True)

# SN比を計算する関数
def add_white_noise(audio, snr_db):
    rms_signal = np.sqrt(np.mean(audio**2))
    rms_noise = rms_signal / (10**(snr_db / 20))
    noise = np.random.normal(0, rms_noise, audio.shape)
    return audio + noise

# フォルダ内のwavファイルにホワイトノイズを追加
for file_name in os.listdir(input_folder):
    if file_name.endswith(".wav"):
        input_path = os.path.join(input_folder, file_name)
        
        # 音声ファイルを読み込む
        audio, samplerate = sf.read(input_path)
        
        # ランダムなSN比(20~10dB)を生成(整数)
        snr_db = random.randint(10, 20)
        
        # ホワイトノイズを追加
        noisy_audio = add_white_noise(audio, snr_db)
        
        # 出力ファイル名にSN比を追加(整数値)
        file_name_no_ext, ext = os.path.splitext(file_name)
        output_file_name = f"{file_name_no_ext}_SNR{snr_db}dB{ext}"
        output_path = os.path.join(output_folder, output_file_name)
        
        # 出力フォルダに保存
        sf.write(output_path, noisy_audio, samplerate)
        print(f"Processed {file_name} with SNR {snr_db} dB")

プログラム実行すると、
同じ階層に「tsuchiya_normal_with_noise」というフォルダが作成されると思います。
このフォルダには、「tsuchiya_normal」に保存されていたwavファイルに
SN比20~10dBのホワイトノイズがランダムで追加されています。
また、保存名に SN比が何dBのノイズが追加されたのかわかるようにしてあります。

ダウンロードした雑音を追加

ここでは、ダウンロードした「bgm」や「効果音」などを
メインの音声にのせるプログラムを考えていきます。

引き続きメインの音声に「tsuchiya_normal」を使用します。
のせる音が準備できていない方は、こちらの記事でおすすめのサイトを紹介していますので、
お好きなサイトからダウンロードしてみてください。
※「tsuchiya_normal」に保存されているwavファイルは100コなので、
100種類ダウンロードしてみてください。

無料で雑音や自然音をダウンロードできるおすすめサイト紹介
この記事では、「音声研究」「仕事」で活用できる、無料で雑音や自然音をダウンロードできるサイトを紹介します。今回ご紹介するサイトは、すべてログイン等なしでご利用できます。 音声データにノイズを加えることは、機械学習や音声認識の研究で重要なステ...

この記事では、「VSQ plus+」というサイトから100種類ダウンロードしたものを使用します。
先ほどと同じ階層に「NOISE」というフォルダ名で保存しました。

「ノイズ追加」というフォルダに
こちらのプログラム「with_noise.py」という名前で保存してください。

プログラムを実行すると、同じ階層に
「WITH_NOISE」というフォルダが作成されます。

「with_noise.py」

import os
import random
import numpy as np
import soundfile as sf
from pydub import AudioSegment

# 入力フォルダと出力フォルダを設定(相対パス)
main_audio_folder = "tsuchiya_normal"
noise_folder = "NOISE"
output_folder = "WITH_NOISE"
os.makedirs(output_folder, exist_ok=True)

# SN比を計算してノイズを追加する関数
def add_noise_with_snr(main_audio, noise_audio, snr_db):
    rms_main = np.sqrt(np.mean(main_audio**2))
    rms_noise = np.sqrt(np.mean(noise_audio**2))
    scaling_factor = rms_main / (10**(snr_db / 20)) / rms_noise
    scaled_noise = noise_audio * scaling_factor
    return main_audio + scaled_noise

# メイン音声フォルダ内のwavファイルを処理
for main_file in os.listdir(main_audio_folder):
    if main_file.endswith(".wav"):
        main_path = os.path.join(main_audio_folder, main_file)
        main_audio, samplerate = sf.read(main_path)
        
        # 雑音フォルダからランダムなノイズファイルを選択
        noise_file = random.choice([f for f in os.listdir(noise_folder) if f.endswith(".mp3")])
        noise_path = os.path.join(noise_folder, noise_file)
        
        # ノイズを読み込み(mp3をwav形式に変換)
        noise_audio = AudioSegment.from_mp3(noise_path)
        noise_audio = np.array(noise_audio.get_array_of_samples()) / 2**15  # 正規化
        
        # ノイズをメイン音声と同じ長さに調整(ループまたは切り詰め)
        if len(noise_audio) < len(main_audio):
            repeats = int(np.ceil(len(main_audio) / len(noise_audio)))
            noise_audio = np.tile(noise_audio, repeats)[:len(main_audio)]
        else:
            noise_audio = noise_audio[:len(main_audio)]
        
        # ランダムなSN比(20~10dB)を生成
        snr_db = random.randint(10, 20)
        
        # ノイズを追加
        noisy_audio = add_noise_with_snr(main_audio, noise_audio, snr_db)
        
        # 出力ファイル名にノイズ名とSN比を追加
        main_name, main_ext = os.path.splitext(main_file)
        noise_name, _ = os.path.splitext(noise_file)
        output_file_name = f"{main_name}_with_{noise_name}_SNR{snr_db}dB{main_ext}"
        output_path = os.path.join(output_folder, output_file_name)
        
        # 出力フォルダに保存
        sf.write(output_path, noisy_audio, samplerate)
        print(f"Processed {main_file} with {noise_file} at SNR {snr_db} dB")

「WITH_NOISE」には
「メインの音声ファイル名」_with_「追加したファイル名」_「SN比」.wav

という順番の名前で保存されます。
先ほどと同様にSN比は10~20dBの間でランダムに追加されます。



コメント

タイトルとURLをコピーしました