shithub: aacenc

Download patch

ref: 4da5aaebe94a8a13ceea2c001b1fd5161ef33e9b
parent: 07a18e8f102dd3d94d93f8f65da5da2f293ca294
author: menno <menno>
date: Wed May 2 01:40:16 EDT 2001

Added support for MAIN AAC object type

--- a/frontend/main.c
+++ b/frontend/main.c
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * $Id: main.c,v 1.14 2001/04/19 13:20:33 menno Exp $
+ * $Id: main.c,v 1.15 2001/05/02 05:39:14 menno Exp $
  */
 
 #ifdef _WIN32
@@ -74,7 +74,7 @@
 	{
 		printf("USAGE: %s -options infile outfile\n", argv[0]);
 		printf("Options:\n");
-		printf("  -pX   AAC object type, X=LC2 gives MPEG2 LC,");
+		printf("  -pX   AAC object type, X=LC2 gives MPEG2 LC,\n");
 		printf("        X=LC4 gives MPEG4 LC and X=LTP gives LTP\n");
 		printf("  -nm   Don\'t use mid/side coding\n");
 		printf("  -tns  Use TNS coding\n");
--- /dev/null
+++ b/libfaac/backpred.c
@@ -1,0 +1,426 @@
+/*
+ * FAAC - Freeware Advanced Audio Coder
+ * Copyright (C) 2001 Menno Bakker
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: backpred.c,v 1.1 2001/05/02 05:40:15 menno Exp $
+ */
+
+/**********************************************************************
+
+INPUT:
+act_spec[]: the current frame's spectral components to be encoded.
+last_spec[]: the previous frame's quantized spectral error components 
+btype: the current frame's window type
+nsfb: the number of scalefactor bands
+isfb_width[]: scalefactor bandwidth
+
+OUTPUT:
+act_spec[]: the current frame's spectral error components to be encoded
+pred_global_flag: global prediction enable/disable flag
+pred_sbf_glag[]: enable/disable flag for each scalefactor band
+reset_group: number for the reset group => if -1, then no reset
+***********************************************************************/
+
+#include <math.h>
+#include "coder.h"
+#include "channels.h"
+#include "backpred.h"
+
+/* Make these work for mulitchannels */  /* CL, 1/98 */
+/*static int psy_init = 0;
+static float dr[LPC][FLEN_LONG/2],e[LPC+1+1][FLEN_LONG/2];
+static float K[LPC+1][FLEN_LONG/2], R[LPC+1][FLEN_LONG/2];
+static float VAR[LPC+1][FLEN_LONG/2], KOR[LPC+1][FLEN_LONG/2];
+static float sb_samples_pred[FLEN_LONG/2];
+static int thisLineNeedsResetting[FLEN_LONG/2];
+static int reset_count = 0;*/
+
+
+static int psy_init_mc[MAX_CHANNELS];
+static float dr_mc[MAX_CHANNELS][LPC][FLEN_LONG/2],e_mc[MAX_CHANNELS][LPC+1+1][FLEN_LONG/2];
+static float K_mc[MAX_CHANNELS][LPC+1][FLEN_LONG/2], R_mc[MAX_CHANNELS][LPC+1][FLEN_LONG/2];
+static float VAR_mc[MAX_CHANNELS][LPC+1][FLEN_LONG/2], KOR_mc[MAX_CHANNELS][LPC+1][FLEN_LONG/2];
+static float sb_samples_pred_mc[MAX_CHANNELS][FLEN_LONG/2];
+static int thisLineNeedsResetting_mc[MAX_CHANNELS][FLEN_LONG/2];
+static int reset_count_mc[MAX_CHANNELS];
+
+/* Max prediction band as function of fs index */
+int MAX_PRED_SFB[][2] = {
+		     {96000,33},
+		     {88200,33},
+		     {64000,38},
+		     {48000,40},
+		     {44100,40},
+		     {32000,40},
+		     {24000,41},
+		     {22050,41}, 
+		     {16000,37}, 
+		     {12000,37}, 
+		     {11025,37},
+			 {8000,34},
+		     {-1,0}};
+
+int GetMaxPredSfb(int samplingRateIdx)
+{
+	return MAX_PRED_SFB[samplingRateIdx][1];
+}
+
+
+
+void PredInit()
+{
+	int i;
+
+	for (i=0;i<MAX_CHANNELS;i++) {
+		psy_init_mc[i] = 0;
+		reset_count_mc[i] = 0;
+	}
+}
+ 
+void PredCalcPrediction( double *act_spec, double *last_spec, int btype, 
+			int nsfb, 
+			int *isfb_width, 
+			CoderInfo *coderInfo,
+			ChannelInfo *channelInfo,                  /* Pointer to Ch_Info */
+			int chanNum) 
+{
+  int i, k, j, cb_long;
+  int leftChanNum;
+  int isRightWithCommonWindow;
+  float small, small_p, num_bit, snr[SBMAX_L];
+  float energy[FLEN_LONG/2], snr_p[FLEN_LONG/2], temp1, temp2;
+  ChannelInfo *thisChannel;
+
+  /* Set pointers for specified channel number */
+  /* int psy_init; */
+  int *psy_init;
+  float (*dr)[FLEN_LONG/2],(*e)[FLEN_LONG/2];
+  float (*K)[FLEN_LONG/2], (*R)[FLEN_LONG/2];
+  float (*VAR)[FLEN_LONG/2], (*KOR)[FLEN_LONG/2];
+  float *sb_samples_pred;
+  int *thisLineNeedsResetting;
+  /* int reset_count; */
+  int *reset_count;
+  int *pred_global_flag;
+  int *pred_sfb_flag;
+  int *reset_group;
+
+  /* Set pointers for this chanNum */
+  pred_global_flag = &(coderInfo[chanNum].pred_global_flag);
+  pred_sfb_flag = coderInfo[chanNum].pred_sfb_flag;
+  reset_group = &(coderInfo[chanNum].reset_group_number);
+  /* psy_init = psy_init_mc[chanNum]; */
+  psy_init = &psy_init_mc[chanNum];
+  dr = &dr_mc[chanNum][0];
+  e = &e_mc[chanNum][0];
+  K = &K_mc[chanNum][0]; 
+  R = &R_mc[chanNum][0];
+  VAR = &VAR_mc[chanNum][0];
+  KOR = &KOR_mc[chanNum][0];
+  sb_samples_pred = &sb_samples_pred_mc[chanNum][0];
+  thisLineNeedsResetting = &thisLineNeedsResetting_mc[chanNum][0];
+  reset_count = &reset_count_mc[chanNum];
+
+  thisChannel = &(channelInfo[chanNum]);
+  *psy_init = (*psy_init && (btype!=2));
+
+  if((*psy_init) == 0) {
+    for (j=0; j<FLEN_LONG/2; j++) {
+      thisLineNeedsResetting[j]=1;
+    }
+    *psy_init = 1;
+  }
+
+  if (btype==2) {
+    pred_global_flag[0]=0;
+    /* SHORT WINDOWS reset all the co-efficients    */
+    if (thisChannel->ch_is_left) {
+      (*reset_count)++;
+      if (*reset_count >= 31 * RESET_FRAME)
+	*reset_count = RESET_FRAME;
+      /*    *reset_count = ((*reset_count) / RESET_FRAME) * RESET_FRAME;*/
+    }
+    return;
+  }
+
+
+  /**************************************************/
+  /*  Compute state using last_spec                 */
+  /**************************************************/
+  for (i=0;i<FLEN_LONG/2;i++) 
+    {
+      /* e[0][i]=last_spec[i]; */ 
+      e[0][i]=last_spec[i]+sb_samples_pred[i];
+      
+      for(j=1;j<=LPC;j++)
+	e[j][i] = e[j-1][i]-K[j][i]*R[j-1][i];
+      
+      for(j=1;j<LPC;j++) 
+	dr[j][i] = K[j][i]*e[j-1][i];
+      
+      for(j=1;j<=LPC;j++) {
+	VAR[j][i] = ALPHA*VAR[j][i]+.5*(R[j-1][i]*R[j-1][i]+e[j-1][i]*e[j-1][i]);
+	KOR[j][i] = ALPHA*KOR[j][i]+R[j-1][i]*e[j-1][i];
+      }
+
+      for(j=LPC-1;j>=1;j--) 
+	R[j][i] = A*(R[j-1][i]-dr[j][i]);
+      R[0][i] = A*e[0][i];
+    }
+
+
+  /**************************************************/
+  /* Reset state here if resets were sent           */
+  /**************************************************/
+   for (i=0;i<FLEN_LONG/2;i++) {
+     if (thisLineNeedsResetting[i]) {
+       for (j = 0; j <= LPC; j++)
+	 {
+	   K[j][i] = 0.0;
+	   e[j][i] = 0.0;
+	   R[j][i] = 0.0;
+	   VAR[j][i] = 1.0;
+	   KOR[j][i] = 0.0;
+	   dr[j][i] = 0.0;
+	 }
+     }
+   }
+
+
+
+  /**************************************************/
+  /* Compute predictor coefficients, predicted data */
+  /**************************************************/
+   for (i=0;i<FLEN_LONG/2;i++) 
+    {
+      for(j=1;j<=LPC;j++) {
+	if(VAR[j][i]>MINVAR)
+	  K[j][i] = KOR[j][i]/VAR[j][i]*B;
+	else
+	  K[j][i] = 0;
+      }
+    }
+
+
+   for (k=0; k<FLEN_LONG/2; k++)
+    {
+      sb_samples_pred[k]=0.0;
+      for (i=1; i<=LPC; i++)
+	sb_samples_pred[k]+=K[i][k]*R[i-1][k];
+    }
+
+
+  /***********************************************************/
+  /* If this is the right channel of a channel_pair_element, */
+  /* AND common_window is 1 in this channel_pair_element,    */
+  /* THEN copy predictor data to use from the left channel.  */
+  /* ELSE determine independent predictor data and resets.   */
+  /***********************************************************/
+  /* BE CAREFUL HERE, this assumes that predictor data has   */
+  /* already been determined for the left channel!!          */
+  /***********************************************************/
+  isRightWithCommonWindow = 0;     /* Is this a right channel with common_window?*/
+  if ((thisChannel->cpe)&&( !(thisChannel->ch_is_left))) {
+    leftChanNum = thisChannel->paired_ch;
+    if (channelInfo[leftChanNum].common_window) {
+      isRightWithCommonWindow = 1;
+    }
+  }
+
+  if (isRightWithCommonWindow) {
+    
+    /**************************************************/
+    /* Use predictor data from the left channel.      */
+    /**************************************************/
+    CopyPredInfo(&(coderInfo[chanNum]),&(coderInfo[leftChanNum]));
+
+    /* Make sure to turn off bands with intensity stereo */
+#if 0
+    if (thisChannel->is_info.is_present) {
+		for (i=0; i<nsfb; i++) {
+			if (thisChannel->is_info.is_used[i]) {
+				pred_sfb_flag[i] = 0;
+			}
+		}
+    }
+#endif
+    
+    cb_long=0;
+    for (i=0; i<nsfb; i++)
+      {
+	if (!pred_sfb_flag[i]) {
+	  for (j=cb_long; j<cb_long+isfb_width[i]; j++)
+	    sb_samples_pred[j]=0.0; 
+	}
+	cb_long+=isfb_width[i];
+      }
+    
+    /* Disable prediction for bands nsfb through SBMAX_L */ 
+    for (i=j;i<FLEN_LONG/2;i++) {
+      sb_samples_pred[i]=0.0;
+    }
+    for (i=nsfb;i<SBMAX_L;i++) {
+      pred_sfb_flag[i]=0;
+    }
+    
+    /* Is global enable set, if not enabled predicted samples are zeroed */
+    if(!pred_global_flag[0]) {
+      for (j=0; j<FLEN_LONG/2; j++)
+	sb_samples_pred[j]=0.0; 
+    }
+    for (j=0; j<FLEN_LONG/2; j++)
+      act_spec[j]-=sb_samples_pred[j];
+    
+  } else {
+
+    /**************************************************/
+    /* Determine whether to enable/disable prediction */
+    /**************************************************/
+    
+    for (k=0; k<FLEN_LONG/2; k++)
+      {energy[k]=act_spec[k]*act_spec[k];
+       snr_p[k]=(act_spec[k]-sb_samples_pred[k])*(act_spec[k]-sb_samples_pred[k]);
+     }
+    
+    cb_long=0;
+    for (i=0; i<nsfb; i++)
+      {
+	pred_sfb_flag[i]=1;
+	temp1=0.0;
+	temp2=0.0;
+	for (j=cb_long; j<cb_long+isfb_width[i]; j++)
+	  {temp1+=energy[j]; temp2+=snr_p[j];}
+	if(temp2<1.e-20) temp2=1.e-20;
+	if(temp1!=0.0) {snr[i]=-10.*log10((double ) temp2/temp1);}
+	else snr[i]=0.0;
+	if(snr[i]<=0.0) {pred_sfb_flag[i]=0; 
+			 for (j=cb_long; j<cb_long+isfb_width[i]; j++)
+			   sb_samples_pred[j]=0.0; }
+	cb_long+=isfb_width[i];
+      }
+    
+    /* Disable prediction for bands nsfb through SBMAX_L */ 
+    for (i=j;i<FLEN_LONG/2;i++) {
+      sb_samples_pred[i]=0.0;
+    }
+    for (i=nsfb;i<SBMAX_L;i++) {
+      pred_sfb_flag[i]=0;
+    }
+
+    num_bit=0.0;
+    for (i=0; i<nsfb; i++)
+      if(snr[i]>0.0) num_bit+=snr[i]/6.*isfb_width[i];	
+    
+    /* Determine global enable, if not enabled predicted samples are zeroed */
+    pred_global_flag[0]=1;
+    if(num_bit<50) {
+      pred_global_flag[0]=0; num_bit=0.0; 
+      for (j=0; j<FLEN_LONG/2; j++)
+	sb_samples_pred[j]=0.0; 
+    }
+    for (j=0; j<FLEN_LONG/2; j++)
+      act_spec[j]-=sb_samples_pred[j];
+    
+  }
+  
+  /**********************************************************/
+  /* If this is a left channel, determine pred resets.      */
+  /* If this is a right channel, using pred reset data from */
+  /* left channel.  Keep left and right resets in sync.     */
+  /**********************************************************/
+  if ((thisChannel->cpe)&&( !(thisChannel->ch_is_left))) {
+    /*  if (!thisChannel->ch_is_left) {*/
+    /**********************************************************/
+    /* Using predictor reset data from the left channel.      */
+    /**********************************************************/
+    reset_count = &reset_count_mc[leftChanNum];
+    /* Reset the frame counter */
+    for (i=0;i<FLEN_LONG/2;i++) {
+      thisLineNeedsResetting[i]=0;
+    }
+    reset_group = &(coderInfo[chanNum].reset_group_number);
+    if (*reset_count % RESET_FRAME == 0)
+      { /* Send a reset in this frame */
+	*reset_group = *reset_count / 8;
+	for (i = *reset_group - 1; i < FLEN_LONG / 2; i += 30)
+	  {
+	    thisLineNeedsResetting[i]=1;
+	  }
+      }
+    else
+      *reset_group = -1;
+  } else {
+    /* Code segment added by JB */
+    /******************************************************************/
+    /* Determine whether a prediction reset is required - if so, then */
+    /* set reset flag for the appropriate group.                      */
+    /******************************************************************/
+    
+    /* Increase counter on left channel, keep left and right resets in sync */
+    (*reset_count)++;
+
+    /* Reset the frame counter */
+    for (i=0;i<FLEN_LONG/2;i++) {
+      thisLineNeedsResetting[i]=0;
+    }
+    if (*reset_count >= 31 * RESET_FRAME)
+      *reset_count = RESET_FRAME;
+    if (*reset_count % RESET_FRAME == 0)
+      { /* Send a reset in this frame */
+	*reset_group = *reset_count / 8;
+	for (i = *reset_group - 1; i < FLEN_LONG / 2; i += 30)
+	  {
+	    thisLineNeedsResetting[i]=1;
+	  }
+      }
+    else
+      *reset_group = -1;
+    /* End of code segment */
+ }
+
+
+  /* Code segment added by JB */
+
+  /* Ensure that prediction data is sent when there is a prediction
+   * reset.
+   */
+  if (*reset_group != -1 && pred_global_flag[0] == 0)
+    {
+      pred_global_flag[0] = 1;
+      for (i = 0; i < nsfb; i++)
+	pred_sfb_flag[i] = 0;
+    }
+  /* End of code segment */
+  
+}
+
+
+void CopyPredInfo(CoderInfo *right, CoderInfo *left)
+{
+	int band;
+
+	right->pred_global_flag = left->pred_global_flag;
+	right->reset_group_number = left->reset_group_number;
+
+	for (band = 0; band<MAX_SCFAC_BANDS; band++) {
+		right->pred_sfb_flag[band] = left->pred_sfb_flag[band];
+	}
+}
+
+
+
+
--- /dev/null
+++ b/libfaac/backpred.h
@@ -1,0 +1,56 @@
+/*
+ * FAAC - Freeware Advanced Audio Coder
+ * Copyright (C) 2001 Menno Bakker
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: backpred.h,v 1.1 2001/05/02 05:40:16 menno Exp $
+ */
+
+#ifndef _AAC_BACK_H_INCLUDED
+#define _AAC_BACK_H_INCLUDED
+
+#define PRED_ALPHA	0.90625
+#define PRED_A		0.953125
+#define PRED_B		0.953125
+
+#define         FLEN_LONG              2048
+#define         SBMAX_L                49
+#define         LPC                    2
+#define         ALPHA                  PRED_ALPHA
+#define         A                      PRED_A
+#define         B                      PRED_B
+#define         MINVAR                 1.e-10
+
+/* Reset every RESET_FRAME frames. */
+#define		RESET_FRAME	       8 
+ 
+int GetMaxPredSfb(int samplingRateIdx);
+
+void PredCalcPrediction( double *act_spec, 
+			 double *last_spec, 
+			 int btype, 
+			 int nsfb, 
+			 int *isfb_width,
+			 CoderInfo *coderInfo,
+			 ChannelInfo *channelInfo,
+			 int chanNum); 
+
+void PredInit();
+
+void CopyPredInfo(CoderInfo *right, CoderInfo *left);
+
+
+#endif
--- a/libfaac/bitstream.c
+++ b/libfaac/bitstream.c
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * $Id: bitstream.c,v 1.13 2001/04/19 13:20:34 menno Exp $
+ * $Id: bitstream.c,v 1.14 2001/05/02 05:39:14 menno Exp $
  */
 
 #include <stdlib.h>
@@ -54,6 +54,7 @@
 					bits += WriteLFE(&coderInfo[channel],
 						&channelInfo[channel],
 						bitStream,
+						hEncoder->config.aacObjectType,
 						1);
 				} else {
 					/* Write out sce */
@@ -60,6 +61,7 @@
 					bits += WriteSCE(&coderInfo[channel],
 						&channelInfo[channel],
 						bitStream,
+						hEncoder->config.aacObjectType,
 						1);
 				}
 
@@ -71,6 +73,7 @@
 						&coderInfo[channelInfo[channel].paired_ch],
 						&channelInfo[channel],
 						bitStream,
+						hEncoder->config.aacObjectType,
 						1);
 				}
 			}
@@ -130,6 +133,7 @@
 					bits += WriteLFE(&coderInfo[channel],
 						&channelInfo[channel],
 						bitStream,
+						hEncoder->config.aacObjectType,
 						0);
 				} else {
 					/* Write out sce */
@@ -136,6 +140,7 @@
 					bits += WriteSCE(&coderInfo[channel],
 						&channelInfo[channel],
 						bitStream,
+						hEncoder->config.aacObjectType,
 						0);
 				}
 
@@ -147,6 +152,7 @@
 						&coderInfo[channelInfo[channel].paired_ch],
 						&channelInfo[channel],
 						bitStream,
+						hEncoder->config.aacObjectType,
 						0);
 				}
 			}
@@ -230,6 +236,7 @@
 					CoderInfo *coderInfoR,
 					ChannelInfo *channelInfo,
 					BitStream* bitStream,
+					int objectType,
 					int writeFlag)
 {
 	int bits = 0;
@@ -253,7 +260,7 @@
 	if (channelInfo->common_window) {
 		int numWindows, maxSfb;
 
-		bits += WriteICSInfo(coderInfoL, bitStream, writeFlag);
+		bits += WriteICSInfo(coderInfoL, bitStream, objectType, writeFlag);
 		numWindows = coderInfoL->num_window_groups;
 		maxSfb = coderInfoL->max_sfb;
 
@@ -275,8 +282,8 @@
 	}
 
 	/* Write individual_channel_stream elements */
-	bits += WriteICS(coderInfoL, bitStream, channelInfo->common_window, writeFlag);
-	bits += WriteICS(coderInfoR, bitStream, channelInfo->common_window, writeFlag);
+	bits += WriteICS(coderInfoL, bitStream, channelInfo->common_window, objectType, writeFlag);
+	bits += WriteICS(coderInfoR, bitStream, channelInfo->common_window, objectType, writeFlag);
 
 	return bits;
 }
@@ -284,6 +291,7 @@
 static int WriteSCE(CoderInfo *coderInfo,
 					ChannelInfo *channelInfo,
 					BitStream *bitStream,
+					int objectType,
 					int writeFlag)
 {
 	int bits = 0;
@@ -300,7 +308,7 @@
 	bits += LEN_TAG;
 
 	/* Write an Individual Channel Stream element */
-	bits += WriteICS(coderInfo, bitStream, 0, writeFlag);
+	bits += WriteICS(coderInfo, bitStream, 0, objectType, writeFlag);
 
 	return bits;
 }
@@ -308,6 +316,7 @@
 static int WriteLFE(CoderInfo *coderInfo,
 					ChannelInfo *channelInfo,
 					BitStream *bitStream,
+					int objectType,
 					int writeFlag)
 {
 	int bits = 0;
@@ -324,7 +333,7 @@
 	bits += LEN_TAG;
 
 	/* Write an individual_channel_stream element */
-	bits += WriteICS(coderInfo, bitStream, 0, writeFlag);
+	bits += WriteICS(coderInfo, bitStream, 0, objectType, writeFlag);
 
 	return bits;
 }
@@ -331,6 +340,7 @@
 
 static int WriteICSInfo(CoderInfo *coderInfo,
 						BitStream *bitStream,
+						int objectType,
 						int writeFlag)
 {
 	int grouping_bits;
@@ -365,8 +375,10 @@
 			PutBit(bitStream, coderInfo->max_sfb, LEN_MAX_SFBL);
 		}
 		bits += LEN_MAX_SFBL;
-		bits += WriteLTPPredictorData(coderInfo, bitStream, writeFlag);
-		/* bits += WritePredictorData(coderInfo, bitStream, writeFlag); */
+		if (objectType == LTP)
+			bits += WriteLTPPredictorData(coderInfo, bitStream, writeFlag);
+		else
+			bits += WritePredictorData(coderInfo, bitStream, writeFlag);
 	}
 
 	return bits;
@@ -375,6 +387,7 @@
 static int WriteICS(CoderInfo *coderInfo,
 					BitStream *bitStream,
 					int commonWindow,
+					int objectType,
 					int writeFlag)
 {
 	/* this function writes out an individual_channel_stream to the bitstream and */
@@ -388,7 +401,7 @@
 
 	/* Write ics information */
 	if (!commonWindow) {
-		bits += WriteICSInfo(coderInfo, bitStream, writeFlag);
+		bits += WriteICSInfo(coderInfo, bitStream, objectType, writeFlag);
 	}
 
 	bits += SortBookNumbers(coderInfo, bitStream, writeFlag);
@@ -446,6 +459,42 @@
 	}
 
 	return (bits);
+}
+
+static int WritePredictorData(CoderInfo *coderInfo,
+							  BitStream *bitStream,
+							  int writeFlag)
+{
+	int bits = 0;
+
+	/* Write global predictor data present */
+	short predictorDataPresent = coderInfo->pred_global_flag;
+	int numBands = min(coderInfo->max_pred_sfb, coderInfo->nr_of_sfb);
+
+	if (writeFlag) {
+		PutBit(bitStream, predictorDataPresent, LEN_PRED_PRES);  /* predictor_data_present */
+		if (predictorDataPresent) {
+			int b;
+			if (coderInfo->reset_group_number == -1) {
+				PutBit(bitStream, 0, LEN_PRED_RST); /* No prediction reset */
+			} else {
+				PutBit(bitStream, 1, LEN_PRED_RST);
+				PutBit(bitStream, (unsigned long)coderInfo->reset_group_number,
+					LEN_PRED_RSTGRP);
+			}
+
+			for (b=0;b<numBands;b++) {
+				PutBit(bitStream, coderInfo->pred_sfb_flag[b], LEN_PRED_ENAB);
+			}
+		}
+	}
+	bits = LEN_PRED_PRES;
+	bits += (predictorDataPresent) ?
+		(LEN_PRED_RST + 
+		((coderInfo->reset_group_number)!=-1)*LEN_PRED_RSTGRP + 
+		numBands*LEN_PRED_ENAB) : 0;
+
+	return bits;
 }
 
 static int WritePulseData(CoderInfo *coderInfo,
--- a/libfaac/bitstream.h
+++ b/libfaac/bitstream.h
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * $Id: bitstream.h,v 1.5 2001/04/19 13:20:34 menno Exp $
+ * $Id: bitstream.h,v 1.6 2001/05/02 05:39:14 menno Exp $
  */
 
 #ifndef BITSTREAM_H
@@ -144,30 +144,39 @@
 					CoderInfo *coderInfoR,
 					ChannelInfo *channelInfo,
 					BitStream* bitStream,
+					int objectType,
 					int writeFlag);
 
 static int WriteSCE(CoderInfo *coderInfo,
 					ChannelInfo *channelInfo,
 					BitStream *bitStream,
+					int objectType,
 					int writeFlag);
 
 static int WriteLFE(CoderInfo *coderInfo,
 					ChannelInfo *channelInfo,
 					BitStream *bitStream,
+					int objectType,
 					int writeFlag);
 
 static int WriteICSInfo(CoderInfo *coderInfo,
 						BitStream *bitStream,
+						int objectType,
 						int writeFlag);
 
 static int WriteICS(CoderInfo *coderInfo,
 					BitStream *bitStream,
 					int commonWindow,
+					int objectType,
 					int writeFlag);
 
 static int WriteLTPPredictorData(CoderInfo *coderInfo,
 								 BitStream *bitStream,
 								 int writeFlag);
+
+static int WritePredictorData(CoderInfo *coderInfo,
+							  BitStream *bitStream,
+							  int writeFlag);
 
 static int WritePulseData(CoderInfo *coderInfo,
 						  BitStream *bitStream,
--- a/libfaac/coder.h
+++ b/libfaac/coder.h
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * $Id: coder.h,v 1.5 2001/04/11 13:50:31 menno Exp $
+ * $Id: coder.h,v 1.6 2001/05/02 05:39:14 menno Exp $
  */
 
 #ifndef CODER_H
@@ -52,7 +52,6 @@
 #define LEN_TNS_NFILTL 2
 #define LEN_TNS_NFILTS 1
 
-#define LPC 1
 #define DELAY 2048
 #define	LEN_LTP_DATA_PRESENT 1
 #define	LEN_LTP_LAG 11
@@ -146,6 +145,11 @@
 
 	TnsInfo tnsInfo;
 	LtpInfo ltpInfo;
+
+	int max_pred_sfb;
+	int pred_global_flag;
+	int pred_sfb_flag[MAX_SCFAC_BANDS];
+	int reset_group_number;
 
 } CoderInfo;
 
--- a/libfaac/frame.c
+++ b/libfaac/frame.c
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * $Id: frame.c,v 1.18 2001/04/19 13:20:34 menno Exp $
+ * $Id: frame.c,v 1.19 2001/05/02 05:39:14 menno Exp $
  */
 
 /*
@@ -24,6 +24,7 @@
  *  2001/01/17: menno: Added frequency cut off filter.
  *  2001/02/28: menno: Added Temporal Noise Shaping.
  *  2001/03/05: menno: Added Long Term Prediction.
+ *  2001/05/01: menno: Added backward prediction.
  *
  */
 
@@ -42,6 +43,7 @@
 #include "psych.h"
 #include "tns.h"
 #include "ltp.h"
+#include "backpred.h"
 
 
 faacEncConfigurationPtr FAACAPI faacEncGetCurrentConfiguration(faacEncHandle hEncoder)
@@ -60,10 +62,14 @@
 	hEncoder->config.aacObjectType = config->aacObjectType;
 	hEncoder->config.mpegVersion = config->mpegVersion;
 
-	 /* No SSR / MAIN supported for now */
-	if ((hEncoder->config.aacObjectType != LTP)&&(hEncoder->config.aacObjectType != LOW))
+	/* No SSR supported for now */
+	if (hEncoder->config.aacObjectType == SSR)
 		return 0;
 
+	/* LTP only with MPEG4 */
+	if ((hEncoder->config.aacObjectType == LTP) && (hEncoder->config.mpegVersion != MPEG4))
+		return 0;
+
 	/* Re-init TNS for new profile */
 	TnsInit(hEncoder);
 
@@ -121,6 +127,9 @@
 		hEncoder->coderInfo[channel].num_window_groups = 1;
 		hEncoder->coderInfo[channel].window_group_length[0] = 1;
 
+		/* FIXME: Use sr_idx here */
+		hEncoder->coderInfo[channel].max_pred_sfb = GetMaxPredSfb(hEncoder->sampleRateIdx);
+
 		hEncoder->sampleBuff[channel] = NULL;
 		hEncoder->nextSampleBuff[channel] = NULL;
 		hEncoder->next2SampleBuff[channel] = NULL;
@@ -138,6 +147,8 @@
 
 	LtpInit(hEncoder);
 
+	PredInit();
+
 	AACQuantizeInit(hEncoder->coderInfo, hEncoder->numChannels);
 
 	HuffmanInit(hEncoder->coderInfo, hEncoder->numChannels);
@@ -360,6 +371,24 @@
 		}
 	}
 
+	for(channel = 0; channel < numChannels; channel++)
+	{
+		if ((aacObjectType == MAIN) && (!channelInfo[channel].lfe)) {
+			int numPredBands = min(coderInfo[channel].max_pred_sfb, coderInfo[channel].nr_of_sfb);
+			PredCalcPrediction(hEncoder->freqBuff[channel], 
+				coderInfo[channel].requantFreq,
+				coderInfo[channel].block_type,
+				numPredBands,
+				(coderInfo[channel].block_type==ONLY_SHORT_WINDOW)?
+				hEncoder->srInfo->cb_width_short:hEncoder->srInfo->cb_width_long,
+				coderInfo,
+				channelInfo,
+				channel); 
+		} else {
+			coderInfo[channel].pred_global_flag = 0;
+		}
+	}
+
 	MSEncode(coderInfo, channelInfo, hEncoder->freqBuff, numChannels, allowMidside);
 
 	/* Quantize and code the signal */
@@ -393,7 +422,7 @@
 			else
 				tnsDecInfo = NULL;
 			
-			if ((!channelInfo[channel].lfe) && (mpegVersion == MPEG4) && (aacObjectType == LTP)) {  /* no reconstruction needed for LFE channel*/
+			if ((!channelInfo[channel].lfe) && (aacObjectType == LTP)) {  /* no reconstruction needed for LFE channel*/
 
 				LtpReconstruct(&coderInfo[channel], &(coderInfo[channel].ltpInfo),
 					coderInfo[channel].requantFreq);
--- a/libfaac/libfaac.dsp
+++ b/libfaac/libfaac.dsp
@@ -89,6 +89,10 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\backpred.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\bitstream.c
 # End Source File
 # Begin Source File
@@ -138,6 +142,10 @@
 # Begin Source File
 
 SOURCE=.\aacquant.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\backpred.h
 # End Source File
 # Begin Source File
 
--- a/todo.txt
+++ b/todo.txt
@@ -7,8 +7,10 @@
 - DONE: Write GUI
 - DONE: Add TNS
 - DONE: Add LTP
+- DONE: Add backward prediction (MPEG2-AAC)????
+- DONE: Test (and maybe fix) sample rates other than 44100 Hz
+- DONE: Test (and maybe fix) multichannel and mono support
 - Add PNS
-- Add backward prediction (MPEG2-AAC)????
 - Add IS
 - Add bit reservoir control
 - Add pulse coding
@@ -18,8 +20,6 @@
 - Clean up psychoacoustics code
 - Better grouping support
 - Add Window shape switching
-- Test (and maybe fix) sample rates other than 44100 Hz
-- Test (and maybe fix) multichannel and mono support
 - Improve command line tool (wildcards)
 - Write documentation for library interface
 - Speedup?? (no priority)