mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 14:50:02 +00:00
fix(studio): make the volume fader tell the truth about the gain it writes (#3305)
* fix(studio): make the volume fader tell the truth about the gain it writes The fader travels in dB, so its stops are irrational values; serializing them through the generic two-decimal numeric formatter collapsed the bottom quarter of its travel onto "0" — a hard mute — and made the knob jump on release everywhere below unity. Both panels now use the exact serializer, which round-trips every integer stop back to itself. Raise the volume automation lane to the same ceiling the fader reaches. Clamping the lane at unity meant automating a boosted clip silently discarded the boost, and the panel disables the fader while a lane owns the level, so there was no way back. This rescales the lane's vertical axis: unity now sits a quarter of the way up rather than at the top. Add audio_volume_tween_overrides_gain. Tween values on `volume` are absolute — they replace the authored gain rather than scaling it — so a clip carrying both plays at whatever the tween names, and the fader gives no sign of it. The rule reuses the tween detector the sibling lane/tween rule already has. * fix(lint): treat a missing data-volume as unity, not as silence readAttr returns null when the attribute is absent, and Number(null) is 0 — finite, and not 1 — so a clip carrying NO data-volume cleared both filters and was reported as authored at silence. Both halves of that were false: absent means unity everywhere else in the runtime. It fired on exactly the case the rule exists to bless. The docs this PR edits say data-volume is the baseline for elements no tween touches, so a tweened clip is expected not to carry one — the common audio fade. A warning does not fail check, but an agent reading the fixHint would have written a gain to correct a level that was never wrong.
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
import { getAudioFxDef, type HfAudioFxChain } from "./audioFx.js";
|
||||
import { MAX_AUDIO_GAIN } from "./audioGain.js";
|
||||
|
||||
export const HF_AUDIO_AUTOMATION_ATTR = "data-automation";
|
||||
|
||||
@@ -135,8 +136,9 @@ export const PRESET_RANGE: AutomationRange = {
|
||||
/**
|
||||
* The value range a lane is drawn and clamped against.
|
||||
*
|
||||
* Volume is linear 0..1, matching `data-volume` and the existing volume
|
||||
* envelope machinery — no dB conversion enters the volume path. Everything
|
||||
* Volume is linear over the full authoring gain range, matching `data-volume`
|
||||
* and the existing volume envelope machinery — no dB conversion enters the
|
||||
* volume path. Everything
|
||||
* else is read from the effect registry, so a lane can never offer a value the
|
||||
* renderer would reject, and the log-scaled knobs sweep the way a DAW's do.
|
||||
*/
|
||||
@@ -151,9 +153,15 @@ export interface AutomationRange {
|
||||
default: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* One ceiling for the fader, the lane, the preview transport and the render
|
||||
* mixer. Capping the lane at unity while the fader reached +12 dB made
|
||||
* automating a boosted clip silently discard the boost — and the panel
|
||||
* disables the fader while a lane owns it, so there was no way back.
|
||||
*/
|
||||
export const VOLUME_RANGE: AutomationRange = {
|
||||
min: 0,
|
||||
max: 1,
|
||||
max: MAX_AUDIO_GAIN,
|
||||
step: 0.01,
|
||||
unit: "",
|
||||
label: "Volume",
|
||||
|
||||
Reference in New Issue
Block a user