summaryrefslogtreecommitdiff
path: root/apps/web/src/media/audio.ts
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/media/audio.ts')
-rw-r--r--apps/web/src/media/audio.ts42
1 files changed, 33 insertions, 9 deletions
diff --git a/apps/web/src/media/audio.ts b/apps/web/src/media/audio.ts
index 7abaf90e..0e8ee826 100644
--- a/apps/web/src/media/audio.ts
+++ b/apps/web/src/media/audio.ts
@@ -10,6 +10,7 @@ import type { MediaAsset } from "@/media/types";
import { applyAudioMasteringToBuffer } from "@/media/audio-mastering";
import type { AudioCapableElement } from "@/timeline/audio-state";
import {
+ getTrackVolume,
hasAnimatedVolume,
isElementMuted,
resolveEffectiveAudioGain,
@@ -21,10 +22,7 @@ import { mediaSupportsAudio } from "@/media/media-utils";
import { getSourceTimeAtClipTime, renderRetimedBuffer } from "@/retime";
import { Input, ALL_FORMATS, BlobSource, AudioBufferSink } from "mediabunny";
import { TICKS_PER_SECOND } from "@/wasm";
-import {
- computeRmsBuckets,
- type SampleBucket,
-} from "@/media/waveform-summary";
+import { computeRmsBuckets, type SampleBucket } from "@/media/waveform-summary";
const MAX_AUDIO_CHANNELS = 2;
const EXPORT_SAMPLE_RATE = 44100;
@@ -37,6 +35,7 @@ export interface CollectedAudioElement {
trimStart: number;
trimEnd: number;
volume: number;
+ trackVolume: number;
muted: boolean;
retime?: RetimeConfig;
}
@@ -89,6 +88,7 @@ export async function decodeAudioToFloat32({
export interface AudibleElementCandidate {
element: AudioElement | VideoElement;
mediaAsset: MediaAsset | null;
+ trackVolume: number;
}
export function collectAudibleCandidates({
@@ -114,7 +114,11 @@ export function collectAudibleCandidates({
: null;
if (!doesElementHaveEnabledAudio({ element, mediaAsset })) continue;
- candidates.push({ element, mediaAsset });
+ candidates.push({
+ element,
+ mediaAsset,
+ trackVolume: canTrackHaveAudio(track) ? getTrackVolume({ track }) : 0,
+ });
}
}
@@ -148,7 +152,7 @@ export async function collectAudioElements({
);
const pendingElements: Array<Promise<CollectedAudioElement | null>> = [];
- for (const { element, mediaAsset } of candidates) {
+ for (const { element, mediaAsset, trackVolume } of candidates) {
if (element.type === "audio") {
pendingElements.push(
resolveAudioBufferForElement({
@@ -166,10 +170,11 @@ export async function collectAudioElements({
trimEnd: element.trimEnd / TICKS_PER_SECOND,
volume: resolveEffectiveAudioGain({
element,
- trackMuted: false,
+ trackVolume,
localTime: 0,
}),
muted: isElementMuted({ element }),
+ trackVolume,
retime: element.retime,
};
}),
@@ -195,10 +200,11 @@ export async function collectAudioElements({
trimEnd: element.trimEnd / TICKS_PER_SECOND,
volume: resolveEffectiveAudioGain({
element,
- trackMuted: false,
+ trackVolume,
localTime: 0,
}),
muted: isElementMuted({ element }),
+ trackVolume,
retime: element.retime,
};
}),
@@ -359,6 +365,7 @@ export interface AudioClipSource {
trimStart: number;
trimEnd: number;
volume: number;
+ trackVolume: number;
muted: boolean;
retime?: RetimeConfig;
}
@@ -401,10 +408,12 @@ async function fetchLibraryAudioClip({
element,
muted,
volume,
+ trackVolume,
}: {
element: LibraryAudioElement;
muted: boolean;
volume: number;
+ trackVolume: number;
}): Promise<AudioClipSource | null> {
try {
const response = await fetch(element.sourceUrl);
@@ -427,6 +436,7 @@ async function fetchLibraryAudioClip({
trimStart: element.trimStart,
trimEnd: element.trimEnd,
volume,
+ trackVolume,
muted,
retime: element.retime,
};
@@ -462,11 +472,13 @@ function collectMediaAudioClip({
mediaAsset,
muted,
volume,
+ trackVolume,
}: {
element: AudioCapableElement;
mediaAsset: MediaAsset;
muted: boolean;
volume: number;
+ trackVolume: number;
}): AudioClipSource {
return {
timelineElement: element,
@@ -478,6 +490,7 @@ function collectMediaAudioClip({
trimStart: element.trimStart / TICKS_PER_SECOND,
trimEnd: element.trimEnd / TICKS_PER_SECOND,
volume,
+ trackVolume,
muted,
retime: element.retime,
};
@@ -507,8 +520,12 @@ export async function collectAudioMixSources({
? (mediaMap.get(element.mediaId) ?? null)
: null;
if (!doesElementHaveEnabledAudio({ element, mediaAsset })) continue;
+ const trackVolume = canTrackHaveAudio(track)
+ ? getTrackVolume({ track })
+ : 0;
const volume = resolveEffectiveAudioGain({
element,
+ trackVolume,
localTime: 0,
});
@@ -562,6 +579,9 @@ export async function collectAudioClips({
for (const track of orderedTracks) {
const isTrackMuted = canTrackHaveAudio(track) && track.muted;
+ const trackVolume = canTrackHaveAudio(track)
+ ? getTrackVolume({ track })
+ : 0;
for (const element of track.elements) {
if (!canElementHaveAudio(element)) continue;
@@ -575,6 +595,7 @@ export async function collectAudioClips({
const volume = resolveEffectiveAudioGain({
element,
trackMuted: isTrackMuted,
+ trackVolume,
localTime: 0,
});
@@ -589,11 +610,12 @@ export async function collectAudioClips({
mediaAsset,
muted,
volume,
+ trackVolume,
}),
);
} else {
pendingLibraryClips.push(
- fetchLibraryAudioClip({ element, muted, volume }),
+ fetchLibraryAudioClip({ element, muted, volume, trackVolume }),
);
}
continue;
@@ -607,6 +629,7 @@ export async function collectAudioClips({
mediaAsset,
muted,
volume,
+ trackVolume,
}),
);
}
@@ -855,6 +878,7 @@ function mixAudioChannels({
const gain = hasAnimatedVolume({ element: element.timelineElement })
? resolveEffectiveAudioGain({
element: element.timelineElement,
+ trackVolume: element.trackVolume,
localTime: clipTime,
})
: element.volume;