#!/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 # # 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 < "${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 add_label_with_text_to_audacity () { local L="${LABEL:-"0"}" local T="$(printf "%04d" ${LABEL:-"0"})" # first observed with audacity 3.2.4 on Debian bookworm # audacity steals the input focus when labels are added / changed FOCUSEDWINID=$(xdotool getwindowfocus) send_to_audacity 'AddLabel' send_to_audacity "SetLabel: Label=${L} Selected=0 Text=\"${T}\"" sleep 0.3 echo "Trying to get the focus back to ${FOCUSEDWINID}" xdotool windowfocus "${FOCUSEDWINID}" } ############################################################################ # 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' add_label_with_text_to_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' LABEL=$(( ${LABEL} + 1 )) CLIPS[$LABEL]=0 add_label_with_text_to_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" add_label_with_text_to_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 ############################################################################