#include "common.h"
#include "decodednet.h"

#define __inline inline

Real_dnet *init_dnet(void)
{
	Real_internal *glob;

	if ((glob=malloc(sizeof(Real_internal))))
	{
		memset(glob,0,sizeof(Real_internal));

		if (glob->state = a52_init(0))
		{
#if 1
			glob->level = 1;
			glob->bias = 384;
#else
			glob->level = 32767;
			glob->bias = 0;
#endif

			return (Real_dnet *)glob;
		}

		free(glob);
	}

	return NULL;
}

void free_dnet(Real_dnet *global)
{
	Real_internal *glob;

	if (!global) return;
	glob = (Real_internal *)global;

	if (glob->state)
		a52_free(glob->state);

	free(glob);
}

void swapbytes(unsigned char *in, unsigned char *out, unsigned int len)
{
	unsigned int i;

	if ((len & 3) == 0)
	{
		for (i=0; i<len; i+=4)
		{
			*(out++) = in[1];
			*(out++) = in[0];
			*(out++) = in[3];
			*(out++) = in[2];

			in += 4;
		}
	} else {
		for (i=0; i<len; i+=2)
		{
			*(out++) = in[1];
			*(out++) = in[0];

			in += 2;
		}
	}
}

int decode_dnet(Real_dnet *global, unsigned char *in, signed short *out, int *freq, int chans)
{
	Real_internal *glob;

	if (!global) return 0;
	glob = (Real_internal *)global;

	return decode(glob, in, out, freq, chans);
}

#if 1
static __inline int16_t convert (int32_t i)
{
    if (i > 0x43c07fff)
	return 32767;
    else if (i < 0x43bf8000)
	return -32768;
    else
	return i - 0x43c00000;
}

static __inline int float_to_int (float * _f, int16_t * s16, int flags)
{
    int i;
    int32_t * f = (int32_t *) _f;

    switch (flags) {
    case A52_MONO:
	for (i = 0; i < 256; i++) {
	    s16[i] = convert (f[i]);
	}
	break;
    case A52_CHANNEL:
    case A52_STEREO:
    case A52_DOLBY:
	for (i = 0; i < 512; i+=2) {
	    s16[i] = convert (f[i/2]);
	    s16[i+1] = convert (f[i/2+256]);
	}
	break;
	default:
	/* This shouldn't happen */
	i = 0;
	break;
    }

	return i;
}
#else
static __inline int16_t convert (sample_t _f)
{
    if (_f > 32767.0)
	return 32767;
    else if (_f < -32768.0)
	return -32768;
    else
	return (int16_t) _f;
}

static __inline int float_to_int (sample_t * f, int16_t * s16, int flags)
{
    int i;

    switch (flags) {
    case A52_MONO:
	for (i = 0; i < 256; i++) {
	    s16[i] = convert (f[i]);
	}
	break;
    case A52_CHANNEL:
    case A52_STEREO:
    case A52_DOLBY:
	for (i = 0; i < 512; i+=2) {
	    s16[i] = convert (f[i/2]);
	    s16[i+1] = convert (f[i/2+256]);
	}
	break;
	default:
	/* This shouldn't happen */
	i = 0;
	break;
    }

	return i;
}
#endif

static int decode(Real_internal *global, unsigned char *in, signed short *out, int *freq, int chans)
{
	int i, total;
	sample_t *samples;

	total = 0;

	if (!a52_syncinfo(in, &global->flags, freq, &global->bitrate)) return 0;
	global->flags = A52_ADJUST_LEVEL | ((chans==1) ? A52_MONO : A52_STEREO);

	if (a52_frame(global->state, in, &global->flags, &global->level, global->bias)) return 0;
	a52_dynrng(global->state, NULL, NULL);

	samples = a52_samples(global->state);

	for(i=0;i<6;i++)
	{
		if (a52_block(global->state))
			return total;

		total += float_to_int(samples, out+total, global->flags);
	}

	return total;
}
