All files / src/utils audio.ts

100% Statements 24/24
100% Branches 12/12
100% Functions 2/2
100% Lines 23/23

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53                            6x 3x 3x 1x   2x 2x 2x 2x   3x 3x 3x     5x 5x       10x 10x 10x   4x 4x 4x 4x 6x   5x         4x      
import fs from "fs";
import path from "path";
 
export interface AudioFileData {
  data: Uint8Array;
  fileName: string;
  duration?: number;
}
 
export class AudioUtils {
  static async load(filePath: string): Promise<AudioFileData> {
    let data: Uint8Array;
    let fileName: string;
 
    if (filePath.startsWith("http")) {
      const response = await fetch(filePath);
      if (!response.ok) {
        throw new Error(`Failed to fetch remote audio file: ${response.statusText}`);
      }
      const arrayBuffer = await response.arrayBuffer();
      data = new Uint8Array(arrayBuffer);
      const urlPath = new URL(filePath).pathname;
      fileName = path.basename(urlPath) || "audio.mp3";
    } else {
      const buffer = await fs.promises.readFile(filePath);
      data = new Uint8Array(buffer);
      fileName = path.basename(filePath);
    }
 
    const duration = this.estimateDuration(data, fileName);
    return { data, fileName, duration };
  }
 
  static estimateDuration(data: Uint8Array, fileName: string): number | undefined {
    try {
      const ext = path.extname(fileName).toLowerCase();
      if (ext === ".wav") {
        // Simple WAV duration: (DataSize / ByteRate)
        const view = new DataView(data.buffer, data.byteOffset, data.length);
        const byteRate = view.getUint32(28, true);
        const dataSize = view.getUint32(40, true);
        if (byteRate > 0) return dataSize / byteRate;
      } else if (ext === ".mp3") {
        // Very rough MP3 estimate (assume 128kbps)
        return data.length / (128000 / 8);
      }
    } catch {
      // Ignore estimation errors
    }
    return undefined;
  }
}