/*** audio.c - MPEG Layer 1/2 audio handling in a MPEG stream ***/

/* (c) 1999 Jesper Svennevid */

#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>

#include "config.h"
#include "mpeg2dec.h"
#include "audio.h"
#include "global.h"
#include "mpegaudio/common.h"
#include "mpegaudio/decoder.h"

extern int Decode_Audio();

struct AudioBuffer
{
	/* contains as a max */ 

	unsigned char *databuffer;

	struct AudioBuffer *next;
};

#define MAX_AUDIOBUFFER_SIZE	65536	/* size of one audio-buffer */
#define MAX_AUDIOFRAMES_DECODE	16	/* number of audio-frames to decode before flushing */

struct AudioBuffer *ab_current = NULL;	/* current audio-buffer reading from */
struct AudioBuffer *ab_feed = NULL;	/* current audio-buffer feeding into */
struct AudioBuffer *ab_free = NULL;	/* free data-buffers */

/* writing offset into current buffer */

unsigned long feedOffset = NULL;

/* reading offset into current buffer */

unsigned long readOffset = NULL;

/* how much data present in the buffer */

unsigned long audioBufferSize = NULL;

void audio_feedbuffer( unsigned char *data )
{
	if(ab_feed)
	{
		if(feedOffset>=MAX_AUDIOBUFFER_SIZE)
		{
			if(ab_free)
			{
				struct AudioBuffer *temp = ab_free;

				ab_free = temp -> next;
				temp -> next = NULL;
				ab_feed -> next = temp;
				ab_feed = temp;
			}
			else
			{
				struct AudioBuffer *temp = malloc(sizeof(struct AudioBuffer));
				if(temp)
				{
					if( (temp -> databuffer = malloc(MAX_AUDIOBUFFER_SIZE)) )
					{
						temp -> next = NULL;
						ab_feed -> next = temp;
						ab_feed = temp;
					}
					else
						exit(0);
				}
				else
					exit(0);
			}
			feedOffset = NULL;
		}
	}
	else
	{
		if( (ab_feed = malloc(sizeof(struct AudioBuffer))) )
		{
			if( !(ab_feed -> databuffer = malloc(MAX_AUDIOBUFFER_SIZE)) )
				exit(0);
		}
		else
			exit(0);
		ab_current = ab_feed;
	}

	/* feed mpeg-audio data to buffer */

	ab_feed -> databuffer[feedOffset++] = data;
	audioBufferSize++;
}

unsigned char audio_pollbuffer()
{
	if(ab_current)
	{
		if((ab_current==ab_feed)&&(readOffset>=feedOffset))
			return 0x00;
		if(readOffset>=MAX_AUDIOBUFFER_SIZE)
		{
			struct AudioBuffer *temp = ab_current -> next;

			if(!temp) return 0x00;

			ab_current -> next = ab_free;
			ab_free = ab_current;
			ab_current = temp;			
			readOffset = NULL;
		}
		if(audioBufferSize)
		{
			audioBufferSize--;
			return ab_current -> databuffer[readOffset++];
		}
	}
	return 0x00;
}

unsigned long audioOpened = NULL;

typedef short PCM[2][3][SBLIMIT];
	PCM FAR *pcm_sample;
	PCM FAR *pcm_sample_full;
typedef unsigned int SAM[2][3][SBLIMIT];
	SAM FAR *sample;
	SAM FAR *sample_full;
typedef double FRA[2][3][SBLIMIT];
	FRA FAR *fraction;
	FRA FAR *fraction_full;
typedef double VE[2][HAN_SIZE];
	VE FAR *w;
	VE FAR *w_full;

    layer             info;

    int               error_protection, crc_error_count, total_error_count;
    unsigned int      old_crc, new_crc;
    unsigned int      bit_alloc[2][SBLIMIT], scfsi[2][SBLIMIT],
                      scale_index[2][3][SBLIMIT];
    unsigned long     bitsPerSlot, samplesPerFrame, frameNum = 0;
    unsigned long     frameBits, gotBits = 0;
    char              t[50];
    int topSb = 0;
    int notEnoughData = NULL;

int Decode_Audio()
{
	int i,j,k,sync,stereo,clip;
	static unsigned long sample_frames;
	static Bit_stream_struc bs;
	static frame_params fr_ps;
	static int done;
	static unsigned long bufferCounter;

	extern FILE *pipe_file;

	if(!Enable_Sound) return 0;

	if(audioBufferSize<1024)
		return 0;	/* hmm, we should always have data to poll */

		if(!audioOpened)
		{
		    pcm_sample = (PCM FAR *) mem_alloc((long) sizeof(PCM), "PCM Samp");
		    sample = (SAM FAR *) mem_alloc((long) sizeof(SAM), "Sample");
		    fraction = (FRA FAR *) mem_alloc((long) sizeof(FRA), "fraction");
		    w = (VE FAR *) mem_alloc((long) sizeof(VE), "w");

			done = FALSE;
			bufferCounter = NULL;

		    fr_ps.header = &info;
		    fr_ps.tab_num = -1;                /* no table loaded */
		    fr_ps.alloc = NULL;
		    for (i=0;i<HAN_SIZE;i++) for (j=0;j<2;j++) (*w)[j][i] = 0.0;

		    open_bit_stream_r(&bs, "", BUFFER_SIZE);

		    sample_frames = 0;


			audioOpened = 1L;
		}

	if(done)
		return 0;

	//if(!notEnoughData)
	//{
	        sync = seek_sync(&bs, SYNC_WORD, SYNC_WORD_LNGTH);
		frameBits = sstell(&bs) - gotBits;
	       gotBits += frameBits;

	       if (!sync) return 0;

		decode_info(&bs, &fr_ps);
		hdr_to_frps(&fr_ps);
	//}
	//else
	//	notEnoughData = NULL;

		stereo = fr_ps.stereo;
		error_protection = info.error_protection;
		crc_error_count = 0;
		total_error_count = 0;

	//if(audioBufferSize<(((144*(bitrate[info.lay-1][info.bitrate_index]*1000)/((long)(s_freq[info.sampling_frequency]*1000)))+(info.padding?1:0))*2))
	//{
	//	printf("out of data\n");
	//	notEnoughData = 1L;
	//	return 0;
	//}

	if(!pipe_file)
	{
		char buffer[256];

		sprintf(buffer,"AUDIO:B 16 C %ld F %ld",stereo,((long)(s_freq[info.sampling_frequency]*1000)));
		pipe_file = fopen(buffer,"w");
	
	}

       if (error_protection) buffer_CRC(&bs, &old_crc);
       switch (info.lay) {

          case 1: {

             bitsPerSlot = 32;        samplesPerFrame = 384;
             I_decode_bitalloc(&bs,bit_alloc,&fr_ps);
             I_decode_scale(&bs, bit_alloc, scale_index, &fr_ps);

             clip = 0;
             for (i=0;i<SCALE_BLOCK;i++) {
                I_buffer_sample(&bs,(*sample),bit_alloc,&fr_ps);
                I_dequantize_sample(*sample,*fraction,bit_alloc,&fr_ps);
                I_denormalize_sample((*fraction),scale_index,&fr_ps);
                if(topSb>0)        /* clear channels to 0 */
                   for(j=topSb; j<fr_ps.sblimit; ++j)
                      for(k=0; k<stereo; ++k)
                         (*fraction)[k][0][j] = 0;

                for (j=0;j<stereo;j++) {
                   clip += SubBandSynthesis (&((*fraction)[j][0][0]), j,
                                             &((*pcm_sample)[j][0][0]));
                }
                if(pipe_file) out_fifo(*pcm_sample, 1, &fr_ps, done,
                         pipe_file, &sample_frames);
             }
             return 1;
          }

          case 2: {
             bitsPerSlot = 8;        samplesPerFrame = 1152;
             II_decode_bitalloc(&bs, bit_alloc, &fr_ps);
             II_decode_scale(&bs, scfsi, bit_alloc, scale_index, &fr_ps);

             clip = 0;
             for (i=0;i<SCALE_BLOCK;i++) {
                II_buffer_sample(&bs,(*sample),bit_alloc,&fr_ps);
                II_dequantize_sample((*sample),bit_alloc,(*fraction),&fr_ps);
                II_denormalize_sample((*fraction),scale_index,&fr_ps,i>>2);

                if(topSb>0)        /* debug : clear channels to 0 */
                   for(j=topSb; j<fr_ps.sblimit; ++j)
                      for(k=0; k<stereo; ++k)
                         (*fraction)[k][0][j] =
                         (*fraction)[k][1][j] =
                         (*fraction)[k][2][j] = 0;

                for (j=0;j<3;j++) for (k=0;k<stereo;k++) {
                   clip += SubBandSynthesis (&((*fraction)[k][j][0]), k,
                                             &((*pcm_sample)[k][j][0]));
                }
                if(pipe_file) out_fifo(*pcm_sample, 3, &fr_ps, done, pipe_file,
                         &sample_frames);
             }
             return 1;
          }

       }
}

void out_fifo(pcm_sample, num, fr_ps, done, outFile, psampFrames)
short FAR pcm_sample[2][3][SBLIMIT];
int num;
frame_params *fr_ps;
int done;
FILE *outFile;
unsigned long *psampFrames;
{
	int i,j,l;
	int stereo = fr_ps->stereo;
	int sblimit = fr_ps->sblimit;
	static short int outsamp[1600];
	static long k = 0;

	for (i=0;i<num;i++) for (j=0;j<SBLIMIT;j++)
	{
		(*psampFrames)++;
		for (l=0;l<stereo;l++)
		{
			if (!(k%(1600)) && k)
			{
				fwrite(outsamp,2,1600,outFile);
				k = 0;
			}
			outsamp[k++] = pcm_sample[l][i][j];
		}
	}
}
