{"version":3,"sources":["../package.json","../src/ts/WorkerPool.ts","../src/ts/WasmLoader.ts","../src/ts/LipSyncEngine.ts","../src/ts/index.ts","../src/ts/utils/AudioConverter.ts"],"names":["package_default","init_package","__esmMin","WorkerPool_exports","__export","StreamAnalyzerController","WorkerPool","_WorkerPool","init_WorkerPool","maxWorkers","workerScriptUrl","version","options","workersToCreate","promises","i","resolve","reject","workerUrl","blob","fetchError","worker","poolWorker","event","error","initHandler","initMessage","message","job","index","idleWorker","w","bufferCopy","pcm16","pcm16Copy","chunks","chunk","busyWorkers","pool","promise","c","WasmLoader","wasmPath","dataPath","jsPath","createModule","module","path","script","_LipSyncEngine","modelsPath","modelsPathLen","modelsPathPtr","errorPtr","dialogText","sampleRate","pcm16Ptr","dialogPtr","resultPtr","pcm16Bytes","dialogLen","resultJson","result","LipSyncEngine","analyze","instance","analyzeAsync","float32ToInt16","float32","int16","s","audioBufferToInt16","audioBuffer","targetSampleRate","resampled","resample","input","fromRate","toRate","ratio","outputLength","output","srcIndex","recordAudio","durationMs","stream","mediaRecorder","audioChunks","track","arrayBuffer","loadAudio","source"],"mappings":"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","file":"index.mjs","sourcesContent":["{\n  \"name\": \"lip-sync-engine\",\n  \"version\": \"1.0.3\",\n  \"description\": \"🎙️ WebAssembly port of Rhubarb Lip Sync for browser-based lip-sync animation. Analyzes audio to generate precise mouth movements using PocketSphinx speech recognition. Framework-agnostic TypeScript API for React, Vue, Svelte, Next.js, and vanilla JS. Perfect for games, chatbots, and virtual characters.\",\n  \"author\": \"Santiago Forero\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"lip-sync\",\n    \"speech-recognition\",\n    \"animation\",\n    \"wasm\",\n    \"webassembly\",\n    \"typescript\",\n    \"rhubarb\",\n    \"visemes\",\n    \"phonemes\",\n    \"framework-agnostic\"\n  ],\n  \"main\": \"./dist/index.js\",\n  \"module\": \"./dist/index.mjs\",\n  \"types\": \"./dist/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"import\": \"./dist/index.mjs\",\n      \"require\": \"./dist/index.js\"\n    },\n    \"./worker\": {\n      \"import\": \"./dist/worker.js\"\n    },\n    \"./wasm\": {\n      \"default\": \"./dist/wasm/lip-sync-engine.js\"\n    },\n    \"./dist/wasm/lip-sync-engine.wasm\": \"./dist/wasm/lip-sync-engine.wasm\",\n    \"./dist/wasm/lip-sync-engine.data\": \"./dist/wasm/lip-sync-engine.data\",\n    \"./dist/wasm/lip-sync-engine.js\": \"./dist/wasm/lip-sync-engine.js\",\n    \"./dist/worker.js\": \"./dist/worker.js\"\n  },\n  \"files\": [\n    \"dist\",\n    \"README.md\",\n    \"LICENSE\"\n  ],\n  \"scripts\": {\n    \"build:wasm\": \"./scripts/build-wasm.sh\",\n    \"build:ts\": \"tsup\",\n    \"build\": \"npm run build:wasm && npm run build:ts\",\n    \"dev\": \"tsup --watch\",\n    \"test\": \"vitest run\",\n    \"test:watch\": \"vitest\",\n    \"typecheck\": \"tsc --noEmit\",\n    \"clean\": \"rm -rf dist build\",\n    \"prepublishOnly\": \"npm run clean && npm run build\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^20.10.0\",\n    \"tsup\": \"^8.0.1\",\n    \"typescript\": \"^5.3.3\",\n    \"vitest\": \"^1.0.4\"\n  },\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/biolimbo/lip-sync-engine.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/biolimbo/lip-sync-engine/issues\"\n  },\n  \"homepage\": \"https://github.com/biolimbo/lip-sync-engine#readme\"\n}\n","import type { LipSyncEngineResult, LipSyncEngineOptions } from './types';\nimport type { WorkerRequest, WorkerResponse } from './worker';\nimport packageJson from '../../package.json';\n\n/**\n * Represents a worker in the pool\n */\ninterface PoolWorker {\n  worker: Worker;\n  busy: boolean;\n  ready: boolean;\n}\n\n/**\n * Represents a pending analysis job\n */\ninterface PendingJob {\n  id: number;\n  pcm16: Int16Array;\n  options: LipSyncEngineOptions;\n  resolve: (result: LipSyncEngineResult) => void;\n  reject: (error: Error) => void;\n}\n\n/**\n * Web Worker pool for non-blocking lip-sync-engine analysis\n * Manages multiple workers with automatic load balancing\n */\nexport class WorkerPool {\n  private static instance: WorkerPool | null = null;\n\n  private workers: PoolWorker[] = [];\n  private queue: PendingJob[] = [];\n  private inFlightJobs: Map<number, PendingJob> = new Map();\n  private nextJobId = 0;\n  private maxWorkers: number;\n  private workerScriptUrl: string;\n  private wasmPaths: {\n    wasmPath: string;\n    dataPath: string;\n    jsPath: string;\n  };\n  private initialized = false;\n\n  private constructor(\n    maxWorkers: number = navigator.hardwareConcurrency || 4,\n    workerScriptUrl?: string\n  ) {\n    this.maxWorkers = Math.max(1, maxWorkers);\n\n    const version = packageJson.version;\n\n    // Default worker script URL - uses CDN, can be overridden\n    this.workerScriptUrl = workerScriptUrl || `https://unpkg.com/lip-sync-engine@${version}/dist/worker.js`;\n\n    // Default WASM paths - uses CDN, can be configured via init()\n    this.wasmPaths = {\n      wasmPath: `https://unpkg.com/lip-sync-engine@${version}/dist/wasm/lip-sync-engine.wasm`,\n      dataPath: `https://unpkg.com/lip-sync-engine@${version}/dist/wasm/lip-sync-engine.data`,\n      jsPath: `https://unpkg.com/lip-sync-engine@${version}/dist/wasm/lip-sync-engine.js`\n    };\n  }\n\n  /**\n   * Get singleton instance\n   */\n  static getInstance(maxWorkers?: number, workerScriptUrl?: string): WorkerPool {\n    if (!this.instance) {\n      this.instance = new WorkerPool(maxWorkers, workerScriptUrl);\n    }\n    return this.instance;\n  }\n\n  /**\n   * Initialize the worker pool\n   * Must be called before using analyze()\n   *\n   * Strategy: Start with 1 worker for fast initialization\n   * - Use warmup() to create all workers upfront if needed\n   * - Workers scale on-demand automatically\n   */\n  async init(options?: {\n    wasmPath?: string;\n    dataPath?: string;\n    jsPath?: string;\n    workerScriptUrl?: string;\n  }): Promise<void> {\n    if (this.initialized) {\n      return;\n    }\n\n    // Update paths if provided\n    if (options) {\n      if (options.wasmPath) this.wasmPaths.wasmPath = options.wasmPath;\n      if (options.dataPath) this.wasmPaths.dataPath = options.dataPath;\n      if (options.jsPath) this.wasmPaths.jsPath = options.jsPath;\n      if (options.workerScriptUrl) this.workerScriptUrl = options.workerScriptUrl;\n    }\n\n    // Start with 1 worker for fast initialization\n    // More workers will be created on-demand when needed\n    await this.createWorker();\n\n    this.initialized = true;\n  }\n\n  /**\n   * Pre-create all workers up to maxWorkers\n   * Call this during app initialization to eliminate worker creation overhead\n   *\n   * @example\n   * ```typescript\n   * const pool = WorkerPool.getInstance();\n   * await pool.init({ ... });\n   * await pool.warmup(); // Pre-create all workers\n   * // Now all workers are ready for chunked processing\n   * ```\n   */\n  async warmup(): Promise<void> {\n    if (!this.initialized) {\n      throw new Error('WorkerPool not initialized. Call init() first.');\n    }\n\n    const workersToCreate = this.maxWorkers - this.workers.length;\n\n    if (workersToCreate <= 0) {\n      return; // Already at max workers\n    }\n\n    // Create remaining workers in parallel\n    const promises: Promise<PoolWorker>[] = [];\n    for (let i = 0; i < workersToCreate; i++) {\n      promises.push(this.createWorker());\n    }\n\n    await Promise.all(promises);\n  }\n\n  /**\n   * Create a new worker and initialize it\n   */\n  private async createWorker(): Promise<PoolWorker> {\n    return new Promise(async (resolve, reject) => {\n      try {\n        // If the worker URL is from a CDN (cross-origin), fetch it and create a blob URL\n        let workerUrl = this.workerScriptUrl;\n        if (workerUrl.startsWith('http://') || workerUrl.startsWith('https://')) {\n          try {\n            const response = await fetch(workerUrl);\n            const blob = await response.blob();\n            workerUrl = URL.createObjectURL(blob);\n          } catch (fetchError) {\n            console.warn('Failed to fetch worker script, trying direct URL:', fetchError);\n            // Fall back to direct URL (will fail with CORS but worth trying)\n          }\n        }\n\n        const worker = new Worker(workerUrl);\n\n        const poolWorker: PoolWorker = {\n          worker,\n          busy: false,\n          ready: false\n        };\n\n        // Set up message handler\n        worker.onmessage = (event: MessageEvent<WorkerResponse>) => {\n          this.handleWorkerMessage(poolWorker, event.data);\n        };\n\n        worker.onerror = (error) => {\n          console.error('Worker error:', error);\n          this.removeWorker(poolWorker);\n        };\n\n        // Wait for worker to be ready\n        const initHandler = (event: MessageEvent<WorkerResponse>) => {\n          if (event.data.type === 'ready') {\n            poolWorker.ready = true;\n            this.workers.push(poolWorker);\n            worker.removeEventListener('message', initHandler);\n            resolve(poolWorker);\n          } else if (event.data.type === 'error') {\n            worker.removeEventListener('message', initHandler);\n            reject(new Error(event.data.error || 'Worker initialization failed'));\n          }\n        };\n\n        worker.addEventListener('message', initHandler);\n\n        // Send init message\n        const initMessage: WorkerRequest = {\n          type: 'init',\n          ...this.wasmPaths\n        };\n        worker.postMessage(initMessage);\n\n      } catch (error) {\n        reject(error);\n      }\n    });\n  }\n\n  /**\n   * Handle messages from workers\n   */\n  private handleWorkerMessage(poolWorker: PoolWorker, message: WorkerResponse): void {\n    if (message.type === 'result') {\n      // Find and resolve the in-flight job\n      const job = this.inFlightJobs.get(message.id);\n      if (job) {\n        this.inFlightJobs.delete(message.id);\n\n        if (message.result) {\n          job.resolve(message.result);\n        } else {\n          job.reject(new Error('No result returned from worker'));\n        }\n      }\n\n      // Mark worker as available and process next job\n      poolWorker.busy = false;\n      this.processQueue();\n\n    } else if (message.type === 'error') {\n      // Check if this is an analyze error (has id) or init error (no id)\n      if ('id' in message) {\n        // Analyze error - find and reject the in-flight job\n        const job = this.inFlightJobs.get(message.id);\n        if (job) {\n          this.inFlightJobs.delete(message.id);\n          job.reject(new Error(message.error || 'Unknown worker error'));\n        }\n\n        // Mark worker as available and process next job\n        poolWorker.busy = false;\n        this.processQueue();\n      }\n      // Init errors are handled in createWorker()\n    }\n  }\n\n  /**\n   * Remove a worker from the pool\n   */\n  private removeWorker(poolWorker: PoolWorker): void {\n    const index = this.workers.indexOf(poolWorker);\n    if (index !== -1) {\n      this.workers.splice(index, 1);\n      poolWorker.worker.terminate();\n    }\n  }\n\n  /**\n   * Process queued jobs\n   * Simple algorithm: assign each queued job to the next available idle worker\n   * Workers must be pre-created via init() or warmup()\n   */\n  private processQueue(): void {\n    // Assign all pending jobs to available idle workers\n    while (this.queue.length > 0) {\n      const idleWorker = this.workers.find(w => w.ready && !w.busy);\n\n      if (!idleWorker) {\n        // No idle workers available - jobs will be processed when a worker becomes free\n        break;\n      }\n\n      const job = this.queue.shift();\n      if (!job) break;\n\n      this.assignJobToWorker(job, idleWorker);\n    }\n  }\n\n  /**\n   * Assign a job to a worker\n   */\n  private assignJobToWorker(job: PendingJob, worker: PoolWorker): void {\n    // Add to in-flight jobs\n    this.inFlightJobs.set(job.id, job);\n\n    // Mark worker as busy\n    worker.busy = true;\n\n    // Send job to worker\n    // Create a true copy with a new ArrayBuffer to avoid detaching the original\n    const bufferCopy = new Int16Array(job.pcm16);\n\n    const message: WorkerRequest = {\n      type: 'analyze',\n      id: job.id,\n      pcm16: bufferCopy,\n      options: job.options\n    };\n\n    // Use transferable objects for zero-copy transfer\n    worker.worker.postMessage(message, [bufferCopy.buffer]);\n  }\n\n  /**\n   * Analyze audio in a Web Worker (non-blocking)\n   *\n   * @param pcm16 - 16-bit PCM audio buffer\n   * @param options - Optional configuration\n   * @returns Promise resolving to lip-sync-engine result\n   */\n  async analyze(\n    pcm16: Int16Array,\n    options: LipSyncEngineOptions = {}\n  ): Promise<LipSyncEngineResult> {\n    if (!this.initialized) {\n      throw new Error('WorkerPool not initialized. Call init() first.');\n    }\n\n    // Create a copy of the buffer since we'll transfer ownership to the worker\n    const pcm16Copy = new Int16Array(pcm16);\n\n    // Create job promise\n    return new Promise<LipSyncEngineResult>((resolve, reject) => {\n      const job: PendingJob = {\n        id: this.nextJobId++,\n        pcm16: pcm16Copy,\n        options,\n        resolve,\n        reject\n      };\n\n      // Add to queue\n      this.queue.push(job);\n\n      // Try to process immediately\n      this.processQueue();\n    });\n  }\n\n  /**\n   * Analyze multiple audio buffers in parallel using chunked processing\n   *\n   * @param chunks - Array of audio chunks to process\n   * @param options - Optional configuration\n   * @returns Promise resolving to array of results in same order as input\n   */\n  async analyzeChunks(\n    chunks: Int16Array[],\n    options: LipSyncEngineOptions = {}\n  ): Promise<LipSyncEngineResult[]> {\n    if (!this.initialized) {\n      throw new Error('WorkerPool not initialized. Call init() first.');\n    }\n\n    // Analyze all chunks in parallel\n    const promises = chunks.map(chunk => this.analyze(chunk, options));\n    return Promise.all(promises);\n  }\n\n  /**\n   * Create a dynamic streaming analyzer that allows adding chunks on-the-fly\n   * Returns a controller that lets you add chunks as they arrive from a stream\n   *\n   * @param options - Optional configuration for all chunks\n   * @returns StreamController with addChunk() and finalize() methods\n   *\n   * @example\n   * ```typescript\n   * const stream = pool.createStreamAnalyzer({ dialogText: \"hello\" });\n   * await pool.warmup(); // Pre-create workers\n   *\n   * // Add chunks as they arrive from your audio stream\n   * for await (const chunk of audioStream) {\n   *   stream.addChunk(chunk); // Non-blocking, queues immediately\n   * }\n   *\n   * // Wait for all chunks to complete and get results in order\n   * const results = await stream.finalize();\n   * ```\n   */\n  createStreamAnalyzer(options: LipSyncEngineOptions = {}): StreamAnalyzerController {\n    if (!this.initialized) {\n      throw new Error('WorkerPool not initialized. Call init() first.');\n    }\n\n    const controller = new StreamAnalyzerController(this, options);\n    return controller;\n  }\n\n  /**\n   * Get pool statistics\n   */\n  getStats(): {\n    totalWorkers: number;\n    busyWorkers: number;\n    idleWorkers: number;\n    queuedJobs: number;\n    maxWorkers: number;\n  } {\n    const busyWorkers = this.workers.filter(w => w.busy).length;\n    return {\n      totalWorkers: this.workers.length,\n      busyWorkers,\n      idleWorkers: this.workers.length - busyWorkers,\n      queuedJobs: this.queue.length,\n      maxWorkers: this.maxWorkers\n    };\n  }\n\n  /**\n   * Destroy the worker pool and terminate all workers\n   */\n  destroy(): void {\n    // Reject all pending jobs in queue\n    this.queue.forEach(job => {\n      job.reject(new Error('WorkerPool destroyed'));\n    });\n    this.queue = [];\n\n    // Reject all in-flight jobs\n    this.inFlightJobs.forEach(job => {\n      job.reject(new Error('WorkerPool destroyed'));\n    });\n    this.inFlightJobs.clear();\n\n    // Terminate all workers\n    this.workers.forEach(poolWorker => {\n      poolWorker.worker.terminate();\n    });\n    this.workers = [];\n\n    this.initialized = false;\n    WorkerPool.instance = null;\n  }\n}\n\n/**\n * Controller for dynamic streaming analysis\n * Allows adding chunks on-the-fly as they arrive from a stream\n */\nexport class StreamAnalyzerController {\n  private pool: WorkerPool;\n  private options: LipSyncEngineOptions;\n  private chunks: Array<{ index: number; promise: Promise<LipSyncEngineResult> }> = [];\n  private nextIndex = 0;\n  private finalized = false;\n\n  constructor(pool: WorkerPool, options: LipSyncEngineOptions) {\n    this.pool = pool;\n    this.options = options;\n  }\n\n  /**\n   * Add a chunk to be analyzed\n   * This immediately queues the chunk for processing - no main thread blocking\n   *\n   * @param chunk - Audio chunk to analyze\n   * @returns The index of this chunk in the result array\n   */\n  addChunk(chunk: Int16Array): number {\n    if (this.finalized) {\n      throw new Error('Cannot add chunks after finalize() has been called');\n    }\n\n    const index = this.nextIndex++;\n    const promise = this.pool.analyze(chunk, this.options);\n\n    this.chunks.push({ index, promise });\n\n    return index;\n  }\n\n  /**\n   * Wait for all chunks to complete and return results in insertion order\n   *\n   * @returns Array of results in the same order chunks were added\n   */\n  async finalize(): Promise<LipSyncEngineResult[]> {\n    this.finalized = true;\n\n    // Wait for all chunks to complete\n    const results = await Promise.all(this.chunks.map(c => c.promise));\n\n    // Results are already in order since we preserved insertion order\n    return results;\n  }\n\n  /**\n   * Get current streaming statistics\n   */\n  getStats(): {\n    chunksAdded: number;\n    chunksCompleted: number;\n    poolStats: ReturnType<WorkerPool['getStats']>;\n  } {\n    return {\n      chunksAdded: this.chunks.length,\n      chunksCompleted: this.nextIndex,\n      poolStats: this.pool.getStats()\n    };\n  }\n}\n","import type { LipSyncEngineModule, WasmLoaderOptions } from './types';\nimport packageJson from '../../package.json';\n\n// Declare worker globals for TypeScript\ndeclare const WorkerGlobalScope: any;\ndeclare function importScripts(...urls: string[]): void;\n\n/**\n * Loads the WASM module\n * This is a singleton loader that handles WASM initialization\n */\nexport class WasmLoader {\n  private static modulePromise: Promise<LipSyncEngineModule> | null = null;\n  private static module: LipSyncEngineModule | null = null;\n\n  /**\n   * Load the WASM module\n   * @param options - Optional paths to WASM files\n   * @returns Promise resolving to the loaded WASM module\n   */\n  static async load(options: WasmLoaderOptions = {}): Promise<LipSyncEngineModule> {\n    // Return cached module if already loaded\n    if (this.module) {\n      return this.module;\n    }\n\n    // Return in-progress load if already loading\n    if (this.modulePromise) {\n      return this.modulePromise;\n    }\n\n    this.modulePromise = this._loadModule(options);\n    this.module = await this.modulePromise;\n    return this.module;\n  }\n\n  /**\n   * Load module directly (for worker context)\n   * This method doesn't use singleton caching and is suitable for workers\n   */\n  static async loadModule(options: WasmLoaderOptions = {}): Promise<LipSyncEngineModule> {\n    return this._loadModuleImpl(options);\n  }\n\n  /**\n   * Internal method to load the module\n   */\n  private static async _loadModule(\n    options: WasmLoaderOptions\n  ): Promise<LipSyncEngineModule> {\n    return this._loadModuleImpl(options);\n  }\n\n  /**\n   * Implementation of module loading that works in both window and worker contexts\n   */\n  private static async _loadModuleImpl(\n    options: WasmLoaderOptions\n  ): Promise<LipSyncEngineModule> {\n    const version = packageJson.version;\n    const {\n      wasmPath = `https://unpkg.com/lip-sync-engine@${version}/dist/wasm/lip-sync-engine.wasm`,\n      dataPath = `https://unpkg.com/lip-sync-engine@${version}/dist/wasm/lip-sync-engine.data`,\n      jsPath = `https://unpkg.com/lip-sync-engine@${version}/dist/wasm/lip-sync-engine.js`,\n    } = options;\n\n    // Detect if we're in a worker context\n    const isWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;\n\n    if (isWorker) {\n      // Worker context - use importScripts\n      return new Promise(async (resolve, reject) => {\n        try {\n          // Import the Emscripten JS file\n          importScripts(jsPath);\n\n          // The factory function is now available in global scope\n          const createModule = (self as any).createLipSyncEngineModule;\n\n          if (!createModule) {\n            throw new Error(\n              'WASM module factory not found in worker. Make sure lip-sync-engine.js exports createLipSyncEngineModule.'\n            );\n          }\n\n          const module = await createModule({\n            locateFile: (path: string) => {\n              if (path.endsWith('.wasm')) {\n                return wasmPath;\n              }\n              if (path.endsWith('.data')) {\n                return dataPath;\n              }\n              return path;\n            },\n          });\n\n          resolve(module as LipSyncEngineModule);\n        } catch (error) {\n          reject(error);\n        }\n      });\n    } else {\n      // Window context - use dynamic script loading\n      if (typeof window === 'undefined') {\n        throw new Error('WasmLoader can only be used in browser or worker environments');\n      }\n\n      return new Promise((resolve, reject) => {\n        const script = document.createElement('script');\n        script.src = jsPath;\n        script.async = true;\n\n        script.onload = async () => {\n          try {\n            // The Emscripten module should expose a factory function\n            const createModule = (window as any).createLipSyncEngineModule;\n\n            if (!createModule) {\n              throw new Error(\n                'WASM module factory not found. Make sure lip-sync-engine.js is loaded correctly.'\n              );\n            }\n\n            const module = await createModule({\n              locateFile: (path: string) => {\n                if (path.endsWith('.wasm')) {\n                  return wasmPath;\n                }\n                if (path.endsWith('.data')) {\n                  return dataPath;\n                }\n                return path;\n              },\n            });\n\n            resolve(module as LipSyncEngineModule);\n          } catch (error) {\n            reject(error);\n          }\n        };\n\n        script.onerror = () => {\n          reject(new Error(`Failed to load WASM module from ${jsPath}`));\n        };\n\n        document.head.appendChild(script);\n      });\n    }\n  }\n\n  /**\n   * Reset the loader (useful for testing)\n   */\n  static reset(): void {\n    this.module = null;\n    this.modulePromise = null;\n  }\n}\n","import type {\n  LipSyncEngineResult,\n  LipSyncEngineOptions,\n  LipSyncEngineModule,\n  WasmLoaderOptions,\n} from './types';\nimport { WasmLoader } from './WasmLoader';\n\n/**\n * Main API class for Lip Sync\n * Framework-agnostic - works with vanilla JS, React, Vue, Svelte, etc.\n *\n * @example Vanilla JavaScript\n * ```typescript\n * import { LipSyncEngine } from 'lip-sync-engine';\n *\n * const lipSyncEngine = LipSyncEngine.getInstance();\n * await lipSyncEngine.init();\n *\n * const result = await lipSyncEngine.analyze(pcm16Buffer, {\n *   dialogText: \"Hello world\",\n *   sampleRate: 16000\n * });\n *\n * console.log(result.mouthCues);\n * ```\n *\n * @example React\n * ```typescript\n * // Create a custom hook in your app\n * function useLipSyncEngine() {\n *   const [result, setResult] = useState(null);\n *   const lipSyncEngineRef = useRef(LipSyncEngine.getInstance());\n *\n *   useEffect(() => {\n *     lipSyncEngineRef.current.init();\n *     return () => lipSyncEngineRef.current.destroy();\n *   }, []);\n *\n *   const analyze = async (pcm16, options) => {\n *     const result = await lipSyncEngineRef.current.analyze(pcm16, options);\n *     setResult(result);\n *   };\n *\n *   return { analyze, result };\n * }\n * ```\n */\nexport class LipSyncEngine {\n  private static instance: LipSyncEngine | null = null;\n  private module: LipSyncEngineModule | null = null;\n  private initialized = false;\n  private initPromise: Promise<void> | null = null;\n\n  private constructor() {}\n\n  /**\n   * Get singleton instance\n   */\n  static getInstance(): LipSyncEngine {\n    if (!this.instance) {\n      this.instance = new LipSyncEngine();\n    }\n    return this.instance;\n  }\n\n  /**\n   * Initialize the WASM module\n   * Call this once before using analyze()\n   *\n   * @param options - Optional paths to WASM files\n   */\n  async init(options: WasmLoaderOptions = {}): Promise<void> {\n    if (this.initialized) return;\n    if (this.initPromise) return this.initPromise;\n\n    this.initPromise = (async () => {\n      // Load WASM module\n      this.module = await WasmLoader.load(options);\n\n      // Initialize LipSyncEngine with models\n      const modelsPath = '/models';\n      const modelsPathLen = this.module.lengthBytesUTF8(modelsPath) + 1;\n      const modelsPathPtr = this.module._malloc(modelsPathLen);\n\n      try {\n        this.module.stringToUTF8(modelsPath, modelsPathPtr, modelsPathLen);\n        const result = this.module._lipsyncengine_init(modelsPathPtr);\n\n        if (result !== 0) {\n          const errorPtr = this.module._lipsyncengine_get_last_error();\n          const error = errorPtr\n            ? this.module.UTF8ToString(errorPtr)\n            : 'Unknown error';\n          throw new Error(`LipSyncEngine initialization failed: ${error}`);\n        }\n\n        this.initialized = true;\n      } finally {\n        this.module._free(modelsPathPtr);\n      }\n    })();\n\n    return this.initPromise;\n  }\n\n  /**\n   * Analyze audio and generate lip-sync-engine data\n   *\n   * @param pcm16 - 16-bit PCM audio buffer (mono, 16kHz recommended)\n   * @param options - Optional configuration\n   * @returns Promise resolving to lip-sync-engine result with mouth cues\n   *\n   * @throws {TypeError} If pcm16 is not an Int16Array\n   * @throws {Error} If audio buffer is empty\n   * @throws {Error} If analysis fails\n   */\n  async analyze(\n    pcm16: Int16Array,\n    options: LipSyncEngineOptions = {}\n  ): Promise<LipSyncEngineResult> {\n    await this.init();\n\n    if (!this.module) {\n      throw new Error('Module not initialized');\n    }\n\n    const { dialogText, sampleRate = 16000 } = options;\n\n    // Validate input\n    if (!(pcm16 instanceof Int16Array)) {\n      throw new TypeError('pcm16 must be an Int16Array');\n    }\n\n    if (pcm16.length === 0) {\n      throw new Error('pcm16 buffer is empty');\n    }\n\n    if (sampleRate <= 0) {\n      throw new Error('sampleRate must be positive');\n    }\n\n    let pcm16Ptr = 0;\n    let dialogPtr = 0;\n    let resultPtr = 0;\n\n    try {\n      // Allocate PCM buffer in WASM memory\n      const pcm16Bytes = pcm16.length * 2;\n      pcm16Ptr = this.module._malloc(pcm16Bytes);\n      this.module.HEAP16.set(pcm16, pcm16Ptr / 2);\n\n      // Allocate dialog text if provided\n      if (dialogText) {\n        const dialogLen = this.module.lengthBytesUTF8(dialogText) + 1;\n        dialogPtr = this.module._malloc(dialogLen);\n        this.module.stringToUTF8(dialogText, dialogPtr, dialogLen);\n      }\n\n      // Call WASM function\n      resultPtr = this.module._lipsyncengine_analyze_pcm16(\n        pcm16Ptr,\n        pcm16.length,\n        sampleRate,\n        dialogPtr\n      );\n\n      if (!resultPtr) {\n        const errorPtr = this.module._lipsyncengine_get_last_error();\n        const error = errorPtr\n          ? this.module.UTF8ToString(errorPtr)\n          : 'Analysis failed';\n        throw new Error(error);\n      }\n\n      // Parse JSON result\n      const resultJson = this.module.UTF8ToString(resultPtr);\n      const result: LipSyncEngineResult = JSON.parse(resultJson);\n\n      // Add metadata\n      result.metadata = {\n        duration: result.mouthCues[result.mouthCues.length - 1]?.end || 0,\n        sampleRate,\n        dialogText,\n      };\n\n      return result;\n    } finally {\n      // Always cleanup allocated memory\n      if (pcm16Ptr) this.module._free(pcm16Ptr);\n      if (dialogPtr) this.module._free(dialogPtr);\n      if (resultPtr) this.module._lipsyncengine_free(resultPtr);\n    }\n  }\n\n  /**\n   * Analyze audio using Web Worker (non-blocking)\n   * Recommended for long audio files to avoid blocking UI\n   *\n   * @param pcm16 - 16-bit PCM audio buffer\n   * @param options - Optional configuration\n   * @returns Promise resolving to lip-sync-engine result\n   */\n  async analyzeAsync(\n    pcm16: Int16Array,\n    options: LipSyncEngineOptions = {}\n  ): Promise<LipSyncEngineResult> {\n    // Lazy load WorkerPool to avoid circular dependencies\n    const { WorkerPool } = await import('./WorkerPool');\n    const pool = WorkerPool.getInstance();\n    return pool.analyze(pcm16, options);\n  }\n\n  /**\n   * Destroy the instance and free resources\n   * Call this when you're completely done with lip-sync-engine analysis\n   */\n  destroy(): void {\n    this.module = null;\n    this.initialized = false;\n    this.initPromise = null;\n    LipSyncEngine.instance = null;\n  }\n}\n\n/**\n * Convenience function for one-off analysis\n * Framework-agnostic - works everywhere\n */\nexport const analyze = async (\n  pcm16: Int16Array,\n  options?: LipSyncEngineOptions\n): Promise<LipSyncEngineResult> => {\n  const instance = LipSyncEngine.getInstance();\n  await instance.init();\n  return instance.analyze(pcm16, options);\n};\n\n/**\n * Convenience function for async analysis with Web Worker\n */\nexport const analyzeAsync = async (\n  pcm16: Int16Array,\n  options?: LipSyncEngineOptions\n): Promise<LipSyncEngineResult> => {\n  const instance = LipSyncEngine.getInstance();\n  return instance.analyzeAsync(pcm16, options);\n};\n","// Main exports\nexport { LipSyncEngine, analyze, analyzeAsync } from './LipSyncEngine';\nexport { WasmLoader } from './WasmLoader';\nexport { WorkerPool, StreamAnalyzerController } from './WorkerPool';\n\n// Utilities\nexport * from './utils/AudioConverter';\n\n// Types\nexport type {\n  MouthCue,\n  LipSyncEngineResult,\n  LipSyncEngineOptions,\n  LipSyncEngineModule,\n  ProgressCallback,\n  WasmLoaderOptions,\n} from './types';\n\n// Worker types\nexport type {\n  WorkerAnalyzeRequest,\n  WorkerAnalyzeResponse,\n  WorkerInitRequest,\n  WorkerInitResponse,\n  WorkerRequest,\n  WorkerResponse,\n} from './worker';\n","/**\n * Audio format conversion utilities\n * Framework-agnostic - works with any audio API\n */\n\n/**\n * Convert Float32Array to Int16Array PCM\n */\nexport function float32ToInt16(float32: Float32Array): Int16Array {\n  const int16 = new Int16Array(float32.length);\n\n  for (let i = 0; i < float32.length; i++) {\n    const s = Math.max(-1, Math.min(1, float32[i]));\n    int16[i] = s < 0 ? s * 0x8000 : s * 0x7fff;\n  }\n\n  return int16;\n}\n\n/**\n * Convert AudioBuffer to Int16Array PCM\n * @param audioBuffer - Web Audio API AudioBuffer\n * @param targetSampleRate - Target sample rate (default: 16000)\n * @returns Int16Array PCM data\n */\nexport function audioBufferToInt16(\n  audioBuffer: AudioBuffer,\n  targetSampleRate = 16000\n): Int16Array {\n  const float32 = audioBuffer.getChannelData(0);\n\n  // Resample if needed\n  if (audioBuffer.sampleRate !== targetSampleRate) {\n    const resampled = resample(\n      float32,\n      audioBuffer.sampleRate,\n      targetSampleRate\n    );\n    return float32ToInt16(resampled);\n  }\n\n  return float32ToInt16(float32);\n}\n\n/**\n * Simple linear resampling\n * For better quality, consider using a dedicated library\n *\n * @param input - Input audio samples\n * @param fromRate - Source sample rate\n * @param toRate - Target sample rate\n * @returns Resampled audio\n */\nexport function resample(\n  input: Float32Array,\n  fromRate: number,\n  toRate: number\n): Float32Array {\n  if (fromRate === toRate) {\n    return input;\n  }\n\n  const ratio = fromRate / toRate;\n  const outputLength = Math.floor(input.length / ratio);\n  const output = new Float32Array(outputLength);\n\n  for (let i = 0; i < outputLength; i++) {\n    const srcIndex = Math.floor(i * ratio);\n    output[i] = input[srcIndex];\n  }\n\n  return output;\n}\n\n/**\n * Record audio from microphone\n *\n * @param durationMs - Recording duration in milliseconds\n * @param sampleRate - Target sample rate (default: 16000)\n * @returns Object containing PCM16 data and AudioBuffer\n */\nexport async function recordAudio(\n  durationMs: number,\n  sampleRate = 16000\n): Promise<{ pcm16: Int16Array; audioBuffer: AudioBuffer }> {\n  const stream = await navigator.mediaDevices.getUserMedia({\n    audio: {\n      channelCount: 1,\n      echoCancellation: true,\n      noiseSuppression: true,\n    },\n  });\n\n  const mediaRecorder = new MediaRecorder(stream);\n  const audioChunks: Blob[] = [];\n\n  mediaRecorder.ondataavailable = (event) => {\n    audioChunks.push(event.data);\n  };\n\n  // Start recording\n  mediaRecorder.start();\n\n  // Record for specified duration\n  await new Promise((resolve) => setTimeout(resolve, durationMs));\n\n  // Stop recording\n  mediaRecorder.stop();\n  stream.getTracks().forEach((track) => track.stop());\n\n  // Wait for final data\n  await new Promise((resolve) => {\n    mediaRecorder.onstop = resolve;\n  });\n\n  // Convert recorded audio to PCM\n  const audioBlob = new Blob(audioChunks);\n  const arrayBuffer = await audioBlob.arrayBuffer();\n\n  const audioContext = new AudioContext({ sampleRate });\n  const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);\n\n  const pcm16 = audioBufferToInt16(audioBuffer, sampleRate);\n\n  return { pcm16, audioBuffer };\n}\n\n/**\n * Load audio from a URL or File\n *\n * @param source - URL string or File object\n * @param targetSampleRate - Target sample rate (default: 16000)\n * @returns Object containing PCM16 data and AudioBuffer\n */\nexport async function loadAudio(\n  source: string | File,\n  targetSampleRate = 16000\n): Promise<{ pcm16: Int16Array; audioBuffer: AudioBuffer }> {\n  let arrayBuffer: ArrayBuffer;\n\n  if (typeof source === 'string') {\n    // Load from URL\n    const response = await fetch(source);\n    arrayBuffer = await response.arrayBuffer();\n  } else {\n    // Load from File\n    arrayBuffer = await source.arrayBuffer();\n  }\n\n  const audioContext = new AudioContext({ sampleRate: targetSampleRate });\n  const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);\n\n  const pcm16 = audioBufferToInt16(audioBuffer, targetSampleRate);\n\n  return { pcm16, audioBuffer };\n}\n"]}