# Copyright 2025 XMOS LIMITED.
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
"""
The Soundcard Pipeline definition.
"""

from audio_dsp.design.pipeline import Pipeline, generate_dsp_main
from audio_dsp.design.parse_json import pipeline_to_dspjson
from audio_dsp.stages import *
from pathlib import Path


def pipeline():
    # 0, 1 USB music
    # 2, 3 Mic
    p, in_edges = Pipeline.begin(4, fs=48000)

    mics = p.stage(Adder, in_edges[2, 3])
    mics = p.stage(VolumeControl, mics, "mic_volume")
    music = p.stage(VolumeControl, in_edges[0, 1], "music_volume")

    peq, peq_bypass = p.stage(Fork, mics).forks
    peq = p.stage(CascadedBiquads, peq, "peq")
    peq_sw = p.stage(Switch, peq_bypass + peq, "peq_sw")

    ns, ns_bypass = p.stage(Fork, peq_sw).forks
    ns = p.stage(NoiseSuppressorExpander, ns, "denoise")
    ns = p.stage(Switch, ns_bypass + ns, "denoise_sw")

    p.next_thread()
    rv_bp0, rv_bp1, rv0, rv1 = p.stage(Fork, ns, count=4).forks

    rv = p.stage(ReverbPlateStereo, rv0 + rv1, "reverb", predelay=20)
    rv_sw = p.stage(SwitchStereo, rv_bp0 + rv_bp1 + rv, "reverb_switch")

    duck_bypass, duck = p.stage(Fork, music).forks

    p.next_thread()
    processed_mic = p.stage(Fork, rv_sw, count=3).forks

    duck0 = p.stage(CompressorSidechain, duck[0] + processed_mic[0][0], "duck0")
    duck1 = p.stage(CompressorSidechain, duck[1] + processed_mic[0][1], "duck1")
    duck = p.stage(SwitchStereo, duck_bypass + duck0 + duck1, "duck_switch")
    duck = p.stage(Fork, duck).forks

    loopback0 = p.stage(Adder, duck[0][0] + processed_mic[1][0])
    loopback1 = p.stage(Adder, duck[0][1] + processed_mic[1][1])

    p.next_thread()

    gl_sw = p.stage(
        SwitchStereo, processed_mic[2][:] + loopback0 + loopback1, "loopback_switch"
    )
    gl_sw = p.stage(Fork, gl_sw).forks

    output = p.stage(VolumeControl, gl_sw[0][:], "output_volume")

    headphone = p.stage(SwitchStereo, duck[1][:] + gl_sw[1][:], "monitor_switch")
    headphone = p.stage(VolumeControl, headphone, "headphone_volume")

    # 4 outputs
    # 0, 1 USB
    # 2, 3 Headphone
    p.set_outputs(output + headphone)
    # p.draw()

    p["peq"].make_parametric_eq(
        [
            ["highpass", 100, 0.707],
            ["lowpass", 14000, 0.707],
        ]
    )

    p["reverb"].set_damping(0.2)
    p["reverb"].set_decay(0.6)
    p["reverb"].set_predelay(14)
    p["reverb"].set_wet_dry_mix(0.7)
    p["reverb"].set_width(1.0)

    p["denoise"].make_noise_suppressor_expander(
        ratio=3, threshold_db=-45, attack_t=0.005, release_t=0.12
    )

    p["duck0"].make_compressor_sidechain(
        ratio=5, threshold_db=-40, attack_t=0.01, release_t=0.5
    )
    p["duck1"].make_compressor_sidechain(
        ratio=5, threshold_db=-40, attack_t=0.01, release_t=0.5
    )
    return p


if __name__ == "__main__":
    p = pipeline()

    # write the JSON data to a file
    json_data = pipeline_to_dspjson(p)
    filepath = Path("live_streaming_sound_card.json")
    filepath.write_text(json_data.model_dump_xdsp())
