suzuna / state kotoha ph3x

Suzuna — STATE Ph3.x 録音品質UI

概要

Phase 1〜3で構築した変換・学習・TTSパイプラインに、 録音品質を担保するための前処理UIを追加する。

「失敗しない録音」を提供することで、学習データの品質を底上げし、 最終的なカスタムモデルの完成度を高める。


音声処理パイプライン

録音 / インポート

① 無音トリミング       (自動)

② ノイズリダクション   (自動 / 強度調整可)

③ ローカット / ハイカット(デフォルト値あり / スライダー調整可)

④ ゲイン調整           (オートノーマライズ or 手動)

⑤ 品質スコア表示       (自動算出)

学習データとして保存 / RVC変換へ

UI構成

録音パネル(ConvertPage / RecordPage)

┌─ 録音 ────────────────────────────────────────┐
│  [🎤 録音開始]                                  │
│                                                 │
│  波形: ▁▂▄▆▄▂▁▃▅▃▁  (リアルタイム)           │
│                                                 │
│  音量: [████████░░] -12dB  ← 適正              │
│        ⚠ クリッピング警告  / ⚠ 小さすぎ警告    │
│                                                 │
│  環境音: 静か ✅  / ノイズ多め ⚠ / 大きい ❌   │
└─────────────────────────────────────────────────┘

録音前チェック(マイク接続時に自動実行)

  • 3秒間の環境音を測定
  • ノイズレベルを判定 → UI上にバッジ表示
    • ✅ 静か(-50dB以下)
    • ⚠ ノイズあり(-50〜-35dB)
    • ❌ 大きい(-35dB以上)

音声処理パネル(録音後 / インポート後)

┌─ 音声処理 ─────────────────────────────────────┐
│  入力: voice_001.wav  [▶試聴]                   │
│                                                 │
│  [✅ 無音トリミング]  自動検出・除去             │
│                                                 │
│  ノイズリダクション                  強度: 0.5  │
│  [──────●──────────]                           │
│                                                 │
│  ローカット                          80 Hz      │
│  [●───────────────]  20〜500Hz                 │
│                                                 │
│  ハイカット                         16000 Hz    │
│  [──────────────●─]  8k〜24kHz                 │
│                                                 │
│  ゲイン調整                                     │
│  ○ オートノーマライズ(ピーク -3dB)            │
│  ○ 手動  [──●──────]  +0.0 dB  (-12〜+12)     │
│                                                 │
│  [▶ 処理を適用]  [↩ リセット]                  │
│                                                 │
│  出力: voice_001_processed.wav  [▶試聴]         │
└─────────────────────────────────────────────────┘

品質スコアパネル

┌─ 録音品質スコア ───────────────────────────────┐
│                                                 │
│           87 / 100  良好 ✅                     │
│                                                 │
│  ノイズレベル   ████████░░  良好                │
│  音量安定度     ███████░░░  普通                │
│  クリッピング   ██████████  問題なし            │
│  無音比率       █████████░  良好                │
│                                                 │
│  💡 音量安定度を上げるにはマイクとの距離を       │
│     一定に保ってください                        │
└─────────────────────────────────────────────────┘

スコア算出ロジック

項目配点算出方法
ノイズレベル30点SNR(信号対雑音比)から換算
音量安定度25点RMS音量の分散から換算
クリッピング25点サンプル値が0.99以上の割合
無音比率20点無音区間が全体の20〜40%が理想

Pythonバックエンド

依存ライブラリ

librosa        # 波形解析・特徴量抽出 (ISC License)
scipy          # ローカット/ハイカットフィルター (BSD)
noisereduce    # ノイズリダクション (MIT)
soundfile      # WAV読み書き (BSD)
numpy          # 数値演算 (BSD)

API追加

POST /audio/process
  body: {
    input_path: string,
    trim_silence: bool,          // 無音トリミング (default: true)
    noise_reduce: float,         // ノイズリダクション強度 0〜1 (default: 0.5, 0=無効)
    lowcut_hz: int,              // ローカット周波数 (default: 80)
    highcut_hz: int,             // ハイカット周波数 (default: 16000)
    gain_mode: "auto" | "manual",
    gain_db: float               // 手動ゲイン -12〜+12 (default: 0)
  }
  response: {
    output_path: string,
    score: QualityScore
  }

POST /audio/score
  body: { input_path: string }
  response: QualityScore

GET /audio/env-check
  response: {
    noise_level_db: float,
    status: "quiet" | "noisy" | "loud"
  }

# WebSocket: リアルタイム波形・音量レベル
WS /audio/monitor
  stream: {
    waveform: float[],    // 波形データ (128サンプル/フレーム)
    rms_db: float,        // 現在のRMS音量
    clipping: bool        // クリッピング検出
  }

型定義

interface QualityScore {
  total: number           // 0〜100
  grade: "excellent" | "good" | "fair" | "poor"
  noise: number           // 0〜30
  stability: number       // 0〜25
  clipping: number        // 0〜25
  silence_ratio: number   // 0〜20
  advice?: string         // 改善アドバイス
}

Python実装スケルトン

# python/routers/audio_process.py

import numpy as np
import librosa
import soundfile as sf
from scipy.signal import butter, sosfilt
import noisereduce as nr

def process_audio(input_path, output_path, config):
    y, sr = librosa.load(input_path, sr=None)

    # ① 無音トリミング
    if config.trim_silence:
        y, _ = librosa.effects.trim(y, top_db=30)

    # ② ノイズリダクション
    if config.noise_reduce > 0:
        y = nr.reduce_noise(y=y, sr=sr, prop_decrease=config.noise_reduce)

    # ③ ローカット / ハイカット
    if config.lowcut_hz > 0:
        sos = butter(4, config.lowcut_hz, btype='high', fs=sr, output='sos')
        y = sosfilt(sos, y)
    if config.highcut_hz < sr // 2:
        sos = butter(4, config.highcut_hz, btype='low', fs=sr, output='sos')
        y = sosfilt(sos, y)

    # ④ ゲイン調整
    if config.gain_mode == "auto":
        peak = np.max(np.abs(y))
        if peak > 0:
            target = 10 ** (-3 / 20)  # -3dBFS
            y = y * (target / peak)
    else:
        gain_linear = 10 ** (config.gain_db / 20)
        y = np.clip(y * gain_linear, -1.0, 1.0)

    sf.write(output_path, y, sr)
    return calc_quality_score(y, sr)

def calc_quality_score(y, sr):
    # ノイズレベル (SNR推定)
    rms = np.sqrt(np.mean(y**2))
    noise_floor = np.percentile(np.abs(y), 10)
    snr = 20 * np.log10(rms / (noise_floor + 1e-10))
    noise_score = min(30, max(0, (snr - 10) / 30 * 30))

    # 音量安定度
    frame_rms = librosa.feature.rms(y=y)[0]
    stability = 1 - min(1, np.std(frame_rms) / (np.mean(frame_rms) + 1e-10))
    stability_score = stability * 25

    # クリッピング
    clip_ratio = np.mean(np.abs(y) > 0.99)
    clipping_score = max(0, 25 - clip_ratio * 1000)

    # 無音比率
    silence_ratio = np.mean(np.abs(y) < 0.01)
    silence_score = 20 if 0.2 <= silence_ratio <= 0.4 else max(0, 20 - abs(silence_ratio - 0.3) * 50)

    total = int(noise_score + stability_score + clipping_score + silence_score)

    return {
        "total": total,
        "grade": "excellent" if total >= 90 else "good" if total >= 70 else "fair" if total >= 50 else "poor",
        "noise": int(noise_score),
        "stability": int(stability_score),
        "clipping": int(clipping_score),
        "silence_ratio": int(silence_score),
        "advice": get_advice(noise_score, stability_score, clipping_score)
    }

デフォルト値まとめ

パラメーターデフォルト推奨範囲備考
無音トリミングON常時推奨
ノイズリダクション0.50.3〜0.7強すぎると声質劣化
ローカット80Hz60〜200Hzファン・エアコン除去
ハイカット16000Hz12k〜20kHz高周波ノイズ除去
ゲインモードオートピーク -3dBFS

完了条件

  • リアルタイム波形・音量メーター(WebSocket)
  • 録音前環境音チェック(3秒計測)
  • 無音トリミング
  • ノイズリダクション(強度スライダー)
  • ローカット / ハイカットフィルター
  • ゲイン調整(オート / 手動)
  • 品質スコア表示(4項目 + アドバイス)
  • 処理前後の試聴比較