diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-04-20 11:31:17 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-04-20 11:31:17 +0200 |
| commit | 3e89d2998588f8e35c524e523ba2ee853f0f6475 (patch) | |
| tree | 57221f96c1259b3b07e3ddf8c1adefc502b9d8eb /apps/web/src/lib/media/audio-mastering.ts | |
| parent | 729d10592f4e802f91c555c309ff3ba4b119f843 (diff) | |
| download | opencut-3e89d2998588f8e35c524e523ba2ee853f0f6475.tar.gz | |
refactor: restructure files to their domains, new preview overlay system, and dep graph
Diffstat (limited to 'apps/web/src/lib/media/audio-mastering.ts')
| -rw-r--r-- | apps/web/src/lib/media/audio-mastering.ts | 103 |
1 files changed, 0 insertions, 103 deletions
diff --git a/apps/web/src/lib/media/audio-mastering.ts b/apps/web/src/lib/media/audio-mastering.ts deleted file mode 100644 index f901c3bf..00000000 --- a/apps/web/src/lib/media/audio-mastering.ts +++ /dev/null @@ -1,103 +0,0 @@ -const MASTER_LIMITER_THRESHOLD_DB = -1;
-const MASTER_LIMITER_KNEE_DB = 0;
-const MASTER_LIMITER_RATIO = 20;
-const MASTER_LIMITER_ATTACK_SECONDS = 0.001;
-const MASTER_LIMITER_RELEASE_SECONDS = 0.12;
-const MASTER_OUTPUT_HEADROOM = 0.98;
-
-export function getAudioBufferPeak({
- audioBuffer,
-}: {
- audioBuffer: AudioBuffer;
-}): number {
- let peak = 0;
-
- for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) {
- const channelData = audioBuffer.getChannelData(channel);
- for (let index = 0; index < channelData.length; index++) {
- const magnitude = Math.abs(channelData[index]);
- if (magnitude > peak) {
- peak = magnitude;
- }
- }
- }
-
- return peak;
-}
-
-export function createAudioMasteringChain({
- audioContext,
- destination,
-}: {
- audioContext: AudioContext | OfflineAudioContext;
- destination: AudioNode;
-}): {
- input: GainNode;
-} {
- const input = audioContext.createGain();
- const limiter = audioContext.createDynamicsCompressor();
- const outputGain = audioContext.createGain();
-
- limiter.threshold.value = MASTER_LIMITER_THRESHOLD_DB;
- limiter.knee.value = MASTER_LIMITER_KNEE_DB;
- limiter.ratio.value = MASTER_LIMITER_RATIO;
- limiter.attack.value = MASTER_LIMITER_ATTACK_SECONDS;
- limiter.release.value = MASTER_LIMITER_RELEASE_SECONDS;
- outputGain.gain.value = MASTER_OUTPUT_HEADROOM;
-
- input.connect(limiter);
- limiter.connect(outputGain);
- outputGain.connect(destination);
-
- return { input };
-}
-
-export async function applyAudioMasteringToBuffer({
- audioBuffer,
-}: {
- audioBuffer: AudioBuffer;
-}): Promise<AudioBuffer> {
- if (getAudioBufferPeak({ audioBuffer }) <= MASTER_OUTPUT_HEADROOM) {
- return audioBuffer;
- }
-
- const offlineContext = new OfflineAudioContext(
- audioBuffer.numberOfChannels,
- Math.max(1, audioBuffer.length),
- audioBuffer.sampleRate,
- );
- const source = offlineContext.createBufferSource();
- source.buffer = audioBuffer;
-
- const { input } = createAudioMasteringChain({
- audioContext: offlineContext,
- destination: offlineContext.destination,
- });
- source.connect(input);
- source.start(0);
-
- const renderedBuffer = await offlineContext.startRendering();
- clampAudioBufferPeak({
- audioBuffer: renderedBuffer,
- maxPeak: MASTER_OUTPUT_HEADROOM,
- });
- return renderedBuffer;
-}
-
-function clampAudioBufferPeak({
- audioBuffer,
- maxPeak,
-}: {
- audioBuffer: AudioBuffer;
- maxPeak: number;
-}): void {
- for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) {
- const channelData = audioBuffer.getChannelData(channel);
- for (let index = 0; index < channelData.length; index++) {
- channelData[index] = Math.max(
- -maxPeak,
- Math.min(maxPeak, channelData[index]),
- );
- }
- }
-}
|
