/**********************************************************************
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 <math.h>
#include "sam_encode.h"

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

static int num_of_channels;
static int bitrate;
static int sampling_frequency_index;
static int sampling_frequency;
static int frame_length_flag;
static int block_size_samples;
static int core_coder_present=0;
static int coreCoderIdx=0;
static int coreUsedBits=0;
static enum JS_MASK corems_mask[SFB_NUM_MAX];
static TNS_INFO	*coretnsInfo;
static enum DC_FLAG coreFssControl[MAX_TIME_CHANNELS][SFB_NUM_MAX];
static int	fs_index[16]={
	96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
	16000, 12000, 11025,  8000,     0,     0,     0,     0
};

/* Frequency Selective Switch Control */

#define FSS_BANDS 16
typedef struct {
	int code[FSS_BANDS];
	int length[FSS_BANDS];
}FSS_CODE;
	 
static FSS_CODE fssCode={
	{0,20,21,22,23,24,25,8,9,26,27,28,29,30,31,1},
	{2, 5, 5, 5, 5, 5, 5,4,4, 5, 5, 5, 5, 5, 5, 2}
};


#ifdef __cplusplus
extern "C" {
#endif

#ifdef __cplusplus
}
#endif

void sam_init_encode_bsac(
		int numChannel,
		int sampling_rate,
		int bit_rate,
		int frame_size,
		int core_coder
)
{
	int	i;

	num_of_channels = numChannel;
	block_size_samples = frame_size;
	if(frame_size == 1024)
		frame_length_flag = 0;
	else
		frame_length_flag = 1;
	if(!core_coder || core_coder == NO_CORE)
		core_coder_present = 0;
	else
		core_coder_present = 1;
	coreCoderIdx = core_coder;
	for(i = 0; i < 12; i++) if(sampling_rate == fs_index[i]) {
		sampling_frequency_index = i;
		break;
	}
	sampling_frequency = sampling_rate;
	bitrate = bit_rate;

	sam_scale_bits_init_enc(sampling_rate, block_size_samples);
}

int sam_encode_frame(
		int num_of_chan,
		WINDOW_TYPE block_type,
		Window_shape	window_shape,
		int sfb_offset[],
		int nr_of_sfs,
		int num_window_groups,
		int window_group_length[],
		int	quant[][1024],
		int	scfacs[][MAX_SCFAC_BANDS],
		int pns_sfb_start,
		int pns_sfb_flag[][SFB_NUM_MAX],
		int pns_sfb_nrg[][SFB_NUM_MAX],
		BsBitStream *fixed_stream,
		BsBitBuffer **gcBitBuf,
		int i_ch,
		int w_flag,
		int avr_bits)
{
	int	i, j, b, ch;
	int common_window=1;
	int	maxSfb[2];
	int groupInfo[2][8];
	int	windowSequence[2];
	int	windowShape[2];
	int	scalefactors[2][MAX_SCFAC_BANDS];
	int	swb_offset[2][MAX_SCFAC_BANDS];
	int	is_info[MAX_SCFAC_BANDS];
	int pns_sfb_mode[MAX_SCFAC_BANDS];
	int	gain_control_data_present[2];
	int	is_intensity;
	int	stereo_mode;
	int	stereo_info[MAX_SCFAC_BANDS];
	int	frameSize;
	int	fsize_len;
	int target;
	int	abits;
	int	ubits;
	int	bottom, top;
	int	nch, num_win, nnch;
	int fsize_position;
	static int framecount=0;
	static int totalframe=0;
	static int frameStart=1;

	nch = i_ch + 1;

	/*
	 *  START BSAC
	 */

	/* initialize */
	is_intensity = 0;
	stereo_mode = 0;
	windowSequence[i_ch] = block_type;
	windowShape[i_ch] = window_shape;

	for(i = 0; i < MAX_SCFAC_BANDS; i++) {
		scalefactors[i_ch][i] = scfacs[i_ch][i];
		stereo_info[i] = 0;
		swb_offset[i_ch][i] = sfb_offset[i];
		pns_sfb_mode[i] = 0;
	}

	top = 0;
	for(ch = i_ch; ch < nch; ch++) for(i = 0; i < nr_of_sfs; i++)
		if(pns_sfb_flag[ch][i]) {
			top = 1;
			break;
		}
	if(top == 0) pns_sfb_start = -1;


	j = 0;
	for(b = 0; b < num_window_groups; b++) {
		groupInfo[i_ch][j++] = 0;
		for(i = 1; i < window_group_length[b]; i++)
			groupInfo[i_ch][j++] = 1;
	}

	maxSfb[i_ch] = nr_of_sfs / num_window_groups - 3;

	bottom = 0;
	for(ch = i_ch; ch < nch; ch++) for(i = 0; i < block_size_samples; i++)
		if(quant[ch][i]) {
			bottom = 1;
			break;
		}
	if(bottom == 0) maxSfb[i_ch] = 0;

	if(w_flag) {

		sam_init_bs();

		nch = 1;
		if(num_of_chan == 2) {
			for(i = 0; i < MAX_SCFAC_BANDS; i++) {
				scalefactors[1][i] = scfacs[1][i];
				swb_offset[1][i] = swb_offset[0][i];
			}
			windowSequence[1] = windowSequence[0];
			windowShape[1] = windowShape[0];
			maxSfb[1] = maxSfb[0];

			for(i = 0; i < 8; i++)
				groupInfo[1][i] = groupInfo[0][i];
			nch = 2;
		}
	}
	if(pns_sfb_start != -1) {
		for(ch = i_ch; ch < nch; ch++) for(i = 0; i < nr_of_sfs; i++)
			if(i >= pns_sfb_start)
				scalefactors[ch][i] = pns_sfb_nrg[ch][i];
	}

	ubits = 0;

	/* make header */

	if(!coreCoderIdx && frameStart) {
		/* number of channels */
		if(w_flag) sam_putbits2bs(nch, 3);	
		ubits += 3;

		/* sampling_frequency_index */
		if(w_flag) sam_putbits2bs(sampling_frequency_index, 4);
		ubits += 4;

		/* frame_length_flag */
		if(w_flag) sam_putbits2bs(frame_length_flag, 1);
		ubits += 1;
	}

	nnch = nch;
	if(num_of_chan == 2 && common_window)
		nnch = 1;

	nnch = 1;

/***** BEGIN tf_scalable_main_header () *******/

	/***** ics_info() *******/
	for(ch = 0; ch < nnch; ch++) {
		if(!coreCoderIdx || coreCoderIdx != NTT_TVQ) {
		if(w_flag) sam_putbits2bs(0x00, 1);	/* ics_reserved_bit : 1 */
		ubits += 1;

		if(w_flag) sam_putbits2bs((int)windowSequence[ch], 2);
		ubits += 2;

		if(w_flag) sam_putbits2bs((int)windowShape[ch], 1);
		ubits += 1;
		}

		if(windowSequence[ch] == EIGHT_SHORT_SEQUENCE) {
			if(w_flag) sam_putbits2bs(maxSfb[ch], 4);
			ubits += 4;
			if(w_flag) for(i = 1; i < 8; i++)
				sam_putbits2bs(groupInfo[ch][i], 1);
			ubits += 7;
		} else {
			if(w_flag) sam_putbits2bs(maxSfb[ch], 6);
			ubits += 6;
			if(w_flag) sam_putbits2bs(0, 1);	/* predictor_data_present : 1 */
			ubits += 1;
		}
	}
	/****** end of ics_info() ******/
	/* stereo mode */
	if(i_ch == 0 && nch == 2) {
		if(core_coder_present)
			stereo_mode = 2;
		if(w_flag) sam_putbits2bs(stereo_mode, 2);
		ubits += 2;
	}


	for(ch = i_ch; ch < nch; ch++) {
		if(w_flag) sam_putbits2bs(0, 1);	/* tns_data_present : 1 */
		ubits += 1;
		/* TNS data should be included here ! */

		/* gain control data */
		if(gcBitBuf && gcBitBuf[ch] && (gcBitBuf[ch]->numBit > 0)) {
			if(w_flag) sam_putbits2bs(0x01, 1);
			ubits += 1;
			{
				int	num_bytes, remain_bits;

				num_bytes = gcBitBuf[ch]->numBit/8;
				if(w_flag) for(i = 0; i < num_bytes; i++)
					sam_putbits2bs(gcBitBuf[ch]->data[i], 8);
				ubits += (8 * num_bytes);
				remain_bits = gcBitBuf[ch]->numBit - (num_bytes * 8);
				if(w_flag) sam_putbits2bs(gcBitBuf[ch]->data[i]>>(8-remain_bits), remain_bits);
				ubits += remain_bits;
			}
		} else {
			if(w_flag) sam_putbits2bs(0x00, 1);
			ubits += 1;
		}

		/* diff_control_data */
		if(core_coder_present && ch == 0) {
			unsigned int fss_bands;

			if(windowSequence[0] == ONLY_SHORT_WINDOW) {
				fss_bands = 8;

				if(w_flag) for(i = 0; i < fss_bands; i++)
					sam_putbits2bs(coreFssControl[ch][i], 1);
				ubits += fss_bands;
			} else {
				unsigned int fssGroup;
				unsigned int fssNoGroups;

				switch(sampling_frequency) {
				case 48000: fss_bands = 20; break;
				case 32000: fss_bands = 24; break;
				case 24000: fss_bands = 32; break;
				case 16000: fss_bands = 32; break;
				default: CommonExit(1, "scalable encoder doesn't support this sampling rate currently");
				}

				fssNoGroups=fss_bands >> 2;
				for( fssGroup = 0; fssGroup < fssNoGroups; fssGroup++) {
					unsigned int group = 0;
					for(i = 0; i < 4; i++) {
						group <<= 1;
						if(coreFssControl[ch][(fssGroup<<2)+i] == DC_SIMUL) {
							group |= 0x1;
						}
					}
					if(w_flag) sam_putbits2bs(fssCode.code[group], fssCode.length[group]);
					ubits += fssCode.length[group];
				}
			}
		}
	}
/***** END tf_scalable_main_header () *******/

	fsize_position = ubits;
	fsize_len = 10;
	if(nch == 2) fsize_len = 11;
	if(w_flag) sam_putbits2bs(0x00, fsize_len);
	ubits += fsize_len;

	target = (bitrate / 1000) - 16;
	if(w_flag) sam_putbits2bs(target, 6);
	ubits += 6;


	if(avr_bits == 0)
		abits = 10000;
	else
		abits = avr_bits - 8;

	if(core_coder_present) {
		ubits += coreUsedBits;
		abits += coreUsedBits;
	}

	frameSize = sam_encode_data(bitrate, common_window, windowSequence, scalefactors,
			groupInfo, quant, maxSfb, swb_offset, nr_of_sfs, stereo_mode, stereo_info,
			pns_sfb_start, pns_sfb_flag, pns_sfb_nrg, pns_sfb_mode,
			block_size_samples, ubits, abits, i_ch, nch, w_flag);

	if(core_coder_present)
		frameSize -= coreUsedBits;

	if(w_flag) {
		/* byte alignment */
		if((frameSize % 8)) {
			frameSize += sam_putbits2bs(0x00, (8 - (frameSize % 8)));
		}
		sam_frame_length_rewrite2bs(frameSize, fsize_position, fsize_len);

		sam_bsflush(fixed_stream, frameSize);
		frameStart = 0;
		totalframe += frameSize;
	} else {
		frameSize += 16;
	}

	return frameSize;
}

void sam_prepare_EncodeScalHeader(
	enum DC_FLAG FssControl[MAX_TIME_CHANNELS][SFB_NUM_MAX],
	enum JS_MASK ms_mask[SFB_NUM_MAX],
	TNS_INFO	*tnsInfo[MAX_TIME_CHANNELS],
	int core_coder_bits)
{
	int	i,j;

	for(i = 0; i < MAX_TIME_CHANNELS; i++)
		for(j = 0; j < SFB_NUM_MAX; j++)
			coreFssControl[i][j] = FssControl[i][j];

	for(j = 0; j < SFB_NUM_MAX; j++)
		corems_mask[j] = ms_mask[j];

	coretnsInfo = (TNS_INFO *)tnsInfo[0];
	coreUsedBits = core_coder_bits;
}

void my_debug(char *str)
{
	write(2, str, strlen(str));
}
