音声ファイルの文字起こしをスムーズに! Pythonでノイズ除去と音量正規化 (Google Colab)

目次
  1. 最初に
  2. 1. 手順
  3. ノイズ除去
  4. 音量正規化
  5. 2. Colab でコードを実行
  6. Colab で実行する .ipynb コード
  7. 自分のローカルPCでPythonで実行する場合
  8. 準備
  9. まとめ

(Gemini 1.5 Pro) あなたはProのWEBライターです。以下のコードを紹介する記事を書いて。音声の文字起こし前のノイズ除去と正規化をしてくれるコードの紹介です。Pythonをまだ触ったことがない人にもわかるように解説してください。

音声データを文字起こしする際、ノイズや音量のばらつきは悩みの種ですよね。特に大量のファイル処理には、事前準備が欠かせません。

そこで今回は、前回[1]Excel で作った表で誤字を一括修正 (Google Colab). https://plaza.umin.ac.jp/shoei05/index.php/2024/05/25/2518/ に引き続き、Google Colaboratory (Colab) とPythonを使って音声ファイルのノイズ除去と音量正規化を自動で行う方法をご紹介します。

GitHubはこちらです[2]https://github.com/shoei05/soundfile_normalization/

最初に

GPTでも同様にノイズ除去と正規化をやってくれるボットを作成しました。「何から始めたらいい?」を押して指示に従ってください。

音声ファイルをアップロードすると自動でノイズ除去と音量の正規化(音量の揃ったデータにする)をしてくれるGPTを作成しました。「何から始めたらいい?」を押して指示に従ってください。音声データの質向上は、文字起こしの精度向上に役立ちます。ぜひご活用ください。 https://t.co/eH7uGfL9oF

— Shoei (@shoei05) May 27, 2024

https://chatgpt.com/g/g-blH6IXYg6-soundfile-normalization

1. 手順

  1. Colab を実行
  2. 音声データをアップロード (“.wav”, “.mp3”, “.mp4”, “.m4a”, “.mkv”, “.webm” に対応しています)
  3. 自動でノイズ除去、音声の正規化を実行
  4. 処理後の音声データが自動でダウンロード

ノイズ除去

音声データには周囲の環境音や機器のノイズなど、目的とする音声以外の音が含まれていることがよくあります。これらのノイズは音声認識や分析の精度を低下させる要因となります。そのため、ノイズ除去はクリアな音声データを得るための重要なプロセスです。

ノイズ除去は音声データから不要なノイズを識別し、除去する処理を指します。さまざまな手法がありますが、多くの場合、音声とノイズの周波数特性の違いを利用したり、機械学習を用いてノイズパターンを学習し除去したりします。

今回のコードでは、 FFmpeg の afftdn フィルターを用いてノイズを除去しています。

denoise_command = f"ffmpeg -i {temp_wav} -af 'afftdn=nr={noise_reduction_db}' {temp_denoised} -y"
if os.system(denoise_command) != 0:
    raise RuntimeError(f"Error executing ffmpeg command: {denoise_command}")Code language: JavaScript (javascript)

afftdn は、FFT(高速フーリエ変換)を用いて音声のノイズを除去する FFmpeg のフィルターです。 nr パラメータでノイズ除去の強度を指定しており、値が大きいほどノイズ除去が強くなります。

今回は、noise_reduction_db = 10 と設定されています。これはノイズ除去の強度を 10dB に設定していることを意味します。 適切なノイズ除去の強度は、音声データのノイズレベルや種類によって異なります。

音量正規化

音声正規化は音量レベルを調整する処理です。異なる録音環境や機器によって音量レベルが異なる場合があり、そのままでは聞き取りにくい、あるいは音声認識で正確に処理できない可能性があります。音声正規化によって適切な音量レベルに統一することで、聞き取りやすさと処理の精度を向上させることができます。

このコードでは、pydubライブラリのnormalize関数を用いて音声を正規化しています。この関数は入力された音声信号のピークレベルを検出し、それを0dBFS(decibels relative to full scale、フルスケールを基準としたデシベル)に調整することで、可能な限り大きな音量にします。

# 音声の正規化
        normalized_audio = normalize(audio)Code language: PHP (php)

これらのパラメータにより、放送規格などでも用いられる、聞きやすく、レベルの揃った音声データを作成することができます。

2. Colab でコードを実行

以下のGoogle Colabのコピーをご自身のDriveに保存してください。

GoogleColabについてもっと知りたい方は、東京大学 数理・情報教育研究センターが公開している「Pythonプログラミング入門」[3]東京大学 数理・情報教育研究センター. Python プログラミング入門. https://utokyo-ipp.github.io/ を参照してください。

https://colab.research.google.com/drive/1S9gfGZZ2NleEv6QgH51dxu2s95sOfgQ2?usp=sharing

コピーが完了したら、再生ボタンを押してコードを実行してください。

しばらくするとコードブロックの下のほうに「音声データをアップロードしてください」と表示されるので、音声データ(“.wav”, “.mp3”, “.mp4”, “.m4a”, “.mkv”, “.webm”)をアップロードしてください。動画データでも処理可能です。

しばらくすると処理が完了して自動でダウンロードが始まります。

Colab で実行する .ipynb コード

!pip install pydub tqdm

import os
from pydub import AudioSegment
from tqdm import tqdm
import logging
from concurrent.futures import ThreadPoolExecutor
import shutil
import tempfile
import uuid
import ipywidgets as widgets
from google.colab import files

# ログの設定
logging.basicConfig(filename='preprocessing.log', level=logging.INFO,
                    format='%(asctime)s - %(levelname)s - %(message)s')

def replace_spaces(filename):
    return filename.replace(" ", "_")

def preprocess_audio(input_path, output_path, noise_reduction_db, done_folder):
    try:
        if not os.path.exists(input_path):
            raise FileNotFoundError(f"Input file not found: {input_path}")

        temp_dir = tempfile.gettempdir()
        temp_id = str(uuid.uuid4())
        temp_wav = os.path.join(temp_dir, f"temp_{temp_id}.wav")
        temp_denoised = os.path.join(temp_dir, f"temp_denoised_{temp_id}.wav")
        temp_normalized = os.path.join(temp_dir, f"temp_normalized_{temp_id}.wav")

        _, extension = os.path.splitext(input_path)
        extension = extension.lower()

        # オーディオファイルを読み込んで一時的にwav形式で保存
        audio = AudioSegment.from_file(input_path, format=extension.lstrip('.'))
        audio.export(temp_wav, format="wav")

        # ノイズ除去
        denoise_command = f"ffmpeg -i {temp_wav} -af 'afftdn=nr={noise_reduction_db}' {temp_denoised} -y"
        if os.system(denoise_command) != 0:
            raise RuntimeError(f"Error executing ffmpeg command: {denoise_command}")

        # サンプリングレートの変換と正規化
        audio = audio.set_frame_rate(16000)
        normalized_audio = normalize(audio)

        # 正規化された音声を読み込んでmp3形式で保存
        normalized_audio = AudioSegment.from_wav(temp_normalized)
        normalized_audio.export(output_path, format="mp3")

        # 処理したファイルをdoneフォルダに移動
        shutil.move(input_path, os.path.join(done_folder, replace_spaces(os.path.basename(input_path))))

        logging.info(f"Preprocessed {input_path}")

    except Exception as e:
        logging.error(f"Error processing {input_path}: {str(e)}")
        raise

    finally:
        # 一時ファイルを削除
        for temp_file in [temp_wav, temp_denoised, temp_normalized]:
            if os.path.exists(temp_file):
                os.remove(temp_file)

def process_files(input_folder, output_folder, noise_reduction_db, max_workers, done_folder):
    audio_files = [f for f in os.listdir(input_folder) if f.lower().endswith((".wav", ".mp3", ".mp4", ".m4a", ".mkv", ".webm"))]
    total_files = len(audio_files)

    progress_bar = tqdm(total=total_files, unit='file')

    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = []
        for filename in audio_files:
            input_path = os.path.join(input_folder, filename)
            output_path = os.path.join(output_folder, f"{os.path.splitext(replace_spaces(filename))[0]}.mp3")
            futures.append(executor.submit(preprocess_audio, input_path, output_path, noise_reduction_db, done_folder))

        for future in futures:
            try:
                future.result()
                progress_bar.update()
            except Exception as e:
                logging.error(f"Error in parallel processing: {str(e)}")

    progress_bar.close()


# --- 音声データファイルのアップロード ---
input_folder = '/content/p_input'
output_folder = '/content/input'
done_folder = '/content/p_done'
os.makedirs(input_folder, exist_ok=True)
os.makedirs(output_folder, exist_ok=True)
os.makedirs(done_folder, exist_ok=True)

while True:
  print("音声データをアップロードしてください。")
  uploaded = files.upload()
  for filename in uploaded.keys():
    shutil.move(filename, os.path.join(input_folder, filename))
  break
# ----------------------

noise_reduction_db = 10
max_workers = 4

process_files(input_folder, output_folder, noise_reduction_db, max_workers, done_folder)

# --- 処理済みファイルのダウンロード ---
print("処理が完了しました。ダウンロードリンクを生成します。")
for filename in os.listdir(output_folder):
  if filename.endswith(".mp3"):
    files.download(os.path.join(output_folder, filename))
# ----------------------Code language: PHP (php)

自分のローカルPCでPythonで実行する場合

準備

1. Pythonをインストール

まだインストールしていない場合は、Python公式ウェブサイトからダウンロードしてインストールしてください。

コマンドプロンプト/ターミナルを開いて、

  • Windows: Windowsキーを押して「cmd」と入力し、Enterキーを押します。
  • Mac: Spotlight検索 (虫眼鏡アイコン) をクリックし、「ターミナル」と入力してEnterキーを押します。
python -V

と入力して、

Python 3.12.3Code language: CSS (css)

などと表示されていればPythonは既にインストールされています。

2. 必要なライブラリのインストール

コマンドプロンプトまたはターミナルを開き、以下のコマンドを実行して必要なライブラリをインストールします。

pip install pydub tqdm

3. FFmpegのインストール

FFmpeg (エフエフエムペグ) は、動画の編集や変換などが可能なフリーソフト[4]FFmpeg. Accessed May 4, 2021. https://www.ffmpeg.org/ です。

FFmpegのインストール方法は過去に書いた下記記事を参照ください。

学術大会で 音声動画発表スライドデータ を求められたときに: .mp4 を FFmpeg でサイズ圧縮shoei05.com

4. コードの準備と実行準備

処理したい音声データ (“.wav”, “.mp3”, “.mp4”, “.m4a”, “.mkv”, “.webm”) と下記のコードをコピーして soundfile_normalization.py の名前で保存します。以下の構造で準備してください。

任意のフォルダ
   ├── soundfile_normalization.py
   ├── input (フォルダ)
   │└── (音声データを入れる)  
   ├── output (コードを実行したら自動で生成されます)
   │└── (処理後の音声データが自動で格納されます)  
   └── done_original (コードを実行したら自動で生成されます)
    └── (処理後の元データが自動で格納されます)  Code language: CSS (css)

GitHubからダウンロードしても構いません。Gitをインストールしている人は、

git clone https://github.com/shoei05/soundfile_normalization.gitCode language: PHP (php)

でクローンしてください。もしくは、

https://github.com/shoei05/soundfile_normalization/tree/main

から Zip ファイルをダウンロードすることもできます。

Pythonコード

import os
from pydub import AudioSegment
from pydub.effects import normalize
from tqdm import tqdm
import logging
from concurrent.futures import ThreadPoolExecutor
import shutil
import tempfile
import uuid

# ログの設定
logging.basicConfig(filename='preprocessing.log', level=logging.INFO,
                    format='%(asctime)s - %(levelname)s - %(message)s')

def replace_spaces(filename):
    return filename.replace(" ", "_")

def preprocess_audio(input_path, output_path, noise_reduction_db, done_folder):
    try:
        if not os.path.exists(input_path):
            raise FileNotFoundError(f"Input file not found: {input_path}")

        temp_dir = tempfile.gettempdir()
        temp_id = str(uuid.uuid4())
        temp_wav = os.path.join(temp_dir, f"temp_{temp_id}.wav")
        temp_denoised = os.path.join(temp_dir, f"temp_denoised_{temp_id}.wav")

        _, extension = os.path.splitext(input_path)
        extension = extension.lower()

        # オーディオファイルを読み込んで一時的にwav形式で保存
        audio = AudioSegment.from_file(input_path, format=extension.lstrip('.'))
        audio.export(temp_wav, format="wav")

        # ノイズ除去
        denoise_command = f"ffmpeg -i {temp_wav} -af 'afftdn=nr={noise_reduction_db}' {temp_denoised} -y"
        if os.system(denoise_command) != 0:
            raise RuntimeError(f"Error executing ffmpeg command: {denoise_command}")

        # ノイズ除去後の音声を読み込み
        audio = AudioSegment.from_wav(temp_denoised)

        # サンプリングレートの変換
        audio = audio.set_frame_rate(16000)

        # 音声の正規化
        normalized_audio = normalize(audio)

        # 正規化された音声を読み込んでmp3形式で保存
        normalized_audio.export(output_path, format="mp3")

        # 処理したファイルをdoneフォルダに移動
        shutil.move(input_path, os.path.join(done_folder, replace_spaces(os.path.basename(input_path))))

        logging.info(f"Preprocessed {input_path}")

    except Exception as e:
        logging.error(f"Error processing {input_path}: {str(e)}")
        raise

    finally:
        # 一時ファイルを削除
        for temp_file in [temp_wav, temp_denoised]:
            if os.path.exists(temp_file):
                os.remove(temp_file)

def process_files(input_folder, output_folder, noise_reduction_db, max_workers, done_folder):
    audio_files = [f for f in os.listdir(input_folder) if f.lower().endswith((".wav", ".mp3", ".mp4", ".m4a", ".mkv", ".webm"))]
    total_files = len(audio_files)

    progress_bar = tqdm(total=total_files, unit='file')

    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = []
        for filename in audio_files:
            input_path = os.path.join(input_folder, filename)
            output_path = os.path.join(output_folder, f"{os.path.splitext(replace_spaces(filename))[0]}.mp3")
            futures.append(executor.submit(preprocess_audio, input_path, output_path, noise_reduction_db, done_folder))

        for future in futures:
            try:
                future.result()
                progress_bar.update()
            except Exception as e:
                logging.error(f"Error in parallel processing: {str(e)}")

    progress_bar.close()

if __name__ == "__main__":
    input_folder = './p_input'
    output_folder = './input'
    done_folder = './p_done'
    noise_reduction_db = 10
    max_workers = 4

    os.makedirs(output_folder, exist_ok=True)
    os.makedirs(done_folder, exist_ok=True)

    process_files(input_folder, output_folder, noise_reduction_db, max_workers, done_folder)Code language: PHP (php)

5. 実行

コマンドプロンプト/ターミナルで、cd コマンドを使ってsoundfile_normalization.pyファイルがあるディレクトリに移動します。前回の記事も参照してください。

Excel で作った表で誤字を一括修正 (Google Colab)shoei05.com

以下のコマンドを実行します。

python sound_normalization.pyCode language: CSS (css)

処理が完了すると、output フォルダが自動生成され、処理後の音声データが .mp3 形式で格納されています。処理前のデータは input_original フォルダに格納されています。

この処理は並列で実行できます。実行したい音声データをフォルダにまとめていれてからコードを実行すると、一括でノイズ除去と正規化が完了します。

まとめ

今回は、私が普段使いしているPythonコードの紹介第2弾として、音声データのノイズ除去と音量正規化を自動化する手法を紹介しました。

音声データの質を向上させることは、文字起こしの精度向上に直結するだけでなく、音声認識を使ったシステム開発や、より快適な音声コンテンツの提供にも役立ちます。ぜひ、今回ご紹介したコードを参考に、ご自身の環境で試してみてください。

私の普段使っているPythonコード紹介、第2段です。音声データのノイズ除去と音量正規化を自動化する手法を紹介しました。Whisper などの音声書き起こしの前処理に使っています。Google Colab上で動かせるコードも公開していますので、ぜひお試しください。 https://t.co/CaAgpRlWYn

— Shoei (@shoei05) May 26, 2024

References[+]

References
↑1 Excel で作った表で誤字を一括修正 (Google Colab). https://plaza.umin.ac.jp/shoei05/index.php/2024/05/25/2518/
↑2 https://github.com/shoei05/soundfile_normalization/
↑3 東京大学 数理・情報教育研究センター. Python プログラミング入門. https://utokyo-ipp.github.io/
↑4 FFmpeg. Accessed May 4, 2021. https://www.ffmpeg.org/ 
この記事は旧サイト(UMIN)から移行したものです。内容は記載の公開・更新時点のものです。