/********************************************************

         IMA ADPCM audio decoder
	 Copyright 2000 Eugene Kuznetsov (divx@euro.ru)

*********************************************************/

#include <stdio.h>
//#include <iostream>
//using namespace std;

#include "adpcm.h"

ADPCM_Decoder::ADPCM_Decoder(const CodecInfo& info, const WAVEFORMATEX* wf)
    :IAudioDecoder(info, wf)
{
    state.valprev = 0;
    state.index = 0;
    adpcm_init_table();
}

size_t ADPCM_Decoder::GetMinSize()
{
    return in_fmt.nBlockAlign * in_fmt.nChannels;
}

#warning TEST WITH MONO
int ADPCM_Decoder::Convert(const void* in_data, size_t in_size,
			   void* out_data, size_t out_size,
			   size_t* size_read, size_t* size_written)
{
    if (!in_data || !out_data)
	return -1;

    // here is still some bug but I can't see it - but
    // the sound is not that bad...

    size_t nblocks = in_size / in_fmt.nBlockAlign;
    int smpl = 2 * in_fmt.nBlockAlign / in_fmt.nChannels
	- 4 * in_fmt.nChannels; // 4 bytes per channel

    int16_t* out_ptr = (int16_t*) out_data;

    size_t minosmpl = out_size / (2 * (smpl + 1) * in_fmt.nChannels);

    if (nblocks > minosmpl)
	nblocks = minosmpl;
    int* in_ptr = (int*) in_data;
    int in_ch[smpl / (4 * in_fmt.nChannels)];
    int16_t out_ch[smpl];

    //printf("in: %d    al: %d  ch: %d  ns %d   sampl %d\n",
    //       in_size, in_fmt.nBlockAlign, in_fmt.nChannels,  nblocks, smpl);
    for (unsigned i = 0; i < nblocks; i++)
    {
	//printf("i %d    lop %d\n", i, sizeof(in_ch)/sizeof(in_ch[0]));
	for (int c = 0; c < in_fmt.nChannels; c++)
	{
	    int* inp = in_ptr + in_fmt.nChannels + c;

	    for (unsigned j = 0; j < sizeof(in_ch)/sizeof(in_ch[0]); j++)
	    {
		in_ch[j] = *inp;
		inp += in_fmt.nChannels;
	    }

	    int16_t* dest = out_ptr + c;
	    uint8_t* hdr = (uint8_t*) (in_ptr + c);
	    //printf("Data 0x%08x \n", ((int*)hdr)[0]);
	    state.valprev = (in_ptr[1] << 8) | in_ptr[0];
	    *dest = state.valprev;
	    state.index = hdr[2];
	    adpcm_decoder(out_ch, in_ch, smpl, &state);

	    for (int j = 0; j < smpl; j++)
	    {
		dest += in_fmt.nChannels;
		*dest = out_ch[j];
	    }
	}
	in_ptr += in_fmt.nBlockAlign / sizeof(int);
	out_ptr += (smpl + 1) * in_fmt.nChannels;
    }
#if 0
    if (0 && in_fmt.nChannels == 1)
    {
	int smpl = in_fmt.nBlockAlign - 4;

	nblocks = in_size / in_fmt.nBlockAlign;
	if(nblocks>out_size/P1)
	    nblocks=out_size/P1;
        uint8_t* in_ptr = (uint8_t*) in_data;
	for(unsigned i = 0; i < nblocks; i++)
	{
	    int* inp = (int*)(in_ptr + 4);
	    //printf("Print size %d  out: %d    %d    %d    %d\n", in_size,
	    //       out_size, i);
	    //printf("Data 0x%08x    0x%08x  0x%08x\n", inp[-1], inp[0], inp[1]);
	    if (i > 0)
                printf("prev %d\n", dest[-1]);
	    state.valprev=inp[-1];
	    state.index=inp[-1]>>16;
	    dest[0]=state.valprev;
	    printf("now %d\n", dest[0]);
	    adpcm_decoder((char*)inp, dest + 1, smpl, &state);
	    in_ptr += in_fmt.nBlockAlign;
            dest += smpl + 1;
	}
    }
#endif

    if (size_read)
	*size_read = nblocks * in_fmt.nBlockAlign;
    if (size_written)
	*size_written = nblocks * 2 * (smpl + 1) * in_fmt.nChannels;
    //printf("###  %d  %d\n", *size_read, *size_written);
    return 0;
}
