/// <reference path="../CommandGlobals.d.ts" />

const APF = (input : Float32Array, output : Float32Array, start: number, end: number, delay : number, coef : number) => {
  for(let i = start; i < end; i++) {
    const delayedIdx = Math.max(0, i - delay);
    output[i] = coef * input[i] + input[delayedIdx] - coef * output[delayedIdx];
  }
};

const FBCF = (input : Float32Array, output : Float32Array, start: number, end: number, delay : number, b : number, a : number) => {
  for(let i = start; i < end; i++) {
    const delayedIdx = Math.max(0, i - delay);
    output[i] = b * input[i] - a * output[delayedIdx];
  }
};

const reverse = (input : Float32Array, output : Float32Array, start: number, end: number) => {
  for(let i = start; i < end; i++) {
    output[end + start - i] = input[i];
  }
};

project.mapSelectedChannels(
  (originalChannelData, selectionStart, selectionEnd) => {
      const outputChannelData = new Float32Array(originalChannelData.length);
      const temp = [];
      temp[0] = Float32Array.from(outputChannelData);

      outputChannelData.set(originalChannelData);
      reverse(originalChannelData, outputChannelData, selectionStart, selectionEnd);
      temp[0].set(outputChannelData);

      APF(outputChannelData, temp[0], selectionStart, selectionEnd, 347, 0.7);
      outputChannelData.set(temp[0]);
      APF(temp[0], outputChannelData, selectionStart, selectionEnd, 113, 0.7);
      temp[0].set(outputChannelData);
      APF(outputChannelData, temp[0], selectionStart, selectionEnd, 37, 0.7);

      outputChannelData.set(temp[0]);

      for(let i = 1; i < 4; i++) {
        temp[i] = Float32Array.from(outputChannelData);
      }

      FBCF(outputChannelData, temp[0], selectionStart, selectionEnd, 1687, 1, 0.773);
      FBCF(outputChannelData, temp[1], selectionStart, selectionEnd, 1601, 1, 0.802);
      FBCF(outputChannelData, temp[2], selectionStart, selectionEnd, 2053, 1, 0.753);
      FBCF(outputChannelData, temp[3], selectionStart, selectionEnd, 2251, 1, 0.733);

      for(let i = selectionStart; i < selectionEnd; i++) {
        temp[0][i] = -0.425 * temp[0][i] + 0.552 * temp[1][i] - 0.567 * temp[2][i] + 0.443 * temp[3][i];
      }
      reverse(temp[0], temp[1], selectionStart, selectionEnd);
      for(let i = selectionStart; i < selectionEnd; i++) {
        outputChannelData[i] = 0.5 * originalChannelData[i] + 0.5 * temp[1][i];
      }

      return outputChannelData;
    }
  }
)
