pamidi/pa_xtouch_control.sh

373 lines
12 KiB
Bash
Raw Normal View History

2021-10-24 17:33:03 -07:00
#!/bin/bash
#
# Assumes a stock PopOS installation with xdotool
#
# X-Touch Mini Mappings (Mackie Mode)
# =====================
# Col#, Knob press, knob turn, top button, bottom button
# 1, 32, 16, 89, 87
# 2, 33, 17, 90, 88
# 3, 34, 18, 40, 91
# 4, 35, 19, 41, 92
# 5, 36, 20, 42, 86
# 6, 37, 21, 43, 93
# 7, 38, 22, 44, 94
# 8, 39, 23, 45, 95
#
# Fader = 8
# ---------------------
# Misc. Info
# Knobs and buttons are all channel 0
# Fader is channel 8
# Button presses (including knobs) are notes at velocity 127
# Knob turns counter-clockwise are a value of 64 + n,
# where n is a small number reflecting the amount it was turned within the last polling period
# Knob turns clockwise are a value of 0 + n,
# where n is a small number reflecting the amount it was turned within the last polling period
# Default column apps
# When you (re)start the script, it looks for the pids of the binaries specified for each column and sets the pid for each column
# These are overridden for the session by the bind_application function
initialize(){
echo "Initializing"
echo "Checking for xdotool"
if ! hash xdotool &> /dev/null; then
echo "xdotool could not be found, exiting"
2021-10-24 19:51:46 -07:00
exit 2
2021-10-24 17:33:03 -07:00
else
echo "xdotool found"
fi
col_1_app_pid=-1
col_2_app_pid=-1
col_3_app_pid=-1
col_4_app_pid=-1
col_5_app_pid=-1
col_6_app_pid=-1
col_7_app_pid=-1
col_8_app_pid=-1
assign_profile_1
print_col_app_ids
}
assign_profile_1() {
echo "Setting profile 1"
}
assign_profile_2() {
echo "Setting profile 2"
}
print_col_app_ids() {
echo "Col 1: $col_1_app_pid"
echo "Col 2: $col_2_app_pid"
echo "Col 3: $col_3_app_pid"
echo "Col 4: $col_4_app_pid"
echo "Col 5: $col_5_app_pid"
echo "Col 6: $col_6_app_pid"
echo "Col 7: $col_7_app_pid"
echo "Col 8: $col_8_app_pid"
}
change_volume_mackie() {
# take the pid of an app
# set the volume of all streams for that app
# get the volume change amount
if (( $2 >= 64 )); then
vol_change="-$(expr $2 - 64)"
else
vol_change="+$2"
fi
# take the pid and change the volume for each of its streams
app_pid=$1
all_sink_inputs="$(pacmd list-sink-inputs)"
all_sink_inputs="$(paste \
<(printf '%s' "$all_sink_inputs" | grep 'application.process.id' | cut -d'"' -f 2) \
<(printf '%s' "$all_sink_inputs" | grep 'index: ' | rev | cut -d' ' -f 1 | rev))"
echo "$all_sink_inputs" | while read line ; do
pid=$(echo "$line" | cut -f1)
if [[ "$pid" == "$1" ]]; then
stream_id="$(echo "$line" | cut -f2)"
pactl set-sink-input-volume $stream_id $vol_change% 2> /dev/null
fi
done
}
change_volume_standard() {
# take the pid of an app
# set the volume of all streams for that app
# get the new volume value
new_vol=$2
# take the pid and change the volume for each of its streams
app_pid=$1
all_sink_inputs="$(pacmd list-sink-inputs)"
all_sink_inputs="$(paste \
<(printf '%s' "$all_sink_inputs" | grep 'application.process.id' | cut -d'"' -f 2) \
<(printf '%s' "$all_sink_inputs" | grep 'index: ' | rev | cut -d' ' -f 1 | rev))"
echo "$all_sink_inputs" | while read line ; do
pid=$(echo "$line" | cut -f1)
if [[ "$pid" == "$1" ]]; then
stream_id="$(echo "$line" | cut -f2)"
pactl set-sink-input-volume $stream_id $new_vol% 2> /dev/null
fi
done
}
toggle_mute() {
# take the pid of an app
# toggle mute all streams for that app
app_pid=$1
all_sink_inputs="$(pacmd list-sink-inputs)"
all_sink_inputs="$(paste \
<(printf '%s' "$all_sink_inputs" | grep 'application.process.id' | cut -d'"' -f 2) \
<(printf '%s' "$all_sink_inputs" | grep 'index: ' | rev | cut -d' ' -f 1 | rev))"
echo "$all_sink_inputs" | while read line ; do
pid=$(echo "$line" | cut -f1)
if [[ "$pid" == "$1" ]]; then
stream_id="$(echo "$line" | cut -f2)"
pactl set-sink-input-mute $stream_id toggle
fi
done
}
mute_on() {
# take the pid of an app
# mute all streams for that app
app_pid=$1
all_sink_inputs="$(pacmd list-sink-inputs)"
all_sink_inputs="$(paste \
<(printf '%s' "$all_sink_inputs" | grep 'application.process.id' | cut -d'"' -f 2) \
<(printf '%s' "$all_sink_inputs" | grep 'index: ' | rev | cut -d' ' -f 1 | rev))"
echo "$all_sink_inputs" | while read line ; do
pid=$(echo "$line" | cut -f1)
if [[ "$pid" == "$1" ]]; then
stream_id="$(echo "$line" | cut -f2)"
pactl set-sink-input-mute $stream_id on
fi
done
}
mute_off() {
# take the pid of an app
# unmute all streams for that app
app_pid=$1
all_sink_inputs="$(pacmd list-sink-inputs)"
all_sink_inputs="$(paste \
<(printf '%s' "$all_sink_inputs" | grep 'application.process.id' | cut -d'"' -f 2) \
<(printf '%s' "$all_sink_inputs" | grep 'index: ' | rev | cut -d' ' -f 1 | rev))"
echo "$all_sink_inputs" | while read line ; do
pid=$(echo "$line" | cut -f1)
if [[ "$pid" == "$1" ]]; then
stream_id="$(echo "$line" | cut -f2)"
pactl set-sink-input-mute $stream_id off
fi
done
}
get_stream_index_from_pid(){
all_sink_inputs="$(pacmd list-sink-inputs)"
all_sink_inputs="$(paste \
<(printf '%s' "$all_sink_inputs" | grep 'application.process.id' | cut -d'"' -f 2) \
<(printf '%s' "$all_sink_inputs" | grep 'index: ' | rev | cut -d' ' -f 1 | rev))"
stream_ids=""
echo "$all_sink_inputs" | while read line ; do
pid=$(echo "$line" | cut -f1)
if [[ "$pid" == "$1" ]]; then
echo "$line" | cut -f2
fi
done
}
get_binary_from_pid(){
output="$(paste -d"\t" \
<(printf '%s' "$output" | grep 'application.process.id' | cut -d'"' -f 2) \
<(printf '%s' "$output" | grep 'application.process.binary' | cut -d'"' -f 2))"
echo "$output" | while read line ; do
pid=$(echo "$line" | cut -f1)
if [[ "$pid" == "$1" ]]; then
echo "$line" | cut -f2
fi
done
2021-10-24 17:33:03 -07:00
}
bind_application() {
window_pid="$(xdotool getactivewindow getwindowpid)"
window_name="$(xdotool getactivewindow getwindowname)"
col_id=$1
#echo "window_pid=$window_pid"
#echo "window_name=$window_name"
#echo "col_id=$col_id"
case "$col_id" in
"1" ) col_1_app_pid=$window_pid && notify-send "Set knob $col_id to $window_name" ;;
"2" ) col_2_app_pid=$window_pid && notify-send "Set knob $col_id to $window_name" ;;
"3" ) col_3_app_pid=$window_pid && notify-send "Set knob $col_id to $window_name" ;;
"4" ) col_4_app_pid=$window_pid && notify-send "Set knob $col_id to $window_name" ;;
"5" ) col_5_app_pid=$window_pid && notify-send "Set knob $col_id to $window_name" ;;
"6" ) col_6_app_pid=$window_pid && notify-send "Set knob $col_id to $window_name" ;;
"7" ) col_7_app_pid=$window_pid && notify-send "Set knob $col_id to $window_name" ;;
"8" ) col_8_app_pid=$window_pid && notify-send "Set knob $col_id to $window_name" ;;
esac
}
media_play_pause() {
xdotool key XF86AudioPlay
}
media_prev() {
xdotool key XF86AudioPrev
}
media_next() {
xdotool key XF86AudioNext
}
media_stop() {
xdotool key XF86AudioStop
}
main_mackie(){
aseqdump -p "X-TOUCH MINI" | \
while IFS=" ," read src ev1 ev2 ch label1 data1 label2 data2 rest; do
#echo "$ev1 $ev2 $data1 $data2"
case "$ev1 $ev2 $data1 $data2" in
# column 1
"Note on 32"* ) bind_application 1 ;; # knob press
"Note on 89"* ) toggle_mute $col_1_app_pid ;; # top button
"Note on 87"* ) print_col_app_ids ;; # bottom button
"Control change 16"* ) change_volume $col_1_app_pid $data2 ;; # knob turn
# column 2
"Note on 33"* ) bind_application 2 ;; # knob press
"Note on 90"* ) toggle_mute $col_2_app_pid ;; # top button
"Note on 88"* ) ;; # bottom button
"Control change 17"* ) change_volume $col_2_app_pid $data2 ;; # knob turn
# column 3
"Note on 34"* ) bind_application 3 ;; # knob press
"Note on 40"* ) toggle_mute $col_3_app_pid ;; # top button
"Note on 91"* ) media_prev ;;
"Control change 18"* ) change_volume $col_3_app_pid $data2 ;; # knob turn
# column 4
"Note on 35"* ) bind_application 4 ;; # knob press
"Note on 41"* ) toggle_mute $col_4_app_pid ;; # top button
"Note on 92"* ) media_next ;;
"Control change 19"* ) change_volume $col_4_app_pid $data2 ;; # knob turn
# column 5
"Note on 36"* ) bind_application 5 ;; # knob press
"Note on 42"* ) toggle_mute $col_5_app_pid ;; # top button
"Note on 86"* ) ;;
"Control change 20"* ) change_volume $col_5_app_pid $data2 ;; # knob turn
# column 6
"Note on 37"* ) bind_application 6 ;; # knob press
"Note on 43"* ) toggle_mute $col_6_app_pid ;; # top button
"Note on 93"* ) media_stop ;;
"Control change 21"* ) change_volume $col_6_app_pid $data2 ;; # knob turn
# column 7
"Note on 38"* ) bind_application 7 ;; # knob press
"Note on 44"* ) toggle_mute $col_7_app_pid ;; # top button
"Note on 94"* ) media_play_pause ;;
"Control change 22"* ) change_volume $col_7_app_pid $data2 ;; # knob turn
# column 8
"Note on 39"* ) bind_application 8 ;; # knob press
"Note on 45"* ) toggle_mute $col_8_app_pid ;; # top button
"Note on 95"* ) ;;
"Control change 23"* ) change_volume $col_8_app_pid $data2 ;; # knob turn
# layer a and b buttons
"Note on 84"* ) assign_profile_1 ;;
"Note on 85"* ) assign_profile_2 ;;
esac
done
}
main_standard(){
aseqdump -p "X-TOUCH MINI" | \
while IFS=" ," read src ev1 ev2 ch label1 data1 label2 data2 rest; do
#echo "$ev1 $ev2 $data1 $data2"
case "$ev1 $ev2 $data1 $data2" in
# column 1
"Control change 9 127" ) bind_application 1 ;; # knob press
"Control change 17 127" ) mute_on $col_1_app_pid ;; # top button on
"Control change 17 0" ) mute_off $col_1_app_pid ;; # top button off
"Control change 25 127" ) print_col_app_ids ;; # bottom button
"Control change 1 "* ) change_volume_standard $col_1_app_pid $data2 ;; # knob turn
# column 2
"Control change 10 127" ) bind_application 2 && echo "bind_application 2";; # knob press
"Control change 18 127" ) mute_on $col_2_app_pid;; # top button on
"Control change 18 0" ) mute_off $col_2_app_pid ;; # top button off
"Control change 26 127" ) ;; # bottom button
"Control change 2 "* ) change_volume_standard $col_2_app_pid $data2 ;; # knob turn
# column 3
"Control change 11 127" ) bind_application 3 ;; # knob press
"Control change 19 127" ) mute_on $col_3_app_pid ;; # top button on
"Control change 19 0" ) mute_off $col_3_app_pid ;; # top button off
"Control change 27 127" ) media_prev ;;
"Control change 3 "* ) change_volume_standard $col_3_app_pid $data2 ;; # knob turn
# column 4
"Control change 12 127" ) bind_application 4 ;; # knob press
"Control change 20 127" ) mute_on $col_4_app_pid ;; # top button on
"Control change 20 0" ) mute_off $col_4_app_pid ;; # top button off
"Control change 28 127" ) media_next ;;
"Control change 4 "* ) change_volume_standard $col_4_app_pid $data2 ;; # knob turn
# column 5
"Control change 13 127" ) bind_application 5 ;; # knob press
"Control change 21 127" ) mute_on $col_5_app_pid ;; # top button on
"Control change 21 0" ) mute_off $col_5_app_pid ;; # top button off
"Control change 29 127" ) ;;
"Control change 5 "* ) change_volume_standard $col_5_app_pid $data2 ;; # knob turn
# column 6
"Control change 14 127" ) bind_application 6 ;; # knob press
"Control change 22 127" ) mute_on $col_6_app_pid ;; # top button on
"Control change 22 0" ) mute_off $col_6_app_pid ;; # top button off
"Control change 30 127" ) media_stop ;;
"Control change 6 "* ) change_volume_standard $col_6_app_pid $data2 ;; # knob turn
# column 7
"Control change 15 127" ) bind_application 7 ;; # knob press
"Control change 23 127" ) mute_on $col_7_app_pid ;; # top button on
"Control change 23 0" ) mute_off $col_7_app_pid ;; # top button off
"Control change 31 127" ) media_play_pause ;;
"Control change 7 "* ) change_volume_standard $col_7_app_pid $data2 ;; # knob turn
# column 8
"Control change 16 127" ) bind_application 8 ;; # knob press
"Control change 24 127" ) mute_on $col_8_app_pid ;; # top button on
"Control change 24 0" ) mute_off $col_8_app_pid ;; # top button off
"Control change 32 127" ) ;;
"Control change 8 "* ) change_volume_standard $col_8_app_pid $data2 ;; # knob turn
esac
done
}
initialize
main_standard