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