#!/bin/bash

checkValuesFn() {
  if [ "$1" = "16" ] || [ "$1" = "32" ] || [ "$1" = "64" ] ||\
     [ "$1" = "128" ] || [ "$1" = "256" ] || [ "$1" = "512" ] || [ "$1" = "1024" ] ||\
     [ "$1" = "2048" ] || [ "$1" = "4096" ]; then
    if [ "$2" = "22050" ] || [ "$2" = "32000" ] || [ "$2" = "44100" ] ||\
       [ "$2" = "48000" ] || [ "$2" = "88200" ] || [ "$2" = "96000" ] ||\
       [ "$2" = "192000" ]; then
      return 0
    else
      return 1
    fi
  else
    return 1
  fi
}

changeConfigFn() {
  . /etc/profile.d/ubuntustudio-pwjack.sh
    pwBuff=$(echo $PIPEWIRE_QUANTUM | cut -d "/" -f 1)
    pwFreq=$(echo $PIPEWIRE_QUANTUM | cut -d "/" -f 2)
    pwSetStr=$(zenity \
    --title "Ubuntu Studio Audio Configuration" \
    --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
    --entry \
    --ok-label="Next" \
    --cancel-label="Cancel" \
    --text="Please enter the values for the PipeWire Quantum / JACK Plugin
  configuration separated by a space.\n
  First value is the Buffer Size which can be one of the following:
  16, 32, 64, 128, 256, 512, 1024, 2048, or 4096\n
  Next value is the Sample Rate in Hertz (Hz) which can be one of the following:
  22050, 32000, 44100, 48000, 88200, 96000, or 192000\n
  Example (default): $pwBuff $pwFreq\n
  Leaving this blank will reset to default unless cancelled
  If you're not sure what to do here, it's best to reset to defaults.\n
  Note: Defaults are controlled via the ubuntustudio-pwjack-config terminal command" )
    strExit=$?
    if ! [ "${strExit}" = "1" ]; then
      if [ -n "${pwSetStr}" ]; then
        pwSetArry[0]=$(echo "${pwSetStr}" | cut -d " " -f 1)
        pwSetArry[1]=$(echo "${pwSetStr}" | cut -d " " -f 2)
        if checkValuesFn ${pwSetArry[0]} ${pwSetArry[1]}; then
          true
        else
          zenity --title "Ubuntu Studio Audio Configuration" \
          --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
          --error \
          --text="An error has occurred. Check your entry and try again."
          return 1
        fi
      else
          pwSetArry[0]=$pwBuff
          pwSetArry[1]=$pwFreq
      fi
    fi
    # Parse JACK configuration
    declare -a jackConfig=(
    [0]=jack.show-monitor
    [1]=jack.merge-monitor
    [2]=jack.show-midi
    [3]=jack.short-name
    )
    jackBool=0
    for param in ${jackConfig[@]}; do
      bool=$(grep "${param}" $HOME/.config/pipewire/jack.conf.d/ubuntustudio.conf | cut -d "=" -f 2 | cut -c 2-)
      if [ "${bool}" = "true" ]; then
        jackParam[jackBool]="TRUE"
      else
        jackParam[jackBool]="FALSE"
      fi
      jackBool=$((jackBool + 1))
    done
    # Build the Paremeter table for the UI
    declare -a jackTableArry=(
      [0]=${jackParam[0]}
      [1]=jack.show-monitor
      [2]="Show the Monitor client and its ports."
      [3]=${jackParam[1]}
      [4]=jack.merge-monitor
      [5]="Exposes the capture ports and monitor ports on the same JACK device client."
      [6]=${jackParam[2]}
      [7]=jack.show-midi
      [8]="Show the MIDI clients and their ports."
      [9]=${jackParam[3]}
      [10]=jack.short-name
      [11]="Use shorter names for the device client name."
    )
    newParams=$(zenity --width=850 --height=350 \
      --title "Ubuntu Studio Audio Configuration" \
      --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
      --list \
      --checklist \
      --separator=" " \
      --text="Select which JACK plugin options you would like" \
      --ok-label="Next" \
      --cancel-label="Cancel" \
      --column=" " \
      --column="Parameter" \
      --column="Description" \
      "${jackTableArry[@]}"
    )
    exitCode=$?
    if [ "${exitCode}" = "1" ]; then
      return
    else
      read -a newJackParams <<< "${newParams}"
      p=0
      for param in "${jackConfig[@]}"; do
        for i in "${newJackParams[@]}"; do
          if [ "${i}" = "${jackConfig[p]}" ]; then
            jackParamWrite[p]=true; continue
          else
            if ! [ "${jackParamWrite[p]}" = "true" ]; then
              jackParamWrite[p]=false
            fi
          fi
        done
        p=$((p + 1))
      done
      scparam=$(grep "jack.self-connect-mode" $HOME/.config/pipewire/jack.conf.d/ubuntustudio.conf | cut -d "=" -f 2 | cut -c 2-)
      declare scParamArry=(
      [0]=allow
      [1]=fail-external
      [2]=ignore-external
      [3]=fail-all
      [4]=ignore-all
      )
      for sc in "${scParamArry[@]}"; do
        if [ "${sc}" = "${scparam}" ]; then
          declare "$sc"="TRUE"
        else
          declare "$sc"="FALSE"
        fi
      done
      declare -a scTableArry=(
      [0]=${allow}
      [1]=allow
      [2]="Don't restrict self connect requests (default)"
      [3]=${fail-external}
      [4]=fail-external
      [5]="Fail self connect requests to external ports only"
      [6]=${ignore-external}
      [7]=ignore-external
      [8]="Ignore self connect requests to external ports only"
      [9]=${fail-all}
      [10]=fail-all
      [11]="Fail all self connect requests"
      [12]=${ignore-all}
      [13]=ignore-all
      [14]="Ignore all self connect requests"
      )
      selfConnect=$(zenity --width=850 --height=350 \
      --title "Ubuntu Studio Audio Configuration" \
      --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
      --list \
      --radiolist \
      --separator=" " \
      --text="Select the self-connect mode. If you don't know what this is, leave it alone." \
      --ok-label="Apply" \
      --cancel-label="Cancel" \
      --column=" " \
      --column="Parameter" \
      --column="Description" \
      "${scTableArry[@]}"
      )
      exitCode=$?
      if [ "${exitCode}" = "1" ]; then return; fi
      jackCfg=$(cat << EOF
#THIS FILE IS AUTOMATICALLY GENERATED BY Ubuntu Studio Audio Configuration
jack.properties = {
    #rt.prio             = 88
    node.latency        = ${pwSetArry[0]}/${pwSetArry[1]}
    #node.lock-quantum   = true
    #node.force-quantum  = 0
    jack.show-monitor   = ${jackParamWrite[0]}
    jack.merge-monitor  = ${jackParamWrite[1]}
    jack.show-midi      = ${jackParamWrite[2]}
    jack.short-name     = ${jackParamWrite[3]}
    #jack.filter-name    = false
    #jack.filter-char    = " "
    #
    # allow:           Don't restrict self connect requests
    # fail-external:   Fail self connect requests to external ports only
    # ignore-external: Ignore self connect requests to external ports only
    # fail-all:        Fail all self connect requests
    # ignore-all:      Ignore all self connect requests
    #jack.self-connect-mode  = ${selfConnect}
    #jack.locked-process     = true
    #jack.default-as-system  = false
    #jack.fix-midi-events    = true
    jack.global-buffer-size = true
    #jack.passive-links      = false
    #jack.max-client-ports   = 768
    #jack.fill-aliases       = false
    #jack.writable-input     = false
    #jack.flag-midi2         = false
}
EOF
)
      echo "$jackCfg" > $HOME/.config/pipewire/jack.conf.d/ubuntustudio.conf
      systemctl --user restart pipewire
      pw-metadata -n settings 0 clock.force-quantum ${pwSetArry[0]}
      pw-metadata -n settings 0 clock.force-rate ${pwSetArry[1]}
      if [ "${dummyDead}" = "FALSE" ]; then
        systemctl --user restart ubuntustudio-dummy-audio.service
      fi
      zenity --title "Ubuntu Studio Audio Configuration" \
          --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
          --info \
          --text "PipeWire Quantum set to ${pwSetArry[0]} Buffer and ${pwSetArry[1]} Hz Sample Rate.\n
jack.show-monitor   = ${jackParamWrite[0]}
jack.merge-monitor  = ${jackParamWrite[1]}
jack.show-midi      = ${jackParamWrite[2]}
jack.short-name     = ${jackParamWrite[3]}
jack.self-connect-mode = ${selfConnect}"
    fi
}

if [ "$1" = "dummystart" ] || [ "$1" = "dummystop" ]; then
  case $1 in
    dummystart)
      pactl load-module module-null-sink media.class=Audio/Sink sink_name=Dummy channel_map=stereo
      pactl load-module module-virtual-source media.class=Audio/Source source_name=Dummy channel_map=stereo
    ;;
    dummystop)
      pactl unload-module module-null-sink
      pactl unload-module module-virtual-source
    ;;
  esac
  exit 0
fi

if [ "$1" = "startup" ]; then
  set -e
  if ! [ -f "$HOME/.config/pipewire/jack.conf.d/ubuntustudio.conf" ]; then
    . /etc/profile.d/ubuntustudio-pwjack.sh
    pwBuff=$(echo $PIPEWIRE_QUANTUM | cut -d "/" -f 1)
    pwFreq=$(echo $PIPEWIRE_QUANTUM | cut -d "/" -f 2)
    pw-metadata -n settings 0 clock.force-quantum ${pwBuff}
    pw-metadata -n settings 0 clock.force-rate ${pwFreq}
    writeFile=$(cat << EOF
#THIS FILE IS AUTOMATICALLY GENERATED BY Ubuntu Studio Audio Configuration
jack.properties = {
    #rt.prio             = 88
    node.latency        = $pwBuff/$pwFreq
    #node.lock-quantum   = true
    #node.force-quantum  = 0
    jack.show-monitor   = true
    jack.merge-monitor  = true
    jack.show-midi      = true
    jack.short-name     = true
    #jack.filter-name    = false
    #jack.filter-char    = " "
    #
    # allow:           Don't restrict self connect requests
    # fail-external:   Fail self connect requests to external ports only
    # ignore-external: Ignore self connect requests to external ports only
    # fail-all:        Fail all self connect requests
    # ignore-all:      Ignore all self connect requests
    #jack.self-connect-mode  = allow
    #jack.locked-process     = true
    #jack.default-as-system  = false
    #jack.fix-midi-events    = true
    jack.global-buffer-size = true
    #jack.passive-links      = false
    #jack.max-client-ports   = 768
    #jack.fill-aliases       = false
    #jack.writable-input     = false
    #jack.flag-midi2         = false
}
EOF
    )
    mkdir -p $HOME/.config/pipewire/jack.conf.d
    echo -e "$writeFile" > $HOME/.config/pipewire/jack.conf.d/ubuntustudio.conf
  else
    pwBuff=$(grep "node.latency" $HOME/.config/pipewire/jack.conf.d/ubuntustudio.conf | cut -f "=" | cut -d "/" -f 1)
    pwFreq=$(grep "node.latency" $HOME/.config/pipewire/jack.conf.d/ubuntustudio.conf | cut -f "=" | cut -d "/" -f 2)
    pw-metadata -n settings 0 clock.force-quantum ${pwBuff}
    pw-metadata -n settings 0 clock.force-rate ${pwFreq}
  fi
  exit 0
fi

if [ "$1" = "writeparams" ]; then
  echo "$2" > /etc/default/grub.d/ubuntustudio.cfg
  update-grub
  if [ -e /boot/refind_linux.conf ]; then
    if grep -qi 'lowlatency' /boot/refind_linux.conf; then
      _rootUuid=$(lsblk -no UUID "$(df -P / | awk 'END{print $1}')");
      _refindRead=$(grep 'lowlatency' /boot/refind_linux.conf);
      _refindWrite="\"Boot with lowlatency options\" \"root=UUID=${_rootUuid} ro quiet splash $3 $4 $5 $6 vt.handoff=1\"";
      echo -e "${_refindRead}\n${_refindWrite}"
      sed -i "/\\$_refindRead/c\\$_refindWrite" /boot/refind_linux.conf;
    fi
  fi
  exit 0
fi

if ! [ "$(id -nu)" = "ubuntu-studio" ]; then
  if ! [ -e /etc/security/limits.d/30-ubuntustudio-audio.conf ] || [ -z "$(groups | grep 'audio')" ]; then
    infotext="Your system and/or user configuration is not optimally configured for audio \
production. In order to fix this, a system restart will be required."
    zenity \
    --title "Ubuntu Studio Audio Configuration" \
    --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
    --info \
    --text="${infotext}"
   if pkexec /usr/sbin/ubuntustudio-installer-fix; then
       touch "${HOME}/.config/ubuntustudio-audio-firstrun"
       reboot
    else
      zenity --title "Ubuntu Studio Audio Configuration" \
      --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
      --error \
      --text="An error has occurred."
    fi
    exit 0
  else
    if ! [ -e "${HOME}/.config/ubuntustudio-audio-firstrun" ]; then
      touch "${HOME}/.config/ubuntustudio-audio-firstrun"
      exit 0
    fi
  fi
fi

while true; do

  if dpkg -s "ubuntustudio-pipewire-config" &> /dev/null; then
    pwConfig="TRUE"; paConfig="FALSE"; swConfig="(NOT Recommended)"
  elif dpkg -s "ubuntustudio-pulseaudio-config" &> /dev/null; then
    paConfig="TRUE"; pwConfig="FALSE"; swConfig="(Recommended)"
  else
    zenity \
    --title "Ubuntu Studio Audio Configuration" \
    --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
    --warning \
    --text="A default Ubuntu Studio audio configuration package could not be found.
  An audio configuration package will now be installed."
    qapt-batch --install ubuntustudio-pipewire-config
    zenity \
    --title "Ubuntu Studio Audio Configuration" \
    --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
    --info \
    --text="You must restart your computer for these changes to take effect."
    exit 0
  fi

  if [ -e /etc/ld.so.conf.d/pipewire-jack.conf ]; then
    pwJackStr="DISABLE PipeWire-JACK (to use JACKd2 with QJackCtl, for Advanced Users)"
  else
    pwJackStr="ENABLE PipeWire-JACK (Default Configuration)"
  fi

  # Get dummy device status
  dummyDead=$(systemctl --user status ubuntustudio-dummy-audio.service | grep active | grep dead)
  if [ "${dummyDead}" = "" ]; then
    dummyDead="FALSE"
  else
    dummyDead="TRUE"
  fi
  if [ "${dummyDead}" = "FALSE" ]; then
    dummyStr="STOP Dummy Audio Device"
  else
    dummyStr="START Dummy Audio Device"
  fi

  changeConfig=$(zenity --width=600 --height=450 \
      --title "Ubuntu Studio Audio Configuration" \
      --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
      --list \
      --radiolist \
      --separator="|" \
      --text="What would you like to do?" \
      --ok-label="Continue" \
      --cancel-label="Close" \
      --column="Select" \
      --column="Selection" \
      FALSE "Configure Current Audio Configuration" FALSE "Change Kernel Boot Parameters" FALSE "${dummyStr}" FALSE "${pwJackStr}" );
  strExit=$?
  if [ "${strExit}" = "1" ]; then
    exit 0;
  fi

  if [ "${changeConfig}" = "Configure Current Audio Configuration" ] && \
     [ "${paConfig}" = "TRUE" ]; then
    if ( zenity \
    --title "Ubuntu Studio Audio Configuration" \
    --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
    --question \
    --ok-label="Yes" \
    --cancel-label="No" \
    --text="For your current audio configuration (JACK/PulseAudio), please use Studio Controls.\n\
  Would you like to launch Studio Controls now?" ); then
      studio-controls;
      exit 0;
    fi
  fi

  if [ "${changeConfig}" = "Configure Current Audio Configuration" ] && \
     [ "${pwConfig}" = "TRUE" ]; then
    changeConfigFn
  fi

  if [ "${changeConfig}" = "Change Kernel Boot Parameters" ]; then
    # Parse current Boot Parameters
    bootParamsLine=$(grep 'GRUB_CMDLINE_LINUX_DEFAULT' /etc/default/grub.d/ubuntustudio.cfg)
    bootParamsLine=${bootParamsLine::-1}
    bootParamsLine=$(echo "${bootParamsLine}" | cut -c 57- )
    bootParamOne="FALSE"; bootParamTwo="FALSE"; bootParamThree="FALSE"; bootParamFour="FALSE"
    echo "${bootParamsLine}"
    declare -a j=(
    [1]=1
    [2]=2
    [3]=3
    [4]=4
    )
    for i in ${j[@]}; do
      parameter=$(echo ${bootParamsLine} | cut -d ' ' -f ${i} )
      echo "${parameter}"
      if [ "${parameter}" = "preempt=full" ]; then
        bootParamOne="TRUE"
      elif [ "${parameter}" = "threadirqs" ]; then
        bootParamTwo="TRUE"
      elif [ "${parameter}" = "rcu_nocbs=all" ]; then
        bootParamThree="TRUE"
      elif [ "${parameter}" = "nohz_full=all" ]; then
        bootParamFour="TRUE"
      fi
    done
    # Build the Parameter table for the UI
    declare -a paramTableArry=(
    [0]=${bootParamOne}
    [1]="preempt=full"
    [2]="Makes the kernel fully-preemptible, best for lowlatency workloads"
    [3]=${bootParamTwo}
    [4]="threadirqs"
    [5]="Forces interrupt handlers to run in a threaded context, reducing buffer xruns"
    [6]=${bootParamThree}
    [7]="rcu_nocbs=all"
    [8]="Offloads Read-Copy-Update (RCU) callbacks from all CPUs to dedicated kernel threads, improves real-time performance."
    [9]=${bootParamFour}
    [10]="nohz_full=all"
    [11]="Reduces noise in latency critical applications such as virtualization"
    )
    newBootParams=$(zenity --width=850 --height=350 \
      --title "Ubuntu Studio Audio Configuration" \
      --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
      --list \
      --checklist \
      --separator=" " \
      --text="Select which kernel boot parameters you would like. Default is first three." \
      --ok-label="Apply (Password Required)" \
      --cancel-label="Back" \
      --column=" " \
      --column="Parameter" \
      --column="Description" \
      "${paramTableArry[@]}"
    )
    exitCode=$?
    if [ "${exitCode}" = "1" ]; then
      true; #do nothing
    else
      grubCfg=$(cat << EOF
# Activate lowlatency effects of kernel
GRUB_CMDLINE_LINUX_DEFAULT="\$GRUB_CMDLINE_LINUX_DEFAULT ${newBootParams[@]}"
EOF
);
      if pkexec /usr/bin/ubuntustudio-audio-config writeparams "${grubCfg}" ${newBootParams[@]} | \
      zenity --progress --auto-close --no-cancel --pulsate; then
        zenity \
           --title "Ubuntu Studio Audio Configuration" \
           --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
           --info \
           --text="You must restart your computer for these changes to take effect."
      else
        zenity --title "Ubuntu Studio Audio Configuration" \
          --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
          --error \
          --text="An error has occurred or action was cancelled."
      fi
    fi
  fi

  if [ "${changeConfig}" = "${dummyStr}" ]; then
    if [ "${dummyDead}" = "TRUE" ]; then
      dummyInfoText="Sometimes, you may wish to enable a dummy audio device for your system \
audio or an audio application so that you don't inadvertently feed that to \
your main output or draw from your main input. This can be useful when you wish \
to send a music application to your your DAW or other mixer without sending to \
your main system output. There may be other workflow reasons as well.\n\n \
Do you wish to start a stereo dummy audio device?"
      if (zenity --width=400 --height=200 \
        --question \
        --title="Ubuntu Studio Audio Configuration" \
        --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
        --cancel-label="Go Back" \
        --text="${dummyInfoText}"); then
        systemctl --user start ubuntustudio-dummy-audio.service
        if (zenity --width=200 --height=100 \
          --question \
          --title="Ubuntu Studio Audio Configuration" \
          --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
          --ok-label="Yes" \
          --cancel-label="No" \
          --text="Would you like the dummy audio device to start at login?"); then
          systemctl --user enable ubuntustudio-dummy-audio.service || true
        else
          systemctl --user disable ubuntustudio-dummy-audio.service || true
        fi
      fi
    else
      if (zenity --width=200 --height=100 \
        --question \
        --title="Ubuntu Studio Audio Configuration" \
        --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
        --ok-label="Yes" \
        --cancel-label="No" \
        --text="Would you like to stop the dummy audio device?"); then
        systemctl --user stop ubuntustudio-dummy-audio.service
        if (zenity --width=200 --height=100 \
          --question \
          --title="Ubuntu Studio Audio Configuration" \
          --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
          --ok-label="Yes" \
          --cancel-label="No" \
          --text="Would you like the dummy audio device to start at login?"); then
          systemctl --user enable ubuntustudio-dummy-audio.service || true
        else
          systemctl --user disable ubuntustudio-dummy-audio.service || true
        fi
      fi
    fi
  fi

  if [ "${changeConfig}" = "${pwJackStr}" ]; then
    if [ -e /etc/ld.so.conf.d/pipewire-jack.conf ]; then
      if pkexec ubuntustudio-pwjack-config disable; then true; else
        zenity --title "Ubuntu Studio Audio Configuration" \
          --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
          --error \
          --text="An error has occurred."
      fi
    else
      if pkexec ubuntustudio-pwjack-config enable; then true; else
        zenity --title "Ubuntu Studio Audio Configuration" \
          --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-audio-config.svg \
          --error \
          --text="An error has occurred."
      fi
    fi
  fi

done
