js-tts-wrapper
Version:
A JavaScript/TypeScript library that provides a unified API for working with multiple cloud-based Text-to-Speech (TTS) services
172 lines (171 loc) • 5.91 kB
JavaScript
/**
* Utility functions for handling different audio input sources
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateSpeakInput = validateSpeakInput;
exports.getAudioFormatFromFilename = getAudioFormatFromFilename;
exports.detectAudioFormat = detectAudioFormat;
exports.readAudioFile = readAudioFile;
exports.streamToBytes = streamToBytes;
exports.processAudioInput = processAudioInput;
const environment_1 = require("./environment");
const stream_utils_1 = require("./stream-utils");
/**
* Validates that only one input source is provided
*/
function validateSpeakInput(input) {
const inputCount = [input.text, input.filename, input.audioBytes, input.audioStream].filter(Boolean).length;
if (inputCount === 0) {
throw new Error("No input provided. Please provide text, filename, audioBytes, or audioStream.");
}
if (inputCount > 1) {
throw new Error("Multiple input sources provided. Please provide only one of: text, filename, audioBytes, or audioStream.");
}
}
/**
* Determines the audio format from a filename extension
*/
function getAudioFormatFromFilename(filename) {
const extension = filename.toLowerCase().split(".").pop();
switch (extension) {
case "mp3":
return "audio/mpeg";
case "wav":
return "audio/wav";
case "ogg":
return "audio/ogg";
case "opus":
return "audio/opus";
case "aac":
return "audio/aac";
case "flac":
return "audio/flac";
default:
return "audio/wav"; // Default fallback
}
}
/**
* Attempts to detect audio format from byte signature
*/
function detectAudioFormat(audioBytes) {
if (audioBytes.length < 4) {
return "audio/wav"; // Default fallback
}
// Check for common audio file signatures
const header = Array.from(audioBytes.slice(0, 12));
// MP3 - ID3 tag or MPEG frame sync
if ((header[0] === 0x49 && header[1] === 0x44 && header[2] === 0x33) || // ID3
(header[0] === 0xff && (header[1] & 0xe0) === 0xe0)) {
// MPEG frame sync
return "audio/mpeg";
}
// WAV - RIFF header
if (header[0] === 0x52 &&
header[1] === 0x49 &&
header[2] === 0x46 &&
header[3] === 0x46 &&
header[8] === 0x57 &&
header[9] === 0x41 &&
header[10] === 0x56 &&
header[11] === 0x45) {
return "audio/wav";
}
// OGG
if (header[0] === 0x4f && header[1] === 0x67 && header[2] === 0x67 && header[3] === 0x53) {
return "audio/ogg";
}
// FLAC
if (header[0] === 0x66 && header[1] === 0x4c && header[2] === 0x61 && header[3] === 0x43) {
return "audio/flac";
}
return "audio/wav"; // Default fallback
}
/**
* Reads an audio file and returns its contents as Uint8Array
* Only works in Node.js environment
*/
async function readAudioFile(filename) {
if (!environment_1.isNode) {
throw new Error("File reading is only supported in Node.js environment");
}
try {
const fs = await Promise.resolve().then(() => __importStar(require("node:fs/promises")));
const buffer = await fs.readFile(filename);
return new Uint8Array(buffer);
}
catch (error) {
throw new Error(`Failed to read audio file "${filename}": ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Converts an audio stream to bytes
*/
async function streamToBytes(stream) {
const result = await (0, stream_utils_1.streamToBuffer)(stream);
// Convert Buffer to Uint8Array if needed (Node.js)
if (result instanceof Buffer) {
return new Uint8Array(result);
}
return result;
}
/**
* Processes the input and returns audio bytes with format information
*/
async function processAudioInput(input) {
validateSpeakInput(input);
if (input.audioBytes) {
return {
audioBytes: input.audioBytes,
mimeType: detectAudioFormat(input.audioBytes),
};
}
if (input.audioStream) {
const audioBytes = await streamToBytes(input.audioStream);
return {
audioBytes,
mimeType: detectAudioFormat(audioBytes),
};
}
if (input.filename) {
const audioBytes = await readAudioFile(input.filename);
return {
audioBytes,
mimeType: getAudioFormatFromFilename(input.filename),
};
}
throw new Error("No valid audio input provided");
}
;