/** * Detection utilities + model catalog for Lotus ML noise suppression * (DeepFilterNet 3 / DTLN / RNNoise / Speex). The catalog is ordered by * quality (and, correspondingly, CPU cost) — highest first — and drives the * order of the model dropdown in settings. */ import { DenoiseModelId } from '../state/settings'; export type DenoiseModel = { id: DenoiseModelId; name: string; description: string; cpuUsage: string; binarySize: string; transients: 'Poor' | 'Good' | 'Excellent'; voiceQuality: 'Moderate' | 'High' | 'Very High'; }; // Ordered best-quality (highest CPU) first — this is the dropdown order. export const DENOISE_MODELS: DenoiseModel[] = [ { id: 'deepfilternet', name: 'DeepFilterNet 3 (beta)', description: 'Studio-grade deep-learning model (48 kHz fullband, ONNX). Best quality; highest CPU and a larger one-time download.', cpuUsage: '25-50%', binarySize: '~18 MB', transients: 'Excellent', voiceQuality: 'Very High', }, { id: 'dtln', name: 'DTLN (beta)', description: 'Dual-signal deep-learning model (16 kHz). Strong on transient noise; moderate CPU.', cpuUsage: '10-20%', binarySize: '~4 MB', transients: 'Excellent', voiceQuality: 'High', }, { id: 'rnnoise', name: 'RNNoise', description: 'Lightweight hybrid model (48 kHz). Very low CPU; good for steady noise like fans, but can sound processed at full strength.', cpuUsage: '< 5%', binarySize: '< 1 MB', transients: 'Good', voiceQuality: 'Moderate', }, { id: 'speex', name: 'Speex (Legacy)', description: 'Classic DSP noise suppressor. Minimal CPU, gentlest on voice; weakest suppression.', cpuUsage: '< 2%', binarySize: '< 1 MB', transients: 'Poor', voiceQuality: 'Moderate', }, ]; export const isMLDenoiseSupported = (): boolean => { if (typeof window === 'undefined') return false; // Requirements: // 1. AudioContext/webkitAudioContext (Web Audio API) // 2. AudioWorklet (Real-time processing in a background thread) // 3. getUserMedia (Microphone access) const hasAudioContext = !!(window.AudioContext || (window as any).webkitAudioContext); // Use `typeof` rather than `!!AudioWorkletNode`: on a browser that has // AudioContext but no AudioWorkletNode binding (older Safari/Edge), a bare // reference throws ReferenceError, making this feature-detection helper throw // instead of returning false. const hasAudioWorklet = hasAudioContext && typeof AudioWorkletNode !== 'undefined'; const hasGetUserMedia = !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia); // Every ML model compiles WebAssembly (and DFN/DTLN load worklets via blob // URLs). Under a strict CSP without `wasm-unsafe-eval` (e.g. some desktop/Tauri // shells) WASM is unavailable, so gate on it — otherwise we'd offer ML and then // silently fall back to the raw mic in-call. const hasWasm = typeof WebAssembly !== 'undefined' && typeof WebAssembly.instantiate === 'function'; return hasAudioWorklet && hasGetUserMedia && hasWasm; }; /** * EXACT requirements for ML Denoise (for UI display). */ export const ML_DENOISE_REQUIREMENTS = [ 'Modern browser with Web Audio API support', 'AudioWorklet support (Chrome 66+, Firefox 76+, Safari 14.1+)', 'WebAssembly (WASM) support', 'Microphone access', ];