class KeyboardNoiseGateProcessor extends AudioWorkletProcessor {
  constructor() {
    super();
    this.gain = 1;
  }

  static get parameterDescriptors() {
    return [
      {
        name: 'threshold',
        defaultValue: 0.03,
        minValue: 0.008,
        maxValue: 0.08,
        automationRate: 'k-rate'
      },
      {
        name: 'floor',
        defaultValue: 0.04,
        minValue: 0,
        maxValue: 1,
        automationRate: 'k-rate'
      },
      {
        name: 'attack',
        defaultValue: 0.65,
        minValue: 0,
        maxValue: 0.9999,
        automationRate: 'k-rate'
      },
      {
        name: 'release',
        defaultValue: 0.985,
        minValue: 0,
        maxValue: 0.99999,
        automationRate: 'k-rate'
      }
    ];
  }

  process(inputs, outputs, parameters) {
    const input = inputs[0];
    const output = outputs[0];
    if (!input || !input.length || !output || !output.length) {
      return true;
    }

    const in0 = input[0];
    if (!in0 || !in0.length) {
      return true;
    }

    let sum = 0;
    for (let i = 0; i < in0.length; i += 1) {
      const s = in0[i];
      sum += s * s;
    }
    const rms = Math.sqrt(sum / in0.length);

    const threshold = parameters.threshold[0] ?? 0.03;
    const floor = parameters.floor[0] ?? 0.04;
    const attack = parameters.attack[0] ?? 0.65;
    const release = parameters.release[0] ?? 0.985;

    const target = rms >= threshold ? 1 : floor;
    const coeff = target > this.gain ? attack : release;
    this.gain = coeff * this.gain + (1 - coeff) * target;

    const channels = Math.min(input.length, output.length);
    for (let ch = 0; ch < channels; ch += 1) {
      const src = input[ch];
      const dst = output[ch];
      const len = Math.min(src.length, dst.length);
      for (let i = 0; i < len; i += 1) {
        dst[i] = src[i] * this.gain;
      }
    }

    return true;
  }
}

registerProcessor('keyboard-noise-gate-processor', KeyboardNoiseGateProcessor);
