/** * Normalization effects */ import { getAudioContext } from '../context'; /** * Normalize audio to peak amplitude * @param buffer - Source audio buffer * @param targetPeak - Target peak amplitude (0.0 to 1.0, default 1.0) * @returns New audio buffer with normalized audio */ export function normalizePeak(buffer: AudioBuffer, targetPeak: number = 1.0): AudioBuffer { const audioContext = getAudioContext(); // Find the absolute peak across all channels let maxPeak = 0; for (let channel = 0; channel < buffer.numberOfChannels; channel++) { const channelData = buffer.getChannelData(channel); for (let i = 0; i < buffer.length; i++) { const abs = Math.abs(channelData[i]); if (abs > maxPeak) { maxPeak = abs; } } } // Calculate gain factor const gainFactor = maxPeak > 0 ? targetPeak / maxPeak : 1.0; // Create output buffer and apply gain const outputBuffer = audioContext.createBuffer( buffer.numberOfChannels, buffer.length, buffer.sampleRate ); for (let channel = 0; channel < buffer.numberOfChannels; channel++) { const inputData = buffer.getChannelData(channel); const outputData = outputBuffer.getChannelData(channel); for (let i = 0; i < buffer.length; i++) { outputData[i] = inputData[i] * gainFactor; } } return outputBuffer; } /** * Normalize audio to RMS (loudness) * @param buffer - Source audio buffer * @param targetRMS - Target RMS level (0.0 to 1.0, default 0.5) * @returns New audio buffer with normalized audio */ export function normalizeRMS(buffer: AudioBuffer, targetRMS: number = 0.5): AudioBuffer { const audioContext = getAudioContext(); // Calculate RMS across all channels let sumSquares = 0; let totalSamples = 0; for (let channel = 0; channel < buffer.numberOfChannels; channel++) { const channelData = buffer.getChannelData(channel); for (let i = 0; i < buffer.length; i++) { sumSquares += channelData[i] * channelData[i]; totalSamples++; } } const currentRMS = Math.sqrt(sumSquares / totalSamples); const gainFactor = currentRMS > 0 ? targetRMS / currentRMS : 1.0; // Create output buffer and apply gain const outputBuffer = audioContext.createBuffer( buffer.numberOfChannels, buffer.length, buffer.sampleRate ); for (let channel = 0; channel < buffer.numberOfChannels; channel++) { const inputData = buffer.getChannelData(channel); const outputData = outputBuffer.getChannelData(channel); for (let i = 0; i < buffer.length; i++) { outputData[i] = inputData[i] * gainFactor; // Clamp to prevent distortion outputData[i] = Math.max(-1, Math.min(1, outputData[i])); } } return outputBuffer; } /** * Get peak amplitude of audio buffer * @param buffer - Audio buffer * @returns Peak amplitude (0.0 to 1.0) */ export function getPeakAmplitude(buffer: AudioBuffer): number { let maxPeak = 0; for (let channel = 0; channel < buffer.numberOfChannels; channel++) { const channelData = buffer.getChannelData(channel); for (let i = 0; i < buffer.length; i++) { const abs = Math.abs(channelData[i]); if (abs > maxPeak) { maxPeak = abs; } } } return maxPeak; } /** * Get RMS amplitude of audio buffer * @param buffer - Audio buffer * @returns RMS amplitude */ export function getRMSAmplitude(buffer: AudioBuffer): number { let sumSquares = 0; let totalSamples = 0; for (let channel = 0; channel < buffer.numberOfChannels; channel++) { const channelData = buffer.getChannelData(channel); for (let i = 0; i < buffer.length; i++) { sumSquares += channelData[i] * channelData[i]; totalSamples++; } } return Math.sqrt(sumSquares / totalSamples); }