#!/usr/bin/env bash

# vrecord
# Open-source software for capturing a video signal and turning it into a digital file.

VERSION="2025-09-04"
SCRIPTNAME="$(basename "${0}")"
SCRIPTDIR="$(dirname "${0}")"
CONFIG_FILE="${HOME}/.${SCRIPTNAME}.conf"
SAT_OUTLIER_THRSHLD=14
AUD_OUTLIER_THRSHLD=10
BRNG_OUTLIER_THRSHLD=14

_usage(){
    cat <<EOF
${SCRIPTNAME} ${VERSION}

${SCRIPTNAME} will record a file via ffmpeg and the the Blackmagic SDK or
AVFoundation. It is an interactive script and will create 10 or 8-bit video
files.

Dependencies: cowsay, amiaopensource/amiaos/decklinksdk,
  amiaopensource/amiaos/gtkdialog, mediaarea/mediaarea/ffmpeg-ma, and
  xmlstarlet
Optional Dependencies: deckcontrol, gnuplot, mediaconch, mkvtoolnix, mpv, qcli

Usage: ${SCRIPTNAME} [ -e | -r | -p | -a | -x | -n|  -v | -s | -h ] [IDENTIFIER]

  IDENTIFIER will be used for the filenaming of the output files. It is only
  required in record mode.

  -e  edit the configuration file before recording
  -r  enable record mode [default]
  -p  enable passthrough mode where the video signal coming into the computer
      can be monitored, but not written to a file. Useful for testing equipment
      and setting up a tape to bars.
  -a  enable audio passthrough mode. Identical to passthrough except for the
      addition of audio bars. Note: Will eventually lag and crash if left on
      too long.
  -x  reset the configuration: this will replace the default configuration file
      at '${CONFIG_FILE}' with an empty one.
  -n  reset Vrecord's stored environment variables. These include
      variables such as the paths to certain dependencies such as ffmpeg-ma.
  -v  Run ffmpeg with '-loglevel debug'. Using this option creates a very large
      log file, so avoid using this option with 'Visual + Numerical' or any
      playback option that display the log as part of the view.
  -s  Generate a test signal and use it in place of external input
  -h  display this help menu

Advanced options
  -I  Provide a string of input options for the recording ffmpeg to use.
      For example "vrecord -I '-loglevel trace'" would force an ffmpeg logging
      level that is usually unaccessible via vrecord preferences.
  -O  Provide a string of output options for the recording ffmpeg to use.
  -i  Provide a file as an input to vrecord, rather than using the decklink
      device. For testing without a decklink device.
  -G  Share warnings from gtkdialog and vrecord, otherwise there are suppressed
      by default.
  -D  Provide a path to a directory containing dependencies to override
      Vrecord's default dependency paths. These new paths will be stored in
      Vrecord's environmental variables.
  -c  Provide a recording configuration file, rather than the default one at
      '${CONFIG_FILE}'.

See also the man page: man ${SCRIPTNAME}
EOF
}

# local functions
_get_iso8601(){
    date +%FT%T
}

_report(){
    local RED="$(tput setaf 1)"    # Red      - For Warnings
    local BG_RED="$(tput setab 1)"    # Background Red      - For STRONG Warnings
    local GREEN="$(tput setaf 2)"  # Green    - For Declarations
    local BLUE="$(tput setaf 4)"   # Blue     - For Questions
    local NC="$(tput sgr0)"        # No Color
    local COLOR=""
    local STARTMESSAGE=""
    local ECHOOPT=""
    OPTIND=1
    while getopts "qdwxstn" opt ; do
        case "${opt}" in
            q) COLOR="${BLUE}" ;;                        # question mode, use color blue
            d) COLOR="${GREEN}" ;;                       # declaration mode, use color green
            w) COLOR="${RED}" ;;                         # warning mode, use color red
            x) COLOR="${BG_RED}" ;;                      # strong warning mode x_x, red background
            s) STARTMESSAGE+=([${SCRIPTNAME}] ) ;;       # prepend scriptname to the message
            t) STARTMESSAGE+=($(_get_iso8601) '- ' ) ;;  # prepend timestamp to the message
            n) ECHOOPT="-n" ;;                           # to avoid line breaks after echo
        esac
    done
    shift "$((OPTIND-1))"
    MESSAGE="${1}"
    echo ${ECHOOPT} "${COLOR}${STARTMESSAGE[@]}${MESSAGE}${NC}"
}

_report_unexpected_error(){
    ERROR_VAR_NAME="${1}"
    ERROR_VAR_VALUE="${!1}"
    shift
    ERROR_DETAIL=("${@}")
    _report -d -wt "vrecord exited a form in an unexpected way (${ERROR_VAR_NAME}=${ERROR_VAR_VALUE}), please report this error to https://github.com/amiaopensource/vrecord/issues"
    if [[ -n "${ERROR_DETAIL[@]}" ]] ; then
        _report -d -wt "Error details: ${ERROR_DETAIL[@]}"
    fi
    if [[ -f "${INGESTLOG}" ]] ; then
        _writeingestlog "vrecord command Error" "invalid ${ERROR_VAR_NAME} value of ${ERROR_VAR_VALUE}"
    fi
    exit 1
}

_parse_report(){
    KEY="${1}"
    REPORT="${2}"
    echo "${REPORT}" | grep -i "^[ ]*${KEY}:" | cut -d : -f 2- | awk '{$1=$1;print}'
}

_maketemp(){
    if [[ "${1}" ]] ; then
        EXT="${1}"
    else
        EXT=""
    fi
    echo "$(mktemp -q "/tmp/$(basename "${0}").XXXXXX")${EXT}"
}

_process_vars_for_gtk(){
    _include_var(){
        while [[ "${@}" != "" ]] ; do
            VAR_NAME="${1}"
            VAR_VALUE="${!1}"
            shift
            echo "${VAR_NAME}=\"${VAR_VALUE}\"" >> "${VRECORD_VARS_FILE}"
        done
    }
    if [[ -f "${VRECORD_VARS_FILE}" ]] ; then
        . "${VRECORD_VARS_FILE}"
    else
        _include_var VRECORD_VARS_FILE
    fi

    if [[ -z "${OS_TYPE}" ]] ; then
        _setup_env_variables
        _include_var OS_TYPE RESOURCE_PATH DEFAULTFONT CORE_COUNT OPEN_COMMAND ZCAT_COMMAND COMPUTER_MODEL_NAME DIR_SELECTION_DIALOG GTKDIALOGBIN
        if [[ "${OS_TYPE}" = "macOS" ]] ; then
            _include_var COMPUTER_MODEL_ID COMPUTER_PROCESSOR_NAME COMPUTER_PROCESSOR_SPEED COMPUTER_PROCESSOR_COUNT COMPUTER_MEMORY COMPUTER_SERIAL
        fi
    fi

    if [[ -z "${FFMPEG_BIN}" ]] ; then
        _gather_ffmpeg_vars
        _include_var CAPTURELOGSUFFIX TIMECODELOGSUFFIX BREW_PREFIX FFMPEG_BIN FFPLAY_BIN
    fi
}

_remove_env_vars(){
    _report -d "Resetting environmental variables at ${VRECORD_VARS_FILE}."
    rm "${VRECORD_VARS_FILE}"
    unset VRECORD_VARS_FILE
    unset OS_TYPE RESOURCE_PATH DEFAULTFONT CORE_COUNT OPEN_COMMAND ZCAT_COMMAND COMPUTER_MODEL_NAME DIR_SELECTION_DIALOG
    unset COMPUTER_MODEL_ID COMPUTER_PROCESSOR_NAME COMPUTER_PROCESSOR_SPEED COMPUTER_PROCESSOR_COUNT COMPUTER_MEMORY COMPUTER_SERIAL
    unset CAPTURELOGSUFFIX TIMECODELOGSUFFIX BREW_PREFIX FFMPEG_BIN FFPLAY_BIN GTKDIALOGBIN
    VRECORD_VARS_FILE="/tmp/v_$(echo "${0}" | sed -e "s/[^A-Za-z0-9.]/_/g")_variables.txt"
}

_setup_env_variables(){
    # Set variables for system differences
    QUERY_OS_TYPE="$(uname -s)"
    PATH_CHECK="$(dirname "$(command -v "${0}")")"
    if [[ "${QUERY_OS_TYPE}" = "Darwin" ]] ; then
        OS_TYPE="macOS"
        if [[ "${PATH_CHECK}" = "/usr/local/bin" ]] ; then
            if [[ -d "/usr/local/opt/vrecord" ]] ; then
                RESOURCE_PATH="/usr/local/opt/vrecord"
            elif [[ -d "/usr/local/share/vrecord" ]] ; then
                RESOURCE_PATH="/usr/local/share/vrecord/Resources"
            else
                RESOURCE_PATH="$(brew --prefix vrecord)"
            fi
        elif [[ "${PATH_CHECK}" = "/opt/homebrew/bin" ]] ; then
            if [[ -d "/opt/homebrew/opt/vrecord" ]] ; then
                RESOURCE_PATH="/opt/homebrew/opt/vrecord"
            else
                RESOURCE_PATH="$(brew --prefix vrecord)"
            fi
        else
            RESOURCE_PATH="${SCRIPTDIR}/Resources"
        fi
        if [[ -f "/Library/Fonts/Andale Mono.ttf" ]] ; then
            DEFAULTFONT="/Library/Fonts/Andale Mono.ttf"
        elif [[ -f "/System/Library/Fonts/Supplemental/Andale Mono.ttf" ]] ; then
            DEFAULTFONT="/System/Library/Fonts/Supplemental/Andale Mono.ttf"
        elif [[ -f "/System/Library/Fonts/Monaco.dfont" ]] ; then
            DEFAULTFONT="/System/Library/Fonts/Monaco.dfont"
        elif [[ -f "/Library/Fonts/Microsoft/Lucida Console.ttf" ]] ; then
            DEFAULTFONT="/Library/Fonts/Microsoft/Lucida\Console.ttf"
        elif [[ -f "/Library/Fonts/LetterGothicStd.otf" ]] ; then
            DEFAULTFONT="/Library/Fonts/LetterGothicStd.otf"
        else
            _report -wt "vrecord can't find a preferred font to use, please report this error to https://github.com/amiaopensource/vrecord/issues"
        fi
        HARDWARE_REPORT="$(system_profiler SPHardwareDataType)"
        COMPUTER_MODEL_NAME="$(_parse_report "Model Name" "${HARDWARE_REPORT}")"
        COMPUTER_MODEL_ID="$(_parse_report "Model Identifier" "${HARDWARE_REPORT}")"
        COMPUTER_PROCESSOR_NAME="$(_parse_report "Processor Name" "${HARDWARE_REPORT}")"
        COMPUTER_PROCESSOR_SPEED="$(_parse_report "Processor Speed" "${HARDWARE_REPORT}")"
        COMPUTER_PROCESSOR_COUNT="$(_parse_report "Number of Processors" "${HARDWARE_REPORT}")"
        COMPUTER_MEMORY="$(_parse_report "Memory" "${HARDWARE_REPORT}")"
        COMPUTER_SERIAL="$(_parse_report "Serial Number (system)" "${HARDWARE_REPORT}")"
        CORE_COUNT="$(_parse_report "Total Number of Cores" "${HARDWARE_REPORT}" | awk '{print $1}')"
        OPEN_COMMAND="open"
        ZCAT_COMMAND="gzcat"
        DECKLINK_DRIVER_PLIST="/Library/Extensions/DeckLink_Driver.kext/Contents/Info.plist"
        VIDEO_CARD_DRIVER_VERSION="$(defaults read "${DECKLINK_DRIVER_PLIST}" CFBundleVersion)"
        DIR_SELECTION_DIALOG="Select an existing folder (or drag/drop one below). File System/Volumes for external media."
    elif [[ "${QUERY_OS_TYPE}" = "Linux" ]] ; then
        OS_TYPE="linux"
        if [[ "${PATH_CHECK}" = "/usr/local/bin" ]] || [[ "${PATH_CHECK}" = "/home/linuxbrew/.linuxbrew/bin" ]] ; then
            if [[ -d "/home/linuxbrew/.linuxbrew/opt/vrecord" ]] ; then
                RESOURCE_PATH="/home/linuxbrew/.linuxbrew/opt/vrecord"
            else
                RESOURCE_PATH="$(brew --prefix vrecord)"
            fi
        else
            RESOURCE_PATH="${SCRIPTDIR}/Resources"
        fi
        DEFAULTFONT="/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf"
        if [[ ! -f "${DEFAULTFONT}" ]] ; then
          _report -wt "vrecord can't find a preferred font to use, please report this error to https://github.com/amiaopensource/vrecord/issues"
        fi
        HARDWARE_REPORT=$(lscpu)
        COMPUTER_MODEL_NAME="$(_parse_report "Model Name" "${HARDWARE_REPORT}")"
        CORE_COUNT="$(nproc --all)"
        OPEN_COMMAND="xdg-open"
        ZCAT_COMMAND="zcat"
        DIR_SELECTION_DIALOG="Select an existing folder (or drag/drop one below)."
    else
        echo "Unsupported OS, ${QUERY_OS_TYPE}, detected. Exiting."
        exit 1
    fi
    # set gtkdialog path
    if [[ -n "${DEPENDENCYDIR}" ]] ; then
        GTKDIALOGBIN=$(find "${DEPENDENCYDIR}" -iname "gtkdialog" | head -n1)
    fi
    if [[ -z "${GTKDIALOGBIN}" ]] ; then
        GTKDIALOGBIN="$(which gtkdialog)"
    fi
}

_gather_ffmpeg_vars(){
    CAPTURELOGSUFFIX="_vrecord_input.log"
    TIMECODELOGSUFFIX="_frame_timecodes.txt"
    if [[ -d "/usr/local/opt/ffmpeg-ma" ]] ; then
        BREW_PREFIX="/usr/local/opt/ffmpeg-ma"
    elif [[ -d "/home/linuxbrew/.linuxbrew/opt/ffmpeg-ma" ]] ; then
        BREW_PREFIX="/home/linuxbrew/.linuxbrew/opt/ffmpeg-ma"
    else
        BREW_PREFIX="$(brew --prefix ffmpeg-ma 2>/dev/null)"
        if [[ -d "${BREW_PREFIX}.reinstall" ]] ; then
            BREW_PREFIX+=".reinstall"
        fi
    fi
    if [[ -n "${DEPENDENCYDIR}" ]] ; then
        FFMPEGALT=$(find "${DEPENDENCYDIR}" -iname "ffmpeg-ma" | head -n1)
    fi
    if [[ -n "${FFMPEGALT}" ]] ; then
        FFMPEG_BIN="${FFMPEGALT}"
        FFPLAY_BIN=$(find "${DEPENDENCYDIR}" -iname "ffplay-ma" | head -n1)
    elif which ffmpeg-ma &> /dev/null ; then
        FFMPEG_BIN="$(which ffmpeg-ma)"
        FFPLAY_BIN="$(which ffplay-ma)"
    elif
        [[ -d "${BREW_PREFIX}/bin" ]] ; then
        FFMPEG_BIN="${BREW_PREFIX}/bin/ffmpeg-ma"
        FFPLAY_BIN="${BREW_PREFIX}/bin/ffplay-ma"
    else
        FFMPEG_BIN="$(which ffmpeg)"
        FFPLAY_BIN="$(which ffplay)"
    fi
}

_eia608dump2scc(){
    EIA608DUMP_IN="${1}"
    SCC_OUT="${2}"

    _smmm_to_hhmmssff(){
        secs="$1"
        echo "${secs}" | awk '{ printf "%02i:%02i:%02i:%02i\n", $1/60/60, $1/60%60, $1%60, $1%1*30 }'
    }
    _write_cc(){
        CC="$1"
        if [[ "$START" == "Y" ]] ; then
            echo -n "	${CC}" >> "${SCC_OUT}"
        else
            echo -n " ${CC}" >> "${SCC_OUT}"
        fi
        START="N"
    }
    _write_new_cc_line(){
        SCC_TIME="$(_smmm_to_hhmmssff "${SECS}")"
        echo -e -n "\n\n${SCC_TIME}" >> "${SCC_OUT}"
        START="Y"
    }
    _start_scc(){
        echo -n "Scenarist_SCC V1.0" > "${SCC_OUT}"
    }
    _end_scc(){
        echo >> "${SCC_OUT}"
    }
    #initialize
    PREV_CC="8080"
    CC_PRESENT=0
    REPORT=0

    _start_scc
    while read METADATA_LINE ; do
        if [[ "${METADATA_LINE:0:8}" == "pts_time" ]] ; then
            SECS="${METADATA_LINE/pts_time:}"
            REPORT=0
        elif [[ "${METADATA_LINE:0:21}" == "lavfi.readeia608.0.cc" ]] ; then
            CC_HEX="${METADATA_LINE/lavfi.readeia608.0.cc=}"
            REPORT=1
            if [[ -n "${CC_HEX}" && "${REPORT}" ]] ; then
                CC="${CC_HEX:2:4}"
                if { [[ "${CC}" != "8080" ]] && [[ "${PREV_CC}" == "8080" ]] ; } || { [[ "${CC}" == "9420" ]] && [[ "${PREV_CC}" != "9420" ]] ; } ; then
                    _write_new_cc_line
                    _write_cc "$CC"
                elif [[ "${CC}" != "8080" ]] ; then
                    _write_cc "$CC"
                fi
                PREV_CC="$CC"
                if [[ "$CC_PRESENT" == 0 ]] ; then
                    CC_PRESENT=1
                    if [[ -n "${CC_LOG}" ]] ; then
                        TRANSITION_TIME="$(_smmm_to_hhmmssff "${SECS}")"
                        _report -d "${CC_LOG} - ${TRANSITION_TIME}."
                    fi
                    TRANSITION_TIME="$(_smmm_to_hhmmssff "${SECS}")"
                    CC_LOG="Caption data  ON: ${TRANSITION_TIME}"
                fi
            else
                if [[ "$CC_PRESENT" == 1 ]] ; then
                    CC_PRESENT=0
                    if [[ -n "${CC_LOG}" ]] ; then
                        TRANSITION_TIME="$(_smmm_to_hhmmssff "${SECS}")"
                        _report -d "${CC_LOG} - ${TRANSITION_TIME}."
                    fi
                    TRANSITION_TIME="$(_smmm_to_hhmmssff "${SECS}")"
                    CC_LOG="Caption data OFF: ${TRANSITION_TIME}"
                fi
                PREV_CC="8080"
            fi
            PREV_SECS="$SECS"
        fi
    done < <(grep -o "pts_time:[^ ]*\|lavfi.readeia608.0.cc=[^ ]*"  "${EIA608DUMP_IN}")
    _end_scc
}

_cleanup(){
    _report -wt "Vrecord is being stopped at $(_get_iso8601), noting this in the capture log."
    _writeingestlog "exit status" "vrecord was forced to quit early at $(_get_iso8601). Some processing may be incomplete."
}

_check_mpv(){
    if ! mpv > /dev/null ; then
        mpv
        _report -wt "mpv doesn't appear to be running correctly. Try 'brew reinstall mpv'."
        exit 1
    fi
}

_gtk_vbox_list() {
    VARIABLE_NAME="${1}"
    WIDTH="${2}"
    LABEL="${3}"
    shift 3
    OPTION_LIST=("${@}")
    SELECTION="$(_get_index_of_value "${!VARIABLE_NAME}" "${OPTION_LIST[@]}")"
    if [[ "${VARIABLE_NAME}" == "DECKLINK_INPUT_CHOICE" ]] ; then
        LIST="<input>_get_decklink_input_list</input>"
    elif [[ "${VARIABLE_NAME}" == "DVRESCUE_INPUT_CHOICE" ]] ; then
        LIST="<input>_get_dvrescue_input_list</input>"
    elif [[ "${VARIABLE_NAME}" == "AUDIO_DEV_CHOICE" ]] ; then
        LIST="<input>_get_audio_device_list</input>"
    elif [[ "${VARIABLE_NAME}" == "STANDARD_CHOICE" ]] ; then
        LIST="<input>_get_format_list</input>"
    else
        LIST="$(_expand_list2items "${OPTION_LIST[@]}")"
    fi

    _get_list_extras(){
        if [[ "${VARIABLE_NAME}" == "VIDEO_CODEC_CHOICE" ]] ; then
            echo '<action condition="command_is_true( [ \"$VIDEO_CODEC_CHOICE\" = \"FFV1 version 3\" ] && echo true)">enable:FFV1_SLICE_CHOICE</action>
                  <action condition="command_is_true( [ \"$VIDEO_CODEC_CHOICE\" != \"FFV1 version 3\" ] && echo true)">disable:FFV1_SLICE_CHOICE</action>
                  <action type="refresh">VRECORD_OUTPUT_NAME</action>'
        elif [[ "${VARIABLE_NAME}" == "CONTAINER_CHOICE" ]] ; then
            echo '<action condition="command_is_true( [ \"$CONTAINER_CHOICE\" = \"Matroska\" ] && echo true)">enable:EMBED_LOGS_CHOICE</action>
                  <action condition="command_is_true( [ \"$CONTAINER_CHOICE\" != \"Matroska\" ] && echo true)">disable:EMBED_LOGS_CHOICE</action>
                  <action type="refresh">VRECORD_OUTPUT_NAME</action>'
        elif  [[ "${VARIABLE_NAME}" == "AUDIO_MODE_CODEC_CHOICE" ]] ; then
            echo '<action type="refresh">VRECORD_OUTPUT_NAME</action>'
        elif [[ "${VARIABLE_NAME}" == "AUDIO_DEV_CHOICE" ]] ; then
            echo '<action condition="command_is_true(echo \"$AUDIO_DEV_CHOICE\" | grep -vq Blackmagic && echo true)">enable:AUDIO_MODE_SR_CHOICE</action>
                  <action condition="command_is_true(echo \"$AUDIO_DEV_CHOICE\" | grep -q Blackmagic && echo true)">disable:AUDIO_MODE_SR_CHOICE</action>
                  <action type="refresh">VRECORD_OUTPUT_NAME</action>'
        elif [[ "${VARIABLE_NAME}" == "DV_CONTAINER_CHOICE" ]] && $DVPACKAGER_INSTALLED ; then
            echo '<action condition="command_is_true( [ \"$DV_CONTAINER_CHOICE\" = \"DV\" ] && echo true)">disable:DV_RESCUE_OPTION_TC</action>
                <action condition="command_is_true( [ \"$DV_CONTAINER_CHOICE\" != \"DV\" ] && echo true)">enable:DV_RESCUE_OPTION_TC</action>'
        fi
    }

    _get_vbox_extras(){
        if [[ "${VARIABLE_NAME}" == "TIMECODE_CHOICE" ]] ; then
            echo "
            <button>
                <label>Scan timecode types</label>
                <action>_update_config_file</action>
                <action type=\"exit\">timecode_scan</action>
            </button>"
        elif [[ "${VARIABLE_NAME}" == "STANDARD_CHOICE" ]] ; then
            echo "
            <checkbox>
                <label>Show HD Formats</label>
                <default>\"${HD_CHOICE}\"</default>
                <variable>HD_CHOICE</variable>
                <action>_update_config_file</action>
                <action type=\"clear\">STANDARD_CHOICE</action>
                <action type=\"refresh\">STANDARD_CHOICE</action>
            </checkbox>"
        elif [[ "${VARIABLE_NAME}" == "EMBED_LOGS_CHOICE" ]] ; then
            echo "<sensitive>$(if $MKVPROPEDIT_INSTALLED ; then echo true ; else echo false ; fi)</sensitive>"
        elif [[ "${VARIABLE_NAME}" == "QCTOOLSXML_CHOICE" ]] ; then
            echo "<sensitive>$(if $QCLI_INSTALLED ; then echo true ; else echo false ; fi)</sensitive>"
        elif [[ "${VARIABLE_NAME}" == "DV_CONTAINER_CHOICE" ]] ; then
            echo "<sensitive>$(if $DVPACKAGER_INSTALLED ; then echo true ; else echo false ; fi)</sensitive>"
        elif [[ "${VARIABLE_NAME}" == "DECKLINK_INPUT_CHOICE" ]] ; then
            echo "
            <button>
                <label>Rescan</label>
                <action type=\"clear\">DECKLINK_INPUT_CHOICE</action>
                <action type=\"refresh\">DECKLINK_INPUT_CHOICE</action>
            </button>"
        elif [[ "${VARIABLE_NAME}" == "DVRESCUE_INPUT_CHOICE" ]] ; then
            echo "
            <button>
                <label>Rescan</label>
                <action type=\"clear\">DVRESCUE_INPUT_CHOICE</action>
                <action type=\"refresh\">DVRESCUE_INPUT_CHOICE</action>
            </button>"
        elif [[ "${VARIABLE_NAME}" == "AUDIO_DEV_CHOICE" ]] ; then
            echo "
            <button>
                <label>Rescan</label>
                <action type=\"clear\">AUDIO_DEV_CHOICE</action>
                <action type=\"refresh\">AUDIO_DEV_CHOICE</action>
            </button>"
        fi
    }

    echo "<vbox space-fill=\"true\">
      <text>
          <label>${LABEL}</label>
      </text>
      <list selection-mode=\"1\" selected-row=\"${SELECTION}\">
          <width>${WIDTH}</width>
          <variable>${VARIABLE_NAME}</variable>
          ${LIST}
          $(_get_list_extras)
      </list>
      $(_get_vbox_extras)
    </vbox>"
}

_setup_vrecord_input(){
    _set_ffmpeg_loglevel(){
        if [[ "$VERBOSE" = "true" ]] ; then
            GRAB_INPUT+=(-loglevel debug)
            _report -wt "When running vrecord in verbose mode, avoid using Visual + Numerical option."
        else
            GRAB_INPUT+=(-loglevel warning)
        fi
    }
    # set up input and playback
    GRAB_INPUT=()
    GRAB_INPUT+=("${EXTRAINPUTOPTIONS[@]}")
    if [[ "${DEVICE_INPUT_CHOICE}" = 0 ]] && [[ -z "${DECKLINK_INPUT_CHOICE}" ]] && [[ -z "${ALT_INPUT}" ]] && [[ -z "${SIGNAL_INPUT}" ]]; then
        _report -w -t "The decklink input is not found."
        exit 1
    fi
    if [[ -n "${ALT_INPUT}" ]] ; then
        _set_ffmpeg_loglevel
        GRAB_INPUT+=(-i "${ALT_INPUT}")
    elif [[ "${SIGNAL_INPUT}" = 'true' ]] ; then
        TEST_SIGNAL_CHOICE="testsrc=size=${SIG_GEN_SIZE}:r=${DECKLINK_FPS}"
        VIDEO_INPUT="Test signal: ${TEST_SIGNAL_CHOICE}"
        AUDIO_INPUT="Test signal: 440Hz"
        GRAB_INPUT+=(-f lavfi -i "${TEST_SIGNAL_CHOICE}")
        GRAB_INPUT+=("${TIME_LIMIT[@]}")
        GRAB_INPUT+=(-f lavfi -i sine=440:r=48000)
        GRAB_INPUT+=(-pix_fmt yuv422p10le)
    elif [[ "${DEVICE_INPUT_CHOICE}" = 0 ]] ; then
        _set_ffmpeg_loglevel
        GRAB_INPUT+=(-f decklink)
        GRAB_INPUT+=(-signal_loss_action none)
        GRAB_INPUT+=(-audio_input "${AUDIO_INPUT}")
        GRAB_INPUT+=(-video_input "${VIDEO_INPUT}")
        GRAB_INPUT+=(-format_code "${STANDARD}")
        GRAB_INPUT+=(-channels 8)
        GRAB_INPUT+=(-audio_depth 32)
        GRAB_INPUT+=(-raw_format "${PIXEL_FORMAT}")
        GRAB_INPUT+=(-i "${DECKLINK_INPUT_CHOICE}")
    elif [[ "${DEVICE_INPUT_CHOICE}" = 1 ]] ; then
        if [[ "${DVRESCUE_INPUT_CHOICE}" = 'FFmpeg iec61883 Default' ]] ; then
            GRAB_INPUT+=(-f iec61883)
            GRAB_INPUT+=(-i auto)
        else
            DVRESCUE_INPUT_INDEX="$(echo "${DVRESCUE_INPUT_CHOICE}" | cut -d " " -f1 | sed 's|:$||g')"
            GRAB_INPUT+=("device://${DVRESCUE_INPUT_INDEX}")
            GRAB_INPUT+=(--capture)
        fi
    elif [[ "${DEVICE_INPUT_CHOICE}" = 2 ]] ; then
        _set_ffmpeg_loglevel
        #Mac Options
        #Linux Options
        if [[ "${OS_TYPE}" = "linux" ]] && [[ "${AUDIO_DEV_CHOICE}" != *"Blackmagic"* ]] ; then
            _get_audio_dev_num
            GRAB_INPUT+=(-f alsa)
            GRAB_INPUT+=(-acodec pcm_s32le -ac 2)
            GRAB_INPUT+=(${S_RATE})
            GRAB_INPUT+=(-i hw:"${AUDIO_DEV_NUM}")
        elif [[ "${OS_TYPE}" = "macOS" ]] && [[ "${AUDIO_DEV_CHOICE}" != *"Blackmagic"* ]] ; then
            GRAB_INPUT+=(-f avfoundation)
            GRAB_INPUT+=(-i "none:${AUDIO_DEV_CHOICE}")
        elif [[ "${AUDIO_DEV_CHOICE}" == *"Blackmagic"* ]] ; then
            GRAB_INPUT+=(-f decklink)
            GRAB_INPUT+=(-format_code ntsc) # just faking it for devices that can't autodetect even though it's unused
            GRAB_INPUT+=(-channels 2)
            GRAB_INPUT+=(-audio_depth 32)
            GRAB_INPUT+=(-i "${DECKLINK_INPUT_CHOICE}")
            GRAB_INPUT+=(-vn)
        fi
    else
        _report "Input unknown"
        exit 1
    fi
}

_setup_vrecord_process(){
    _setup_vrecord_input
    if [[ "${DEVICE_INPUT_CHOICE}" = 0 ]] ; then
        WINDOW_NAME="mode:${RUNTYPE} - video:'${VIDEO_INPUT}' audio:'${AUDIO_INPUT}' - to end recording press q, esc, or close video window"
        # DEVICE_INPUT_CHOICE=0 is decklink, other DEVICE_INPUT_CHOICE values don't yet use such filtering
        if [[ "${RUNTYPE}" = "record" || \
            "${SIGNAL_INPUT}" = 'true' || \
            "${PLAYBACKVIEW_CHOICE_PASS}" = "Audio + Video" || \
            "${MEDIA_PLAYER_CHOICE}" = "mpv" || \
            "$(basename "${FFPLAY_BIN}")" != "ffplay-ma" ]] ; then
            VRECORD_STEPS="2" # Steps: record | player
        else
            VRECORD_STEPS="1" # Steps: player
        fi

        # caption handling if ntsc
        if [[ "${STANDARD}" == "ntsc" ]] ; then
            CAPTION_TMP="$(_maketemp .eia608.txt)"
            CAPTION_WRITE=",readeia608=lp=1:spw=0.27,metadata=mode=print:key=lavfi.readeia608.0.cc:file=${CAPTION_TMP}"
        fi

        RECORD_COMMAND=("${FFMPEG_BIN}")
        RECORD_COMMAND+=(-nostdin -nostats "${TIME_LIMIT[@]}")
        if [[ "${SIGNAL_INPUT}" != 'true' ]] ; then
            RECORD_COMMAND+=("${TC_INPUT_OPTION[@]}")
        fi
        RECORD_COMMAND+=("${GRAB_INPUT[@]}")
        if [[ -n "${VIDEOCODECNAME}" ]] ; then
            MIDDLEOPTIONS_PRES+=(-metadata:s:v:0 encoder="${VIDEOCODECNAME}")
        fi
        RECORD_COMMAND+=("${MIDDLEOPTIONS_PRES[@]}" "${MIDDLEOPTIONS_ALL[@]}")
        if [[ "${RUNTYPE}" = "record" ]] ; then
            RECORD_COMMAND+=(-filter_complex "[0:v:0]${RECORDINGFILTER#,*}${TC_WRITE}${CAPTION_WRITE}[vout];${AUDIOMAP}" -map "[vout]" "${AUDIO_CHANNEL_MAP[@]}")
            RECORD_COMMAND+=(-f tee [f=${FORMAT}:select=v,${AUDIO_TEE_SELECT_MAP}]"${VRECORD_OUTPUT}"\|[f=nut:onfail=abort:select=v,${AUDIO_TEE_SELECT_MAP},a\\\\:0]pipe:1)
            RECORD_COMMAND+=("${EXTRAOUTPUTS[@]}")
        else
            if [[ "${SIGNAL_INPUT}" = 'true' ]] ; then
                PIPE_OUTPUT=(-c:v ffv1)
                AUD_PIPE_MAP='1:a'
            else
                AUD_PIPE_MAP='0:a'
            fi
            PIPE_OUTPUT=(-c:v rawvideo)
            PIPE_OUTPUT+=(-vf "${RECORDINGFILTER#,*}")
            PIPE_OUTPUT+=(-c:a pcm_s24le)
            PIPE_OUTPUT+=(-map 0:v -map "${AUD_PIPE_MAP}")
            PIPE_OUTPUT+=(-f nut)
            PIPE_OUTPUT+=(-)
            RECORD_COMMAND+=("${PIPE_OUTPUT[@]}")
        fi
    elif [[ "${DEVICE_INPUT_CHOICE}" = 1 ]] ; then
        WINDOW_NAME="mode:${RUNTYPE} - DV input:'${DVRESCUE_INPUT_INDEX}' - to end recording press q, esc, or close video window"
        if [[ "${DVRESCUE_INPUT_CHOICE}" = 'FFmpeg iec61883 Default' ]] ; then
            if [[ "${RUNTYPE}" = "record" ]] ; then
                VRECORD_STEPS="2" # Steps: record | player
            else
                VRECORD_STEPS="1" # Steps: player
            fi
            RECORD_COMMAND=("${FFMPEG_BIN}" -nostdin -nostats "${TIME_LIMIT[@]}" "${GRAB_INPUT[@]}")
            RECORD_COMMAND+=(-map 0:v -c copy)
            RECORD_COMMAND+=(-f "${FORMAT}" "${VRECORD_OUTPUT}")
            RECORD_COMMAND+=(-map 0:v -f rawvideo -c copy -)
        else
            VRECORD_STEPS="2" # Steps: record | player
            RECORD_COMMAND=(dvrescue)
            RECORD_COMMAND+=("${GRAB_INPUT[@]}")
            if [[ "${RUNTYPE}" = "record" ]] ; then
                RECORD_COMMAND+=(--merge-output-concealed)
                RECORD_COMMAND+=(--merge-ignore-speed)
                RECORD_COMMAND+=(--cc-format scc)
                RECORD_COMMAND+=(--cc-output "${VRECORD_OUTPUT}.dvrescue.scc")
                RECORD_COMMAND+=(--xml-output "${VRECORD_OUTPUT}.dvrescue.xml")
                RECORD_COMMAND+=(--merge "${VRECORD_OUTPUT}")
            fi
            RECORD_COMMAND+=(--merge-output-concealed)
            RECORD_COMMAND+=(--merge-output-speed)
            RECORD_COMMAND+=(--merge -)
        fi
    elif [[ "${DEVICE_INPUT_CHOICE}" = 2 ]] ; then
        WINDOW_NAME="mode:${RUNTYPE} - input:'${AUDIO_DEV_CHOICE}' - to end recording press q, esc, or close video window"
        VRECORD_STEPS="2" # Steps: record | player (record is adjusted if actually recording)
        RECORD_COMMAND=("${FFMPEG_BIN}")
        RECORD_COMMAND+=(-nostdin -nostats "${TIME_LIMIT[@]}" "${GRAB_INPUT[@]}")
        RECORD_COMMAND+=("${MIDDLEOPTIONS_PRES[@]}" "${MIDDLEOPTIONS_ALL[@]}")
        if [[ "${RUNTYPE}" = "record" ]] ; then
            RECORD_COMMAND+=(-f "${FORMAT}" -filter_complex "${AUDIOMAP}" "${AUDIO_CHANNEL_MAP[@]}" "${VRECORD_OUTPUT}")
        fi
        PIPE_OUTPUT+=(-c:a pcm_s16le -ar 48k)
        PIPE_OUTPUT+=(-f wav)
        PIPE_OUTPUT+=(-)
        RECORD_COMMAND+=(-filter_complex "${AUDIOMAP}" "${AUDIO_CHANNEL_MAP[@]}" "${PIPE_OUTPUT[@]}")
    else
        _report_unexpected_error DEVICE_INPUT_CHOICE
        _report "Input unknown"
        exit 1
    fi
    # get player command
    if [[ "${MEDIA_PLAYER_CHOICE}" = "mpv" ]] ; then
        _check_mpv
        MPVOPTS=(--no-osc)
        MPVOPTS+=(--load-scripts=no)
        MPVOPTS+=(--script="${RESOURCE_PATH}/qcview.lua")
        MPVOPTS+=(--really-quiet)
        MPVOPTS+=(--title="${WINDOW_NAME}")
        if [[ "${MONITOR_AUDIO_CHOICE}" = "No" ]] ; then
            MPVOPTS+=(--aid=no)
        fi
        PLAYER_COMMAND=(mpv "${MPVOPTS[@]}" -)
    else
        FFPLAY_OPTIONS=(-v info)
        FFPLAY_OPTIONS+=(-hide_banner)
        FFPLAY_OPTIONS+=(-stats)
        FFPLAY_OPTIONS+=(-autoexit)
        FFPLAY_OPTIONS+=(-window_title "${WINDOW_NAME}")
        if [[ "${DEVICE_INPUT_CHOICE}" = 0 ]] && [[ "${PLAYBACKVIEW_CHOICE_PASS}" = "Audio + Video" ]] && [[ "${RUNTYPE}" = "passthrough" ]] ; then
            FFPLAY_OPTIONS+=(-f lavfi "amovie='pipe\:0':${PLAYBACKFILTER}")
        elif [[ "${DEVICE_INPUT_CHOICE}" = 0 ]] && [[ "${PLAYBACKVIEW_CHOICE}" = "Audio + Video" ]] && [[ "${RUNTYPE}" = "record" ]] ; then
            FFPLAY_OPTIONS+=(-f lavfi "amovie='pipe\:0':${PLAYBACKFILTER}")
        elif [[ "${DEVICE_INPUT_CHOICE}" = 2 ]] ; then
            FFPLAY_OPTIONS+=(-f lavfi "amovie='pipe\:0',${PLAYBACKFILTER}")
        else
            if [[ "${VRECORD_STEPS}" = "1" ]] ; then
                FFPLAY_OPTIONS+=("${GRAB_INPUT[@]}")
            else
                FFPLAY_OPTIONS+=(-i -)
            fi
            if [[ -n "${PLAYBACKFILTER}" ]] ; then
                FFPLAY_OPTIONS+=(-vf "${PLAYBACKFILTER}")
            fi
            if [[ -n "${AUDIO_PLAY_MAP}" ]] ; then
                FFPLAY_OPTIONS+=(-af "${AUDIO_PLAY_MAP}")
            fi
        fi
        if [[ "${MONITOR_AUDIO_CHOICE}" = "No" ]] ; then
            FFPLAY_OPTIONS+=(-an)
        fi
        PLAYER_COMMAND=("${FFPLAY_BIN}" "${FFPLAY_OPTIONS[@]}")
    fi
}

_get_inputs(){
    # determine decklink inputs
    unset DECKLINK_DEVICES
    while read decklink_device ; do
        DECKLINK_DEVICES+=("${decklink_device}")
    done < <("${FFMPEG_BIN}" -nostdin -v 0 -sources decklink | awk -F'[][]' '{print $2}' | grep -v "^$")
    if [[ "${#DECKLINK_DEVICES[@]}" = 1 ]] ; then # default to first input if only one
        DECKLINK_INPUT_CHOICE="${DECKLINK_DEVICES[0]}"
    fi

    # determine avfoundation inputs
    unset AVFOUNDATION_DEVICES
    while read avf_device ; do
        AVFOUNDATION_DEVICES+=("${avf_device}")
    done < <("${FFMPEG_BIN}" -nostdin -hide_banner -f avfoundation -list_devices 1 -i dummy 2>&1 | grep -A 10 "AVFoundation audio devices" | grep -o "\[[0-9]\].*" | cut -d " " -f2-)

    # determine dvrescue inputs
    unset DVRESCUE_DEVICES
    while read dvrescue_device ; do
        DVRESCUE_DEVICES+=("${dvrescue_device}")
    done < <(dvrescue -list_devices 2>/dev/null | grep "\[DV\]")
    if [[ "${OS_TYPE}" = 'linux' ]] ; then
        DVRESCUE_DEVICES+=( "FFmpeg iec61883 Default" )
    fi
    if [[ "${#DVRESCUE_DEVICES[@]}" = 1 ]] ; then # default to first input if only one
        DVRESCUE_INPUT_CHOICE="${DVRESCUE_DEVICES[0]}"
    fi
}

_get_audio_dev_num(){
    if [[ $(echo ${AUDIO_DEVICES[@]} | grep -F -w "$AUDIO_DEV_CHOICE") ]]
    then
      AUDIO_DEV_FULL=$(printf '%s\n' "${AUDIO_DEVICES[@]}" | grep -F "$AUDIO_DEV_CHOICE")
      AUDIO_DEV_NUM="$(echo "$AUDIO_DEV_FULL" | cut -d ':' -f1 | sed 's|card ||g'),$(echo "$AUDIO_DEV_FULL" | rev | cut -d ' ' -f1)"
    fi
}

_set_up_edit_form() {
  _expand_list2items(){
    LIST=( "$@" )
    for i in "${LIST[@]}" ; do
        echo "<item>${i}</item>"
    done
  }
  _get_index_of_value(){
    # run with function, value to look for as first argument, and array to look in as 2nd argument, such function as
    # _get_index_of_value "${VIDEO_INPUT_CHOICE}" "${VIDEO_INPUT_OPTIONS[@]}"
    VALUE="${1}"
    shift
    LIST=( "$@" )
    INDEX=0
    MATCH=""
    for ITEM in "${LIST[@]}" ; do
        if [[ "${VALUE}" = "${ITEM}" ]] ; then
            MATCH="$INDEX"
        fi
        (( ++INDEX ))
    done
    if [[ -n "${MATCH}" ]] ; then
        echo -n "${MATCH}"
    fi
  }

# initialize deckcontrol temp files
FFMPEG_STATUS_TMP="$(_maketemp .ffmpeg.status.txt)"
DECKCONTROL_STATUS_TMP="$(_maketemp .deckcontrol.status.txt)"
DECKCONTROL_TIMECODE_TMP="$(_maketemp .deckcontrol.timecode.txt)"
DVRESCUE_STATUS_TMP="$(_maketemp .dvrescue.status.txt)"
echo "" > "${FFMPEG_STATUS_TMP}"
echo "disabled" > "$DECKCONTROL_STATUS_TMP"
echo "--:--:--:--" > "$DECKCONTROL_TIMECODE_TMP"
echo "disabled" > "$DVRESCUE_STATUS_TMP"

STARTUP_VIEW_TMP=$(_maketemp .startup.txt)
echo "MAIN" > "${STARTUP_VIEW_TMP}"

SIDECAR_FILES_GUI="
<frame Sidecar file options>
    <hbox space-expand=\"true\">
        <vbox>
            <checkbox>
                <label>Access MP4</label>
                <default>\"${MP4_CHOICE}\"</default>
                <variable>MP4_CHOICE</variable>
            </checkbox>
            <checkbox tooltip-text=\"If enabled, vrecord will write an MD5 checksum of each raw video frame to a sidecar file with a .framemd5 extension. More info on this format is available at https://ffmpeg.org/ffmpeg-formats.html#framehash-1.\">
                <label>FrameMD5s</label>
                <default>\"${FRAMEMD5_CHOICE}\"</default>
                <variable>FRAMEMD5_CHOICE</variable>
            </checkbox>
        </vbox>
        $(_gtk_vbox_list "QCTOOLSXML_CHOICE" "180"  "QCTools XML?"              "${QCTOOLSXML_OPTIONS[@]}")
    </hbox>
</frame>"

PLAYBACK_OPT_GUI="
<frame Playback options>
    <hbox space-expand=\"true\">
        $(_gtk_vbox_list "PLAYBACKVIEW_CHOICE"      "130" "View (recording)"   "${PLAYBACKVIEW_OPTIONS[@]}")
        $(_gtk_vbox_list "PLAYBACKVIEW_CHOICE_PASS" "130" "View (passthrough)" "${PLAYBACKVIEW_PASS_OPTIONS[@]}")
    </hbox>
</frame>"

OPTIONAL_TOOLS_GUI=$(cat << CONFIG_FORM
<frame Preferences>
    <hbox>
        <notebook tab-labels="Player|Aspect Ratio|Closed Captioning">
            <frame Player Settings>
                <hbox>
                $(_gtk_vbox_list "WAVEFORM_SCALE_CHOICE" "100" "Select Waveform Scale"            "${WAVEFORM_SCALE_OPTIONS[@]}")
                $(_gtk_vbox_list "SIGNAL_VIEW_CHOICE"    "100" "Select Video Scale"               "${SIGNAL_OPTIONS[@]}")
                $(_gtk_vbox_list "SIGNAL_INT_CHOICE"     "100" "Force Interlacement"              "${INT_OPTIONS[@]}")
                $(_gtk_vbox_list "MONITOR_AUDIO_CHOICE"  "100" "Monitor Audio?"                   "${MONITOR_AUDIO_OPTIONS[@]}")
                </hbox>
            </frame>
            <frame Player AspectRatioSettings>
                <vbox>
                    <text width-chars="-1">
                        <label>Here you can set the sample aspect ratio to use for any display aspect ratio. The recommendation of the vrecord community is the first value of each list. If unset then the recommendation will be used.</label>
                    </text>
                    <hbox>
                        $(_gtk_vbox_list "NTSC_43_SAR_CHOICE"   "-1" "NTSC 4/3"  "${NTSC_43_SAR_OPTIONS[@]}")
                        $(_gtk_vbox_list "NTSC_169_SAR_CHOICE"  "-1" "NTSC 16/9" "${NTSC_169_SAR_OPTIONS[@]}")
                        $(_gtk_vbox_list "PAL_43_SAR_CHOICE"    "-1" "PAL 4/3"   "${PAL_43_SAR_OPTIONS[@]}")
                        $(_gtk_vbox_list "PAL_169_SAR_CHOICE"   "-1" "PAL 16/9"  "${PAL_169_SAR_OPTIONS[@]}")
                    </hbox>
                </vbox>
            </frame>
            <frame Closed Captioning Settings>
                <vbox>
                    <text width-chars="-1">
                        <label>For NTSC decklink captures, vrecord will try to make an scc file for you. Any other requests.</label>
                    </text>
                    <checkbox>
                        <label>Make a webVTT</label>
                        <default>"${CC2VTT}"</default>
                        <variable>CC2VTT</variable>
                    </checkbox>
                    <checkbox>
                        <label>Make an SRT</label>
                        <default>"${CC2SRT}"</default>
                        <variable>CC2SRT</variable>
                    </checkbox>
                </vbox>
            </frame>
        </notebook>
        <frame Invert Audio Phase>
            <vbox space-fill="true" space-expand="true">
                <text>
                    <label>WARNING: Do not use this option unless required</label>
                </text>
                <text>
                    <label>This options applies only to decklink inputs</label>
                </text>
                <checkbox>
                    <label>Invert channel 2</label>
                    <default>false</default>
                    <variable>INVERT_PHASE_2</variable>
                </checkbox>
                <checkbox>
                    <label>Invert channel 4</label>
                    <default>false</default>
                    <variable>INVERT_PHASE_4</variable>
                </checkbox>
            </vbox>
        </frame>
        <frame Optional Tools>
            <hbox>
                <text>
                    <label>deckcontrol: </label>
                </text>
                <pixmap stock-icon-size="1" tooltip-text="If deckcontrol is installed, vrecord can offer an interface to control videodecks via RS422 via a Blackmagic capture device.">
                    <input file stock="$(if $DECKCONTROL_INSTALLED ; then echo gtk-yes ; else echo gtk-no ; fi)"></input>
                </pixmap>
            </hbox>
            <hbox>
                <text>
                    <label>gnuplot: </label>
                </text>
                <pixmap stock-icon-size="1" tooltip-text="If gnuplot is installed, vrecord can may a graph output from qctools reports.">
                    <input file stock="$(if $GNUPLOT_INSTALLED ; then echo gtk-yes ; else echo gtk-no ; fi)"></input>
                </pixmap>
            </hbox>
            <hbox>
                <text>
                    <label>mediaconch: </label>
                </text>
                <pixmap stock-icon-size="1" tooltip-text="If mediaconch is installed, vrecord can perform checks after capture to ensure the file is as expected.">
                    <input file stock="$(if $MEDIACONCH_INSTALLED ; then echo gtk-yes ; else echo gtk-no ; fi)"></input>
                </pixmap>
            </hbox>
            <hbox>
                <text>
                    <label>mkvpropedit: </label>
                </text>
                <pixmap stock-icon-size="1" tooltip-text="If mkvpropedit is installed, vrecord can embed capture logs into any Matroska recordings.">
                    <input file stock="$(if $MKVPROPEDIT_INSTALLED ; then echo gtk-yes ; else echo gtk-no ; fi)"></input>
                </pixmap>
            </hbox>
            <hbox>
                <text>
                    <label>mpv: </label>
                </text>
                <pixmap stock-icon-size="1" tooltip-text="If mpv is installed, vrecord can offer additional playback view options.">
                    <input file stock="$(if $MPV_INSTALLED ; then echo gtk-yes ; else echo gtk-no ; fi)"></input>
                </pixmap>
            </hbox>
            <hbox>
                <text>
                    <label>qcli: </label>
                </text>
                <pixmap stock-icon-size="1" tooltip-text="If qcli is installed, vrecord can offer options to create QCTools reports during or after capture.">
                    <input file stock="$(if $QCLI_INSTALLED ; then echo gtk-yes ; else echo gtk-no ; fi)"></input>
                </pixmap>
            </hbox>
            <hbox>
                <text>
                    <label>dvpackager: </label>
                </text>
                <pixmap stock-icon-size="1" tooltip-text="If dvpackager is installed, vrecord can offer options to split and wrap DV captures.">
                    <input file stock="$(if $DVPACKAGER_INSTALLED ; then echo gtk-yes ; else echo gtk-no ; fi)"></input>
                </pixmap>
            </hbox>
        </frame>
    </hbox>
    <hbox space-fill="true" space-expand="true">
        <vbox>
            <text>
                <label>FFmpeg Status</label>
            </text>
            <vbox scrollable="true" height="120">
                <text wrap="true" xalign="0" selectable="true">
                    <variable export="false">ffmpeg_status</variable>
                    <input file>"${FFMPEG_STATUS_TMP}"</input>
                </text>
            </vbox>
            <button>
                <label>Check FFmpeg status</label>
                <action>_check_ffmpeg_install > ${FFMPEG_STATUS_TMP}</action>
                <action type="refresh">ffmpeg_status</action>
            </button>
        </vbox>
        <vbox>
            <text>
                <label>Environment</label>
            </text>
            <vbox scrollable="true" height="120">
                <text xalign="0" selectable="true">
                    <variable export="false">vrecord_env</variable>
                    <input file>"${VRECORD_VARS_FILE}"</input>
                </text>
            </vbox>
            <button>
                <label>Reset Environment Variables</label>
                <action type="exit">env_reset</action>
            </button>
        </vbox>
        <vbox>
            <text>
                <label>Alternate Dependency Source</label>
            </text>
            <entry accept="directory">
                <default>"${DEPENDENCYDIR}"</default>
                <variable>DEPENDENCYDIR</variable>
            </entry>
            <button tooltip-text="Select alternate dependency directory and then reset environmental variables">
                <input file stock="gtk-open"></input>
                <action type="fileselect">DEPENDENCYDIR</action>
            </button>
        </vbox>
    </hbox>
</frame>
CONFIG_FORM
)

_get_deckcontrol_button(){
    # four arguments are needed in the following order
    # 1) variable name, 2) gtk stock icon name, 3) a label if no icon is used, 4) the assigned command
    VARIABLE_NAME="${1}"
    ICON="${2}"
    LABEL="${3}"
    COMMAND="${4}"
    if [ -n "${COMMAND}" ] ; then
        if [[ -n "$ICON" ]] ; then
            INPUT="<input file stock=\"${ICON}\"></input>"
        else
            INPUT="<label>${LABEL}</label>"
        fi
        echo "<button>
            <variable export=\"false\">${VARIABLE_NAME}</variable>
            ${INPUT}
            <visible>disabled</visible>
            <action>${COMMAND}& >/dev/null</action>
        </button>"
    fi
}

DECKLINK_INPUT_GUI=$(cat << DECKLINK_FORM
<frame Decklink input options>
    <vbox>
        <hbox space-expand="true">
            $(_gtk_vbox_list "DECKLINK_INPUT_CHOICE"    "120" "Video Card"             "${DECKLINK_DEVICES[@]}")
            $(_gtk_vbox_list "VIDEO_INPUT_CHOICE"       "80" "Video Input"            "${VIDEO_INPUT_OPTIONS[@]}")
            $(_gtk_vbox_list "AUDIO_INPUT_CHOICE"       "130" "Audio Input"            "${AUDIO_INPUT_OPTIONS[@]}")
            $(_gtk_vbox_list "AUDIO_MAPPING_CHOICE"      "-1" "Audio Channel Mapping"  "${CHANNEL_MAPPING_OPTIONS[@]}" )
            $(_gtk_vbox_list "STANDARD_CHOICE"           "110" "Standard"               "${STANDARD_OPTIONS[@]}")
            $(_gtk_vbox_list "VIDEO_BIT_DEPTH_CHOICE"    "40" "Video Bit Depth"        "${VIDEO_BITDEPTH_OPTIONS[@]}")
            $(_gtk_vbox_list "ASPECT_RATIO_CHOICE"       "40" "Display Aspect Ratio"   "${ASPECT_RATIO_OPTIONS[@]}")
            $(_gtk_vbox_list "TIMECODE_CHOICE"           "40" "Timecode format"        "${TIMECODE_OPTIONS[@]}")
        </hbox>
        <frame Output file options>
            <hbox space-expand="true">
                $(_gtk_vbox_list "EMBED_LOGS_CHOICE"        "100" "Embed digitization logs in video file (Matroska ONLY)" "${EMBED_LOGS_OPTIONS[@]}")
                $(_gtk_vbox_list "CONTAINER_CHOICE"         "100" "Select File Format"            "${CONTAINER_OPTIONS[@]}")
                $(_gtk_vbox_list "FFV1_SLICE_CHOICE"        "100" "FFV1 Slice Count"              "${FFV1_SLICE_OPTIONS[@]}")
                $(_gtk_vbox_list "VIDEO_CODEC_CHOICE"       "160" "Select Video Codec"            "${VIDEO_CODEC_OPTIONS[@]}")
                $(_gtk_vbox_list "AUDIO_CODEC_CHOICE"       "100" "Select Audio Codec"            "${AUDIO_CODEC_OPTIONS[@]}")
            </hbox>
        </frame>
        <hbox>
            ${PLAYBACK_OPT_GUI}
            ${SIDECAR_FILES_GUI}
            <frame RS422 deck control>
                <hbox>
                    <vbox>
                        <text>
                            <label>Status</label>
                        </text>
                        <entry editable="false" has-frame="false">
                            <variable export="false">decklink_status</variable>
                            <input file>"${DECKCONTROL_STATUS_TMP}"</input>
                        </entry>
                    </vbox>
                    <vbox>
                        <text>
                            <label>Timecode</label>
                        </text>
                        <entry editable="false" has-frame="false">
                            <variable export="false">decklink_timecode</variable>
                            <input file>"${DECKCONTROL_TIMECODE_TMP}"</input>
                        </entry>
                    </vbox>
                    <timer milliseconds="true" interval="500" visible="false" disabled="true">
                         <variable export="false">deckcontrol_timer</variable>
                         <visible>disabled</visible>
                         <action>{ deckcontrol getcurrentstate | grep "state:\|detect" | sed "s/VTR control state: //g" > "${DECKCONTROL_STATUS_TMP}" ; deckcontrol gettimecode | grep "TC=" | cut -c 4- > "${DECKCONTROL_TIMECODE_TMP}" ; } &</action>
                         <action>refresh:decklink_status</action>
                         <action>refresh:decklink_timecode</action>
                    </timer>
                </hbox>
                <hbox>
                    <togglebutton>
                        <label>Deck Control</label>
                        <default>false</default>
                        <variable export="false">deckcontrol_toggle</variable>
                        <input file stock="gtk-execute"></input>
                        <action>if true enable:deckcontrol_timer</action>
                        <action>if true enable:decklink_status</action>
                        <action>if true enable:decklink_timecode</action>
                        <action>if true enable:deckcontrol_rewind</action>
                        <action>if true enable:deckcontrol_prev</action>
                        <action>if true enable:deckcontrol_play</action>
                        <action>if true enable:deckcontrol_stop</action>
                        <action>if true enable:deckcontrol_next</action>
                        <action>if true enable:deckcontrol_ff</action>
                        <action>if true enable:deckcontrol_eject</action>
                        <action>if false disable:deckcontrol_timer</action>
                        <action>if false disable:decklink_status</action>
                        <action>if false disable:decklink_timecode</action>
                        <action>if false disable:deckcontrol_rewind</action>
                        <action>if false disable:deckcontrol_prev</action>
                        <action>if false disable:deckcontrol_play</action>
                        <action>if false disable:deckcontrol_stop</action>
                        <action>if false disable:deckcontrol_next</action>
                        <action>if false disable:deckcontrol_ff</action>
                        <action>if false disable:deckcontrol_eject</action>
                    </togglebutton>
                    <hbox>
                        $(_get_deckcontrol_button "deckcontrol_rewind" "gtk-media-rewind"   "Rewind"    "deckcontrol rewind")
                        $(_get_deckcontrol_button "deckcontrol_prev"   "gtk-media-previous" "Step Back" "deckcontrol stepback")
                        $(_get_deckcontrol_button "deckcontrol_play"   "gtk-media-play"     "Play"      "deckcontrol play")
                        $(_get_deckcontrol_button "deckcontrol_stop"   "gtk-media-stop"     "Stop"      "deckcontrol stop")
                        $(_get_deckcontrol_button "deckcontrol_next"   "gtk-media-next"     "Step Fwd"  "deckcontrol stepforward")
                        $(_get_deckcontrol_button "deckcontrol_ff"     "gtk-media-forward"  "FF"        "deckcontrol fastforward")
                        $(_get_deckcontrol_button "deckcontrol_eject"  ""                   "Eject"     "deckcontrol eject")
                    </hbox>
                </hbox>
            </frame>
        </hbox>
    </vbox>
</frame>
DECKLINK_FORM
)

# Set DV Control variables
if [[ "${OS_TYPE}" = "linux" ]] ; then
        DV_REPACK_CMD=""
        DV_RW_CMD='dvcont rewind '
        DV_PLAY_CMD='dvcont play '
        DV_STOP_CMD='dvcont stop '
        DV_FF_CMD='dvcont ff '
        STATUS_CMD='dvcont status '
    elif [[ "${OS_TYPE}" = "macOS" ]] ; then
        DV_REPACK_CMD='{ dvrescue -cmd ff --foreground; dvrescue -cmd rew; }'
        DV_RW_CMD='dvrescue "device://${DVRESCUE_INPUT_INDEX}" -cmd rew '
        DV_PLAY_CMD='dvrescue "device://${DVRESCUE_INPUT_INDEX}" -cmd play '
        DV_STOP_CMD='dvrescue "device://${DVRESCUE_INPUT_INDEX}" -cmd stop '
        DV_FF_CMD='dvrescue "device://${DVRESCUE_INPUT_INDEX}" -cmd ff '
        STATUS_CMD='dvrescue "device://${DVRESCUE_INPUT_INDEX}" -status 2>&1'
fi

DVRESCUE_INPUT_GUI=$(cat << DVRESCUE_FORM
<frame DVRescue input options>
    <vbox>
        <hbox>
            <hbox space-expand="true">
                $(_gtk_vbox_list "DVRESCUE_INPUT_CHOICE"         "400" "Select a DV Device"           "${DVRESCUE_DEVICES[@]}")
            </hbox>
            <vbox>
                <frame dvpackager options>
                    <hbox>
                        <vbox>
                            <text>
                                <label>Split the output on:</label>
                            </text>
                            <checkbox>
                                $(if [[ ${DVPACKAGER_INSTALLED} != "true" ]] ; then echo "<sensitive>false</sensitive>" ; fi)
                                <label>recording start flags</label>
                                <default>"${DV_RESCUE_OPTION_S}"</default>
                                <variable>DV_RESCUE_OPTION_S</variable>
                            </checkbox>
                            <checkbox>
                                $(if [[ ${DVPACKAGER_INSTALLED} != "true" ]] ; then echo "<sensitive>false</sensitive>" ; fi)
                                <label>recording timestamps jumps</label>
                                <default>"${DV_RESCUE_OPTION_D}"</default>
                                <variable>DV_RESCUE_OPTION_D</variable>
                            </checkbox>
                            <checkbox>
                                $(if [[ ${DVPACKAGER_INSTALLED} != "true" ]] ; then echo "<sensitive>false</sensitive>" ; fi)
                                <label>timecode jumps</label>
                                <default>"${DV_RESCUE_OPTION_T}"</default>
                                <variable>DV_RESCUE_OPTION_T</variable>
                            </checkbox>
                        </vbox>
                        <vbox>
                            <text>
                                <label>Other options:</label>
                            </text>
                            <checkbox>
                                $(if [[ ${DVPACKAGER_INSTALLED} != "true" ]] ; then echo "<sensitive>false</sensitive>" ; fi)
                                <label>Create technical subtitle track</label>
                                <default>"${DV_RESCUE_OPTION_TC}"</default>
                                <variable>DV_RESCUE_OPTION_TC</variable>
                            </checkbox>
                        </vbox>
                        $(_gtk_vbox_list "DV_CONTAINER_CHOICE"         "100" "Select File Format"            "${DV_CONTAINER_OPTIONS[@]}")
                    </hbox>
                </frame>
            </vbox>
        </hbox>
    </vbox>
    <frame DV deck control>
        <hbox>
            <vbox>
                <pixmap><input file>"${RESOURCE_PATH}/dvrecord.png"</input></pixmap>
            </vbox>
            <vbox>
                <hbox>
                    <vbox>
                        <text>
                            <label>Status</label>
                        </text>
                        <entry editable="false" has-frame="false">
                            <variable export="false">dvrescue_status</variable>
                            <input file>"${DVRESCUE_STATUS_TMP}"</input>
                        </entry>
                    </vbox>
                    <timer milliseconds="true" interval="300" visible="false" disabled="true">
                         <variable export="false">dvrescue_timer</variable>
                         <visible>disabled</visible>
                         <action>${STATUS_CMD} > "${DVRESCUE_STATUS_TMP}" &</action>
                         <action>refresh:dvrescue_status</action>
                    </timer>
                    <togglebutton>
                        <label>Deck Control</label>
                        <default>false</default>
                        <variable export="false">dvrescue_toggle</variable>
                        <input file stock="gtk-execute"></input>
                        <action>if true enable:dvrescue_timer</action>
                        <action>if true enable:dvrescue_status</action>
                        <action>if true enable:dvrescue_repack</action>
                        <action>if true enable:dvrescue_rewind</action>
                        <action>if true enable:dvrescue_play</action>
                        <action>if true enable:dvrescue_stop</action>
                        <action>if true enable:dvrescue_ff</action>
                        <action>if false disable:dvrescue_timer</action>
                        <action>if false disable:dvrescue_status</action>
                        <action>if false disable:dvrescue_repack</action>
                        <action>if false disable:dvrescue_rewind</action>
                        <action>if false disable:dvrescue_play</action>
                        <action>if false disable:dvrescue_stop</action>
                        <action>if false disable:dvrescue_ff</action>
                    </togglebutton>
                </hbox>
                <hbox>
                    $(_get_deckcontrol_button "dvrescue_repack" ""                  "Repack" "${DV_REPACK_CMD}")
                    $(_get_deckcontrol_button "dvrescue_rewind" "gtk-media-rewind"  "Rewind" "${DV_RW_CMD}")
                    $(_get_deckcontrol_button "dvrescue_play"   "gtk-media-play"    "Play"   "${DV_PLAY_CMD}")
                    $(_get_deckcontrol_button "dvrescue_stop"   "gtk-media-stop"    "Stop"   "${DV_STOP_CMD}")
                    $(_get_deckcontrol_button "dvrescue_ff"     "gtk-media-forward" "FF"     "${DV_FF_CMD}")
                </hbox>
            </vbox>
        </hbox>
    </frame>
</frame>
DVRESCUE_FORM
)

AUDIO_INPUT_GUI=$(cat << AUDIO_INPUT_FORM
<frame Audio input options>
  <vbox space-expand="true">
    <hbox space-expand="true">
      $(_gtk_vbox_list "AUDIO_DEV_CHOICE"         "-1" "Select an Audio Device"           "${AUDIO_DEVICES[@]}")
      $(_gtk_vbox_list "AUDIO_MODE_CODEC_CHOICE"  "-1" "Select Audio Codec"            "${AUDIO_CODEC_OPTIONS[@]:0:2}")
      $(_gtk_vbox_list "AUDIO_CHANNEL_CHOICE"     "-1" "Select Audio Channels"            "${AUDIO_CHANNEL_CHOICE_OPTIONS[@]}")
      $(_gtk_vbox_list "AUDIO_MODE_SR_CHOICE"     "-1" "Select Sampling Rate"            "${AUDIO_MODE_SR_CHOICE_OPTIONS[@]}")
    </hbox>
  </vbox>
  <vbox space-expand="true">
    <pixmap><input file>"${RESOURCE_PATH}/audio_mode.gif"</input></pixmap>
  </vbox>
</frame>
AUDIO_INPUT_FORM
)

export MAIN_DIALOG='
<window title="Welcome to Vrecord!">
    <vbox shadow-type="0">
        <vbox scrollable="true" width="1080" height="520" shadow-type="0">
            <vbox>
                <hbox homogenous="true" space-expand="true">
                    <button image-position="Top">
                        <label>Record</label>
                        <variable export="false">record_button_main</variable>
                        <width>100</width>
                        <input file>"'"${RESOURCE_PATH}/vrecord_logo.png"'"</input>
                        <action type="exit">record_button</action>
                    </button>
                    <button image-position="Top">
                        <label>Passthrough</label>
                        <width>100</width>
                        <input file>"'"${RESOURCE_PATH}/vrecord_logo_playback.png"'"</input>
                        <action type="exit">passthrough</action>
                    </button>
                    <button image-position="Top">
                        <label>Audio Check</label>
                        <width>100</width>
                        <input file>"'"${RESOURCE_PATH}/vrecord_logo_audio.png"'"</input>
                        <action type="exit">audiopassthrough</action>
                    </button>
                    <button image-position="Top">
                        <label>Edit Settings</label>
                        <width>100</width>
                        <input file>"'"${RESOURCE_PATH}/vrecord_logo_edit.png"'"</input>
                        <action type="show">INPUTSETTINGS</action>
                        <action type="hide">MAIN</action>
                        <action>echo "INPUTSETTINGS" > "'"$STARTUP_VIEW_TMP"'"</action>
                    </button>
                    <button image-position="Top">
                        <label>Help</label>
                        <width>100</width>
                        <input file>"'"${RESOURCE_PATH}/vrecord_logo_help.png"'"</input>
                        <action>man vrecord</action>
                    </button>
                    <button image-position="Top">
                        <label>Documentation</label>
                        <width>100</width>
                        <input file>"'"${RESOURCE_PATH}/vrecord_logo_documentation.png"'"</input>
                        <action>"'"${OPEN_COMMAND} https://github.com/amiaopensource/vrecord#vrecord-documentation"'"</action>
                    </button>
                </hbox>
            </vbox>
            <vbox space-expand="true">
                <frame Settings Summary>
                    <vbox scrollable="true" height="320">
                        <text wrap="false" xalign="0">
                            <variable export="false">VRECORD_SETTINGS_SUMMARY</variable>
                            <input>_get_summary</input>
                        </text>
                    </vbox>
                </frame>
            </vbox>
            <variable export="false">MAIN</variable>
            <action signal="show" type="refresh">VRECORD_SETTINGS_SUMMARY</action>
        </vbox>
        <vbox scrollable="true" width="1420" height="520" shadow-type="0">
            <frame Input Options>
            <notebook page="'"${DEVICE_INPUT_CHOICE}"'" tab-labels="Decklink|DV|Audio|Config">
                '"${DECKLINK_INPUT_GUI}"'
                '"${DVRESCUE_INPUT_GUI}"'
                '"${AUDIO_INPUT_GUI}"'
                '"${OPTIONAL_TOOLS_GUI}"'
                <variable>DEVICE_INPUT_CHOICE</variable>
                <action signal="button-release-event" type="refresh">VRECORD_OUTPUT_NAME</action>
                <action signal="button-release-event" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" != 3 -a -n \"${ID}\" ] && echo true)">enable:record_button</action>
                <action signal="button-release-event" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" =  3 -o -z \"${ID}\" ] && echo true)">disable:record_button</action>
                <action signal="button-release-event" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" != 3 -a -n \"${ID}\" ] && echo true)">enable:record_button_main</action>
                <action signal="button-release-event" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" =  3 -o -z \"${ID}\" ] && echo true)">disable:record_button_main</action>
                <action signal="button-release-event" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" != 3 ] && echo true)">enable:passthrough_button</action>
                <action signal="button-release-event" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" =  3 ] && echo true)">disable:passthrough_button</action>
            </notebook>
        </frame>
        <variable export="false">INPUTSETTINGS</variable>
    </vbox>
    <vbox>
        <hbox>
            <frame Select a recording directory>
                <hbox>
                    <entry accept="directory" fs-title="'"${DIR_SELECTION_DIALOG}"'">
                        <variable>DIR</variable>
                        <default>'"${DIR:-\"\"}"'</default>
                        <action signal="key-release-event" type="refresh">VRECORD_OUTPUT_NAME</action>
                    </entry>
                    <button>
                        <input file stock="gtk-open"></input>
                        <variable export="false">DIRBROWSE</variable>
                        <action type="fileselect">DIR</action>
                    </button>
                </hbox>
            </frame>
            <frame Select a directory for auxiliary files (leave blank to match the recording directory).>
                <hbox>
                    <entry accept="directory" tooltip-text="select the directory for automatically generated logs and checksums"  \fs-title="'"${DIR_SELECTION_DIALOG}"'">
                        <variable>LOGDIR</variable>
                        <default>'"${LOGDIR:-\"\"}"'</default>
                    </entry>
                    <button>
                        <input file stock="gtk-open"></input>
                        <variable export="false">LOGDIRBROWSE</variable>
                        <action type="fileselect">LOGDIR</action>
                    </button>
                </hbox>
            </frame>
            <entry visible="false">
                <variable>STARTUP_VIEW</variable>
                <default>'"${STARTUP_VIEW:-MAIN}"'</default>
                <input file>'"${STARTUP_VIEW_TMP}"'</input>
                <action type="refresh">STARTUP_VIEW</action>
            </entry>
        </hbox>
        <hbox>
            <frame Recording event options>
                <hbox space-expand="true">
                    <vbox>
                        <text>
                            <label>Name of Recording</label>
                        </text>
                        <entry>
                            <default>"'"${ID}"'"</default>
                            <variable>ID</variable>
                            <action signal="key-release-event" type="refresh">VRECORD_OUTPUT_NAME</action>
                            <action signal="key-release-event" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" != 3 -a -n \"${ID}\" ] && echo true)">enable:record_button</action>
                            <action signal="key-release-event" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" =  3 -o -z \"${ID}\" ] && echo true)">disable:record_button</action>
                            <action signal="key-release-event" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" != 3 -a -n \"${ID}\" ] && echo true)">enable:record_button_main</action>
                            <action signal="key-release-event" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" =  3 -o -z \"${ID}\" ] && echo true)">disable:record_button_main</action>
                            <action signal="key-release-event" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" != 3 ] && echo true)">enable:passthrough_button</action>
                            <action signal="key-release-event" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" =  3 ] && echo true)">disable:passthrough_button</action>
                        </entry>
                    </vbox>
                    <vbox>
                        <text>
                            <label>Name of the person digitizing this tape.</label>
                        </text>
                        <entry>
                            <default>"'"${TECHNICIAN}"'"</default>
                            <variable>TECHNICIAN</variable>
                        </entry>
                    </vbox>
                    <vbox>
                        <text>
                            <label>Recording time in minutes</label>
                        </text>
                        <entry activates_default="true" tooltip-text="Suggested:23 33 63 93. Leave blank for indefinite recording time">
                            <default>"'"${DURATION}"'"</default>
                            <variable>DURATION</variable>
                        </entry>
                    </vbox>
                </hbox>
            </frame>
            <frame File naming options>
                <hbox space-expand="true">
                    <vbox>
                        <text>
                            <label>Optional filename prefix</label>
                        </text>
                        <entry>
                            <default>"'"${PREFIX}"'"</default>
                            <variable>PREFIX</variable>
                            <action signal="key-release-event" type="refresh">VRECORD_OUTPUT_NAME</action>
                        </entry>
                    </vbox>
                    <vbox>
                        <text>
                            <label>Optional filename suffix</label>
                        </text>
                        <entry>
                            <default>"'"${USER_SUFFIX}"'"</default>
                            <variable>USER_SUFFIX</variable>
                            <action signal="key-release-event" type="refresh">VRECORD_OUTPUT_NAME</action>
                        </entry>
                    </vbox>
                    <vbox>
                        <checkbox>
                            <label>Enable suffixes</label>
                            <default>"'"${YES_SUFFIX}"'"</default>
                            <variable>YES_SUFFIX</variable>
                            <action signal="key-release-event" type="refresh">VRECORD_OUTPUT_NAME</action>
                        </checkbox>
                    </vbox>
                </hbox>
            </frame>
        </hbox>
        <vbox>
            <hbox>
                <text>
                    <label>Output Filename:</label>
                </text>
                <entry editable="false" has-frame="false">
                    <variable>VRECORD_OUTPUT_NAME</variable>
                    <input>_get_output_filename</input>
                </entry>
            </hbox>
            <hbox>
                <text>
                    <label>Errors & Warnings:</label>
                </text>
                <vbox scrollable="true" height="28">
                    <text wrap="false" xalign="0" selectable="true">
                        <variable export="false">VRECORD_FORM_VALIDATION</variable>
                        <input>_validate_form</input>
                    </text>
                </vbox>
            </hbox>
        </vbox>
    </vbox>
        <hbox space-expand="false" space-fill="false">
            <button>
                <label>Home</label>
                <input file stock="gtk-index"></input>
                <variable export="false">home_button</variable>
                <action>_update_config_file</action>
                <action type="show">MAIN</action>
                <action type="hide">INPUTSETTINGS</action>
                <action>echo "MAIN" > "'"$STARTUP_VIEW_TMP"'"</action>
                <action type="refresh">STARTUP_VIEW</action>
            </button>
            <button>
                <label>Settings</label>
                <input file stock="gtk-index"></input>
                <variable export="false">settings_button</variable>
                <action>_update_config_file</action>
                <action type="show">INPUTSETTINGS</action>
                <action type="hide">MAIN</action>
                <action>echo "INPUTSETTINGS" > "'"$STARTUP_VIEW_TMP"'"</action>
                <action type="refresh">STARTUP_VIEW</action>
            </button>
            <hbox space-expand="true" space-fill="true"><text><label>""</label></text></hbox>
            <button>
                <label>Record</label>
                <input file stock="gtk-media-record"></input>
                <variable export="false">record_button</variable>
                <action>_update_config_file</action>
                <action type="exit">record</action>
            </button>
            <button>
                <label>Passthrough</label>
                <input file stock="gtk-media-play"></input>
                <variable export="false">passthrough_button</variable>
                <action>_update_config_file</action>
                <action type="exit">passthrough</action>
            </button>
            <button>
                <label>Save Settings</label>
                <input file stock="gtk-save"></input>
                <variable export="false">save_button</variable>
                <action>_update_config_file</action>
            </button>
            <button cancel>
            </button>
            <button>
                <label>Refresh</label>
                <input file stock="gtk-refresh"></input>
                <action>_update_config_file</action>
                <action type="exit">refresh</action>
            </button>
        </hbox>
    </vbox>
    <variable export="false">MAIN_DIALOG</variable>
    <action signal="realize" type="show">MAIN</action>
    <action signal="realize" type="hide">INPUTSETTINGS</action>
    <action signal="realize" condition="command_is_true( [ \"$STARTUP_VIEW\" = \"INPUTSETTINGS\" ] && echo true)" type="show">INPUTSETTINGS</action>
    <action signal="realize" condition="command_is_true( [ \"$STARTUP_VIEW\" = \"INPUTSETTINGS\" ] && echo true)" type="hide">MAIN</action>
    <action signal="show" type="refresh">VRECORD_FORM_VALIDATION</action>
    <action signal="enter-notify-event" type="refresh">VRECORD_FORM_VALIDATION</action>
    <action signal="leave-notify-event" type="refresh">VRECORD_FORM_VALIDATION</action>
    <action signal="show" type="refresh">VRECORD_OUTPUT_NAME</action>
    <action signal="show" condition="command_is_true(echo \"$AUDIO_DEV_CHOICE\" | grep -vq Blackmagic && echo true)">enable:AUDIO_MODE_SR_CHOICE</action>
    <action signal="show" condition="command_is_true(echo \"$AUDIO_DEV_CHOICE\" | grep -q Blackmagic && echo true)">disable:AUDIO_MODE_SR_CHOICE</action>
    <action signal="show" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" != 3 -a -n \"${ID}\" ] && echo true)">enable:record_button</action>
    <action signal="show" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" =  3 -o -z \"${ID}\" ] && echo true)">disable:record_button</action>
    <action signal="show" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" != 3 -a -n \"${ID}\" ] && echo true)">enable:record_button_main</action>
    <action signal="show" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" =  3 -o -z \"${ID}\" ] && echo true)">disable:record_button_main</action>
    <action signal="show" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" != 3 ] && echo true)">enable:passthrough_button</action>
    <action signal="show" condition="command_is_true( [ \"${DEVICE_INPUT_CHOICE}\" =  3 ] && echo true)">disable:passthrough_button</action>
</window>
'
}

# edit mode
_edit_mode(){
    _set_up_edit_form

    # run the edit form in gtkdialog
    MAIN_DIALOG_TMP="${MAIN_DIALOG}"

    GTK_INC="$(_maketemp .vrecord.gtkdialog.inc)"
    cat "${VRECORD_VARS_FILE}" > "${GTK_INC}"
    echo "CONFIG_FILE=${CONFIG_FILE}" >> "${GTK_INC}"
    cat "${SHARED_FUNCTIONS_FILE}" >> "${GTK_INC}"

    if [[ "${VERBOSE_GTKDIALOG}" = "Y" ]] ; then
        eval "$("${GTKDIALOGBIN}" --include="${GTK_INC}" --program MAIN_DIALOG --center)"
    else
        eval "$("${GTKDIALOGBIN}" --include="${GTK_INC}" --program MAIN_DIALOG --center 2> /dev/null)"
    fi
    MAIN_DIALOG="${MAIN_DIALOG_TMP}"

    # process the results of the edit form
    if   [[ "${EXIT}" = "abort" ]] ; then
        _report -d "Exiting Vrecord. Goodbye!"
        exit 0
    elif [[ "${EXIT}" = "Cancel" ]] ; then
        _report -d "Editing of preferences was canceled by the user."
        _report -d "Exiting Vrecord. Goodbye!"
        exit 0
    elif [[ "${EXIT}" = "record" ]] ; then
        RUNTYPE="record"
    elif [[ "${EXIT}" = "passthrough" ]] ; then
        RUNTYPE="passthrough"
    elif [[ "${EXIT}" = "audiopassthrough" ]] ; then
        RUNTYPE="audiopassthrough"
    elif [[ "${EXIT}" = "refresh" ]] ; then
        RUNTYPE="edit"
    elif [[ "${EXIT}" = "timecode_scan" ]] ; then
        _report -dt "Scanning each supported type of timecode."
        _review_all_options
        _report -dt "Note: some types of timecode are only supported if the video input is set to 'sdi' (currently the video input is set to '${VIDEO_INPUT}')."
        _setup_vrecord_input
        echo "Timecode Type | Timecode Value"
        echo "--------------|---------------"
        for timecode_type in "${TIMECODE_OPTIONS[@]}" ; do
            tc_value="$("${FFMPEG_BIN}" -timecode_format "${timecode_type}" "${GRAB_INPUT[@]}" -loglevel info 2>&1 | grep " timecode " | cut -d ":" -f2- | sed 's/ //g')"
            printf "  %-11s | %-12s \n" "${timecode_type}" "${tc_value:-none}"
        done
        echo "--------------|---------------"
        RUNTYPE="edit"
        unset MIDDLEOPTIONS_ALL MIDDLEOPTIONS_PRES RECORDINGFILTER AUDIO_CHANNEL_MAP
    elif [[ "${EXIT}" = "env_reset" ]] ; then
        _remove_env_vars
        _process_vars_for_gtk
        RUNTYPE="edit"
    else
        _report_unexpected_error EXIT
    fi
}

# passthrough and audiopassthrough modes
_passthrough_mode(){
    _setup_vrecord_process
    if [[ "${VERBOSE_GTKDIALOG}" = "Y" ]] ; then
        echo "RUNTYPE ${RUNTYPE}"
        echo "STEPS ${VRECORD_STEPS}"
        echo "PLAY ${PLAYER_COMMAND[@]}"
        echo "RECORD ${RECORD_COMMAND[@]}"
    fi

    if [[ "${PLAYBACKVIEW_CHOICE_PASS}" == "Captions" ]] && [[ "${RUNTYPE}" == "passthrough" ]] ; then
        "${SCRIPTDIR}/cchex_to_display" "${FFREPORT_TMP}" "${CAP_DISPLAY_TMP}" > /dev/null 2> /dev/null &
        CC_PID=$!
        export FFREPORT="file=${FFREPORT_TMP}:level=32"
    fi
    if [[ "${VRECORD_STEPS}" = "1" ]] ; then
        "${PLAYER_COMMAND[@]}" 2> "${VRECORD_INPUT_TMP}"
    elif [[ "${VRECORD_STEPS}" = "2" ]] ; then
        "${RECORD_COMMAND[@]}" 2> "${VRECORD_INPUT_TMP}" | "${PLAYER_COMMAND[@]}"
    fi
    if [[ "${PLAYBACKVIEW_CHOICE_PASS}" == "Captions" ]] && [[ "${RUNTYPE}" == "passthrough" ]] ; then
        kill "$CC_PID"
    fi
}

_audiopassthrough_mode(){
    if [[ "${DEVICE_INPUT_CHOICE}" = 2 ]] ; then
        _passthrough_mode
    else
        PLAYBACKVIEW_CHOICE_PASS="Audio + Video"
        _lookup_choice "Audio + Video"
        _passthrough_mode
    fi
}

# create a capture log of decisions made in vrecord
_writeingestlog(){
    if [[ "${INGESTLOG}" ]] ; then
        KEY="${1}"
        shift
        VALUE="${@}"
        # need to add yaml style escaping
        echo "${KEY}: ${VALUE}" >> "${INGESTLOG}"
    else
        _report -wt "The _writeingestlog function was called, but the ingestlog file (${INGESTLOG}) is not declared."
    fi
}

# create a jpeg of qc data graphs for quick assessment
_qcgraphimage(){
    # get audio data
    qctools_CONFIGFILE_A="$(_maketemp .astats_A.csv)"
    "${ZCAT_COMMAND}" "$1" | perl -nle 'print if not m{lavfi.(?!astats.Overall.Min_level|astats.Overall.Max_level|astats.Overall.Peak_level|aphasemeter.phase)}' | xmlstarlet select -t -m "//ffprobe:ffprobe/frames/frame[@media_type='audio']" \
       -v "@pkt_pts_time" -o " " \
       -v "tag[@key='lavfi.astats.Overall.Max_level']/@value" -o " " \
       -v "tag[@key='lavfi.astats.Overall.Min_level']/@value" -o " " \
       -v "tag[@key='lavfi.astats.Overall.Peak_level']/@value" -o " " \
       -v "tag[@key='lavfi.aphasemeter.phase']/@value" -n > "${qctools_CONFIGFILE_A}"
    # get video data
    qctools_CONFIGFILE_V="$(_maketemp .signalstats.V.csv)"
    "${ZCAT_COMMAND}" "$1" | perl -nle 'print if not m{lavfi.(?!signalstats.BRNG|signalstats.TOUT|signalstats.SATMAX|signalstats.SATAVG|ssim.Y|ssim.U|ssim.V)}' | xmlstarlet select -t -m "//ffprobe:ffprobe/frames/frame[@media_type='video']" \
       -v "@pkt_pts_time" -o " " \
       -v "tag[@key='lavfi.signalstats.TOUT']/@value" -o " " \
       -v "tag[@key='lavfi.signalstats.BRNG']/@value" -o " " \
       -v "tag[@key='lavfi.signalstats.SATMAX']/@value" -o " " \
       -v "tag[@key='lavfi.signalstats.SATAVG']/@value" -o " " \
       -v "tag[@key='lavfi.ssim.Y']/@value" -o " " \
       -v "tag[@key='lavfi.ssim.U']/@value" -o " " \
       -v "tag[@key='lavfi.ssim.V']/@value" -n > "${qctools_CONFIGFILE_V}"

    # determine SATURATION scale
    VBitdepth="$("${ZCAT_COMMAND}" "$1" | perl -nle 'print if not m{<frame |</frame>|<tag}' | xmlstarlet sel -t -v "//stream[@codec_type='video']/@pix_fmt" -n)"
    if [[ "${VBitdepth}" = "yuv422p10le" ]] ; then
        SATpalette="(0'#a0a0a0',80'#bebebe',177.4'#c8c800',322'#a0ff20',354.8'#00ff00',413.8'#006400',433.46'#00ff00',453.13'#a0ff20',472.8'#ffa500',496'#ff0000')"
        SATcbrange="[0:496]"
        SATyrange="[0:725]"
    else
        SATpalette="(0'#a0a0a0',20'#bebebe',44.35'#c8c800',80'#a0ff20',88.7'#00ff00',103.45'#006400',108.2'#00ff00',113.2'#a0ff20',118.2'#ffa500',124'#ff0000')"
        SATcbrange="[0:124]"
        SATyrange="[0:183]"
    fi

    echo "set terminal jpeg size 1920, 1080
    set output '${LOGDIR}/${FULL_OUTPUT_ID}_QC_output_graphs.jpeg'
    set term jpeg font 'times,12'
    set multiplot layout 7, 1 title '${ID} QC Data Graphs (ver.2)' margins screen .05,.93, .05, .93 spacing screen 0, char .7
    set style line 11 lc rgb '#808080' lt 1
    set border 15 back ls 11
    set format x '%tH:%tM:%.1tS' time
    set format x2 '%tH:%tM:%.1tS' time
    set x2tics border out nomirror
    set xtics border mirror in scale 1.5,.7 format ''
    set ytics border out nomirror font 'times,10'
    set grid y
    set grid x
    set grid mxtics
    set colorbox vertical back user origin graph 1.01,0 size char 1,6
    set cbtics font 'times,10'
    set key inside right top reverse samplen .00
    unset key
    set yrange [-1.:1]
    set palette model RGB defined (-0.8'#ff0000',-0.6'#ffa500',-0.4'#a0ff20',-0.2'#00ff00',0'#006400',0.2'#00ff00',0.4'#a0ff20',.6'#ffa500',0.8'#ff0000') maxcolors 128
    set cbrange [-1.:1.]
    set style fill solid
    set label 1 'Min/Max Level' at graph .5,.9 center front
    plot '${qctools_CONFIGFILE_A}' using 1:2:2 with boxes palette title 'Max Level', '' using 1:3:3 with boxes palette title 'Min Level'
    unset cbrange
    unset x2tics
    set yrange [-70:0]
    set cbrange [0:-50.]
    set palette model RGB defined (-50'#006400',-35'#00ff00',-15'#a0ff20',-5'#ffa500',-0.5'#ff0000') maxcolors 128
    set style line 15 linecolor palette lw 4
    set label 1 'Peak Level (dB)' at graph .5,.9 front
    plot '' using 1:4:4 with lines ls 15 title 'Peak Level (dB)'
    unset yrange
    unset cbrange
    set palette model RGB defined (-0.8'#ff0000',-0.6'#ffa500',-0.4'#a0ff20',0'#00ff00',1'#006400') maxcolors 128
    set cbrange [-0.8:1]
    set yrange [-1:1]
    set style line 25 linecolor palette lw 4
    set label 1 'Audio Phase' at graph .5,.9 front
    plot '' using 1:5:5 with lines ls 25 title 'Audio Phase'
    unset yrange
    unset cbrange
    set palette model RGB defined (0'#006400',0.01'#00ff00',0.02'#fffb20',.04'#ffa500',0.05'#ff0000') maxcolors 128
    set cbrange [0:.05]
    set yrange [0:.1]
    set label 1 '% Outside of Broadcast Range' at graph .5,.9 front
    plot '${qctools_CONFIGFILE_V}' using 1:3:3 with boxes palette title '% Outside of Broadcast Range'
    unset yrange
    set style line 10 linecolor '#804080' lw 2
    set label 1 '% Temporal OUTliers' at graph .5,.9 front
    plot '' using 1:2 with lines ls 10 title '% Temporal OUTliers'
    unset yrange
    unset cbrange
    set style line 1 linecolor '#f03232' lw 2
    set style line 2 linecolor '#006400' lw 2
    set style line 3 linecolor '#00ff00' lw 2
    set style line 4 linecolor '#f03232' lw 2
    set style line 5 linecolor '#000000' lw 2
    set style line 6 linecolor '#00008b' lw 2
    set yrange ${SATyrange}
    set palette model RGB defined ${SATpalette} maxcolors 128
    set cbrange ${SATcbrange}
    unset label
    set key at graph 1.06,.5 center vertical Left noopaque noreverse font 'times,9'
    set label 1 'Saturation Level' at graph .5,.9 center front
    plot '' using 1:4:4 with boxes palette title 'SatMax', '' using 1:5 with lines ls 5 title 'SatAvg'
    unset yrange
    unset cbrange
    unset xtics
    unset key
    set key at graph 1.06,.5 right vertical Right noopaque noreverse
    set x2tics border mirror in scale 1.5,.7 format ''
    set xtics border out nomirror format '%tH:%tM:%.1tS' time
    set label 1 'Structural SImilarity Metric' at graph .5,.1 center front
    plot '' using 1:6 with lines ls 5 title 'SSIM-Y', '' using 1:7 with lines ls 2 title 'SSIM-U', '' using 1:8 with lines ls 6 title 'SSIM-V'
    " | gnuplot
}

_dvpackager(){
    _report -d "Please wait: running dvpackager on file."
    local TARGET="${1}"
    dvpackager ${DV_RESCUE_OPTS[@]} -e "${DV_EXTENSION}" "${TARGET}"
}

_set_some_params(){
    if [[ "${SIGNAL_INPUT}" = 'true' ]] ; then
        SET_FIELD_MODE="${SIG_INTERLACEMENT}"
    else
        SET_FIELD_MODE="${SIGNAL_INT_CHOICE:-auto}"
    fi
    if [[ "${SIGNAL_VIEW_CHOICE}" == "Full Range" ]] ; then
        SET_RANGE="full"
    else
        SET_RANGE="limited"
    fi
}

# decipher vrecord options as specified by user
_lookup_choice(){
    case "${2}" in
        "quit"|"Quit"|"QUIT"|"q"|"Q") _report -dt "Bye." ; exit ;;
    esac
    case "${1}" in
        # video inputs
        "Composite") VIDEO_INPUT="composite" ;;
        "SDI")       VIDEO_INPUT="sdi" ;;
        "Component") VIDEO_INPUT="component" ;;
        "S-Video")   VIDEO_INPUT="s_video" ;;

        # audio inputs
        "Analog")                  AUDIO_INPUT="analog" ;;
        "SDI Embedded Audio")      AUDIO_INPUT="embedded" ;;
        "Digital Audio (AES/EBU)") AUDIO_INPUT="aes_ebu" ;;

        # container
        "QuickTime")
            _add_mediaconch_rule_set "${CONTAINER_QUICKTIME_TEST}"
            EXTENSION="mov"
            DV_EXTENSION="mov"
            MIDDLEOPTIONS_PRES+=(-movflags write_colr)
            FORMAT="mov" ;;
        "Matroska")
            _add_mediaconch_rule_set "${CONTAINER_MATROSKA_TEST}"
            EXTENSION="mkv"
            DV_EXTENSION="mkv"
            FORMAT="matroska" ;;
        "AVI")
            EXTENSION="avi"
            FORMAT="avi" ;;
        "MXF")
            EXTENSION="mxf"
            FORMAT="mxf" ;;
        "MP4")
            EXTENSION="mp4"
            MIDDLEOPTIONS_PRES+=(-movflags write_colr)
            FORMAT="mp4" ;;
        "DV")
            EXTENSION="dv"
            DV_EXTENSION="dv" ;;

        # video codec
        "Uncompressed Video")
            _add_mediaconch_rule_set "${CODEC_UNCOMPRESSED_TEST}"
            if [[ "${PIXEL_FORMAT}" = "yuv422p10" ]] ; then
                VIDEOCODECNAME="Uncompressed 10-bit 4:2:2"
                MIDDLEOPTIONS_PRES+=(-c:v v210)
            elif [[ "${PIXEL_FORMAT}" = "uyvy422" ]] ; then
                VIDEOCODECNAME="Uncompressed 8-bit 4:2:2"
                MIDDLEOPTIONS_PRES+=(-c:v rawvideo -pix_fmt uyvy422 -tag:v 2vuy)
            fi ;;
        "FFV1 version 3")
            _add_mediaconch_rule_set "${CODEC_FFV1_TEST}"
            VIDEOCODECNAME="FFV1 version 3"
            MIDDLEOPTIONS_PRES+=(-c:v ffv1 -level 3 -g 1 -slices "${FFV1_SLICE_CHOICE}" -slicecrc 1)
            SUFFIX="_ffv1" ;;
        "JPEG2000")
            VIDEOCODECNAME="JPEG2000"
            MIDDLEOPTIONS_PRES+=(-c:v libopenjpeg)
            SUFFIX="_j2k" ;;
        "ProRes")
            VIDEOCODECNAME="Apple ProRes 422"
            MIDDLEOPTIONS_PRES+=(-c:v prores_ks -flags +ildct -profile:v 2)
            SUFFIX="_prores" ;;
        "ProRes (HQ)")
            VIDEOCODECNAME="Apple ProRes 422 HQ"
            MIDDLEOPTIONS_PRES+=(-c:v prores_ks -flags +ildct -profile:v 3)
            SUFFIX="_prores" ;;
        "h264")
            VIDEOCODECNAME="H.264"
            MIDDLEOPTIONS_PRES+=(-c:v h264 -pix_fmt yuv420p)
            SUFFIX="_h264" ;;
        "HuffYUV")
            VIDEOCODECNAME="HuffYUV"
            if [[ "${PIXEL_FORMAT}" = "yuv422p10" ]] ; then
                MIDDLEOPTIONS_PRES+=(-c:v ffvhuff -pix_fmt yuv422p10le -pred median -context 1)
            elif [[ "${PIXEL_FORMAT}" = "uyvy422" ]] ; then
                MIDDLEOPTIONS_PRES+=(-c:v ffvhuff -pix_fmt yuv422p -pred median -context 1)
            fi
            SUFFIX="_huff" ;;

        # video pixel format and bit depth
        "10 bit") PIXEL_FORMAT="yuv422p10" ;;
        "8 bit")  PIXEL_FORMAT="uyvy422" ;;

        # audio codec
        "24-bit PCM")
            MIDDLEOPTIONS_PRES+=(-c:a pcm_s24le)
            AUDIO_EXT='wav' ;;
        "24-bit FLAC")
            MIDDLEOPTIONS_PRES+=(-c:a flac)
            MIDDLEOPTIONS_PRES+=(-sample_fmt s32)
            MIDDLEOPTIONS_PRES+=(-bits_per_raw_sample:a 24)
            AUDIO_EXT='flac' ;;
        "AAC")
            MIDDLEOPTIONS_PRES+=(-c:a aac) ;;

        # audio mappings
        "2 Stereo Tracks (Channels 1 & 2 -> 1st Track Stereo, Channels 3 & 4 -> 2nd Track Stereo)")
            AUDIOMAP="[0:a:0]asplit[orig],pan=stereo| c0=c0 | c1=${PHASE_VALUE_2}c1[stereo1];[0:a:0]pan=stereo| c0=c2 | c1=${PHASE_VALUE_4}c3[stereo2]"
            AUDIO_PLAY_MAP="pan=4c|c0=c0|c1=${PHASE_VALUE_2}c1|c2=c2|c3=${PHASE_VALUE_4}c3"
            AUDIO_PLAY_LABELS=",drawtext=fontfile=${DEFAULTFONT}:text='L(1)':fontcolor=white:fontsize=18:x=0:y=0,drawtext=fontfile=${DEFAULTFONT}:text='R(1)':fontcolor=white:fontsize=18:x=0:y=20,drawtext=fontfile=${DEFAULTFONT}:text='L(2)':fontcolor=white:fontsize=18:x=0:y=40,drawtext=fontfile=${DEFAULTFONT}:text='R(2)':fontcolor=white:fontsize=18:x=0:y=60"
            AUDIO_CHANNEL_MAP+=(-map "[orig]")
            AUDIO_CHANNEL_MAP+=(-map "[stereo1]")
            AUDIO_CHANNEL_MAP+=(-map "[stereo2]")
            AUDIO_TEE_SELECT_MAP="a\\\\:1,a\\\\:2" ;;
        "1 Stereo Track (From Channels 1 & 2)")
            AUDIOMAP="[0:a:0]asplit[orig],pan=stereo| c0=c0 | c1=${PHASE_VALUE_2}c1[stereo1]"
            AUDIO_PLAY_MAP="pan=stereo|c0=c0|c1=${PHASE_VALUE_2}c1"
            AUDIO_PLAY_LABELS=",drawtext=fontfile=${DEFAULTFONT}:text='L(1)':fontcolor=white:fontsize=18:x=0:y=0,drawtext=fontfile=${DEFAULTFONT}:text='R(1)':fontcolor=white:fontsize=18:x=0:y=20"
            AUDIO_CHANNEL_MAP+=(-map "[orig]")
            AUDIO_CHANNEL_MAP+=(-map "[stereo1]")
            AUDIO_TEE_SELECT_MAP="a\\\\:1" ;;
        "1 Stereo Track (From Channels 3 & 4)")
            AUDIOMAP="[0:a:0]asplit[orig],pan=stereo| c0=c2 | c1=${PHASE_VALUE_2}c3[stereo1]"
            AUDIO_PLAY_MAP="pan=stereo|c0=c2|c1=${PHASE_VALUE_2}c3"
            AUDIO_PLAY_LABELS=",drawtext=fontfile=${DEFAULTFONT}:text='L(1)':fontcolor=white:fontsize=18:x=0:y=40,drawtext=fontfile=${DEFAULTFONT}:text='R(1)':fontcolor=white:fontsize=18:x=0:y=60"
            AUDIO_CHANNEL_MAP+=(-map "[orig]")
            AUDIO_CHANNEL_MAP+=(-map "[stereo1]")
            AUDIO_TEE_SELECT_MAP="a\\\\:1" ;;
        "Channel 1 -> 1st Track Mono, Channel 2 -> 2nd Track Mono")
            AUDIOMAP="[0:a:0]asplit[orig],pan=mono| c0=c0[mono1];[0:a:0]pan=mono| c0=${PHASE_VALUE_2}c1[mono2]"
            AUDIO_PLAY_MAP="pan=stereo|c0=c0|c1=${PHASE_VALUE_2}c1"
            AUDIO_PLAY_LABELS=",drawtext=fontfile=${DEFAULTFONT}:text='M(1)':fontcolor=white:fontsize=18:x=0:y=0,drawtext=fontfile=${DEFAULTFONT}:text='M(2)':fontcolor=white:fontsize=18:x=0:y=20"
            AUDIO_CHANNEL_MAP+=(-map "[orig]")
            AUDIO_CHANNEL_MAP+=(-map "[mono1]")
            AUDIO_CHANNEL_MAP+=(-map "[mono2]")
            AUDIO_TEE_SELECT_MAP="a\\\\:1,a\\\\:2" ;;
        "Channel 2 -> 1st Track Mono, Channel 1 -> 2nd Track Mono")
            AUDIOMAP="[0:a:0]asplit[orig],pan=mono| c0=${PHASE_VALUE_2}c1[mono1];[0:a:0]pan=mono| c0=c0[mono2]"
            AUDIO_PLAY_MAP="pan=stereo|c0=${PHASE_VALUE_2}c1|c1=c0"
            AUDIO_PLAY_LABELS=",drawtext=fontfile=${DEFAULTFONT}:text='M(2)':fontcolor=white:fontsize=18:x=0:y=0,drawtext=fontfile=${DEFAULTFONT}:text='M(1)':fontcolor=white:fontsize=18:x=0:y=20"
            AUDIO_CHANNEL_MAP+=(-map "[orig]")
            AUDIO_CHANNEL_MAP+=(-map "[mono1]")
            AUDIO_CHANNEL_MAP+=(-map "[mono2]")
            AUDIO_TEE_SELECT_MAP="a\\\\:1,a\\\\:2" ;;
        "Channel 1 -> Single Track Mono")
            AUDIOMAP="[0:a:0]asplit[orig],pan=mono| c0=c0[mono1]"
            AUDIO_PLAY_MAP="pan=mono| c0=c0"
            AUDIO_PLAY_LABELS=",drawtext=fontfile=${DEFAULTFONT}:text='M(1)':fontcolor=white:fontsize=18:x=0:y=0"
            AUDIO_CHANNEL_MAP+=(-map "[orig]")
            AUDIO_CHANNEL_MAP+=(-map "[mono1]")
            AUDIO_TEE_SELECT_MAP="a\\\\:1" ;;
        "Channel 2 -> Single Track Mono")
            AUDIOMAP="[0:a:0]asplit[orig],pan=mono| c0=c1[mono1]"
            AUDIO_PLAY_MAP="pan=mono| c0=c1"
            AUDIO_PLAY_LABELS=",drawtext=fontfile=${DEFAULTFONT}:text='M(1)':fontcolor=white:fontsize=18:x=0:y=20"
            AUDIO_CHANNEL_MAP+=(-map "[orig]")
            AUDIO_CHANNEL_MAP+=(-map "[mono1]")
            AUDIO_TEE_SELECT_MAP="a\\\\:1" ;;
        # Audio mode channel options
        "Mono")
            AUDIOMAP="[0:a:0]pan=mono| c0=c0[mono1]"
            PASSTHROUGH_MAP="pan=mono|c0=c0"
            AUDIO_CHANNEL_MAP+=(-map "[mono1]") ;;
        "Stereo")
            AUDIOMAP="[0:a:0]pan=stereo| c0=c0 | c1=${PHASE_VALUE_2}c1[stereo1]"
            PASSTHROUGH_MAP="pan=stereo|c0=c0|c1=${PHASE_VALUE_2}c1"
            AUDIO_CHANNEL_MAP+=(-map "[stereo1]") ;;
        # Audio mode sample rate options
        "96 kHz")
            S_RATE='-ar 96k'
            MIDDLEOPTIONS_PRES+=(${S_RATE}) ;;
        "48 kHz")
            S_RATE='-ar 48k'
            MIDDLEOPTIONS_PRES+=(${S_RATE}) ;;
        "44.1 kHz")
            S_RATE='-ar 44.1k'
            MIDDLEOPTIONS_PRES+=(${S_RATE}) ;;
        # timecode options
        "none"|"rp188vitc"|"rp188vitc2"|"rp188ltc"|"rp188any"|"vitc"|"vitc2"|"serial")
            TC_TYPE="${1}"
            TC_INPUT_OPTION=(-timecode_format "${TC_TYPE}")
            MIDDLEOPTIONS_PRES+=(-map_metadata 0:s:v:0)
            if [[ "${TC_TYPE}" != "none" ]] ; then
                if [[ "${RUNTYPE}" = "passthrough" ]] ; then
                TIMECODE_OVERLAY=",drawtext=fontfile=${DEFAULTFONT}:x=(w-text_w)*0.5:y=(h-text_h)*0.75:fontcolor=white:box=1:boxcolor=gray@0.7:boxborderw=4:fontsize=22:shadowx=1:shadowy=1:text=%{metadata\\\:timecode\\\:no ${TC_TYPE} timecode}"
                fi
                TC_TMP=$(_maketemp .timecode.txt)
                TC_WRITE=",metadata=mode=print:file=${TC_TMP}"
            fi
            declare TC_TYPE "${TC_TYPE}"
            ;;
        # video standard
        "NTSC")
            STANDARD="ntsc"
            DECKLINK_FPS="30000/1001"
            SIG_GEN_SIZE="720x486"
            SIG_INTERLACEMENT="bff"
            if [[ "${VIDEO_CODEC_CHOICE}" = "h264" ]] ; then
                RECORDINGFILTER+=",crop=w=720:h=480:x=0:y=4"
                _add_mediaconch_rule_set "${STANDARD_NTSC_ACCESS_TEST}"
            else
                _add_mediaconch_rule_set "${STANDARD_NTSC_TEST}"
            fi
            RECORDINGFILTER_MP4+=",crop=w=720:h=480:x=0:y=4"
            _set_some_params
            SET_COLOR_PRIMARIES="smpte170m"
            SET_COLOR_TRC="bt709"
            SET_COLORSPACE="smpte170m"
            RECORDINGFILTER+=",setparams=range=${SET_RANGE}:color_primaries=${SET_COLOR_PRIMARIES}:color_trc=${SET_COLOR_TRC}:colorspace=${SET_COLORSPACE}:field_mode=${SET_FIELD_MODE}" ;;
        "PAL")
            STANDARD="pal "
            DECKLINK_FPS="25000/1000"
            SIG_GEN_SIZE="720x576"
            SIG_INTERLACEMENT="tff"
            _add_mediaconch_rule_set "${STANDARD_PAL_TEST}"
            _set_some_params
            SET_COLOR_PRIMARIES="bt470bg"
            SET_COLOR_TRC="bt709"
            SET_COLORSPACE="bt470bg"
            RECORDINGFILTER+=",setparams=range=${SET_RANGE}:color_primaries=${SET_COLOR_PRIMARIES}:color_trc=${SET_COLOR_TRC}:colorspace=${SET_COLORSPACE}:field_mode=${SET_FIELD_MODE}" ;;
        "23ps - 1080p23.98")
            STANDARD="23ps"
            DECKLINK_FPS="24000/1001"
            SIG_GEN_SIZE="1920x1080"
            SIG_INTERLACEMENT="prog"
            _set_some_params
            SET_COLOR_PRIMARIES="bt709"
            SET_COLOR_TRC="bt709"
            SET_COLORSPACE="bt709"
            RECORDINGFILTER+=",setparams=range=${SET_RANGE}:color_primaries=${SET_COLOR_PRIMARIES}:color_trc=${SET_COLOR_TRC}:colorspace=${SET_COLORSPACE}:field_mode=${SET_FIELD_MODE}" ;;
        "24ps - 1080p24")
            STANDARD="24ps"
            DECKLINK_FPS="24000/1000"
            SIG_GEN_SIZE="1920x1080"
            SIG_INTERLACEMENT="prog"
            _set_some_params
            SET_COLOR_PRIMARIES="bt709"
            SET_COLOR_TRC="bt709"
            SET_COLORSPACE="bt709"
            RECORDINGFILTER+=",setparams=range=${SET_RANGE}:color_primaries=${SET_COLOR_PRIMARIES}:color_trc=${SET_COLOR_TRC}:colorspace=${SET_COLORSPACE}:field_mode=${SET_FIELD_MODE}" ;;
        "Hp25 - 1080p25")
            STANDARD="Hp25"
            DECKLINK_FPS="25000/1000"
            SIG_GEN_SIZE="1920x1080"
            SIG_INTERLACEMENT="prog"
            _set_some_params
            SET_COLOR_PRIMARIES="bt709"
            SET_COLOR_TRC="bt709"
            SET_COLORSPACE="bt709"
            RECORDINGFILTER+=",setparams=range=${SET_RANGE}:color_primaries=${SET_COLOR_PRIMARIES}:color_trc=${SET_COLOR_TRC}:colorspace=${SET_COLORSPACE}:field_mode=${SET_FIELD_MODE}" ;;
        "Hp29 - 1080p29.97")
            STANDARD="Hp29"
            DECKLINK_FPS="30000/1001"
            SIG_GEN_SIZE="1920x1080"
            SIG_INTERLACEMENT="prog"
            _set_some_params
            SET_COLOR_PRIMARIES="bt709"
            SET_COLOR_TRC="bt709"
            SET_COLORSPACE="bt709"
            RECORDINGFILTER+=",setparams=range=${SET_RANGE}:color_primaries=${SET_COLOR_PRIMARIES}:color_trc=${SET_COLOR_TRC}:colorspace=${SET_COLORSPACE}:field_mode=${SET_FIELD_MODE}" ;;
        "Hp30 - 1080p30")
            STANDARD="Hp30"
            DECKLINK_FPS="30000/1000"
            SIG_GEN_SIZE="1920x1080"
            SIG_INTERLACEMENT="prog"
            _set_some_params
            SET_COLOR_PRIMARIES="bt709"
            SET_COLOR_TRC="bt709"
            SET_COLORSPACE="bt709"
            RECORDINGFILTER+=",setparams=range=${SET_RANGE}:color_primaries=${SET_COLOR_PRIMARIES}:color_trc=${SET_COLOR_TRC}:colorspace=${SET_COLORSPACE}:field_mode=${SET_FIELD_MODE}" ;;
        "Hi50 - 1080i50")
            STANDARD="Hi50"
            DECKLINK_FPS="25000/1000"
            SIG_GEN_SIZE="1920x1080"
            SIG_INTERLACEMENT="tff"
            _set_some_params
            SET_COLOR_PRIMARIES="bt709"
            SET_COLOR_TRC="bt709"
            SET_COLORSPACE="bt709"
            RECORDINGFILTER+=",setparams=range=${SET_RANGE}:color_primaries=${SET_COLOR_PRIMARIES}:color_trc=${SET_COLOR_TRC}:colorspace=${SET_COLORSPACE}:field_mode=${SET_FIELD_MODE}" ;;
        "Hi59 - 1080i59.94")
            STANDARD="Hi59"
            DECKLINK_FPS="30000/1001"
            SIG_GEN_SIZE="1920x1080"
            SIG_INTERLACEMENT="tff"
            _set_some_params
            SET_COLOR_PRIMARIES="bt709"
            SET_COLOR_TRC="bt709"
            SET_COLORSPACE="bt709"
            RECORDINGFILTER+=",setparams=range=${SET_RANGE}:color_primaries=${SET_COLOR_PRIMARIES}:color_trc=${SET_COLOR_TRC}:colorspace=${SET_COLORSPACE}:field_mode=${SET_FIELD_MODE}" ;;
        "Hi60 - 1080i60")
            STANDARD="Hi60"
            DECKLINK_FPS="30000/1000"
            SIG_GEN_SIZE="1920x1080"
            SIG_INTERLACEMENT="tff"
            _set_some_params
            SET_COLOR_PRIMARIES="bt709"
            SET_COLOR_TRC="bt709"
            SET_COLORSPACE="bt709"
            RECORDINGFILTER+=",setparams=range=${SET_RANGE}:color_primaries=${SET_COLOR_PRIMARIES}:color_trc=${SET_COLOR_TRC}:colorspace=${SET_COLORSPACE}:field_mode=${SET_FIELD_MODE}" ;;
        "hp50 - 720p50")
            STANDARD="hp50"
            DECKLINK_FPS="50000/1000"
            SIG_GEN_SIZE="1280x720"
            SIG_INTERLACEMENT="prog"
            _set_some_params
            SET_COLOR_PRIMARIES="bt709"
            SET_COLOR_TRC="bt709"
            SET_COLORSPACE="bt709"
            RECORDINGFILTER+=",setparams=range=${SET_RANGE}:color_primaries=${SET_COLOR_PRIMARIES}:color_trc=${SET_COLOR_TRC}:colorspace=${SET_COLORSPACE}:field_mode=${SET_FIELD_MODE}" ;;
        "hp59 - 720p59.94")
            STANDARD="hp59"
            DECKLINK_FPS="60000/1001"
            SIG_GEN_SIZE="1280x720"
            SIG_INTERLACEMENT="prog"
            _set_some_params
            SET_COLOR_PRIMARIES="bt709"
            SET_COLOR_TRC="bt709"
            SET_COLORSPACE="bt709"
            RECORDINGFILTER+=",setparams=range=${SET_RANGE}:color_primaries=${SET_COLOR_PRIMARIES}:color_trc=${SET_COLOR_TRC}:colorspace=${SET_COLORSPACE}:field_mode=${SET_FIELD_MODE}" ;;
        "hp60 - 720p60")
            STANDARD="hp60"
            DECKLINK_FPS="60000/1000"
            SIG_GEN_SIZE="1280x720"
            SIG_INTERLACEMENT="prog"
            _set_some_params
            SET_COLOR_PRIMARIES="bt709"
            SET_COLOR_TRC="bt709"
            SET_COLORSPACE="bt709"
            RECORDINGFILTER+=",setparams=range=${SET_RANGE}:color_primaries=${SET_COLOR_PRIMARIES}:color_trc=${SET_COLOR_TRC}:colorspace=${SET_COLORSPACE}:field_mode=${SET_FIELD_MODE}" ;;
        # aspect ratio options
        "4/3")
            if [[ "${STANDARD}" = "ntsc" ]] ; then
                RECORDINGFILTER+=",setsar=${NTSC_43_SAR_CHOICE}"
                RECORDINGFILTER_MP4+=",setsar=${NTSC_43_SAR_CHOICE}"
            elif [[ "${STANDARD}" = "pal " ]] ; then
                RECORDINGFILTER+=",setsar=${PAL_43_SAR_CHOICE}"
                RECORDINGFILTER_MP4+=",setsar=${PAL_43_SAR_CHOICE}"
            elif [[ "${STANDARD}" = "23ps" ]] ; then
                RECORDINGFILTER+=",setdar=4/3"
                RECORDINGFILTER_MP4+=",setdar=4/3"
            elif [[ "${STANDARD}" = "24ps" ]] ; then
                RECORDINGFILTER+=",setdar=4/3"
                RECORDINGFILTER_MP4+=",setdar=4/3"
            elif [[ "${STANDARD:0:2}" = "Hp" ]] ; then
                RECORDINGFILTER+=",setdar=4/3"
                RECORDINGFILTER_MP4+=",setdar=4/3"
            elif [[ "${STANDARD:0:2}" = "Hi" ]] ; then
                RECORDINGFILTER+=",setdar=4/3"
                RECORDINGFILTER_MP4+=",setdar=4/3"
            elif [[ "${STANDARD:0:2}" = "hp" ]] ; then
                RECORDINGFILTER+=",setdar=4/3"
                RECORDINGFILTER_MP4+=",setdar=4/3"
            else
                _report -w "Error: the standard wasn't set to an expected when it was expected to be."
            fi ;;
        "16/9")
            if [[ "${STANDARD}" = "ntsc" ]] ; then
                RECORDINGFILTER+=",setsar=${PAL_43_SAR_CHOICE}"
                RECORDINGFILTER_MP4+=",setsar=${PAL_43_SAR_CHOICE}"
            elif [[ "${STANDARD}" = "pal " ]] ; then
                RECORDINGFILTER+=",setsar=${PAL_169_SAR_CHOICE}"
                RECORDINGFILTER_MP4+=",setsar=${PAL_169_SAR_CHOICE}"
            elif [[ "${STANDARD}" = "23ps" ]] ; then
                RECORDINGFILTER+=",setdar=16/9"
                RECORDINGFILTER_MP4+=",setdar=16/9"
            elif [[ "${STANDARD}" = "24ps" ]] ; then
                RECORDINGFILTER+=",setdar=16/9"
                RECORDINGFILTER_MP4+=",setdar=16/9"
            elif [[ "${STANDARD:0:2}" = "Hp" ]] ; then
                RECORDINGFILTER+=",setdar=16/9"
                RECORDINGFILTER_MP4+=",setdar=16/9"
            elif [[ "${STANDARD:0:2}" = "Hi" ]] ; then
                RECORDINGFILTER+=",setdar=16/9"
                RECORDINGFILTER_MP4+=",setdar=16/9"
            elif [[ "${STANDARD:0:2}" = "hp" ]] ; then
                RECORDINGFILTER+=",setdar=16/9"
                RECORDINGFILTER_MP4+=",setdar=16/9"
            else
                _report -w "Error: the standard wasn't set to an expected when it was expected to be."
            fi ;;

        # playback views
        "Unfiltered") PLAYBACKFILTER="" ;;
        "Quality Control View (mpv)") MEDIA_PLAYER_CHOICE="mpv" ;;
        "Audio")
if [[ "${RUNTYPE}" = "record" ]] ; then
    AUDIO_SPLIT='4[c][e][f][out1],'
    WAVEFORM="[e]astats=metadata=1:reset=1,adrawgraph=m1=lavfi.astats.1.Min_level:m2=lavfi.astats.1.Max_level:size=700x160:bg=Black:fg1=0xFFFF0000:fg2=0xFFFF0000:slide=scroll:min=-32767:max=32767[wav1],\
    [f]astats=metadata=1:reset=1,adrawgraph=m1=lavfi.astats.2.Min_level:m2=lavfi.astats.2.Max_level:size=700x160:bg=Black:fg1=0xFF00FF00:fg2=0xFF00FF00:slide=scroll:min=-32767:max=32767[wav2]"
    AP_MAP='[c1][wav1][wav2]xstack=inputs=3:layout=0_0|0_h0|0_h0+h1[out0]'
else
    PRINT_PHASE=",drawtext=fontfile=${DEFAULTFONT}:box=1:text=Phase\\\: %{metadata\\\:lavfi.astats.1.DC_offset}:x=135:y=380:fontcolor=black"
    PRINT_CHANNELS_1_2=",drawtext=fontfile=${DEFAULTFONT}:text=Ch.1/2:x=10: y=10:fontcolor=white"
    AUDIO_SPLIT='7[a][b][c][d][e][f][out1],'
    WAVEFORM="[e]astats=metadata=1:reset=1,adrawgraph=m1=lavfi.astats.1.Min_level:m2=lavfi.astats.1.Max_level:size=800x200:bg=Black:fg1=0xFFFF0000:fg2=0xFFFF0000:slide=scroll:min=-32767:max=32767[wav1],\
    [f]astats=metadata=1:reset=1,adrawgraph=m1=lavfi.astats.2.Min_level:m2=lavfi.astats.2.Max_level:size=800x200:bg=Black:fg1=0xFF00FF00:fg2=0xFF00FF00:slide=scroll:min=-32767:max=32767[wav2]"
    CHANNEL_PARAMS="[b]avectorscope=s=320x400${PRINT_CHANNELS_1_2}[b1],"
    AP_MAP='[a1][b1][x][wav1][wav2]xstack=inputs=5:layout=0_0|w0_0|0_h0|w0+w1_0|w0+w1_h3,fps=25[out0]'
    PHASE_LOCATION='x=135:y=380'
    SHOW_SPECTUM="[d]showspectrum=s=1155x200:fps=10:color=rainbow:saturation=2:legend=1[d1],"
    VOLUME_OVERLAY='[d1][c1]overlay=640:0:format=yuv444[x],'
    PHASE_MAP="[a]aformat=dblp,channelsplit,axcorrelate,astats=metadata=1:reset=1,adrawgraph=lavfi.astats.1.DC_offset:max=1.01:min=-1.01:size=320x400:bg=black:fg1=0x99999999,drawbox=x=0:y=200:w=400:c=white:h=1${PRINT_PHASE}${PRINT_CHANNELS_1_2}[a1],"
fi
PLAYBACKFILTER="${PASSTHROUGH_MAP},asplit=${AUDIO_SPLIT}\
${PHASE_MAP}\
${CHANNEL_PARAMS}\
${WAVEFORM},\
[c]showvolume=t=0:h=28:w=700[c1],\
${SHOW_SPECTUM}\
${VOLUME_OVERLAY}\
${AP_MAP}" ;;
        "Audio + Video")
if [[ "${RUNTYPE}" = "record" ]] ; then
    PLAYBACKFILTER="streams=dv+da[vid][aud],\
    [aud]asplit=2[original_audio][audio_to_map];[audio_to_map]${AUDIO_PLAY_MAP}[out1];\
    [original_audio]showvolume=t=0:dm=5400:rate=${DECKLINK_FPS}${AUDIO_PLAY_LABELS}[aud2];\
    [vid]${PLAYBACK_FILTER_ADJUSTMENT}split=5[a][b][c][d][e];\
    [a]copy${TIMECODE_OVERLAY}[a1];\
    [b]field=top,${WAVEFORM_FILTER}[b1];\
    [c]field=bottom,${WAVEFORM_FILTER}[c1];\
    [d]${VECTORSCOPE_FILTER}[d1];\
    [e]scale=512:ih,${SIGNAL_FILTER}[e1];\
    [a1][b1][c1][e1][d1]xstack=inputs=5:layout=0_0|0_h0|0_h0+h1|w0_0|w0_h0[vidstack];\
    [vidstack][aud2]overlay=10:10:format=yuv444[out0]"
else
    VECTORSCOPE_FILTER="\
    format=yuv422p,\
    vectorscope=i=0.04:mode=color2:c=1:envelope=instant:graticule=green:flags=name,\
    scale=400:400"
    if [[ "${AUDIO_MAPPING_CHOICE}" = '2 Stereo Tracks (Channels 1 & 2 -> 1st Track Stereo, Channels 3 & 4 -> 2nd Track Stereo)' ]] ; then
        PRINT_PHASE=",drawtext=fontfile=${DEFAULTFONT}:box=1:text=Phase\\\: %{metadata\\\:lavfi.astats.1.DC_offset}:x=135:y=180:fontcolor=black"
        PRINT_CHANNELS_1_2=",drawtext=fontfile=${DEFAULTFONT}:text=Ch.1/2:x=10: y=10:fontcolor=white"
        PRINT_CHANNELS_3_4=",drawtext=fontfile=${DEFAULTFONT}:text=Ch.3/4:x=10: y=10:fontcolor=white"
        AUDIO_SPLIT='6[a][aa][b][d][e][out1]'
        CHANNEL_PARAMS="[b]pan=stereo|c0=c0|c1=c1,avectorscope=s=320x400${PRINT_CHANNELS_1_2}[b1],[e]pan=stereo|c0=c2|c1=c3,avectorscope=s=320x400${PRINT_CHANNELS_3_4}[e1]"
        AP_MAP='[phase1][phase2][b1][e1][x][d1][TFIELD][BFIELD][vector]xstack=inputs=9:layout=0_0|0_h0|w0_0|w0+w2_0|w0+w2+w3_0|0_h0+h1|0_h0+h1+h5|w6_h0+h1+h5|w5_h0+h1,fps=25[out0]'
        PHASE_LOCATION='x=135:y=180'
        PHASE_MAP="[a]pan=stereo|c0=c0|c1=c1,aformat=dblp,channelsplit,axcorrelate,astats=metadata=1:reset=1,adrawgraph=lavfi.astats.1.DC_offset:max=1.01:min=-1.01:size=400x200:bg=black:fg1=0x99999999,drawbox=x=0:y=100:w=400:c=white:h=1${PRINT_PHASE}${PRINT_CHANNELS_1_2}[phase1],\
        [aa]pan=stereo|c0=c2|c1=c3,aformat=dblp,channelsplit,axcorrelate,astats=metadata=1:reset=1,adrawgraph=lavfi.astats.1.DC_offset:max=1.01:min=-1.01:size=400x200:bg=black:fg1=0x99999999,drawbox=x=0:y=100:w=400:c=white:h=1${PRINT_PHASE}${PRINT_CHANNELS_3_4}[phase2]"
        SPECTRUM_SIZE='755x265'
    else
        PRINT_PHASE=",drawtext=fontfile=${DEFAULTFONT}:box=1:text=Phase\\\: %{metadata\\\:lavfi.astats.1.DC_offset}:x=135:y=380:fontcolor=black"
        PRINT_CHANNELS_1_2=",drawtext=fontfile=${DEFAULTFONT}:text=Ch.1/2:x=10: y=10:fontcolor=white"
        AUDIO_SPLIT='4[a][b][d][out1]'
        CHANNEL_PARAMS="[b]pan=stereo|c0=c0|c1=c1,avectorscope=s=320x400${PRINT_CHANNELS_1_2}[b1]"
        AP_MAP='[a1][b1][x][d1][TFIELD][BFIELD][vector]xstack=inputs=7:layout=0_0|w0_0|w0+w1_0|0_h0+h4|0_h0|w4_h0|w0+w1+w2_0,fps=25[out0]'
        PHASE_LOCATION='x=135:y=380'
        PHASE_MAP="[a]aformat=dblp,channelsplit,axcorrelate,astats=metadata=1:reset=1,adrawgraph=lavfi.astats.1.DC_offset:max=1.01:min=-1.01:size=320x400:bg=black:fg1=0x99999999,drawbox=x=0:y=200:w=400:c=white:h=1${PRINT_PHASE}${PRINT_CHANNELS_1_2}[a1]"
        SPECTRUM_SIZE='1155x200'
    fi
    PLAYBACKFILTER="streams=dv+da[vid][aud],[aud]asplit=2[original_audio][audio_to_map];[audio_to_map]${AUDIO_PLAY_MAP},asplit=${AUDIO_SPLIT},\
    ${PHASE_MAP},\
    ${CHANNEL_PARAMS},\
    [original_audio]showvolume=t=0:h=17:w=200:rate=30${AUDIO_PLAY_LABELS}[c1],\
    [d]showspectrum=s=${SPECTRUM_SIZE}:fps=10:color=rainbow:saturation=2:legend=1[d1],\
    [vid]split=4[vid1][vid2][vid3][vid4],[vid1]scale=400x400,${SIGNAL_FILTER}[vidscale],\
    [vid2]field=top,${WAVEFORM_FILTER}[TFIELD],\
    [vid3]field=bottom,${WAVEFORM_FILTER}[BFIELD],\
    [vid4]${VECTORSCOPE_FILTER}[vector],\
    [vidscale][c1]overlay=10:10:format=yuv444[x],\
    ${AP_MAP}"
fi ;;
        "Visual")
            PLAYBACKFILTER="\
${PLAYBACK_FILTER_ADJUSTMENT}split=5[a][b][c][d][e];\
[a]copy${TIMECODE_OVERLAY}[a1];\
[b]field=top,${WAVEFORM_FILTER}[b1];\
[c]field=bottom,${WAVEFORM_FILTER}[c1];\
[d]${VECTORSCOPE_FILTER}[d1];\
[e]scale=512:ih,${SIGNAL_FILTER}[e1];\
[a1][b1][c1][e1][d1]xstack=inputs=5:layout=0_0|0_h0|0_h0+h1|w0_0|w0_h0" ;;
      "Visual + Numerical")
          _set_up_drawtext
          PLAYBACKFILTER="\
${PLAYBACK_FILTER_ADJUSTMENT}split=6[a][b][c][d][e][f];\
[a]copy${TIMECODE_OVERLAY}[a1];\
[b]field=top,${WAVEFORM_FILTER}[b1];\
[c]field=bottom,${WAVEFORM_FILTER}[c1];\
[d]${VECTORSCOPE_FILTER}[d1];\
[e]signalstats=out=brng:stat=brng+vrep+tout,scale=512:ih,split[e1][e2];\
[e2]format=yuv422p,geq=lum=60:cb=128:cr=128,\
scale=180:ih+512,setsar=1/1,\
drawtext=fontcolor=white:fontsize=22:\
fontfile=${DEFAULTFONT}:textfile=${DRAWTEXT_TMP_1},\
drawtext=fontcolor=white:fontsize=17:\
fontfile=${DEFAULTFONT}:textfile=${DRAWTEXT_TMP_2}:y=480,\
drawtext=fontcolor=white:fontsize=52:\
fontfile=${DEFAULTFONT}:textfile=${DRAWTEXT_TMP_3}:y=640[e3];\
[f]scale=iw+512+180:82,format=yuv422p,geq=lum=60:cb=128:cr=128,drawtext=fontcolor=white:fontsize=22:\
fontfile=${DEFAULTFONT}:textfile=${VRECORD_INPUT_TMP}:\
reload=1:y=82-th[f1];\
[e3][a1][b1][c1][e1][d1][f1]xstack=inputs=7:layout=0_0|w0_0|w0_h1|w0_h1+h2|w0+w1_0|w0+w1_h1|0_h0" ;;
      "Color Matrix")
          HUE=20
          SAT=0.3
          PLAYBACKFILTER="\
${PLAYBACK_FILTER_ADJUSTMENT}scale=iw/4:ih/4,\
split=9[x][hm][hp][sm][sp][hmsm][hmsp][hpsm][hpsp];\
[hm]hue=h=-${HUE}[hm1];\
[hp]hue=h=${HUE}[hp1];\
[sm]hue=s=1-${SAT}[sm1];\
[sp]hue=s=1+${SAT}[sp1];\
[hmsm]hue=h=-${HUE}:s=1-${SAT}[hmsm1];\
[hmsp]hue=h=-${HUE}:s=1+${SAT}[hmsp1];\
[hpsm]hue=h=${HUE}:s=1-${SAT}[hpsm1];\
[hpsp]hue=h=${HUE}:s=1+${SAT}[hpsp1];\
[hpsm1][hp1][hpsp1][sm1][x][sp1][hmsm1][hm1][hmsp1]xstack=inputs=9:layout=0_0|0_h0|0_h0+h1|w0_0|w0_h0|w0_h0+h1|w0+w1_0|w0+w1_h0|w0+w1_h0+h1" ;;
      "Bit Planes")
          if [[ "${PIXEL_FORMAT}" = "uyvy422" ]] ; then
              BITS=8
              SPLIT="8[b0][b1][b2][b3][b4][b5][b6][b7]"
              STACK="[b0c][b1c][b2c][b3c][b4c][b5c][b6c][b7c]hstack=8,format=yuv444p,drawgrid=w=iw/8:h=ih:t=2:c=green@0.5"
          elif [[ "${PIXEL_FORMAT}" = "yuv422p10" ]] ; then
              BITS=10
              SPLIT="10[b0][b1][b2][b3][b4][b5][b6][b7][b8][b9]"
              STACK="\
[b8]bitplanenoise=bitplane=2,crop=iw/10:ih:(iw/10)*8:0,lutyuv=u=(maxval/2):v=(maxval/2):y=bitand(val\\,pow(2\\,10-9))*pow(2\\,9),pad=iw:ih+64:0:64,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.0.2}:y=0:fontcolor=white:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.1.2}:y=20:fontcolor=white:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.2.2}:y=40:fontcolor=white:fontsize=20[b8c];\
[b9]bitplanenoise=bitplane=1,crop=iw/10:ih:(iw/10)*9:0,lutyuv=u=(maxval/2):v=(maxval/2):y=bitand(val\\,pow(2\\,10-10))*pow(2\\,10),pad=iw:ih+64:0:64,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.0.1}:y=0:fontcolor=silver:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.1.1}:y=20:fontcolor=silver:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.2.1}:y=40:fontcolor=silver:fontsize=20[b9c];\
[b0c][b1c][b2c][b3c][b4c][b5c][b6c][b7c][b8c][b9c]hstack=10,format=yuv444p,drawgrid=w=iw/10:h=ih:t=2:c=green@0.5"
          fi
          PLAYBACKFILTER="\
${PLAYBACK_FILTER_ADJUSTMENT}format=yuv420p10le|yuv422p10le|yuv444p10le|yuv440p10le,split=${SPLIT};\
[b0]bitplanenoise=bitplane=10,crop=iw/${BITS}:ih:(iw/${BITS})*0:0,lutyuv=u=(maxval/2):v=(maxval/2):y=bitand(val\\,pow(2\\,10-1))*pow(2\\,1),pad=iw:ih+64:0:64,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.0.10}:y=0:fontcolor=white:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.1.10}:y=20:fontcolor=white:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.2.10}:y=40:fontcolor=white:fontsize=20[b0c];\
[b1]bitplanenoise=bitplane=9,crop=iw/${BITS}:ih:(iw/${BITS})*1:0,lutyuv=u=(maxval/2):v=(maxval/2):y=bitand(val\\,pow(2\\,10-2))*pow(2\\,2),pad=iw:ih+64:0:64,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.0.9}:y=0:fontcolor=silver:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.1.9}:y=20:fontcolor=silver:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.2.9}:y=40:fontcolor=silver:fontsize=20[b1c];\
[b2]bitplanenoise=bitplane=8,crop=iw/${BITS}:ih:(iw/${BITS})*2:0,lutyuv=u=(maxval/2):v=(maxval/2):y=bitand(val\\,pow(2\\,10-3))*pow(2\\,3),pad=iw:ih+64:0:64,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.0.8}:y=0:fontcolor=white:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.1.8}:y=20:fontcolor=white:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.2.8}:y=40:fontcolor=white:fontsize=20[b2c];\
[b3]bitplanenoise=bitplane=7,crop=iw/${BITS}:ih:(iw/${BITS})*3:0,lutyuv=u=(maxval/2):v=(maxval/2):y=bitand(val\\,pow(2\\,10-4))*pow(2\\,4),pad=iw:ih+64:0:64,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.0.7}:y=0:fontcolor=silver:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.1.7}:y=20:fontcolor=silver:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.2.7}:y=40:fontcolor=silver:fontsize=20[b3c];\
[b4]bitplanenoise=bitplane=6,crop=iw/${BITS}:ih:(iw/${BITS})*4:0,lutyuv=u=(maxval/2):v=(maxval/2):y=bitand(val\\,pow(2\\,10-5))*pow(2\\,5),pad=iw:ih+64:0:64,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.0.6}:y=0:fontcolor=white:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.1.6}:y=20:fontcolor=white:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.2.6}:y=40:fontcolor=white:fontsize=20[b4c];\
[b5]bitplanenoise=bitplane=5,crop=iw/${BITS}:ih:(iw/${BITS})*5:0,lutyuv=u=(maxval/2):v=(maxval/2):y=bitand(val\\,pow(2\\,10-6))*pow(2\\,6),pad=iw:ih+64:0:64,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.0.5}:y=0:fontcolor=silver:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.1.5}:y=20:fontcolor=silver:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.2.5}:y=40:fontcolor=silver:fontsize=20[b5c];\
[b6]bitplanenoise=bitplane=4,crop=iw/${BITS}:ih:(iw/${BITS})*6:0,lutyuv=u=(maxval/2):v=(maxval/2):y=bitand(val\\,pow(2\\,10-7))*pow(2\\,7),pad=iw:ih+64:0:64,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.0.4}:y=0:fontcolor=white:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.1.4}:y=20:fontcolor=white:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.2.4}:y=40:fontcolor=white:fontsize=20[b6c];\
[b7]bitplanenoise=bitplane=3,crop=iw/${BITS}:ih:(iw/${BITS})*7:0,lutyuv=u=(maxval/2):v=(maxval/2):y=bitand(val\\,pow(2\\,10-8))*pow(2\\,8),pad=iw:ih+64:0:64,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.0.3}:y=0:fontcolor=silver:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.1.3}:y=20:fontcolor=silver:fontsize=20,drawtext=fontfile=${DEFAULTFONT}:text=%{metadata\\\:lavfi.bitplanenoise.2.3}:y=40:fontcolor=silver:fontsize=20[b7c];\
${STACK}" ;;
        "Frame Positioning")
            CORNER_W=24
            CORNER_H=8
            CORNER_ZOOM=16
            PLAYBACKFILTER="\
${PLAYBACK_FILTER_ADJUSTMENT}format=yuv420p10le|yuv422p10le|yuv444p10le|yuv440p10le,split=2[f1][f2];\
[f1]field=top,split=4[t1][t2][t3][t4];\
[f2]field=bottom,split=4[b1][b2][b3][b4];\
color=color=darkgray,scale=${CORNER_W}*${CORNER_ZOOM}*2:${CORNER_H}*2,split=4[l1][l2][l3][l4];\
[l1]drawtext=fontfile=${DEFAULTFONT}:text='Top ${CORNER_H} Rows of Field 1 - Left ${CORNER_W} pixels and Right ${CORNER_W} pixels':fontcolor=white:fontsize=${CORNER_H}*2:x=(w-text_w)/2:y=(h-text_h)/2[l1t];\
[l2]drawtext=fontfile=${DEFAULTFONT}:text='Top ${CORNER_H} Rows of Field 2 - Left ${CORNER_W} pixels and Right ${CORNER_W} pixels':fontcolor=white:fontsize=${CORNER_H}*2:x=(w-text_w)/2:y=(h-text_h)/2[l2t];\
[l3]drawtext=fontfile=${DEFAULTFONT}:text='Bottom ${CORNER_H} Rows of Field 1 - Left ${CORNER_W} pixels and Right ${CORNER_W} pixels':fontcolor=white:fontsize=${CORNER_H}*2:x=(w-text_w)/2:y=(h-text_h)/2[l3t];\
[l4]drawtext=fontfile=${DEFAULTFONT}:text='Bottom ${CORNER_H} Rows of Field 2 - Left ${CORNER_W} pixels and Right ${CORNER_W} pixels':fontcolor=white:fontsize=${CORNER_H}*2:x=(w-text_w)/2:y=(h-text_h)/2[l4t];\
[t1]crop=w=${CORNER_W}:h=${CORNER_H}:x=0:y=0[a1t];\
[t2]crop=w=${CORNER_W}:h=${CORNER_H}:x=iw-${CORNER_H}:y=0[b1t];\
[t3]crop=w=${CORNER_W}:h=${CORNER_H}:x=0:y=ih-${CORNER_H}[c1t];\
[t4]crop=w=${CORNER_W}:h=${CORNER_H}:x=iw-${CORNER_H}:y=ih-${CORNER_H}[d1t];\
[b1]crop=w=${CORNER_W}:h=${CORNER_H}:x=0:y=0[a1b];\
[b2]crop=w=${CORNER_W}:h=${CORNER_H}:x=iw-${CORNER_H}:y=0[b1b];\
[b3]crop=w=${CORNER_W}:h=${CORNER_H}:x=0:y=ih-${CORNER_H}[c1b];\
[b4]crop=w=${CORNER_W}:h=${CORNER_H}:x=iw-${CORNER_H}:y=ih-${CORNER_H}[d1b];\
[a1t][b1t]hstack,scale=${CORNER_W}*16*2:${CORNER_H}*16:flags=neighbor,drawgrid=w=iw/${CORNER_W}/2:h=ih/${CORNER_H}:t=1:c=green@0.5[abt];\
[a1b][b1b]hstack,scale=${CORNER_W}*16*2:${CORNER_H}*16:flags=neighbor,drawgrid=w=iw/${CORNER_W}/2:h=ih/${CORNER_H}:t=1:c=green@0.5[abb];\
[c1t][d1t]hstack,scale=${CORNER_W}*16*2:${CORNER_H}*16:flags=neighbor,drawgrid=w=iw/${CORNER_W}/2:h=ih/${CORNER_H}:t=1:c=green@0.5[cdt];\
[c1b][d1b]hstack,scale=${CORNER_W}*16*2:${CORNER_H}*16:flags=neighbor,drawgrid=w=iw/${CORNER_W}/2:h=ih/${CORNER_H}:t=1:c=green@0.5[cdb];\
[l1t][abt][l2t][abb][l3t][cdt][l4t][cdb]vstack=8,setsar=1/1" ;;
        "Captions")
            if [[ "${RUNTYPE}" = "record" ]] ; then
            PLAYBACKFILTER="\
                ${PLAYBACK_FILTER_ADJUSTMENT}format=yuv420p10le|yuv422p10le|yuv444p10le|yuv440p10le,split=4[f1][f2][f3][f4];\
                [f1]readeia608=scan_max=2:spw=0.30,drawtext=fontfile=${DEFAULTFONT}:fontcolor=white:fontsize=36:box=1:boxcolor=black@0.5:x=(w-tw)/2:y=h*3/4-ascent:text=Line %{metadata\\\:lavfi.readeia608.0.line\\\:-} %{metadata\\\:lavfi.readeia608.0.cc\\\:------} - Line %{metadata\\\:lavfi.readeia608.1.line\\\:-} %{metadata\\\:lavfi.readeia608.1.cc\\\:------}[f1b];\
                [f2]crop=iw:1:0:1,scale=iw:2:flags=neighbor,tile=layout=1x120:overlap=119:init_padding=119[caption_scroll];\
                [f3]format=gray,crop=iw:1:0:1,waveform=i=1:g=green,drawtext=fontfile=${DEFAULTFONT}:text='Line 1':fontcolor=white:fontsize=18:x=20:y=20[wvf];\
                [f4]format=gray,crop=iw:1:0:2,waveform=i=1:g=green,drawtext=fontfile=${DEFAULTFONT}:text='Line 2':fontcolor=white:fontsize=18:x=20:y=20[wvf2];\
                [caption_scroll][f1b][wvf][wvf2]vstack=4" 
            else
                PLAYBACKFILTER="\
                ${PLAYBACK_FILTER_ADJUSTMENT}format=yuv420p10le|yuv422p10le|yuv444p10le|yuv440p10le,split=4[f1][f2][f3][f4];\
                [f1]readeia608=scan_max=2:spw=0.30,metadata=mode=print:key=lavfi.readeia608.0.cc,drawtext=fontfile=${DEFAULTFONT}:fontcolor=white:fontsize=36:box=1:boxcolor=black@0.5:x=(w-tw)/2:y=h*3/4-ascent:text=Line %{metadata\\\:lavfi.readeia608.0.line\\\:-} %{metadata\\\:lavfi.readeia608.0.cc\\\:------} - Line %{metadata\\\:lavfi.readeia608.1.line\\\:-} %{metadata\\\:lavfi.readeia608.1.cc\\\:------},drawtext=fontfile=${DEFAULTFONT}:textfile=${CAP_DISPLAY_TMP}:reload=1:fontcolor=white:fontsize=18:x=(w-text_w)/2:y=h-100:shadowcolor=blue:shadowx=1:shadowy=1[f1b];\
                [f2]crop=iw:1:0:1,scale=iw:2:flags=neighbor,tile=layout=1x120:overlap=119:init_padding=119[caption_scroll];\
                [f3]format=gray,crop=iw:1:0:1,waveform=i=1:g=green,drawtext=fontfile=${DEFAULTFONT}:text='Line 1':fontcolor=white:fontsize=18:x=20:y=20[wvf];\
                [f4]format=gray,crop=iw:1:0:2,waveform=i=1:g=green,drawtext=fontfile=${DEFAULTFONT}:text='Line 2':fontcolor=white:fontsize=18:x=20:y=20[wvf2];\
                [caption_scroll][f1b][wvf][wvf2]vstack=4" 
            fi ;;
        # others
        "Yes"|"Yes, after recording"|"Yes, concurrent with recording"|"No") ;;
        *) _report -w "Error: ${1} is not a valid option." ; return 1 ;;
    esac
}

_frames_to_hhmmss(){
    H=$(echo "${i} / (60 * 60 * ${DECKLINK_FPS})" | bc)
    M=$(echo "(${i} - (${H}*60 * 60 * ${DECKLINK_FPS})) / (60 * ${DECKLINK_FPS})" | bc)
    S="$(echo "scale=3;(${i} - (${H}*60 * 60 * ${DECKLINK_FPS})-($M*60*${DECKLINK_FPS})) / (${DECKLINK_FPS})" | bc)"
    Ss=$(echo "${S}" | cut -d. -f1 | bc)
    Sm=$(echo "${S}" | cut -d. -f2 | bc)
    printf "%02d:%02d:%02d.%03d\n" "${H}" "${M}" "${Ss}" "${Sm}"
}

_set_up_drawtext(){
    # set up drawtext.txt files for Visual + Numerical playback view
    DRAWTEXT_TMP_1="$(_maketemp .drawtext.1.txt)"
    DRAWTEXT_TMP_2="$(_maketemp .drawtext.2.txt)"
    DRAWTEXT_TMP_3="$(_maketemp .drawtext.3.txt)"
    echo "%{pts:hms}

  Y
 Low  %{metadata:lavfi.signalstats.YLOW}
 Avg  %{metadata:lavfi.signalstats.YAVG}
 High %{metadata:lavfi.signalstats.YHIGH}
 Diff %{metadata:lavfi.signalstats.YDIF}

  U
 Low  %{metadata:lavfi.signalstats.ULOW}
 Avg  %{metadata:lavfi.signalstats.UAVG}
 High %{metadata:lavfi.signalstats.UHIGH}
 Diff %{metadata:lavfi.signalstats.UDIF}

  V
 Low  %{metadata:lavfi.signalstats.VLOW}
 Avg  %{metadata:lavfi.signalstats.VAVG}
 High %{metadata:lavfi.signalstats.VHIGH}
 Diff %{metadata:lavfi.signalstats.VDIF}

  SAT
 Low  %{metadata:lavfi.signalstats.SATLOW}
 Avg  %{metadata:lavfi.signalstats.SATAVG}
 High %{metadata:lavfi.signalstats.SATHIGH}" > "${DRAWTEXT_TMP_1}"

    echo " HUE(med) %{metadata:lavfi.signalstats.HUEMED}
 HUE(avg) %{metadata:lavfi.signalstats.HUEAVG}
 TOUT     %{metadata:lavfi.signalstats.TOUT}
 VREP     %{metadata:lavfi.signalstats.VREP}

 Used Bitdepths
 Y        %{metadata:lavfi.signalstats.YBITDEPTH}
 U        %{metadata:lavfi.signalstats.UBITDEPTH}
 V        %{metadata:lavfi.signalstats.VBITDEPTH}" > "${DRAWTEXT_TMP_2}"
    echo "BRNG
%{metadata:lavfi.signalstats.BRNG}" > "${DRAWTEXT_TMP_3}"
}

# select playback view
_set_scopes(){
    WAVEFORM_FILTER="\
    format=yuv422p,\
    waveform=scale=${WAVEFORM_SCALE_CHOICE:-0}:intensity=0.1:mode=column:mirror=1:c=1:f=lowpass:e=instant:graticule=green:flags=numbers+dots"
    VECTORSCOPE_FILTER="\
    format=yuv422p,\
    vectorscope=i=0.04:mode=color2:c=1:envelope=instant:graticule=green:flags=name,\
    scale=512:512,\
    drawbox=w=9:h=9:t=1:x=128-3:y=512-452-5:c=sienna@0.8,\
    drawbox=w=9:h=9:t=1:x=160-3:y=512-404-5:c=sienna@0.8,\
    drawbox=w=9:h=9:t=1:x=192-3:y=512-354-5:c=sienna@0.8,\
    drawbox=w=9:h=9:t=1:x=224-3:y=512-304-5:c=sienna@0.8,\
    drawgrid=w=32:h=32:t=1:c=white@0.1,\
    drawgrid=w=256:h=256:t=1:c=white@0.2"
    if [[ "${SIGNAL_VIEW_CHOICE}" == "Full Range" ]] ; then
        SIGNAL_FILTER="format=yuv444p,pseudocolor=if(between(1\,val\,amax)+between(val\,254\,amax)\,65\,-1):if(between(1\,val\,amax)+between(val\,254\,amax)\,100\,-1):if(between(1\,val\,amax)+between(val\,254\,amax)\,212\,-1)"
    else
        SIGNAL_FILTER="signalstats=out=brng"
    fi
}

_review_option(){
    unset NO_LOOKUP DEFAULT
    OPTIND=1
    while getopts "nd:" opt ; do
        case "${opt}" in
            n) NO_LOOKUP="Y" ;; #also the SELECTED value to be used as-is rather than lookup what it means
            d) DEFAULT="${OPTARG}" ;;
        esac
    done
    shift "$((OPTIND-1))"
    VALUE_NAME="${1}"
    SELECTED="${!1}"
    shift
    CHOICES=("${@}")
    if [[ -z "${SELECTED}" ]] && [[ -n "${DEFAULT}" ]] ; then
        SELECTED="${DEFAULT}"
        export "${VALUE_NAME}"="${SELECTED}"
    fi
    if [[ ! " ${CHOICES[@]} " =~ " ${SELECTED} " ]] ; then
        if [[ -z "${SELECTED}" ]] ; then
            _report -w "Error: An option for ${VALUE_NAME} is required. Please restart ${SCRIPTNAME} in edit mode (${SCRIPTNAME} -e) or update the configuration file at ${CONFIG_FILE}."
            exit 2
        else
            _report -w "The configuration file uses an invalid value of ${SELECTED} for ${VALUE_NAME}. Valid values are: ${CHOICES[*]}. Please restart ${SCRIPTNAME} in edit mode (${SCRIPTNAME} -e) or update the configuration file at ${CONFIG_FILE}."
            exit 2
        fi
    fi
    if [[ "${SELECTED}" ]] ; then
        if [[ "${NO_LOOKUP}" != "Y" ]] ; then
          _lookup_choice "${SELECTED}"
        fi
    else
        _report -w "The option for ${VALUE_NAME} is not set. Please restart ${SCRIPTNAME} in edit mode (${SCRIPTNAME} -e) or update the configuration file at ${CONFIG_FILE}."
        exit 3
    fi
    LOG_OF_OPTIONS+="${VALUE_NAME}: ${SELECTED}\n"
}

_review_all_options(){
    if [[ "${INVERT_PHASE_2}" = 'true' ]] ; then
        PHASE_VALUE_2="-1*"
    fi
    if [[ "${INVERT_PHASE_4}" = 'true' ]] ; then
        PHASE_VALUE_4="-1*"
    fi
    if [[ "${DEVICE_INPUT_CHOICE}" = "0" ]] ; then
        _review_option "VIDEO_INPUT_CHOICE" "${VIDEO_INPUT_OPTIONS[@]}"
        _review_option "AUDIO_INPUT_CHOICE" "${AUDIO_INPUT_OPTIONS[@]}"
        _review_option "VIDEO_BIT_DEPTH_CHOICE" "${VIDEO_BITDEPTH_OPTIONS[@]}"
        _review_option "AUDIO_MAPPING_CHOICE" "${CHANNEL_MAPPING_OPTIONS[@]}"
        if [[ -z "${ALT_INPUT}" ]] ; then
            _review_option "TIMECODE_CHOICE" "${TIMECODE_OPTIONS[@]}"
        fi
        _review_option "STANDARD_CHOICE" "${STANDARD_OPTIONS[@]}"
        _review_option -d "4/3" "ASPECT_RATIO_CHOICE" "${ASPECT_RATIO_OPTIONS[@]}"
        _review_option -n -d "10/11" "NTSC_43_SAR_CHOICE"  "${NTSC_43_SAR_OPTIONS[@]}"
        _review_option -n -d "40/33" "NTSC_169_SAR_CHOICE" "${NTSC_169_SAR_OPTIONS[@]}"
        _review_option -n -d "12/11" "PAL_43_SAR_CHOICE"   "${PAL_43_SAR_OPTIONS[@]}"
        _review_option -n -d "16/11" "PAL_169_SAR_CHOICE"  "${PAL_169_SAR_OPTIONS[@]}"
    elif [[ "${DEVICE_INPUT_CHOICE}" = "1" ]] ; then
        _review_option -n "DVRESCUE_INPUT_CHOICE" "${DVRESCUE_DEVICES[@]}"
    elif [[ "${DEVICE_INPUT_CHOICE}" = "2" ]] ; then
        _review_option -n "AUDIO_DEV_CHOICE" "${AUDIO_DEVICES[@]}"
    fi
    if [[ "${CORE_COUNT}" -le 2 && "${RUNTYPE}" = "record" ]] ; then
        _report -w "Since this computer has only ${CORE_COUNT} cores, the playback will display only half of the frames to reduce CPU. This will not impact the recording."
        PLAYBACK_FILTER_ADJUSTMENT="select=not(mod(n\,2)),"
    fi
    _review_option -n -d "digital" "WAVEFORM_SCALE_CHOICE" "${WAVEFORM_SCALE_OPTIONS[@]}"
    _review_option -n -d "Broadcast Range" "SIGNAL_VIEW_CHOICE" "${SIGNAL_OPTIONS[@]}"
    _review_option -n -d "auto" "SIGNAL_INT_CHOICE" "${INT_OPTIONS[@]}"
    _review_option -n -d "Yes" "MONITOR_AUDIO_CHOICE" "${MONITOR_AUDIO_OPTIONS[@]}"
    _set_scopes
    if [[ "${RUNTYPE}" = "passthrough" ]] && [[ -n "${PLAYBACKVIEW_CHOICE_PASS}" ]] && [[ "${PLAYBACKVIEW_CHOICE_PASS}" != "Unselected" ]] ; then
        _review_option -d "Visual" "PLAYBACKVIEW_CHOICE_PASS" "${PLAYBACKVIEW_PASS_OPTIONS[@]}"
    else
        _review_option -d "Visual" "PLAYBACKVIEW_CHOICE" "${PLAYBACKVIEW_OPTIONS[@]}"
    fi
    if [[ "${DEVICE_INPUT_CHOICE}" = 0 ]] ; then
        MIDDLEOPTIONS_ALL+=(-metadata creation_time=now)
        MIDDLEOPTIONS_PRES+=(${EXTRAOUTPUTOPTIONS[@]})
    elif [[ "${DEVICE_INPUT_CHOICE}" = "1" ]] ; then
        PLAYBACKVIEW_CHOICE_PASS="Unfiltered"
        PLAYBACKVIEW_CHOICE="Unfiltered"
        _lookup_choice "Unfiltered"
        if [[ "${DV_RESCUE_OPTION_D}" = 'true' ]] ; then
            DV_RESCUE_OPTS+=(-d)
        fi

        if [[ "${DV_RESCUE_OPTION_S}" = 'true' ]] ; then
            DV_RESCUE_OPTS+=(-s)
        fi

        if [[ "${DV_RESCUE_OPTION_T}" = 'true' ]] ; then
            DV_RESCUE_OPTS+=(-t)
        fi

        if [[ "${DV_RESCUE_OPTION_TC}" = 'true' ]] ; then
            DV_RESCUE_OPTS+=(-S)
        fi
    elif [[ "${DEVICE_INPUT_CHOICE}" = "2" ]] ; then
        _review_option "AUDIO_CHANNEL_CHOICE" "${AUDIO_CHANNEL_CHOICE_OPTIONS[@]}"
        if [[ "${AUDIO_DEV_CHOICE}" != *"Blackmagic"* ]] ; then
            _review_option "AUDIO_MODE_SR_CHOICE" "${AUDIO_MODE_SR_CHOICE_OPTIONS[@]}"
        else
            MIDDLEOPTIONS_PRES+=(-ar 48k)
        fi
        PLAYBACKVIEW_CHOICE_PASS="Audio"
        PLAYBACKVIEW_CHOICE="Audio"
        _lookup_choice "Audio"
    fi
}

# Define mediaconch test fragments - start
CONTAINER_GENERAL_TEST='
    <rule name="Is the video stream first?" value="StreamOrder" tracktype="Video" operator="=">0</rule>
    <rule name="Is the audio stream on track 2?" value="StreamOrder" tracktype="Audio" operator="=">1</rule>
'
CONTAINER_QUICKTIME_TEST='
    <rule name="Is the file extension mov?" value="FileExtension" tracktype="General" operator="=">mov</rule>
    <rule name="Is the format MPEG-4?" value="Format" tracktype="General" operator="=">MPEG-4</rule>
    <rule name="Is the format profile QuickTime?" value="Format_Profile" tracktype="General" operator="=">QuickTime</rule>
    <rule name="Is the codec ID qt  ?" value="CodecID" tracktype="General" operator="=">qt  </rule>
'

CONTAINER_MATROSKA_TEST='
    <rule name="Is the file extension mkv?" value="FileExtension" tracktype="General" operator="=">mkv</rule>
    <rule name="Is it Matroska?" value="Format" tracktype="General" operator="=">Matroska</rule>
    <rule name="Matroska version 4 or greater?" value="Format_Version" tracktype="General" operator="&gt;=">4</rule>
    <rule name="Unique ID is present?" value="UniqueID" tracktype="General"/>
    <policy type="and" name="Has Matroska finished writing?">
        <rule name="Duration is greater than zero?" scope="mmt" operator="&gt;" value="Segment/Info/Duration/Data">0</rule>
        <rule name="SeekHead is present?" scope="mmt" value="Segment/SeekHead/"/>
        <rule name="Cues is present?" scope="mmt" value="Segment/Cues/"/>
        <policy type="and" name="Select Top-Level Elements have CRCs?">
            <rule name="SeekHead CRC-32 is present?" scope="mmt" value="Segment/SeekHead/CRC-32/"/>
            <rule name="Info CRC-32 is present?" scope="mmt" value="Segment/Info/CRC-32/"/>
            <rule name="Tracks CRC-32 is present?" scope="mmt" value="Segment/Tracks/CRC-32/"/>
            <rule name="Cluster CRC-32 is present?" scope="mmt" value="Segment/Cluster/CRC-32/"/>
            <rule name="Cues CRC-32 is present?" scope="mmt" value="Segment/Cues/CRC-32/"/>
            <rule name="Tags CRC-32 is present?" scope="mmt" value="Segment/Tags/CRC-32/"/>
        </policy>
    </policy>
'

CODEC_GENERAL_TEST='
    <rule name="Is the video format YUV?" value="ColorSpace" tracktype="Video" operator="=">YUV</rule>
    <rule name="Is the frame rate mode constant?" value="FrameRate_Mode" tracktype="Video" operator="=">CFR</rule>
    <rule name="Is the color space YUV?" value="ColorSpace" tracktype="Video" operator="=">YUV</rule>
    <policy type="or" name="Is the video bit depth 8 or 10?">
        <rule name="Is the video 2yuv?" value="CodecID" tracktype="Video" operator="=">2vuy</rule>
        <!--MediaInfo library does not currently store explicit video BitDepth value for 2yuv-->
        <rule name="Is the video bit depth 8?" value="BitDepth" tracktype="Video" operator="=">8</rule>
        <rule name="Is the video bit depth 10?" value="BitDepth" tracktype="Video" operator="=">10</rule>
    </policy>
    <rule name="Is the video interlaced?" value="ScanType" tracktype="Video" operator="=">Interlaced</rule>
'

CODEC_UNCOMPRESSED_TEST='
    <rule name="Is the bitrate mode CBR?" value="BitRate_Mode" tracktype="Video" operator="=">CBR</rule>
    <policy type="or" name="Is the Codec ID v210 or 2vuy?">
        <rule name="Is the Codec ID v210?" value="CodecID" tracktype="Video" operator="=">v210</rule>
        <rule name="Is the Codec ID 2vuy?" value="CodecID" tracktype="Video" operator="=">2vuy</rule>
    </policy>
'

CODEC_FFV1_TEST='
    <rule name="Is the video format FFV1?" value="Format" tracktype="Video" operator="=">FFV1</rule>
    <rule name="FFV1 is version 3.4 or later?" value="Format_Version" tracktype="Video" operator="&gt;=">3.4</rule>
    <rule name="FFV1 is encoded in GOP size of 1?" value="Format_Settings_GOP" tracktype="Video" operator="=">N=1</rule>
'

STANDARD_NTSC_TEST='
    <policy type="and" name="Is it NTSC?">
        <rule name="Is the height 486?" value="Height" tracktype="Video" operator="=">486</rule>
        <rule name="Is the width 720?" value="Width" tracktype="Video" operator="=">720</rule>
        <rule name="Is the frame rate 29.970?" value="FrameRate" tracktype="Video" operator="=">29.970</rule>
        <rule name="Is the scan order bottom field first?" value="ScanOrder" tracktype="Video" operator="=">BFF</rule>
        <rule name="Are the colour primaries BT.601 NTSC?" value="colour_primaries" tracktype="Video" operator="=">BT.601 NTSC</rule>
        <rule name="Are the matrix coefficients BT.601?" value="matrix_coefficients" tracktype="Video" operator="=">BT.601</rule>
    </policy>
'

# same as above NTSC test but with 480 height
STANDARD_NTSC_ACCESS_TEST='
    <policy type="and" name="Is it NTSC?">
        <rule name="Is the height 480?" value="Height" tracktype="Video" operator="=">480</rule>
        <rule name="Is the width 720?" value="Width" tracktype="Video" operator="=">720</rule>
        <rule name="Is the frame rate 29.970?" value="FrameRate" tracktype="Video" operator="=">29.970</rule>
        <rule name="Is the scan order bottom field first?" value="ScanOrder" tracktype="Video" operator="=">BFF</rule>
        <rule name="Are the colour primaries BT.601 NTSC?" value="colour_primaries" tracktype="Video" operator="=">BT.601 NTSC</rule>
        <rule name="Are the matrix coefficients BT.601?" value="matrix_coefficients" tracktype="Video" operator="=">BT.601</rule>
    </policy>
'

STANDARD_PAL_TEST='
    <policy type="and" name="Is it PAL?">
        <rule name="Is the height 576?" value="Height" tracktype="Video" operator="=">576</rule>
        <rule name="Is the width 720?" value="Width" tracktype="Video" operator="=">720</rule>
        <rule name="Is the frame rate 25.000?" value="FrameRate" tracktype="Video" operator="=">25.000</rule>
        <rule name="Is the scan order top field first?" value="ScanOrder" tracktype="Video" operator="=">TFF</rule>
        <rule name="Are the colour primaries BT.601 PAL?" value="colour_primaries" tracktype="Video" operator="=">BT.601 PAL</rule>
        <policy type="or" name="Are the matrix coefficients BT.601, BT.470 System B, BT.470 System G?">
            <rule name="Are the matrix coefficients BT.470 System B, BT.470 System G?" value="matrix_coefficients" tracktype="Video" operator="=">BT.470 System B, BT.470 System G</rule>
            <rule name="Are the matrix coefficients BT.470 System B/G?" value="matrix_coefficients" tracktype="Video" operator="=">BT.470 System B/G</rule>
            <rule name="Are the matrix coefficients BT.601?" value="matrix_coefficients" tracktype="Video" operator="=">BT.601</rule>
        </policy>
    </policy>
'

AUDIO_CODEC_GENERAL_TEST='
    <policy type="or" name="1 or 2 channels of audio?">
        <rule name="1 channel of audio?" value="Channels" tracktype="Audio" operator="=">1</rule>
        <rule name="2 channels of audio?" value="Channels" tracktype="Audio" operator="=">2</rule>
    </policy>
    <rule name="Is the sample rate 48kHz?" value="SamplingRate" tracktype="Audio" operator="=">48000</rule>
'

AUDIO_CODEC_PCM_TEST='
    <rule name="Is the audio PCM?" value="Format" tracktype="Audio" operator="=">PCM</rule>
    <rule name="Is the endianness Little?" value="Format_Settings_Endianness" tracktype="Audio" operator="=">Little</rule>
    <rule name="Is the signedness Signed?" value="Format_Settings_Sign" tracktype="Audio" operator="=">Signed</rule>
    <rule name="Is the bitrate mode CBR?" value="BitRate_Mode" tracktype="Audio" operator="=">CBR</rule>
    <rule name="Is the audio bit depth 24?" value="BitDepth" tracktype="Audio" operator="=">24</rule>
'

AUDIO_CODEC_FLAC_TEST='
    <rule name="Is the audio FLAC?" value="Format" tracktype="Audio" operator="=">FLAC</rule>
    <policy type="or" name="Bit Depth is 32 or 24?">
        <rule name="Bit Depth is 32?" value="BitDepth" tracktype="Audio" operator="=">32</rule>
        <rule name="Bit Depth is 24?" value="BitDepth" tracktype="Audio" operator="=">24</rule>
    </policy>
'
# define mediaconch test fragment -end

_start_mediaconch_policy(){
    MEDIACONCH_POLICY_TMP="$(_maketemp .mediaconch.xml)"
cat <<MC_START > "${MEDIACONCH_POLICY_TMP}"
<?xml version="1.0"?>
<policy type="and" name="Check validity of a vrecord output">
    <description>This policy tests FFV1 Matroska and Quicktime files made using vrecord and checks their validity</description>
MC_START
}

_end_mediaconch_policy(){
    cat <<MC_END >> "${MEDIACONCH_POLICY_TMP}"
</policy>
<!-- :) -->
MC_END
}

_add_mediaconch_rule_set(){
    if [[ -f "${MEDIACONCH_POLICY_TMP}" ]] ; then
        RULE_SET="${1}"
        echo "$RULE_SET" >> "${MEDIACONCH_POLICY_TMP}"
    fi
}

# command-line options to set media id and original variables
OPTIND=1
while getopts ":hc:erpaxnvI:O:D:i:sG" opt ; do
    case "${opt}" in
        h) _usage ; exit 0 ;;
        c) CONFIG_FILE="${OPTARG}" ;;
        e) RUNTYPE="edit" ;;
        r) RUNTYPE="record" ;;
        p) RUNTYPE="passthrough" ;;
        a) RUNTYPE="audiopassthrough" ;;
        x) RUNTYPE="reset" ;;
        n) RUNTYPE="resetenvironment" ;;
        v) VERBOSE="true" ;;
        I) EXTRAINPUTOPTIONS=(${OPTARG}) ;;
        O) EXTRAOUTPUTOPTIONS=(${OPTARG}) ;;
        D) DEPENDENCYDIR=("${OPTARG}") && RUNTYPE="resetenvironment";;
        i) ALT_INPUT="${OPTARG}" ;;
        s) SIGNAL_INPUT="true" ;;
        G) VERBOSE_GTKDIALOG="Y" ;;
        :) _report -w "Option -${OPTARG} requires an argument" ; _usage ; exit 1 ;;
        *) _report -w "Error: bad option -${OPTARG}" ; _usage ; exit 1 ;;
    esac
done
shift "$((OPTIND-1))"

if [[ -z "${1}" ]] && [[ -z "${RUNTYPE}" ]] ; then
    _report -d "Starting the vrecord GUI. To bypass the GUI, run like 'vrecord FILENAME'."
    RUNTYPE="edit"
elif [[ -n "${1}" ]] && [[ -z "${RUNTYPE}" ]] ; then
    ID="${1}"
    RUNTYPE="record"
fi

VRECORD_INPUT_TMP="$(_maketemp .vrecord_input.log)"
FFREPORT_TMP="$(_maketemp .cffreport.txt)"
CAP_DISPLAY_TMP="$(_maketemp .caption_scroll.txt)"

# manage an include file to pass variables to gtkdialog
VRECORD_VARS_FILE="/tmp/v_$(echo "${0}" | sed -e "s/[^A-Za-z0-9.]/_/g")_variables.txt"

# setup extra binary path for packaged version
if [[ "$(dirname "$(command -v "${0}")")" = "/usr/local/bin" ]] ; then
    if [[ -d "/usr/local/lib/vrecord/bin" ]] ; then
        export PATH="/usr/local/lib/vrecord/bin:${PATH}"
    fi
fi

_process_vars_for_gtk

SHARED_FUNCTIONS_FILE="${RESOURCE_PATH}/vrecord_functions"
. "${SHARED_FUNCTIONS_FILE}"

# optional dependency checks
DECKCONTROL_INSTALLED="$(if command -v deckcontrol >/dev/null ; then echo true ; else echo false ; fi)"
GNUPLOT_INSTALLED="$(if command -v gnuplot >/dev/null ; then echo true ; else echo false ; fi)"
MEDIACONCH_INSTALLED="$(if command -v mediaconch >/dev/null ; then echo true ; else echo false ; fi)"
MKVPROPEDIT_INSTALLED="$(if command -v mkvpropedit >/dev/null ; then echo true ; else echo false ; fi)"
MPV_INSTALLED="$(if command -v mpv >/dev/null ; then echo true ; else echo false ; fi)"
QCLI_INSTALLED="$(if command -v qcli >/dev/null ; then echo true ; else echo false ; fi)"
DVPACKAGER_INSTALLED="$(if command -v dvpackager >/dev/null ; then echo true ; else echo false ; fi)"

_upgrade_config_file(){
    # update value because the framemd5 choice changed from a yes/no picklist to a boolean as was the case in version 2023-08-07 and earlier
    if [[ -n "$(grep "FRAMEMD5_CHOICE=\"[YN]" "${CONFIG_FILE}")" ]] ; then
        sed 's|FRAMEMD5_CHOICE="No"|FRAMEMD5_CHOICE="false"|g;s|FRAMEMD5_CHOICE="Yes"|FRAMEMD5_CHOICE="true"|g' > "${CONFIG_FILE}tmp" < "${CONFIG_FILE}"
        _mv_tmp_file "${CONFIG_FILE}tmp" "${CONFIG_FILE}"
    fi
}

_mv_tmp_file(){
    # this is to move a temp file into its final place without really worrying about preserving owner and group file attributes
    TMP_FROM="${1}"
    TMP_TO="${2}"
    TMP_DIR=$(dirname -- "${TMP_TO}")
    if [[ -e "${TMP_TO}" ]]; then
        _report -w "ERROR: _mv_tmp_file, destination ${TMP_TO} already exists"
        exit 1
    fi
    if [[ ! -d "${TMP_DIR}" ]] ; then
        _report -w "WARNING: logging directory ${TMP_DIR} does not exist"
    fi

    if [[ ! -w "${TMP_DIR}" ]] ; then
        _report -w "WARNING: logging directory ${TMP_DIR} is not writable"
    fi
    if [[ -f "${TMP_FROM}" ]] ; then
        cp -p "${TMP_FROM}" "${TMP_TO}" && rm "${TMP_FROM}"
    else
        _report -w "ERROR _mv_tmp_file is moving ${TMP_FROM} but it doesn't exist"
        exit 1
    fi
}

if [[ -f "${CONFIG_FILE}" ]] ; then
    _upgrade_config_file
    . "${CONFIG_FILE}"
else
    _report -d "Initializing the configuration file at ${CONFIG_FILE}."
    RUNTYPE="edit"
    STARTUP_VIEW="INPUTSETTINGS"
fi

_get_inputs

if [[ "${OS_TYPE}" = "linux" ]] ; then
    while read audio_device ; do
        AUDIO_DEVICES+=("${audio_device}")
    done < <(arecord -l | grep card | cut -d ':' -f1-2 | awk '{$1=$1;print}')
elif [[ "${OS_TYPE}" = "macOS" ]] ; then
    AUDIO_DEVICES=("${AVFOUNDATION_DEVICES[@]}")
fi

# list of selections for each vrecord option
VIDEO_INPUT_OPTIONS=("Composite" "SDI" "Component" "S-Video")
AUDIO_INPUT_OPTIONS=("Analog" "SDI Embedded Audio" "Digital Audio (AES/EBU)")
CONTAINER_OPTIONS=("QuickTime" "Matroska" "AVI" "MXF" "MP4")
DV_CONTAINER_OPTIONS=("DV" "Matroska" "QuickTime")
VIDEO_CODEC_OPTIONS=("Uncompressed Video" "FFV1 version 3" "JPEG2000" "ProRes" "ProRes (HQ)" "h264" "HuffYUV")
FFV1_SLICE_OPTIONS=("4" "6" "9" "12" "16" "24" "30")
AUDIO_CODEC_OPTIONS=("24-bit PCM" "24-bit FLAC" "AAC")
AUDIO_CHANNEL_CHOICE_OPTIONS=("Mono" "Stereo")
AUDIO_MODE_SR_CHOICE_OPTIONS=("96 kHz" "48 kHz" "44.1 kHz")
VIDEO_BITDEPTH_OPTIONS=("10 bit" "8 bit")
ASPECT_RATIO_OPTIONS=("4/3" "16/9")
NTSC_43_SAR_OPTIONS=("10/11" "8/9" "9/10" "4320/4739")
NTSC_169_SAR_OPTIONS=("40/33" "32/27" "6/5" "5760/4739")
PAL_43_SAR_OPTIONS=("12/11" "16/15" "128/117")
PAL_169_SAR_OPTIONS=("16/11" "64/45" "512/351")
CHANNEL_MAPPING_OPTIONS=("2 Stereo Tracks (Channels 1 & 2 -> 1st Track Stereo, Channels 3 & 4 -> 2nd Track Stereo)" "1 Stereo Track (From Channels 1 & 2)" "1 Stereo Track (From Channels 3 & 4)" "Channel 1 -> 1st Track Mono, Channel 2 -> 2nd Track Mono" "Channel 2 -> 1st Track Mono, Channel 1 -> 2nd Track Mono" "Channel 1 -> Single Track Mono" "Channel 2 -> Single Track Mono")
TIMECODE_OPTIONS=("none" "rp188vitc" "rp188vitc2" "rp188ltc" "rp188any" "vitc" "vitc2" "serial")
if [[ ${HD_CHOICE} != "true" ]] ; then
  STANDARD_OPTIONS=("NTSC" "PAL")
else
  STANDARD_OPTIONS=("NTSC" "PAL" "23ps - 1080p23.98" "24ps - 1080p24" "Hp25 - 1080p25" "Hp29 - 1080p29.97" "Hp30 - 1080p30" "Hi50 - 1080i50" "Hi59 - 1080i59.94" "Hi60 - 1080i60" "hp50 - 720p50" "hp59 - 720p59.94" "hp60 - 720p60")
fi
# STANDARD_OPTIONS list must be synced with Resources/vrecord_functions in _get_format_list
QCTOOLSXML_OPTIONS=("Yes, concurrent with recording" "Yes, after recording" "No")
EMBED_LOGS_OPTIONS=("Yes" "No")
PLAYBACKVIEW_OPTIONS=("Unfiltered" "Visual" "Audio + Video" "Visual + Numerical" "Color Matrix" "Bit Planes" "Frame Positioning" "Captions")
PLAYBACKVIEW_PASS_OPTIONS=("Unfiltered" "Visual" "Audio + Video" "Visual + Numerical" "Color Matrix" "Bit Planes" "Frame Positioning" "Captions")
if $MPV_INSTALLED ; then
    PLAYBACKVIEW_OPTIONS+=("Quality Control View (mpv)")
    PLAYBACKVIEW_PASS_OPTIONS+=("Quality Control View (mpv)")
fi
WAVEFORM_SCALE_OPTIONS=("digital" "millivolts" "ire")
SIGNAL_OPTIONS=("Broadcast Range" "Full Range")
INT_OPTIONS=("auto" "bff" "tff" "prog")
MONITOR_AUDIO_OPTIONS=("Yes" "No")

# CLI reset, edit modes
if [[ "${RUNTYPE}" = "reset" ]] ; then
    _report -q -n "Resetting the configuration will clear ${CONFIG_FILE}. Please enter [Y] to confirm: "
    read RESET_RESPONSE
    if [[ "${RESET_RESPONSE}" = [Yy] ]] ; then
        _report -d "Clearing ${CONFIG_FILE}."
        echo -n "" > "${CONFIG_FILE}"
        RUNTYPE="edit"
        STARTUP_VIEW="INPUTSETTINGS"
    else
        _report -d "Reset aborted. Exiting."
        exit 0
    fi
fi

if [[ "${RUNTYPE}" = "resetenvironment" ]] ; then
    if [[ -n "${DEPENDENCYDIR}" ]] ; then
        _report -q -n "Rewriting the configuration to include dependencies found in ${DEPENDENCYDIR}. Please enter [Y] to confirm: "
    else
        _report -q -n "Resetting the configuration will clear ${VRECORD_VARS_FILE}. Please enter [Y] to confirm: "
    fi
    read RESET_RESPONSE
    if [[ "${RESET_RESPONSE}" = [Yy] ]] ; then
        _report -d "Clearing ${VRECORD_VARS_FILE}."
        _remove_env_vars
        _process_vars_for_gtk
        RUNTYPE="edit"
        STARTUP_VIEW="INPUTSETTINGS"
    else
        _report -d "Reset aborted. Exiting."
        exit 0
    fi
fi

while [[ "${RUNTYPE}" = "edit" ]] ; do
    STARTUP_VIEW="INPUTSETTINGS"
    _edit_mode
done

_start_mediaconch_policy
_add_mediaconch_rule_set "${CONTAINER_GENERAL_TEST}"
if [[ ! "${VIDEO_CODEC_CHOICE}" = "h264" ]] ; then
    _add_mediaconch_rule_set "${CODEC_GENERAL_TEST}"
fi
_add_mediaconch_rule_set "${AUDIO_CODEC_GENERAL_TEST}"
if [[ "${AUDIO_CODEC_CHOICE}" = "24-bit PCM" ]] ; then
    _add_mediaconch_rule_set "${AUDIO_CODEC_PCM_TEST}"
elif [[ "${AUDIO_CODEC_CHOICE}" = "24-bit FLAC" ]] ; then
    _add_mediaconch_rule_set "${AUDIO_CODEC_FLAC_TEST}"
fi
_review_all_options

# CLI passthrough and audiopassthrough modes
if [[ "${RUNTYPE}" = "passthrough" ]] ; then
    _passthrough_mode
    exit 0
elif [[ "${RUNTYPE}" = "audiopassthrough" ]] ; then
    _audiopassthrough_mode
    exit 0
fi

while [[ -z "${ID}" ]] ; do
    _report -q -n "Enter ${AHEM}Identifier: "
    read ID
    if [[ "${ID}" = "q" ]] ; then
        _report -w "Interpreting 'q' to quit."
        exit 1
    fi
    AHEM="a (non-blank) "
done
DIR="$(echo "${DIR}" | sed "s/^['\"]\(.*\).$/\1/")"
if [[ -z "${DIR}" ]] ; then
    _report -d "We'll record files to $(pwd)."
    DIR="$(pwd)"
elif [[ ! -d "${DIR}" ]] ; then
    _report -w "Error: The recording directory at ${DIR} is not a valid directory. Let's use $(pwd) instead."
    DIR="$(pwd)"
fi
LOGDIR="$(echo "${LOGDIR}" | sed "s/^['\"]\(.*\).$/\1/")"
if [[ -z "${LOGDIR}" ]] ; then
    _report -d "And place logs at ${DIR} too."
    LOGDIR="${DIR}"
elif [[ ! -d "${LOGDIR}" ]] ; then
    _report -w "Error: The directory for auxiliary files at ${DIR} is not a valid directory. Let's use ${DIR} instead."
    LOGDIR="${DIR}"
fi

if [[ "${DEVICE_INPUT_CHOICE}" = "0" ]] ; then
    _review_option "CONTAINER_CHOICE" "${CONTAINER_OPTIONS[@]}"
    _review_option "VIDEO_CODEC_CHOICE" "${VIDEO_CODEC_OPTIONS[@]}"
    if [[ "${VIDEO_CODEC_CHOICE}" = "FFV1 version 3" ]] ; then
        _review_option -n -d "16" "FFV1_SLICE_CHOICE" "${FFV1_SLICE_OPTIONS[@]}"
    fi
    _review_option "AUDIO_CODEC_CHOICE" "${AUDIO_CODEC_OPTIONS[@]}"
elif [[ "${DEVICE_INPUT_CHOICE}" = "1" ]] ; then
    _review_option "DV_CONTAINER_CHOICE" "${DV_CONTAINER_OPTIONS[@]}"
    FORMAT="rawvideo"
    EXTENSION='dv'
elif [[ "${DEVICE_INPUT_CHOICE}" = "2" ]] ; then
    _review_option "AUDIO_MODE_CODEC_CHOICE" "${AUDIO_CODEC_OPTIONS[@]}"
    EXTENSION="${AUDIO_EXT}"
    FORMAT="${AUDIO_EXT}"
fi

_end_mediaconch_policy

# Check for user suffix to override automatic settings
if [[ -n "${USER_SUFFIX}" ]] ; then
    SUFFIX="${USER_SUFFIX}"
fi

FULL_OUTPUT_ID="${PREFIX}${ID}"
if [[ "${YES_SUFFIX}" = 'true' ]] ; then
    FULL_OUTPUT_ID="${PREFIX}${ID}${SUFFIX}"
else
    FULL_OUTPUT_ID="${PREFIX}${ID}"
fi
FULL_CAPTURE_LOG="${LOGDIR}/${FULL_OUTPUT_ID}${CAPTURELOGSUFFIX}"
TIMECODE_LOG="${LOGDIR}/${FULL_OUTPUT_ID}_${TC_TYPE}${TIMECODELOGSUFFIX}"
CAPTION_LOG="${LOGDIR}/${FULL_OUTPUT_ID}_frame_eia608data.txt"
CAPTION_SCC="${LOGDIR}/${FULL_OUTPUT_ID}.scc"
VRECORD_OUTPUT="${DIR}/${FULL_OUTPUT_ID}.${EXTENSION}"
if [[ -f "${VRECORD_OUTPUT}" ]] ; then
    _report -w "A file called ${VRECORD_OUTPUT} already exists."
    _report -w "Exiting to avoid overwriting that file."
    exit
fi

if [[ "${DEVICE_INPUT_CHOICE}" = "0" ]] ; then
    _review_option "QCTOOLSXML_CHOICE" "${QCTOOLSXML_OPTIONS[@]}"
    if [[ "${QCTOOLSXML_CHOICE}" != "No" && ! "$(command -v qcli)" ]] ; then
        _report -w "Please install qcli to use the qctools reporting option."
        _report -w "Such as \`brew install qcli\`."
        exit 1
    fi
    if [[ "${FRAMEMD5_CHOICE}" = "true" ]] ; then
        FRAMEMD5NAME="${LOGDIR}/${FULL_OUTPUT_ID}.framemd5"
        EXTRAOUTPUTS+=(-an -f framemd5 "${FRAMEMD5NAME}")
    fi
    if [[ "${SIGNAL_INPUT}" = 'true' ]] ; then
            AUDIOMAP=$(sed "s/0:a:0/1:a:0/g" <<< "$AUDIOMAP")
    fi
    if [[ "${MP4_CHOICE}" = "true" ]] ; then
        RECORDINGFILTER_MP4+=",bwdif"
        RECORD_COMMAND_MP4+=(-filter_complex "[0:v:0]${RECORDINGFILTER_MP4#,*}[mp4_v_out];${AUDIOMAP}")
        MP4NAME="${DIR}/${FULL_OUTPUT_ID}.mp4"
        EXTRAOUTPUTS+=("${MIDDLEOPTIONS_ALL[@]}" -movflags write_colr+faststart "${RECORD_COMMAND_MP4[@]}" -pix_fmt yuv420p -c:v h264 -c:a aac -map "[mp4_v_out]" "${AUDIO_CHANNEL_MAP[@]}" "${MP4NAME}")
    fi
    if [[ "${FORMAT}" = "matroska" ]] ; then
        _review_option "EMBED_LOGS_CHOICE" "${EMBED_LOGS_OPTIONS[@]}"
    fi
fi

if [[ -n "${DURATION}" ]] ; then
    DUR_SECONDS=$(bc <<< "${DURATION} * 60" | sed "s/^\./0./")
    TIME_LIMIT=(-t "${DUR_SECONDS}")
    DURATION_TEXT="Tape duration set to: ${DURATION} minutes."
fi

if [[ "${DURATION}" -gt 200 ]] ; then
    _report -w "WARNING: Recording duration set to greater than 200 minutes. QCTools report will not be generated."
    QCTOOLSXML_CHOICE="No"
fi

if [[ -n ${TECHNICIAN} ]] ; then
    TECHNICIAN_TEXT="Technician=${TECHNICIAN}."
fi

if [[ "${DEVICE_INPUT_CHOICE}" = "0" ]] ; then
    _report -d "Summary: ${VIDEOCODECNAME}/${FORMAT} ${PIXEL_FORMAT} file from ${STANDARD} ${VIDEO_INPUT} ${AUDIO_INPUT}. ${TECHNICIAN_TEXT} Frame MD5s=${FRAMEMD5_CHOICE}, QCTools XML=${QCTOOLSXML_CHOICE}. Inputs recorded to ${VRECORD_OUTPUT} and Auxiliary Files created in ${LOGDIR}. ${DURATION_TEXT}"
elif [[ "${DEVICE_INPUT_CHOICE}" = "1" ]] ; then
    _report -d "Summary: Copying video from ${DVRESCUE_INPUT_CHOICE}. ${TECHNICIAN_TEXT} Inputs recorded to ${VRECORD_OUTPUT} and Auxiliary Files created in ${LOGDIR}. ${DURATION_TEXT}"
elif [[ "${DEVICE_INPUT_CHOICE}" = "2" ]] ; then
    _report -d "Summary: Recording audio from ${AUDIO_DEV_CHOICE}. ${TECHNICIAN_TEXT} Inputs recorded to ${VRECORD_OUTPUT} and Auxiliary Files created in ${LOGDIR}. ${DURATION_TEXT}"
fi

if [[ "${DEVICE_INPUT_CHOICE}" = "0" ]] || [[ "${DEVICE_INPUT_CHOICE}" = "2" ]] ; then
    if [[ "${INVERT_PHASE_2}" = "true" ]] ; then
        _report -w "WARNING: Option to invert phase of second audio channel has been selected"
    fi
    if [[ "${INVERT_PHASE_4}" = "true" ]]; then
        _report -w "WARNING: Option to invert phase of fourth audio channel has been selected"
    fi
fi
if [[ "${DEVICE_INPUT_CHOICE}" = "0" ]] ; then
    if [[ "${SIGNAL_INT_CHOICE}" != "auto" ]] ; then
        _report -w "WARNING: The configuration ignores the interlacement of the input and forces it to ${SIGNAL_INT_CHOICE}. Set to 'auto' if you prefer to keep the interlacement as the device describes it."
    fi
fi

_report -q "Hit enter to start recording"
read

# create log of vrecord decisions
INGESTLOG="${LOGDIR}/${FULL_OUTPUT_ID}_capture_options.log"
QCTOOLS_REPORT="${LOGDIR}/${FULL_OUTPUT_ID}.${EXTENSION}.qctools.mkv"
QCXML="$(_maketemp)"
QCLI_COMMAND_PIPE=(qcli -audio 1 -f signalstats+aphasemeter+astats+ssim -i - -o "${QCTOOLS_REPORT}")
QCLI_COMMAND_FILE=(qcli -audio 1 -f signalstats+aphasemeter+astats+ssim -i "${VRECORD_OUTPUT}" -o "${QCTOOLS_REPORT}")
touch "${INGESTLOG}"
_writeingestlog "computer_name" "$(uname -n)"
_writeingestlog "computer_model_name" "${COMPUTER_MODEL_NAME}"
if [[ "${OS_TYPE}" = "macOS" ]] ; then
    _writeingestlog "computer_model_id" "${COMPUTER_MODEL_ID}"
    _writeingestlog "computer_processor_name" "${COMPUTER_PROCESSOR_NAME}"
    _writeingestlog "computer_processor_speed" "${COMPUTER_PROCESSOR_SPEED}"
    _writeingestlog "computer_processor_count" "${COMPUTER_PROCESSOR_COUNT}"
    _writeingestlog "computer_memory" "${COMPUTER_MEMORY}"
    _writeingestlog "computer_serial" "${COMPUTER_SERIAL}"
fi
_writeingestlog "computer_cores" "$CORE_COUNT"
_writeingestlog "user_name" "$(whoami)"
_writeingestlog "operating_system_VERSION" "$(uname -v)"
_writeingestlog "vrecord version" "${VERSION}"
_writeingestlog "datetime_start" "$(_get_iso8601)"

MOUNT_PATH="$(df -Ph "${DIR}" 2>/dev/null | tail -n 1 | awk '{print $6}')"
if [[ "${OS_TYPE}" = "macOS" ]] ; then
    VOLUME_INFO="$(diskutil info "${MOUNT_PATH}")"
    PART_OF_WHOLE="/dev/$(_parse_report "Part of Whole" "${VOLUME_INFO}")"
    CAPTURE_DEVICE_INFO="$(diskutil info "${PART_OF_WHOLE}")"

    _writeingestlog "capture_device_node" "$(_parse_report "Device Node" "${CAPTURE_DEVICE_INFO}")"
    _writeingestlog "capture_device_protocol" "$(_parse_report "Protocol" "${CAPTURE_DEVICE_INFO}")"
    _writeingestlog "capture_device_name" "$(_parse_report "Device / Media Name" "${CAPTURE_DEVICE_INFO}")"
    _writeingestlog "capture_device_block_size" "$(_parse_report "Device Block Size" "${CAPTURE_DEVICE_INFO}")"
    _writeingestlog "capture_device_location" "$(_parse_report "Device Location" "${CAPTURE_DEVICE_INFO}")"
    _writeingestlog "capture_device_partition_type" "$(_parse_report "Partition Type" "${VOLUME_INFO}")"
    _writeingestlog "capture_device_partition_name" "$(_parse_report "Name (User Visible)" "${VOLUME_INFO}")"
    _writeingestlog "capture_device_volume_uuid" "$(_parse_report "Volume UUID" "${VOLUME_INFO}")"
    _writeingestlog "capture_device_volume_available" "$(_parse_report "Volume Available Space" "${VOLUME_INFO}")"
    _writeingestlog "capture_device_volume_total" "$(_parse_report "Volume Total Space" "${VOLUME_INFO}")"
fi

_writeingestlog "FILE_PATH" "${VRECORD_OUTPUT}"

if [[ "${DEVICE_INPUT_CHOICE}" = 0 ]] ; then
    if [[ -n "${VIDEO_CARD_DRIVER_VERSION}" ]] ; then
        _writeingestlog "video_card_driver_version" "${VIDEO_CARD_DRIVER_VERSION}"
    fi
    _writeingestlog "video_card_name" "${DECKLINK_INPUT_CHOICE}"
fi

echo -e "${LOG_OF_OPTIONS}" >> "${INGESTLOG}"
if [[ -n "${TECHNICIAN}" ]] ; then
    _writeingestlog "TECHNICIAN" "${TECHNICIAN}"
fi
if [[ "${INVERT_PHASE}" = 1 ]] ; then
    _writeingestlog "INVERT_PHASE" "Yes"
fi
if [[ -n "${EXTRAINPUTOPTIONS[@]}" ]] ; then
    _writeingestlog "EXTRA_INPUT_OPTIONS" "${EXTRAINPUTOPTIONS[@]}"
fi
if [[ -n "${EXTRAOUTPUTOPTIONS[@]}" ]] ; then
    _writeingestlog "EXTRA_OUTPUT_OPTIONS" "${EXTRAOUTPUTOPTIONS[@]}"
fi

_report -d "Close the playback window to stop recording."

# vrecord process!
_setup_vrecord_process
if [[ "${VERBOSE_GTKDIALOG}" = "Y" ]] ; then
    echo "STEPS ${VRECORD_STEPS}"
    echo "PLAY ${PLAYER_COMMAND[@]}"
    echo "RECORD ${RECORD_COMMAND[@]}"
    echo "QCLI ${QCLI_COMMAND_PIPE[@]}"
fi
if [[ "${VRECORD_STEPS}" = "2" ]] ; then
    _writeingestlog "Record command" "${RECORD_COMMAND[@]}"
    _writeingestlog "Playback command" "${PLAYER_COMMAND[@]}"

    # start background caption process
    ## disabling cchex_to_display during recording for now. If back here, please kill the CC_PID after use of it is done.
    ## "${SCRIPTDIR}/cchex_to_display" "${FFREPORT_TMP}" "${CAP_DISPLAY_TMP}" > /dev/null 2> /dev/null &
    ## CC_PID=$!
    ## export FFREPORT="file=${FFREPORT_TMP}:level=32"
    "${RECORD_COMMAND[@]}" 2> >(tee "${VRECORD_INPUT_TMP}" 1>&2) | \
    if [[ "${DEVICE_INPUT_CHOICE}" = 0 ]] && [[ "${QCTOOLSXML_CHOICE}" = "Yes, concurrent with recording" ]]; then
        tee >("${PLAYER_COMMAND[@]}") | "${QCLI_COMMAND_PIPE[@]}"
    else
        "${PLAYER_COMMAND[@]}"
    fi
else
    _report_unexpected_error VRECORD_STEPS
fi
# capture errors from components of recording pipe
RESULTING_EXIT_CODES=("${PIPESTATUS[@]}")
P1_ERR="${RESULTING_EXIT_CODES[0]}"
P2_ERR="${RESULTING_EXIT_CODES[1]}"

if [[ "${VRECORD_STEPS}" = "2" ]] ; then
    _writeingestlog "Record exit code" "${P1_ERR}"
    _writeingestlog "Playback exit code" "${P2_ERR}"
fi

if [[ ! -s "${VRECORD_OUTPUT}" ]] ; then
    if [[ "$P1_ERR" != "0" ]] ; then
        _report_unexpected_error P1_ERR "${RECORD_COMMAND[@]} // ${PLAYER_COMMAND}"
    fi
    if [[ "$P2_ERR" != "0" && -n "$P2_ERR" ]] ; then
        _report_unexpected_error P2_ERR "${RECORD_COMMAND[@]} // ${PLAYER_COMMAND}"
    fi
fi

_mv_tmp_file "${VRECORD_INPUT_TMP}" "${FULL_CAPTURE_LOG}"
_writeingestlog "datetime_end" "$(_get_iso8601)"
trap _cleanup SIGHUP SIGINT SIGTERM

if [[ "${DEVICE_INPUT_CHOICE}" = 0 ]] ; then
    # timecode document handling
    if [[ -f "${TC_TMP}" ]] ; then
        _mv_tmp_file "${TC_TMP}" "${TIMECODE_LOG}"
    fi
    # caption handling
    if [[ -s "${CAPTION_TMP}" ]] ; then
        _mv_tmp_file "${CAPTION_TMP}" "${CAPTION_LOG}"
        _eia608dump2scc "${CAPTION_LOG}" "${CAPTION_SCC}"
        if [[ "${CC2VTT}" = 'true' ]] ; then
            "${FFMPEG_BIN}" -nostdin -v 0 -y -i "${CAPTION_SCC}" "${CAPTION_SCC%.*}.vtt"
        fi
        if [[ "${CC2SRT}" = 'true' ]] ; then
            "${FFMPEG_BIN}" -nostdin -v 0 -y -i "${CAPTION_SCC}" "${CAPTION_SCC%.*}.srt"
        fi
    fi

    # qc tools process
    if [[ "${QCTOOLSXML_CHOICE}" = "Yes, after recording" ]] ; then
        "${QCLI_COMMAND_FILE[@]}"
    fi
    if [[ "${QCTOOLSXML_CHOICE}" != "No" ]] ; then
        _report -d "Vrecord is analyzing your video file. Please be patient."
        if [[ -s "${QCTOOLS_REPORT}" ]] ; then
            if [[ ! -s "${QCXML}" ]] ; then
                "${FFMPEG_BIN}" -nostdin -v 0 -y -dump_attachment:t "${QCXML}" -i "${QCTOOLS_REPORT}"
            fi
            if [[ "${PIXEL_FORMAT}" = "yuv422p10" ]] ; then
                SAT_OUTLIERS=$("${ZCAT_COMMAND}" "${QCXML}" | perl -nle 'print if not m{lavfi.(?!signalstats.SATMAX)}' | xmlstarlet sel -t -v "count(//tag[@key='lavfi.signalstats.SATMAX'][@value>496])" -n)
            elif [[ "${PIXEL_FORMAT}" = "uyvy422" ]] ; then
                SAT_OUTLIERS=$("${ZCAT_COMMAND}" "${QCXML}" | perl -nle 'print if not m{lavfi.(?!signalstats.SATMAX)}' | xmlstarlet sel -t -v "count(//tag[@key='lavfi.signalstats.SATMAX'][@value>124])" -n)
            fi
            AUD_OUTLIERS=$("${ZCAT_COMMAND}" "${QCXML}" | perl -nle 'print if not m{lavfi.(?!astats.Overall.Peak_level)}' | grep -v "tag key=\"lavfi.[^a]" | xmlstarlet sel -t -v "count(//tag[@key='lavfi.astats.Overall.Peak_level'][@value>=-0.01])" -n)
            BRNG_OUTLIERS=$("${ZCAT_COMMAND}" "${QCXML}" | perl -nle 'print if not m{lavfi.(?!signalstats.BRNG)}' | xmlstarlet sel -t -v "count(//tag[@key='lavfi.signalstats.BRNG'][@value>=0.03])" -n)
            AUDIO_PEAK=$("${ZCAT_COMMAND}" "${QCXML}" | grep lavfi.astats.Overall.Peak_level | cut -d '"' -f 4 | sort -n | tail -n 1)
            _writeingestlog "Peak Volume is (dB)" "${AUDIO_PEAK}"
            if "$GNUPLOT_INSTALLED" && "$QCLI_INSTALLED" ; then
                _report -d "Vrecord is generating graphs from the QCTools data. One moment please."
                _qcgraphimage "${QCXML}"
            fi
        else
            _report -w "qctools XML ${QCTOOLS_REPORT} is empty or does not exist!"
        fi
        if [[ "${SAT_OUTLIERS}" -gt "${SAT_OUTLIER_THRSHLD}" ]] ; then
            cowsay "$(_report -w "WARNING: Your video file contains ${SAT_OUTLIERS} frames with illegal saturation values. Your deck may require cleaning.")"
        fi
        if [[ "${AUD_OUTLIERS}" -gt "${AUD_OUTLIER_THRSHLD}" ]] ; then
            cowsay "$(_report -w "WARNING: Your video file contains ${AUD_OUTLIERS} frames with clipped audio levels.")"
        fi
        if [[ "${BRNG_OUTLIERS}" -gt "${BRNG_OUTLIER_THRSHLD}" ]] ; then
            cowsay "$(_report -w "WARNING: Your video file contains ${BRNG_OUTLIERS} frames with pixels out of broadcast range.")"
        fi
        _report -d "QCTools analysis is complete."
    fi

    # check for discontinuities in the Frame MD5s; if user chose not to use Frame MD5s, check for frame discontinuties in the FFmpeg file
    if [[ "${FRAMEMD5_CHOICE}" = "true" ]] ; then
        PTS_DISCONTINUITY=$(cat "${FRAMEMD5NAME}" | grep -v "^#" | cut -d, -f3 | sed 's/ //g' | grep -v "^0$" | awk '{if($1!=p+1){if(p+1==$1-1){printf p+1" "}else{printf p+1"-"$1-1" "}}{p=$1}}')
        if [[ -z "${PTS_DISCONTINUITY}" ]] ; then
            _writeingestlog "PTS_DISCONTINUITY" "none"
        else
            _writeingestlog "PTS_DISCONTINUITY" "${PTS_DISCONTINUITY}"
            cowsay "$(_report -w "WARNING: There were presentation timestamp discontinuities in the file's frame MD5s for these frame ranges: ${PTS_DISCONTINUITY}. This error may indicate frames dropped by FFmpeg or vrecord. The file may have sync issues.")"
        fi
    elif [[ "${FRAMEMD5_CHOICE}" = "false" ]] ; then
        FRAMES_ENCODED=$(cat "${LOGDIR}/${FULL_OUTPUT_ID}"_vrecord_input.log | grep -w "frames encoded" | awk '{print $10}' | grep -m 1 [0-9])
        FRAMES_DECODED=$(cat "${LOGDIR}/${FULL_OUTPUT_ID}"_vrecord_input.log | grep -w "frames decoded" | awk '{print $10}' | grep -m 1 [0-9])
        if [[ "${FRAMES_ENCODED}" -lt $((FRAMES_DECODED-1)) ]] ; then
            FRAMES_DISCREPANCY=$((FRAMES_DECODED-FRAMES_ENCODED))
            cowsay "$(_report -w "WARNING: There were presentation timestamp discontinuities found in the framemd5s. This error may indicate frames dropped by FFmpeg or vrecord. The file may have sync issues.")"
            _writeingestlog "ffmpeg_missing_frames" "${FRAMES_DISCREPANCY}"
        else
            _writeingestlog "ffmpeg_missing_frames" "None"
        fi
    fi

    # check for frames dropped in ffmpeg_input.log
    DROPPED_FRAMES_INSTANCES=$(grep -c "Frames dropped" "${FULL_CAPTURE_LOG}")
    DROPPED_FRAMES_FRAMENUMBERS=$(grep "Frames dropped" "${FULL_CAPTURE_LOG}" | awk '{print $6}' | sed 's/[(#)]//g')
    if [[ "${DROPPED_FRAMES_INSTANCES}" -gt 0 ]] ; then
        cowsay "$(_report -w "WARNING: FFmpeg Decklink input reported dropped frames in the following ${DROPPED_FRAMES_INSTANCES} locations. This error may indicate an interrupted signal between hardware components. The file may be missing content. With decklink inputs, this cow recommends reviewing your settings in Desktop Video Setup and setting the video and audio inputs to match what those set in vrecord.")"
        for i in ${DROPPED_FRAMES_FRAMENUMBERS} ; do # do not quote this variable
            DROPPED_FRAMES_TIMESTAMPS+="$(_frames_to_hhmmss "${i}") "
        done
        _report -w "Dropped frames timestamps: ${DROPPED_FRAMES_TIMESTAMPS}"
        _writeingestlog "DROPPED_FRAMES_TIMESTAMPS" "${DROPPED_FRAMES_TIMESTAMPS}"
    fi

    # check for input buffer overrun error
    BUFFER_OVERRUN=$(grep -c "Decklink input buffer overrun" "${FULL_CAPTURE_LOG}")
    if [[ "${BUFFER_OVERRUN}" -gt 0 ]] ; then
        cowsay "$(_report -w "WARNING: FFmpeg Decklink input reported a buffer overrun. The file is likely missing frames or contains artifacts from the buffer overrun.")"
        _writeingestlog "Decklink input buffer overrun" "Yes"
    fi

    # policy checks with mediaconch
    if "$MEDIACONCH_INSTALLED" ; then
        _report -d "Checking file conformance against a mediaconch policy..."
        STATUS=$(mediaconch -fx -p "${MEDIACONCH_POLICY_TMP}" "${VRECORD_OUTPUT}" | xmlstarlet sel -N mc="https://mediaarea.net/mediaconch" -t -v mc:MediaConch/mc:media/mc:policy/@outcome -n)
        if [[ "${STATUS}" = "pass" ]] ; then
            _report -dt "File passed policy check for the video."
            _writeingestlog "mediaconch_outcome" "passed"
        elif [[ "${STATUS}" = "fail" ]] ; then
            _report -wt "File did not pass vrecord policy check and may not conform to digital preservation standards."
            mediaconch -fx -p "${MEDIACONCH_POLICY_TMP}" "${VRECORD_OUTPUT}" | xmlstarlet fo > "${DIR}/${FULL_OUTPUT_ID}_mediaconchreport.xml"
            _mv_tmp_file "${MEDIACONCH_POLICY_TMP}" "${DIR}/${FULL_OUTPUT_ID}_mediaconch_policy.xml"
            _writeingestlog "mediaconch_outcome" "failed ${DIR}/${FULL_OUTPUT_ID}_mediaconch_policy.xml"
            _report -wt "See ${DIR}/${FULL_OUTPUT_ID}_mediaconchreport.xml for a full MediaConch policy report."
            _report -wt "Or review this attempt to summarize the issue:"
            xmlstarlet edit -N "mc=https://mediaarea.net/mediaconch" -d "//*[@outcome='pass']" "${DIR}/${FULL_OUTPUT_ID}_mediaconchreport.xml"
        else
            _report -wt "Mediaconch ended in an unexpected way (${STATUS}). Here is its output."
            mediaconch -p "${MEDIACONCH_POLICY_TMP}" "${VRECORD_OUTPUT}"
        fi
    fi

    # embed logs in Matroska files
    if "$MKVPROPEDIT_INSTALLED" ; then
        if [[ "${CONTAINER_CHOICE}" = "Matroska" ]] && [[ "${EMBED_LOGS_CHOICE}" = "Yes" ]] ; then
            _report -d "Vrecord is attaching logs to your Matroska file:"
            mkvpropedit "${VRECORD_OUTPUT}" --attachment-description "Capture options selected by user during vrecord process" --add-attachment "${INGESTLOG}"
            mkvpropedit "${VRECORD_OUTPUT}" --attachment-description "Full FFmpeg output from vrecord capture process" --add-attachment "${FULL_CAPTURE_LOG}"
            if [[ "${QCTOOLSXML_CHOICE}" = "Yes" ]] ; then
                mkvpropedit "${VRECORD_OUTPUT}" --attachment-description "QCTools report from vrecord capture process (zipped XML)" --add-attachment "${QCXML}"
                mkvpropedit "${VRECORD_OUTPUT}" --attachment-description "QCTools report from vrecord capture process (Matroska report)" --add-attachment "${QCTOOLS_REPORT}"
            fi
            _report -d "Vrecord is done attaching logs to your Matroska file!"
        fi
    fi
    if [[ -f "${QCXML}" ]] ; then
        rm "${QCXML}"
    fi
elif [[ "${DEVICE_INPUT_CHOICE}" == "1" ]] ; then
    if "$DVPACKAGER_INSTALLED" ; then
        if [[ -n "${DV_RESCUE_OPTS}" ]] || [[ "${DV_EXTENSION}" != 'dv' ]] ; then
            _dvpackager "${VRECORD_OUTPUT}"
        fi
    fi
fi
