shithub: aacenc

ref: 5f0d6417237a6895b39ef2a20f9fbbe6689f57fe
dir: /libfaac/backpred.c/

View raw version
/*
 * FAAC - Freeware Advanced Audio Coder
 * Copyright (C) 2001 Menno Bakker
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * $Id: backpred.c,v 1.3 2001/05/30 08:57:08 menno Exp $
 */

#include <math.h>
#include "frame.h"
#include "coder.h"
#include "channels.h"
#include "backpred.h"


void PredInit(faacEncHandle hEncoder)
{
	unsigned int channel;

	for (channel = 0; channel < hEncoder->numChannels; channel++) {
		BwpInfo *bwpInfo = &(hEncoder->coderInfo[channel].bwpInfo);

		bwpInfo->psy_init_mc = 0;
		bwpInfo->reset_count_mc = 0;
	}
}
 
void PredCalcPrediction(double *act_spec, double *last_spec, int btype, 
						int nsfb, 
						int *isfb_width, 
						CoderInfo *coderInfo,
						ChannelInfo *channelInfo,
						int chanNum) 
{
	int i, k, j, cb_long;
	int leftChanNum;
	int isRightWithCommonWindow;
	double num_bit, snr[SBMAX_L];
	double energy[BLOCK_LEN_LONG], snr_p[BLOCK_LEN_LONG], temp1, temp2;
	ChannelInfo *thisChannel;

	/* Set pointers for specified channel number */
	/* int psy_init; */
	int *psy_init;
	double (*dr)[BLOCK_LEN_LONG],(*e)[BLOCK_LEN_LONG];
	double (*K)[BLOCK_LEN_LONG], (*R)[BLOCK_LEN_LONG];
	double (*VAR)[BLOCK_LEN_LONG], (*KOR)[BLOCK_LEN_LONG];
	double *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 = &coderInfo[chanNum].bwpInfo.psy_init_mc;
	dr = &coderInfo[chanNum].bwpInfo.dr_mc[0];
	e = &coderInfo[chanNum].bwpInfo.e_mc[0];
	K = &coderInfo[chanNum].bwpInfo.K_mc[0]; 
	R = &coderInfo[chanNum].bwpInfo.R_mc[0];
	VAR = &coderInfo[chanNum].bwpInfo.VAR_mc[0];
	KOR = &coderInfo[chanNum].bwpInfo.KOR_mc[0];
	sb_samples_pred = &coderInfo[chanNum].bwpInfo.sb_samples_pred_mc[0];
	thisLineNeedsResetting = &coderInfo[chanNum].bwpInfo.thisLineNeedsResetting_mc[0];
	reset_count = &coderInfo[chanNum].bwpInfo.reset_count_mc;

	thisChannel = &(channelInfo[chanNum]);
	*psy_init = (*psy_init && (btype!=2));

	if((*psy_init) == 0) {
		for (j=0; j<BLOCK_LEN_LONG; 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;
		}
		return;
	}


	/**************************************************/
	/*  Compute state using last_spec                 */
	/**************************************************/
	for (i=0;i<BLOCK_LEN_LONG;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<BLOCK_LEN_LONG;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<BLOCK_LEN_LONG;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<BLOCK_LEN_LONG; 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<BLOCK_LEN_LONG;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<BLOCK_LEN_LONG; j++)
				sb_samples_pred[j]=0.0; 
		}
		for (j=0; j<BLOCK_LEN_LONG; j++)
			act_spec[j]-=sb_samples_pred[j];
		
	} else {

		/**************************************************/
		/* Determine whether to enable/disable prediction */
		/**************************************************/
		
		for (k=0; k<BLOCK_LEN_LONG; 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<BLOCK_LEN_LONG;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<BLOCK_LEN_LONG; j++)
				sb_samples_pred[j]=0.0; 
		}
		for (j=0; j<BLOCK_LEN_LONG; 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 = &coderInfo[leftChanNum].bwpInfo.reset_count_mc;
		/* Reset the frame counter */
		for (i=0;i<BLOCK_LEN_LONG;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 < BLOCK_LEN_LONG; i += 30)
			{
				thisLineNeedsResetting[i]=1;
			}
		}
		else
			*reset_group = -1;
	} else {
		/******************************************************************/
		/* 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<BLOCK_LEN_LONG;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 < BLOCK_LEN_LONG; i += 30)
			{
				thisLineNeedsResetting[i]=1;
			}
		}
		else
			*reset_group = -1;
	}


	/* 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;
    }
}


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];
	}
}