/**********************************************************************
MPEG-4 Audio VM

This software module was originally developed by
  Y.B. Thomas Kim and S.H. Park (Samsung AIT)
and edited by
  Y.B. Thomas Kim (Samsung AIT) on 1997-11-06

in the course of development of the MPEG-2 NBC/MPEG-4 Audio standard
ISO/IEC 13818-7, 14496-1,2 and 3. This software module is an
implementation of a part of one or more MPEG-2 NBC/MPEG-4 Audio tools
as specified by the MPEG-2 NBC/MPEG-4 Audio standard. ISO/IEC gives
users of the MPEG-2 NBC/MPEG-4 Audio standards free license to this
software module or modifications thereof for use in hardware or
software products claiming conformance to the MPEG-2 NBC/ MPEG-4 Audio
standards. Those intending to use this software module in hardware or
software products are advised that this use may infringe existing
patents. The original developer of this software module and his/her
company, the subsequent editors and their companies, and ISO/IEC have
no liability for use of this software module or modifications thereof
in an implementation. Copyright is not released for non MPEG-2
NBC/MPEG-4 Audio conforming products. The original developer retains
full right to use the code for his/her own purpose, assign or donate
the code to a third party and to inhibit third party from using the
code for non MPEG-2 NBC/MPEG-4 Audio conforming products. This
copyright notice must be included in all copies or derivative works.

Copyright (c) 1997.

**********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
#include "bitstream.h"
#include "tf_main.h"
#include "tns.h"
#include "sam_dec.h"
#ifdef	SRS
#include "sony_local.h"
#endif

#define	ID_SCE	0x00
#define	ID_CPE	0x01
#define	MAX_PRED_SFB	40


static float	spectrums[2][1024];
static int		samples[2][1024];

static void sam_get_tns( int windowSequence, sam_TNS_frame_info *tns_frame_info );
static void sam_ics_info(int *windowSequence,
	int *windowShape,
	int *maxSfb,
	int *groupInfo,
	int *predict_data);
static int sam_get_gcBuf(int window_sequence, BsBitStream *gc_streamCh);

int	sam_decode_frame(
	BsBitStream *fixed_stream,
	BsBitStream *gc_stream[MAX_TIME_CHANNELS],
	int	target_br,
	double	**coef,
	int	*block_type,
	Window_shape *window_Shape)
{
	int		i, ch, nch;
	int		frameLength;
	int		usedBits;
	int		stereo_mode;
	int		maxScaleFactor[2];
	int		id_syn_ele;
	int		element_instance_tag;
	int		nok_lt_data_present;
	int		common_window;
	int		windowSequence[2];
	int		windowShape[2];
	int		maxSfb[2];
	int		groupInfo[2][7];
	int		predict_data[2][50];
	int		gain_control_data_present[2];
	int		tns_data_present[2];
	int		ms_mask[112];
	int		is_intensity;
	int		is_info[112];
	int		scalefactors[2][112];
	sam_TNS_frame_info tns[2];


	sam_setBsacdec2BitBuffer(fixed_stream);

	/********* READ BITSTREAM **********/
	/* ***************************************************** */
	/* # the side information part for Mulit-channel		 */ 
	/* ***************************************************** */

    /* id_syn_ele  */
	id_syn_ele = sam_getbits(3);

	switch(id_syn_ele) {
		case ID_SCE:
			nch = 1;
			break;
		case ID_CPE:
			nch = 2;
			break;
		default:
			fprintf(stderr, "Unknown ID %d\n", id_syn_ele);
			break;
	}

	/* initialize variables */
	for(i = 0; i < 50; i++)
		predict_data[0][i] = predict_data[1][i] = 0;

	for(i = 0; i < 112; i++) {
		ms_mask[i] = 0;
		is_info[i] = 0;
	}

	ms_mask[0] = 0;
	is_intensity = 0;
	stereo_mode = 0;
	common_window = 0;

    /*  element_instance_tag  */
	element_instance_tag  = sam_getbits(4);

	nok_lt_data_present = sam_getbits(1);

	/* ***************************************************** */
	/*   bsac_channel_stream()                               */
	/* ***************************************************** */
	if(id_syn_ele == ID_CPE)
		common_window = sam_getbits(1);

	for(ch = 0; ch < nch; ch++)
		maxScaleFactor[ch] = sam_getbits(8);

	/* ***************************************************** */
	/* # 			ics_info()                             * */
	/* ***************************************************** */
	sam_ics_info(&windowSequence[0], &windowShape[0], &maxSfb[0],
			groupInfo[0], predict_data[0]);

	if(id_syn_ele == ID_CPE && !common_window)
		sam_ics_info(&windowSequence[1], &windowShape[1], &maxSfb[1],
				groupInfo[1], predict_data[1]);


	if(id_syn_ele == ID_CPE && common_window) {
		windowSequence[1] = windowSequence[0];
		maxSfb[1] = maxSfb[0];
		for(i = 0; i < 7; i++)
			groupInfo[1][i] = groupInfo[0][i];
		for(i = 0; i < 50; i++)
			predict_data[1][i] = predict_data[0][i];
	}

	/* ***************************************************** */
	/* # 			the other side info					   * */
	/* ***************************************************** */
	for(ch = 0; ch < nch; ch++) {
		tns_data_present[ch] = sam_getbits(1);
		if(tns_data_present[ch]) {
			sam_get_tns(windowSequence[ch], &tns[ch]);
		}

		gain_control_data_present[ch] = sam_getbits(1); 
		if(gain_control_data_present[ch]) {
#ifdef	SRS
			sam_get_gcBuf(windowSequence[ch], gc_stream[ch]);
#else
			CommonExit(1, "Gain control not implemented\n");
#endif
		}
	}

	/* ***************************************************** */
	/* # 			stereo mode							   * */
	/* ***************************************************** */
	if(id_syn_ele == ID_CPE) {
		stereo_mode = sam_getbits(2);
		if(stereo_mode == 1) {
			ms_mask[0] = 2;
			for(i = 0; i < 112; i++)
				ms_mask[i+1] = 1;
		} else if(stereo_mode == 2) {
			ms_mask[0] = 1;
		} else if(stereo_mode == 3) {
			ms_mask[0] = 1;
			is_intensity = 1;
		}
	}

	/* ***************************************************** */
	/* # 			BSAC D E C O D I N G				   * */
	/* ***************************************************** */
	frameLength = sam_decode_bsac_data(target_br,
						stereo_mode,
						windowSequence,
						scalefactors,
						groupInfo,
						samples,
						maxSfb,
						maxScaleFactor,
						ms_mask,
						is_info,
						nch);

	/* ***************************************************** */
	/* # 			dequantization      				   * */
	/* ***************************************************** */
	for(ch = 0; ch < nch; ch++) {
		sam_dequantization(target_br,
				windowSequence[ch],
				scalefactors[ch],
				groupInfo[ch],
				samples[ch],
				maxSfb[ch],
				is_info,
				spectrums[ch],
				ch);
	}

	/* ***************************************************** */
	/* # 			M/S stereo		      				   * */
	/* ***************************************************** */
	if(ms_mask[0])
		sam_ms_stereo(windowSequence[0], groupInfo[0], spectrums, ms_mask, maxSfb[0]);


	/* ***************************************************** */
	/* # 			Intensity/Prediction   				   * */
	/* ***************************************************** */
	for(ch = 0; ch < nch; ch++) {
		if(ch == 1 && is_intensity)
			sam_intensity(windowSequence[0], groupInfo[0], spectrums, scalefactors, is_info, ms_mask, predict_data, maxSfb[0]);

		sam_prediction(windowSequence[ch], predict_data[ch], spectrums[ch], ch);
	}

	for(ch = 0; ch < nch; ch++) {
		/* predictor reset */
		sam_predict_reset(windowSequence[ch], predict_data[ch], ch);

		/* ***************************************************** */
		/* # 			Temporal Noise Shaping 				   * */
		/* ***************************************************** */
		if(tns_data_present[ch])
			sam_tns_data(windowSequence[ch], maxSfb[ch], spectrums[ch], &tns[ch]);

		for(i = 0; i < 1024; i++)
			coef[ch][i] = (double)spectrums[ch][i];
	}

	*block_type = windowSequence[0];
	*window_Shape = windowShape[0];

	usedBits = sam_getUsedBits();

	while(usedBits < frameLength) {
		int	remain, read_bits;

		remain = frameLength - usedBits;
		read_bits = remain > 8 ? 8 : remain;
		i = sam_getbits(read_bits);
		usedBits = sam_getUsedBits();
	}


	return usedBits;
}

/* ***************************************************** */
/* # 			ics_info()                             * */
/* ***************************************************** */
static void sam_ics_info(int *windowSequence,
	int *windowShape,
	int *maxSfb,
	int *groupInfo,
	int *predict_data)
{
	int	 i, j, ics_reserved;

   	/* ics_reserved_bit  */
	ics_reserved = sam_getbits(1); 

    /*  window sequence */
	*windowSequence = sam_getbits(2); 

    /*  window shape */
	*windowShape = sam_getbits(1); 

	if (*windowSequence == EIGHT_SHORT_SEQUENCE)
	{
		*maxSfb = sam_getbits(4);

  			for (i = 0; i < 7; i++)
			groupInfo[i] =  sam_getbits(1); 
	}
	else 
	{
		*maxSfb = sam_getbits(6);

		predict_data[0] = sam_getbits(1);
		if(predict_data[0]) {
			predict_data[1] = sam_getbits(1);	/* predictor reset */
			if(predict_data[1]) {
				for(i = 1; i < 6; i++)
					predict_data[1+i] = sam_getbits(1);
			}
			j = ((*maxSfb < MAX_PRED_SFB) ? *maxSfb : MAX_PRED_SFB) + 1;
			for(i = 1; i < j; i++)
				predict_data[6+i] = sam_getbits(1);
			for(; i < MAX_PRED_SFB+1; i++)
				predict_data[6+i] = 1;
		}
	}
}

static void sam_get_tns( int windowSequence, sam_TNS_frame_info *tns_frame_info )
{
    int                       f, t, top, res, res2, compress;
    int                       short_flag, s, k;
    int                       top_bands;
    short                     *sp, tmp, s_mask, n_mask;
    sam_TNSfilt                   *tns_filt;
    sam_TNSinfo                   *tns_info;
    static short              sgn_mask[] = { 
	0x2, 0x4, 0x8     };
    static short              neg_mask[] = { 
	0xfffc, 0xfff8, 0xfff0     };


	if(windowSequence == 2) {
    	short_flag = 1;
    	tns_frame_info->n_subblocks = 8;
		top_bands = 14;
	} else {
    	short_flag = 0;
    	tns_frame_info->n_subblocks = 1;
		top_bands = 49;
	}


	for (s=0; s<tns_frame_info->n_subblocks; s++) {
		tns_info = &tns_frame_info->info[s];

		tns_info->n_filt = sam_getbits( short_flag ? 1 : 2 );
		if (!(tns_info->n_filt))
			continue;
		
		tns_info -> coef_res = res = sam_getbits( 1 ) + 3;
		top = top_bands;
		tns_filt = &tns_info->filt[ 0 ];
		for (f=tns_info->n_filt; f>0; f--)  {
			tns_filt->stop_band = top;
			tns_filt->length = sam_getbits( short_flag ? 4 : 6 );
			top = tns_filt->start_band = top - tns_filt->length;
			tns_filt->order = sam_getbits( short_flag ? 3 : 5 );

			if (tns_filt->order)  {
				tns_filt->direction = sam_getbits( 1 );
				compress = sam_getbits( 1 );
				tns_filt->coef_compress = compress;

				res2 = res - compress;
				s_mask = sgn_mask[ res2 - 2 ];
				n_mask = neg_mask[ res2 - 2 ];

				sp = tns_filt -> coef;
				k = 0;
				for (t=tns_filt->order; t>0; t--)  {
					tmp = sam_getbits( res2 );
					tns_filt->coef1[k++] = tmp;
					*sp++ = (tmp & s_mask) ? (tmp | n_mask) : tmp;
				}
			}
			tns_filt++;
		}
	}   /* subblock loop */
}

#ifdef	SRS
static int
sam_get_gcBuf(int window_sequence, BsBitStream *gc_streamCh)
{
	int	bd, wd, ad;
	unsigned long	max_band, natks, ltmp;
	int	loc;

	loc = gc_streamCh->currentBit;
	max_band = sam_getbits(NBANDSBITS);
	BsPutBit(gc_streamCh, max_band, NBANDSBITS);/* 	 0 < max_band <= 3 */

	switch (window_sequence) {
	case ONLY_LONG_SEQUENCE:
		for (bd = 1; bd <= max_band; bd++) {
			for (wd = 0; wd < 1; wd++) {
				natks = sam_getbits(NATKSBITS);
				BsPutBit(gc_streamCh, natks, NATKSBITS);
				for (ad = 0; ad < natks; ad++) {
					ltmp = sam_getbits(IDGAINBITS);
					BsPutBit(gc_streamCh, ltmp, IDGAINBITS);
					ltmp = sam_getbits(ATKLOCBITS);
					BsPutBit(gc_streamCh, ltmp, ATKLOCBITS);
				}
			}
		}
		break;
	case LONG_START_SEQUENCE:
		for (bd = 1; bd <= max_band; bd++) {
			for (wd = 0; wd < 2; wd++) {
				natks = sam_getbits(NATKSBITS);
				BsPutBit(gc_streamCh, natks, NATKSBITS);
				for (ad = 0; ad < natks; ad++) {
					ltmp = sam_getbits(IDGAINBITS);
					BsPutBit(gc_streamCh, ltmp, IDGAINBITS);
					if (wd == 0) {
						ltmp = sam_getbits(ATKLOCBITS_START_A);
						BsPutBit(gc_streamCh, ltmp, ATKLOCBITS_START_A);
					}
					else {
						ltmp = sam_getbits(ATKLOCBITS_START_B);
						BsPutBit(gc_streamCh, ltmp, ATKLOCBITS_START_B);
					}
				}
			}
		}
		break;
	case EIGHT_SHORT_SEQUENCE:
		for (bd = 1; bd <= max_band; bd++) {
			for (wd = 0; wd < 8; wd++) {
				natks = sam_getbits(NATKSBITS);
				BsPutBit(gc_streamCh, natks, NATKSBITS);
				for (ad = 0; ad < natks; ad++) {
					ltmp = sam_getbits(IDGAINBITS);
					BsPutBit(gc_streamCh, ltmp, IDGAINBITS);
					ltmp = sam_getbits(ATKLOCBITS_SHORT);
					BsPutBit(gc_streamCh, ltmp, ATKLOCBITS_SHORT);
				}
			}
		}
		break;
	case LONG_STOP_SEQUENCE:
		for (bd = 1; bd <= max_band; bd++) {
			for (wd = 0; wd < 2; wd++) {
				natks = sam_getbits(NATKSBITS);
				BsPutBit(gc_streamCh, natks, NATKSBITS);
				for (ad = 0; ad < natks; ad++) {
					ltmp = sam_getbits(IDGAINBITS);
					BsPutBit(gc_streamCh, ltmp, IDGAINBITS);
					if (wd == 0) {
						ltmp = sam_getbits(ATKLOCBITS_STOP_A);
						BsPutBit(gc_streamCh, ltmp, ATKLOCBITS_STOP_A);
					}
					else {
						ltmp = sam_getbits(ATKLOCBITS_STOP_B);
						BsPutBit(gc_streamCh, ltmp, ATKLOCBITS_STOP_B);
					}
				}
			}
		}
		break;
	default:
		return	-1;
	}
	return	gc_streamCh->currentBit - loc;
}
#endif	/* SRS */
