#!/bin/bash
#set -n		# read but do not execute commands (check on syntax errors)
#
# File: /usr/local/bin/mediafilter-equalizer
#
# Use an equalizer.
#
#    Copyright (C) 2020  Juergen Kaesmann (JK)
#
##############################################################################
# GPL NOTICE
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
##############################################################################
# FIND SAMPLES
#
##############################################################################
# FILTER SAMPLES
#
# To avoid spaces (shell) surround filter and arguments with ""
# There are two filter types:
# a) Simple filter
#	-filter:a|-filter:v "<filter>=<arguments_list>"
#	or
#	-af|-vf "<filter>=<arguments_list>"
# b) Complex filter
#	-filter_complex "[<arguments_list>]<filter>=<arguments_list>"
#
#-----------------------------------------------------------------------------
# SETPTS filter explanation:
# setpts	Set timestamps.
#
# generate video timestamps from zero:
# -filter:v "trim" -filter:v "setpts=PTS-STARTPTS"
#
# generate audio timestamps from zero:
# -filter:a "atrim" -filter:a "asetpts=PTS-STARTPTS"
#
#-----------------------------------------------------------------------------
# VOLUME filter explanation:
# volume	Adjust the volume. Do not set the volume.
#
# increase volume by 150%:
# -filter:a "volume=1.5"
#
# increase volume by 10dB:
# -filter:a "volume=10dB"
#
# reduce volume by 5dB, use a negative value:
# -filter:a "volume=-5dB"
#
#-----------------------------------------------------------------------------
# PEAK and RMS Normalization:
# volume	Adjust the volume to a peak or RMS level.
#
# To normalize the volume to a given peak or RMS level, the file first has to
# be analyzed with filter a) or b):
# a) -filter:a volumedetect
# b) -filter_complex [0:a]ebur128=peak=sample
#
# Read the output values from the command line log (relative to max value)
# and calculate the required offset to adjust max_volume/PEAK to 0.
# Then change the volume with the filter:
# -filter:a "volume=<offset>dB"
#
# or normalize the file with:
# -af "dynaudnorm=<...>"
#
#-----------------------------------------------------------------------------
# COMPANDER explanation:
# compand	Compress or expand the audio's dynamic range.
#
# Show compand params - separate every PART with ':'
# PARTS		DEFAULTS		MODE "s"
# attack lst	0.3 0.3			0 0
# decay lst	0.8 0.8			1 1
# points lst	-70/-70 -60/-60 1/0	-90/-900 -70/-70 -30/-9 0/-3
# soft-knee	0.01			6
# gain		0			0
# volume	0			0
# delay		0			0
#
# Using simple audiofilter:
# -af "aformat=channel_layouts=stereo, compand=0 0:1 1:-90/-900 -70/-70 -30/-9 0/-3:6:0:0:0"
#
# Using complex audiofilter:
# -filter_complex "compand=0 0:1 1:-90/-900 -70/-70 -30/-9 0/-3:6:0:0:0"
#
# same as above but avoid SPACES:
# -filter_complex compand=0|0:1|1:-90/-900|-70/-70|-30/-9|0/-3:6:0:0:0
#
#-----------------------------------------------------------------------------
# EQUALIZER explanation:
# equalizer	Apply a two-pole peaking equalisation (EQ) filter.
#
# With this filter, the signal-level at and around a selected frequency can
# be increased or decreased, whilst (unlike bandpass and bandreject filters)
# that at all other frequencies signal is unchanged.
#
# In order to produce complex equalisation curves, this filter can be
# given several times, each with a different central frequency and separated
# with a comma.
#
# The filter accepts the following options:
# frequency, f	Set the filter's central frequency in Hz.
# width_type	Set method to specify band-width of filter.
# 	h	Hz
# 	q	Q-Factor
# 	o	octave
# 	s	slope
# width, w	Specify the band-width of a filter in width_type units.
#		Have in mind that the frequency is limited to 999 Hz.
# gain, g	Set the required gain or attenuation in dB.
# 		Beware of clipping when using a positive gain.
#
# Examples:
# Attenuate 10 dB at 1000 Hz, with a bandwidth of 200 Hz:
# -af equalizer=f=1000:width_type=h:width=200:g=-10
#
# Apply 2 dB gain at 1000 Hz with Q 1 and attenuate 5 dB at 100 Hz with Q 2:
# -af equalizer=f=1000:width_type=q:width=1:g=2,equalizer=f=100:wid
#
# Apply 6 dB gain at 200 Hz and width 300 Hz:
# -af equalizer=f=200:width_type=h:w=300:g=6
#
# Sound Distribution:
# BAND		TYPE
# 16-100	Sub Bass
# 50-250	Bass
# --------------------------
# 250-2k	Low Midd
# 2k-4k		High Midd
# --------------------------
# 4k-6k		Präsenz
# 6k-16k	Brillanz
#
# Template EQ with 18 bands non-overlaping
# BAND		f	w
# 50-100	75	50
# 100-250	175	150
# 250-1k	625	750
# 1k-2k		1500	999
# 2k-3k		2500	999
# 3k-4k		3500	999
# 4k-5k		4500	999
# 5k-6k		5500	999
# 6k-7k		6500	999
# 7k-8k		7500	999
# 8k-9k		8500	999
# 9k-10k	9500	999
# 10k-11k	10500	999
# 11k-12k	11500	999
# 12k-13k	12500	999
# 13k-14k	13500	999
# 14k-15k	14500	999
# 15k-16k	15500	999
# -af equalizer=f=75:width_type=h:w=50:g=0,equalizer=f=175:width_type=h:w=150:g=0,equalizer=f=625:width_type=h:w=750:g=0,equalizer=f=1500:width_type=h:w=999:g=0,equalizer=f=2500:width_type=h:w=999:g=0,equalizer=f=3500:width_type=h:w=999:g=0,equalizer=f=4500:width_type=h:w=999:g=0,equalizer=f=5500:width_type=h:w=999:g=0,equalizer=f=6500:width_type=h:w=999:g=0,equalizer=f=7500:width_type=h:w=999:g=0,equalizer=f=8500:width_type=h:w=999:g=0,equalizer=f=9500:width_type=h:w=999:g=0,equalizer=f=10500:width_type=h:w=999:g=0,equalizer=f=11500:width_type=h:w=999:g=0,equalizer=f=12500:width_type=h:w=999:g=0,equalizer=f=13500:width_type=h:w=999:g=0,equalizer=f=14500:width_type=h:w=999:g=0,equalizer=f=15500:width_type=h:w=999:g=0
#
#-----------------------------------------------------------------------------
# ANEQUALIZER explanation:
# anequalizer	High-order parametric multiband equalizer for each channel.
#
# This option string is in format: "c<chn> f=<cf> w=<bw> g=<bg> t=<ft> | ..."
# Each equalizer band is separated by '|'.
#
# chn	Channel number to which equalization will be applied (0|1 for stereo).
#	If input doesn't have that channel the entry is ignored.
# cf	Central frequency for band.  If input doesn't have that
#	frequency the entry is ignored.
# bw	Band width in hertz.
# bg	Band gain in dB.
# ft	Filter type for band, optional, can be:
#	0	Butterworth, this is default.
#	1	Chebyshev type 1.
#	2	Chebyshev type 2.
#
# Examples:
# Lower gain by 10 of central frequency 200Hz and width 100 Hz for
# first 2 channels using Chebyshev type 1 filter:
# -af "anequalizer=c0 f=200 w=100 g=-10 t=1|c1 f=200 w=100 g=-10 t=1"
#
# Rise gain by 6 dB of central frequency 200 Hz and width 300 Hz for
# first 2 channels using Butterworth type 0 filter:
# -af "anequalizer=c0 f=200 w=300 g=6 t=0|c1 f=200 w=300 g=6 t=0"
#
#-----------------------------------------------------------------------------
# AFADE filter explanation:
# afade		Apply fade-in/out effect to input audio.
#
# type, t
#   Specify the effect type, can be either "in" for fade-in, or "out"
#   for a fade-out effect. Default is "in".
#
# start_time, st
#   Specify the start time of the fade effect. Default is 0.  The value
#   must be specified as a time duration; see the Time duration section
#   in the ffmpeg-utils(1) manual for the accepted syntax.
#
# duration, d
#   Specify the duration of the fade effect. See the Time duration
#   section in the ffmpeg-utils(1) manual for the accepted syntax.  At
#   the end of the fade-in effect the output audio will have the same
#   volume as the input audio, at the end of the fade-out transition
#   the output audio will be silence.
#
# curve
#   Set curve for fade transition.
#   It accepts the following values:
#     tri	select triangular, linear slope (default)
#     qsin	select quarter of sine wave
#     hsin	select half of sine wave
#     esin	select exponential sine wave
#     log	select logarithmic
#     ipar	select inverted parabola
#     qua	select quadratic
#     cub	select cubic
#     squ	select square root
#     cbr	select cubic root
#     par	select parabola
#     exp	select exponential
#     iqsin	select inverted quarter of sine wave
#     ihsin	select inverted half of sine wave
#     dese	select double-exponential seat
#     desi	select double-exponential sigmoid
#
# Examples:
# Fade in first 1 second of audio:
# -af "afade=t=in:st=0:d=1"
# Fade out last 3 seconds of a 180 seconds audio:
# -af "afade=t=out:st=177:d=3"
#
#-----------------------------------------------------------------------------
# ATEMPO filter explanation:
# atempo - Adjust audio tempo.
#
# The filter accepts exactly one parameter, the audio tempo. If not
# specified then the filter will assume nominal 1.0 tempo. Tempo must be
# in the [0.5, 2.0] range.
#
# Examples:
# Slow down audio to 80% tempo:
# -af "atempo=0.8"
# To speed up audio to 125% tempo:
# -af atempo=1.25
#
##############################################################################
# AWK SAMPLES
#
##############################################################################
# SED SAMPLES
#
##############################################################################
# RSYNC OPTIONS
#
##############################################################################
# DIALOG SAMPLES
#
##############################################################################
# REPLACE STRINGS
#
##############################################################################
# EXIT CODES

##############################################################################
# SOURCE FILES
#
. /usr/local/etc/main.conf				# config main
#. $LLIBDIR/libfuncerr-sh				# functions error
. $LLIBDIR/libfuncstd-sh				# functions standard
#. $LLIBDIR/libfuncmath-sh				# functions math
#. $LLIBDIR/libfuncip-sh				# functions IP
#. /usr/local/etc/multimedia.conf			# config sample

if [ ! -e ~/.mediafilter-equalizerrc ]; then			# install config user
	cp /usr/local/share/ksm-multimedia/mediafilter-equalizerrc ~/.mediafilter-equalizerrc
fi
. ~/.mediafilter-equalizerrc					# config user

##############################################################################
# DECLARATION OF STANDARD CONSTANTS AND VARIABLES
#
readonly package=Multimedia				# package name
readonly package_file=ksm-multimedia			# package file name
readonly vinfopath="/usr/local/share/$package_file"	# path to package dir
readonly version=$(/bin/cat $vinfopath/VERSION)		# package version
readonly release=$(/bin/cat $vinfopath/RELEASE)		# package release
readonly scriptname=$(basename $0)			# name of script
readonly tempfile=$TEMPDIR/$scriptname.$UID.tmp		# temporary file name
#readonly tempfile=$(mktemp -u $TEMPDIR/$scriptname.$UID.XXXXXX) # temporary file name
#readonly lockfile=$TEMPDIR/lock/$scriptname.$UID.lock	# lock file name
readonly debuglog="/usr/bin/logger -p user.debug -t $scriptname -- DEBUG:"	# log dbg msg
readonly errlog="/usr/bin/logger -p user.err -t $scriptname -- ERROR:"		# log err msg
readonly infolog="/usr/bin/logger -p user.info -t $scriptname -- INFO:"		# log inf msg
cmd=''							# sub command
debug=no						# debug=yes/no
verbose=''						# verbose=yes/''/no
err=${_ERR_OK_}						# error code

##############################################################################
# USER FILL IN AT FIRST RUN

##############################################################################
# SYSTEM

##############################################################################
# USER-CONSTANTS

##############################################################################
# USER-VARIABLES
#
# STRINGS
#args=''				# all args from cmdline
arg1=''					# 1. arg from cmdline
arg2=''					# 2. arg from cmdline
#opt_o=''				# option -o (yes)
					# option --output (yes)
#opt_i=''				# option -i (arg)
					# option --infile (arg)
opt_o=''				# option -o (arg)
					# option --outfile (arg)
#opt_p=''				# option -p (arg)
					# option --pages (arg)
opt_ab=''				# option --ab (arg)
opt_c=''				# option -c (arg)
outfile=''

# NUMBERS
#p_first=0				# first page
#p_last=0				# last page

# ARRAYS
# Indexed arrays are always zero based string arrays.
# If index starts with 1 and all members are assigned then
# count of members of array = last index of array
#declare -a arr
#maxarr="${#arr[@]}"			# get number of elements in arr
#unset arr[@]				# remove the entire array

declare -a g				# array of gain values (18)
#declare -a EQInfo			# Implizit definiert in rcfile
#declare -a EQProfile			# Implizit definiert in rcfile
maxEQ="${#EQInfo[@]}"			# get number of elements in EQInfo

##############################################################################
# SIGNAL HANDLING

##############################################################################
# FUNCTIONS
##############################################################################
#
##############################################################################
# HELP
#
#=============================================================================
function helptext ()
{
# Output helptext
# Uses cat, echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG helptext: $# $@" >&2
	$debuglog helptext: $# $@
fi

cat <<EOT
NAME
$scriptname - Use an equalizer.

SYNOPSIS
$scriptname [options] [fil num pstr]

DESCRIPTION
Use an equalizer with a multimedia file. This multimedia file must be
an MPEG4 file (.mp4). The video stream is always copied and the audio
stream is transcoded to aac.

All profiles are stored in the local user config file

.mediafilter-equalizerrc. 

Data for each profile is stored in the array EQProfile[]. Because we
use an 18 band equalizer we have to store 18 comma separated gain
values in each profile. Lowest band at left side and highest band at
right side.

Each profile has his own profile info in the array EQInfo[]. This
should be a description for you to identify this profile. The index
should correspond to the profile array.

Three profiles are coming with this packet. Do not change anything in
these 3 profiles because they may be overwritten at next update. More
can easily added.

Have a look at the manpage of ffmpeg-filters for 'equalizer'.

ATTENTION
The profile numbers has to be in uninterrupted contignous order
starting with 1!

OPTIONS
Gnu style options:

  -h|--help    = Output help, then exit.
  -V|--version = Output version info, then exit.
  -d|--debug   = Turn on DEBUG mode.
  -q|--quiet   = Be quiet.
  -v|--verbose = Be verbose.
  --ab abr     = Audio bitrate <abr> to use for outfile
                 (default = ffmpeg default).
  -c acod      = Audio codec <acod> to use for outfile (default = aac).
  -l           = List all profiles.
  -p           = Give a profile string as second arg on the cmd line.
                 Do not apply <num>.
  -o f         = Output to file <f>.
  --outfile=f  = Output to file <f>.
  --           = End of options.

ARGUMENTS
Give if needed:

  fil  = A multimedia file (.mp4)
  num  = The profile number to use (1 - $maxEQ)
  pstr = A profile string with 18 comma separated gain values like
         '0,6,3,3,3,3,2,2,2,2,3,3,2,2,1,1,0,0'. Same as in user config.

EXIT STATUS
On program exit:

  Code 0 = OK

  See output of 'showerrmsg'.

FILES
Used directories and files:

  Config User = ~/.mediafilter-equalizerrc

SEE ALSO
Related manpages:

  showerrmsg(1), ffmpeg(1), ffmpeg-filters(1), media2media(1),
  mediafilter-compand(1), mediafilter-dynaudnorm(1),
  mediafilter-volcomp(1), mediafilter-volume(1).

AUTHORS
Juergen Kaesmann <juergen@kaesmann-online.de>
EOT
#  -o|--output  = Output to STDOUT.
#  -i f         = Input from file <f>.
#  --infile=f   = Input from file <f>.
#  --outfile=f  = Output to file <f>.
#  -p s,e       = Pages s=START e=END.
#  --pages=s,e  = Pages s=START e=END.

#EXAMPLES
#For instance:
#
#  Do it:
#  $scriptname

return
}

#=============================================================================
function list_profiles ()
{
# List the profiles.
# par1 = 
# Uses echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG list_profiles: $# $@" >&2
	$debuglog list_profiles: $# $@
fi

local i=0 ret=0

i=0
while [ "$i" -lt "$maxEQ" ]; do
	let ++i
	echo "Profile [$i] = ${EQInfo[$i]}"
done

return $ret
}

#=============================================================================
function get_gains ()
{
# Get the gains.
# par1 = profile string.
# Uses echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG get_gains: $# $@" >&2
	$debuglog get_gains: $# $@
fi

local prof="$1" fin=no s=''
local i=0 ret=0

i=0
while [ "$fin" == no ]; do
	let ++i
	g[$i]=${prof%%,*}				# get 1. val
	prof=${prof#*,}					# cut 1. val
	Find_Substr $prof ','
	ret=$?
	if [ $ret -eq 0 ]; then
		Pop s
	else
		let ++i
		g[$i]=$prof
		fin=yes
	fi
done
if [ $i -eq 18 ]; then
	ret=0
else
	if [ "$verbose" != no ]; then
		echo "${ErrMsg[${_ERR_GENERAL_}]} Profile is defect!" >&2
	else
		$errlog ${ErrMsg[${_ERR_GENERAL_}]} Profile is defect!
	fi
	ret=${_ERR_GENERAL_}
fi

return $ret
}

#=============================================================================
function make_cli ()
{
# Use ffmpeg with the equalizer function.
# par1 = 
# Uses echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG make_cli: $# $@" >&2
	$debuglog make_cli: $# $@
fi

local ffs='' outfile=''
local ret=0

if [ -z "$opt_o" ]; then
	outfile="fixeq_p.mp4"
else
	outfile="$opt_o"
fi

get_gains "$arg2"
ret=$?

if [ $ret -eq 0 ]; then
	ffs="equalizer=f=30:width_type=h:w=40:g=${g[1]},equalizer=f=150:width_type=h:w=200:g=${g[2]},equalizer=f=625:width_type=h:w=750:g=${g[3]},equalizer=f=1500:width_type=h:w=999:g=${g[4]},equalizer=f=2500:width_type=h:w=999:g=${g[5]},equalizer=f=3500:width_type=h:w=999:g=${g[6]},equalizer=f=4500:width_type=h:w=999:g=${g[7]},equalizer=f=5500:width_type=h:w=999:g=${g[8]},equalizer=f=6500:width_type=h:w=999:g=${g[9]},equalizer=f=7500:width_type=h:w=999:g=${g[10]},equalizer=f=8500:width_type=h:w=999:g=${g[11]},equalizer=f=9500:width_type=h:w=999:g=${g[12]},equalizer=f=10500:width_type=h:w=999:g=${g[13]},equalizer=f=11500:width_type=h:w=999:g=${g[14]},equalizer=f=12500:width_type=h:w=999:g=${g[15]},equalizer=f=13500:width_type=h:w=999:g=${g[16]},equalizer=f=14500:width_type=h:w=999:g=${g[17]},equalizer=f=15500:width_type=h:w=999:g=${g[18]}"
	ffmpeg -hide_banner -i $arg1 -vcodec copy -acodec aac -af $ffs $outfile
	ret=$?
fi

return $ret
}

#=============================================================================
function mainproc ()
{
# Use ffmpeg with the equalizer function.
# par1 = 
# Uses echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG mainproc: $# $@" >&2
	$debuglog mainproc: $# $@
fi

local acod=aac abr='' ffs=''
local ret=0
#local -a arr
#maxarr="${#arr[@]}"			# get number of elements in arr
#unset arr[@]				# remove the entire array

if [ -n "$opt_c" ]; then
	acod=$opt_c
fi
if [ -n "$opt_ab" ]; then
	abr=$opt_ab
fi

if [ $arg2 -ge 1 ] && [ $arg2 -le $maxEQ ]; then
	:
else
	if [ "$verbose" != no ]; then
		echo "${ErrMsg[${_ERR_VAL_OUT_OF_RANGE_}]}" >&2
	else
		$errlog ${ErrMsg[${_ERR_VAL_OUT_OF_RANGE_}]}
	fi
	return ${_ERR_VAL_OUT_OF_RANGE_}
fi

get_gains "${EQProfile[$arg2]}"
ret=$?

if [ $ret -eq 0 ]; then
	ffs="equalizer=f=30:width_type=h:w=40:g=${g[1]},equalizer=f=150:width_type=h:w=200:g=${g[2]},equalizer=f=625:width_type=h:w=750:g=${g[3]},equalizer=f=1500:width_type=h:w=999:g=${g[4]},equalizer=f=2500:width_type=h:w=999:g=${g[5]},equalizer=f=3500:width_type=h:w=999:g=${g[6]},equalizer=f=4500:width_type=h:w=999:g=${g[7]},equalizer=f=5500:width_type=h:w=999:g=${g[8]},equalizer=f=6500:width_type=h:w=999:g=${g[9]},equalizer=f=7500:width_type=h:w=999:g=${g[10]},equalizer=f=8500:width_type=h:w=999:g=${g[11]},equalizer=f=9500:width_type=h:w=999:g=${g[12]},equalizer=f=10500:width_type=h:w=999:g=${g[13]},equalizer=f=11500:width_type=h:w=999:g=${g[14]},equalizer=f=12500:width_type=h:w=999:g=${g[15]},equalizer=f=13500:width_type=h:w=999:g=${g[16]},equalizer=f=14500:width_type=h:w=999:g=${g[17]},equalizer=f=15500:width_type=h:w=999:g=${g[18]}"
	case "$verbose" in
	    yes)				# allow STDOUT and STDERR
		echo "Run $scriptname"
		ffmpeg -i $arg1 -vcodec copy -acodec $acod $abr -af $ffs $outfile
		ret=$?
		;;
	    '')					# suppress STDOUT or STDERR
		#echo "Run $scriptname"
		ffmpeg -hide_banner -i $arg1 -vcodec copy -acodec $acod $abr -af $ffs $outfile
		#2>/dev/null
		#1>/dev/null
		ret=$?
		;;
	    no)					# suppress STDOUT and STDERR
		ffmpeg -hide_banner -y -i $arg1 -vcodec copy -acodec $acod $abr -af $ffs $outfile &>/dev/null
		ret=$?
		;;
	esac

	if [ "$ret" -ne 0 ]; then			# for other progs
		if [ "$verbose" != no ]; then
			echo "${ErrMsg[${_ERR_GENERAL_}]} $ret from ffmpeg!" >&2
		else
			$errlog ${ErrMsg[${_ERR_GENERAL_}]} $ret from ffmpeg
		fi
		ret=${_ERR_GENERAL_}
	fi
fi

return $ret
}

##############################################################################
# GET OPTIONS
##############################################################################
# Give 2 strings and all cmdline_args to func GetOpt
# (POSIX_options Gnu_long_options cmdline_args):
# GetOpt 'hVdqvi:m:' 'help version debug quiet verbose infile= myval=' $@
#
# A ':' after a POSIX option means this option needs an arg.
# A '=' after a Gnu long option means this option needs an arg.
#
# All cmd/options have to be initialised to ''!
#
# Options are divided in 2 classes:
#   a) cmds (mutually exclusive). All cmds are given to var 'cmd'.
#   b) options (as many as you like). Each option is given to it's own var.
# As a general rule: If cmds/options are given multiple then last given wins.
#
# Options can take 1 argument (no whitespace in arg). If you want to give more
# than 1 arg or want to use multiple strings as 1 arg then concatenate them
# together with a delimiter like ',' or ';' or '.'
# Use a delimiter which will not be part of the arg:
# sampleprog -m val1,val2
# sampleprog --myval=val1,val2
# It's at the programmers responsibility to do meaningfull things with the
# content of the options.
#
# While err = 0 then look for a next option.
# When GetOpt finishes then all options are removed from cmdline.
#
if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG Parse Commandline: $# $@" >&2
	$debuglog Parse Commandline: $# $@
fi
#
err=${_ERR_OK_}
while [ "$err" -eq 0 ]; do
	GetOpt 'hVdqvc:lo:p' 'help version debug quiet verbose outfile= ab=' $@
	err=$?
	#echo "DEBUG GET OPTIONS: err=${err}  _OPTNAME_=${_OPTNAME_}  _OPTVAL_=${_OPTVAL_}  _OPTPOS_=${_OPTPOS_}  _OPTIDX_=${_OPTIDX_}" >&2
	if [ $err -eq 0 ]; then
		case "$_OPTNAME_" in
		    h|help)	cmd="-h";;
		    V|version)	cmd="-V";;
		    l)		cmd="-${_OPTNAME_}";;
		    p)		cmd="-${_OPTNAME_}";;
		    d|debug)	debug=yes;;
		    q|quiet)	verbose=no;;
		    v|verbose)	verbose=yes;;
#		    o|output)	opt_o=yes;;
#		    i|infile)	opt_i="${_OPTVAL_}";;
		    o|outfile)	opt_o="${_OPTVAL_}";;
#		    p|pages)	opt_p="${_OPTVAL_}";;
		    ab)		opt_ab="${_OPTVAL_}";;
		    c)		opt_c="${_OPTVAL_}";;
		    --)		break;;
		    :)	if [ "$verbose" != no ]; then
				echo "${ErrMsg[${_ERR_MISSING_ARG_FOR_OPT_}]} -${_OPTVAL_}" >&2
			else
				$errlog ${ErrMsg[${_ERR_MISSING_ARG_FOR_OPT_}]} -${_OPTVAL_}
			fi; exit ${_ERR_MISSING_ARG_FOR_OPT_};;
		    ?)	if [ "$verbose" != no ]; then
				echo "${ErrMsg[${_ERR_UNKNOWN_OPT_}]} -${_OPTVAL_}" >&2
			else
				$errlog ${ErrMsg[${_ERR_UNKNOWN_OPT_}]} -${_OPTVAL_}
			fi; exit ${_ERR_UNKNOWN_OPT_};;
		    *)	if [ "$verbose" != no ]; then
				echo "${ErrMsg[${_ERR_UNKNOWN_ERR_}]} _OPTNAME_=${_OPTNAME_} _OPTVAL_=${_OPTVAL_}" >&2
			else
				$errlog ${ErrMsg[${_ERR_UNKNOWN_ERR_}]} _OPTNAME_=${_OPTNAME_} _OPTVAL_=${_OPTVAL_}
			fi; exit ${_ERR_UNKNOWN_ERR_};;
		esac
	fi
done
err=${_ERR_OK_}
shift ${_OPTIDX_}				# rm all opts from cmdline
#
# Uncomment if giving a cmd is mandatory
#if [ -z "$cmd" ]; then					# error no cmd given
#	if [ "$verbose" != no ]; then
#		echo "${ErrMsg[${_ERR_MISSING_SUB_CMD_}]}" >&2
#	else
#		$errlog ${ErrMsg[${_ERR_MISSING_SUB_CMD_}]}
#	fi
#	exit ${_ERR_MISSING_SUB_CMD_}
#fi

##############################################################################
# CHECK LINK NAMES

##############################################################################
# CHECK OPTIONS

##############################################################################
# CHECK VERSION

##############################################################################
# CHECK ARGUMENTS
#
case "$cmd" in
    ''|-p)
	if [ "$#" -eq 2 ]; then				# parameter count ok
		arg1="$1"
		arg2="$2"
		shift 2
		#args="$@"
		#shift $#
	else						# error in param count
		if [ "$verbose" != no ]; then
			echo "${ErrMsg[${_ERR_WRONG_PAR_COUNT_}]}" >&2
		else
			$errlog ${ErrMsg[${_ERR_WRONG_PAR_COUNT_}]}
		fi
		exit ${_ERR_WRONG_PAR_COUNT_}
	fi
	;;
    *)
	if [ "$#" -ne 0 ]; then				# error in param count
		if [ "$verbose" != no ]; then
			echo "${ErrMsg[${_ERR_WRONG_PAR_COUNT_}]}" >&2
		else
			$errlog ${ErrMsg[${_ERR_WRONG_PAR_COUNT_}]}
		fi
		exit ${_ERR_WRONG_PAR_COUNT_}
	fi
	;;
esac

##############################################################################
# LOCK

##############################################################################
# MAINPROGRAM
##############################################################################
#
if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG Main: $# $@" >&2
	$debuglog Main: $# $@
fi

# Check what to do (sub commands, options and args are removed from cmdline)
case "$cmd" in
    '')							# no cmd given
	if [ -z "$opt_o" ]; then
		outfile="fixeq_${arg2}.mp4"
	else
		outfile="$opt_o"
	fi
	mainproc
	err=$?
	;;
    -p)							# cmd -p
	make_cli
	err=$?
	;;
    -h)							# cmd -h
	helptext
	exit 0
	;;
    -V)							# cmd -V
	echo "${scriptname}: (${package}) $package_file ${version}-${release}"
	exit 0
	;;
    -l)							# cmd -l
	list_profiles
	err=$?
	;;
    *)							# other cmds = error
	if [ "$verbose" != no ]; then
		echo "${ErrMsg[${_ERR_SUB_CMD_NOT_FOUND_}]}" >&2
	else
		$errlog ${ErrMsg[${_ERR_SUB_CMD_NOT_FOUND_}]}
	fi
	err=${_ERR_SUB_CMD_NOT_FOUND_}
	;;
esac

#rm -f $lockfile

exit $err
