package net.heartshield.filter;

/**
 * Realtime FIR filter using direct convolution.
 *
 * Introduces a delay that depends on the filter parameters (taps.length/2).
 * Also, the first 2*delay output samples are invalid (initial settling of the filter).
 *
 * @author David Madl (git@abanbytes.eu)
 * @date 2017-05-15
 */
public class FFirFilterRunning extends FFilterBlock {
    private float[] taps;
    private float[] xbuf;

    public FFirFilterRunning(float[] taps) {
        if(taps.length == 0)
            throw new IllegalStateException("taps.length must be > 0");
        this.taps = taps;
        this.xbuf = new float[taps.length];
    }

    /** roll in-place by 1 position to left. in: [x_0 x_1 x_2] out: [x_1 x_2 x_0] */
    private static void rollLeft(float[] x) {
        if(x.length == 0)
            return;
        float x0 = x[0];
        for(int i = 0; i < x.length-1; i++)
            x[i] = x[i+1];
        x[x.length-1] = x0;
    }

    private float convolveOne(float val) {
        float sum = 0.0f;
        rollLeft(xbuf);
        xbuf[xbuf.length-1] = val;
        for(int j = 0; j < taps.length; j++)
            sum += xbuf[j] * taps[j];
        return sum;
    }

    @Override
    protected float[] batch(float[] x) {
        float[] y = new float[x.length];
        for(int i = 0; i < x.length; i++)
            y[i] = convolveOne(x[i]);
        return y;
    }
}
