const attack = new Float64Array(bufferSize).fill(0);
const sustain = new Float64Array(bufferSize);
const gate = new Float64Array(bufferSize);
const trigger = new Float64Array(bufferSize);
const frequency = new Float64Array(bufferSize);

const Metronome = ({
  clickLength,
  downbeatFrequency,
  otherBeatFrequency,
  frequencyDropAmount,
  amplitude,
  output
}, {
  clock,
  playing,
  beatNumerator,
  metronome,
  bpm
}) => {
  const oscillator = useOscillator(Waveform.Sine, true);
  const envelope = useEnvelope();
  output[0].fill(0);
  output[1].fill(0);
  trigger.fill(0);
  gate.fill(0);
  const lastBeat = useVal(-1);

  if (playing && metronome) {
    for (let i = 0; i < clock.length; i++) {
      const wholeBeat = Math.floor(clock[i]);
      const beatsPerSample = (60/bpm[i])/sampleRate;
      trigger[i] = (wholeBeat !== lastBeat.current && clock[i] % 1 < (beatsPerSample * 10)) ? 1 : 0;
      gate[i] = clock[i] % 1 < 0.5 ? 1 : 0
      lastBeat.current = wholeBeat;
    }
  }

  const envelopeOutput = envelope(trigger, gate, attack, clickLength, sustain, clickLength);

  for (let i = 0; i < frequency.length; i ++) {
    const beatNumberInBar = Math.floor(((clock[i] % beatNumerator) + beatNumerator) % beatNumerator);
    frequency[i] = (
      (beatNumberInBar === 0 ? downbeatFrequency[i] : otherBeatFrequency[i]) *
      (((frequencyDropAmount[i]) * envelopeOutput[i]) + (1 - frequencyDropAmount[i]))
    );
  }

  const oscillatorOutput = oscillator(frequency, useConstantBuffer(0), trigger);

  for (let i = 0; i < output[0].length; i ++) {
    output[0][i] = oscillatorOutput[i] * amplitude[i] * envelopeOutput[i];
    output[1][i] = output[0][i]
  }
}

this.constructDevice = () => constructPerBufferDevice({
  implementation: Metronome,
  inputs: {
    clickLength: collapse(adsrTimeSetting('Click Length', 20)),
    downbeatFrequency: collapse(frequencySetting('Downbeat', 1500)),
    otherBeatFrequency: collapse(frequencySetting('Other Beat', 750)),
    frequencyDropAmount: collapse(numberSetting('Drop', { defaultValue: 0.4, min: 0, max: 1, curve: Curve.Linear })),
    amplitude: collapse(numberSetting('Amplitude', { defaultValue: 0.75, min: 0, max: 1, curve: Curve.Linear }))
  },
  outputs: {
    output: stereo('Output')
  }
});
