#!/bin/bash
# Fast Site Engine. Copyright © AC (acwed@ya.ru), 2004-2024. All rights reserved. 2-clause BSD license.
if [[ -z $1 ]]; then echo 'Error: no param! Manual: https://fsen.ru/linux/sound'; exit 1; fi
export LANGUAGE=en LANG=en_US.UTF-8 A1=$1 A2=${2-0} A3=${3-} A4=${4-} A5=${5-}
declare -A AC;
cv(){ local V=${1-}; V=${V#*\"}; V=${V%\"}; echo $V; }
acp(){
  local I=${1-} N=${2-} D=${3-} B=${4-} O=${5-} R=${6-} M=${7-} J=${8-} F=${9-}
  AC[$I]=$I; AC[$I'n']=$N; AC[$I'f']=${D,,}; AC[$I'd']=$D; AC[$I'b']=$B; AC[$I'o']=${O%, };
  if [[ -z $F ]]; then
    AC[$I'r']=$R; AC[$I's']=$M; AC[$I'j']=$J
    [[ $M == ${AC['sink']} ]] && AC['def']=$I
  else AC[$I'i']=${R%, }; AC[$I'p']=${M%, }; AC[$I'a']=$J; fi
}
fcards(){
  local F=${1-} C=$(pactl info) L='' T='' I='' N='' D='' B='' O='' R='' M='' J='' DB='device.bus_path' CD='alsa.card =' CN='alsa.card.name' DD='device.description' U='output' A='available)'
  AC=()
  while read L; do
    if [[ $L =~ 'Default Sink: ' ]]; then AC['sink']=${L/Default Sink: /};
    elif [[ $L =~ 'Default Source: ' ]]; then AC['source']=${L/Default Source: /}; fi
  done <<< "$(echo -e "$C")"
  C=$(pactl list sinks)
  while read L; do
    if [[ $L =~ 'Sink #' ]]; then
      [[ -n $I ]] && acp "$I" "$N" "$D" "$B" "$O" "$R" "$M" "$J"
      I=''; N=''; D=''; B=''; O=''; R=''; M=''; J=${L/Sink #/}
    elif [[ $L =~ 'State: ' ]]; then R=${L/State: /}
    elif [[ $L =~ 'Name: ' ]]; then M=${L/Name: /}
    elif [[ $L =~ $DB ]]; then B=$(cv "$L")
    elif [[ $L =~ $CD ]]; then I=$(cv "$L")
    elif [[ $L =~ $CN ]]; then D=$(cv "$L")
    elif [[ $L =~ $DD ]]; then D+=' - '$(cv "$L")
    elif [[ $L =~ $U && $L =~ $A ]]; then
      [[ $L =~ 'not '$A ]] && T=' (not '$A || T=' ('$A
      O+=${L%' ('*}$T', '
    fi
  done <<< "$(echo -e "$C")"
  [[ -n $I ]] && acp "$I" "$N" "$D" "$B" "$O" "$R" "$M" "$J"
  if [[ -n $F ]]; then
    C=$(pactl list cards); I=''; N=''; D=''; B=''; O=''; R=''; M=''; J=''
    while read L; do
      if [[ $L =~ 'Name: ' ]]; then
        [[ -n $I ]] && acp "$I" "$N" "$D" "$B" "$O" "$R" "$M" "$J" 1
        N=${L/Name: /}; I=''; D=''; B=''; O=''; R=''; M=''; J=''
      elif [[ $L =~ $CD ]]; then I=$(cv "$L");
      elif [[ $L =~ $CN ]]; then D=$(cv "$L")
      elif [[ $L =~ $DB ]]; then B=$(cv "$L")
      elif [[ $L =~ $DD && ! $L =~ 'Sink' ]]; then D+=' - '$(cv "$L")
      elif [[ $L =~ 'available: yes' ]]; then M+=${L%' ('*}', '
      elif [[ $L =~ 'Active Profile:' ]]; then J=${L/Active Profile: /}
      elif [[ $L =~ $A ]]; then
        [[ $L =~ 'not '$A ]] && T=' (not '$A || T=' ('$A
        if [[ $L =~ $U ]]; then
          [[ $L =~ 'hdmi' && $T == ' (not '$A ]] && continue
          O+=${L%' ('*}$T', '
        else R+=${L%' ('*}$T', '; fi
      fi
    done <<< "$(echo -e "$C")"
    [[ -n $I ]] && acp "$I" "$N" "$D" "$B" "$O" "$R" "$M" "$J" 1
  fi
}
getcard(){
  local C=${1-} I=0 R='^[0-9]+$' V=''
  if [[ -z $C ]]; then V=${AC['def']}
  elif [[ $C =~ $R ]]; then
    if [[ -n ${AC[$C]+x} ]]; then (($C > 9)) && V=${AC[$C]} || V=$C; fi
  else C=${C,,}
    for ((I=0; I < 9; I++)); do
      if [[ -n ${AC[$I]+x} ]] && [[ ${AC[$I'f']} =~ $C ]]; then V=$I; break; fi
    done
  fi; echo "$V"
}
setv(){
  local V=${1-0} C=${2-} J=''
  C=$(getcard "$C")
  if [[ -n $C ]]; then
    J=${AC[$C'j']}
    if [[ $V =~ '+' ]]; then V='+'${V//+/}
    elif [[ $V =~ '-' ]]; then V='-'${V//-/}; fi
    pactl set-sink-volume "$J" "$V"
    pactl set-sink-mute "$J" 0
  fi
}
setvol(){
  local C=${1-} V=${2-0} J=0
  if [[ $C == 'all' ]]; then
    for ((J=0; J < 9; J++)); do
      if [[ -n ${AC[$J]+x} ]]; then setv "$V" "$J"; fi
    done
  else setv "$V" "$C"; fi
}
if [[ $A1 == 'up' ]]; then fcards; setvol "$A3" "+${A2//-/}"; exit 0
elif [[ $A1 == 'down' ]]; then fcards; setvol "$A3" "-${A2//+/}"; exit 0
elif [[ $A1 == 'vol' ]]; then fcards; setvol "$A3" "$A2"; exit 0
elif [[ $A1 == 'start' ]]; then fcards; setvol 'all' '1%'; sleep 1s; setvol 'all' '1%'; sleep 3s; setvol 'all' "$A2%"; exit 0; fi
if [[ $A1 == 'showcards' || $A1 == 'set' || $A1 == 'toggle' || $A1 == 'setpreset' ]]; then
  export -f cv acp fcards getcard setv setvol
  fsesoundf; exit 0;
fi
if [[ $A1 == 'icon' || $A1 == 'upmix' ]]; then fsesoundf; exit 0; fi
