1class SnichDenoiseProcessor extends AudioWorkletProcessor { 2 static get parameterDescriptors() { 3 return [ 4 { 5 name: 'strength', 6 defaultValue: 0.55, 7 minValue: 0, 8 maxValue: 1, 9 automationRate: 'k-rate', 10 }, 11 { 12 name: 'outputGain', 13 defaultValue: 1, 14 minValue: 0.25, 15 maxValue: 2, 16 automationRate: 'k-rate', 17 }, 18 ]; 19 } 20 21 constructor() { 22 super(); 23 this.noiseFloor = 0.003; 24 this.gain = 1; 25 this.frame = 0; 26 this.lastRms = 0; 27 this.lastGain = 1; 28 } 29 30 process(inputs, outputs, parameters) { 31 const input = inputs[0]; 32 const output = outputs[0]; 33 if (!input || !output || input.length === 0) { 34 return true; 35 } 36 37 const strength = parameters.strength.length > 0 ? parameters.strength[0] : 0.55; 38 const outputGain = parameters.outputGain.length > 0 ? parameters.outputGain[0] : 1; 39 const channelCount = Math.min(input.length, output.length); 40 41 let sumSquares = 0; 42 let sampleCount = 0; 43 44 for (let ch = 0; ch < channelCount; ch += 1) { 45 const inputChannel = input[ch]; 46 for (let i = 0; i < inputChannel.length; i += 1) { 47 const sample = inputChannel[i]; 48 sumSquares += sample * sample; 49 sampleCount += 1; 50 } 51 } 52 53 const rms = sampleCount > 0 ? Math.sqrt(sumSquares / sampleCount) : 0; 54 this.lastRms = rms; 55 56 const isLikelyNoise = rms < Math.max(0.012, this.noiseFloor * 3.2); 57 if (isLikelyNoise) { 58 this.noiseFloor = this.noiseFloor * 0.995 + rms * 0.005; 59 } else { 60 this.noiseFloor = this.noiseFloor * 0.9995 + Math.min(rms, this.noiseFloor * 1.8) * 0.0005; 61 } 62 63 const openThreshold = Math.max(0.01, this.noiseFloor * (2.6 - strength * 0.7)); 64 const closeThreshold = Math.max(0.006, this.noiseFloor * (1.45 - strength * 0.25)); 65 const minGain = 1 - strength * 0.72; 66 const ratio = rms <= closeThreshold 67 ? 0 68 : Math.min(1, (rms - closeThreshold) / Math.max(0.0001, openThreshold - closeThreshold)); 69 const targetGain = minGain + (1 - minGain) * ratio; 70 const smoothing = targetGain > this.gain ? 0.32 : 0.045; 71 this.gain = this.gain + (targetGain - this.gain) * smoothing; 72 this.lastGain = this.gain; 73 74 for (let ch = 0; ch < output.length; ch += 1) { 75 const inputChannel = input[ch] || input[0]; 76 const outputChannel = output[ch]; 77 for (let i = 0; i < outputChannel.length; i += 1) { 78 const sample = inputChannel ? inputChannel[i] : 0; 79 const gained = sample * this.gain * outputGain; 80 outputChannel[i] = Math.tanh(gained * 1.15) / 1.15; 81 } 82 } 83 84 this.frame += 1; 85 if (this.frame % 120 === 0) { 86 this.port.postMessage({ 87 type: 'metrics', 88 rms: this.lastRms, 89 noiseFloor: this.noiseFloor, 90 gain: this.lastGain, 91 }); 92 } 93 94 return true; 95 } 96} 97 98registerProcessor('snich-denoise-processor', SnichDenoiseProcessor);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.