ai
Version:
AI SDK by Vercel - build apps like ChatGPT, Claude, Gemini, and more with a single interface for any model using the Vercel AI Gateway or go direct to OpenAI, Anthropic, Google, or any other model provider.
83 lines (73 loc) • 2.68 kB
text/typescript
/**
* Converts Float32 audio samples to a base64-encoded PCM16 string
* for sending to a realtime model via input_audio_buffer.append.
*
* Samples are expected to be in the range [-1.0, 1.0].
* Output is 16-bit signed integer, little-endian, base64-encoded.
*/
export function encodeRealtimeAudio(float32Array: Float32Array): string {
const buffer = new ArrayBuffer(float32Array.length * 2);
const view = new DataView(buffer);
for (let i = 0; i < float32Array.length; i++) {
const s = Math.max(-1, Math.min(1, float32Array[i]));
view.setInt16(i * 2, s < 0 ? s * 0x8000 : s * 0x7fff, true);
}
const bytes = new Uint8Array(buffer);
const chunkSize = 0x8000;
let binary = '';
for (let i = 0; i < bytes.length; i += chunkSize) {
const chunk = bytes.subarray(i, i + chunkSize);
binary += String.fromCharCode(...chunk);
}
return btoa(binary);
}
/**
* Converts a base64-encoded PCM16 string (from a realtime model's
* audio-delta event) back to Float32 audio samples.
*
* Input is expected to be 16-bit signed integer, little-endian, base64-encoded.
* Output samples are in the range [-1.0, 1.0].
*/
export function decodeRealtimeAudio(base64Audio: string): Float32Array {
const binaryString = atob(base64Audio);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
const pcm16 = new Int16Array(bytes.buffer);
const float32 = new Float32Array(pcm16.length);
for (let i = 0; i < pcm16.length; i++) {
float32[i] = pcm16[i] / 32768.0;
}
return float32;
}
/**
* Resamples audio from one sample rate to another using linear
* interpolation. Suitable for voice audio.
*
* @param input - Float32 audio samples at the input sample rate.
* @param inputRate - The sample rate of the input audio (e.g. 48000).
* @param outputRate - The desired output sample rate (e.g. 24000).
* @returns Float32 audio samples at the output sample rate.
*/
export function resampleAudio(
input: Float32Array,
inputRate: number,
outputRate: number,
): Float32Array {
if (inputRate === outputRate) {
return input;
}
const ratio = inputRate / outputRate;
const outputLength = Math.round(input.length / ratio);
const output = new Float32Array(outputLength);
for (let i = 0; i < outputLength; i++) {
const srcIndex = i * ratio;
const srcIndexFloor = Math.floor(srcIndex);
const srcIndexCeil = Math.min(srcIndexFloor + 1, input.length - 1);
const fraction = srcIndex - srcIndexFloor;
output[i] =
input[srcIndexFloor] * (1 - fraction) + input[srcIndexCeil] * fraction;
}
return output;
}