/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
*/

/* layer3.c  layer3 audio decoding
 *
 * Created by: tomislav uzelac  Mar  1 97
 * Last modified by: 
 */
#include "amp.h"
#include "audio.h"
#include "dump.h"
#include "getbits.h"
#include "getdata.h"
#include "huffman.h"
#include "misc2.h"
#include "rtbuf.h"
#include "transform.h"

#define LAYER3
#include "layer3.h"

/* this function decodes one layer3 audio frame, except for the header decoding
 * which is done in main() [audio.c]. returns 0 if everything is ok.
 */
int layer3_frame(struct AUDIO_HEADER *header,int cnt)
{
	static struct SIDE_INFO info;
	
	int gr,ch,sb,i;
	int mean_frame_size,bitrate,fs,hsize,ssize;
	
	/* we need these later, hsize is the size of header+side_info
	*/
	if (header->ID) 
	{
		if (header->mode==3) 
		{
			nch=1;
			hsize=21;
		} 
		else 
		{
			nch=2;
			hsize=36;
		}
	}
	else 
	{
		if (header->mode==3) 
		{
			nch=1;
			hsize=13;
		} 
		else 
		{
			nch=2;
			hsize=21;
		}
	}
		
	/* crc increases hsize by 2
	*/
	if (header->protection_bit==0) hsize+=2;
	
	
	/* read layer3 specific side_info
	*/
	getinfo(header,&info);
	
	
	/* MPEG2 only has one granule
	*/
	bitrate=t_bitrate[header->ID][3-header->layer][header->bitrate_index];
	fs=t_sampling_frequency[header->ID][header->sampling_frequency];
	if (header->ID) mean_frame_size=144000*bitrate/fs;
	else mean_frame_size=72000*bitrate/fs;
	
	
	/* check if mdb is too big for the first few frames. this means that
	* a part of the stream could be missing. We must still fill the buffer
	*/
	/*	if (info.main_data_begin > append ) 
	if (cnt*mean_frame_size < 960) {
	warn(" frame %d discarded, incomplete main_data\n",cnt);
	fillbfr(mean_frame_size + header->padding_bit - hsize);
	return 0;
	}
	... this must be _the_ worst piece of code I've ever written!
	*/
	/* don't forget to (re)initialise bclean_bytes to 0, and f_bdirty to FALSE!!!
	*/
	if (f_bdirty) 
	{
		if (info.main_data_begin > bclean_bytes) 
		{
			fillbfr(mean_frame_size + header->padding_bit - hsize);
			bclean_bytes+=mean_frame_size + header->padding_bit - hsize;
			/* warn(" frame %d discarded, incomplete main_data\n",cnt);*/
			return 0;
		} 
		else 
		{
			/* re-initialise */
			f_bdirty=FALSE;
			bclean_bytes=0;
		}
	}
		
	/* now update the data 'pointer' (counting in bits) according to
	* the main_data_begin information
	*/
	data = 8 * ((append - info.main_data_begin) & (BUFFER_SIZE-1));
	
	/* read into the buffer all bytes up to the start of next header
	*/
	fillbfr(mean_frame_size + header->padding_bit - hsize);
	
	/* these two should go away
	*/
	t_l=&t_b8_l[header->ID][header->sampling_frequency][0];
	t_s=&t_b8_s[header->ID][header->sampling_frequency][0];
	
	/* debug/dump stuff
	*/
	if (A_DUMP_BINARY) dump((int *)info.part2_3_length);
	
	/* decode the scalefactors and huffman data
	* this part needs to be enhanced for error robustness
	*/
	
	for (gr=0;gr < ((header->ID) ? 2 : 1);gr++) 
	{
	
		for (ch=0;ch<nch;ch++) 
		{
			ssize=decode_scalefactors(&info,header,gr,ch);
			decode_huffman_data(&info,gr,ch,ssize);
#ifdef DEBUG_HUFFMAN
			{
				int i;
				FILE *tf;
				tf=fopen("_ah","w");
				for (i=0;i<576;i++) fprintf(tf,"%d\n",is[ch][i]);
				fclose(tf);
			}
#endif /* DEBUG_HUFFMAN */
		}
		/* requantization, stereo processing, reordering(shortbl)
		*/
		if (header->mode!=1 || (header->mode==1 && header->mode_extension==0))
		{
			for (ch=0;ch<nch;ch++) requantize_mono(gr,ch,&info,header);
		}
		else
		{
			requantize_ms(gr,&info,header);
		}
		
		/* just which window?
		*/
		for (ch=0;ch<nch;ch++) 
		{
			int win_type; /* same as in the standard, long=0, start=1 ,.... */
			int window_switching_flag = info.window_switching_flag[gr][ch];
			int block_type = info.block_type[gr][ch];
			int mixed_block_flag = info.mixed_block_flag[gr][ch];
			
#if defined(PENTIUM_RDTSC)
			unsigned int cnt4, cnt3, cnt2, cnt1;
			static int min_cycles = 99999999;
			
			 	__asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt4));
#endif
			
			/* antialiasing butterflies
			*/
#ifdef DEBUG_REQ
			{
				int i;
				FILE *tf;
				tf=fopen("_ar","w");
				for (i=0;i<576;i++) fprintf(tf,"%f\n",xr[ch][i]);
				fclose(tf);
			}
#endif /* DEBUG_REQ */
			if (!(window_switching_flag && block_type==2))
			{
				alias_reduction(ch);
			}
			
			if (window_switching_flag && block_type==2 && mixed_block_flag)
			{	
				win_type=0;
			}
			else
			{
			   if (!window_switching_flag) win_type=0;
			   else win_type=block_type;
			}
			
#if defined(PENTIUM_RDTSC)
			__asm__(".byte 0x0f,0x31" : "=a" (cnt3), "=d" (cnt4));
#endif
			
			/* imdct ...
			*/
			for (sb=0;sb<2;sb++)
			{
				imdct(win_type,sb,ch);
			}
			
			if (window_switching_flag && block_type==2 && mixed_block_flag)
			{
				win_type=2;
			}
			
			/* no_of_imdcts tells us how many subbands from the top are all zero
			* it is set by the requantize functions in misc2.c
			*/
			
			for (sb=2;sb<no_of_imdcts[ch];sb++)
			{
				imdct(win_type,sb,ch);
			}
			
			float f00=0.0f;
			float *schsb=(float *)s[ch][sb];
			float *ressb=(float *)res[sb];
			
			for (;sb<32;sb++)
			{
				ressb[ 0]=schsb[ 0];
				ressb[ 1]=schsb[ 1];
				ressb[ 2]=schsb[ 2];
				ressb[ 3]=schsb[ 3];
				ressb[ 4]=schsb[ 4];
				ressb[ 5]=schsb[ 5];
				ressb[ 6]=schsb[ 6];
				ressb[ 7]=schsb[ 7];
				ressb[ 8]=schsb[ 8];
				ressb[ 9]=schsb[ 9];
				ressb[10]=schsb[10];
				ressb[11]=schsb[11];
				ressb[12]=schsb[12];
				ressb[13]=schsb[13];
				ressb[14]=schsb[14];
				ressb[15]=schsb[15];
				ressb[16]=schsb[16];
				ressb[17]=schsb[17];
				schsb[ 0]=f00;
				schsb[ 1]=f00;
				schsb[ 2]=f00;
				schsb[ 3]=f00;
				schsb[ 4]=f00;
				schsb[ 5]=f00;
				schsb[ 6]=f00;
				schsb[ 7]=f00;
				schsb[ 8]=f00;
				schsb[ 9]=f00;
				schsb[10]=f00;
				schsb[11]=f00;
				schsb[12]=f00;
				schsb[13]=f00;
				schsb[14]=f00;
				schsb[15]=f00;
				schsb[16]=f00;
				schsb[17]=f00;
				schsb+=18;		
				ressb+=18;		
			}
			/* polyphase filterbank
			*/
			/* if (nch == 2) this was a bug, tomislav */
		
			for (i=0;i<18;i++)
			{
				poly(ch,i);
			}
			
#if defined(PENTIUM_RDTSC)
			__asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt4));
			
			if (cnt2-cnt1 < min_cycles) 
			{
				min_cycles = cnt2-cnt1;
				printf("%d, %d cycles\n", cnt3-cnt1, min_cycles);
			}
#endif
		}
		printout(header);
	}    /*  for (gr... */ 
	
	/* return status: 0 for ok, errors will be added
	*/
	return 0;
} 

