From 07965e9fe93fc7b53dfe7c933f8abd0c4b10c86d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Tue, 21 Jul 2026 14:32:13 +0200 Subject: [PATCH] fix(studio): play preview audio at speeds above 1x (#2691) * fix(studio): play preview audio at speeds above 1x The player force-muted preview audio whenever playback rate exceeded 1x and disabled the mute button (and the M shortcut) in that state. Users changing speed to 2x heard nothing, and clicking unmute did nothing. Media elements play audio fine at any rate (pitch preserved by default), so remove the special case: audio now follows only the user's mute toggle at every speed. Drops the shouldMutePreviewAudio helper and the audioAutoMuted UI/keyboard gating that existed solely for it. * test(studio): update seek audio test for unmuted-above-1x behavior useTimelinePlayer.seek.test.ts still asserted the old force-mute: at 2x with the user unmuted it expected a set-muted{muted:true} message. With audio now following only the user's toggle, the preview receives set-muted{muted:false}. Update the assertion and title to match. --- .../player/components/PlayerControls.test.ts | 17 ---------- .../src/player/components/PlayerControls.tsx | 31 +++++-------------- .../player/hooks/usePlaybackKeyboard.test.ts | 4 +-- .../src/player/hooks/usePlaybackKeyboard.ts | 5 +-- .../hooks/useTimelinePlayer.seek.test.ts | 4 +-- .../src/player/hooks/useTimelinePlayer.ts | 18 +++-------- packages/studio/src/player/lib/timelineDOM.ts | 1 - .../src/player/lib/timelineIframeHelpers.ts | 4 --- 8 files changed, 18 insertions(+), 66 deletions(-) diff --git a/packages/studio/src/player/components/PlayerControls.test.ts b/packages/studio/src/player/components/PlayerControls.test.ts index fad6e3cd6..84f23ac59 100644 --- a/packages/studio/src/player/components/PlayerControls.test.ts +++ b/packages/studio/src/player/components/PlayerControls.test.ts @@ -1,6 +1,5 @@ import { describe, expect, it } from "vitest"; import { resolveSeekPercent } from "./PlayerControls"; -import { shouldMutePreviewAudio } from "../lib/timelineIframeHelpers"; describe("resolveSeekPercent", () => { it("returns 0 when the track width is invalid", () => { @@ -19,19 +18,3 @@ describe("resolveSeekPercent", () => { expect(resolveSeekPercent(150, 100, 200)).toBe(0.25); }); }); - -describe("shouldMutePreviewAudio", () => { - it("mutes when the user toggled audio off", () => { - expect(shouldMutePreviewAudio(true, 1)).toBe(true); - }); - - it("auto-mutes above 1x playback", () => { - expect(shouldMutePreviewAudio(false, 1.5)).toBe(true); - expect(shouldMutePreviewAudio(false, 2)).toBe(true); - }); - - it("keeps audio on at 1x or slower when the user has not muted it", () => { - expect(shouldMutePreviewAudio(false, 1)).toBe(false); - expect(shouldMutePreviewAudio(false, 0.5)).toBe(false); - }); -}); diff --git a/packages/studio/src/player/components/PlayerControls.tsx b/packages/studio/src/player/components/PlayerControls.tsx index dd32c1342..0ebe6ec2d 100644 --- a/packages/studio/src/player/components/PlayerControls.tsx +++ b/packages/studio/src/player/components/PlayerControls.tsx @@ -2,7 +2,6 @@ import { useRef, useCallback, useEffect, memo } from "react"; import gsap from "gsap"; import { MorphSVGPlugin } from "gsap/MorphSVGPlugin"; import { formatFrameTime, formatTime, stepFrameTime } from "../lib/time"; -import { shouldMutePreviewAudio } from "../lib/timelineIframeHelpers"; import { usePlayerStore } from "../store/playerStore"; import { trackStudioEvent } from "../../utils/studioTelemetry"; import { Tooltip } from "../../components/ui"; @@ -60,40 +59,30 @@ function PlayPauseMorphIcon({ playing }: { playing: boolean }) { const MuteButton = memo(function MuteButton({ audioMuted, - audioAutoMuted, - effectiveAudioMuted, controlsDisabled, setAudioMuted, }: { audioMuted: boolean; - audioAutoMuted: boolean; - effectiveAudioMuted: boolean; controlsDisabled: boolean; setAudioMuted: (v: boolean) => void; }) { - const label = audioAutoMuted - ? "Audio muted above 1x speed" - : audioMuted - ? "Unmute audio" - : "Mute audio"; + const label = audioMuted ? "Unmute audio" : "Mute audio"; return (