TECH NOTE / 005

WindowsでIrodori-TTSの声を作り、Codexの返答を自動読み上げさせた備忘録

VoiceDesignで作った声を、CodexのStopフックと非同期ワーカー経由でローカル再生するまでの構成、観測、調整をまとめます。

01 / OVERVIEW

声を作り、返答の要点だけを読む

これはCodexの標準機能ではなく、ローカルで組み合わせた独自連携です。2026-08-19に記録した構成と観測をもとにしており、Codexのフック、画面、同梱CLIの配置や操作はバージョンで変わり得ます。

  1. TTS要約返答末尾へ短い要約を付ける
  2. Stopフック最後のタグを抽出し、対象と重複を確認する
  3. 非同期ワーカージョブを受け、ローカルAPIへ渡す
  4. 生成と再生WAVを処理して音量を調整し、再生する

時間のかかるモデル推論をStopフック内で待たず、ジョブ登録後は別プロセスへ任せる構成にしました。

02 / IRODORI-TTS

VoiceDesignをループバックで動かす

記録時はWindows、NVIDIA GPU / CUDA 12.8、uv、Irodori-TTS v4系(revision 8224daf)、Aratako/Irodori-TTS-v4.1-Smallgradio_app_voicedesign.pyを使い、127.0.0.1:7861でVoiceDesign UIを起動しました。

記録時の項目
GPUバックエンドNVIDIA CUDA 12.8向け環境
パッケージ管理uv
checkpointAratako/Irodori-TTS-v4.1-Small
UI / URLgradio_app_voicedesign.py / 127.0.0.1:7861
launch exampleRECORDED CONFIG
uv sync --extra cu128
uv run --no-sync python gradio_app_voicedesign.py --server-name 127.0.0.1 --server-port 7861

uv sync --extra cu128は当時のGPUバックエンド向けの例で、すべての環境に共通するコマンドではありません。外部公開ではなくループバックへ限定する意図で127.0.0.1を使いました。Irodori-TTS公式READMEは2026-09-11に、v4.1-Small、VoiceDesign UI、uvのバックエンド別extraを確認しています。

03 / VOICE DESIGN

説明文と三つの評価文で声を選ぶ

落ち着いた成人女性の声。やや低めで澄んだ音色。知的だが冷たくなく、自然体。親しい相手に少し近い距離感で話す。感情は控えめだが好奇心がにじむ。幼すぎる声、甲高い声、芝居がかった演技は避ける。
evaluation textTHREE TESTS
今確認できているのはここまで。まだ推測の部分もあるから、次は実際の動作を見て判断しよう。

それ、ちょっと面白いね。どういう条件で変わるのか、もう少し中を見てみたい。

いや待って。それを直すために機能を三つ増やすのは違う。

各文章から選んだWAVを一本ずつ、合計三本を参照音声にしました。採用時のseedと評価文の対応を保存していなかったため、同一候補の再現性には限界が残ります。実際のWAVや固有のファイル名は掲載しません。

設定採用値
Num Steps / candidates40 / 1
seed / seconds / durationrandom / auto / 1.0
schedule / guidancelinear / independent
CFGtext 3.0 / caption 4.0 / speaker 5.0
model / codeccuda fp32 / cuda fp32

04 / SIBILANCE

歯擦音は狭い帯域だけで比較した

約13kHz付近の電子的な歯擦音が気になったため、常時EQではなく、対象帯域が強い瞬間だけを抑える処理を比較しました。

試行対象帯域最大減衰観測
Mild11.5–15.2 kHz4 dB変化が小さかった
Strong11.5–15.2 kHz8 dB問題がまだ残った
Focused12.3–14.5 kHz16 dB改善した
Focused12.3–14.5 kHz24 dBこの声では採用した
postprocess.jsonADOPTED EXAMPLE
{
  "max_reduction_db": 24.0,
  "low_hz": 12300.0,
  "high_hz": 14500.0,
  "threshold_percentile": 82.0,
  "knee_db": 8.0,
  "detector_ms": 8.0,
  "attack_ms": 0.8,
  "release_ms": 30.0
}

これはこの環境、この生成音声に対する局所的な調整結果です。別の声へそのまま適用する一般的な推奨ではありません。

05 / TTS TAG

詳細な本文と、短い読み上げ要約を分ける

response suffixTTS FORMAT
<TTS>重要な結論と次の行動だけを、短い自然な文章で書く。</TTS>
  • 一つだけ置く

    返答末尾に一つだけ置き、閉じタグより後ろへ文字を書かない。

  • 音声向けに短くする

    Markdown、コード、URL、引用や出典表記を含めず、自然な話し言葉にする。

  • 運用例として扱う

    これは記録時のAGENTS.md運用例であり、Codexの将来仕様を断定するものではない。

06 / HOOK & WORKER

Stopフックは登録だけを行い、生成は非同期へ渡す

hooks.jsonGENERALIZED EXAMPLE
{
  "hooks": {
    "Stop": [{
      "hooks": [{
        "type": "command",
        "command": "powershell.exe -NoProfile -ExecutionPolicy Bypass -File \"<TTS_PROJECT>\\tools\\codex_tts_hook.ps1\"",
        "timeout": 10,
        "async": true
      }]
    }]
  }
}
  1. 読み上げが有効か、cwdが許可リスト内か確認する。
  2. 最後の<TTS>だけを抽出し、空なら終了する。
  3. 内容からSHA-256のジョブIDを作り、同じジョブを重複実行しない。
  4. ローカルのジョブJSONを作り、非表示のPowerShellワーカーを起動する。
  5. 失敗はローカルログへ残し、Codexの停止処理を妨げない。
hook stdoutSUCCESS
{"continue":true}

ワーカーはhttp://127.0.0.1:7861/gradio_api/infoで起動確認を行い、VoiceDesign呼び出し、生成WAVの保存、歯擦音処理、gain調整、成果物・レポート保存、winsound再生を行います。ジョブはファイルロックで直列化しました。

automation.jsonSCOPE EXAMPLE
{
  "scope": {
    "allowed_project_roots": [
      "<PROJECT_ROOT_A>",
      "<PROJECT_ROOT_B>"
    ]
  }
}

グローバルフックでローカルの全Codex作業を無条件に読まないよう、明示的に許可したプロジェクトだけを対象にします。

07 / OBSERVATIONS

実際に詰まった点

  • CLIの配置

    codexが見つからず、当時はCodex Desktop同梱の実行ファイルを使いました。記録時の版は0.148.0-alpha.15で、将来の配置は保証されません。

  • フックの信頼

    /hooksで内容を確認してから信頼しました。当時の画面で観測した信頼操作のキーTも、将来の操作として断定しません。

  • 二重実行

    ユーザー設定とプロジェクト設定へ同じStopフックを置くと二重実行されたため、プロジェクト側の重複を外しました。

  • プロセス寿命

    Codexの子プロセスとして起動すると終了時にWeb UIも止まったため、独立したCMDランチャーへ分けました。

08 / GAIN

再生音量は会話で比較して決める

ゲイン振幅比試聴結果
-6 dB約0.50まだ大きかった
-12 dB約0.25まだ大きかった
-20 dB0.10この環境で採用した
amplitude ratioFORMULA
amplitude_ratio = 10^(gain_db / 20)

-20 dBはこの環境で採用した値であり、一般的な推奨ではありません。振幅比と人間が感じる音量も同じ尺度ではありません。

09 / STRUCTURE & SAFETY

構成を分け、安全境界を明示する

directory structureGENERALIZED
<TTS_PROJECT>/
├─ AGENTS.md
├─ tools/
│  ├─ start-irodori-tts.cmd
│  ├─ codex_tts_hook.ps1
│  ├─ codex_tts_worker.ps1
│  ├─ codex_tts_worker.py
│  └─ process_irodori_sibilance.py
└─ voice/
   ├─ AUTOMATION.md
   ├─ automation.json
   ├─ generated/YYYY-MM-DD/
   ├─ runtime/jobs/ and logs/
   └─ voice-profile-v1/
      ├─ profile.json
      ├─ postprocess.json
      └─ reference/selected-reference-wavs...
症状今回の原因・確認点
Web UIのCMDを開くとエラーになるIrodori-TTS、uv、起動対象スクリプトのパスと、ランチャーの用途を確認する。
返答後に音が出ないWeb UI、TTSタグ、対象プロジェクトが許可リスト内かを確認する。
Codex再起動後に音が出ないCodex終了時にWeb UIまで停止していないか確認し、Web UIを独立起動する。
codexコマンドが見つからないスタンドアロンCLIのPATHまたはDesktop同梱CLIの有無を確認する。
Hooks need review/hooksでソースとコマンドを確認し、納得したものだけ信頼する。
Stopフックが複数表示されるユーザー設定とプロジェクト設定の重複を確認する。複数の一致フックはすべて動く。
初回の読み上げが遅いモデルとcodecの初回ロードを通常時と分けて評価する。
さ行に電子的な音が乗る問題帯域を測り、狭い帯域の動的処理を比較する。
処理後のさ行が弱すぎる最大抑制量、帯域、閾値を弱め、通常文章で再評価する。
読み上げ音量が大きい再生前に負のゲインを適用し、デシベルと振幅比を混同しない。
別プロジェクトで読まないそのプロジェクトのAGENTS.mdとフック側の許可リストを確認する。
設定変更が既存チャットへ反映されない新しいセッションで開始するか、AGENTS.mdを読み直す。
  • TTSサーバーはループバックだけへbindする。
  • スクリプトやフックへ認証情報を書かない。
  • <TTS>へ個人情報や秘密情報を入れない。
  • WAV、ジョブJSON、ログは公開ディレクトリへ置かない。
  • フックは内容を確認してから信頼し、声や参照音声の権利・同意を確認する。
  • 公開例ではユーザー名、パス、プロジェクト名、音声名、ハッシュを一般化する。

記録時の最終設定

項目採用値
TTSモデルAratako/Irodori-TTS-v4.1-Small
参照音声選定した生成WAV三本
VoiceDesign caption落ち着いた成人女性、やや低め、自然体、近い距離感
歯擦音処理12.3–14.5 kHzを検出時に最大24 dB抑制
全体再生ゲイン-20 dB、振幅比0.10
Web UI127.0.0.1:7861で独立起動
Codex連携Stopフックから非同期ジョブ登録
読み上げ対象回答末尾の最後のTTSタグだけ
プロジェクト範囲明示的な許可リスト
保存元WAV、処理後WAV、ジョブ状態、ログ

10 / FINAL CHECK

導入時の確認項目

これは閲覧用のチェックリストです。サイト上で操作する項目ではありません。

  • Irodori-TTSの現在のREADMEと対応バックエンドを確認する
  • uv環境を適切なGPUまたはCPU extraで同期する
  • Web UIを127.0.0.1で起動する
  • caption、モデル、全生成設定を保存する
  • 各候補の文章、seed、採用理由を保存する
  • 参照WAVは未加工のまま保持する
  • 問題音は印象だけでなく、発生箇所と帯域も確認する
  • 後処理は弱い版から比較し、通常文章でも評価する
  • AGENTS.mdへTTS要約の書式を追加する
  • Stopフックは一か所だけへ登録する
  • /hooksでフック内容を確認して信頼する
  • Web UIをCodexとは独立して起動する
  • 許可プロジェクト以外ではフックが何もしないことを試す
  • 同一ジョブの重複防止を確認する
  • 初回ロードと通常時の待ち時間を分けて評価する
  • 再生音量を実際の会話で調整する
  • ログや公開用記事に個人情報・秘密情報がないか確認する

11 / REFERENCES

まとめと参考リンク

声づくりだけでなく、短い要約の形式、Stopフックからの非同期化、Web UIの寿命、重複設定、局所的な後処理、音量、プロジェクト範囲の制御を分けて扱うことで、問題を個別に観測して直せる構成になりました。

公式情報は利用時点で再確認してください。