feat: Bilibili Live Danmaku -> Yukkuri TTS Reader
- Python main entry with CLI (--room-id, --voice, --speed) - blivedm integration for real-time danmaku receiving - Chinese-to-Japanese katakana conversion (pypinyin + mapping table) - Node.js persistent bridge for aquestalk.js TTS synthesis - Audio playback via sounddevice - Message queue for sequential TTS playback
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
"""Audio playback for WAV files."""
|
||||
|
||||
import asyncio
|
||||
import io
|
||||
import logging
|
||||
|
||||
import sounddevice as sd
|
||||
import soundfile as sf
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def play_wav(wav_data: bytes) -> None:
|
||||
"""Play WAV audio data synchronously (blocking).
|
||||
|
||||
Args:
|
||||
wav_data: Raw WAV file bytes.
|
||||
"""
|
||||
data, samplerate = sf.read(io.BytesIO(wav_data), dtype="float32")
|
||||
sd.play(data, samplerate)
|
||||
sd.wait()
|
||||
|
||||
|
||||
async def play_wav_async(wav_data: bytes) -> None:
|
||||
"""Play WAV audio data asynchronously.
|
||||
|
||||
Args:
|
||||
wav_data: Raw WAV file bytes.
|
||||
"""
|
||||
loop = asyncio.get_running_loop()
|
||||
await loop.run_in_executor(None, play_wav, wav_data)
|
||||
|
||||
|
||||
def get_output_devices() -> list[dict]:
|
||||
"""List available audio output devices."""
|
||||
devices = sd.query_devices()
|
||||
result = []
|
||||
for i, dev in enumerate(devices):
|
||||
if dev["max_output_channels"] > 0:
|
||||
result.append({
|
||||
"index": i,
|
||||
"name": dev["name"],
|
||||
"channels": dev["max_output_channels"],
|
||||
"default_samplerate": dev["default_samplerate"],
|
||||
})
|
||||
return result
|
||||
Reference in New Issue
Block a user