#!/bin/sh
# mksffuncs : Linux version only; there is a separate SGI version 
# creates soundfile functions for a score11 file score
# see also : mkkeymap , mkmidisffuncs , mkmidikeymap
# last modified 7/28/03  A. S.

if ( [ $# == 0 ] ) ; then  # print usage summary
   echo " This script creates Csound gen1 function definitions for soundfiles in a format"
   echo " suitable for inclusion in SCORE11 input files. Syntax:"
   echo "  mksffuncs [-flag(s)] infile1 [infile2] [infileN] [> outputfile]"
   echo "where valid flag options are "
   echo " -f : the following argument(s) are ascii files containing"
   echo "      lists of soundfiles, rather than the names of soundfiles"
   echo " -s : before creating the functions, sort the soundfiles by"
   echo "      pitch abbreviation (lowest to highest pitched, then unpitched)"
   echo " -N : (must be in CAPS) the next argument gives the number for the first"
   echo "      (lowest numbered) function definition"
   echo "Multiple flag option can be given one at a time or concatenated."
   echo 'Soundfile arguments are the names of soundfiles in your current'
   echo "working soundfile directory or in any of the 44.1 k or 96 k sflib directories."
   echo "To include soundfiles from one of your soundfile subdirectories,"
   echo "include the subdirectory name or the full path name."
   echo " You can omit .wav extensions from input soundfile names if you wish."
    echo " Examples:  1:   mksffuncs  myvoice.wav fl.c4.wav  cym.brush.edge.ff.wav"
    echo "   or mksffuncs  myvoice fl.c4  cym.brush.edge.ff"
   echo ' Result: Function definitions are created for your soundfile "myvoice.wav", for'
   echo " the 44.1k sflib soundfiles wind/fl.c4.wav  and for the sflib96 soundfile"
   echo "/perc/cymcym.brush.edge.ff.wav"
   echo ' (2)   mksffuncs -N 20  myvoice fl.c4  cym.brush.edge.ff.wav'
   echo " Result: same as above, but  function numbers begin with f20 rather than f1"
   echo ' (3)     mksffuncs -fs playlist1 playlist2'
   echo "  or     mksffuncs -s -f playlist1 playlist2"
   echo ' Result: Functions are made for the soundfiles listed in'
   echo ' ascii files "playlist1" and "playlist2" and are sorted from lowest to highest pitched."'
   echo " For more details, see the mksffuncs man page."
   echo "       -   -   -   -   -"
   exit 0
fi

SFLIBDIRS="/sflib"
# (1) separate flag arguments (which can be concatenated or given separately) from soundfile arguments
FILEINPUT="NO"
SORT="NO"
FUNCNUM="1"
# Function used whenever -N flag found:
NUMBERFUNC() {
      CHECK=`echo $1 | grep  '[0-9]' | grep -v '[a-z][A-Z]'`
      if [[ `echo $CHECK` != "" ]] ; then
         FUNCNUM=$CHECK
         shift
      else
         echo " ERROR: When the -N flag is used, the next argument must be a number for the"
         echo " first (lowest numbered) function definition to be created."
         echo ' Your argument " '$1' "  is not a valid integer function number. Quitting.'
        exit 1
       fi
}

# check all permutations of inputs for the 3 flags f s and N:
while (( "$#" )); do
  if [ `echo $1 | grep -e "\-" |  grep -e "f" | grep -e "s" | grep -e "N"` ] ; then
       FILEINPUT="YES"
       SORT="YES"
      shift
      NUMBERFUNC $1
      shift
  elif [ `echo $1 | grep -e "\-" |  grep -e "f" | grep -e "N"` ] ; then
       FILEINPUT="YES"
       shift
       NUMBERFUNC $1
       shift
  elif [ `echo $1 | grep -e "\-" |  grep -e "s" | grep -e "N"` ] ; then
       SORT="YES"
       shift
       NUMBERFUNC $1
       shift

   elif [ `echo $1 | grep -e "\-" |  grep -e "f" | grep -e "N"` ] ; then
       FILEINPUT="YES"


   elif  [  "$1" == "-f" ]  ; then
       FILEINPUT="YES"
       shift
   elif  [  "$1" == "-s" ]  ; then
        SORT="YES"
       shift
   elif  ( [  "$1" == "-fs" ] || [  "$1" == "-sf" ] ) ; then
       FILEINPUT="YES"
       SORT="YES"
       shift
   elif  [  "$1" == "-N" ]  ; then
      shift
      NUMBERFUNC $1
      shift
  else
  SFARGS=`echo $SFARGS $1`
  shift
      fi
done
  # echo FILEINPUT is $FILEINPUT, SORT is $SORT, FUNCNUM is $FUNCNUM and SFARGS is $SFARGS

# Check to make certain there are soundfile arguments
if [ "$SFARGS" == "" ] ; then
    echo "ERROR: NO input soundfiles specified. Quitting."
    exit 1
 fi
############################
# If file input of soundfile names is specified with -f flag:
if [ $FILEINPUT = "YES" ] ; then   
  for FILE in $SFARGS ; do  
      if  ( ! [  -f $FILE ] ) ; then
      echo "ERROR: No file named >> $FILE << found. Quitting."
      echo "   (Your current working directory is `pwd`)"
     exit 1
     fi
  SFLIST=`cat $SFARGS | grep -v COMMENT`
  done
   #echo SFLIST is $SFLIST
fi  # maybe make this an else
# Actual soundfile names are specified on command line
# Search user's soundfile directories, then sflib96, then 44.1k sflib:
cd $SFDIR
if [ ! $FILEINPUT = "YES" ] ; then ### OPENING IF : search nest level 1 ######
  SFLIST=""
# first search user's soundfile directories:
   for SF in $SFARGS ; do  #### LOOP FOR ALL SF ARGUMENTS ## search nest level 2 ##
     CONTIN="YES"  # ugly, but avoids too many nested levels
      if  ( [  -f $SF ] ) ; then  ### search nest level 3 ######
        SFLIST=`echo $SFLIST $SF`  # in $SFDIR, or user supplies full path
        CONTIN="NO"  # ugly, but avoids too many nested levels
      elif  ( [  -f $SF.wav ] ) ; then  
        SFLIST=`echo $SFLIST $SF.wav`
        CONTIN="NO"  # ugly, but avoids too many nested levels
######################################
# at this point you could recurively search all of the user's directories so that
# user would only need supply soundfile name, not directory path, like this:
#  USERDIRS=`ls -R $SFDIR | grep : | sed -e 's/://g'`
     #  need an else if here -- soundfile not yet found
#      foreach UDIR `echo $USERDIRS` ; do
#         if ( [  -f $UDIR/$SF ] ) ; then
#             SFLIST=`echo $SFLIST $SF.wav`
#         fi       
#       done
#    if  xxxxxx
######################################
fi
# if not found yet search the sflib directories, 96k first then 44.1k:
   if ( [ "$CONTIN" == "YES" ] && [  -d $SFLIB96 ] ) ; then  # search 96k sflib dirs
   SFLIB96DIRS=`ls -R $SFLIB96 | grep sflib | sed -e 's/://g' | sed -e 's/\/snd//g' | grep -v \/anal\//`
    for DIR in $SFLIB96DIRS ; do
        if ( [ -f $DIR/$SF ] ) ; then  # in $SFDIR, or user supplies full path
            SFLIST=`echo $SFLIST $DIR/$SF`
            CONTIN="NO"  
        elif  ( [  -f $DIR/$SF.wav ] ) ; then  # in $SFDIR, or user supplies full path
            SFLIST=`echo $SFLIST $DIR/$SF.wav`
            CONTIN="NO" 
        fi
    done
  fi
#####################################
  if ( [ "$CONTIN" == "YES" ] && [  -d $SFLIB ] ) ; then  # search 44.1k sflib dirs
   # elif ( [  -d $SFLIB ] ) ; then  # if still not found search 44.1 k sflib dirs
   SFLIB44DIRS=`ls -R $SFLIB | grep sflib | sed -e 's/://g' | sed -e 's/\/snd//g' | grep -v /sflib/anal`
     for DIR in $SFLIB44DIRS ; do
          if ( [ -f $DIR/$SF ] ) ; then  
                SFLIST=`echo $SFLIST $DIR/$SF`
                CONTIN="NO" 
          elif  ( [  -f $DIR/$SF.wav ] ) ; then
                 SFLIST=`echo  $SFLIST $DIR/$SF.wav`
                 CONTIN="NO" 
          fi
   done
fi
  if [ "$CONTIN" == "YES" ] ; then  # search failed
     echo "ERROR: No soundfile named >> $SF << found in in $SFDIR"
     echo "or any of the 96k or 441.k sflib directories. Quitting."
     exit 1 
     echo "or any of the 96k or 44.1k sflib directories. Quitting."
     exit 1 
    fi
  done   ## end of search nest level 2 ###
fi   ## end of search nest level 1 ###
   # echo SFLIST is $SFLIST
#####################################
# sort soundfiles
if [ $SORT == "YES" ] ; then
    TMPFILE=/tmp/tmpmksffuncs$$
    TMPFILE2=/tmp/tmpmksffuncs2$$
    rm -f $TMPFILE $TMPFILE2
    # NO WILL NOT WORK: echo $SFLIST > $TMPFILE
   for i in `echo $SFLIST` ; do
     echo $i >> $TMPFILE
   done
    sortsflist $TMPFILE > $TMPFILE2
    SFLIST=`cat $TMPFILE2 | grep -v COMMENT`
    rm -f $TMPFILE $TMPFILE2
fi
#####################################
# Get needed header information and then make each function
for SF in `echo $SFLIST` ; do
   SAMPLES=`sfsamples $SF | awk '{print $1}'`
   CHANS=`sfchans $SF | awk '{print $1}'`
   DUR=`sfdur $SF | awk '{print $1}'`
   BITS=`sfbits $SF | awk '{print $1}'`
  # echo SAMPLES is $SAMPLES CHANS is $CHANS dur is $DUR and BITS is $BITS
###################################
# (4) Now determine the size of the Csound function table:
TSIZE=16384
while [ "$SAMPLES" -ge $TSIZE ] ; do
  TSIZE=$[$TSIZE * 2]
done
   # ??? @ TSIZE = ( $TSIZE * $CHANS )

if [ "${TSIZE}" -gt 16777216 ] ;  then
    echo "ERROR: Soundfile $SOURCESF is too long. Maximum allowable table size is"
    echo "16 MB (16,777,216). $SF has a duration of $DUR, $SAMPLES samples, $CHANS channels"
    echo "and would require a table size of $TSIZE. Quitting."
    exit 1
fi
### Maximum dur. of sf @ 44.1k is 380.43 seconds, at 96k 174.76 seconds
# Finally, make the functions:
TAG=""
if [ $CHANS == "2" ] ; then
   TAG=`echo $TAG STEREO`
elif [ $CHANS -ge "3" ] ; then
   TAG=`echo $TAG $CHANS ch.`
fi
 echo '* f'$FUNCNUM' 0 '$TSIZE' -1 "'$SF'" 0 0 0 ; < '$DUR sec $TAG
   FUNCNUM=$(($FUNCNUM+1))
done

