package party.bami.eqfix.convolution;

public class Convolver {
    private int sigS;
    private int kerS;
    private float[] ker;
    private float[] prevOverflow;

    public Convolver(int sS, float[] ker) {
        this.sigS = sS;
        this.kerS = ker.length;
        this.ker = ker;
        this.prevOverflow = new float[0];
    }

    /**
     * Returns the convolved signal based on the current kernel
     * @param sig The to be convolved signal.
     * @return The convolved signal
     */
    public float[] convolve(float[] sig) {
        float[] convSig = new float[this.sigS + this.kerS];

        appPrevOverf(convSig);

        for (int i = 0; i < this.sigS; i++) {
            for (int k = 0; k < this.kerS; k++) {
                convSig[i + k] += (sig[i] * this.ker[k]);
            }
        }

        return stripOverflow(convSig);
    }

    /**
     * Adds the overflow of the last convolve operation to the new buffer arrayhier .
     * @param convSig The new buffer array.
     */
    private void appPrevOverf(float[] convSig) {
        for (int i = 0; i < this.prevOverflow.length; i++) {
            convSig[i] = this.prevOverflow[i];
        }
    }

    /**
     * Returns the signal without the overflow and stores the overflow locally.
     * @param convSig The convolved signal.
     * @return The signal without the overflow.
     */
    private float[] stripOverflow(float[] convSig) {
        float[] convSigS = new float[sigS];
        this.prevOverflow = new float[convSig.length - sigS];

        for (int i = 0; i < convSig.length; i ++) {
            if (i < sigS) {
                convSigS[i] = convSig[i];
            } else {
                this.prevOverflow[i - sigS] = convSig[i];
            }
        }

        return convSigS;
    }
}
