feat: wire up all effects to audio processing pipeline

- Updated queue system to pass effects as dict instead of individual params
- Updated process_queue to handle effects_dict for previews
- Updated speak_message to extract all 7 effects from user settings
- Updated _generate_wav_bytes to accept effects dict and pass all params
- Updated _handle_voice_preview to use new effects dict system
- Effects now actually process the audio:
  - pitch, speed, echo, robot, chorus, tremolo_depth, tremolo_rate
- Fixed preview effect description to use preview_effects dict
This commit is contained in:
2026-01-31 17:25:52 -06:00
parent 795d5087e9
commit 7e76deed3d

72
bot.py
View File

@@ -514,18 +514,25 @@ class TTSBot(commands.Bot):
# Use user's current effects if not overridden
user_effects = self.voice_manager.get_user_effects(interaction.user.id)
final_pitch = preview_pitch if preview_pitch is not None else user_effects["pitch"]
final_speed = preview_speed if preview_speed is not None else user_effects["speed"]
effect_overrides = {}
if preview_pitch is not None:
effect_overrides["pitch"] = preview_pitch
if preview_speed is not None:
effect_overrides["speed"] = preview_speed
# Use default effects from user settings for preview
preview_effects = user_effects.copy()
preview_effects.update(effect_overrides)
# Queue the preview with voice override and effects
await self.message_queue.put((preview_message, preview_text, voice_name, final_pitch, final_speed))
await self.message_queue.put((preview_message, preview_text, voice_name, preview_effects))
# Build effect description
effect_desc = []
if final_pitch != 0:
effect_desc.append(f"pitch: {final_pitch:+d}")
if final_speed != 1.0:
effect_desc.append(f"speed: {final_speed:.1f}x")
if preview_effects.get("pitch", 0) != 0:
effect_desc.append(f"pitch: {preview_effects['pitch']:+d}")
if preview_effects.get("speed", 1.0) != 1.0:
effect_desc.append(f"speed: {preview_effects['speed']:.1f}x")
effect_str = f" (with {', '.join(effect_desc)})" if effect_desc else ""
@@ -622,24 +629,22 @@ class TTSBot(commands.Bot):
while True:
queue_item = await self.message_queue.get()
# Handle queue items of different lengths:
# Handle queue items:
# - (message, text) - regular message
# - (message, text, voice_name) - preview with voice override
# - (message, text, voice_name, pitch, speed) - preview with effects
if len(queue_item) == 5:
message, text, voice_override, pitch, speed = queue_item
# - (message, text, voice_override) - preview with voice override
# - (message, text, voice_override, effects_dict) - preview with effect overrides
if len(queue_item) == 4 and isinstance(queue_item[3], dict):
message, text, voice_override, effect_overrides = queue_item
elif len(queue_item) == 3:
message, text, voice_override = queue_item
pitch = None
speed = None
effect_overrides = {}
else:
message, text = queue_item
voice_override = None
pitch = None
speed = None
effect_overrides = {}
try:
await self.speak_message(message, text, voice_override, pitch, speed)
await self.speak_message(message, text, voice_override, effect_overrides)
except Exception as e:
print(f"Error processing message: {e}")
finally:
@@ -650,8 +655,7 @@ class TTSBot(commands.Bot):
message: discord.Message,
text: str,
voice_override: str | None = None,
pitch: int | None = None,
speed: float | None = None,
effect_overrides: dict | None = None,
) -> None:
"""Generate TTS and play it in the user's voice channel."""
if message.author.voice is None:
@@ -685,16 +689,14 @@ class TTSBot(commands.Bot):
)
return
# Get user's effects if not overridden
if pitch is None or speed is None:
# Get user's effects and apply any overrides
user_effects = self.voice_manager.get_user_effects(message.author.id)
if pitch is None:
pitch = user_effects["pitch"]
if speed is None:
speed = user_effects["speed"]
effects = user_effects.copy()
if effect_overrides:
effects.update(effect_overrides)
wav_bytes = await asyncio.to_thread(
self._generate_wav_bytes, voice_state, text, pitch, speed
self._generate_wav_bytes, voice_state, text, effects
)
audio_source = discord.FFmpegPCMAudio(
@@ -723,8 +725,7 @@ class TTSBot(commands.Bot):
self,
voice_state: Any,
text: str,
pitch: int = 0,
speed: float = 1.0,
effects: dict,
) -> bytes:
"""Generate audio and return as WAV file bytes."""
model = self.voice_manager.model
@@ -739,12 +740,21 @@ class TTSBot(commands.Bot):
audio_np = audio_np.reshape(-1, 1)
# Apply audio effects if any are active
if pitch != 0 or speed != 1.0:
print(f"Applying effects - Pitch: {pitch:+d}, Speed: {speed:.1f}x")
pitch = effects.get("pitch", AudioEffects.PITCH_DEFAULT)
speed = effects.get("speed", AudioEffects.SPEED_DEFAULT)
echo = effects.get("echo", AudioEffects.ECHO_DEFAULT)
robot = effects.get("robot", AudioEffects.ROBOT_DEFAULT)
chorus = effects.get("chorus", AudioEffects.CHORUS_DEFAULT)
tremolo_depth = effects.get("tremolo_depth", AudioEffects.TREMOLO_DEPTH_DEFAULT)
tremolo_rate = effects.get("tremolo_rate", AudioEffects.TREMOLO_RATE_DEFAULT)
if any([pitch != 0, speed != 1.0, echo > 0, robot > 0, chorus > 0, tremolo_depth > 0]):
print(f"Applying {AudioEffects.count_active_effects(**effects)} effect(s)...")
# Squeeze to 1D for librosa effects, then reshape back
audio_1d = audio_np.squeeze()
audio_1d, show_processing = AudioEffects.apply_effects(
audio_1d, model.sample_rate, pitch, speed
audio_1d, model.sample_rate,
pitch, speed, echo, robot, chorus, tremolo_depth, tremolo_rate
)
# Reshape back to 2D
audio_np = audio_1d.reshape(-1, 1)