This sort of FAQ-howto will explain how to make a 'general' or 'phases' 
plugin for MP3do.

1. What means 'general' and 'phases'?
   A 'general' plugin is a piece of code that MP3do call during phase
   1 and 3. It will give to MP3do capability to read and convert formats
   files.
   A 'phases' plugin is a piece of code that will be executed at the end
   or at the beginning of a phase. (More about phases in README)

2. How can I write a general plugin?
   Firstly to write this kind of plugin you must to know:
   1. how to check for file type (i.e. how to understand that a .ogg file
      is a OGG/Vorbis file without beleave to extension only);
   2. How to extract time duration of audio file without play it;
   3. How to extract kbit/s and rate of audio file without play it.
   All these actions must be performed using shell commands.

   If you don't know one of these three things you can't write a plugin.

   Secondly you must to know that all plugins must be 'configured' and 
   then executed.
   Configuration phase is done in ConfigMP3do. Each time you want to add
   a plugin you must re-run ConfigMP3do.
   So all plugins must be split in two files: one to configure and another
   to be used by MP3do.
   I will call first "config general plugin" and second "general plugin".
   All configure general plugin will be saved in:
   $MP3doBASEDIR/plugins/config/general
   and general plugins in:
   $MP3doBASEDIR/plugins/general/

   A general plugin must have a valid bash function name. (i.e ogg123,
   mpg321, sox, and NOT ogg-123)

2.1 Writing a config general plugin

   A config general plugin must have same name of general plugin and must
   contain following function:
  
   Name            : cat_variables_<plugin_name> 
   Description     : Must output to stdout variables names and vaules
                     used by this plugin. There are no limit to what you
                     can output. This will became a piece of mp3do.rc file
   Return values   : None

   At the end of this file must be inserted code to configure plugin.
   All config plugins ereditate some functions and variables from 
   ConfigMP3do, so following functions can be used:
  
   Name            : missing
   Description     : Display a message (see code, it's very easy to
                     understand...)
   Return values   : None
                     
   Name            : QueryVersion
   Description     : Search for a string in a list of strings. If can't
                     find display an error message (see code, it's very
                     easy to understand...)
   Return values   : On successful exit fills FOUNDVER variable containing
                     exact string matched
                     
   Name            : QuerySuid
   Description     : Check for suid bit on a file 
   Return values   : On successful exit fills PRIVUSER variable containing
                     root or a user selected by user (contained in
                     /etc/passwd)
   
   Name            : quest
   Description     : Display a [Y/N] message
   Return values   : Return valued of #4 or #5 parameter passed 
                     (value associated to Y or N)
   
   Name            : find_prg
   Description     : Find a file in predefined dir
   Return values   : On successful exit fills FOUND_PRG variable
                     containing complete path of founded program
   
   Name            : begin_check
   Description     : Display a "echo -n" message
   Return values   : None
   
   Name            : end_check
   Description     : Display "Done"
   Return values   : None

   Firstly you must search for binary program that you want to use. 
   If (and only if) find_prg return a non zero value in FOUND_PRG 
   you must fill following variables:
   Name            : EXTENSIONS
   Description     : must be filled with handled file extensions in input
   
   Name            : SUPPORTED_FORMATS
   Description     : must be filled adding supported formats in output
                     Use something like:
                     SUPPORTED_FORMATS="$SUPPORTED_FORMATS <fmt> <...>"
                     
   Name            : AUDIO_PLUGINS
   Description     : must be filled adding plugin's name. Use something
                     like:
                     AUDIO_PLUGINS="$AUDIO_PLUGINS plugin-name"

   If plugin will handle some parameters on command line you must update
   PLUGINS_WITH_PARAMETERS variable with something like:
   PLUGINS_WITH_PARAMETERS="$PLUGINS_WITH_PARAMETERS plugin-name"

   There is some naming convention for variables:
   - All binary programs must be stored in variables named
     <plugin-name>_DECODER (i.e. ogg_DECODER, cdparanoia_DECODER, ...)
   - All options to a program to output in some format file must be stored
     in variables named:
     <identifier>_TO_<lowercased-output-format-file>
     (i.e. OGG_TO_wav, cdparanoia_TO_aiff, cdda2wav_to_wav, ...)
   - Default output format must be stored in a variable named:
     <identifier>_TOFMT.
   - Supported output formats must be stored in an array called
     OUTPUT_FORMATS_<plugin-name> (i.e. OUTPUT_FORMATS_ogg123,
     OUTPUT_FORMATS_mpg321, ...)


2.2 Writing a general plugin

   This little piece of code will add to MP3do capability to handle a new
   audio format file.
   The first function you must create is:
   
   Name            : plugin_present_<plugin-name>
   Description     : Little function to prevent multiple inclusion by
                     MP3do
   Return values   : 0 (in facts the only row of this function is 
                     return 0)

   Thanks to this little function you can handle dependencies between
   plugins. So if your new plugin must use another plugin you can check if
   it is present on system calling plugin_present_<interested-plugin> 
   function and expecting for a 0 return value.

   Then you must write this following and FUNDAMENTAL function:
   Name            : parse_param_t_<plugin-name>
   Description     : This function is used in MP3do code during command
                     line parsing and will be called if -t option is used.
                     You can use variables saved in configuration file
                     during configuration phase (see section 2.1) to
                     handle output format files. If output format file
                     specified with -t option is not supported by this
                     plugin you must print a warning message and output to
                     a default format file. WAV is the standard output
                     format used by many programs.
   Input values	   : $1 is the file type to be checked
   Return values   : On success T_SUPP variable must me appended with
                     format used: T_SUPP="$T_SUPP $1"
   
   Optionally can be coded following function too. It will be called after
   command line parsing.
   Plugin's sanity checks are performed in a cicle calling all plugins
   defined in PLUGINS_WITH_PARAMETERS variable.

   Name            : sanity_check_<plugin-name>
   Description     : Perform sanity check after command line parsing. This
                     function can be used to handle dependencies among
                     parameters, or to perform some run time variable 
                     initialization useful for program to be used.
   Input values    : All variabled setup during command line parsing.
   Return values   : On error must fill STRERROR string containing error
                     message and USCITA containing an exit code.
   
   For each format file must be created following functions:

   Name            : extract_time_<format-file>
   Description     : This function is used to extract time duration of
                     audio file of <format-file> file types.
   Input values    : $1 	filename
                     SONGDATA   Filename of a temporary data file
   Return values   : TS must contain time duration of the song in format
                     hh:mm:ss
                     RET_WCL must contain a non-zero value if file
                     contains some error.
   
   Name            : extract_check_info_<format-file>
   Description     : Must return some information about this file
   Input values    : i 		filename
                     TIPOFILE   file -Lb "$i"
                     SONGDATA   Filename of temporary data file
   Return values   : RET_RATE              Frequency rate of file
                     RET_KBITSTEREO        Kbit/s and if stereo and mono
                                           (not required)
   
   Name            : check_file_type_<plugin_name>
   Description     : Must check for all supported format files (by this
                     plugin) and can use variables wrote in config file 
                     during configuration phase.
   Input values    : See extract_check_info_<format-file>
   Return values   : ISTYPE        extension of format file 
                     FILETYPE      Description string of format file

   All following functions can use these variables:
   Name            : i
   Description     : Filename given on command line

   Name            : nc
   Description     : Decoding phase is performed using a FOR cicle. nc is
                     the counter of this cicle.
   
   Name            : tempname 
   Description     : =filename but with all lowercases
   
   Name            : nome
   Description     : filename without extension
   
   Name            : numbered_name
   Description     : =nome + two digit number on front
   
   Name            : RATE[$nc]
   Description     : Rate in Hz of actual file
   
   Name            : TYPE[$nc]
   Description     : Type of actual file

   Functions:
   
   Name            : setup_vars_<plugin_name>
   Description     : Set up variables used in phase 3: decoding of MP3do.
   Return values   : FLYFMT        Format of data send to stdout. If data
                                   are in raw format must contain RAW.
                     fmt_OUT_TYPE  (Where fmt is format-file). File type 
                                   to use to force sox format conversion.
                                   
   Name            : to_stdout_buffered_<format-file>
   Description     : To send data to standard output using program's 
                     buffer
   Input values    : $1 is the filename
   Return values   : None
   
   Name            : to_stdout_no_buffer_<format-file>
   Description     : To send data to standard output without
                     program's buffer
   Return values   : None
   
   Name            : decode_<format-file>
   Description     : To output data in WAV or format specified by -t
                     option
   Return values   : None


2.3 Example of writing a general plugin
   Now it's the time for an example to write a general plugin.

   I will look if I can use ogg123 to makes a plugin to handle Ogg/Vorbis
   files.

   I will follow each single point described above.
   
   1. how to check for file type:
   Output of file(1) command can't be used, it's too much 'fuzzy':
   ~$ file song.ogg
   song.ogg: data

   So I will use strings with a piped head:
   ~$ strings "song.ogg"|head -c 3
   Ogg

   :-)
   2. How can extract time duration of ogg file without play it
   I can use -k option to skip all file's frames and use output:
   
   ~$ ogg123 -v -d null -k 9999999 song.ogg
   Playing from file sviluppo/MP3do/song.ogg.
   Device:   Null output
   Author:   Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
   Comments: This plugin does nothing


   Bitstream is 2 channel, 44100Hz
   Encoded by: Xiphophorus libVorbis I 20010225

   Time: 00:08.88 [00:00.00] of 00:08.88, Bitrate: 1781.1   
   Done.

   And I will know time duration of this song without play it.
   
   3. How can extract kbit/s and rate of audio file without play it
   From prevoius output I can use row beginning by 'Bitstream' to take
   rate infos. kbit/s are variable (ogg format uses VBR).

   OK. Now I can write a ogg123 plugin to handle Ogg/Vorbis files!

   I will write two files called ogg123. The first will be saved in
   $PLUGINDIR/config/general (the config general plugin) and second (the
   general plugin) in $PLUGINDIR/general.

   Now I will write "config general plugin".
   Function cat_variables_ogg123 will output to stdout a piece of future
   mp3do.rc file.
   Here is the code:
   -----------------------------------------------------------------
 
   # Config plugin for ogg123
   #
 
   cat_variables_ogg123 () {
       cat <<EOF # To send to stdout all text between following row and
                 # first beginning by EOF
   # Complete path for ogg decoder
   ogg123_DECODER="$ogg123_DECODER"
 
   # Params to only show a time line
   OGG_EXTRACT_TIME="$OGG_EXTRACT_TIME"
 
   # Parameters to output to stdout with buffered mode
   OGG_BUFFERED_DECODE="$OGG_BUFFERED_DECODE"
 
   # Parameters to output to stdout without buffer
   OGG_DECODE_TO_STDOUT="$OGG_DECODE_TO_STDOUT"
 
   # Parameters to simply decode
   OGG_NORMALDECODE="$OGG_NORMALDECODE"
 
   # Parameters to output to file in wav format
   OGG_TO_wav="$OGG_TO_wav"
 
   # Array of supported output formats files
   OUTPUT_FORMATS_ogg123=( ${OUTPUT_FORMATS_ogg123[@]} )
 
   # default output file format
   OGG_TOFMT="$OGG_TOFMT"
 
   # Default conversion file extension
   OGG_MPGCMD="$OGG_MPGCMD"
 
 
   EOF
   }


   ############
   # MAIN PART: Here configure
   ############

   # This is a redundant check to prevend multiple inclusions...
   if [ $(expr "$SUPPORTED_FORMATS" : ".*ogg.*") -ne \
        ${#SUPPORTED_FORMATS} ]; then

     # Display message "Checking for ogg123..."
     begin_check ogg123

     # Search for ogg123 in predefined paths
     find_prg ogg123

     # find_prg function fill FOUND_PRG variable if ogg123 has been found.
     # Otherwise this variable contains a null value
     ogg123_DECODER=$FOUND_PRG

     # If ogg123_DECODER is void...
     if [ -z $ogg123_DECODER ]; then
       # Display a message like: this program is missing, you must
       # download it from http://...
       missing ogg123 "http://www.xiph.org/ogg/vorbis"
     else
       # Check for version of program if version is not "1.0beta4" will be
       # displayed a warning message. First parameter passed to this function
       # must be a row containing version string to compare with last
       # parameter.
       QueryVersion $($ogg123_DECODER -V 2>&1|cut -d' ' -f4) ogg123 "1.0beta4"

       echo
       # REQUIRED variable to makes MP3do understand it can handle
       # ogg files with this plugin. This is used to handle multiple plugins
       # that handle same extensions too.
       EXTENSIONS="ogg"

       # These variables will be used in to_stdout_buffered_ogg,
       # to_stdout_no_buffer_ogg, and decode_ogg functions
       OGG_EXTRACT_TIME=" -v -d null -k 9999999 "
       OGG_BUFFERED_DECODE=" -q -v -b 4 -d oss -o dsp:/dev/stdout" 
       OGG_DECODE_TO_STDOUT="-q -v -d oss -o dsp:/dev/stdout"
       OGG_NORMALDECODE=" -q -v "

       # Variables following naming conventions:
    
       # Array containing supported output formats
       OUTPUT_FORMATS_ogg123=(wav)

       # Options to output in wav format
       OGG_TO_wav="-d wav -o file:"

       # Default output options
       OGG_TOFMT=$OGG_TO_wav

       # Default extension of decoded files
       OGG_MPGCMD="wav"
    
       # Append plugin name to AUDIO_PLUGINS variable
       AUDIO_PLUGINS="$AUDIO_PLUGINS ogg123"

       # Append extensions handled to SUPPORTED_FORMATS
       SUPPORTED_FORMATS="$SUPPORTED_FORMATS $EXTENSIONS"

       # "cosmetic" output
       lechoc CYAN $"Summary of command used by $ogg123_DECODER:"
       lechoc YELLOW " -> $ogg123_DECODER $OGG_EXTRACT_TIME song.ogg"
       lechoc CYAN $"Buffered decode:"
       lechoc YELLOW " -> $ogg123_DECODER $OGG_BUFFERED_DECODE song.ogg | ..."
       lechoc CYAN $"Decoding to stdout:"
       lechoc YELLOW " -> $ogg123_DECODER $OGG_DECODE_TO_STDOUT song.ogg | ..."
       lechoc CYAN $"Normal decoding to wav (default):"
       lechoc YELLOW " -> $ogg123_DECODER $OGG_NORMALDECODE ${OGG_TO_wav}filename.wav song.ogg"

       # Display "Done"
       end_check
     fi
   fi
   # End of config plugin

   -----------------------------------------------------------------

   Now I must write "general plugin" using variables defined in "config
   general plugin".
   I will call it ogg123 and will save it in $PLUGINDIR/general.

   Here is the code:
   -----------------------------------------------------------------
   # Functions for ogg123:
   # FORMAT FILE: ogg

   # DEPENDENCIES:
   # I use plugin_present_sox function to check if sox module is present
   # Variable $? will not be 0 if plugin_present_sox does'nt exist, so I
   # load it if needed.
   plugin_present_sox 2>/dev/null
   if [ $? -ne 0 ]; then
     #This plugin require sox plugin!
     . $PLUGINDIR/general/sox
   fi
       
   # Now I define this function to handle dependencies (and say to MP3do
   # that this plugin has been loaded)
   plugin_present_ogg123 () {
     return 0
   }

   # Fundamental function used in parsing -t MP3do's parameters
   parse_param_t_ogg123 () {
     # Recall variable loaded from configuration file.
     # This syntax is used to call a variable called OGG_TO_<fmt> where
     # <fmt> is first parameter passed to this function and store it in
     # OGG_TOFMT. If OGG_TO_<fmt> is not defined, OGG_FMT will have a null
     # value.
     eval OGG_TOFMT=\$OGG_TO_${1}

     # Some "cosmetic" warning. 
     # If variable OGG_TO_<fmt> is not defined, ogg123 can't output to this
     # format. But we can use sox to convert from predefined format to $1
 
     if [ -z "$OGG_TOFMT" ]; then
       lechoc GREEN -n "Type %s is not supported by ogg123."
       lechoc GREEN "Using sox's auto-conversion." "$1"
       # BIG TRICK
       # Remember: if OGG_TOFMT contain a null value, ogg123 doesn't handle
       # this file type. So we can use ogg_OUT_TYPE to force sox's auto
       # conversion feature. ogg123 will output data to stdout and sox will 
       # take this output (in FLYFMT format) and will convert it to
       # ogg_OUT_TYPE saving OUTPUT_FILE file.
       ogg_OUT_TYPE="$1"
     fi

     # Fill some "internal to the plugin" variable
     OGG_MPGCMD="$1"

     # This variable must be filled like explained in 2.2 section
     T_SUPP="$T_SUPP $1"

     # return to caller function
     return 0
   }

   # This function must be used to extract time from a ogg file without
   # play all file. I will use trick explained in point 2 of this section
   extract_time_ogg () {
     # SONGDATA is a temporary file defined in MP3do. I will redirect all
     # output from stdout and stderr to SONGDATA
     $ogg123_DECODER -v -d null -k 9999999 "$1" >$SONGDATA 2>&1
 
     # I analyze SONGDATA to extract Time row and take time
     TS=$(cat $SONGDATA|$GREP Time|cut -d' ' -f2)
 
     # I don't know how to understand if a ogg file has some error, so i
     # return always 0...
     RET_WCL=0
   }
 
   # Extract other infos from ogg123 output
   extract_check_info_ogg() {
     # Like explained in point 3 of this section I will use Bitstream line
     # I use "local" syntax to restrict scope of this variable to this
     # function only.
     local DATI=$($ogg123_DECODER -v -d null -k 9999999 "$i" 2>&1|\
                  $GREP "Bitstream")
 
     # Rate in Hz...
     RET_RATE=$(echo $DATI|tr -d ' '|cut -d',' -f2|cut -d'H' -f1)
 
     # "Cosmetical" info...
     RET_KBITSTEREO="Variable"
   }  
 
   # Function called for each file given on MP3do's commandline
   check_file_type_ogg123 () {
   
     # Like explained in point 1 of this section I will use some 'shell'
     # command to know what kind of file MP3do is analyzing in phase 1
     if [ "$(strings "$i"|head -c 3)" = "Ogg" ]; then
       # This variable MUST be filled with type of file 
       ISTYPE="ogg"
 
       # "cosmetical" variable
       FILETYPE="Ogg/Vorbis"
     fi
 
     # If above condition is not verified ISTYPE is not filled, so MP3do
     # will understand that "$i" is not a Ogg/Vorbis file
   }
 
   # This function is called at the beginning of cicle in phase 3: decoding
   # if actual file is a Ogg/Vorbis file
   setup_vars_ogg () {
     # Format of file used when output to stdout
     FLYFMT="raw"
 
     # Filename of decoded file
     OUTPUT_FILE="$nomef.$OGG_MPGCMD"
 
   }
 
   # This function is called if rate of file is less than 44100 hz. It
   # takes input from file passed likeargument ($1) and output data to
   # stdout. Output of this function willbe redirected to
   # sox_convert_rate_[file|piped].
   to_stdout_buffered_ogg () {
     $ogg123_DECODER $OGG_BUFFERED_DECODE "$1"
   }
 
   # This function is called if --on-the-fly option is used and output must
   # be piped directly to cdrecord.
   to_stdout_no_buffer_ogg () {
     $ogg123_DECODER $OGG_DECODE_TO_STDOUT "$1"
   }
 
   # This function is called if --on-the-fly option is not used, output
   # file type are handled by ogg123 and rate is 44100Hz 
   decode_ogg () {
     $ogg123_DECODER $OGG_NORMALDECODE $OGG_TOFMT"$nomef.$MPGCMD" "$i"
   }

   # End of general plugin.

   -----------------------------------------------------------------

   Now I must only re-run ConfigMp3do to add this plugin to MP3do.
   If something goes wrong I can use sh -x to debug script.

3. How can I write a 'phases' plugin?
   Writing a 'phases' plugin is very similar to general plugin.
   This kind of plugin must be also configured, so all configure phases
   plugins must be saved in:
   $MP3doBASEDIR/plugins/config/phase[1234]
   and phases plugin must be saved in:
   $MP3doBASEDIR/plugins/phase[1234]

3.1 Writing a 'config phases' plugin
   A config phases plugin must have same name of phases plugin, and must 
   contain following functions:
   Name            : configure_<plugin-name>
   Description     : Fill variables to be wrote in mp3do.rc file and used 
                     by ConfigMP3do
   Return values   : None

   Name            : cat_variables_<plugin-name>
   Description     : Must output to stdout variables names and vaules
                     used by this plugin. There are no limit to what you
                     can output. This will became a piece of mp3do.rc file
   Return values   : None

   In this file MUST be defined following variables:
   Name            : WHERE
   Description     : Location of plugin (begin or end of phase)

   Name            : PARAMETERS
   Description     : List of all command line parameters handled by this
                     plugin (separated by a pipe '|')

   Name            : DESCRIPTION
   Description     : Short description of what this plugin does

3.2 Writing a 'phases' plugin

                               

3.3 Example of writing a phases plugin
  
   If you have'nt understand something you can send me an e-mail to:
   stefko5@inwind.it 


