shithub: aacenc

ref: 6d1a5cff3f992e07718299eaa62cfc01ab2baacb
dir: /imdct.c/

View raw version

#include <math.h>
#include <stdlib.h>

#include "tf_main.h"
#include "transfo.h"
#include "block.h"
#include "dolby_win.h"

#define DPI	3.14159265358979323846264338327950288

double zero = 0;

void vcopy( double src[], double dest[], int inc_src, int inc_dest, int vlen )
{
	int i;

	for( i=0; i<vlen; i++ ) {
		*dest = *src;
		dest += inc_dest;
		src  += inc_src;
	}
}

void vmult1(double src1[], double src2[], double dest[], int vlen )
{
	int i;

	for( i=0; i<vlen; i++ ) {
		*dest = *src1 * *src2;
		dest++;
		src1++;
		src2++;
	}
}

void vmult2( double src1[], double src2[], double dest[], int vlen)
{
	int i;

	for( i=0; i<vlen; i++ ) {
		*dest = *src1 * *src2;
		dest++;
		src1++;
		src2--;
	}
}

void vadd( double src1[], double src2[], double dest[], 
            int inc_src1, int inc_src2, int inc_dest, int vlen )
{
	int i;

	for( i=0; i<vlen; i++ ) {
		*dest = *src1 + *src2;
		dest += inc_dest;
		src1 += inc_src1;
		src2 += inc_src2;
	}
}
 

/* Calculate window */
void calc_window( double window[], int len, Window_shape wfun_select )
{
	int i;
	extern double dolby_win_1024[];
	extern double dolby_win_128[];

	switch(wfun_select)
    {
    case WS_FHG: 
		for( i=0; i<len; i++ )
			window[i] = sin((DPI/(2*len)) * (i + 0.5));
		break;
		
    case WS_DOLBY: 
		switch(len)
		{
		case BLOCK_LEN_SHORT:
			for( i=0; i<len; i++ ) 
				window[i] = dolby_win_128[i]; 
			break;
		case BLOCK_LEN_LONG:
			for( i=0; i<len; i++ ) 
				window[i] = dolby_win_1024[i]; 
			break;
		}
		break;
    }
}

#define MAX_SHIFT_LEN_LONG 4096

/* %%%%%%%%%%%%%%%%% MDCT - STUFF %%%%%%%%%%%%%%%% */

void mdct( double in_data[], double out_data[], int len )
{
	vcopy(in_data, out_data, 1, 1, len); 
	MDCT(out_data, len);
}

void buffer2freq(double           p_in_data[], 
				 double           p_out_mdct[],
				 double           p_overlap[],
				 enum WINDOW_TYPE block_type,
				 Window_shape     wfun_select,      /* offers the possibility to select different window functions */
				 int              nlong,            /* shift length for long windows   */
				 int              nmed,             /* shift length for medium windows */
				 int              nshort,           /* shift length for short windows  */
				 Mdct_in      overlap_select     /*  YT 970615 for son_PP */
				 )
{
	double         transf_buf[ 2*MAX_SHIFT_LEN_LONG ];
	double         windowed_buf[ 2*MAX_SHIFT_LEN_LONG ];
	double         *p_o_buf;
	int            k;

	double           window_long[MAX_SHIFT_LEN_LONG]; 
	double           window_long_prev[MAX_SHIFT_LEN_LONG]; 
	double           window_short[MAX_SHIFT_LEN_LONG]; 
	double           window_short_prev[MAX_SHIFT_LEN_LONG]; 
	double           *window_short_prev_ptr;


	int nflat_ls    = (nlong-nshort)/ 2; 
	int transfak_ls =  nlong/nshort; 
	int nflat_ms    = (nmed-nshort) / 2; 
	int transfak_ms =  nmed/nshort; 
	
	static Window_shape wfun_select_prev=WS_FHG;
	static int firstTime=1;
	window_short_prev_ptr = window_short_prev ; 

	calc_window( window_long,      nlong, wfun_select ); 
	calc_window( window_long_prev, nlong, wfun_select_prev ); 
	calc_window( window_short,      nshort, wfun_select ); 
	calc_window( window_short_prev, nshort, wfun_select_prev ); 
	
	/* create / shift old values */
	/* We use p_overlap here as buffer holding the last frame time signal*/
	/* YT 970615 for son_pp */
	if(overlap_select != MNON_OVERLAPPED){
		if (firstTime){
			firstTime=0;
			vcopy( &zero, transf_buf, 0, 1, nlong );
		}
		else
			vcopy( p_overlap, transf_buf, 1, 1, nlong );

		/* Append new data */
		vcopy( p_in_data, transf_buf+nlong, 1, 1, nlong );
		vcopy( p_in_data, p_overlap,        1, 1, nlong );
	}
	else{
		vcopy( p_in_data, transf_buf, 1, 1, 2*nlong );
	}

	/* Set ptr to transf-Buffer */
	p_o_buf = transf_buf;
	
	
	/* Separate action for each Block Type */
	switch( block_type ) {
	case ONLY_LONG_WINDOW :
		vmult1( p_o_buf, window_long_prev, windowed_buf, nlong );
		vmult2( p_o_buf+nlong, window_long+nlong-1, windowed_buf+nlong, nlong );
		mdct( windowed_buf, p_out_mdct, 2*nlong );    
		break;
		
	case LONG_SHORT_WINDOW :
		vmult1( p_o_buf, window_long_prev, windowed_buf, nlong );
		vcopy( p_o_buf+nlong, windowed_buf+nlong, 1, 1, nflat_ls );
		vmult2( p_o_buf+nlong+nflat_ls, window_short+nshort-1, windowed_buf+nlong+nflat_ls, nshort );
		vcopy( &zero, windowed_buf+2*nlong-1, 0, -1, nflat_ls );
		mdct( windowed_buf, p_out_mdct, 2*nlong );
		break;

	case SHORT_LONG_WINDOW :
		vcopy( &zero, windowed_buf, 0, 1, nflat_ls );
		vmult1( p_o_buf+nflat_ls, window_short_prev_ptr, windowed_buf+nflat_ls, nshort );
		vcopy( p_o_buf+nflat_ls+nshort, windowed_buf+nflat_ls+nshort, 1, 1, nflat_ls );
		vmult2( p_o_buf+nlong, window_long+nlong-1, windowed_buf+nlong, nlong );
		mdct( windowed_buf, p_out_mdct, 2*nlong );
		break;

	case ONLY_SHORT_WINDOW :
		if(overlap_select != MNON_OVERLAPPED){ /* YT 970615 for sonPP */
			p_o_buf += nflat_ls;
		}
		for (k=transfak_ls-1; k-->=0; ) {
			vmult1( p_o_buf,        window_short_prev_ptr, windowed_buf, nshort );
			vmult2( p_o_buf+nshort, window_short+nshort-1, windowed_buf+nshort, nshort );
			mdct( windowed_buf, p_out_mdct, 2*nshort );

			p_out_mdct += nshort;
			/* YT 970615 for sonPP*/
			if(overlap_select != MNON_OVERLAPPED) p_o_buf += nshort;
			else 	p_o_buf += 2*nshort;
			window_short_prev_ptr = window_short; 
		}
		break;
	}

	/* --- Save old window shape --- */
	wfun_select_prev = wfun_select;
}

void imdct(double in_data[], double out_data[], int len)
{
	vcopy(in_data, out_data, 1, 1, len/2);
	IMDCT(out_data, len);
}

void freq2buffer(double           p_in_data[], 
				 double           p_out_data[],
				 double           p_overlap[],
				 enum WINDOW_TYPE block_type,
				 int              nlong,            /* shift length for long windows   */
				 int              nmed,             /* shift length for medium windows */
				 int              nshort,           /* shift length for short windows  */
				 Window_shape     wfun_select,      /* offers the possibility to select different window functions */
				 Mdct_in	   overlap_select		/* select imdct output *TK*	*/
													/* switch (overlap_select) {	*/
													/* case OVERLAPPED:		*/
													/*   p_out_data[]			*/
													/*   = overlapped and added signal */
													/*		(bufferlength: nlong)	*/
													/* case MNON_OVERLAPPED:		*/
													/*   p_out_data[]			*/
													/*   = non overlapped signal	*/
													/*		(bufferlength: 2*nlong)	*/
				 )
{
	double           *o_buf, transf_buf[ 2*MAX_SHIFT_LEN_LONG ];
	double           overlap_buf[ 2*MAX_SHIFT_LEN_LONG ]; 
	
	double           window_long[MAX_SHIFT_LEN_LONG]; 
	double           window_long_prev[MAX_SHIFT_LEN_LONG]; 
	double           window_short[MAX_SHIFT_LEN_LONG]; 
	double           window_short_prev[MAX_SHIFT_LEN_LONG]; 
	double           *window_short_prev_ptr;
	
	double  *fp; 
	int     k; 
	
	int nflat_ls    = (nlong-nshort)/ 2; 
	int transfak_ls =  nlong/nshort; 
	int nflat_ms    = (nmed-nshort) / 2; 
	int transfak_ms =  nmed/nshort;  
	
	static Window_shape wfun_select_prev=WS_FHG;
	window_short_prev_ptr=window_short_prev ; 

	calc_window( window_long,      nlong, wfun_select ); 
	calc_window( window_long_prev, nlong, wfun_select_prev ); 
	calc_window( window_short,      nshort, wfun_select ); 
	calc_window( window_short_prev_ptr, nshort, wfun_select_prev ); 
	
	
	/* Assemble overlap buffer */ 
	vcopy( p_overlap, overlap_buf, 1, 1, nlong ); 
	o_buf = overlap_buf; 
	

	/* Separate action for each Block Type */ 
	switch( block_type ) { 
	case ONLY_LONG_WINDOW : 
		imdct( p_in_data, transf_buf, 2*nlong ); 
		vmult1( transf_buf, window_long_prev, transf_buf, nlong ); 
		if (overlap_select != MNON_OVERLAPPED) {
			vadd( transf_buf, o_buf, o_buf, 1, 1, 1, nlong ); 
			vmult2( transf_buf+nlong, window_long+nlong-1, o_buf+nlong, nlong ); 
		}
		else { /* overlap_select == NON_OVERLAPPED */
			vmult2( transf_buf+nlong, window_long+nlong-1, transf_buf+nlong, nlong );
		}
		break; 
		
	case LONG_SHORT_WINDOW : 
		imdct( p_in_data, transf_buf, 2*nlong ); 
		vmult1( transf_buf, window_long_prev, transf_buf, nlong ); 
		if (overlap_select != MNON_OVERLAPPED) {
			vadd( transf_buf, o_buf, o_buf, 1, 1, 1, nlong ); 
			vcopy( transf_buf+nlong, o_buf+nlong, 1, 1, nflat_ls ); 
			vmult2( transf_buf+nlong+nflat_ls, window_short+nshort-1, o_buf+nlong+nflat_ls, nshort ); 
			vcopy( &zero, o_buf+2*nlong-1, 0, -1, nflat_ls ); 
		}
		else { /* overlap_select == NON_OVERLAPPED */
			vmult2( transf_buf+nlong+nflat_ls, window_short+nshort-1, transf_buf+nlong+nflat_ls, nshort ); 
			vcopy( &zero, transf_buf+2*nlong-1, 0, -1, nflat_ls ); 
		}
		break; 
		
	case SHORT_LONG_WINDOW : 
		imdct( p_in_data, transf_buf, 2*nlong ); 
		vmult1( transf_buf+nflat_ls, window_short_prev_ptr, transf_buf+nflat_ls, nshort ); 
		if (overlap_select != MNON_OVERLAPPED) {
			vadd( transf_buf+nflat_ls, o_buf+nflat_ls, o_buf+nflat_ls, 1, 1, 1, nshort ); 
			vcopy( transf_buf+nflat_ls+nshort, o_buf+nflat_ls+nshort, 1, 1, nflat_ls ); 
			vmult2( transf_buf+nlong, window_long+nlong-1, o_buf+nlong, nlong ); 
		}
		else { /* overlap_select == NON_OVERLAPPED */
			vcopy( &zero, transf_buf, 0, 1, nflat_ls);
			vmult2( transf_buf+nlong, window_long+nlong-1, transf_buf+nlong, nlong);
		}
		break; 
		
	case ONLY_SHORT_WINDOW : 
		if (overlap_select != MNON_OVERLAPPED) {
			fp = o_buf + nflat_ls; 
		}
		else { /* overlap_select == NON_OVERLAPPED */
			fp = transf_buf;
		}
		for( k = transfak_ls-1; k-->= 0; ) { 
			if (overlap_select != MNON_OVERLAPPED) {
				imdct( p_in_data, transf_buf, 2*nshort ); 
				vmult1( transf_buf, window_short_prev_ptr, transf_buf, nshort ); 
				vadd( transf_buf, fp, fp, 1, 1, 1, nshort ); 
				vmult2( transf_buf+nshort, window_short+nshort-1, fp+nshort, nshort ); 
				p_in_data += nshort; 
				fp        += nshort; 
				window_short_prev_ptr = window_short; 
			}
			else { /* overlap_select == NON_OVERLAPPED */
				imdct( p_in_data, fp, 2*nshort );
				vmult1( fp, window_short_prev_ptr, fp, nshort ); 
				vmult2( fp+nshort, window_short+nshort-1, fp+nshort, nshort ); 
				p_in_data += nshort; 
				fp        += 2*nshort;
				window_short_prev_ptr = window_short; 
			}
		} 
		vcopy( &zero, o_buf+2*nlong-1, 0, -1, nflat_ls ); 
		break;     
	} 

	if (overlap_select != MNON_OVERLAPPED) {
		vcopy( o_buf, p_out_data, 1, 1, nlong ); 
	}
	else { /* overlap_select == NON_OVERLAPPED */
		vcopy( transf_buf, p_out_data, 1, 1, 2*nlong ); 
	}

	/* save unused output data */ 
	vcopy( o_buf+nlong, p_overlap, 1, 1, nlong ); 

	/* --- Save old window shape --- */
	wfun_select_prev = wfun_select;
}

/***********************************************************************************************/ 

void specFilter (double p_in[],
				 double p_out[],
				 int  samp_rate,
				 int lowpass_freq,
				 int    specLen
				 )
{
	float lowpass;
	int    xlowpass,i;

	/* calculate the last line which is not zero */
	lowpass = (float)lowpass_freq * (float)specLen;
	lowpass /= (samp_rate>>1);
	lowpass += 1.0;             /* round up to ensure that the desired upper frequency limit is correct */
	xlowpass = ((int)lowpass < specLen) ? (int)lowpass : specLen ;

	if( p_out != p_in ) {
		for (i = 0; i < specLen; i++ ) {
			p_out[i] = p_in[i];
		}
	}
	for (i = xlowpass; i <specLen ; i++ ) {
		p_out[i]  = 0;
	}
}