/*
 * HalfNES by Andrew Hoffman
 * Licensed under the GNU GPL Version 3. See LICENSE file
 */
package com.grapeshot.halfnes.audio;

/**
 *
 * @author Andrew
 */
public class Reverberator implements AudioOutInterface {

    AudioOutInterface iface;
    CircularBuffer cb;
    double echo, lp_coef, hp_coef;

    public Reverberator(AudioOutInterface i, int length, double echo_gain, double lp_coef, double hp_coef) {
        this.echo = echo_gain;
        this.lp_coef = lp_coef;
        this.hp_coef = hp_coef;
        iface = i;
        cb = new CircularBuffer(length);
    }
    int lpaccum = 0;

    private int lowpass_filter(int sample) {
        sample += lpaccum;
        lpaccum -= sample * lp_coef;
        return lpaccum;
    }
    private int dckiller = 0;

    private int highpass_filter(int sample) {
        //for killing the dc in the signal
        sample += dckiller;
        dckiller -= sample * hp_coef;//the actual high pass part
        dckiller += (sample > 0 ? -1 : 1);//guarantees the signal decays to exactly zero
        return sample;
    }

    @Override
    public void outputSample(int sample) {
        sample -= cb.read() * echo;
        if (sample < -32768) {
            sample = -32768;
            //System.err.println("clip");
        }
        if (sample > 32767) {
            sample = 32767;
            //System.err.println("clop");
        }
        cb.write(lowpass_filter(highpass_filter(sample)));
        if (!(iface == null)) {
            iface.outputSample(sample);
        }
    }

    @Override
    public void flushFrame(boolean waitIfBufferFull) {
        if (!(iface == null)) {
            iface.flushFrame(waitIfBufferFull);
        }

    }

    @Override
    public void pause() {
        if (!(iface == null)) {
            iface.pause();
        }
    }

    @Override
    public void resume() {
        if (!(iface == null)) {
            iface.resume();
        }
    }

    @Override
    public void destroy() {
        if (!(iface == null)) {
            iface.destroy();
        }
    }

    @Override
    public boolean bufferHasLessThan(int samples) {
        if (!(iface == null)) {
            return iface.bufferHasLessThan(samples);
        } else {
            return false;
        }
    }
}
