2 # Desc: Convert IPA string into audio file 
   4 #==BEGIN Define script parameters== 
   5 #===BEGIN Initialize variables=== 
   8 scriptName
="bkipas";             # Define basename of script file. 
   9 scriptVersion
="0.1.0";         # Define version of script. 
  10 scriptTimeStart
="$(date +%Y%m%dT%H%M%S.%N)"; # YYYYmmddTHHMMSS.NNNNNNNNN 
  11 scriptURL
="https://zdv2.bktei.com/gitweb/baltakatei-exdev.git"; # Define website hosting this script. 
  12 scriptHostname
=$
(hostname
);     # Save hostname of system running this script. 
  13 PATH
="$HOME/.local/bin:$PATH";  # Add "$(systemd-path user-binaries)" path in case user apps saved there 
  16 declare -Ag appRollCall    
# Associative array for storing app status 
  17 declare -Ag fileRollCall   
# Associative array for storing file status 
  18 declare -Ag dirRollCall    
# Associative array for storing dir status 
  21 optionVerbose
=""; optionOutputDir
=""; optionInputString
=""; argStrIn
=""; argDirOut
=""; pathOut
=""; 
  23 #===END Initialize variables=== 
  24 #===BEGIN Declare local script functions=== 
  27 # Initialize variables and functions 
  28 yell
() { echo "$0: $*" >&2; }      #o Yell, Die, Try Three-Fingered Claw technique 
  29 die
() { yell 
"$*"; exit 111; }     #o Ref/Attrib: https://stackoverflow.com/a/25515370 
  30 try
() { "$@" || die 
"cannot $*"; } #o 
  32     # Description: Prints verbose message ("vbm") to stderr if optionVerbose is set to "true". 
  33     # Usage: vbm "DEBUG :verbose message here" 
  38     # Depends: bash 5.0.3, echo 8.30, date 8.30 
  40     if [ "$optionVerbose" = "true" ]; then 
  41         functionTime
=$
(date --iso-8601=ns
); # Save current time in nano seconds. 
  42         echo "[$functionTime]:$0:""$*" 1>&2; # Display argument text. 
  46     return 0; # Function finished. 
  47 } # Displays message if optionVerbose true 
  49     while [ ! $# -eq 0 ]; do   # While number of arguments ($#) is not (!) equal to (-eq) zero (0). 
  51             -v | 
--verbose) optionVerbose
="true"; vbm 
"DEBUG :Verbose mode enabled.";; # Enable verbose mode. 
  52             -h | 
--help) showUsage
; exit 1;; # Display usage. 
  53             --version) showVersion
; exit 1;; # Show version. 
  54             -i | 
--input-string) optionInputString
="true"; if [[ ! -z "$2" ]]; then argStrIn
="$2"; vbm 
"DEBUG :argStrIn:$argStrIn"; shift; fi ;; # Identify input string. 
  55             -o | 
--output-dir) optionOutputDir
="true"; if [[ -d "$2" ]]; then argDirOut
="$2"; vbm 
"DEBUG :argDirOut:$argDirOut"; shift; fi ;; # Define output directory. 
  56             *) yell 
"ERROR: Unrecognized argument: $1"; yell 
"STATUS:All arguments:$*"; exit 1;; # Handle unrecognized options. 
  60 } # Argument Processing 
  62     # Desc: If arg is a command, save result in assoc array 'appRollCall' 
  63     # Usage: checkapp arg1 arg2 arg3 ... 
  65     # Input: global assoc. array 'appRollCall' 
  66     # Output: adds/updates key(value) to global assoc array 'appRollCall' 
  72         if command -v "$arg" 1>/dev
/null 
2>&1; then # Check if arg is a valid command 
  73             appRollCall
[$arg]="true"; 
  74             if ! [ "$returnState" = "false" ]; then returnState
="true"; fi; 
  76             appRollCall
[$arg]="false"; returnState
="false"; 
  80     #===Determine function return code=== 
  81     if [ "$returnState" = "true" ]; then 
  86 } # Check that app exists 
  88     # Desc: If arg is a file path, save result in assoc array 'fileRollCall' 
  89     # Usage: checkfile arg1 arg2 arg3 ... 
  91     # Input: global assoc. array 'fileRollCall' 
  92     # Output: adds/updates key(value) to global assoc array 'fileRollCall'; 
  93     # Output: returns 0 if app found, 1 otherwise 
  99         if [ -f "$arg" ]; then 
 100             fileRollCall
["$arg"]="true"; 
 101             if ! [ "$returnState" = "false" ]; then returnState
="true"; fi; 
 103             fileRollCall
["$arg"]="false"; returnState
="false"; 
 107     #===Determine function return code=== 
 108     if [ "$returnState" = "true" ]; then 
 113 } # Check that file exists 
 115     # Desc: If arg is a dir path, save result in assoc array 'dirRollCall' 
 116     # Usage: checkdir arg1 arg2 arg3 ... 
 118     # Input: global assoc. array 'dirRollCall' 
 119     # Output: adds/updates key(value) to global assoc array 'dirRollCall'; 
 120     # Output: returns 0 if app found, 1 otherwise 
 121     # Depends: Bash 5.0.3 
 126         if [ -d "$arg" ]; then 
 127             dirRollCall
["$arg"]="true"; 
 128             if ! [ "$returnState" = "false" ]; then returnState
="true"; fi 
 130             dirRollCall
["$arg"]="false"; returnState
="false"; 
 134     #===Determine function return code=== 
 135     if [ "$returnState" = "true" ]; then 
 140 } # Check that dir exists 
 142     # Desc: Displays missing apps, files, and dirs 
 143     # Usage: displayMissing 
 145     # Input: associative arrays: appRollCall, fileRollCall, dirRollCall 
 146     # Output: stderr: messages indicating missing apps, file, or dirs 
 147     # Depends: bash 5, checkAppFileDir() 
 148     local missingApps value appMissing missingFiles fileMissing
 
 149     local missingDirs dirMissing
 
 151     #==BEGIN Display errors== 
 152     #===BEGIN Display Missing Apps=== 
 153     missingApps
="Missing apps  :"; 
 154     #for key in "${!appRollCall[@]}"; do echo "DEBUG :$key => ${appRollCall[$key]}"; done 
 155     for key 
in "${!appRollCall[@]}"; do 
 156         value
="${appRollCall[$key]}"; 
 157         if [ "$value" = "false" ]; then 
 158             #echo "DEBUG :Missing apps: $key => $value"; 
 159             missingApps
="$missingApps""$key "; 
 163     if [ "$appMissing" = "true" ]; then  # Only indicate if an app is missing. 
 164         echo "$missingApps" 1>&2; 
 167     #===END Display Missing Apps=== 
 169     #===BEGIN Display Missing Files=== 
 170     missingFiles
="Missing files:"; 
 171     #for key in "${!fileRollCall[@]}"; do echo "DEBUG :$key => ${fileRollCall[$key]}"; done 
 172     for key 
in "${!fileRollCall[@]}"; do 
 173         value
="${fileRollCall[$key]}"; 
 174         if [ "$value" = "false" ]; then 
 175             #echo "DEBUG :Missing files: $key => $value"; 
 176             missingFiles
="$missingFiles""$key "; 
 180     if [ "$fileMissing" = "true" ]; then  # Only indicate if an app is missing. 
 181         echo "$missingFiles" 1>&2; 
 184     #===END Display Missing Files=== 
 186     #===BEGIN Display Missing Directories=== 
 187     missingDirs
="Missing dirs:"; 
 188     #for key in "${!dirRollCall[@]}"; do echo "DEBUG :$key => ${dirRollCall[$key]}"; done 
 189     for key 
in "${!dirRollCall[@]}"; do 
 190         value
="${dirRollCall[$key]}"; 
 191         if [ "$value" = "false" ]; then 
 192             #echo "DEBUG :Missing dirs: $key => $value"; 
 193             missingDirs
="$missingDirs""$key "; 
 197     if [ "$dirMissing" = "true" ]; then  # Only indicate if an dir is missing. 
 198         echo "$missingDirs" 1>&2; 
 201     #===END Display Missing Directories=== 
 203     #==END Display errors== 
 204 } # Display missing apps, files, dirs 
 206     yell 
"$scriptVersion" 
 208 Copyright (C) 2020 Steven Baltakatei Sandoval 
 209 License GPLv3: GNU GPL version 3 
 210 This is free software; you are free to change and redistribute it. 
 211 There is NO WARRANTY, to the extent permitted by law. 
 213   lexconvert (https://github.com/ssb22/lexconvert commit 64a4837) 
 214   Copyright (C) 2020 Silas S. Brown 
 215   License GPLv3: GNU GPL version 3 
 217 } # Display script version. 
 225                 Display help information. 
 227                 Display script version. 
 229                 Display debugging info. 
 230         -i, --input-string [ str input ] 
 231                 Specify input IPA string. 
 232         -o, --output-dir [ path dir ] 
 233                 Specify output directory path. 
 236         bkipas -i "təˈmeɪtoʊ"           # same as: echo "[[t@'meItoU]]" | espeak 
 237         bkipas -i "təˈmeɪtoʊ" -o /tmp/ 
 239 } # Display information on how to use this script. 
 242     # Desc: Main function 
 245     # Outputs: file (pathout_tar) 
 248     # Debug:Get function name 
 251     vbm 
"STATUS:$fn:Started function main()."; 
 253     processArguments 
"$@"; 
 255     # Specify expected lexconvert.py path 
 256     pathLexConvert
="./bkipas.d/lexconvert.py" && vbm 
"DEBUG :$fn:pathLexConvert:$pathLexConvert"; 
 257     ## Note: lexconvert.py converts IPA into eSpeak phoneme mneumonics 
 258     ##       See https://github.com/ssb22/lexconvert 
 259     ##       See https://github.com/espeak-ng/espeak-ng/issues/539#issuecomment-536192362 
 261     # Check vital apps, files, dirs 
 262     if ! checkapp 
sed python3 espeak oggenc 
&& ! checkfile 
"$pathLexConvert"; then 
 263         yell 
"ERROR:$fn:Critical components missing."; 
 264         displayMissing
; yell 
"Exiting."; exit 1; fi; 
 266     # Process input string 
 268     strIn
="$(echo "$argStrIn" | sed 's/\///g')"; 
 269     ## Check for empty string 
 270     if [[ -z "$strIn" ]]; then yell 
"ERROR:No IPA string provided."; exit 1; fi; 
 272     # Determine output file name 
 273     if [[ "$optionOutputDir" = "true" ]]; then 
 274         #pathOut="$argDirOut/$scriptTimeStart".ogg && vbm "DEBUG :$fn:pathOut:$pathOut"; 
 275         pathOut
="$argDirOut/$strIn".ogg 
&& vbm 
"DEBUG :$fn:pathOut:$pathOut"; 
 277         #pathOut="$(pwd)/$scriptTimeStart".ogg && vbm "DEBUG :$fn:pathOut:$pathOut"; 
 278         pathOut
="$(pwd)/$strIn".ogg 
&& vbm 
"DEBUG :$fn:pathOut:$pathOut"; 
 281     # Generate espeak phoneme mneumonic 
 282     espeakInput
="$(python3 "$pathLexConvert" --phones2phones unicode-ipa espeak "$strIn")" && vbm 
"DEBUG :$fn:espeakInput:$espeakInput"; 
 284     # Output pronunciation 
 285     if [[ "$optionOutputDir" = "true" ]]; then 
 286         ## Write to file if -o specified 
 287         echo "$espeakInput" | espeak 
--stdout | oggenc 
-o "$pathOut" - ; 
 289         ## Speak pronunciation via espeak 
 290         echo "$espeakInput" | espeak 
; 
 295 #===END Declare local script functions=== 
 296 #==END Define script parameters== 
 298 #==BEGIN Perform work and exit== 
 299 main 
"$@" # Run main function. 
 301 #==END Perform work and exit== 
 303 # Author: Steven Baltakatei Sandoval;