From 4d127a038bf768eded68aae3cfa5c1b12241bdac Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Fri, 27 Mar 2026 00:55:15 +0100 Subject: chore: normalize line endings --- apps/web/src/lib/media/audio-mastering.ts | 206 +++++++++++++++--------------- 1 file changed, 103 insertions(+), 103 deletions(-) (limited to 'apps/web/src/lib/media/audio-mastering.ts') diff --git a/apps/web/src/lib/media/audio-mastering.ts b/apps/web/src/lib/media/audio-mastering.ts index 29af223b..f901c3bf 100644 --- a/apps/web/src/lib/media/audio-mastering.ts +++ b/apps/web/src/lib/media/audio-mastering.ts @@ -1,103 +1,103 @@ -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 { - 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]), - ); - } - } -} +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 { + 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]), + ); + } + } +} -- cgit v1.3.1