#!/bin/bash
#
# iyambae-tuner — Steuerung für die PipeWire-Filterkette.
#
# Das Umstimmen selbst steckt im LADSPA-Plugin; PipeWire hängt es ein. Dieses
# Werkzeug tut nur das, wofür ein Mensch sonst Kennungen nachschlagen müsste:
# den Dienst starten, die Senke zur Standardsenke machen, und den Faktor im
# laufenden Betrieb ändern, ohne dass der Ton abreißt.
set -uo pipefail

PLUGIN=/usr/lib/ladspa/iyambae_tuner.so
KONFIG=/usr/share/iyambae-tuner/iyambae-tuner.conf
KONFIG_HQ=/usr/share/iyambae-tuner/iyambae-tuner-hq.conf
KNOTEN=iyambae-tuner
DIENST=iyambae-tuner.service
DIENST_HQ=iyambae-tuner-hq.service

hilfe() {
cat <<'ENDE'
IYAMBAE Tuner — stimmt den Systemton unter PipeWire um.

  iyambae-tuner start [hq]       Dienst starten (und beim Anmelden mitstarten).
                                 "hq" nimmt Signalsmith statt der Delay-Line.
  iyambae-tuner stop             Dienst beenden
  iyambae-tuner status           Läuft er? Welche Stimmung? Woran hängt er?

  iyambae-tuner stimmung <Hz>    Zielstimmung, bezogen auf 440 Hz. Wirkt sofort.
  iyambae-tuner faktor <x>       Faktor unmittelbar setzen (0,25 bis 4,0).
  iyambae-tuner bypass an|aus    Durchreichen ohne Umstimmung.

  iyambae-tuner standard         Den Tuner zur Standardsenke machen.
  iyambae-tuner zurueck <Senke>  Eine andere Senke zur Standardsenke machen.

Beispiele:
  iyambae-tuner start && iyambae-tuner standard
  iyambae-tuner stimmung 432
  iyambae-tuner stimmung 440      # wieder Kammerton, ohne Neustart

Die Engine (schnell oder HQ) wird in der Konfiguration gewählt:
  /usr/share/iyambae-tuner/iyambae-tuner.conf   —   siehe iyambae-tuner(1)
ENDE
}

# Kennung des Filterknotens im laufenden Graphen suchen. Ohne laufenden
# Dienst gibt es sie nicht — dann ist das kein Fehler, sondern eine Antwort.
knoten_id() {
    pw-cli ls Node 2>/dev/null | awk -v n="$KNOTEN" '
        /^[[:space:]]*id [0-9]+,/ { id = $2; sub(",", "", id) }
        $0 ~ ("node\\.name = \"" n "\"") { print id; exit }'
}

setze_param() {
    local id
    id="$(knoten_id)"
    if [ -z "$id" ]; then
        echo "Der Tuner läuft nicht — erst 'iyambae-tuner start'." >&2
        return 1
    fi
    # `params` spricht die Steuerports der Filterkette an. Der Name ist
    # <Knoten>:<Port> aus der Konfigurationsdatei.
    pw-cli s "$id" Props "{ params = [ \"tuner:$1\" $2 ] }" >/dev/null 2>&1 \
        || { echo "Konnte $1 nicht setzen." >&2; return 1; }
}

standardsenke_setzen() {
    local name="$1"
    if command -v wpctl >/dev/null 2>&1; then
        local id
        id="$(pw-cli ls Node 2>/dev/null | awk -v n="$name" '
            /^[[:space:]]*id [0-9]+,/ { id = $2; sub(",", "", id) }
            $0 ~ ("node\\.name = \"" n "\"") { print id; exit }')"
        [ -n "$id" ] && wpctl set-default "$id" >/dev/null 2>&1 && return 0
    fi
    if command -v pactl >/dev/null 2>&1; then
        pactl set-default-sink "$name" >/dev/null 2>&1 && return 0
    fi
    # Letzter Weg ohne beide Werkzeuge: unmittelbar in die Metadaten.
    pw-metadata 0 default.audio.sink "{\"name\":\"$name\"}" >/dev/null 2>&1
}

befehl="${1:-hilfe}"; shift 2>/dev/null || true

case "$befehl" in
    start)
        # Ohne Argument die schnelle Engine; `start hq` nimmt Signalsmith.
        # Die beiden Dienste schließen einander aus — zwei Senken desselben
        # Zwecks wären nur verwirrend.
        case "${1:-schnell}" in
            hq)      d="$DIENST_HQ"; k="$KONFIG_HQ" ;;
            schnell) d="$DIENST";    k="$KONFIG" ;;
            *) echo "start schnell oder start hq?" >&2; exit 2 ;;
        esac
        systemctl --user enable --now "$d" 2>/dev/null \
            || { echo "systemd nicht verfügbar — starte im Vordergrund:"; \
                 exec pipewire -c "$k"; }
        sleep 1
        if [ -n "$(knoten_id)" ]; then
            echo "Läuft. Jetzt noch: iyambae-tuner standard"
        else
            echo "Gestartet, aber der Knoten ist nicht aufgetaucht." >&2
            echo "  journalctl --user -u $d" >&2
            exit 1
        fi
        ;;
    stop)
        n=0
        for d in "$DIENST" "$DIENST_HQ"; do
            systemctl --user disable --now "$d" 2>/dev/null && n=$((n+1))
        done
        [ "$n" -gt 0 ] && echo "Beendet." || echo "Kein laufender Dienst gefunden."
        ;;
    status)
        id="$(knoten_id)"
        if [ -z "$id" ]; then echo "Der Tuner läuft nicht."; exit 1; fi
        echo "Knoten:        $KNOTEN (id $id)"
        echo "Standardsenke: $(pactl get-default-sink 2>/dev/null || echo unbekannt)"
        echo "Verkabelung:"
        pw-link -l 2>/dev/null | grep -A1 -i iyambae | sed 's/^/  /'
        ;;
    stimmung)
        [ $# -ge 1 ] || { echo "Wieviel Hz?" >&2; exit 2; }
        f="$(awk -v h="$1" 'BEGIN{ printf "%.12f", h/440.0 }')"
        setze_param Factor "$f" && echo "Stimmung $1 Hz (Faktor $f)"
        ;;
    faktor)
        [ $# -ge 1 ] || { echo "Welcher Faktor?" >&2; exit 2; }
        setze_param Factor "$1" && echo "Faktor $1"
        ;;
    bypass)
        case "${1:-}" in
            an|ein|1)  setze_param Bypass 1 && echo "Bypass an (nicht umgestimmt)" ;;
            aus|0)     setze_param Bypass 0 && echo "Bypass aus" ;;
            *) echo "an oder aus?" >&2; exit 2 ;;
        esac
        ;;
    standard)
        standardsenke_setzen "$KNOTEN" \
            && echo "Standardsenke ist jetzt der Tuner." \
            || { echo "Konnte die Standardsenke nicht setzen." >&2; exit 1; }
        ;;
    zurueck)
        [ $# -ge 1 ] || { echo "Auf welche Senke?" >&2; exit 2; }
        standardsenke_setzen "$1" && echo "Standardsenke ist jetzt $1."
        ;;
    -h|--help|hilfe|help) hilfe ;;
    *) echo "Unbekannt: $befehl"; echo; hilfe; exit 2 ;;
esac
