
VOICEPEAKをPythonから操作して、ChatGPTの返答を「感情つきの音声」に変換するスクリプトを作りました。
SAPI連携ではなく、コマンドライン引数を使った直接制御で動かしています。
🎯 やりたいこと
- ChatGPTに発言させたい
- その返答をVOICEPEAKで喋らせたい
- 感情パラメータも自動で入れたい
- 音声を自動再生したい
- 最終的には3Dアバターにリップシンクさせたい(→VoiceMeeter Bananaで明日以降実装予定)
📦 使用ツール
- VOICEPEAK(Minase Kou)
- ChatGPT(OpenAI API)
- Python 3.x
- winsound(標準モジュール)
- subprocess(標準モジュール)
📁 ファイル構成
- chatgpt_3d/
- output/
- reply.txt # ChatGPTの返答テキスト
- scripts/
- chatgpt_speaks.py # 今回作った音声合成スクリプト
- output/
🐍 chatgpt_speaks.py の中身
import subprocess import tempfile import os import winsound import re import random import time # === 設定 === VOICEPEAK_PATH = r"C:\Program Files\VOICEPEAK\voicepeak.exe" NARRATOR = "Minase Kou" SPEED = 135 PITCH = -75 DEFAULT_EMOTIONS = { 'genki': 100, 'happy': 100, 'angry': 75, 'sad': 5, 'sasayaki': 0, } def random_emotions(): return { 'genki': random.randint(-10, 0), 'happy': random.randint(-10, 0), 'angry': random.randint(-10, 10), 'sad': random.randint(-5, 10), 'sasayaki': random.randint(0, 10), } def build_emotion_string(): delta = random_emotions() combined = { k: max(0, DEFAULT_EMOTIONS[k] + delta[k]) for k in DEFAULT_EMOTIONS } return ",".join(f"{k}={v}" for k, v in combined.items() if v > 0) def split_sentences(text, max_len=140): raw_sentences = re.split(r'(?<=[。!?])', text) chunks = [] current = '' for sentence in raw_sentences: if len(current) + len(sentence) <= max_len: current += sentence else: if current: chunks.append(current.strip()) current = sentence if current: chunks.append(current.strip()) return [c for c in chunks if c] def speak(text): emotion = build_emotion_string() with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp_wav: wav_path = tmp_wav.name cmd = [ VOICEPEAK_PATH, "-s", text, "-n", NARRATOR, "-e", emotion, "-o", wav_path, "--speed", str(SPEED), "--pitch", str(PITCH) ] subprocess.run(cmd) return wav_path # === 実行 === with open("chatgpt_3d/output/reply.txt", encoding="utf-8") as f: full_text = f.read() sentences = split_sentences(full_text) wav_files = [] for s in sentences: print(f"🗣️ {s}") wav_files.append(speak(s)) time.sleep(0.3) for wav_path in wav_files: winsound.PlaySound(wav_path, winsound.SND_FILENAME) os.remove(wav_path)
👣 今後の展望
- VoiceMeeter Bananaを導入して、音声出力をVB-CABLE経由で3teneに送信
- 3teneのリップシンクでキャラが「喋ってるように」見せる
- ChatGPTのAPIと連携し、完全に自動応答するアバターへ進化予定
📝 おわりに
CLI連携に切り替えたことで、VOICEPEAKの柔軟なコントロールが可能になりました。 Pythonの中で感情パラメータも制御できるので、音声の“表情”を作るのが楽しくなります。
次は「キャラが口を動かす」段階へ。 物語の“声”が、いよいよ“存在”になっていきます。
💬 おまけ:キャラAIの感情制御について興味がある人へ
感情パラメータの扱いは、人間らしさと制御性のバランスが大事。 今回はランダム生成でしたが、「入力内容に応じた感情制御」も今後試したいですね。
