/*___________________________________________________________________________
 |                                                                           |
 |                                                                           |
 |                 Residual Error Insertion Device                           |
 |                                                                           |
 |                                                                           |
 |      File  :  REID.C                                                      |
 |                                                                           |
 |      Date  :  February 03, 1995                                           |
 |                                                                           |
 |      Version: 4.1                                                         |
 |                                                                           |
 |                                                                           |
 |   Description:                                                            |
 |   ------------                                                            |
 |      This routine transforms the output file format of the GSM Half       |
 |      Rate Encoder module consisting of:                                   |
 |           * 18 speech parameters (see GSM TS 06.20)                       |
 |           *  1 speech flag SP (see GSM TS 06.41)                          |
 |           *  1 voice activity flag VAD (see GSM TS 06.42)                 |
 |                                                                           |
 |      to the input file format of the GSM Half Rate Decoder module         |
 |      requiring:                                                           |
 |           * 18 speech parameters (see GSM TS 06.20)                       |
 |           *  1 channel condition flag BFI (see GSM TS 06.21, 05.05)       |
 |           *  1 channel condition flag UFI (see GSM TS 06.21, 05.05)       |
 |           *  1 SID flag (2 bits) (see GSM TS 06.41, 05.05)                |
 |           *  1 time alignment flag TAF (see GSM TS 06.41)                 |
 |                                                                           |
 |      Between SID updates the speech parameters are replaced by random     |
 |      values simulating an interrupted transmission on the air interface   |
 |                                                                           |
 |      The actual implementation only supports error free transmission (EP0)|
 |                                                                           |
 |      The shell for the future use of error patterns (residual error       |
 |      pattern insertion) is already included.  If necessary, byte swapping |
 |      is performed on the input speech parameters so that they are always  |
 |      represented internally in PC byte order (assuming that the byte      |
 |      order of the input file is compatible with the machine on which the  |
 |      program is run).  However, byte swapping is not done on the flag     |
 |      words (input: SP and VAD, output: BFI, UFI, SID, and TAF).  Thus,    |
 |      the residual error pattern insertion code may be written to handle   |
 |      the speech parameter words on a byte basis, but the flag words must  |
 |      always be handled on a word basis.                                   |
 |___________________________________________________________________________|
*/
/*___________________________________________________________________________
 |                                                                           |
 |      Creation: 19.12.94                                                   |
 |                                                                           |
 |  Changes:                                                                 |
 |      22.12.94:  Removal of BCI flag, instead: determination of SID flag   |
 |      12.01.95:  SID update period = 12 (instead of 24)                    |
 |      13.01.95:  When in CNI mode, the parameters between SID updates are  |
 |                 random values. This simulates the interrupted transmission|
 |      03.02.95:  int32_t main( int32_t...) replaced by int main(int ...),|
 |                 initial value of swTAFCnt set to 1                        |
 |___________________________________________________________________________|
*/

/*___________________________________________________________________________
 |                                                                           |
 |      Include-Files                                                        |
 |___________________________________________________________________________|
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#ifdef VAX
#   define OPEN_WI  "wb","mrs=512","rfm=fix","ctx=stm"
#   define OPEN_RI  "rb","mrs=512","rfm=fix","ctx=stm"
#   define OPEN_WB  "wb","mrs=512","rfm=fix","ctx=stm"
#   define OPEN_RB  "rb","mrs=2","rfm=fix","ctx=stm"
#   define OPEN_WT  "w","mrs=256","rat=cr","rfm=var"
#   define OPEN_RT  "r","mrs=256","rat=cr","rfm=var"
#else
#   define OPEN_WB  "wb"
#   define OPEN_RB  "rb"
#   define OPEN_WI  "wb"
#   define OPEN_RI  "rb"
#   define OPEN_WT  "wt"
#   define OPEN_RT  "rt"
#endif

#define LW_SIGN (long)0x80000000       /* sign bit */
#define LW_MIN (long)0x80000000
#define LW_MAX (long)0x7fffffff
#define SW_MIN (short)0x8000           /* smallest Ram */
#define SW_MAX (short)0x7fff           /* largest Ram */

typedef char  Byte;
typedef long int int32_t;             /* 32 bit "accumulator" (L_*) */
typedef short int int16_t;           /* 16 bit "register"  (sw*) */

/*___________________________________________________________________________
 |                                                                           |
 |      local Functions                                                      |
 |___________________________________________________________________________|
*/
static int32_t error_free( FILE *infile, FILE *outfile);
static void SwapBytes( int16_t buffer[], int32_t len );
static int32_t ByteOrder( void );
static size_t ReadInputFile( int16_t buffer[], FILE *fp );
static size_t WriteOutputFile( int16_t buffer[], FILE *fp );
static int32_t EncoderInterface( FILE *infile, int16_t swInPara[] );
static int16_t swSidDetection(int16_t pswParameters[],
                                                  int16_t pswErrorFlag[]);
static void RandomParameters(int16_t pswParameters[]);
static int16_t getPnBits(int16_t iBits, int32_t *pL_PNSeed);
FILE *OpenBinfile( char *name, char *mode );
int32_t Strincmp( const char *s, const char *t, size_t max );
int32_t Stricmp( const char *s, const char *t );

int32_t L_shr(int32_t L_var1, int16_t var2);   /* 2 ops */
int32_t L_shl(int32_t L_var1, int16_t var2);   /* 2 ops */
int16_t shr(int16_t var1, int16_t var2);     /* 1 ops */
int16_t shl(int16_t var1, int16_t var2);     /* 1 ops */

/*___________________________________________________________________________
 |                                                                           |
 |      Subroutines                                                          |
 |___________________________________________________________________________|
*/
static int32_t error_free( FILE *infile, FILE *outfile)
{

#define SPEECH      1
#define CNIFIRSTSID 2
#define CNICONT     3
#define VALIDSID    11
#define GOODSPEECH  33

    static int16_t swDecoMode = {SPEECH};
    static int16_t swTAFCnt = {1};
    int16_t swInPara[20], i, swFrameType;
    int16_t swOutPara[22],pswErrorFlag[3];
 
    if( EncoderInterface( infile, swInPara )) return( 1 );

    /* Copy input parameters to output parameters (error free transmission) */
    /* -------------------------------------------------------------------- */
    for (i=0;i<18;i++)
       swOutPara[i] = swInPara[i];

    /* Set channel status flags (error free transmission) */
    /* -------------------------------------------------- */
    swOutPara[18] = 0;     /* BFI flag */
    swOutPara[19] = 0;     /* UFI flag */

    /* Evaluate SID flag */
    /* ----------------- */
    pswErrorFlag[0] = 0;   /* BFI flag */
    pswErrorFlag[1] = 0;   /* UFI flag */
    pswErrorFlag[2] = 0;   /* BCI flag */
    swOutPara[20] = swSidDetection(swOutPara, pswErrorFlag);


    /* Evaluate TAF flag */
    /* ----------------- */
    if (swTAFCnt == 0) swOutPara[21] = 1;
    else               swOutPara[21] = 0;
    swTAFCnt = (swTAFCnt + 1) % 12;

   
    /* Frame classification:                                                */
    /* Since the transmission is error free, the received frames are either */
    /* valid speech or valid SID frames                                     */
    /* -------------------------------------------------------------------- */
    if      ( swOutPara[20] == 2) swFrameType = VALIDSID;
    else if ( swOutPara[20] == 0) swFrameType = GOODSPEECH;
    else {
            printf( "Error in SID detection\n" );
            return( 1 );
    }

    /* Update of decoder state */
    /* ----------------------- */
    if (swDecoMode == SPEECH) {
       if      (swFrameType == VALIDSID)   swDecoMode = CNIFIRSTSID;
       else if (swFrameType == GOODSPEECH) swDecoMode = SPEECH;
    }
    else {  /* comfort noise insertion mode */
       if      (swFrameType == VALIDSID)   swDecoMode = CNICONT;
       else if (swFrameType == GOODSPEECH) swDecoMode = SPEECH;
    }


    /* Replace parameters by random data if in CNICONT-mode and TAF=0 */
    /* -------------------------------------------------------------- */
    if ((swDecoMode == CNICONT) && (swOutPara[21] == 0)){
       RandomParameters(swOutPara);
       /* Set flags such, that an "unusable frame" is produced */
       swOutPara[18] = 1;     /* BFI flag */
       swOutPara[19] = 1;     /* UFI flag */
       swOutPara[20] = 0;     /* SID flag */
    }    



    if( outfile ) {
        if( WriteOutputFile( swOutPara, outfile )) {
            printf( "Error writing File\n" );
            return( 1 );
        }
    }
    return( 0 );
}

static int32_t EncoderInterface( FILE *infile, int16_t swInPara[] )
{
    size_t i = 0;    

    i = ReadInputFile( swInPara, infile );

    return(( i == 0 ) ? 1 : 0 );
}

static size_t ReadInputFile( int16_t buffer[], FILE *fp )
{
    size_t i;

    i = fread( buffer, sizeof( int16_t ), 20, fp );
    SwapBytes( buffer, 18 );
    return( i );
}

static size_t WriteOutputFile( int16_t buffer[], FILE *fp )
{
    size_t i;

    SwapBytes( buffer, 18 );
    i = fwrite( buffer, sizeof( int16_t ), 22, fp );
    return( ( i == 22 ) ? 0 : 1 );
}


static void SwapBytes( int16_t buffer[], int32_t len )
{
    Byte *pc, tmp;
    int32_t i;
    
    if( !ByteOrder())
        return;
    pc = (Byte *)buffer;
    for( i = 0; i < len; i++ ) {
        tmp   = pc[0];
        pc[0] = pc[1];
        pc[1] = tmp;
        pc += 2;
    }
}

static int32_t ByteOrder( void )
{
    int16_t si;
    Byte *pc;

    si = 0x1234;
    pc = (Byte *)&si;
    if (pc[1] == 0x12 && pc[0] == 0x34 )
            return( 0 );
    if (pc[0] == 0x12 && pc[1] == 0x34 )
            return( 1 );
    printf( "Error in ByteOrder: %X, %X\n", (int)pc[0], (int)pc[1] );
    exit( 1 );
    return( 2 );
}

FILE *OpenBinfile( char *name, char *mode )
{
    FILE *fp;

    if( toupper( *mode ) == 'W' ) { /* Write access */
        if(( fp = fopen( name, OPEN_WB )) == NULL ) { 
            printf( "Can't open output file '%s'\n", name );
            exit( 1 );
        }
    } else { /* Read access */
        if(( fp = fopen( name, OPEN_RB )) == NULL ) { 
            printf( "Can't open file '%s'\n", name );
            exit( 1 );
        } 
    }
    return( fp );
}

int32_t Strincmp( const char *s, const char *t, size_t max )
{
    for( ; max > 1; ++s, ++t, --max ) {
        if( toupper( *s ) != toupper( *t ))
            break;
        if( *s == '\0' )
            return( 0 );
    }
    return( toupper( *s ) - toupper( *t ));
}

int32_t Stricmp( const char *s, const char *t )
{
    for(; toupper( *s ) == toupper( *t ); ++s, ++t ) {
        if( *s == '\0' )
            return( 0 );
    }
    return( toupper( *s ) - toupper( *t ));
}

/*************************************************************************
 *
 *   FUNCTION NAME: getPnBits
 *
 *   PURPOSE:
 *     
 *     Generate iBits pseudo-random bits using *pL_PNSeed as the
 *     pn-generators seed.
 *
 *   INPUTS:
 *
 *     iBits - integer indicating how many random bits to return.
 *     range [0,15], 0 yields 1 bit output
 *     
 *     *pL_PNSeed - 32 bit seed (changed by function)
 *     
 *   OUTPUTS:
 *     
 *     *pL_PNSeed - 32 bit seed, modified.
 *     
 *   RETURN VALUE:
 *     
 *    random bits in iBits LSB's.  
 *     
 *     
 *   IMPLEMENTATION:
 *     
 *    implementation of x**31 + x**3 + 1 == PN_XOR_REG | PN_XOR_ADD a
 *    PN sequence generator using int32_ts generating a 2**31 -1
 *    length pn-sequence.
 *
 *************************************************************************/

static int16_t getPnBits(int16_t iBits, int32_t *pL_PNSeed){

#define PN_XOR_REG (int32_t)0x00000005L
#define PN_XOR_ADD (int32_t)0x40000000L

  int16_t swPnBits=0;
  int32_t L_Taps,L_FeedBack;
  int16_t i;

  for (i=0; i < iBits; i++){
    
    /* update the state */                     
    /********************/
    
    L_Taps = *pL_PNSeed & PN_XOR_REG;  
    L_FeedBack = L_Taps; /* Xor tap bits to yield feedback bit */
    L_Taps = L_shr(L_Taps,1);

    while(L_Taps){
      L_FeedBack = L_FeedBack ^ L_Taps;
      L_Taps = L_shr(L_Taps,1);
    }

    /* LSB of L_FeedBack is next MSB of PN register */

    *pL_PNSeed = L_shr(*pL_PNSeed,1);
    if (L_FeedBack & 1)
       *pL_PNSeed = *pL_PNSeed | PN_XOR_ADD;
    
    /* State update complete.  
       Get the output bit from the state, add/or it into output */

    swPnBits = shl(swPnBits,1);
    swPnBits = swPnBits | (*pL_PNSeed & 1);
    
  }
  return(swPnBits);
}


/***************************************************************************
 *
 *   FUNCTION NAME: L_shl
 *
 *   PURPOSE:
 *
 *     Arithmetic shift left (or right).
 *     Arithmetically shift the input left by var2.   If var2 is
 *     negative then an arithmetic shift right (L_shr) of L_var1 by
 *     -var2 is performed.
 *
 *   INPUTS:
 *
 *     var2
 *                     16 bit short signed integer (int16_t) whose value
 *                     falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff.
 *     L_var1
 *                     32 bit long signed integer (int32_t) whose value
 *                     falls in the range
 *                     0x8000 0000 <= L_var1 <= 0x7fff ffff.
 *   OUTPUTS:
 *
 *     none
 *
 *   RETURN VALUE:
 *
 *     L_Out
 *                     32 bit long signed integer (int32_t) whose value
 *                     falls in the range
 *                     0x8000 0000 <= L_var1 <= 0x7fff ffff.
 *
 *
 *   IMPLEMENTATION:
 *
 *     Arithmetically shift the 32 bit input left by var2.  This
 *     operation maintains the sign of the input number. If var2 is
 *     negative then an arithmetic shift right (L_shr) of L_var1 by
 *     -var2 is performed.  See description of L_shr for details.
 *
 *     Equivalent to the Full-Rate GSM ">> n" operation.  Note that
 *     ANSI-C does not guarantee operation of the C ">>" or "<<"
 *     operator for negative numbers.
 *
 *   KEYWORDS: shift, arithmetic shift left,
 *
 *************************************************************************/

int32_t L_shl(int32_t L_var1, int16_t var2)
{

  int32_t L_Mask,
         L_Out;
  int    i,
         iOverflow = 0;

  if (var2 == 0 || L_var1 == 0)
  {
    L_Out = L_var1;
  }
  else if (var2 < 0)
  {
    if (var2 <= -31)
    {
      if (L_var1 > 0)
        L_Out = 0;
      else
        L_Out = 0xffffffffL;
    }
    else
      L_Out = L_shr(L_var1, -var2);
  }
  else
  {

    if (var2 >= 31)
      iOverflow = 1;

    else
    {

      if (L_var1 < 0)
        L_Mask = LW_SIGN;              /* sign bit mask */
      else
        L_Mask = 0x0;
      L_Out = L_var1;
      for (i = 0; i < var2 && !iOverflow; i++)
      {
        /* check the sign bit */
        L_Out = (L_Out & 0x7fffffffL) << 1;
        if ((L_Mask ^ L_Out) & LW_SIGN)
          iOverflow = 1;
      }
    }

    if (iOverflow)
    {
      /* saturate */
      if (L_var1 > 0)
        L_Out = LW_MAX;
      else
        L_Out = LW_MIN;
    }
  }

  return (L_Out);
}

/***************************************************************************
 *
 *   FUNCTION NAME: L_shr
 *
 *   PURPOSE:
 *
 *     Arithmetic shift right (or left).
 *     Arithmetically shift the input right by var2.   If var2 is
 *     negative then an arithmetic shift left (shl) of var1 by
 *     -var2 is performed.
 *
 *   INPUTS:
 *
 *     var2
 *                     16 bit short signed integer (int16_t) whose value
 *                     falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff.
 *     L_var1
 *                     32 bit long signed integer (int32_t) whose value
 *                     falls in the range
 *                     0x8000 0000 <= L_var1 <= 0x7fff ffff.
 *   OUTPUTS:
 *
 *     none
 *
 *   RETURN VALUE:
 *
 *     L_Out
 *                     32 bit long signed integer (int32_t) whose value
 *                     falls in the range
 *                     0x8000 0000 <= L_var1 <= 0x7fff ffff.
 *
 *
 *   IMPLEMENTATION:
 *
 *     Arithmetically shift the input right by var2.  This
 *     operation maintains the sign of the input number. If var2 is
 *     negative then an arithmetic shift left (shl) of L_var1 by
 *     -var2 is performed.  See description of L_shl for details.
 *
 *     The input is a 32 bit number, as is the output.
 *
 *     Equivalent to the Full-Rate GSM ">> n" operation.  Note that
 *     ANSI-C does not guarantee operation of the C ">>" or "<<"
 *     operator for negative numbers.
 *
 *   KEYWORDS: shift, arithmetic shift right,
 *
 *************************************************************************/

int32_t L_shr(int32_t L_var1, int16_t var2)
{

  int32_t L_Mask,
         L_Out;

  if (var2 == 0 || L_var1 == 0)
  {
    L_Out = L_var1;
  }
  else if (var2 < 0)
  {
    /* perform a left shift */
    /*----------------------*/
    if (var2 <= -31)
    {
      /* saturate */
      if (L_var1 > 0)
        L_Out = LW_MAX;
      else
        L_Out = LW_MIN;
    }
    else
      L_Out = L_shl(L_var1, -var2);
  }
  else
  {

    if (var2 >= 31)
    {
      if (L_var1 > 0)
        L_Out = 0;
      else
        L_Out = 0xffffffffL;
    }
    else
    {
      L_Mask = 0;

      if (L_var1 < 0)
      {
        L_Mask = ~L_Mask << (32 - var2);
      }

      L_var1 >>= var2;
      L_Out = L_Mask | L_var1;
    }
  }
  return (L_Out);
}


/***************************************************************************
 *
 *   FUNCTION NAME: shl
 *
 *   PURPOSE:
 *
 *     Arithmetically shift the input left by var2.
 *
 *
 *   INPUTS:
 *
 *     var1
 *                     16 bit short signed integer (int16_t) whose value
 *                     falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff.
 *     var2
 *                     16 bit short signed integer (int16_t) whose value
 *                     falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff.
 *
 *   OUTPUTS:
 *
 *     none
 *
 *   RETURN VALUE:
 *
 *     swOut
 *                     16 bit short signed integer (int16_t) whose value
 *                     falls in the range
 *                     0xffff 8000 <= swOut <= 0x0000 7fff.
 *
 *   IMPLEMENTATION:
 *
 *     If Arithmetically shift the input left by var2.  If var2 is
 *     negative then an arithmetic shift right (shr) of var1 by
 *     -var2 is performed.  See description of shr for details.
 *     When an arithmetic shift left is performed the var2 LS bits
 *     are zero filled.
 *
 *     The only exception is if the left shift causes an overflow
 *     or underflow.  In this case the LS bits are not modified.
 *     The number returned is 0x8000 in the case of an underflow or
 *     0x7fff in the case of an overflow.
 *
 *     The shl is equivalent to the Full-Rate GSM "<< n" operation.
 *     Note that ANSI-C does not guarantee operation of the C ">>"
 *     or "<<" operator for negative numbers - it is not specified
 *     whether this shift is an arithmetic or logical shift.
 *
 *   KEYWORDS: asl, arithmetic shift left, shift
 *
 *************************************************************************/

int16_t shl(int16_t var1, int16_t var2)
{
  int16_t swOut;
  int32_t L_Out;

  if (var2 == 0 || var1 == 0)
  {
    swOut = var1;
  }
  else if (var2 < 0)
  {

    /* perform a right shift */
    /*-----------------------*/

    if (var2 <= -15)
    {
      if (var1 < 0)
        swOut = (int16_t) 0xffff;
      else
        swOut = 0x0;
    }
    else
      swOut = shr(var1, -var2);

  }
  else
  {
    /* var2 > 0 */
    if (var2 >= 15)
    {
      /* saturate */
      if (var1 > 0)
        swOut = SW_MAX;
      else
        swOut = SW_MIN;
    }
    else
    {

      L_Out = (int32_t) var1 *(1 << var2);

      swOut = (int16_t) L_Out;       /* copy low portion to swOut,
                                        * overflow could have hpnd */
      if (swOut != L_Out)
      {
        /* overflow  */
        if (var1 > 0)
          swOut = SW_MAX;              /* saturate */
        else
          swOut = SW_MIN;              /* saturate */
      }
    }
  }
  return (swOut);
}

/***************************************************************************
 *
 *   FUNCTION NAME: shr
 *
 *   PURPOSE:
 *
 *     Arithmetic shift right (or left).
 *     Arithmetically shift the input right by var2.   If var2 is
 *     negative then an arithmetic shift left (shl) of var1 by
 *     -var2 is performed.
 *
 *   INPUTS:
 *
 *     var1
 *                     16 bit short signed integer (int16_t) whose value
 *                     falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff.
 *     var2
 *                     16 bit short signed integer (int16_t) whose value
 *                     falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff.
 *
 *   OUTPUTS:
 *
 *     none
 *
 *   RETURN VALUE:
 *
 *     swOut
 *                     16 bit short signed integer (int16_t) whose value
 *                     falls in the range
 *                     0xffff 8000 <= swOut <= 0x0000 7fff.
 *
 *   IMPLEMENTATION:
 *
 *     Arithmetically shift the input right by var2.  This
 *     operation maintains the sign of the input number. If var2 is
 *     negative then an arithmetic shift left (shl) of var1 by
 *     -var2 is performed.  See description of shl for details.
 *
 *     Equivalent to the Full-Rate GSM ">> n" operation.  Note that
 *     ANSI-C does not guarantee operation of the C ">>" or "<<"
 *     operator for negative numbers.
 *
 *   KEYWORDS: shift, arithmetic shift right,
 *
 *************************************************************************/

int16_t shr(int16_t var1, int16_t var2)
{

  int16_t swMask,
         swOut;

  if (var2 == 0 || var1 == 0)
    swOut = var1;

  else if (var2 < 0)
  {
    /* perform an arithmetic left shift */
    /*----------------------------------*/
    if (var2 <= -15)
    {
      /* saturate */
      if (var1 > 0)
        swOut = SW_MAX;
      else
        swOut = SW_MIN;
    }
    else
      swOut = shl(var1, -var2);
  }

  else
  {

    /* positive shift count */
    /*----------------------*/

    if (var2 >= 15)
    {
      if (var1 < 0)
        swOut = (int16_t) 0xffff;
      else
        swOut = 0x0;
    }
    else
    {
      /* take care of sign extension */
      /*-----------------------------*/

      swMask = 0;
      if (var1 < 0)
      {
        swMask = ~swMask << (16 - var2);
      }

      var1 >>= var2;
      swOut = swMask | var1;

    }
  }
  return (swOut);
}

/*___________________________________________________________________________
 |                                                                           |
 |     This subroutine calculates the 'SID flag'                             |
 |                                                                           |
 |     Input:     pswParameters[18]                                          |
 |                           input parameters of the speech decoder          |
 |                                                                           |
 |                pswErrorFlag[3]                                            |
 |                           error flags, generated by channel decoder       |
 |                                                                           |
 |     Return Value:                                                         |
 |                0:         speech frame detected                           |
 |                1:         most likely SID frame received                  |
 |                2:         SID frame detected                              |
 |                                                                           |
 |___________________________________________________________________________|
 |                                                                           |
 |     History:                                                              |
 |                                                                           |
 |     12-Oct-1994: Bug removed: error corrected in case of a mode (unvoiced/|
 |                  voiced) mismatch, if a SID frame was received as an      |
 |                  unvoiced frame                                           |
 |___________________________________________________________________________|
*/

static int16_t swSidDetection(int16_t pswParameters[],
                                int16_t pswErrorFlag[])
{
  static int16_t ppswIBit[2][18] = {
        5, 11,9,8, 1, 2, 7,7,5, 7,7,5, 7,7,5, 7,7,5,  /* unvoiced */
        5, 11,9,8, 1, 2, 8,9,5, 4,9,5, 4,9,5, 4,9,5}; /* voiced */

  static int16_t ppswCL1pCL2[2][18] = {
                              0x0001, /* R0      */  /* unvoiced */
                              0x00ef, /* LPC1    */
                              0x003e, /* LPC2    */
                              0x007f, /* LPC3    */
                              0x0001, /* INT LPC */
                              0x0003, /* Mode    */
                              0x001f, /* Code1_1 */
                              0x0072, /* Code2_1 */
                              0x0012, /* GSP0_1  */
                              0x003f, /* Code1_2 */
                              0x007f, /* Code2_2 */
                              0x0008, /* GSP0_2  */
                              0x007f, /* Code1_3 */
                              0x007f, /* Code2_3 */
                              0x0008, /* GSP0_3  */
                              0x007f, /* Code1_4 */
                              0x007f, /* Code2_4 */
                              0x000c, /* GSP0_4  */
                              
                              0x0000, /* R0      */  /* voiced */
                              0x0000, /* LPC1    */
                              0x0000, /* LPC2    */
                              0x0000, /* LPC3    */
                              0x0001, /* INT LPC */
                              0x0003, /* Mode    */
                              0x00ff, /* Lag_1   */
                              0x01ff, /* Code_1  */
                              0x001f, /* GSP0_1  */
                              0x000f, /* Lag_2   */
                              0x01ff, /* Code_2  */
                              0x001f, /* GSP0_2  */
                              0x000f, /* Lag_3   */
                              0x01ff, /* Code_3  */
                              0x001f, /* GSP0_3  */
                              0x000f, /* Lag_4   */
                              0x01ff, /* Code_4  */
                              0x001f}; /* GSP0_4 */

  static int16_t ppswCL2[2][18] = {
                              0x0000, /* R0      */ /* unvoiced */
                              0x0000, /* LPC1    */
                              0x0000, /* LPC2    */
                              0x0000, /* LPC3    */
                              0x0000, /* INT LPC */
                              0x0000, /* Mode    */ 
                              0x0000, /* Code1_1 */
                              0x0000, /* Code2_1 */
                              0x0000, /* GSP0_1  */
                              0x0000, /* Code1_2 */
                              0x0000, /* Code2_2 */
                              0x0000, /* GSP0_2  */
                              0x0000, /* Code1_3 */
                              0x0007, /* Code2_3 */  /* 3 bits */
                              0x0000, /* GSP0_3  */
                              0x007f, /* Code1_4 */  /* 7 bits */
                              0x007f, /* Code2_4 */  /* 7 bits */
                              0x0000, /* GSP0_4  */

                              0x0000, /* R0      */  /* voiced */
                              0x0000, /* LPC1    */
                              0x0000, /* LPC2    */
                              0x0000, /* LPC3    */
                              0x0000, /* INT LPC */
                              0x0000, /* Mode    */
                              0x0000, /* Lag_1   */
                              0x0000, /* Code_1  */
                              0x0000, /* GSP0_1  */
                              0x0000, /* Lag_2   */
                              0x0000, /* Code_2  */
                              0x0000, /* GSP0_2  */
                              0x0000, /* Lag_3   */
                              0x00ff, /* Code_3  */  /* 8 bits */
                              0x0000, /* GSP0_3  */
                              0x0000, /* Lag_4   */
                              0x01ff, /* Code_4  */  /* 9 bits */
                              0x0000}; /* GSP0_4 */

  static int first = 1;

  int16_t swMode, swBitMask;
  int16_t swSidN1, swSidN2, swSidN1pN2;
  int16_t swSid ;

  short siI, siII;


  if (first)
  {
    /* Force Sid codewords to be represented */
    /* internally in PC byte order           */
    /* ------------------------------------- */

    SwapBytes(ppswCL1pCL2[0], 18);
    SwapBytes(ppswCL1pCL2[1], 18);
    SwapBytes(ppswCL2[0], 18);
    SwapBytes(ppswCL2[1], 18);

    first = 0;
  }


  /* count transmission errors within the SID codeword      */
  /* count number of bits equal '0' within the SID codeword */
  /* ------------------------------------------------------ */

  if (pswParameters[5] == 0)
    swMode = 0;
  else 
    swMode = 1;
  

  swSidN1pN2 = 0;         /* N1 + N2 */
  swSidN2    = 0;
  swSidN1    = 0;
  
  for (siI = 0; siI < 18; siI++) {
      swBitMask = 0x0001;
      SwapBytes(&swBitMask, 1);  /* force swBitMask to PC byte order */
      for (siII = 0; siII < ppswIBit[swMode][siI]; siII++) {
        if ( (pswParameters[siI] & swBitMask) == 0 ) {
          if ( (ppswCL1pCL2[swMode][siI] & swBitMask) != 0 ) swSidN1pN2++;
          if ( (ppswCL2[swMode][siI] & swBitMask)     != 0 ) swSidN2++;
        }
        SwapBytes(&swBitMask, 1);  /* return swBitMask to native byte order */
        swBitMask = swBitMask << 1;
        SwapBytes(&swBitMask, 1);  /* force swBitMask to PC byte order */
      }
  }

  swSidN1 = swSidN1pN2 - swSidN2;


  /* frame classification */
  /* -------------------- */

  if (pswErrorFlag[2]) {

    if (swSidN1 < 3)
       swSid = 2;
    else if (swSidN1pN2 < 16)
       swSid = 1;
    else
       swSid = 0;
     
    if ( (swSidN1pN2 >= 16) && (swSidN1pN2 <= 25) ) {
      pswErrorFlag[0] = 1;     
    }

  }
  else {

    if (swSidN1 < 3)
       swSid = 2;
    else if (swSidN1pN2 < 11)
       swSid = 1;
    else
       swSid = 0;

  }


  /* in case of a mode mismatch */
  /*----------------------------*/
  
  if ( (swSid == 2) && (swMode == 0) ) swSid = 1;

  return(swSid);

}


/*___________________________________________________________________________
 |                                                                           |
 |     This subroutine sets the 18 speech parameters to random values        |
 |                                                                           |
 |     Input:     pswParameters[18]                                          |
 |                           input parameters of the speech decoder          |
 |                                                                           |
 |___________________________________________________________________________|
*/

static void RandomParameters(int16_t pswParameters[])
{
  static int16_t ppswIBit[2][18] = {
             5, 11,9,8, 1, 2, 7,7,5, 7,7,5, 7,7,5, 7,7,5,  /* unvoiced */
             5, 11,9,8, 1, 2, 8,9,5, 4,9,5, 4,9,5, 4,9,5}; /* voiced */

  static int32_t L_PNSeed=(int32_t)0x1091988L;
  int16_t  i,ind;

  /* Determine mode bit */
  /* ------------------ */
  pswParameters[5] = getPnBits(2, &L_PNSeed);

  /* Switch bit allocation accordingly */
  /* --------------------------------- */
  ind = 0;
  if (pswParameters[5] > 0) ind = 1;

  for (i=0; i < 5; i++){
     pswParameters[i] = getPnBits(ppswIBit[ind][i], &L_PNSeed);
  }
  for (i=6; i < 18; i++){
     pswParameters[i] = getPnBits(ppswIBit[ind][i], &L_PNSeed);
  }

  /* force random parameters to PC byte order */
  /* ---------------------------------------- */

  SwapBytes(pswParameters, 18);  
}

/*___________________________________________________________________________
 |                                                                           |
 |     Main - Program                                                        |
 |                                                                           |
 |___________________________________________________________________________|
*/
int main( int argc, char *argv[] )
{
    FILE *infile, *outfile;
    int16_t errpat, i = 0;

    if( argc < 4 || argc > 4 ) {
        fprintf( stderr, "\tUsage: REID input output EPx \n" );
        fprintf( stderr, "\tEPx: EP0\n" );
        fprintf( stderr, "\t     EP1 (not implemented)\n" );
        fprintf( stderr, "\t     EP2 (not implemented)\n" );
        fprintf( stderr, "\t     EP3 (not implemented)\n" );
        return( 1 );
    }


    if( !Strincmp( argv[3], "ep", 2 )) 
        errpat  = atoi( &argv[3][2] );

    printf( "  _____________________________________________\n" );
    printf( " |                                             |\n" );
    printf( " |       Residual Error Insertion Device       |\n" );
    printf( " |                 for                         |\n" );
    printf( " |       GSM Half-Rate Codec Simulation        |\n" );
    printf( " |                                             |\n" );
    printf( " |_____________________________________________|\n\n" );

    printf( "    Input File       : %s\n", argv[1] );
    printf( "    Output File      : %s\n", argv[2] );
    if( errpat ){
        printf( "    Error Pattern    : EP%d (not implemented)\n", errpat);
        return (1);
    }
    else
        printf( "    Error Pattern    : EP%d (error free)\n", errpat );
    printf( "\n" );

    infile  = OpenBinfile( argv[1], "r" );
    outfile = OpenBinfile( argv[2], "w" );


    if (errpat == 0) {
       for (i=0;i<6000;i++)
           if( error_free( infile, outfile)) break;
    }
    /*else
       for (i=0;i<6000;i++)
           if( residual_error_pattern( infile, outfile)) break;
        EP1-3 not implemented */

    fclose( infile );
    fclose( outfile );

    printf( " %d Frame%s processed      \n\n", i,( i != 1 ) ? "s" : "" ); 
    return( 0 );
}
