#!/bin/sh
# voiceCommon.sh
#
# Copyright (c) 2006 Jonas Häggqvist
# Licensed under version 2 of the GPL
#
# A selection of functions common to creating voicefiles for Rockbox.
# 
# You may wish to change some of the settings below.
#
# Bugs:
# - Probably full of bashisms
# - And more, I'm sure
# Todo:
# - Implement trim()

#####################
# Program locations #
#####################

# Leave any you're not using untouched, enter full path if the program is
# not found

# the festival main executable
FESTIVAL_BIN=festival
# the festival_client binary
FESTIVAL_CLIENT=festival_client

# The flite executable
FLITE_BIN=flite

# The lame executable
LAME_BIN=lame

# The speexenc executable
SPEEX_BIN=speexenc

# The oggenc executable
VORBIS_BIN=oggenc

#####################
# Festival settings #
#####################

# If you're not using festival, leave untouched

# whether to start the Festival server locally (Y/N)
FESTIVAL_START=Y
# the host of the Festival server
# this is set to localhost automatically when FESTIVAL_START is Y
FESTIVAL_HOST=localhost
# the port of the Festival server
FESTIVAL_PORT=1314
# where to log the Festival client output
FESTIVAL_LOG=/dev/null

##################
# Flite settings #
##################

# If you're not using flite, leave untouched

#####################
# Encoding settings #
#####################
# where to log the encoder output
ENC_LOG=/dev/null

# Suggested: --vbr-new -t --nores -S
#            VBR, independent frames, silent mode
LAME_OPTS="--vbr-new -t --nores -S"

# Suggested:
# xxx: suggest a default
SPEEX_OPTS=""

# Suggested: -q0 --downmix
#            Low quality, mono
VORBIS_OPTS="-q0 --downmix"

###################
# End of settings #
###################

# Check if executables exist and perform any necessary initialisation
function init_tts() {
    case $TTS_ENGINE in
        festival)
            # Check for festival_client
            if [ ! `which $FESTIVAL_CLIENT` ]; then
                echo "Error: $FESTIVAL_CLIENT not found"
                exit 4
            fi

            # Check for, and start festival server if specified
            if [ X$FESTIVAL_START = XY ]; then
                if [ ! `which $FESTIVAL_BIN` ]; then
                    echo "Error: $FESTIVAL_BIN not found"
                    exit 3
                fi
                FESTIVAL_HOST='localhost'
                $FESTIVAL_BIN --server 2>&1 > /dev/null &
                FESTIVAL_SERVER_PID=$!
                sleep 3
                if [ `ps | grep -c "^\ *$FESTIVAL_SERVER_PID"` -ne 1 ]; then
                    echo "Error: Festival not started"
                    exit 9
                fi
            fi
            # Test connection to festival server
            output=`echo -E "Rockbox" | $FESTIVAL_CLIENT --server \
                   $FESTIVAL_HOST --otype riff --ttw --output \
                   /dev/null 2>&1`
            if [ $? -ne 0 ]; then
                echo "Error: Couldn't connect to festival server at" \
                     "$FESTIVAL_HOST ($output)"
                exit 8
            fi
            ;;
        flite)
            # Check for flite
            if [ ! `which $FLITE_BIN` ]; then
                echo "Error: $FLITE_BIN not found"
                exit 5
            fi
            ;;
        *)
            echo "Error: no valid TTS engine selected: $TTS_ENGINE"
            exit 2
            ;;
    esac
}

# Perform any necessary shutdown for TTS engine
function stop_tts() {
    case $TTS_ENGINE in
        festival)
            if [ X$FESTIVAL_START = XY ]; then
                # xxx: This is probably possible to do using festival_client
                kill $FESTIVAL_SERVER_PID > /dev/null 2>&1
            fi
            ;;
    esac
}

# Check if executables exist and perform any necessary initialisation
function init_encoder() {
    case $ENCODER in
        lame)
            # Check for lame binary
            if [ ! `which $LAME_BIN` ]; then
                echo "Error: $LAME_BIN not found"
                exit 6
            fi
            ;;
        speex)
            # Check for speexenc binary
            if [ ! `which $SPEEX_BIN` ]; then
                echo "Error: $SPEEX_BIN not found"
                exit 7
            fi
            ;;
        vorbis)
            # Check for vorbis encoder binary
            if [ ! `which $VORBIS_BIN` ]; then
                echo "Error: $VORBIS_BIN not found"
                exit 10
            fi
            ;;
        *)
            echo "Error: no valid encoder selected: $ENCODER"
            exit 1
            ;;
    esac

}

# Encode file $1 with ENCODER and save the result in $2, delete $1 if specified
function encode() {
    INPUT=$1
    OUTPUT=$2

    if [ ! -f "$INPUT" ]; then
        echo "Warning: missing input file: \"$INPUT\""
    else
        echo "Action: Encode $OUTPUT with $ENCODER"
        case $ENCODER in
            lame)
                $LAME_BIN $LAME_OPTS "$WAV_FILE" "$OUTPUT" >>$ENC_LOG 2>&1
                ;;
            speex)
                $SPEEX_BIN $SPEEX_OPTS "$WAV_FILE" "$OUTPUT" >>$ENC_LOG 2>&1
                ;;
            vorbis)
                $VORBIS_BIN $VORBIS_OPTS "$WAV_FILE" -o "$OUTPUT" >>$ENC_LOG 2>&1
        esac
        if [ ! -f "$OUTPUT" ]; then
            echo "Warning: missing output file \"$OUTPUT\""
        fi
    fi
}

# Generate file $2 containing $1 spoken by TTS_ENGINE, trim silence 
function speak() {
    TO_SPEAK=$1
    WAV_FILE=$2
    if [ ! -f "$WAV_FILE" ] || [ X$OVERWRITE_WAV = XY ]; then
        case $TTS_ENGINE in
            festival)
                echo "Action: Generate $WAV_FILE with festival"
                echo -E "$TO_SPEAK" | $FESTIVAL_CLIENT --server $FESTIVAL_HOST \
                     --otype riff --ttw --output "$WAV_FILE" 2>"$WAV_FILE"
                ;;
            flite)
                echo "Action: Generate $WAV_FILE with flite"
                echo -E "$TO_SPEAK" | $FLITE_BIN -o "$WAV_FILE"
                ;;
        esac
    fi
    trim "$WAV_FILE"
}

# Trim wavefile $1
function trim() {
    # xxx: unimplemented, use wavtrim from the VoiceBuilding wikipage
    WAVEFILE=$1
}
