133 lines
3.7 KiB
TypeScript
133 lines
3.7 KiB
TypeScript
|
|
/**
|
||
|
|
* 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);
|
||
|
|
}
|