Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions packages/studio-server/src/helpers/loudness.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,39 @@ const track = (integratedLufs: number, truePeakDbfs: number, volume = 1) => ({
truePeakDbfs,
});

describe("audioTags playback offsets", () => {
it.each([
['data-playback-start="4"', 4],
['data-playback-start="4" data-media-start="1"', 4],
['data-playback-start="0" data-media-start="4"', 0],
['data-playback-start="4" data-media-start="invalid"', 4],
['data-playback-start="-1" data-media-start="3"', 3],
['data-playback-start="1.5s" data-media-start="3"', 3],
['data-playback-start="" data-media-start="3"', 3],
['data-playback-start="invalid"', 0],
['data-media-start="3"', 3],
])("measures the selected in-point for %s", (attributes, expected) => {
const html = `<audio id="voice" src="voice.wav" data-duration="2" ${attributes}></audio>`;
expect(audioTags(html)[0]).toEqual(expect.objectContaining({ mediaStart: expected }));
});

it("measures a video from its playback in-point at its authored speed", () => {
const html = `<video id="talk" src="talk.mp4" data-playback-start="4" data-media-start="1" data-duration="2" data-playback-rate="2"></video>`;
const [tag] = audioTags(html);
expect(tag).toBeDefined();
if (!tag) throw new Error("missing video");
const args = loudnessMeasureArgs("talk.mp4", tag);
expect(args.slice(args.indexOf("-ss"), args.indexOf("-i"))).toEqual(["-ss", "4", "-t", "4"]);
});

it("preserves the selected in-point when writing the matched gain", () => {
const html = `<audio id="voice" src="voice.wav" data-playback-start="4" data-media-start="1" data-volume="1"></audio>`;
const changed = updateAudioVolume(html, "voice", 0.5);
expect(changed).toBe(html.replace('data-volume="1"', 'data-volume="0.5"'));
expect(audioTags(changed)[0]).toEqual(expect.objectContaining({ mediaStart: 4, volume: 0.5 }));
});
});

describe("audioTags with video", () => {
it("includes a video with sound as a normalizable clip", () => {
const html = `<video id="a-roll" src="talk.mp4" data-has-audio="true" data-duration="4"></video>`;
Expand Down
16 changes: 10 additions & 6 deletions packages/studio-server/src/helpers/loudness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { promisify } from "node:util";
import { isAudibleVideoElement } from "@hyperframes/core/audible-video";
import { formatAudioGain, MAX_AUDIO_GAIN_DB } from "@hyperframes/core/audio-gain";
import { findFfBinary } from "@hyperframes/parsers/ff-binaries";
import { readMediaOffsetSeconds } from "@hyperframes/parsers/media-duration";
import { requestedProjectPath } from "./requestSubPath.js";

const execFileAsync = promisify(execFile);
Expand Down Expand Up @@ -253,6 +254,14 @@ function requiredAudioIdentity(attributes: Map<string, AttributeSpan>) {
return { id, src };
}

function authoredMediaStart(attributes: Map<string, AttributeSpan>, id: string): number {
return readMediaOffsetSeconds((name) => {
const raw = attributes.get(name)?.value;
if (name === "data-media-start") authoredNumber(raw, 0, name, id);
return raw;
});
}

/** Boolean attributes carry no `=`, so the value map cannot see them. */
function hasBareAttribute(html: string, range: TagRange, name: string): boolean {
const unquoted = html.slice(range.start, range.end).replace(/"[^"]*"|'[^']*'/g, '""');
Expand Down Expand Up @@ -298,12 +307,7 @@ function mediaTagFromRange(html: string, range: MediaTagRange): AudioTag | null
id,
src,
volume: authoredNumber(volumeAttribute?.value, 1, "data-volume", id),
mediaStart: authoredNumber(
attributes.get("data-media-start")?.value,
0,
"data-media-start",
id,
),
mediaStart: authoredMediaStart(attributes, id),
duration: authoredDuration(attributes, id),
playbackRate: authoredNumber(
attributes.get("data-playback-rate")?.value,
Expand Down
Loading