#!/bin/bash
#
# Copyright (C) by Stefano Falsetto
# e-mail contact ....: mailto:stefko@libero.it
# This program is distributed under the GNU General Public License
# You are not allowed to remove the copyright notice
#
# This script converts a list of mp3 files in .wav or .cdr
# and eventually record these files on a cd.


TEMPDIR="$HOME/tmp"
[ ! -d $TEMPDIR ] && mkdir -p $TEMPDIR
TEMPDATA=$TEMPDIR/mp3conv-tempdata.$$
TEMPNOMEF=$TEMPDIR/mp3conv-tempnomef.$$
SONGDATA=$TEMPDIR/mp3conv-songdata.$$
TMPTOC=$TEMPDIR/mp3conv-tocdata.$$
FILETEMPSONG=$TEMPDIR/mp3conv-filetempsong.$$
trap 'rm -f $TEMPDATA $SONGDATA $TMPTOC $FILETEMPSONG $TEMPNOMEF; exit $USCITA' 0
trap 'echoc RED "Esecuzione interrotta!"; exit 99' 2
USCITA=0

################################################################################
#                         BEGIN CONFIGURABLE DEFAULT VALUES                    #
################################################################################
DELFILES=""				# If set remove files from actual dir
NODUMMY=""				# If set don't ask for a dummy write
MPGCMD="wav"				# Default conversion type
SOX="/usr/bin/sox"			# Complete path for sox
DECODER="/usr/local/bin/mpg123"		# Complete path for mpg123
DEFWRITER="cdrecord"			# Default writer program
OPZCDRECORD="dev=0,0,0 -v -pad -audio "	# Options for cdrecord
OPZCDRDAO=" --device 0,0,0 -v 3 "	# Options for cdrdao
PRIVUSER="root"				# Username that can exec cdrdao/cdrecord
NORM=""					# Normalize wav files by default?
NORMALIZE="/usr/local/bin/normalize"	# Complete path for normalize
OPZNORM=" -v "				# Global options for normalize
DEFMETNORM=" -b "			# Default method of normalize 
					# (-b batch -m mix)
DEFNORM="batch"				# Only a description...
################################################################################
#                        END CONFIGURABLE DEFAULT VALUES                       #
################################################################################

if [ -r $HOME/.mp3do.rc ]; then 
  . $HOME/.mp3do.rc
elif [ -r /etc/mp3do.rc ]; then
  . /etc/mp3do.rc
fi

TOCFILE="";
SONGFILE="";
VERSION="1.4b"

banner() {
  echoc WHITE "This is MP3do ver $VERSION"
  echoc WHITE "Copyright (C) 2001 by Stefano Falsetto"
  echo
}

quest() {
  local Q

  if [ -z $4 ]; then
    echoc RED "There are no valid return valules!"
    exit -999;
  fi
  # TODO parametrize default reponse
  while [ 0 ]; do
    echoc CYAN -n "$1 (Y/N) [Y] "
    read Q
    case "$Q" in
      ""|Y|y|S|s)
        echoc YELLOW "$2"
        return $4
        break
        ;;
      N|n)
        echoc YELLOW "$3"
        return $5
        break
        ;;
      *)
        echoc CYAN "Valid reponses: Y or N"
        ;;
    esac
  done
}

writecd() {

# Preparing parameters...
  local WRITER="$1"
  local OPZDUMMY="$2"
  local OPZ="$3"
  local OTHER=""

  while [ ! -z "$4" ]; do
    OTHER="$OTHER $4"
    shift
  done

  while [ 0 ]; do
    COMMAND="$WRITER $OPZDUMMY $OPZ $OTHER"
    $COMMAND
    if [ $? -ne 0 ]; then
      echoc RED "CD has not been properly writed!"
      USCITA=12
      exit $USCITA
    else
      if [ -z "$OPZDUMMY" ]; then
        echoc YELLOW "Sucessfully Terminated. :-)"
        return 0
      else
        echoc CYAN "Dummy write successfully terminated. Will execute real write..."
        OPZDUMMY=""
      fi
    fi
  done
}

atip_cd() {
  local ATIPTOT=$($ATIP 2>&1|grep "lead out"|cut -d'(' -f2)
  if [ -z "$ATIPTOT" ]; then
    echoc RED "Could'nt read ATIP from CD! Perhaps CD in not in the writer?"
    USCITA=11; exit $USCITA
  fi
  #ATIPTOT="74:45/00)"
  #ATIPTOT=" 9:00/00)"
  ATIPMIN=${ATIPTOT:0:2}
  ATIPSEC=${ATIPTOT:3:2}
}

estrai_tempo() {
  $DECODER -t -q -v -n 0 "$1" >$SONGDATA 2>&1
  TEMPOSONG=$(cat $SONGDATA|grep Frame|cut -d'[' -f3)
  WCL=$(cat $SONGDATA|wc -l)

  if [ $WCL -ne 0 ]; then
    echoc GREEN " WARNING: This file has some error"
  fi

  # isoliamo i vari pezzi
  MINUTI=${TEMPOSONG:0:2}
  SECONDI=${TEMPOSONG:3:2}
  MSEC=${TEMPOSONG:6:2}

}
calcola_tempo() {

  TTOT="00:00:00"

  #echoc CYAN "--------------------------------------------------------------"
  while read i; do
    #echoc CYAN " Song : $(basename "$i" .mp3)"
    estrai_tempo "$i"   
    #echoc CYAN " Time : $MINUTI:$SECONDI/$MSEC"
  
    TOTMSEC=$[ 10#$TOTMSEC + 10#$MSEC ];
    if [ $TOTMSEC -gt 99 ]; then
      SECONDI=$[ 10#$SECONDI + 1];
      TOTMSEC=$[ 10#$TOTMSEC - 100 ];
    fi
  
    TOTSEC=$[ 10#$TOTSEC + 10#$SECONDI ];
    if [ $TOTSEC -gt 59 ]; then
      MINUTI=$[ 10#$MINUTI + 1 ];
      TOTSEC=$[ 10#$TOTSEC - 60 ];
    fi
    
    TOTMIN=$[ 10#$TOTMIN + 10#$MINUTI ];
    #echoc CYAN "--------------------------------------------------------------"

done <$SONGFILE


TTOT=$(echo "$TOTMIN:$TOTSEC.$TOTMSEC");

}

sintassi() {
  cat << EOF
  Sintassi: MP3do <options>
  -h, --help
      Display this help screen
  -V, --version
      Display version and exit
  -f=<filename>, --file=<filename>
      The mp3 files are read from this file.
  -t=<wav|cdr>, --type=<wav|cdr>
      The type of file that will be used for "expand" an mp3 file.
      Default: $MPGCMD
  -s <filelist>, --songs <filelist>
      Instead of using -f option you can specify each file one-by-one.
  --toc=<tocfile>
      The tocfile (cdrdao compatible) created while decoding mp3 files. 
  -T, --timesum
      Compute sum of minutes and seconds of all mp3 files and exit.
  -n <=mix|batch>, --normalize <=mix|batch>
      Normalize all the song with the method specified.
      Default method is $DEFNORM
EOF
if [ "$USER" = "$PRIVUSER" ]; then
  cat << EOF

  Options for user $PRIVUSER:
  -a, --atip
      Read ATIP data from cd in the mastering device and compares the
      lead out time with the duration of all the mp3 files.
      (Implies -w)
  -w [=<cdrdao|cdrecord>], --write [=<cdrdao|cdrecord>]
      To write a cd with the previously converted files. 
      Implies -t=wav. Default: $DEFWRITER
  --on-the-fly
      Burn a cd 'on the fly' while decoding mp3. 
      (Implies -w=cdrecord -t=cdr)
  --one-by-one
      Decode and burn one song at time. (Implies -w=cdrecord)
  -r, --nodummy
      Don't ask to perform a dummy write before a real burning process
      (Implies -w)
  -d, --purge
      Delete converted files from actual dir after a well terminated
      burning process. (Implies -w)
EOF
fi
}

banner

if [ $# -eq 0 ]; then
  echoc RED "No parameters specified!"
  sintassi
  USCITA=1; exit $USCITA
fi

if [ ! -e $SOX ]; then
  echoc GREEN "WARNING WARNING WARNING"
  echoc GREEN "I can't find sox program. Perhaps you must set properly"
  echoc GREEN "SOX variable."
  echoc GREEN "For this instance auto-conversion is disabled..."
  echoc GREEN "WARNING WARNING WARNING"
  echo ""
  SOX=""
fi

if [ ! -e $NORMALIZE ]; then
  echoc GREEN "WARNING WARNING WARNING"
  echoc GREEN "I can't find normalize program. Perhaps you must set properly"
  echoc GREEN "NORMALIZE variable."
  echoc GREEN "Eventually normalize phase will not be performed..."
  echoc GREEN "WARNING WARNING WARNING"
  echo
  NORMALIZE=""
fi

if [ ! -e $DECODER ]; then
  echoc RED "I can't find mpg123 program. Perhaps you must set properly";
  echoc RED "DECODER variable"
  USCITA=7; exit $USCITA
fi

# Parsing della linea di comando
while [ 0 ]; do
  case "$1" in
  -h|--help)
       sintassi;
       USCITA=0; exit 0;
       ;;
  -f=*|--file=*)
       if [ $(expr match "$1" "-f=") -eq 0 ]; then
         NOMEF=${1:7}
       else
         NOMEF=${1:3}
       fi
       if [ -r "$NOMEF" ]; then
         grep -v "#" $NOMEF |grep "[:print:]" >$TEMPNOMEF
         SONGFILE=$TEMPNOMEF 
       else
         echoc RED "File $1 is not readable"
         USCITA=2; exit 2
       fi
       ;;
  --toc=*)
       if [ ! -e "${1:6}" ]; then
         TOCFILE="${1:6}"
       else
         echoc RED "TOC file already exist!"
         USCITA=5; exit 5
       fi
       ;;
  -t=*|--type=*)
       if [ $(expr match "$1" "-t=") -eq 0 ]; then
         TIPO=${1:7}
       else
         TIPO=${1:3}
       fi
       case "$TIPO" in
         WAV|wav|CDR|cdr)
         	MPGCMD=$(echo "$TIPO"|tr A-Z a-z); # convert to lowercase
         	;;
         *)
         	echoc RED "Type $TIPO not supported"
         	USCITA=3; exit 3
         	;;
       esac
       ;;
  -s|--song)
       #echo "Lista canzoni da linea di comando:"
       SONGFILE=$TEMPDATA
       ;;
  -T|--timesum)
       ONLYTIME=1
       ;;
  -n|--normalize)
       if [ ! -z $NORMALIZE ]; then
         NORM=$DEFNORM
         METHODNORM=$DEFMETNORM
       fi
       ;;
  -n=batch|--normalize=batch)
       if [ ! -z $NORMALIZE ]; then
        NORM="batch"
        METHODNORM=" -b "
       fi
       ;;
  -n=mix|--normalize=mix)
       if [ ! -z $NORMALIZE ]; then
         NORM="mix"
         METHODNORM=" -m "
       fi
       ;;
  -a|--atip)
       if [ "$USER" != "$PRIVUSER" ]; then
         echoc GREEN "WARNING: $1 is only for $PRIVUSER!"
       #  ATIP=""
       else
         ATIP="cdrecord -atip"
       fi
       ;;
  -w|--writer)
       if [ "$USER" != "$PRIVUSER" ]; then
         echoc GREEN "WARNING: $1 is only for $PRIVUSER!"
       else
         WRITER=$DEFWRITER;
       fi
       ;;
  -w=*)
       if [ "$USER" != "$PRIVUSER" ]; then
         echoc GREEN "WARNING: $1 is only for $PRIVUSER!"
         WRITER=""
       else
         WRITER=$(echo "${1:3}"|tr A-Z a-z)
       fi
       ;;
   --writer=*)
       if [ "$USER" != "$PRIVUSER" ]; then
         echoc GREEN "WARNING: $1 is only for $PRIVUSER!"
         WRITER=""
       else
         WRITER=$(echo "${1:9}"|tr A-Z a-z)
       fi
       ;;
  -r|--nodummy)
       if [ "$USER" != "$PRIVUSER" ]; then
         echoc GREEN "WARNING: $1 is only for $PRIVUSER!"
       else
         NODUMMY=1
       fi
       ;;
  -d|--purge)
       if [ "$USER" != "$PRIVUSER" ]; then
         echoc GREEN "WARNING: $1 is only for $PRIVUSER!"
       else
         DELFILES=1
       fi
       ;;
  --on-the-fly)
       if [ "$USER" != "$PRIVUSER" ]; then
         echoc GREEN "WARNING: $1 is only for $PRIVUSER!"
       else
         ALVOLO=1;
       fi
       ;;
  --one-by-one)
       if [ "$USER" != "$PRIVUSER" ]; then
         echoc GREEN "WARNING: $1 is only for $PRIVUSER!"
       else
         UNOAUNO=1;
       fi
       ;;
  -V|--version)
       banner
       USCITA=0; exit 0
       ;;
  *)
       if [ "$SONGFILE" = "$TEMPDATA" ]; then
           echo "$1">>"$TEMPDATA"
       else
         echoc RED "Bad parameter: $1"
         USCITA=4; exit 4
       fi
       ;;
  esac
  shift
  if [ $? = $# ]; then
    break
  fi
          
done

# Sanity checks...

if [ -z $SONGFILE ]; then 
  echoc RED "Need parameter -s or -f"
  USCITA=14; exit $USCITA
fi

if [ ! -z "$WRITER" ]; then
  if [ "$WRITER" != "cdrdao" -a "$WRITER" != "cdrecord" ]; then
    echoc RED "Unknown writer!"
    USCITA=9; exit $USCITA
  fi
fi

if [ ! -z "$UNOAUNO" -o ! -z "$ALVOLO" ] && [ "$WRITER" = "cdrdao" ]; then
  echoc GREEN "WARNING: --one-by-one option implies --writer=cdrecord"
  echoc GREEN "WARNING: Using --writer=cdrecord"
  WRITER="cdrecord"
fi

if [ ! -z "$UNOAUNO" ]; then
  WRITER="cdrecord "
fi

if [ "$WRITER" = "cdrdao" ] && [ -z "$TOCFILE" ]; then
  T="cd_$$.toc"
  echoc GREEN "WARNING: No tocfile specified. Using tocfile $T"
  TOCFILE=$T
fi

if [ ! -z "$NORM" ] && [ "$TIPO" = "cdr" ]; then
  echoc RED "ERROR: Can't normalize cdr file type!"
  USCITA=16; exit $USCITA
fi

if [ ! -z $NODUMMY ] && [ -z $WRITER ]; then
  echoc GREEN "WARNING: -r option has no effect without -w!"
fi

if [ ! -z $DELFILES ] && [ -z $WRITER ]; then
  echoc GREEN "WARNING: -d option has no effect without -w!"
fi

if [ ! -z $TOCFILE ]; then
  echo "CD_DA" >> $TOCFILE
  echo "" >> $TOCFILE
fi

# Check if all files are readable:
echoc CYAN "Checking for file type..."
echoc CYAN "--------------------------------------------------------------"
c=0
while read i; do
  TIPOFILE=$(file "$i"|cut -d':' -f2)
  if [ -r "$i" ] && [ ! -z "$(expr "${TIPOFILE:1:16}" : '\(MPEG [1-4].0 layer 3\)')" ]; then
     echo "$i">>"$FILETEMPSONG"
     echoc CYAN "File : $(basename "$i" .mp3).mp3"
     echoc CYAN "Type : ${TIPOFILE:1:16}"
     estrai_tempo "$i"
     echoc CYAN "Time : $MINUTI:$SECONDI/$MSEC"
  else
     echoc GREEN "WARNING: File "$i" is not readable or not an mp3."
  fi
  echoc CYAN "--------------------------------------------------------------"
done <$SONGFILE
echoc CYAN "Check finished."

if [ ! -e $FILETEMPSONG ]; then
  echoc RED "No valid song! What kind of playlist you've submitted?"
  USCITA=15; exit $USCITA
else
  SONGFILE=$FILETEMPSONG
fi

calcola_tempo
echoc CYAN "Total song time: $TOTMIN:$TOTSEC/$TOTMSEC"

if [ ! -z "$ATIP" ]; then
  atip_cd
  [ $ATIPSEC -gt $TOTSEC ] && SEC=$[ ATIPSEC - TOTSEC ] || SEC=$[ TOTSEC - ATIPSEC ]
  if [ $TOTMIN -gt $ATIPMIN ]; then
    echoc RED "Songs don't fit on CD!"
    echoc RED "Total song time exceed maximum time recordable on this CD"
    echoc RED "Time exceeding: $[ TOTMIN - ATIPMIN ] minutes"
    USCITA=6; exit $USCITA
  fi
  if [ $TOTMIN -eq $ATIPMIN ]; then
    if [ $TOTSEC -gt $ATIPSEC ]; then
      echoc GREEN "Songs don't fit on CD!"
      echoc GREEN "Total song time exceed maximum time recordable on this CD"
      echoc GREEN "Time exceeding: $SEC seconds"
      echo ""
      echoc GREEN "Some CD writer may overburn"
      quest "Did you want to try to record this cd?" "Songs will be converted" "You must edit your playlist!" 1
      OVRBURN=$?
      if [ $OVRBURN -eq 0 ]; then
         USCITA=8; exit $USCITA
      else
         SEC="-$SEC"
      fi
    fi
  fi
  echoc CYAN "Total time for cd: $ATIPMIN:$ATIPSEC"
  echoc CYAN "Time remaining on cd: $[ ATIPMIN - TOTMIN ]:$SEC"
fi

if [ ! -z $ONLYTIME ]; then
  USCITA=0; exit $USCITA
fi

numero=0
while read i; do 
  numero=$[ numero + 1]
  nome=$(echo "$(basename "$i" .mp3)")
  if [ $numero -lt 10 ]; then 
    nomef=$(echo "0$numero-$nome"|tr " " "_")
  else 
    nomef=$(echo "$numero-$nome"|tr " " "_")
  fi

  [ -z $TOCFILE ] || echo "TRACK AUDIO" >> $TOCFILE

  echo ""
  echoc CYAN "Decoding $nomef ..."
  RATESONG=$($DECODER -t -q -v -n 1 "$i" 2>&1|grep Audio|cut -d':' -f4|cut -d',' -f1)
  if [ $RATESONG -ne 44100 ] && [ ! -z $SOX ]; then
    echoc CYAN "Automatic conversion: ${RATESONG}Hz -> 44100Hz"
    if [ ! -z "$ALVOLO" ]; then
      $DECODER -b 10000 -s "$i" | \
        $SOX -t raw -r $RATESONG -s -w -c 2 - -r 44100 -t wav -c 2 - rate | \
        cdrecord -v -pad -nofix -audio -
    else
      $DECODER -q -v -b 10000 -s "$i" | \
       $SOX -t raw -r $RATESONG -s -w -c 2 - -c 2 -r 44100 "$nomef.$MPGCMD" rate
    fi
  else
    if [ ! -z "$ALVOLO" ]; then
      $DECODER  --cdr - "$i" | cdrecord -v -audio -pad -nofix -
    else
      $DECODER -q -v --$MPGCMD "$nomef.$MPGCMD" "$i"
    fi
  fi
  echo ""
  
  if [ ! -z "$UNOAUNO" ]; then
    echoc CYAN -n "Writing this track"
    if [ -z "$NODUMMY" ]; then
      OPZDUMMY="-dummy"
      echoc CYAN -n " in dummy mode"
    fi
    echoc CYAN "..."
    writecd "cdrecord" "$OPZDUMMY" "$OPZCDRECORD -nofix" "$nomef.$MPGCMD"
    if [ ! -z "$DELFILES" ]; then
      echoc CYAN "Removing $nomef.$MPGCMD"
      rm -f "$nomef.$MPGCMD" 
    fi
  fi
  
  if [ ! -z $TOCFILE ]; then 
    echo "AUDIOFILE \"$nomef.$MPGCMD\" 0">>$TOCFILE
    echo "" >>$TOCFILE
  fi

done<$SONGFILE

echo ""
if [ ! -z "$UNOAUNO" ]; then
  writecd "cdrecord" "" "-v -fix" 
  USCITA=0; exit $USCITA
fi

echoc CYAN "Decoding phase terminated."
echo
if [ -z $NORM ] && [ -z $WRITER ]; then
  USCITA=0; exit $USCITA
fi
# It's realy needed?
NUMSONG=$(/bin/ls [0-9]*.$MPGCMD|wc -l)
NUMLSONG=$(cat $SONGFILE|wc -l)

if [ $NUMSONG -ne $NUMLSONG ]; then
  echoc RED "There is some problem: in this dir there are some 'outsider'"
  USCITA=10; exit $USCITA
fi

for i in [0-9]*.$MPGCMD; do
  LISTASONG="$LISTASONG $i"
done

if [ ! -z "$NORM" ]; then
  echoc CYAN "Normalize phase in $NORM mode..."
  $NORMALIZE $OPZNORM $DEFMETNORM $LISTASONG
fi

# Normal burning phase
if [ ! -z $WRITER ]; then
  OPZDUMMY=""
  echoc CYAN "Writing procedure with $WRITER"
  if [ "$WRITER" = "cdrecord" ]; then
    if [ -z "$NODUMMY" ]; then
      quest "Do you want to test this burning process (dummy write)?" "Dummy write..." "Will not perform dummy write..." 1
      if [ $? -eq 1 ]; then
        OPZDUMMY="-dummy"
      fi
    fi
    writecd "$WRITER" "$OPZDUMMY" "$OPZCDRECORD" "$LISTASONG"
  else
    $WRITER show-toc $TOCFILE 2>$TMPTOC
    grep -q "ERROR" $TMPTOC>/dev/null
    if [ $? -eq 0 ]; then
      echoc RED "There is some problem: the toc-file has some error..."
      USCITA=13; exit $USCITA
    fi
    if [ -z "$NODUMMY" ]; then 
      quest "Do you want to test this burning process (dummy write)?" "Dummy write..." "Will not perform dummy write..." 1
      if [ $? -eq 1 ]; then
        OPZDUMMY="--simulate"
      fi
    fi
    writecd "$WRITER write" "$OPZDUMMY" "$OPZCDRDAO" "$TOCFILE"
  fi
  if [ ! -z $DELFILES ]; then
    echoc CYAN "Removing $MPGCMD files..."
    rm -fv $LISTASONG
  fi
fi
