/**********************************************************************
 * ISO MPEG Audio Subgroup Software Simulation Group (1996)
 * ISO 13818-3 MPEG-2 Audio Encoder - Lower Sampling Frequency Extension
 *
 * $Id: encode.c,v 1.2 1998/10/05 17:06:47 larsi Exp $
 *
 * $Log: encode.c,v $
 * Revision 1.2  1998/10/05 17:06:47  larsi
 * *** empty log message ***
 *
 * Revision 1.1.1.1  1998/10/05 14:47:17  larsi
 *
 * Revision 1.1  1996/02/14 04:04:23  rowlands
 * Initial revision
 *
 * Received from Mike Coleman
 **********************************************************************/

 
#include "common.h"
#include "encoder.h"

/*=======================================================================\
|                                                                       |
| This segment contains all the core routines of the encoder,           |
| except for the psychoacoustic models.                                 |
|                                                                       |
| The user can select either one of the two psychoacoustic              |
| models. Model I is a simple tonal and noise masking threshold         |
| generator, and Model II is a more sophisticated cochlear masking      |
| threshold generator. Model I is recommended for lower complexity      |
| applications whereas Model II gives better subjective quality at low  |
| bit rates.                                                            |
\=======================================================================*/
 
/************************************************************************
*
* read_samples()
*
* PURPOSE:  reads the PCM samples from a file to the buffer
*
*  SEMANTICS:
* Reads #samples_read# number of shorts from #musicin# filepointer
* into #sample_buffer[]#.  Returns the number of samples read.
*
************************************************************************/

unsigned long read_samples(musicin, sample_buffer, num_samples, frame_size)
FILE *musicin;
short sample_buffer[2304];
unsigned long num_samples, frame_size;
{
    unsigned long samples_read;
    static unsigned long samples_to_read;
    static char init = TRUE;
    extern int swapbytes; /* if TRUE then force swapping of byte order */

    if (init) {
        samples_to_read = num_samples;
        init = FALSE;
    }
    if (samples_to_read >= frame_size)
        samples_read = frame_size;
    else
        samples_read = samples_to_read;
    if ((samples_read =
         fread(sample_buffer, sizeof(short), (int)samples_read, musicin)) == 0)
      { /* printf("Hit end of audio data\n"); */ }
    /*
       Samples are big-endian. If this is a little-endian machine
       we must swap
     */
    if ( NativeByteOrder == order_unknown )
      {
	NativeByteOrder = DetermineByteOrder();
	if ( NativeByteOrder == order_unknown )
	  {
	    fprintf( stderr, "byte order not determined\n" );
	    exit( 1 );
	  }
      }
    if (!iswav && ( NativeByteOrder == order_littleEndian ))
      SwapBytesInWords( sample_buffer, samples_read );

    if (swapbytes==TRUE)
      SwapBytesInWords( sample_buffer, samples_read );

    samples_to_read -= samples_read;
    if (samples_read < frame_size && samples_read > 0) {
      /* printf("Insufficient PCM input for one frame - fillout with zeros\n"); */
        for (; samples_read < frame_size; sample_buffer[samples_read++] = 0);
        samples_to_read = 0;
    }
    return(samples_read);
}

/************************************************************************
*
* get_audio()
*
* PURPOSE:  reads a frame of audio data from a file to the buffer,
*   aligns the data for future processing, and separates the
*   left and right channels
*
*
************************************************************************/
 
unsigned long get_audio( musicin, bufferL,bufferR, num_samples, stereo, info )
FILE *musicin;
/*
short FAR buffer[2][1152];
*/
short FAR bufferL[1152],bufferR[1152];
unsigned long num_samples;
int stereo;
layer *info;
{
    int j;
    short insamp[3176];
    unsigned long samples_read;
    int lay;
    extern int autoconvert;

    lay = info->lay;

    /* pad with zeros in case we hit EOF */
    memset((char *) insamp, 0, sizeof(insamp));

    if ( (lay == 3) && (info->version == 0) )  /* ie MPEG-2 LSF */
    {
	if ( stereo == 2 )
	{
	    samples_read = read_samples( musicin, insamp, num_samples,
					 (unsigned long) 1152 );
	    for ( j = 0; j < 576; j++ )
	    {
		bufferL[j] = insamp[2 * j];
		bufferR[j] = insamp[2 * j + 1];
	    }
	}
	else
	{
	    samples_read = read_samples( musicin, insamp, num_samples,
					 (unsigned long) 576 );
	    for ( j = 0; j < 576; j++ )
	    {
		bufferL[j] = insamp[j];
		bufferR[j] = 0;
	    }
	}
    }
    else
    /* MPEG 1 */
      {
	    if(stereo == 2){ /* layer 2 (or 3), stereo */
	      samples_read = read_samples(musicin, insamp, num_samples,
					  (unsigned long) 2304);
	      for(j=0;j<1152;j++) {
		bufferL[j] = insamp[2*j];
		bufferR[j] = insamp[2*j+1];
		
	      }
	    }
	    else { /* layer 2 (or 3), mono */
	      if (autoconvert==TRUE) {  /* downconvert from a stereo file into a mono buffer */
		samples_read = read_samples(musicin, insamp, num_samples,
					    (unsigned long) 2304);
		for(j=0;j<1152;j++){
		  bufferL[j] = insamp[2*j];
		  bufferR[j] = 0;
		}	
	      }
	      else {
		samples_read = read_samples(musicin, insamp, num_samples,
					    (unsigned long) 1152);
		for(j=0;j<1152;j++){
		    bufferL[j] = insamp[j];
		    bufferR[j] = 0;
		}
	      }
	    }
	}
    return(samples_read);
}
 
/************************************************************************
*
* window_subband()
*
* PURPOSE:  Overlapping window on PCM samples
*
* SEMANTICS:
* 32 16-bit pcm samples are scaled to fractional 2's complement and
* concatenated to the end of the window buffer #x#. The updated window
* buffer #x# is then windowed by the analysis window #c# to produce the
* windowed sample #z#
*
************************************************************************/

extern double enwindow[];

void window_subband(buffer, z, k)
short **buffer;
double z[HAN_SIZE];
int k;
{
    typedef double FAR XX[2][HAN_SIZE];
    static XX FAR *x;
    double *xk;
    int i, j;
    static int off[2] = {0,0};
    static char init = 0;
    if (!init) {
        x = (XX FAR *) mem_alloc(sizeof(XX),"x");
        for (i=0;i<2;i++)
            for (j=0;j<HAN_SIZE;j++)
                (*x)[i][j] = 0;
        init = 1;
    }
    xk=(*x)[k];

    /* replace 32 oldest samples with 32 new samples */
    for (i=0;i<32;i++) /*(*x)[k]*/xk[31-i+off[k]] = (double) *(*buffer)++/SCALE;
    /* shift samples into proper window positions */
    for (i=0;i<HAN_SIZE;i++) z[i] = xk[(i+off[k])&HAN_SIZE-1] * enwindow[i];
    off[k] += 480;              /*offset is modulo (HAN_SIZE-1)*/
    off[k] &= HAN_SIZE-1;

}
 
/************************************************************************
*
* filter_subband()
*
* PURPOSE:  Calculates the analysis filter bank coefficients
*
* SEMANTICS:
*      The windowed samples #z# is filtered by the digital filter matrix #m#
* to produce the subband samples #s#. This done by first selectively
* picking out values from the windowed samples, and then multiplying
* them by the filter matrix, producing 32 subband samples.
*
************************************************************************/


/*#define NORING*/
/* define NORING to use the MDCT from Fredrik Noring <noring@lysator.liu.se>
 * actually seems to be about 10% slower than we have.  
 */

#ifdef NORING
extern void mfct(double *, double *);
void filter_subband(z,s)
double FAR z[HAN_SIZE], s[SBLIMIT];
{
  double y[64];
  int i,j;
  
  for (i=0;i<64;i++) for (j=0, y[i] = 0;j<8;j++) y[i] += z[i+64*j];
  mfct(y, s);
}
#else
void
create_dct_matrix( filter )
double filter[16][32];
{
  register int i,k;
 
  for (i=0; i<16; i++)
    for (k=0; k<32; k++) {
       filter[i][k] = cos((double)((2*i+1)*k*PI64));
    }
}

void
IDCT32( xin, xout )
double *xin, *xout;
{
  int i,j;
  double s0, s1;
  typedef double MM[16][32];
  static MM FAR * m = 0;
  if( m==0 ) {
    m = (MM FAR *)mem_alloc(sizeof(MM),"filter");
    create_dct_matrix( *m );
  }
  for( i=0; i<16; i++ ) {
    s0 = s1 = 0.0;
    for( j=0; j<32; j+=2 ) {
      s0 += (*m)[i][j]*xin[j+0];
      s1 += (*m)[i][j+1]*xin[j+1];
    }
    xout[i] = s0+s1;
    xout[31-i] = s0-s1;
  }
}

void filter_subband(z,s)
double FAR z[HAN_SIZE], s[SBLIMIT];
{
   double y[64],yprime[32];
   int i,j;
   double *zi;

   zi = z;
   for( i=0; i<64; i++ ) {
      y[ i ] = *zi + zi[ 64 ] + zi[ 128 ] + zi[ 192 ] +
               zi[ 256 ] + zi[ 320 ] + zi[ 384 ] + zi[ 448 ];
      zi++;
   }

   {
     yprime[0] = y[16];
     for( i=1; i<=16; i++ ) yprime[i] = y[i+16]+y[16-i];
     for( i=17; i<=31; i++ ) yprime[i] = y[i+16]-y[80-i];
     IDCT32( yprime, s );
   }
}
#endif

/************************************************************************
* encode_info()
*
* PURPOSE:  Puts the syncword and header information on the output
* bitstream.
*
************************************************************************/
 
void encode_info(fr_ps,bs)
frame_params *fr_ps;
Bit_stream_struc *bs;
{
        layer *info = fr_ps->header;
 
        putbits(bs,0xfff,12);                    /* syncword 12 bits */
        put1bit(bs,info->version);               /* ID        1 bit  */
        putbits(bs,4-info->lay,2);               /* layer     2 bits */
        put1bit(bs,!info->error_protection);     /* bit set => no err prot */
        putbits(bs,info->bitrate_index,4);
        putbits(bs,info->sampling_frequency,2);
        put1bit(bs,info->padding);
        put1bit(bs,info->extension);             /* private_bit */
        putbits(bs,info->mode,2);
        putbits(bs,info->mode_ext,2);
        put1bit(bs,info->copyright);
        put1bit(bs,info->original);
        putbits(bs,info->emphasis,2);
}
 
/************************************************************************
*
* mod()
*
* PURPOSE:  Returns the absolute value of its argument
*
************************************************************************/
 
double mod(a)
double a;
{
    return (a > 0) ? a : -a;
}

