#!/bin/bash

#######################################################################
# Speak a text with spd-say (speech-dispatcher) and RHVoice TTS engine.
#######################################################################

readonly kitexe="unix";
readonly kitrun="crwrun";
readonly thekit="crwkit";
readonly scriptfile="${BASH_SOURCE[0]}";
readonly scriptname="$(basename $scriptfile)";
readonly versionstr="$scriptname version 1.0 built 20230621";
readonly copyrights="Copyright (c) 2001-2023 Alexey Kuryakin daqgroup@mail.ru";
readonly thekitinfo="This tool is part of $thekit to be run via {$thekit, $kitrun or $kitexe} wrapper.";
readonly rhvoice="sd_rhvoice";
readonly speaker="spd-say";

function fatal(){ echo -ne "\n$1\n\n"; exit 1; };
function do_version(){ echo "$versionstr"; exit 0; };
function do_copyright(){ echo "$copyrights"; exit 0; };

function do_noargs(){
 echo "$versionstr";
 echo "No arguments specified. Use '$scriptname -h' to get help.";
 exit 0;
};

function do_help(){
 echo "$versionstr";
 echo "$copyrights";
 echo "$thekitinfo";
 echo "Speak a text with speech synthesizer.";
 echo "Usage: $scriptname [-option] ['Text to speak.']";
 echo "Option:";
 echo " -v,--version                Print version.";
 echo " --copyright                 Print copyright.";
 echo " -h,--help                   Print this help screen.";
 echo " -q,--quiet                  Set quiet (silent) execution mode.";
 echo " -r,--rate r                 Set speech rate   r=(-100..+100,default:0).";
 echo " -p,--pitch p                Set speech pitch  p=(-100..+100,default:0).";
 echo " -i,--volume v               Set speech volume v=(-100..+100,default:0).";
 echo " -o,--output-module m        Set output module m=(rhvoice,espeak-ng,…).";
 echo " -O,--list-output-modules    Get list of output modules.";
 echo " -l,--language l             Set the language l=(ISO code)=(en,ru,…).";
 echo " -t,--voice-type t           Set preferred voice type t=(male1,male2,male3,";
 echo "                              female1,female2,female3,child_male,child_female).";
 echo " -L,--list-synthesis-voices  Get the list of synthesis voices.";
 echo " -y,--synthesis-voice v      Set synthesis voice v=(Elena,Anna,Irina,Aleksandr…)";
 echo " -m,--punctuation-mode m     Set punctuation mode m=(none,some,all).";
 echo " -s,--spelling               Spell the message.";
 echo " -e,--pipe-mode              Pipe from stdin to stdout + Speech Dispatcher.";
 echo " -P,--priority p             Set message priority p=(important,message,";
 echo "                              text,notification,progress;default:text).";
 echo " -w,--wait                   Wait until stop speaking.";
 echo " -S,--stop                   Stop speaking the message being spoken.";
 echo " -C,--cancel                 Cancel all messages.";
 echo "Voices for default output module (rhvoice):";
 echo " en: $($speaker -L -o rhvoice | grep ' en ' | awk '{ print $1}' | tr '\n' ',')";
 echo " ru: $($speaker -L -o rhvoice | grep ' ru ' | awk '{ print $1}' | tr '\n' ',')";
 echo "Examples:";
 echo " $kitexe $scriptname 'Это тест для речевого синтезатора.'";
 echo " $kitexe $scriptname -w 'Это тест для речевого синтезатора.'";
 echo " $kitexe $scriptname -w -y Irina 'Это тест для речевого синтезатора.'";
 echo " echo 'Привет, мир!' | $kitexe $scriptname -e -p 50 -r -50";
 exit 0;
};

##################
## Declare Options
##################
declare opt_wait="";
declare opt_rate="";
declare opt_pitch="";
declare opt_quiet="0";
declare opt_volume="";
declare opt_spelling="";
declare opt_priority="";
declare opt_pipe_mode="";
declare opt_voice_type="";
declare opt_punctuation_mode="";
declare opt_language="--language ru";
declare opt_output_module="--output-module rhvoice";
declare opt_synthesis_voice="--synthesis-voice Elena";

##################
## Helper routines
##################
function do_opt_quiet()             { if [[ -n "$1" ]]; then opt_quiet="$1"; fi; };
function do_opt_wait()              { if [[ -n "$1" ]]; then opt_wait="--wait"; fi; };
function do_opt_spelling()          { if [[ -n "$1" ]]; then opt_spelling="--spelling"; fi; };
function do_opt_pipe_mode()         { if [[ -n "$1" ]]; then opt_pipe_mode="--pipe-mode"; fi; };
function do_opt_rate()              { if [[ -n "$1" ]]; then opt_rate="--rate $1"; fi; };
function do_opt_pitch()             { if [[ -n "$1" ]]; then opt_pitch="--pitch $1"; fi; };
function do_opt_volume()            { if [[ -n "$1" ]]; then opt_volume="--volume $1"; fi; };
function do_opt_language()          { if [[ -n "$1" ]]; then opt_language="--language $1"; fi; };
function do_opt_priority()          { if [[ -n "$1" ]]; then opt_priority="--priority $1"; fi; };
function do_opt_voice_type()        { if [[ -n "$1" ]]; then opt_voice_type="--voice-type $1"; fi; };
function do_opt_output_module()     { if [[ -n "$1" ]]; then opt_output_module="--output-module $1"; fi; };
function do_opt_synthesis_voice()   { if [[ -n "$1" ]]; then opt_synthesis_voice="--synthesis-voice $1"; fi; };
function do_opt_punctuation_mode()  { if [[ -n "$1" ]]; then opt_punctuation_mode="--punctuation-mode $1"; fi; };
function options() { echo $opt_rate $opt_pitch $opt_volume $opt_priority $opt_language $opt_output_module $opt_synthesis_voice $opt_wait $opt_spelling $opt_pipe_mode; };
function logger()                   { if [[ "$opt_quiet" = "1" ]]; then return; fi; echo "$@"; };
function call()                     { logger "$@"; "$@"; };
function do_speak()                 { call $speaker $(options) "$1"; };
function do_cancel()                { call $speaker --cancel; };
function do_stop()                  { call $speaker --stop; };
function do_list_output_modules()   { call $speaker --list-output-modules; };
function do_list_synthesis_voices() { call $speaker $opt_output_module --list-synthesis-voices; };
function check_command()            { if [[ -z "$(which $1)" ]]; then fatal "Error: not found $1. $2"; fi; };

#######
## MAIN
#######

function main(){
 #############################################################
 ## Check speech-dispatcher and RHVoice is installed properly.
 #############################################################
 check_command $speaker "Please install speech-dispatcher package.";
 check_command $rhvoice "Please install RHVoice (daqgroup-rhvoice package).";
 ################################
 ## Parse command line arguments.
 ################################
 if [[ $# -lt 1 ]]; then do_noargs; fi;                 # show message if no arguments found
 while [[ -n "$1" ]]; do
  case $1 in
   -v|-version|--version)                               do_version;                          ;;
   -copyright|--copyright)                              do_copyright;                        ;;
   -h|-help|--help)                                     do_help;                             ;;
   -q|-quiet|--quiet)                                   do_opt_quiet 1;                      ;;
   -r|-rate|--rate)                                     shift; do_opt_rate "$1";             ;;
   -p|-pitch|--pitch)                                   shift; do_opt_pitch "$1";            ;;
   -i|-volume|--volume)                                 shift; do_opt_volume "$1";           ;;
   -P|-priority|--priority)                             shift; do_opt_priority "$1";         ;;
   -l|-language|--language)                             shift; do_opt_language "$1";         ;;
   -t|-voice-type|--voice-type)                         shift; do_voice_type "$1";           ;;
   -o|-output-module|--output-module)                   shift; do_opt_output_module "$1";    ;;
   -y|-synthesis-voice|--synthesis-voice)               shift; do_opt_synthesis_voice "$1";  ;;
   -m|-punctuation-mode|--punctuation-mode)             shift; do_opt_punctuation_mode "$1"; ;;
   -O|-list-output-modules|--list-output-modules)       do_list_output_modules;              ;;
   -L|-list-synthesis-voices|--list-synthesis-voices)   do_list_synthesis_voices;            ;;
   -e|-pipe-mode|--pipe-mode)                           do_opt_pipe_mode 1;                  ;;
   -s|-spelling|--spelling)                             do_opt_spelling 1;                   ;;
   -w|-wait|--wait)                                     do_opt_wait 1;                       ;;
   -C|-cancel|--cancel)                                 do_cancel;                           ;;
   -S|-stop|--stop)                                     do_stop;                             ;;
   --)                                                  shift; do_speak "$*"; return;        ;;
   -*)                                                  fatal "Error: unknown option $1.";   ;;
   *)                                                   do_speak "$1";                       ;;
  esac;
  shift;
 done;
 if [[ -n "$opt_pipe_mode" ]]; then do_speak; fi;
};

main "$@";

##############
## END OF FILE
##############
