UNPKG

@tw2gem/audio-converter

Version:

TypeScript utilities to convert audio formats (e.g., PCM, mu-law) and resample audio for real-time streaming with Twilio or AI models.

89 lines (66 loc) 2.85 kB
export class AudioConverter { private static base64ToUint8Array(base64: string): Uint8Array { const binary = Buffer.from(base64, 'base64'); return new Uint8Array(binary); } private static base64ToInt16Array(base64: string): Int16Array { const buffer = Buffer.from(base64, 'base64'); return new Int16Array(buffer.buffer, buffer.byteOffset, buffer.byteLength / 2); } private static muLawToPCM(muLawSample: number): number { const BIAS = 0x84; muLawSample = ~muLawSample; const sign = muLawSample & 0x80; const exponent = (muLawSample >> 4) & 0x07; const mantissa = muLawSample & 0x0F; let sample = ((mantissa << 3) + BIAS) << exponent; if (sign !== 0) sample = -sample; return sample; } static pcmToMuLaw(sample: number): number { const BIAS = 0x84; const CLIP = 32635; const sign = (sample >> 8) & 0x80; if (sign !== 0) sample = -sample; if (sample > CLIP) sample = CLIP; sample += BIAS; let exponent = 7; for (let expMask = 0x4000; (sample & expMask) === 0 && exponent > 0; expMask >>= 1) { exponent--; } const mantissa = (sample >> (exponent + 3)) & 0x0F; const muLawByte = ~(sign | (exponent << 4) | mantissa); return muLawByte & 0xFF; } static convertBase64MuLawToBase64PCM16k(base64: string): string { const muLawBytes = this.base64ToUint8Array(base64); const pcm8000 = new Int16Array(muLawBytes.length); for (let i = 0; i < muLawBytes.length; i++) { pcm8000[i] = this.muLawToPCM(muLawBytes[i]); } const pcm16000 = new Int16Array(pcm8000.length * 2); for (let i = 0; i < pcm8000.length; i++) { const sample = pcm8000[i]; pcm16000[2 * i] = sample; pcm16000[2 * i + 1] = sample; } const buffer = Buffer.from(pcm16000.buffer); return buffer.toString('base64'); } static convertBase64PCM24kToBase64MuLaw8k(base64: string): string { const pcm24k = this.base64ToInt16Array(base64); const samples8k = Math.floor(pcm24k.length / 3); const interpolated = new Int16Array(samples8k); for (let i = 0; i < samples8k; i++) { const a = pcm24k[i * 3]; const b = pcm24k[i * 3 + 1] ?? a; const c = pcm24k[i * 3 + 2] ?? b; interpolated[i] = Math.round((a + b + c) / 3); } const muLaw = new Uint8Array(samples8k); for (let i = 0; i < samples8k; i++) { muLaw[i] = this.pcmToMuLaw(interpolated[i]); } return Buffer.from(muLaw).toString('base64'); } }