import { describe, expect, test } from "bun:test"; import { DEFAULT_VOICE_OVER_ENHANCEMENTS, encodeAudioBufferToWav, getAudioBufferPeak, hasEnabledVoiceOverEnhancement, type VoiceOverEnhancementSettings, } from "@/voiceover/enhancements"; /* eslint-disable opencut/prefer-object-params -- Browser AudioBuffer methods are positional. */ class FakeAudioBuffer implements AudioBuffer { duration: number; length: number; numberOfChannels: number; sampleRate: number; constructor( private readonly channels: Array>, sampleRate: number, ) { this.length = channels[0]?.length ?? 0; this.numberOfChannels = channels.length; this.sampleRate = sampleRate; this.duration = this.length / sampleRate; } copyFromChannel( destination: Float32Array, channelNumber: number, bufferOffset = 0, ): void { destination.set( this.getChannelData(channelNumber).slice( bufferOffset, bufferOffset + destination.length, ), ); } copyToChannel( source: Float32Array, channelNumber: number, bufferOffset = 0, ): void { this.getChannelData(channelNumber).set(source, bufferOffset); } getChannelData(channel: number): Float32Array { const data = this.channels[channel]; if (!data) { throw new Error(`Missing channel ${channel}`); } return data; } } /* eslint-enable opencut/prefer-object-params */ describe("hasEnabledVoiceOverEnhancement", () => { test("detects enabled defaults", () => { expect( hasEnabledVoiceOverEnhancement({ settings: DEFAULT_VOICE_OVER_ENHANCEMENTS, }), ).toBe(true); }); test("detects an all-disabled chain", () => { const settings: VoiceOverEnhancementSettings = { voiceBoost: false, noiseGate: false, highPass: false, deEss: false, limiter: false, normalize: false, }; expect(hasEnabledVoiceOverEnhancement({ settings })).toBe(false); }); }); describe("getAudioBufferPeak", () => { test("returns the maximum absolute sample", () => { const buffer = new FakeAudioBuffer( [ createSamples([0, -0.25, 0.5]), createSamples([0.1, -0.8, 0.2]), ], 48000, ); expect(getAudioBufferPeak({ buffer })).toBeCloseTo(0.8); }); }); describe("encodeAudioBufferToWav", () => { test("writes a 16-bit PCM WAV header", async () => { const buffer = new FakeAudioBuffer( [createSamples([0, 0.5, -0.5])], 44100, ); const blob = encodeAudioBufferToWav({ buffer }); const view = new DataView(await blob.arrayBuffer()); expect(blob.type).toBe("audio/wav"); expect(blob.size).toBe(50); expect(readAscii({ view, offset: 0, length: 4 })).toBe("RIFF"); expect(readAscii({ view, offset: 8, length: 4 })).toBe("WAVE"); expect(view.getUint16(22, true)).toBe(1); expect(view.getUint32(24, true)).toBe(44100); expect(view.getUint16(34, true)).toBe(16); expect(readAscii({ view, offset: 36, length: 4 })).toBe("data"); }); }); function readAscii({ view, offset, length, }: { view: DataView; offset: number; length: number; }): string { return Array.from({ length }, (_, index) => String.fromCharCode(view.getUint8(offset + index)), ).join(""); } function createSamples(values: number[]): Float32Array { const samples = new Float32Array(new ArrayBuffer(values.length * 4)); samples.set(values); return samples; }