/*** 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 */

#ifdef STORM
    ab_feed -> databuffer[feedOffset++] = (unsigned char)data;
#else
    ab_feed -> databuffer[feedOffset++] = data;
#endif
    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;
          }

       }
}

#ifdef STORM
void out_fifo(short FAR pcm_sample[2][3][SBLIMIT], int num, frame_params *fr_ps, int done, FILE *outFile, unsigned long *psampFrames)
#else
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;
#endif
{
    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];
        }
    }
}
