fix(classroom): audio speed slider now actually changes playback speed with pitch correction

- Fix client: playbackRate was set to 1 for non-native-speed providers (Speaches/Piper),
  making the speed slider ineffective in the main Pizzicato audio path
- Fix server: pass speed parameter to Speaches TTS API
- Add pitch-preserving playback via MediaElementSourceNode when rate != 1,
  routing through the same Web Audio effects chain (radio filters, distortion, etc.)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
itsrubberduck
2026-02-15 01:01:02 +01:00
parent ea51e1dcc3
commit 5a25e212d7
3 changed files with 108 additions and 28 deletions

View File

@@ -89,7 +89,8 @@ async function speachesTTS(
voice: string,
model: string,
response_format: AudioFmt,
baseUrl: string
baseUrl: string,
speed: number = 1.0
): Promise<Buffer> {
const url = `${baseUrl.replace(/\/+$/, "")}/v1/audio/speech`;
const body = {
@@ -97,7 +98,8 @@ async function speachesTTS(
model,
voice,
// API erwartet "response_format": "mp3" | "flac" | "wav" | "pcm"
response_format
response_format,
speed
};
const res = await fetch(url, {
method: "POST",
@@ -174,7 +176,7 @@ export default defineEventHandler(async (event) => {
if (!baseUrl) {
throw new Error("SPEACHES_BASE_URL not set");
}
audioBuffer = await speachesTTS(normalized, voice, model, fmt, baseUrl);
audioBuffer = await speachesTTS(normalized, voice, model, fmt, baseUrl, speed);
modelUsed = model;
// Server returns the correct format according to response_format
actualMime = fmtToMime(fmt);