#include "decodermp3.h"
int S = 0;
enum mad_flow decodermp3::mp3output(void *data, struct mad_header const *header, struct mad_pcm *pcm){
    decodermp3* self = (decodermp3*) data;


    unsigned int nchannels, nsamples;
    mad_fixed_t const *left_ch, *right_ch;
    int sf = self->getfactor( pcm->samplerate );


    /* pcm->samplerate contains the sampling frequency */
    nchannels = pcm->channels;
    nsamples  = pcm->length;
    left_ch   = pcm->samples[0];
    right_ch  = pcm->samples[1];


/*if( self->bufferpos >= self->sblen ){
            self->output( self->buffer, self->sblen );
        }*/

    //int l = nsamples * self->bps / 8 * self->chan + self->decodebufpos;
    //self->decodebuf = realloc( self->decodebuf, l );
    S += nsamples;
    //printf("%i\t", S);
    while (nsamples--) {

        int64_t sample;
        sample = self->scale(*left_ch++);
        self->samps.push( &sample, self->bps/8 );
        if (nchannels == 2)
            sample = self->scale(*right_ch++);
        if( self->chan == 2 )
            self->samps.push( &sample, self->bps/8 );
    }

    /*int carry = 0;
    if( sf < 0xFF ){
        while( l*0xFF/sf > self->sblen ){
            int newpo = 0;
            for( int k = 0; k < self->chan; ++k){
                carry = 0;
                int64_t s = 0;
                int64_t p = 0;
                int prat = 0;
                for( int i = k; i < l / (self->bps/8); ){

                    int t = 1;
                    while( carry < 0xFF ){
                        carry += sf;
                        if( carry < 0xFF ) { s += B.get(i+=self->chan); ++t; }
                    }
                    s /= t;
                    int64_t o = B.get(i+=self->chan);
                    carry -= 0xFF;
                    s = self->mixsamples( o, s, sf - carry );
                    s = self->mixsamples( s, p, prat );
                    int po =  self->bufferpos + i * (self->bps / 8) * self->chan;

                    A.set( po , s );
                    newpo = po;

                    p = o;
                    prat = carry;
                    if( po > self->sblen - self->bps/8*self->chan )
                        break;
                }
            }
            self->bufferpos = newpo;
            if( self->bufferpos >= self->sblen ){
                self->output( self->buffer, self->sblen );
            }
        }

    }*/
    //printf("=p");
    return MAD_FLOW_CONTINUE;
}

enum mad_flow decodermp3::mp3input(void *data, struct mad_stream *stream){

    decodermp3* self = (decodermp3*) data;
    int len;
    //self->data->seek( (void*)stream->next_frame );
    self->data->get(0, &len);
    if (self->data->eof()){

        return MAD_FLOW_STOP;
    }
    mad_stream_buffer(stream, (const unsigned char*)(self->data->get( len, 0 )), len);

    return MAD_FLOW_CONTINUE;
}

enum mad_flow decodermp3::mp3error(void *data, struct mad_stream *stream, struct mad_frame *frame){
    decodermp3* self = (decodermp3*) data;
    return MAD_FLOW_CONTINUE;
}

inline int64_t decodermp3::scale( mad_fixed_t sample ){
  /* round */
  sample += (1L << (MAD_F_FRACBITS - bps));

  /* clip */
  if (sample >= MAD_F_ONE)
    sample = MAD_F_ONE - 1;
  else if (sample < -MAD_F_ONE)
    sample = -MAD_F_ONE;

  /* quantize */
  return sample >> (MAD_F_FRACBITS + 1 - bps);
}


decodermp3::decodermp3( decoder::info a ){

    __init__( a );
    decodermp3::info* aa = (decodermp3::info*) data;

    mad_decoder_init(&mydecoder, (void*) this, mp3input, 0, 0, mp3output, mp3error, 0 );
}

void decodermp3::decode( ){
    mad_decoder_run(&mydecoder, MAD_DECODER_MODE_SYNC);
    delete data;
    data = new indata();
}

decodermp3::~decodermp3( ){
    mad_decoder_finish(&mydecoder);

    __destroy__();
}


