/* * 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; } } }