UNPKG

murmuraba

Version:

Real-time audio noise reduction with advanced chunked processing for web applications

86 lines (85 loc) 3.24 kB
export class RNNoiseEngine { constructor(config) { this.name = 'RNNoise'; this.description = 'Neural network-based noise suppression'; this.isInitialized = false; this.module = null; this.state = null; this.inputPtr = 0; this.outputPtr = 0; this.lastVad = 0; this.config = { wasmPath: config?.wasmPath || '', scriptPath: config?.scriptPath || '' }; } async initialize() { if (this.isInitialized) return; console.log('[RNNoiseEngine] Starting initialization...'); // Check WebAssembly support first if (typeof WebAssembly === 'undefined') { throw new Error('WebAssembly is not supported in this environment'); } const errors = []; try { // Use the bundled RNNoise loader const { loadRNNoiseModule } = await import('../utils/rnnoise-loader'); this.module = await loadRNNoiseModule(); } catch (error) { const errorMsg = error?.message || String(error); console.error('[RNNoiseEngine] Failed to load RNNoise:', errorMsg); throw new Error(`Failed to initialize RNNoise: ${errorMsg}`); } // Create state if not already created if (!this.state) { this.state = this.module._rnnoise_create(0); if (!this.state) { throw new Error('Failed to create RNNoise state'); } } // Allocate memory for float32 samples this.inputPtr = this.module._malloc(480 * 4); this.outputPtr = this.module._malloc(480 * 4); // Warm up const silentFrame = new Float32Array(480); for (let i = 0; i < 10; i++) { this.module.HEAPF32.set(silentFrame, this.inputPtr >> 2); this.module._rnnoise_process_frame(this.state, this.outputPtr, this.inputPtr); } this.isInitialized = true; console.log('[RNNoiseEngine] Initialization complete!'); } process(inputBuffer) { if (!this.isInitialized) { throw new Error('RNNoiseEngine not initialized'); } if (inputBuffer.length !== 480) { throw new Error('RNNoise requires exactly 480 samples per frame'); } // Copy to WASM heap this.module.HEAPF32.set(inputBuffer, this.inputPtr >> 2); // Process with RNNoise and capture VAD const vad = this.module._rnnoise_process_frame(this.state, this.outputPtr, this.inputPtr); // Get output const outputData = new Float32Array(480); for (let i = 0; i < 480; i++) { outputData[i] = this.module.HEAPF32[(this.outputPtr >> 2) + i]; } // Store VAD for later use if needed this.lastVad = vad || 0; // Return audio data only return outputData; } cleanup() { if (this.module && this.state) { this.module._free(this.inputPtr); this.module._free(this.outputPtr); this.module._rnnoise_destroy(this.state); this.state = null; this.module = null; this.isInitialized = false; } } }