Skript pro míchání zvuků a mikrofonu v Audacity

Dobrý den,
snažil jsem se včera, a dnes ráno rozjet skript, protože chci v audacity zaznamenat svůj rozhovor s GPT. Ale marně, nepodařilo se mi to. Včera se mi akorád povedlo slyšet svůj hlas ve sluchátkách a donutit GPT, aby dal příkaz jak to zeslabit na cca 42%. Nahrával se zvuk z přehrávané písničky ve vlc ale písničku jsem neslyšel během toho aktuálního přehrávání přes vlc. Myslím nefungovaly nahlas ty systémové zvuky abych to slyšel ve sluchátkách. A můj hlas se nepovedlo nahrát.

Mám Mint 21.3 xFce.
 
Skript co jsem od něho dostal:
Kód: [Vybrat]
#!/usr/bin/env bash
set -euo pipefail

# ====== CONFIG ======
MIC_PATTERN='input'              # pattern (lowercase) který hledá v 2. sloupci sources
NULL_SINK_NAME='MixSink'         # null-sink pro nahrávání (mix)
VIRTUAL_SRC_NAME='MixSource'     # virtuální zdroj pro Audacity (monitor null-sinku)
MONITOR_ATTEN='42%'              # poslechová hlasitost mikrofonu pro sluchátka
ACTIVATE_TRIES=60                # kolikrát čekat na vznik sink-input (0.1s krok)
SLEEP_STEP=0.1

# ====== helper ======
cmd_exists() { command -v "$1" >/dev/null 2>&1; }

# ====== najdi fyzický sink (prefer RUNNING, jinak první) ======
DEFAULT_SINK=$(pactl list short sinks \
  | sed -E 's/[[:space:]]+/ /g' \
  | awk '{
      if($4=="RUNNING" && !found){ print $2; found=1; next }
      if(!first) first=$2
    }
    END{ if(!found) print first }' \
  || true)

if [ -z "$DEFAULT_SINK" ]; then
  echo "Nelze zjistit fyzický sink." >&2
  exit 1
fi

# ====== najdi mikrofon (preferuj sources, 2. sloupec obsahuje 'input') ======
MIC_SRC=$(pactl list short sources \
  | sed -E 's/[[:space:]]+/ /g' \
  | awk -v pat="$MIC_PATTERN" 'BEGIN{lc_pat=tolower(pat)}
      {
        s=tolower($2)
        if(s ~ lc_pat){ print $2; exit }
        if(!first) first=$2
      }
      END{ if(NR>0 && !found) print first }' \
  || true)

if [ -z "$MIC_SRC" ]; then
  echo "Nenalezen source mikrofonu (pattern: $MIC_PATTERN)." >&2
  exit 1
fi

echo "Fyzický výstup (selected): $DEFAULT_SINK"
echo "Mikrofon (selected): $MIC_SRC"

# ====== cleanup předchozích modulů vztahujících se k našim jménům / mic ======
echo "Odstraňuji předchozí modul-loopback / MixSink / MixSource (pokud existují)..."
pactl list short modules | while read -r id name rest; do
  if [ "$name" = "module-loopback" ] && echo "$rest" | grep -q -F "$MIC_SRC"; then
    echo "  unload-module $id (loopback referející mic)"
    pactl unload-module "$id" || true
  elif echo "$rest" | grep -q -F "$NULL_SINK_NAME"; then
    echo "  unload-module $id (referuje $NULL_SINK_NAME)"
    pactl unload-module "$id" || true
  elif echo "$rest" | grep -q -F "$VIRTUAL_SRC_NAME"; then
    echo "  unload-module $id (referuje $VIRTUAL_SRC_NAME)"
    pactl unload-module "$id" || true
  fi
done

# také pro jistotu odpojit moduly přes přesný řetězec jména
pactl list short modules | awk -v n1="$NULL_SINK_NAME" -v n2="$VIRTUAL_SRC_NAME" '$0 ~ n1 || $0 ~ n2 {print $1}' \
  | xargs -r -n1 -I{} pactl unload-module {} >/dev/null 2>&1 || true

# ====== vytvoř null-sink MixSink pokud neexistuje ======
if pactl list short sinks | sed -E 's/[[:space:]]+/ /g' | awk -v n="$NULL_SINK_NAME" '$2==n{print; exit}' >/dev/null 2>&1; then
  echo "Null-sink $NULL_SINK_NAME existuje (nebudu znovu vytvářet)."
else
  echo "Vytvářím null-sink $NULL_SINK_NAME..."
  pactl load-module module-null-sink sink_name="$NULL_SINK_NAME" sink_properties=device.description="$NULL_SINK_NAME"
fi

NULL_SINK_IDX=$(pactl list short sinks | sed -E 's/[[:space:]]+/ /g' | awk -v n="$NULL_SINK_NAME" '$2==n{print $1; exit}' || true)
echo "MixSink index: ${NULL_SINK_IDX:-<unknown>}"

# ====== vytvoř loopback mikrofon -> MixSink (pro nahrávání Audacity) ======
echo "Vytvářím loopback: $MIC_SRC -> $NULL_SINK_NAME ..."
RECORD_LOOP_MOD=$(pactl load-module module-loopback source="$MIC_SRC" sink="$NULL_SINK_NAME" latency_msec=1 || true)
if [ -z "$RECORD_LOOP_MOD" ]; then
  echo "Chyba: nelze vytvořit record-loop." >&2
  exit 1
fi
echo "Record loop module id: $RECORD_LOOP_MOD"

# ====== probuď mic dočasným čtením (pokud dostupné) ======
ACT_PID=""
if cmd_exists parec; then
  parec -d "$MIC_SRC" >/dev/null 2>&1 &
  ACT_PID=$!
  echo "Spuštěn temporary parec pid=$ACT_PID"
elif cmd_exists pw-cat; then
  pw-cat -d "$MIC_SRC" >/dev/null 2>&1 &
  ACT_PID=$!
  echo "Spuštěn temporary pw-cat pid=$ACT_PID"
else
  echo "parec/pw-cat nenalezeny — pokud bude MIC SUSPENDED, nahrávání ho probudí."
fi

# ====== počkej na sink-input pro record loop (nezbytné pro případné nastavení) ======
REC_SINK_INPUT=""
for i in $(seq 1 $ACTIVATE_TRIES); do
  REC_SINK_INPUT=$(pactl list short sink-inputs | sed -E 's/[[:space:]]+/ /g' | awk -v m="$RECORD_LOOP_MOD" '$3==m{print $1; exit}' || true)
  if [ -n "$REC_SINK_INPUT" ]; then break; fi
  sleep "$SLEEP_STEP"
done

if [ -n "$REC_SINK_INPUT" ]; then
  echo "Record sink-input id: $REC_SINK_INPUT"
else
  echo "Poznámka: record sink-input zatím nevznikl (Audacity při spuštění nahrávání ho probudí)."
fi

# ====== vytvoř monitorovací loopback: mic -> fyzický sink (pro poslech), a ztlum jej ======
echo "Vytvářím monitor loopback: $MIC_SRC -> $DEFAULT_SINK (attenuated monitoring)..."
MON_LOOP_MOD=$(pactl load-module module-loopback source="$MIC_SRC" sink="$DEFAULT_SINK" latency_msec=1 || true)
if [ -n "$MON_LOOP_MOD" ]; then
  echo "Monitor loop module id: $MON_LOOP_MOD"
  MON_SINK_INPUT=""
  for i in $(seq 1 $ACTIVATE_TRIES); do
    MON_SINK_INPUT=$(pactl list short sink-inputs | sed -E 's/[[:space:]]+/ /g' | awk -v m="$MON_LOOP_MOD" '$3==m{print $1; exit}' || true)
    if [ -n "$MON_SINK_INPUT" ]; then
      pactl set-sink-input-volume "$MON_SINK_INPUT" "$MONITOR_ATTEN"
      echo "Monitor sink-input $MON_SINK_INPUT nastavena na $MONITOR_ATTEN"
      break
    fi
    sleep "$SLEEP_STEP"
  done
  if [ -z "$MON_SINK_INPUT" ]; then
    echo "Poznámka: monitor sink-input nevznikl — probuď mic nahráváním v Audacity a pak spusť 'pactl list short sink-inputs' pro nastavení."
  fi
else
  echo "Nepodařilo se vytvořit monitor loopback." >&2
fi

# ====== vytvoř virtuální zdroj (monitor MixSink) pro Audacity ======
if pactl list short sources | sed -E 's/[[:space:]]+/ /g' | awk -v n="$VIRTUAL_SRC_NAME" '$2==n{print $2; exit}'; then
  echo "Virtual source $VIRTUAL_SRC_NAME již existuje."
else
  echo "Vytvářím virtual source $VIRTUAL_SRC_NAME z $NULL_SINK_NAME.monitor..."
  pactl load-module module-virtual-source source_name="$VIRTUAL_SRC_NAME" source_properties=device.description="$VIRTUAL_SRC_NAME" master="$NULL_SINK_NAME.monitor"
fi

VIRT_SRC_IDX=$(pactl list short sources | sed -E 's/[[:space:]]+/ /g' | awk -v n="$VIRTUAL_SRC_NAME" '$2==n{print $1; exit}' || true)
echo "Virtual source index: ${VIRT_SRC_IDX:-<unknown>}"

# ====== cleanup activator ======
if [ -n "${ACT_PID:-}" ]; then
  sleep 0.1
  kill "$ACT_PID" >/dev/null 2>&1 || true
fi

echo
echo "HOTOVO: Audacity vyber zdroj '$VIRTUAL_SRC_NAME' (Mix of system apps + mic at full volume)."
echo "Pro zahrnutí VLC do záznamu: přesuň jeho sink-input do $NULL_SINK_NAME nebo duplikuj fyzický monitor do MixSink."

Skript pro unload
Kód: [Vybrat]
#!/usr/bin/env bash
set -euo pipefail

# ===== Nastavení =====
VIRTUAL_SRC_NAME='MixSource'   # virtuální zdroj pro Audacity
NULL_SINK_NAME='MixSink'       # null-sink pro smíchání zvuků

# ===== Odpojit všechny loopback moduly =====
echo "Odpojuji všechny loopbacky..."
while IFS= read -r id; do
    if pactl unload-module "$id"; then
        echo "Odpojen loopback modul $id"
    else
        echo "Chyba při odpojování loopback modulu $id" >&2
    fi
done < <(pactl list short modules | awk '/module-loopback/ {print $1}')

# ===== Odstranit virtuální zdroj =====
if pactl list short sources | awk '{print $2}' | grep -Fxq "$VIRTUAL_SRC_NAME"; then
    echo "Odstraňuji virtuální zdroj '$VIRTUAL_SRC_NAME'..."
    MODULE_ID=$(pactl list short modules | awk -v src="$VIRTUAL_SRC_NAME" '$0 ~ src {print $1; exit}')
    if [ -n "$MODULE_ID" ]; then
        pactl unload-module "$MODULE_ID" && echo "Odpojen virtuální zdroj '$VIRTUAL_SRC_NAME'"
    fi
fi

# ===== Odstranit null-sink =====
if pactl list short sinks | awk '{print $2}' | grep -Fxq "$NULL_SINK_NAME"; then
    echo "Odstraňuji null-sink '$NULL_SINK_NAME'..."
    MODULE_ID=$(pactl list short modules | awk -v sink="$NULL_SINK_NAME" '$0 ~ sink {print $1; exit}')
    if [ -n "$MODULE_ID" ]; then
        pactl unload-module "$MODULE_ID" && echo "Odpojen null-sink '$NULL_SINK_NAME'"
    fi
fi

echo "Hotovo. Všechny loopbacky, virtuální zdroje a null-sinky odstraněny."

A protože přestaly fungovat zvuky - přehrávání, tak je ještě třeba to opravit
Kód: [Vybrat]
systemctl --user restart pipewire pipewire-pulse wireplumber || systemctl --user restart pipewire pipewire-pulse pulseaudio || true

Pomůžete mi s tím prosím?


Re:Skript pro míchání zvuků a mikrofonu v Audacity
« Odpověď #1 kdy: Dnes v 10:24:29 »
Nelze očekávat, že AI dá na první dobrou skript, který složitě parsuje textové výstupy nějakých utilitek. Např. tohle peklo:

pactl list short modules | awk -v n1="$NULL_SINK_NAME" -v n2="$VIRTUAL_SRC_NAME" '$0 ~ n1 || $0 ~ n2 {print $1}' \
  | xargs -r -n1 -I{} pactl unload-module {} >/dev/null 2>&1 || true

Opravdu myslíš, že tu budou lidi ručně kontrolovat, zda je taková pipeline vygenerovaná správně?

Pokud to po AI chceš, pak jí musíš dodat kvalitní podklady, ze kterých může vycházet se svými znalostmi. Minimálně konkrétní texty výstupů těch volání pactl. Samozřejmě záleží na LLM modelu, zda to vůbec umí.

Rovněž bych po AI chtěl, aby napsala skript tak, aby když přidáš parametr bashe -x a nakopíruješ do ní výsledný debug výstup skriptu, aby z toho dokázala po  sobě zkontrolovat správnou funkci, příp. najít chybu.

Věřím, že dobrý LLM model s dobrým vedením takový skript napíše bez problémů, ale musí se držet pod kontrolou a musí mít k dispozici vhodné vstupní podklady.

A nebo po AI chtěj jen jednotlivé bloky/klíčové řádky a skládej si to do skriptu sám, samozřejmě po ručním otestování každého bloku.

Re:Skript pro míchání zvuků a mikrofonu v Audacity
« Odpověď #2 kdy: Dnes v 11:16:49 »
Dodal jsem to GPT po krokách:
$ pactl list short sources
133   alsa_output.pci-0000_00_1b.0.pro-output-0.monitor   PipeWire   s32le 2 ch 48000 Hz   SUSPENDED
134   alsa_output.pci-0000_00_1b.0.pro-output-3.monitor   PipeWire   s32le 8 ch 48000 Hz   SUSPENDED
135   alsa_input.pci-0000_00_1b.0.pro-input-0   PipeWire   s32le 2 ch 48000 Hz   RUNNING
user@Toshi:~/Bash$ pactl list short sinks
133   alsa_output.pci-0000_00_1b.0.pro-output-0   PipeWire   s32le 2 ch 48000 Hz   SUSPENDED
134   alsa_output.pci-0000_00_1b.0.pro-output-3   PipeWire   s32le 8 ch 48000 Hz   SUSPENDED

plus případné chybové hlášky.

Když se to spustí:
$ ./pulse-zeslab.sh
Fyzický výstup (selected): alsa_output.pci-0000_00_1b.0.pro-output-0
Mikrofon (selected): alsa_input.pci-0000_00_1b.0.pro-input-0
alsa_output.pci-0000_00_1b.0.pro-output-0.monitor
Odstraňuji předchozí modul-loopback / MixSink / MixSource (pokud existují)...
Null-sink MixSink existuje (nebudu znovu vytvářet).
MixSink index: <unknown>
Vytvářím loopback: alsa_input.pci-0000_00_1b.0.pro-input-0
alsa_output.pci-0000_00_1b.0.pro-output-0.monitor -> MixSink ...
Record loop module id: 536870913
Spuštěn temporary parec pid=2150404
Poznámka: record sink-input zatím nevznikl (Audacity při spuštění nahrávání ho probudí).
Vytvářím monitor loopback: alsa_input.pci-0000_00_1b.0.pro-input-0
alsa_output.pci-0000_00_1b.0.pro-output-0.monitor -> alsa_output.pci-0000_00_1b.0.pro-output-0 (attenuated monitoring)...
Monitor loop module id: 536870914
Poznámka: monitor sink-input nevznikl — probuď mic nahráváním v Audacity a pak spusť 'pactl list short sink-inputs' pro nastavení.
Virtual source MixSource již existuje.
Virtual source index: <unknown>

HOTOVO: Audacity vyber zdroj 'MixSource' (Mix of system apps + mic at full volume).
Pro zahrnutí VLC do záznamu: přesuň jeho sink-input do MixSink nebo duplikuj fyzický monitor do MixSink.


V Pavucntrol nahrávání vidím že tam vznikly dva loopbacky pro vstup.
Na vstupní kartě vidím Build in Audio pro jak kdyby tam běžel nějaký šum nebo co. Mám sice zapojený mic ale tento indikátor "Ticho" nereaguje pokud mluvím, takže asi šum - ale toto tam vlastně vidím defaultně i po restartu pulse.

Ale nejde to audacity spustit nebo to krachuje, musím opravit zvuk, vše vrátit jinak audacity ani nespustím.
« Poslední změna: Dnes v 11:18:44 od exkalibr »

Re:Skript pro míchání zvuků a mikrofonu v Audacity
« Odpověď #3 kdy: Dnes v 13:32:23 »
Zkusil jsem copilot, aby dal něco jednoduchého. Netestoval jsem, protože na starším mintu nemám ještě wireplumber. IMO na tom by se dalo stavět https://github.com/copilot/share/403a52b0-0a84-8046-a813-240a6413209a . Je to celkem jednoduché, pár příkazů a generátor konfigurace pro wireplumber, žádné komplikované pipeliny.

Samozřejmě to používá sémantiku PW, ne outdated PA.

Re:Skript pro míchání zvuků a mikrofonu v Audacity
« Odpověď #4 kdy: Dnes v 19:05:01 »
Chápu to dobře že se snažíš nahrát mikrofon namíchaný s interníma zvukama počítače? Audacity neumí zachytávat vícero nezávislých vstupů současně. Použij ffmpeg! Jestli si jako výstup představuješ jeden stereo wav, můžeš zkusit něco takového:
Kód: [Vybrat]
ffmpeg -f pulse -i $(pactl get-default-source) -f pulse -i $(pactl get-default-sink).monitor -filter_complex "[0:a][1:a]amerge=inputs=2[a]" -map "[a]" -ac 2 /tmp/nahrávka.wav