add muxa-vr
This commit is contained in:
parent
c8d97515dc
commit
0a19796698
331
bin/muxsa-vr
Executable file
331
bin/muxsa-vr
Executable file
@ -0,0 +1,331 @@
|
||||
#!/bin/bash
|
||||
|
||||
# muxsa-vr (voice recorder)
|
||||
#
|
||||
# part of muxsa, https://git-nks-public.tik.uni-stuttgart.de/edu/muxsa
|
||||
#
|
||||
# this script waits for keystrokes, in particular the typical key sequences
|
||||
# of a "wireless presenter" device, and controls audacity and geeqie, for
|
||||
# convenient recording of voiceover for presentation slides.
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2023 Sebastian Kiesel <sebastian.kiesel@tik.uni-stuttgart.de>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||
# copy of this software and associated documentation files (the "Software"),
|
||||
# to deal in the Software without restriction, including without limitation
|
||||
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
# and/or sell copies of the Software, and to permit persons to whom the
|
||||
# Software is furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
############################################################################
|
||||
|
||||
echo "This is muxsa-vr."
|
||||
|
||||
show_help () {
|
||||
cat <<EOF
|
||||
############################################################################
|
||||
|
||||
This is muxsa-vr. Enter one of the following keys.
|
||||
|
||||
NORMAL COMMANDS
|
||||
|
||||
i
|
||||
initialize muxsa-vr and audacity (normally do it once after start)
|
||||
|
||||
PgDown (big right key on wireless presenter)
|
||||
start or stop recording, respectively
|
||||
|
||||
PgUp (big left key on wireless presenter)
|
||||
play clip that has been recorded most recently
|
||||
|
||||
. (dot, small right key on wireless presenter)
|
||||
add a numbered label at current position
|
||||
|
||||
F5/ESC (small left key on wireless presenter)
|
||||
delete most recent clip or label
|
||||
|
||||
|
||||
SPECIAL-PURPOSE / RECOVERY COMMANDS
|
||||
s = set state to STOP
|
||||
l = manually enter current label number
|
||||
c = manually enter current clip number
|
||||
u = send undo to Audacity
|
||||
r = send redo to Audacity
|
||||
b = send back to Geeqie
|
||||
n = send next to Geeqie
|
||||
|
||||
############################################################################
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
############################################################################
|
||||
# interaction with audacity
|
||||
# https://manual.audacityteam.org/man/scripting_reference.html
|
||||
|
||||
AUDACITY_PIPE_FROM="/tmp/audacity_script_pipe.from.$(id -u)"
|
||||
AUDACITY_PIPE_TO="/tmp/audacity_script_pipe.to.$(id -u)"
|
||||
|
||||
send_to_audacity () {
|
||||
if [ -p "${AUDACITY_PIPE_TO}" ] ; then
|
||||
echo "muxsa-vr: send_to_audacity: $1"
|
||||
echo "$1" > "${AUDACITY_PIPE_TO}"
|
||||
else
|
||||
echo "muxsa-vr: send_to_audacity: pipe ${AUDACITY_PIPE_TO}"\
|
||||
"does not exist. not sending: $1"
|
||||
fi
|
||||
}
|
||||
|
||||
receive_from_audacity () {
|
||||
while true ; do
|
||||
if [ -p "${AUDACITY_PIPE_FROM}" ] ; then
|
||||
timeout 10 sed 's/^/muxsa-vr: receive_from_audacity: /' \
|
||||
${AUDACITY_PIPE_FROM}
|
||||
else
|
||||
echo "muxsa-vr: receive_from_audacity:"\
|
||||
"pipe ${AUDACITY_PIPE_FROM} does not exist."\
|
||||
"wait for one second"
|
||||
sleep 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
receive_from_audacity &
|
||||
RECEIVE_FROM_AUDACITY_PID=$!
|
||||
echo "muxsa-vr: receive_from_audacity subprocess started"\
|
||||
"with PID: ${RECEIVE_FROM_AUDACITY_PID}"
|
||||
trap 'kill "${RECEIVE_FROM_AUDACITY_PID}"' EXIT
|
||||
|
||||
|
||||
#####
|
||||
|
||||
# LABEL is assumed to be a global variable holding an integer value
|
||||
set_label_text_audacity () {
|
||||
local L="${LABEL:-"0"}"
|
||||
local T="$(printf "%04d" ${LABEL:-"0"})"
|
||||
send_to_audacity "SetLabel: Label=${L} Selected=0 Text=\"${T}\""
|
||||
}
|
||||
|
||||
############################################################################
|
||||
# interation with geeqie
|
||||
|
||||
send_to_geeqie () {
|
||||
echo "muxsa-vr: send_to_geeqie: $1"
|
||||
case "$1" in
|
||||
back)
|
||||
geeqie --remote --back
|
||||
;;
|
||||
next)
|
||||
geeqie --remote --next
|
||||
;;
|
||||
*)
|
||||
echo "muxsa-vr: send_to_geeqie: ignore unknown command $1"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
############################################################################
|
||||
# main
|
||||
|
||||
STATE="uninitialized"
|
||||
LABEL=0
|
||||
CLIPS[0]=0
|
||||
echo "muxsa-vr started. press i to initialize or h for help."
|
||||
|
||||
while true ; do
|
||||
|
||||
echo "State: ${STATE} Label: ${LABEL} Clips: ${CLIPS[$LABEL]:=0}"
|
||||
|
||||
##### read one key stroke, including some special keys
|
||||
read -s -n1 -p "Press key (h for help): " KEYCODE
|
||||
while read -t0.001 -s -n1 MORE ; do
|
||||
KEYCODE="${KEYCODE}${MORE}"
|
||||
done
|
||||
case "${KEYCODE}" in
|
||||
$'\e[6~')
|
||||
KEYCODE="PGDOWN"
|
||||
;;
|
||||
$'\e[5~')
|
||||
KEYCODE="PGUP"
|
||||
;;
|
||||
$'\e[15~')
|
||||
KEYCODE="F5"
|
||||
;;
|
||||
$'\e')
|
||||
KEYCODE="ESC"
|
||||
;;
|
||||
esac
|
||||
#####
|
||||
echo "muxsa-vr: key pressed: ${KEYCODE}"
|
||||
|
||||
case "${KEYCODE}" in
|
||||
'h')
|
||||
show_help
|
||||
;;
|
||||
'i')
|
||||
echo "Initializing muxsa-vr and Audacity."
|
||||
STATE="STOP"
|
||||
LABEL=0
|
||||
CLIPS[0]=0
|
||||
send_to_audacity 'NewMonoTrack'
|
||||
send_to_audacity 'NewLabelTrack'
|
||||
send_to_audacity 'AddLabel'
|
||||
set_label_text_audacity
|
||||
send_to_audacity 'SelAllTracks'
|
||||
;;
|
||||
|
||||
'PGDOWN')
|
||||
# pgdown = right big button on the wireless presenter
|
||||
case "${STATE}" in
|
||||
'STOP')
|
||||
send_to_audacity 'CursTrackEnd'
|
||||
send_to_audacity 'Record1stChoice'
|
||||
echo "START RECORDING"
|
||||
STATE="RECORDING"
|
||||
;;
|
||||
'RECORDING')
|
||||
send_to_audacity 'Stop'
|
||||
send_to_audacity 'CursTrackEnd'
|
||||
echo "STOP RECORDING"
|
||||
STATE="STOP"
|
||||
CLIPS[$LABEL]=$(( ${CLIPS[$LABEL]} + 1 ))
|
||||
;;
|
||||
*)
|
||||
echo "start/stop: invalid state ${STATE} ... ignore"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
||||
'PGUP')
|
||||
# pgup = left big button on the wireless presenter
|
||||
case "${STATE}" in
|
||||
'STOP')
|
||||
echo "Playback last clip"
|
||||
send_to_audacity 'CursTrackEnd'
|
||||
send_to_audacity 'CursPrevClipBoundary'
|
||||
send_to_audacity 'Play'
|
||||
send_to_audacity 'CursTrackEnd'
|
||||
;;
|
||||
*)
|
||||
echo "playback: invalid state ${STATE} ... ignore"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
||||
$'.')
|
||||
# dot = right small button on the wireless presenter
|
||||
case "${STATE}" in
|
||||
'STOP')
|
||||
if [ "${CLIPS[$LABEL]}" -eq 0 ] ; then
|
||||
echo "Add label: not adding a second label here"
|
||||
else
|
||||
echo "Adding label at end while paused"
|
||||
send_to_audacity 'CursTrackEnd'
|
||||
send_to_audacity 'AddLabel'
|
||||
LABEL=$(( ${LABEL} + 1 ))
|
||||
CLIPS[$LABEL]=0
|
||||
set_label_text_audacity
|
||||
send_to_geeqie 'next'
|
||||
fi
|
||||
;;
|
||||
'RECORDING')
|
||||
send_to_audacity 'AddLabelPlaying'
|
||||
echo "Adding label while recording"
|
||||
LABEL=$(( ${LABEL} + 1 ))
|
||||
CLIPS[$LABEL]=0
|
||||
send_to_geeqie 'next'
|
||||
;;
|
||||
*)
|
||||
echo "add label: invalid state ${STATE} ... ignore"
|
||||
;;
|
||||
esac
|
||||
|
||||
;;
|
||||
|
||||
'F5'|'ESC')
|
||||
# F5/Esc(alternating) = left small button on the wireless presenter
|
||||
case "${STATE}" in
|
||||
'STOP')
|
||||
case "${CLIPS[$LABEL]}" in
|
||||
'0')
|
||||
if [ "${LABEL}" -eq 0 ] ; then
|
||||
echo "Delete: Nothing recorded ... ignore."
|
||||
else
|
||||
echo "Nothing recorded since last label."
|
||||
echo "Deleting last label."
|
||||
send_to_audacity 'CursTrackEnd'
|
||||
send_to_audacity 'Delete'
|
||||
send_to_geeqie 'back'
|
||||
LABEL=$(( ${LABEL} - 1 ))
|
||||
fi
|
||||
;;
|
||||
'1')
|
||||
echo "Deleting first clip after label."
|
||||
send_to_audacity 'CursTrackEnd'
|
||||
send_to_audacity 'SelPrevClipBoundaryToCursor'
|
||||
send_to_audacity 'Delete'
|
||||
echo "Re-install deleted label"
|
||||
send_to_audacity 'AddLabel'
|
||||
set_label_text_audacity
|
||||
CLIPS[$LABEL]=0
|
||||
;;
|
||||
*)
|
||||
echo "Deleting second or later clip after label."
|
||||
send_to_audacity 'CursTrackEnd'
|
||||
send_to_audacity 'SelPrevClipBoundaryToCursor'
|
||||
send_to_audacity 'Delete'
|
||||
CLIPS[$LABEL]=$(( ${CLIPS[$LABEL]} - 1 ))
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
echo "Delete: invalid state ${STATE} ... ignore"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
||||
|
||||
's')
|
||||
echo "Setting STATE to STOP"
|
||||
STATE="STOP"
|
||||
;;
|
||||
'l')
|
||||
read -p "Enter current label number: " LABEL
|
||||
[ "${LABEL}" -gt 0 ] &>/dev/null || LABEL=0
|
||||
;;
|
||||
'c')
|
||||
read -p "Enter current clip number: " CLIPS[$LABEL]
|
||||
[ "${CLIPS[$LABEL]}" -gt 0 ] &>/dev/null || CLIPS[$LABEL]=0
|
||||
;;
|
||||
'u')
|
||||
send_to_audacity 'Undo'
|
||||
;;
|
||||
'r')
|
||||
send_to_audacity 'Redo'
|
||||
;;
|
||||
'b')
|
||||
send_to_geeqie 'back'
|
||||
;;
|
||||
'n')
|
||||
send_to_geeqie 'next'
|
||||
;;
|
||||
*)
|
||||
echo "unknown key pressed: ${KEYCODE}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# End of muxsa-vr
|
||||
############################################################################
|
Loading…
Reference in New Issue
Block a user