/** * Fade in/out effects */ import { getAudioContext } from '../context'; export type FadeType = 'linear' | 'exponential' | 'logarithmic'; /** * Apply fade in to audio buffer * @param buffer - Source audio buffer * @param duration - Fade duration in seconds * @param type - Fade curve type * @returns New audio buffer with fade in applied */ export function applyFadeIn( buffer: AudioBuffer, duration: number, type: FadeType = 'linear' ): AudioBuffer { const audioContext = getAudioContext(); const fadeSamples = Math.min( Math.floor(duration * buffer.sampleRate), buffer.length ); 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++) { if (i < fadeSamples) { const progress = i / fadeSamples; const gain = calculateFadeGain(progress, type); outputData[i] = inputData[i] * gain; } else { outputData[i] = inputData[i]; } } } return outputBuffer; } /** * Apply fade out to audio buffer * @param buffer - Source audio buffer * @param duration - Fade duration in seconds * @param type - Fade curve type * @returns New audio buffer with fade out applied */ export function applyFadeOut( buffer: AudioBuffer, duration: number, type: FadeType = 'linear' ): AudioBuffer { const audioContext = getAudioContext(); const fadeSamples = Math.min( Math.floor(duration * buffer.sampleRate), buffer.length ); const fadeStartSample = buffer.length - fadeSamples; 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++) { if (i >= fadeStartSample) { const progress = (i - fadeStartSample) / fadeSamples; const gain = calculateFadeGain(1 - progress, type); outputData[i] = inputData[i] * gain; } else { outputData[i] = inputData[i]; } } } return outputBuffer; } /** * Calculate fade gain based on progress and curve type * @param progress - Progress from 0 to 1 * @param type - Fade curve type * @returns Gain value from 0 to 1 */ function calculateFadeGain(progress: number, type: FadeType): number { switch (type) { case 'linear': return progress; case 'exponential': // Exponential curve: faster at the start, slower at the end return progress * progress; case 'logarithmic': // Logarithmic curve: slower at the start, faster at the end return Math.sqrt(progress); default: return progress; } }