/*------------------------------------------------------------------------------

    File    :	user_interface.c

    Author  :	Stéphane TAVENARD

    $VER:   user_interface.c  1.1  (27/07/1995)

    (C) Copyright 1995-1995 Stéphane TAVENARD
	All Rights Reserved

    #Rev|   Date   |			  Comment
    ----|----------|--------------------------------------------------------
    0	|05/06/1995| Initial revision					  ST
    1	|23/06/1995| First release (aminet)                               ST
    2	|27/07/1995| Added mixing frequency				  ST

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

    User (Text) interface for MPEG audio decoding

------------------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "mpega_decode_asm.h"
#include "mpega_decode.h"
#include "user_interface.h"

#define NULL_CHAR '\0'

static char *Version = "$VER:MPEGA (Fast MPEG audio decoder) V1.1 (C)Stéphane TAVENARD";
static char *mode_names[4] = { "stereo", "j-stereo", "dual-ch", "single-ch" };
static char *layer_names[3] = { "I", "II", "III" };
static char *programName;
static int   display_header_only = 0;
static clock_t time_to_decode;

static void write_header_info( frame_params *fr_ps, FILE *s )
{
   layer *info = fr_ps->header;

   fprintf( s, "HDR:  s=FFF, id=%X, l=%X, ep=%X, br=%X, sf=%X, pd=%X, ",
	    info->version, info->lay, !info->error_protection,
	    info->bitrate_index, info->sampling_frequency, info->padding );
   fprintf( s, "pr=%X, m=%X, js=%X, c=%X, o=%X, e=%X\n",
	    info->extension, info->mode, info->mode_ext,
	    info->copyright, info->original, info->emphasis );
   fprintf( s, "layer=%s, tot bitrate=%d, sfrq=%d, mode=%s, ",
	    layer_names[ info->lay-1 ], fr_ps->bitstream_rate,
	    fr_ps->bitstream_freq, mode_names[ info->mode ] );
   fprintf( s, "sblim=%d, jsbd=%d, ch=%d\n",
	    fr_ps->sblimit, fr_ps->jsbound, fr_ps->stereo );
   fflush( s );
}

static void usage( void )
/*-----------------------
   Display MPEG Audio decoder usage
*/
{
   FILE *s;

   s = stderr;
   fprintf( s, "%s\n", &Version[ 5 ] );
   fprintf( s, "Adapted from 'musicout' of MPEG/audio software simulation group\n" );
   fprintf( s, "Fast integer version by Stéphane TAVENARD ["__DATE__"]\n" );
   fprintf( s, "MPEG decoding has been optimzed (68020+ assembler rewritten) for layers I & II\n" );
   fprintf( s, "Can play real time now (if you have enough CPU power) !\n" );
   fprintf( s, "email: tavenard@xiii.univ-angers.fr\n\n" );
   fprintf( s, "usage: %s -> queries for all arguments, or\n", programName);
   fprintf( s, "       %s [-A][-d div][-q qual][-e sh][-h][-m][-p][-f 0|1][-x freq] inputBS [outPCM]\n", programName);
   fprintf( s, "where\n");
   fprintf( s, " -A       write an AIFF output PCM sound file\n");
   fprintf( s, " -d div   output frequency divide (1, 2 or 4)\n");
   fprintf( s, " -q qual  output quality (0=worst 2=best)\n");
   fprintf( s, " -e sh    8 bits output with sh bits right shifted (8 usually)\n");
   fprintf( s, " -h       display header only\n" );
   fprintf( s, " -m       mono output (=left voice)\n" );
   fprintf( s, " -p       play audio\n" );
   fprintf( s, " -f 0|1   audio filter off/on\n" );
   fprintf( s, " -x freq  mixing frequency\n" );
   fprintf( s, " inputBS  input bit stream of encoded audio\n");
   fprintf( s, " outPCM   output PCM sound file (dflt inName+%s)\n", DFLT_OPEXT );
   fprintf( s, "\nEnjoy fast MPEG :-) \n" );
}

void USIN_get_parameters( int argc, char **argv, frame_params *fr_ps )
/*--------------------------------------------------------------------
   Get MPEG Audio decode parameters
*/
{
   static char encoded_file_name[ MAX_NAME_SIZE ];
   static char decoded_file_name[ MAX_NAME_SIZE ];
   char t[ 50 ];
   int	quality_set = 0;
   int	audio_filter_set = 0;
   int	value;

   programName = argv[ 0 ];
   fr_ps->mixing_frequency = 0;
   if( argc == 1 ) {        /* no command line args -> interact */
      do {
	 usage();
	 printf( "Enter encoded file name <required>: " );
	 gets( encoded_file_name );
	 if( encoded_file_name[ 0 ] == NULL_CHAR )
	    printf( "Encoded file name is required. \n" );
      } while( encoded_file_name[ 0 ] == NULL_CHAR );
      printf( ">>> Encoded file name is: %s \n", encoded_file_name );

      printf( "Do you want audio play ? (y/<n>) : " );
      gets( t );
      if( (*t == 'y') || (*t == 'Y') ) {
	 fr_ps->play = 1;
      }
      if( !fr_ps->play ) {
	 printf( "Enter MPEG decoded file name <%s%s>: ", encoded_file_name,
		  DFLT_OPEXT );
	 gets( decoded_file_name );

	 if( decoded_file_name[ 0 ] == NULL_CHAR ) {
	    strcat( strcpy( decoded_file_name, encoded_file_name ), DFLT_OPEXT );
	 }
	 printf( ">>> MPEG decoded file name is: %s \n", decoded_file_name );
      }

      printf( "Frequency division output (<1>/2/4) : " );
      gets( t );
      fr_ps->freq_div = atoi( t );
      if( (fr_ps->freq_div != 1) && (fr_ps->freq_div != 2) &&
	  (fr_ps->freq_div != 4) ) fr_ps->freq_div = 1;

      printf( "Ouput quality (0/1/<2>) : " );
      gets( t );
      if( !*t ) fr_ps->quality = 2;
      else fr_ps->quality = atoi( t );
      if( fr_ps->quality < 0 ) fr_ps->quality = 0;
      else if( fr_ps->quality > 2 ) fr_ps->quality = 2;

      printf( "Do you want mono output ? (y/<n>) : ");
      gets( t );
      if( (*t == 'y') || (*t == 'Y') ) fr_ps->mono_forced = TRUE;

      printf( "Do you want 8 bits output ? (y/<n>) : ");
      gets( t );
      if( (*t == 'y') || (*t == 'Y') ) {
	 fr_ps->output_8bits = 8;
      }
      if( !fr_ps->play ) {
	 printf( "Do you wish to write an AIFF compatible sound file ? (y/<n>) : " );
	 gets( t );
	 if( (*t == 'y') || (*t == 'Y') ) {
	    fr_ps->out_file_type = MPEGA_FILETYPE_AIFF;
	    printf( ">>> An AIFF compatible sound file will be written\n" );
	 }
	 else {
	    fr_ps->out_file_type = MPEGA_FILETYPE_RAW;
	    printf( ">>> A non-headered PCM sound file will be written\n" );
	 }
      }
      printf( "Do you wish to exit (last chance before decoding) ? (y/<n>) : " );
      gets( t );
      if( (*t == 'y') || (*t == 'Y') ) exit( 0 );
   }
   else {	 /* interpret CL Args */
      int i=0, err=0;

      encoded_file_name[ 0 ] = '\0';
      decoded_file_name[ 0 ] = '\0';
      while( (++i<argc) && (err == 0) ) {
	 char c, *token, *arg, *nextArg;
	 int  argUsed;

	 token = argv[ i ];
	 if( *token++ == '-' ) {
	    if( (i+1) < argc ) nextArg = argv[ i+1 ];
	    else	       nextArg = "";
	    argUsed = 0;
	    while( c = *token++ ) {
	       if( *token ) arg = token;
	       else	    arg = nextArg;
	       switch( c ) {
		  case 'A':  fr_ps->out_file_type = MPEGA_FILETYPE_AIFF;
			      break;
		  case 'd':  value = atoi( arg ); argUsed = 1;
			      switch( value ) {
				 case 1:
				    if( !quality_set ) fr_ps->quality = 2;
				    if( !audio_filter_set ) fr_ps->audio_filter = 0;
				    fr_ps->freq_div = value;
				    break;
				 case 2:
				    if( !quality_set ) fr_ps->quality = 1;
				    if( !audio_filter_set ) fr_ps->audio_filter = 0;
				    fr_ps->freq_div = value;
				    break;
				 case 4:
				    if( !quality_set ) fr_ps->quality = 0;
				    if( !audio_filter_set ) fr_ps->audio_filter = 1;
				    fr_ps->freq_div = value;
				    break;
				 default:
				    fprintf( stderr, "%s: invalid option value -%c %ld\n",
					     programName, c, value );
				    err = 1;
				 break;
			      }
			      break;
		   case 'q':  value = atoi( arg ); argUsed = 1;
			      switch( value ) {
				 case 0:
				 case 1:
				 case 2:
				    fr_ps->quality = value;
				    quality_set = TRUE;
				    break;
				 default:
				    fprintf( stderr, "%s: invalid option value -%c %ld\n",
					     programName, c, value );
				    err = 1;
				 break;
			      }
			      break;
		   case 'f':  value = atoi( arg ); argUsed = 1;
			      switch( value ) {
				 case 0:
				 case 1:
				    fr_ps->audio_filter = value;
				    audio_filter_set = TRUE;
				    break;
				 default:
				    fprintf( stderr, "%s: invalid option value -%c %ld\n",
					     programName, c, value );
				    err = 1;
				 break;
			      }
			      break;
		   case 'e':  fr_ps->output_8bits = atoi( arg ); argUsed = 1;
			      if( fr_ps->output_8bits < 0 ) fr_ps->output_8bits = 0;
			      else if( fr_ps->output_8bits > 8 ) fr_ps->output_8bits = 8;
			      break;
		   case 'm':  fr_ps->mono_forced = TRUE;
			      break;
		   case 'p':  fr_ps->play = TRUE;
			      break;
		   case 'h':  display_header_only = TRUE;
			      break;
		   case 'x':  fr_ps->mixing_frequency = atoi( arg ); argUsed = 1;
			      break;
		   default:   fprintf( stderr,"%s: unrecognized option %c\n",
				       programName, c );
		      err = 1; break;
		}
		if( argUsed ) {
		   if( arg == token ) token = ""; /* no more from token */
		   else 	      ++i; /* skip arg we used */
		   arg = ""; argUsed = 0;
		}
	     }
	  }
	  else {
	     if( encoded_file_name[ 0 ] == '\0' )
		strcpy( encoded_file_name, argv[ i ] );
	     else
		if( decoded_file_name[ 0 ] == '\0' )
		   strcpy( decoded_file_name, argv[ i ] );
		else {
		   fprintf( stderr,
			    "%s: excess arg %s\n", programName, argv[i] );
		   err = 1;
		}
	  }
       }

       if( err || (encoded_file_name[ 0 ] == '\0') ) {
	  usage();
	  exit( 0 );
       }
       if( decoded_file_name[ 0 ] == '\0' ) {
	  strcpy( decoded_file_name, encoded_file_name );
	  strcat( decoded_file_name, DFLT_OPEXT );
       }

    }

   /* report results of dialog / command line */
   if( !display_header_only ) {
      if( !fr_ps->play ) {
	 printf( "Input file = '%s'  output file = '%s'\n",
		encoded_file_name, decoded_file_name );
      }
      else {
	 printf( "Input file = '%s'  output -> audio\n", encoded_file_name );
      }
      if( fr_ps->out_file_type == MPEGA_FILETYPE_AIFF ) {
	 printf("Output file written in AIFF format\n");
      }
      if( fr_ps->freq_div != 1 ) {
	 printf( "Output frequency/%ld.\n", fr_ps->freq_div );
      }
      if( fr_ps->mono_forced ) {
	 printf( "Mono ouput forced.\n" );
      }
      if( fr_ps->output_8bits ) {
	 printf( "8 bits output selected.\n" );
      }
      printf( "Output quality %ld\n", fr_ps->quality );
    }

    fr_ps->bitstream_name = encoded_file_name;
    if( display_header_only ) {
      fr_ps->out_file_name = NULL;
    }
    else {
      fr_ps->out_file_name = decoded_file_name;
    }
}

void USIN_display_info( frame_params *fr_ps )
/*-----------------------------------------
   display current frame info
   -> exit if display_header_only is set
*/
{
   write_header_info( fr_ps, stderr );
   if( display_header_only ) exit( 0 );
   time_to_decode = clock();
}

void USIN_display_frame_number( frame_params *fr_ps )
/*---------------------------------------------------
   display current frame number
   -> exit if display_header_only is set
*/
{
   fprintf( stderr, "{%4lu}\r", fr_ps->frame_count ); fflush( stderr );
}

void USIN_epilog( frame_params *fr_ps )
/*-------------------------------------
   Write epilog info
*/
{
   time_to_decode = clock() - time_to_decode;

   if( fr_ps->out_sample_freq ) {
      printf( "Stream time=%.2lf sec\n",
	      (double)(fr_ps->out_sample_length)
	      / (double)(fr_ps->out_sample_freq) );
   }

   printf( "Total time used to decode the stream was %.2lf secs.\n",
	   (double)time_to_decode / CLK_TCK);
}
