package com.foxx.androidcast.receiver.av;

/**
 * Stereo headphone spatialization stub: crossfeed + short delays (5.1 or 7.1 flavor).
 */
public final class DolbySurroundAudioFilter implements AudioFilter {
    private final boolean sevenOne;
    private float[] delayL;
    private float[] delayR;
    private int writeIdx;
    private int channels;

    DolbySurroundAudioFilter(boolean sevenOne) {
        this.sevenOne = sevenOne;
    }

    @Override
    public void reset(int sampleRate, int channels) {
        this.channels = channels;
        int maxDelay = sampleRate > 0 ? Math.max(32, sampleRate * 12 / 1000) : 512;
        delayL = new float[maxDelay];
        delayR = new float[maxDelay];
        writeIdx = 0;
    }

    @Override
    public void process(byte[] pcm, int bytes, int sampleRate, int channels, int intensity) {
        if (intensity <= 0 || channels < 2 || sampleRate <= 0) {
            return;
        }
        if (delayL == null || this.channels != channels) {
            reset(sampleRate, channels);
        }
        float g = PcmAudioFilters.intensityGain(intensity);
        int d1 = Math.min(delayL.length - 1, sampleRate * 3 / 1000);
        int d2 = Math.min(delayL.length - 1, sampleRate * 7 / 1000);
        int d3 = sevenOne ? Math.min(delayL.length - 1, sampleRate * 11 / 1000) : 0;
        float wet = 0.22f * g;
        int frames = bytes / (2 * channels);
        int off = 0;
        for (int i = 0; i < frames; i++) {
            float l = PcmAudioFilters.readSample(pcm, off);
            float r = PcmAudioFilters.readSample(pcm, off + 2);
            delayL[writeIdx] = l;
            delayR[writeIdx] = r;
            float tapL = delayL[(writeIdx - d1 + delayL.length) % delayL.length];
            float tapR = delayR[(writeIdx - d1 + delayR.length) % delayR.length];
            float wideL = l + wet * (tapR * 0.6f + delayR[(writeIdx - d2 + delayR.length) % delayR.length] * 0.3f);
            float wideR = r + wet * (tapL * 0.6f + delayL[(writeIdx - d2 + delayL.length) % delayL.length] * 0.3f);
            if (sevenOne && d3 > 0) {
                wideL += wet * 0.15f * delayR[(writeIdx - d3 + delayR.length) % delayR.length];
                wideR += wet * 0.15f * delayL[(writeIdx - d3 + delayL.length) % delayL.length];
            }
            PcmAudioFilters.writeSample(pcm, off, wideL);
            PcmAudioFilters.writeSample(pcm, off + 2, wideR);
            writeIdx = (writeIdx + 1) % delayL.length;
            off += 2 * channels;
        }
    }
}
