#!/bin/tcsh 

# Improve speech signals before BAS WebSevice Processing.

# This is the backend script for the BAS AudioEnhance service
# (runAudioEnhance). It reads a SIGNAL and performs several transformations
# mostly based on SoX that improve the speech signal for processing in 
# BAS WebServices. Depending on input and given options (in brackets) the service
# - extracts sound track from video input (always, if applicable),
# - converts non-RIFF sound formats into RIFF (always, using sox's extension recognition),
# - set bit width per sample to 16bits (always, if applicable),
# - normalize channels to -3dB (NORM=true),
# - merge multi-channel files into one channel (MONO=true),
# - re-sample to given sampling rate (RATE); RATE=0 : no re-sampling,
# - filters signal for constant background noise (NOISE); NOISE=0 : no filtering
#
# Motivation for this service:
# Users are often not aware that their recordings are not optimal for speech 
# processing. For instance, sampling rates and bits withs are too high and signal
# is stereo (although only one channel was recorded), format is video or non-RIFF, etc.
# This service can be used to 'enhance' speech signals before BAS WebService
# processing; it can be used as a stand-alone service, or at the very start of
# a processing pipeline (see service Pipeline).

# Programs required by this script: awk, wav2trn, sox, avconv, ffmpeg.

# The structure of this script is as follows:
# If video input, use ffmpeg to extract sound tracks.
# If MP3 input, convert to PCM (requires avconv, since sox does not support MP3 input)
# Then build a sox option string soxOpt and sox pipeline string soxPipe according to the following 
# command line options:
  - signal is not 16bit PCM : soxOpt '-e signed -b 16' 
# - RESAMPLE=<RATE> : soxOpt '-r <RATE>', RESAMPLE=0 : no resampling
# - NORM=true : soxPipe = 'gain -3dB', NORM=false : no normalizing
# - MONO=true : soxOpt = '-c 1', MONO=false : multi-channel output
# - NOISE=<AMOUNT> (AMOUNT=0...1) : filtering, AMOUNT=0 : no filtering (default)
#   Before sox pipe is operated, use wav2trn to determine BEG/END of speech in recording;
#   calculate noise profile 'noiseprof' from concatenated leading/trailing silence; then
#   add to soxPipe: 'noisered noiseprof <AMOUNT>'
# Finally, perform : sox -D input.ext $soxOpt output.wav $soxPipe
 

# Version 
set VERSION = 0.1

if ( $1 == '--version' ) then 
  echo $VERSION
  exit 0
endif

##########################################################################
set SCRIPT = `readlink -f "$0"`
set SOURCE = `dirname "$SCRIPT"`  # location where the script is stored 
                           # (even if we start via a symbolic link)
set TEMP = /tmp
setenv LANG en_US.UTF-8  # defines the behavior of text processing, sorting etc.
##########################################################################

# Pre-set commandline and other options

# converter helpers

# debugging
set v = 0 
set CLEAN = TRUE       # if set to false, temporary files are not purged

# command line
set SIGNAL = ""            # input to be converted
set OUT = ""               # converted output
set NORM = true
set MONO = true
set RESAMPLE = 16000
set NOISE = 0


# other
#
# ...
#
# -------------------------------------------------------------------------

#
# Exit codes
# 0 : everything seems ok
# 1 : serious error
# 4 : no arguments, printing help message to stdout
# 5 : missing necessary helper program

# Actually do the argument parsing here

#echo parsing commandline
while ( "$1" != "" )
	switch ("$1")
	case *=*:
		#set key = `echo $1 | cut -d= -f1`
		set key = `echo $1 | awk -F= '{ print $1 }'`
		#check if option is known (set)
		eval set checkoption = '$?'$key
                if ( $checkoption == 0 ) then 
		  echo "ERROR: unknown option $key - exiting" >> /dev/stderr
		  exit 1
		endif  
		#set val = `echo $1 | cut -d= -f2`
		set val = `echo $1 | awk -F= '{ print $2 }'`
		eval "set $key "= \'"$val"\'
		unset key val
		shift
		breaksw
        default:
		break
        endsw
end

# end option parser

# preliminaries
set beginsec = `date '+%s'`
set PID = "$$_${beginsec}_"
if ( $v > 0 ) echo "DEBUG: Starting $0:t on `date` (${beginsec}), TEMP/PID : $TEMP/$PID"
set v_minus = $v
if ( $v > 0 ) @ v_minus --  # debug level for sub-scripts

# boolean variable check; define all boolean input parameters here

set bool = ( NORM MONO CLEAN )
foreach booleanvariable ( $bool )
  eval set val = '$'$booleanvariable
  switch ( $val ) 
  case true:
    eval set $booleanvariable = TRUE
    breaksw
  case True:
    eval set $booleanvariable = TRUE
    breaksw
  case TRUE:
    eval set $booleanvariable = TRUE
    breaksw
  case 1:
    eval set $booleanvariable = TRUE
    breaksw
  case yes:
    eval set $booleanvariable = TRUE
    breaksw
  case Yes:
    eval set $booleanvariable = TRUE
    breaksw
  case YES:
    eval set $booleanvariable = TRUE
    breaksw
  case false:
    eval set $booleanvariable = FALSE
    breaksw
  case False:
    eval set $booleanvariable = FALSE
    breaksw
  case FALSE:
    eval set $booleanvariable = FALSE
    breaksw
  case 0:
    eval set $booleanvariable = FALSE
    breaksw
  case no:
    eval set $booleanvariable = FALSE
    breaksw
  case No:
    eval set $booleanvariable = FALSE
    breaksw
  case NO:
    eval set $booleanvariable = FALSE
    breaksw
  case force:
    eval set $booleanvariable = force
    breaksw
  default:
    echo "ERROR: ${0:t} : Boolean $booleanvariable=$val is not a boolean value. Use either '0,1,true,false,yes,no,(force)' - exiting" >> /dev/stderr
    exit 1
  endsw    
end

# check for helpers
if( ! -x  || ! -x  || ! -x  ) then 
  echo "ERROR: ${0:t} is missing one or more helpers. Be sure that you install helpers ... - exiting" >> /dev/stderr
  exit 5
endif
if ( $1 == '--help' ) then 
  awk '/  usage: /{pf=1}/  end usage/{pf=0}{if(pf==1)print}' $SOURCE/${0:t}   
  exit 4
endif

if ( "$SIGNAL" == "" || "$OUT" == "" ) then 
  echo "${0:t} : version $VERSION"
  cat <<ENDE

  usage: audioEnhance SIGNAL=inputFile OUT=outputFile [NORM=true][MONO=true][RESAMPLE=16000][NOISE=0]
  usage: audioEnhance --version
  usage: audioEnhance --help
  
  Improve speech signals before BAS WebSevice Processing.

  This is the backend script for the BAS AudioEnhance service
  (runAudioEnhance). It reads a SIGNAL and performs several transformations
  mostly based on SoX that improve the speech signal for processing in 
  BAS WebServices. Depending on input and given options (in brackets) the service
  - extracts sound track from video input (always, if applicable),
  - converts non-RIFF sound formats into RIFF (always, using sox's extension recognition),
  - set bit width per sample to 16bits (always, if applicable),
  - normalize channels to -3dB (NORM=true),
  - merge multi-channel files into one channel (MONO=true),
  - re-sample to given sampling rate (RATE); RATE=0 : no re-sampling,
  - filters signal for constant background noise (NOISE); NOISE=0 : no filtering
 
  Motivation for this service:
  Users are often not aware that their recordings are not optimal for speech 
  processing. For instance, sampling rates and bits withs are too high and signal
  is stereo (although only one channel was recorded), format is video or non-RIFF, etc.
  This service can be used to 'enhance' speech signals before BAS WebService
  processing; it can be used as a stand-alone service, or at the very start of
  a processing pipeline (see service Pipeline).

  ERRORs are reported to stderr and the exit code is >0.
  WARNINGs are reported to stderr and the exit code is 0
  end usage
  
ENDE

  exit 4
endif

# Pre-checks
if ( ! -e "$SIGNAL" ) then
  echo "ERROR: ${0:t} : cannot read input signal file '$SIGNAL' - exiting" >> /dev/stderr
  exit 1
endif  
touch "$OUT"
if ( $status != 0 ) then
  echo "ERROR: ${0:t} : cannot write to output file '$OUT' - exiting" >> /dev/stderr
  exit 1
endif  

# start code


# clean up 
clean:
set endsec = `date '+%s'`
if ( "$CLEAN" == "TRUE" ) rm -rf $TEMP/${PID}* >& /dev/null
if ( $v > 0 ) echo "DEBUG: $0:t : finished with exit = ${exitCode} at `date` (${endsec})"

exit $exitCode

