PageSourceSearch

https://snich.ai/audio-worklets/snich-denoise-processor.js

js snich.ai collected 2026-10-05 15:08:23 UTC 2,955 bytes, 98 lines download raw bytes

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.