#!/bin/bash
#####################################################################
#                                                                   #
#  Compiles Faust programs for the Chaos Stratus pedal with         #
#  optional CPP compile and pedal install                           #
#                                                                   #
#####################################################################

#-------------------------------------------------------------------
#
# Various default variables
#
ARCHFILE=${STRATUS_ARCH:-chaos-stratus/stratus.cpp}
HOSTNAME="$(hostname)"
CPPCOMPILE=true
export TMPDIR=$(mktemp -d)

##
## Install cleanup routine
##
for sig in SIGTERM ERR EXIT; do trap "_term ${sig}" ${sig}; done
_term() {
  trap "" SIGTERM ERR EXIT
  declare -F "disconnectStratus" > /dev/null && disconnectStratus
  rm -rf ${TMPDIR}
  exit 0
}

#-------------------------------------------------------------------
#
# Bring in the Faust environment and the usage utilities,
# and the pedal-specific utilities
#
. faustpath
. usage.sh
. ${FAUSTARCH}/chaos-stratus/_pedal-tools.sh

#-------------------------------------------------------------------
#
# Standard help
#
echoHelp() 
{
    usage faust2stratus "[options] [Faust options] <file.dsp> ... [<file.cpp> ...]"
    platform "Chaos Audio Stratus pedal"
    echo "Compiles Faust programs for the Chaos Audio Stratus pedal"
    echo "  with optional c++ compile for, and effect install to, the pedal"
    echo
    echo "Unlike most other "faust2xxx" scripts, this can also be used to compile"
    echo "  effect c++ code that has been constructed elsewhere, or has been modified "
    echo "  after being generated by the Faust compiler (e.g. where the algorithm c++ code"
    echo "  has been 'tweaked' after generation)"
    echo
    echo "The script can be used to build and install multiple different effects in one go"
    echo
    echo "Running this script with no options except input files will result in effect libraries"
    echo "  built for the platform upon which the script is executed, not for the pedal"
    echo
    echo "Options:"
    option "-nocppc" "Do not compile the generated c++ source files"
    option "-nodocker" "Do not use docker for pedal builds even if it is available"
    option "-stratusbuild" "Generates the c++ code locally, then builds the effect library for the Stratus pedal"
    option "-stratusinstall" "Generates the c++ code locally, then builds and installs the effect library for the Stratus pedal"
    echo
    option "Faust options"
    echo   "     the script automatically uses '-i -scn FaustDSP -light -nvi'"
    echo   "     -O and/or -o can be used, otherwise all output is in the same folder as the corresponding input"
    exit
}

#-------------------------------------------------------------------
#
# Initial sniff test
#
if [ "$#" -eq 0 ]; then
    echo 'Please, provide a Faust file to process !'
    echo ''
    echoHelp
fi

#-------------------------------------------------------------------
#
# Pick out the Faust and Stratus options
#
OPTIONS="-i -scn FaustDSP -light -nvi"
STRATUSCLASS=dsp
while [[ "$1" ]]; do
    opt=$1
    shift
    if [[ "${opt}" =~ ^--?"help"$ || ${opt} == "-h" ]]; then
        echoHelp
    elif [[ "${opt}" =~ ^--?"stratusc"$ ]]; then
        # Ignore obsolete option
        true
    elif [[ "${opt}" =~ ^--?"stratusbuild"$ ]]; then
        STRATUSBUILD="true"
    elif [[ "${opt}" =~ ^--?"stratusinstall"$ ]]; then
        STRATUSBUILD="true"
        STRATUSINSTALL="true"
    elif [[ "${opt}" =~ ^--?"nocppc"$ ]]; then
        CPPCOMPILE="false"
    elif [[ "${opt}" =~ ^--?"nodocker"$ ]]; then
        NO_DOCKER="-nodocker"
    elif [[ "${opt}" =~ ^--?"stratusclass"$ ]]; then
        STRATUSCLASS=${1:-dsp}
        shift
    elif [[ "${opt}" =~ ^--?"o"$ ]]; then
        OUTPUT_FILE=${1:-}
        shift
    elif [[ "${opt}" =~ ^--?"O"$ ]]; then
        OUTPUT_DIR=${1:-}
        shift
    elif [[ "${opt}" =~ ^--?"a"$ ]]; then
    #
    # Used to test other versions of the Stratus arch file!
    #
        ARCHFILE=${1:-stratus.cpp}
        shift
    elif [[ -f "${opt}" && ${opt: -4} == ".dsp" ]]; then
        FILES="${FILES} ${opt}"
    elif [[ -f "${opt}" && ${opt: -4} == ".cpp" ]]; then
        CPPFILES="${CPPFILES} ${opt}"
    else
        OPTIONS="${OPTIONS} ${opt}"
    fi
done

#-------------------------------------------------------------------
# compile the *.dsp files using faust and ${CXX}
#

#
# OUTPUT_DIR is -O, or the dirname of -o, or (eventually) where the input comes from
#
OUTPUT_DIR=${OUTPUT_DIR:-${OUTPUT_FILE:+$(dirname "$([[ ! "${OUTPUT_FILE}" =~ ^/ ]] && echo "${PWD}/")${OUTPUT_FILE}")}}
OUTPUT_FILE=${OUTPUT_FILE:+$(basename ${OUTPUT_FILE})}

for f in ${FILES}; do

    # Some old Macs don't have realpath!
    EFFECT="$([[ ! "${f}" =~ ^/ ]] && echo "${PWD}/")${f}"

    EFFECT_OUPUT_DIR=${OUTPUT_DIR:-$(dirname "${EFFECT}")}

    # Derive the c++ file name based on -o (first only) or the input file name
    EFFECT_FILENAME="${OUTPUT_FILE:-$(basename ${EFFECT})}"

    # -o, if presented, is interpreted as the Faust compiler output file name (first only)
    EFFECT_CPP="${EFFECT_OUPUT_DIR}/${OUTPUT_FILE:-${EFFECT_FILENAME%.*}.cpp}"

    # In a multi-file build, the "-o" option can only apply to the first DSP file
    OUTPUT_FILE=""
    
    # compile faust to c++
    echo "Building effect ${EFFECT_CPP} with Faust:"
    echo "  Faust options: -a ${ARCHFILE} ${OPTIONS} ${EFFECT} -o ${EFFECT_CPP}"

    faust -json -a ${ARCHFILE} ${OPTIONS} "${EFFECT}" -o "${EFFECT_CPP}" || exit

    CPPFILES="${EFFECT_CPP} ${CPPFILES}"
done

#
# And now the CPP files - generated and specified
#
if [[ "${CPPCOMPILE}" == "true" ]]; then
    for EFFECT_CPP in ${CPPFILES}; do
        EFFECT_SO="${EFFECT_CPP%.cpp}.so"
        setIDandVersion "${EFFECT}.json"
  
        #
        # If we are building or installing for the Stratus we use pedalBuild, otherwise we use buildLocal
        #
        if [[ "${STRATUSBUILD}" == "true" ]]; then
            pedalBuild $NO_DOCKER "${EFFECT_CPP}" "${EFFECT_SO}" || { echo "Pedal build of ${EFFECT_CPP} failed"; exit 1; }
            if [[ "${STRATUSINSTALL}" == "true" ]]; then
                [[ -z "${EFFECT_ID}" ]] && { echo "Unable to find 'stratusId' in ${EFFECT_CPP} - install not possible"; continue; }
                pedalInstall "${EFFECT_SO}" "${EFFECT_ID}" "${EFFECT_VERSION}" || { echo "Pedal install of ${EFFECT_SO} failed"; exit 1; }
            fi
        else
            buildLocal $NO_DOCKER "${EFFECT_CPP}" "${EFFECT_SO}" || { echo "Local build of ${EFFECT_CPP} failed"; exit 1; }
        fi
    done
else
    [[ "$CPPFILES" ]] && echo "Not compiling ${CPPFILES} (-nocppc specified)"
fi
