Pedalboard によるエレクトロボイス生成(ソースコードと実行結果)

Python開発環境,ライブラリ類

ここでは、最低限の事前準備について説明する。機械学習や深層学習を行う場合は、NVIDIA CUDA、Visual Studio、Cursorなどを追加でインストールすると便利である。これらについては別ページ https://www.kkaneko.jp/cc/dev/aiassist.htmlで詳しく解説しているので、必要に応じて参照してください。

Python 3.12 のインストール

インストール済みの場合は実行不要。

管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要である。

REM Python をシステム領域にインストール
winget install --scope machine --id Python.Python.3.12 -e --silent
REM Python のパス設定
set "PYTHON_PATH=C:\Program Files\Python312"
set "PYTHON_SCRIPTS_PATH=C:\Program Files\Python312\Scripts"
echo "%PATH%" | find /i "%PYTHON_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_PATH%" /M >nul
echo "%PATH%" | find /i "%PYTHON_SCRIPTS_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_SCRIPTS_PATH%" /M >nul

関連する外部ページ

Python の公式ページ: https://www.python.org/

AI エディタ Windsurf のインストール

Pythonプログラムの編集・実行には、AI エディタの利用を推奨する。ここでは,Windsurfのインストールを説明する。

管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行して、Windsurfをシステム全体にインストールする。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要となる。

winget install --scope machine Codeium.Windsurf -e --silent

関連する外部ページ

Windsurf の公式ページ: https://windsurf.com/

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

コマンドプロンプトを管理者として実行(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する


pip install numpy pyaudio pedalboard

Pedalboard によるエレクトロボイス生成プログラム

概要

本プログラムは、音声信号処理により、入力音声をエレクトロボイスとして変換する。マイクからの音声入力を連続的に取得し、複数のデジタル信号処理エフェクトを適用することで、ロボット音声のような音響効果を生成する。

主要技術

参考文献

[1] Sobot, P. (2021). Pedalboard: A Python library for adding effects to audio. Spotify Research. https://github.com/spotify/pedalboard

[2] Bencina, R., & Burk, P. (2001). PortAudio - an open source cross platform audio API. In Proceedings of the International Computer Music Conference (pp. 263-266).


# プログラム名: Pedalboard によるエレクトロボイス生成プログラム
# 特徴技術名: Pedalboard(Spotify製オーディオエフェクトライブラリ)
# 出典: Sobot, P. (2021). Pedalboard: A Python library for audio effects. Spotify. https://github.com/spotify/pedalboard
# 特徴機能: エフェクトチェーンによるリアルタイム音声変換
# 学習済みモデル: 使用なし(DSPベースのエフェクト処理)
# 方式設計:
#   - 関連利用技術: NumPy(配列演算)、PyAudio(リアルタイム音声入出力)
#   - 入力と出力: 入力: マイクからのリアルタイム音声入力、出力: エレクトロボイスに変換された音声のリアルタイム再生
#   - 処理手順: 1.マイクから音声フレームを取得 2.無音検出とバイパス処理 3.NoiseGateでノイズ除去 4.PitchShiftでピッチ変更 5.Distortionでロボット感付与 6.Chorusで金属的響き追加 7.Gainで音量調整 8.Compressorで最終調整 9.スピーカーから出力
#   - 前処理、後処理: 前処理: 入力正規化とノイズゲート、後処理: クリッピング防止のための振幅制限
#   - 追加処理: RMSベースの無音検出による処理バイパス(CPU負荷軽減とノイズ防止)
#   - 調整を必要とする設定値: pitch_shift_semitones(ピッチシフト量、-12〜12半音)、distortion_drive_db(歪み量、0〜20dB)、noise_gate_threshold_db(ノイズゲート閾値、-60〜-20dB)、silence_threshold(無音判定閾値、0.0001〜0.01)
# 将来方策: pitch_shift_semitonesをMIDIコントローラーで制御可能にすることで、演奏中のリアルタイム音程変化を実現
# その他の重要事項: 低レイテンシ実現のため、CHUNKサイズ1024サンプルで最適化済み。RMSベースの無音検出により、無音時は処理をバイパスしてノイズを防止
# 前準備: pip install numpy pyaudio pedalboard

import numpy as np
import pyaudio
from pedalboard import Pedalboard, PitchShift, Distortion, Chorus, NoiseGate, Gain, Compressor
import threading

# 音声パラメータ
RATE = 44100
CHUNK = 1024
CHANNELS = 1
FORMAT = pyaudio.paFloat32

# エフェクトパラメータ(調整可能な設定値)
PITCH_SHIFT_SEMITONES = -5.0   # ピッチシフト量(-12〜12半音、負値で低音化)
DISTORTION_DRIVE_DB = 12.0     # 歪み量(0〜20dB、控えめに設定)
CHORUS_RATE_HZ = 1.5           # コーラス速度(0.1〜10Hz)
CHORUS_DEPTH = 0.3             # コーラス深度(0.0〜1.0)
CHORUS_MIX = 0.5               # コーラスミックス量(0.0〜1.0)
NOISE_GATE_THRESHOLD_DB = -40.0 # ノイズゲート閾値(-60〜-20dB)
GAIN_DB = -6.0                 # 最終ゲイン調整(歪み後の音量調整)

# コンプレッサーパラメータ
COMPRESSOR_THRESHOLD_DB = -15.0  # コンプレッサー閾値
COMPRESSOR_RATIO = 3.0            # コンプレッサー比率
COMPRESSOR_ATTACK_MS = 5.0        # アタック時間(ミリ秒)
COMPRESSOR_RELEASE_MS = 50.0      # リリース時間(ミリ秒)

# 無音検出・処理パラメータ
SILENCE_THRESHOLD = 0.001      # 無音判定閾値
CLIPPING_LIMIT = 0.95          # クリッピング防止の最大値

# 無音時用バッファ(事前作成で効率化)
SILENCE_BUFFER = np.zeros(CHUNK, dtype=np.float32)

# エフェクトチェーンの構築
effect_board = Pedalboard([
    NoiseGate(                                               # ノイズゲート(最初に配置)
        threshold_db=NOISE_GATE_THRESHOLD_DB,
        ratio=10.0,
        attack_ms=1.0,
        release_ms=100.0
    ),
    PitchShift(semitones=PITCH_SHIFT_SEMITONES),           # ピッチシフト
    Distortion(drive_db=DISTORTION_DRIVE_DB),              # 歪み(控えめ)
    Chorus(                                                 # コーラス(金属的響き)
        rate_hz=CHORUS_RATE_HZ,
        depth=CHORUS_DEPTH,
        mix=CHORUS_MIX
    ),
    Gain(gain_db=GAIN_DB),                                  # ゲイン調整
    Compressor(                                             # 最終段コンプレッサー
        threshold_db=COMPRESSOR_THRESHOLD_DB,
        ratio=COMPRESSOR_RATIO,
        attack_ms=COMPRESSOR_ATTACK_MS,
        release_ms=COMPRESSOR_RELEASE_MS
    )
])

def audio_callback(in_data, frame_count, time_info, status):
    # 入力データをnumpy配列に変換
    audio_data = np.frombuffer(in_data, dtype=np.float32)

    # 無音検出(RMS計算)
    rms = np.sqrt(np.mean(audio_data**2))

    # 無音時は事前作成バッファを返す(効率化)
    if rms < SILENCE_THRESHOLD:
        return (SILENCE_BUFFER.tobytes(), pyaudio.paContinue)

    try:
        # Pedalboardでエフェクト処理
        # 1次元配列のまま処理
        processed_audio = effect_board(audio_data, sample_rate=RATE)

        # クリッピング防止(定数使用)
        processed_audio = np.clip(processed_audio, -CLIPPING_LIMIT, CLIPPING_LIMIT)

        # float32として返す
        return (processed_audio.astype(np.float32).tobytes(), pyaudio.paContinue)

    except Exception:
        # エラー時は入力をそのまま返す(エラーログは出さない)
        return (audio_data.tobytes(), pyaudio.paContinue)

print('エレクトロボイス生成システムを開始します')
print('マイクに向かって話すと、エレクトロボイスに変換されます')
print('終了するには Ctrl+C を押してください')
print(f'現在の設定: ピッチシフト={PITCH_SHIFT_SEMITONES}半音, 歪み={DISTORTION_DRIVE_DB}dB')
print(f'ノイズゲート={NOISE_GATE_THRESHOLD_DB}dB, 無音閾値={SILENCE_THRESHOLD}')

try:
    p = pyaudio.PyAudio()

    stream = p.open(format=FORMAT,
                    channels=CHANNELS,
                    rate=RATE,
                    input=True,
                    output=True,
                    frames_per_buffer=CHUNK,
                    stream_callback=audio_callback)

    stream.start_stream()

    while stream.is_active():
        try:
            threading.Event().wait(0.1)
        except KeyboardInterrupt:
            break

    stream.stop_stream()
    stream.close()
    p.terminate()

except Exception as e:
    print(f'エラーが発生しました: {e}')
    exit()

print('エレクトロボイス生成システムを終了しました')