import type { AudioSource } from "expo-audio"; import { File, Paths } from "expo-file-system"; import { Platform } from "react-native"; export type PreparedVoicepeakAudio = | { kind: "expo-audio"; source: AudioSource; cleanup?: () => void; } | { kind: "native-webview"; html: string; }; const BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; export const encodeBase64 = (bytes: Uint8Array) => { let encoded = ""; for (let index = 0; index < bytes.length; index += 3) { const byte1 = bytes[index] ?? 0; const byte2 = bytes[index + 1] ?? 0; const byte3 = bytes[index + 2] ?? 0; const combined = (byte1 << 16) | (byte2 << 8) | byte3; encoded += BASE64_CHARS[(combined >> 18) & 0x3f]; encoded += BASE64_CHARS[(combined >> 12) & 0x3f]; encoded += index + 1 < bytes.length ? BASE64_CHARS[(combined >> 6) & 0x3f] : "="; encoded += index + 2 < bytes.length ? BASE64_CHARS[combined & 0x3f] : "="; } return encoded; }; const buildNativeVoicepeakHtml = ( bytes: Uint8Array, extension: "mp3" | "wav" ) => { const mimeType = extension === "wav" ? "audio/wav" : "audio/mpeg"; const base64 = encodeBase64(bytes); const source = `data:${mimeType};base64,${base64}`; return `
`; }; export const EMPTY_NATIVE_VOICEPEAK_HTML = ` `; export const createVoicepeakAudioSource = async ( bytes: Uint8Array, extension: "mp3" | "wav" = "mp3" ): Promise