#include "core/instrument/engine/filter/voice_filter.h"

namespace reasampler::instrument::engine::filter {

void VoiceFilter::prepare(const FilterSettings& settings, double sampleRate) {
    q_ = filterQFromNorm(settings.resonanceNorm);
    coeffs_ = svfCoeffs(filterCutoffHzFromNorm(settings.cutoffNorm), q_, sampleRate);
    if (sampleRate > 0.0) {
        mix_ = morphMix(morphWeights(settings.morphNorm, settings.morphLaw), coeffs_.k);
    } else {
        // Bypass: a1=1, a2=a3=0 makes both state updates the exact identity, and bypassMix()
        // reads only the input, never the state -- so clearing here is audibly free (the state
        // was already going to be ignored) and prevents a stale nonzero ic1/ic2 from latching
        // isSilent() false forever, which prepare() otherwise deliberately never does.
        mix_ = bypassMix();
        for (State& s : state_) s = State{};
    }
    driveDepth_ = filterDriveDepthFromNorm(settings.driveNorm);
    driven_ = driveDepth_ != 0.0f;
}

void VoiceFilter::setCutoffNorm(float cutoffNorm, double sampleRate) {
    coeffs_ = svfCoeffs(filterCutoffHzFromNorm(cutoffNorm), q_, sampleRate);
}

void VoiceFilter::reset() {
    for (State& s : state_) s = State{};
}

bool VoiceFilter::isSilent() const {
    for (const State& s : state_) {
        if (s.ic1 != 0.0f || s.ic2 != 0.0f) return false;
    }
    return true;
}

}  // namespace reasampler::instrument::engine::filter
