diff --git a/wsai/backends/emotion.py b/wsai/backends/emotion.py index 98a080a..cfe7cd4 100644 --- a/wsai/backends/emotion.py +++ b/wsai/backends/emotion.py @@ -23,27 +23,33 @@ from dataclasses import dataclass # Canonical emotion -> (speed multiplier relative to base, pitch shift in semitones). # Kept deliberately modest so delivery stays natural, not cartoonish. +# +# Pitch is held at 0.0 for every emotion: librosa's post-hoc pitch_shift on Melo +# output produced a robotic, "monster"-sounding artefact (worse when stacked on a +# fast base speed). Emotion is therefore conveyed by speed only — natural and +# artefact-free. The pitch column is retained (rather than removed) so the effect +# can be re-enabled per-emotion later with a real, artefact-free pitch method. EMOTION_PARAMS: dict[str, tuple[float, float]] = { - "happy": (1.08, 2.0), # 기쁨 / cheerful - "excited": (1.15, 3.0), # 신남 / excited - "hopeful": (1.10, 1.5), # 희망 / 힘차게 - "sad": (0.90, -2.5), # 슬픔 / sad - "angry": (1.12, 1.0), # 화남 / angry - "fearful": (1.12, 2.0), # 두려움 / terrified - "surprised": (1.05, 3.0), # 놀람 / surprise - "disgust": (0.96, -1.0), # 혐오 / disgust - "calm": (0.95, -1.0), # 차분 / calm - "friendly": (1.00, 1.0), # 다정 / friendly - "serious": (0.97, -1.0), # 진지 / serious - "disappointed":(0.92, -2.0), # 실망 / disappointed - "tired": (0.90, -2.0), # 피곤 / 지침 - "affectionate":(0.98, 1.0), # 사랑스럽게 / affectionate - "playful": (1.08, 2.0), # 장난스럽게 / playful - "whisper": (0.92, -1.5), # 속삭임 / whispering - "shout": (1.05, 2.5), # 외침 / shouting - "determined": (1.05, 0.5), # 단호 / determined - "relieved": (0.95, 0.5), # 안도 / relieved - "curious": (1.03, 1.5), # 궁금 / curious + "happy": (1.08, 0.0), # 기쁨 / cheerful + "excited": (1.15, 0.0), # 신남 / excited + "hopeful": (1.10, 0.0), # 희망 / 힘차게 + "sad": (0.90, 0.0), # 슬픔 / sad + "angry": (1.12, 0.0), # 화남 / angry + "fearful": (1.12, 0.0), # 두려움 / terrified + "surprised": (1.05, 0.0), # 놀람 / surprise + "disgust": (0.96, 0.0), # 혐오 / disgust + "calm": (0.95, 0.0), # 차분 / calm + "friendly": (1.00, 0.0), # 다정 / friendly + "serious": (0.97, 0.0), # 진지 / serious + "disappointed":(0.92, 0.0), # 실망 / disappointed + "tired": (0.90, 0.0), # 피곤 / 지침 + "affectionate":(0.98, 0.0), # 사랑스럽게 / affectionate + "playful": (1.08, 0.0), # 장난스럽게 / playful + "whisper": (0.92, 0.0), # 속삭임 / whispering + "shout": (1.05, 0.0), # 외침 / shouting + "determined": (1.05, 0.0), # 단호 / determined + "relieved": (0.95, 0.0), # 안도 / relieved + "curious": (1.03, 0.0), # 궁금 / curious } # Every spelling Claude might realistically emit, mapped to a canonical emotion. diff --git a/wsai/backends/melo.py b/wsai/backends/melo.py index d1ef5f6..f77a54e 100644 --- a/wsai/backends/melo.py +++ b/wsai/backends/melo.py @@ -12,7 +12,7 @@ Env: WSAI_MELO_DEVICE cpu | cuda | auto (default auto: GPU if torch sees one, else CPU; the worker falls back to CPU if CUDA fails) WSAI_TTS_OUT_DIR where wavs are written (default ~/.cache/wsai/tts) - WSAI_TTS_SPEED synthesis speed multiplier (default 1.3) + WSAI_TTS_SPEED synthesis speed multiplier (default 1.0) """ from __future__ import annotations @@ -93,7 +93,7 @@ class MeloTTS: self.out_dir = Path(out_dir or os.environ.get("WSAI_TTS_OUT_DIR") or (Path.home() / ".cache/wsai/tts")) self.speed = float(speed if speed is not None - else os.environ.get("WSAI_TTS_SPEED", "1.3")) + else os.environ.get("WSAI_TTS_SPEED", "1.0")) self.sink = sink or _log_sink self._proc: asyncio.subprocess.Process | None = None self._lock = asyncio.Lock()