/**********************************************************************
 * ISO MPEG Audio Subgroup Software Simulation Group (1996)
 * ISO 13818-3 MPEG-2 Audio Decoder - Lower Sampling Frequency Extension
 *
 * $Id: musicout.c,v 1.2 1996/03/28 03:13:37 rowlands Exp $
 *
 * $Log: musicout.c,v $
 * Revision 1.2  1996/03/28 03:13:37  rowlands
 * Merged layers 1-2 and layer 3 revisions
 *
 * Revision 1.1  1996/02/14 03:45:52  rowlands
 * Initial revision
 *
 * Received from FhG
 **********************************************************************/
/**********************************************************************
 *   date   programmers                comment                        *
 * 2/25/91  Douglas Wong        start of version 1.0 records          *
 * 3/06/91  Douglas Wong        rename setup.h to dedef.h             *
 *                              removed extraneous variables          *
 *                              removed window_samples (now part of   *
 *                              filter_samples)                       *
 * 3/07/91  Davis Pan           changed output file to "codmusic"     *
 * 5/10/91  Vish (PRISM)        Ported to Macintosh and Unix.         *
 *                              Incorporated new "out_fifo()" which   *
 *                              writes out last incomplete buffer.    *
 *                              Incorporated all AIFF routines which  *
 *                              are also compatible with SUN.         *
 *                              Incorporated user interface for       *
 *                              specifying sound file names.          *
 *                              Also incorporated user interface for  *
 *                              writing AIFF compatible sound files.  *
 * 27jun91  dpwe (Aware)        Added musicout and &sample_frames as  *
 *                              args to out_fifo (were glob refs).    *
 *                              Used new 'frame_params' struct.       *
 *                              Clean,simplify, track clipped output  *
 *                              and total bits/frame received.        *
 * 7/10/91  Earle Jennings      changed to floats to FLOAT            *
 *10/ 1/91  S.I. Sudharsanan,   Ported to IBM AIX platform.           *
 *          Don H. Lee,                                               *
 *          Peter W. Farrett                                          *
 *10/ 3/91  Don H. Lee          implemented CRC-16 error protection   *
 *                              newly introduced functions are        *
 *                              buffer_CRC and recover_CRC_error      *
 *                              Additions and revisions are marked    *
 *                              with "dhl" for clarity                *
 * 2/11/92  W. Joseph Carter    Ported new code to Macintosh.  Most   *
 *                              important fixes involved changing     *
 *                              16-bit ints to long or unsigned in    *
 *                              bit alloc routines for quant of 65535 *
 *                              and passing proper function args.     *
 *                              Removed "Other Joint Stereo" option   *
 *                              and made bitrate be total channel     *
 *                              bitrate, irrespective of the mode.    *
 *                              Fixed many small bugs & reorganized.  *
 *19 aug 92 Soren H. Nielsen    Changed MS-DOS file name extensions.  *
 * 8/27/93 Seymour Shlien,      Fixes in Unix and MSDOS ports,        *
 *         Daniel Lauzon, and                                         *
 *         Bill Truerniet                                             *
 *--------------------------------------------------------------------*
 * 4/23/92  J. Pineda           Added code for layer III.  LayerIII   *
 *          Amit Gulati         decoding is currently performed in    *
 *                              two-passes for ease of sideinfo and   *
 *                              maindata buffering and decoding.      *
 *                              The second (computation) pass is      *
 *                              activated with "decode -3 <outfile>"  *
 * 10/25/92 Amit Gulati         Modified usage() for layerIII         *
 * 12/10/92 Amit Gulati         Changed processing order of re-order- *
 *                              -ing step.  Fixed adjustment of       *
 *                              main_data_end pointer to exclude      *
 *                              side information.                     *
 *  9/07/93 Toshiyuki Ishino    Integrated Layer III with Ver 3.9.    *
 *--------------------------------------------------------------------*
 * 11/20/93 Masahiro Iwadare    Integrated Layer III with Ver 4.0.    *
 *--------------------------------------------------------------------*
 *  7/14/94 Juergen Koller      Bug fixes in Layer III code           *
 *--------------------------------------------------------------------*
 * 08/11/94 IIS                 Bug fixes in Layer III code           *
 *--------------------------------------------------------------------*
 * 11/04/94 Jon Rowlands        Prototype fixes                       *
 *--------------------------------------------------------------------*
 *  7/12/95 Soeren H. Nielsen   Changes for LSF Layer I and II        *
 *--------------------------------------------------------------------*
 *  7/14/94 Juergen Koller      Bug fixes in Layer III code           *
 *--------------------------------------------------------------------*
 *     8/95 Roland Bitto        addapdet to MPEG 2                    *
 *--------------------------------------------------------------------*
 * 11/22/95 Heiko Purnhagen     skip ancillary data in bitstream      *
 *--------------------------------------------------------------------*
 * 12/16/96 Johan Hagman	Adapted for Solaris (mpeg3play 0.9)   *
 **********************************************************************/

#include        "common.h"
#include        "decoder.h"
#include	"sound.h"

/********************************************************************
 *
 *        This part contains the MPEG I decoder for Layers I & II.
 *
 *********************************************************************/

/****************************************************************
 *
 *        For MS-DOS user (Turbo c) change all instance of malloc
 *        to _farmalloc and free to _farfree. Compiler model hugh
 *        Also make sure all the pointer specified are changed to far.
 *
 *****************************************************************/
/* local functions definition */

static void usage(int level);
static void GetArguments();

/*********************************************************************
 *
 * Core of the Layer II decoder.  Default layer is Layer II.
 *
 *********************************************************************/

/* Global variable definitions for "musicout.c" */

char		*programName;
Arguments_t	 Arguments;
int		 audiofd;

/* Implementations */

int main(int argc, char **argv)
{
    typedef unsigned int SAM[2][3][SBLIMIT];
    static SAM FAR	*sample;

    typedef REAL	 FRA[2][3][SBLIMIT];
    static FRA FAR	*fraction;

    typedef short	 PCMBUF[2][SSLIMIT][SBLIMIT];
    static PCMBUF FAR	*pcm_sample;

    static Bit_stream_struc bs;
    frame_params	 fr_ps;
    layer		 info;
    FILE		*musicout;		/* decode to file */
    unsigned long	 sample_frames;

    static int 		 i, j, k, stereo,
			 done = FALSE, clip, sync,
			 error_protection, crc_error_count,
			 total_error_count;
    static unsigned int	 old_crc, new_crc;
    static unsigned int	 bit_alloc[2][SBLIMIT],
			 scfsi[2][SBLIMIT],
			 scale_index[2][3][SBLIMIT];
    unsigned long	 bitsPerSlot = 0, samplesPerFrame = 0, frameNum = 0;
    unsigned long	 frameBits, gotBits = 0;
    IFF_AIFF		 pcm_aiff_data;
    int			 Max_gr;

    III_scalefac_t	 III_scalefac;
    III_side_info_t	 III_side_info;

#ifdef	MACINTOSH
    console_options.nrows = MAC_WINDOW_SIZE;
    argc = ccommand(&argv);
#endif

    /* Most large variables are declared dynamically to ensure
       compatibility with smaller machines */

    pcm_sample = (PCMBUF FAR *) mem_alloc((long) sizeof(PCMBUF),
                                              "PCM Sample");
    sample = (SAM FAR *) mem_alloc((long) sizeof(SAM), "Sample");
    fraction = (FRA FAR *) mem_alloc((long) sizeof(FRA), "fraction");

    fr_ps.header = &info;
    fr_ps.tab_num = -1;                /* no table loaded */
    fr_ps.alloc = NULL;

    Arguments.topSb = 0;
    Arguments.forkoff = 0;
    GetArguments(argc, argv, &Arguments);

    if (Arguments.forkoff) {
#ifndef RISCOS
	switch (fork()) {
	case 0:
	    break;	/* child continues*/
	case -1:
	    perror("fork");
	    exit(-1);
	    break;
	default:
	    return 0;	/* parent returns*/
	}
#else
        fprintf(stderr,"Not supported on RISCOS\n");
        exit(-1);
#endif
    }

    if (Arguments.write_to_file) {
	if (strcmp(Arguments.decoded_file_name, "-") == 0)
	    musicout = stdout;
	else {
	    if ((musicout = fopen(Arguments.decoded_file_name, "w+b")) == NULL) {
		fprintf(stderr, "Could not create \"%s\".\n", Arguments.decoded_file_name);
		exit(1);
	    }
	}
    } else {
	/* Open audio device write-only (to avoid buffering input data) */
	if( (audiofd = sound_open()) < 0) {
	    perror("open audio device");
	    exit(1);
	}
    }
    open_bit_stream_r(&bs, Arguments.encoded_file_name, BUFFER_SIZE);

    if (Arguments.need_aiff)
	if (aiff_seek_to_sound_data(musicout) == -1) {
	    if (strcmp(Arguments.decoded_file_name, "-") == 0)
		fprintf(stderr, "Could not seek to PCM sound data in stdout\n");
	    else
		fprintf(stderr, "Could not seek to PCM sound data in \"%s\"\n",
			Arguments.decoded_file_name);
	    exit(1);
	}

    sample_frames = 0;

    /* The output loop */
    while (!end_bs(&bs)) {

	sync = seek_sync(&bs, SYNC_WORD, SYNC_WORD_LNGTH);
	frameBits = sstell(&bs) - gotBits;
	if (frameNum > 0)        /* don't want to print on 1st loop; no lay */
	    if(frameBits % bitsPerSlot)
		fprintf(stderr, "Got %ld bits = %ld slots plus %ld\n",
		     frameBits, frameBits/bitsPerSlot, frameBits%bitsPerSlot);
	gotBits += frameBits;

	if (!sync) {
	    if (Arguments.verbose) {
		fprintf(stderr,
		    "\rFrame %ld cannot be located, input stream may be empty\n",
		    frameNum);
	    }
	    done = TRUE;
	    /* Finally write out the buffer */
	    if (info.lay != 1)
		out_fifo(*pcm_sample, 3, &fr_ps, done, musicout,
				&sample_frames);
	    else
		out_fifo(*pcm_sample, 1, &fr_ps, done, musicout,
				&sample_frames);
	    break;
	}

	decode_info(&bs, &fr_ps);
	hdr_to_frps(&fr_ps);
	stereo = fr_ps.stereo;
	if (fr_ps.header->version == MPEG_PHASE2_LSF)
	    Max_gr = 1;
	else
	    Max_gr = 2;

	error_protection = info.error_protection;
	crc_error_count = 0;
	total_error_count = 0;

	if (frameNum == 0) {
	    if (Arguments.verbose)
		WriteHdr(&fr_ps, stderr);	/* printout layer/mode */

	    if (!Arguments.write_to_file) {
		if (sound_init(audiofd, &info, stereo)) {
		    perror("Couldn't initialize audio device");
		    exit(1);
		}
	    }
	}

#ifdef ESPS
	if (frameNum == 0 && Arguments.need_esps) {
	    esps_write_header(musicout,(long) sample_frames,
		s_freq[info.version][info.sampling_frequency] * 1000,
		(int) stereo, Arguments.decoded_file_name );
	} /* MI */
#endif

	if (Arguments.verbose && frameNum % 10 == 0) {
	    fprintf(stderr, "\rFrame %-3lu ", frameNum);
	}

	frameNum++;

	if (error_protection)
	    buffer_CRC(&bs, &old_crc);

	switch(info.lay) {
	case 1:
	    bitsPerSlot = 32;
	    samplesPerFrame = 384;

	    I_decode_bitalloc(&bs,bit_alloc,&fr_ps);
	    I_decode_scale(&bs, bit_alloc, scale_index, &fr_ps);

	    if (error_protection) {
		I_CRC_calc(&fr_ps, bit_alloc, &new_crc);
		if (new_crc != old_crc) {
		    crc_error_count++;
		    total_error_count++;
		    recover_CRC_error(*pcm_sample, crc_error_count,
					&fr_ps, musicout, &sample_frames);
		    break;
		}
		else crc_error_count = 0;
	    }

	    clip = 0;
	    for (i = 0; i < SCALE_BLOCK; i++) {
		I_buffer_sample(&bs, (*sample), bit_alloc,&fr_ps);
		I_dequantize_sample(*sample, *fraction, bit_alloc,&fr_ps);
		I_denormalize_sample((*fraction),scale_index,&fr_ps);
#ifdef DEBUG
		if (Arguments.topSb > 0)     /* clear channels to 0 */
		   for (j = Arguments.topSb; j < fr_ps.sblimit; ++j)
		      for (k = 0; k < stereo; ++k)
			 (*fraction)[k][0][j] = 0.0;
#endif
		for (j = 0; j < stereo; j++) {
		   clip += SubBandSynthesis(&((*fraction)[j][0][0]), j,
					     &((*pcm_sample)[j][0][0]));
		}
		out_fifo(*pcm_sample, 1, &fr_ps, done,
			 musicout, &sample_frames);
	     }
	     if (clip > 0 && Arguments.verbose)
		fprintf(stderr, "\rFrame %-3lu: %d output samples clipped\n",
				frameNum - 1, clip);
	     break;

	case 2:
	    bitsPerSlot = 8;
	    samplesPerFrame = 1152;

	    II_decode_bitalloc(&bs, bit_alloc, &fr_ps);
	    II_decode_scale(&bs, scfsi, bit_alloc, scale_index, &fr_ps);

	    if (error_protection) {
		II_CRC_calc(&fr_ps, bit_alloc, scfsi, &new_crc);
		if (new_crc != old_crc) {
		    crc_error_count++;
		    total_error_count++;
		    recover_CRC_error(*pcm_sample, crc_error_count,
				&fr_ps, musicout, &sample_frames);
		    break;
		} else
		    crc_error_count = 0;
	     }

	     clip = 0;
	     for (i = 0; i < SCALE_BLOCK; i++) {	/* SCALE_BLOCK = 12*/
		II_buffer_sample(&bs, (*sample), bit_alloc, &fr_ps);
		II_dequantize_sample((*sample), bit_alloc, (*fraction), &fr_ps);
		II_denormalize_sample((*fraction), scale_index, &fr_ps, i>>2);
#ifdef DEBUG
		if (Arguments.topSb > 0)      /* debug : clear channels to 0 */
		    for (j=Arguments.topSb; j<fr_ps.sblimit; ++j)
			for (k=0; k<stereo; ++k)
			    (*fraction)[k][0][j] =
			    (*fraction)[k][1][j] =
			    (*fraction)[k][2][j] = 0.0;
#endif
		for (j = 0; j < 3; j++) {
		    for (k = 0; k < stereo; k++) {
			clip += SubBandSynthesis(&((*fraction)[k][j][0]),
				k, &((*pcm_sample)[k][j][0]));
		    }
		}
		out_fifo(*pcm_sample, 3, &fr_ps, done, musicout,
			 &sample_frames);
	     }
	     if (clip > 0 && Arguments.verbose)
		fprintf(stderr, "\rFrame %-3lu: %d output samples clipped\n",
				frameNum - 1, clip);
	     break;

	case 3: {
	    static int	nSlots;
	    static int	gr, ch, ss, sb,
			main_data_end, flush_main;
	    static int	bytes_to_discard;
	    static int	frame_start = 0;

	    bitsPerSlot = 8;
	    if (fr_ps.header->version == MPEG_PHASE2_LSF)
		samplesPerFrame = 576;
	    else
		samplesPerFrame = 1152;

	    III_get_side_info(&bs, &III_side_info, &fr_ps);
	    nSlots = main_data_slots(fr_ps);

	    for (; nSlots > 0; nSlots--)	/* read main data*/
		hputbuf((unsigned int) getbits(&bs,8), 8);
	    main_data_end = hsstell() / 8;	/* of previous frame*/

	    if ((flush_main = (hsstell() % bitsPerSlot))) {
		hgetbits((int)(bitsPerSlot - flush_main));
		main_data_end ++;
	    }
	    bytes_to_discard = frame_start - main_data_end -
			       III_side_info.main_data_begin ;
	    if (main_data_end > 4096) {
		frame_start -= 4096;
		rewindNbytes(4096);
	    }

	    frame_start += main_data_slots(fr_ps);
	    if (bytes_to_discard < 0) {
		if (Arguments.verbose)
		    fprintf(stderr, "not enough main data to decode, "
				 "frame discarded\n");
		break;
	    }
	    for (; bytes_to_discard > 0; bytes_to_discard--)
		 hgetbits(8);

	    clip = 0;
	    for (gr = 0; gr < Max_gr; gr++) {	/* 1 or 2*/
		static REAL	lr[2][SBLIMIT][SSLIMIT],
				ro[2][SBLIMIT][SSLIMIT];

		for (ch = 0; ch < stereo; ch++) {
		    /* Quantized samples*/
		    static long int is[SBLIMIT+1][SSLIMIT];
		    int part2_start;

		    part2_start = hsstell();
		    if (fr_ps.header->version != MPEG_PHASE2_LSF)
			III_get_scale_factors(&III_scalefac,
				&III_side_info,	gr, ch, &fr_ps);
		    else
			III_get_LSF_scale_factors(&III_scalefac,
				&III_side_info, gr,ch,&fr_ps);

		    III_hufman_decode(is, &III_side_info, ch, gr, part2_start,
				&fr_ps);
		    III_dequantize_sample(is, ro[ch], &III_scalefac,
				&(III_side_info.ch[ch].gr[gr]), ch, &fr_ps);
		}
		III_stereo(ro, lr, &III_scalefac,
				&(III_side_info.ch[0].gr[gr]), &fr_ps);

		for (ch = 0; ch < stereo; ch++) {
		    static REAL re[SBLIMIT][SSLIMIT];
		    /* Hybrid filter input*/
		    static REAL hybridIn[SBLIMIT][SSLIMIT];
		    /* Hybrid filter out*/
		    static REAL hybridOut[SBLIMIT][SSLIMIT];
		    /* PolyPhase Input*/
		    static REAL polyPhaseIn[SBLIMIT];

		    III_reorder(lr[ch],re,&(III_side_info.ch[ch].gr[gr]),
				  &fr_ps);

		    III_antialias(re, hybridIn,		/* antialias butterflies*/
				  &(III_side_info.ch[ch].gr[gr]), &fr_ps);

		    for (sb = 0; sb < SBLIMIT; sb++) {	/* hybrid synthesis*/
			III_hybrid(hybridIn[sb], hybridOut[sb], sb, ch,
				   &(III_side_info.ch[ch].gr[gr]), &fr_ps);
		    }

#ifdef OPTIMIZE
		    for (ss = 0; ss < SSLIMIT; ss++) {	/* Polyphase synthesis*/
			for (sb = 0; sb < SBLIMIT; sb++) {
			    /* Perform frequency inversion for polyphase*/
			    if ((ss % 2) && (sb % 2))
				polyPhaseIn[sb] = -hybridOut[sb][ss];
			    else
				polyPhaseIn[sb] = hybridOut[sb][ss];
			}
			clip += SubBandSynthesis(polyPhaseIn, ch,
						&((*pcm_sample)[ch][ss][0]));
		    }
#else
		    /* Frequency inversion for polyphase*/
		    for (ss = 0; ss < SSLIMIT; ss++)		/* 18*/
			for (sb = 0; sb < SBLIMIT; sb++)	/* 32*/
			    if ((ss%2) && (sb%2))
				hybridOut[sb][ss] = -hybridOut[sb][ss];

		    for (ss = 0; ss < SSLIMIT; ss++) {	/* Polyphase synthesis*/
			for (sb = 0; sb < SBLIMIT; sb++)
			    polyPhaseIn[sb] = hybridOut[sb][ss];
			clip += SubBandSynthesis (polyPhaseIn, ch,
						&((*pcm_sample)[ch][ss][0]));
		    }
#endif	/* OPTIMIZE */
		}
		/* Output PCM sample points for one granule*/
		out_fifo(*pcm_sample, 18, &fr_ps, done, musicout,
			 &sample_frames);
	    }
	    if (clip > 0 && Arguments.verbose)
		fprintf(stderr, "\rFrame %-3lu: %d output samples clipped\n",
				frameNum - 1, clip);

	    } /* end of layer 3 block*/
	    break;

	} /* end of case*/

/* Commented out for now*/
#if 0
	/* Skip ancillary data   HP 22-nov-95 */
	if (info.bitrate_index > 0) { /* if not free-format */
		long anc_len;

		anc_len = (int)((double)samplesPerFrame /
			       s_freq[info.version][info.sampling_frequency] *
			       (double)bitrate[info.version][info.lay-1][info.bitrate_index] /
			       (double)bitsPerSlot);
		if (info.padding)
			anc_len++;
		anc_len *= bitsPerSlot;
		anc_len -= sstell(&bs)-gotBits+SYNC_WORD_LNGTH;
		for (j=0; j<anc_len; j++)
			get1bit(&bs);
	}
#endif

    }

    if (Arguments.need_aiff) {
	pcm_aiff_data.numChannels	= stereo;
	pcm_aiff_data.numSampleFrames	= sample_frames;
	pcm_aiff_data.sampleSize	= 16;
	pcm_aiff_data.sampleRate	= (double)
		s_freq[info.version][info.sampling_frequency] * 1000;
	pcm_aiff_data.sampleType	= IFF_ID_SSND;
	pcm_aiff_data.blkAlgn.offset	= 0;
	pcm_aiff_data.blkAlgn.blockSize = 0;

	if (aiff_write_headers(musicout, &pcm_aiff_data) == -1) {
	    if (strcmp(Arguments.decoded_file_name, "-") == 0)
		fprintf(stderr, "Could not write AIFF headers to stdout\n");
	    else
		fprintf(stderr, "Could not write AIFF headers to \"%s\"\n",
			Arguments.decoded_file_name);
	    exit(2);
	}
    }

    if (Arguments.verbose)
	fprintf(stderr, "\r%ld frames, avg slots/frame = %.3f; b/smp = %.2f; br = %.3f kbps\n",
		frameNum, (float) gotBits / (frameNum * bitsPerSlot),
		(float) gotBits / (frameNum * samplesPerFrame),
		(float) gotBits / (frameNum * samplesPerFrame) *
		s_freq[info.version][info.sampling_frequency]);

    close_bit_stream_r(&bs);
    if (Arguments.write_to_file)
	fclose(musicout);
    else {
	if (sound_close(audiofd))
	    perror("Error closing audio device");
    }

    /* for the correct AIFF header information */
    /*             on the Macintosh            */
    /* the file type and the file creator for  */
    /* Macintosh compatible Digidesign is set  */

#ifdef  MACINTOSH
    if (Arguments.need_aiff)
		set_mac_file_attr(Arguments.decoded_file_name, VOL_REF_NUM,
                                     CREATR_DEC_AIFF, FILTYP_DEC_AIFF);
    else	set_mac_file_attr(Arguments.decoded_file_name, VOL_REF_NUM,
                                     CREATR_DEC_BNRY, FILTYP_DEC_BNRY);
#endif

    if (Arguments.verbose) {
	fprintf(stderr, "Decoding of \"%s\" is finished\n",
	    Arguments.encoded_file_name);
	if (Arguments.write_to_file) {
	    if (strcmp(Arguments.decoded_file_name, "-") == 0)
		fprintf(stderr, "The decoded PCM output was written to stdout\n");
	    else
		fprintf(stderr, "The decoded PCM output file name is \"%s\"\n",
			Arguments.decoded_file_name);
	}
    }
    return 0;
}

static void usage(int level)	/* print help info and exit*/
{
    if (level >= 1) {
	fprintf(stderr,
	"+---------------------------------------+\n"
	"|   mpeg3play version 0.9.6, 6-Apr-97   |\n"
	"+---------------------------------------+\n"
	"This is an MPEG audio layer 2 and layer 3 decoder/player\n"
	"based on public ISO/MPEG audio decoder source code. Solaris\n"
	"port and optimizations by Johan.Hagman@mailbox.swipnet.se.\n\n"
	"Copyright (C) 1996, 1997 by Johan Hagman.\n"
	"This program is free software.\n\n");
    }
#ifdef DEBUG
    fprintf(stderr, "usage: %s [-v] [-h] [-f] [-o outfile.aiff] [-s sb] filename\n",
		programName);
#else
# ifdef AMIGA
    fprintf(stderr, "usage: %s [-v] [-h] [-f] [-r] [-o outfile.aiff] filename\n",
		programName);
# else
    fprintf(stderr, "usage: %s [-v] [-h] [-f] [-o outfile.aiff] filename\n",
		programName);
# endif
#endif
    fprintf(stderr,"  -v          enable verbose mode\n");
    fprintf(stderr,"  -h          display program help information\n");
    fprintf(stderr,"  -f          fork off new player and return\n");
#ifdef AMIGA
    fprintf(stderr,"  -r          switch to raw PCM (amiga)\n");
#endif
    fprintf(stderr,"  -o outfile  write an AIFF output PCM sound file\n");
#ifdef DEBUG
    fprintf(stderr,"  -s sb       resynth only up to this subband (debugging)\n");
#endif
    fprintf(stderr,"  filename    bit stream of encoded audio (\"-\" means stdin)\n");
    exit(1);
}


static void GetArguments(int argc, char **argv, Arguments_t *Arguments)
{
    int		i = 0, err = 0, raw_output = FALSE;

    programName = "mpeg3play";

    Arguments->need_aiff = FALSE;
    Arguments->need_esps = FALSE;	/* MI */
    Arguments->write_to_file= FALSE;
    Arguments->verbose = FALSE;

    Arguments->encoded_file_name[0] = '\0';
    Arguments->decoded_file_name[0] = '\0';

    while (++i < argc && err == 0) {
	char c, *token, *arg, *nextArg;
	int  argUsed;

	token = argv[i];
	/* Original code was if (*token++ == '-'), this change makes*/
	/* it possible to use "-" for reading input stream from stdin*/
	if (*token++ == '-' && *token != '\0') {
	    if (i+1 < argc)
		nextArg = argv[i+1];
	    else
		nextArg = "";
	    argUsed = 0;
	    while ((c = *token++)) {
		if (*token /* NumericQ(token) */)
		    arg = token;
		else
		    arg = nextArg;
		switch(c) {
		case 'v':
		    Arguments->verbose = TRUE;
		    break;
		case 'h':
		    usage(1);
		    break;
		case 'f':
		    Arguments->forkoff = TRUE;
		    break;
#ifdef AMIGA
		case 'r':
		    raw_output = TRUE;
		    break;
#endif
		case 'o':
		    argUsed = 1;	/* eat one arg*/
		    if (*arg == '\0') {
			fprintf(stderr,"error: -o requires a filename arg\n");
			err = 1;	/* found no filename*/
		    } else {
			strcpy(Arguments->decoded_file_name, arg);

			if (raw_output)	   /* set only by Amiga -r switch */
			    Arguments->need_aiff = FALSE;
			else
			    Arguments->need_aiff = TRUE;

			Arguments->write_to_file = TRUE;
		    }
		    break;
#ifdef DEBUG
		case 's':
		    Arguments->topSb = atoi(arg);
		    argUsed = 1;
		    if (Arguments->topSb < 1 || Arguments->topSb > SBLIMIT) {
			fprintf(stderr, "%s: -s band %s not %d..%d\n",
					programName, arg, 1, SBLIMIT);
			err = 1;
		    }
		    break;
#endif
		default:
		    fprintf(stderr,"error: unrecognized option \"%c\"\n", c);
		    err = 1;
		    break;
		}
		if (argUsed) {
		    if (arg == token)
			token = "";	/* no more from token */
		    else
			++i;		/* skip arg we used */
		    arg = "";
		    argUsed = 0;
		}
	    } /* end while*/

	} else { /* end of options*/

	    if (Arguments->encoded_file_name[0] == '\0') {
		strcpy(Arguments->encoded_file_name, argv[i]);
	    } else {
	        fprintf(stderr, "error: excess arg \"%s\"\n", argv[i]);
	        err = 1;
	    }
	}

    }

    if (err)
	usage(0);
    if (Arguments->encoded_file_name[0] == '\0') {
        fprintf(stderr, "error: input file is missing\n");
	usage(0);  /* never returns */
    }

    if (Arguments->verbose && Arguments->need_aiff) {
	if (strcmp(Arguments->decoded_file_name, "-") == 0)
	    fprintf(stderr, "The AIFF audio data is written to stdout\n");
	else
	    fprintf(stderr, "The output file \"%s\" is written in AIFF format\n",
			Arguments->decoded_file_name);
    }
}
