/*

libdemac - A Monkey's Audio decoder

Copyright (C) Dave Chapman 2007

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA

*/

#include <inttypes.h>
#include <string.h>

#include "parser.h"
#include "predictor.h"

#include "vector_math32.h"

/* Return 0 if x is zero, -1 if x is positive, 1 if x is negative */
#define SIGN(x) (x) ? (((x) > 0) ? -1 : 1) : 0

static const int32_t initial_coeffs[4] = {
  360, 317, -109, 98
};

static void init_predictor(struct predictor_t* p)
{
    /* Zero the history buffers */
    memset(p->historybuffer, 0, (PREDICTOR_ORDER*4) * sizeof(int32_t));
    p->delayA = p->historybuffer + PREDICTOR_ORDER*4;
    p->delayB = p->historybuffer + PREDICTOR_ORDER*3;
    p->adaptcoeffsA = p->historybuffer + PREDICTOR_ORDER*2;
    p->adaptcoeffsB = p->historybuffer + PREDICTOR_ORDER;

    /* Initialise and zero the co-efficients */
    memcpy(p->coeffsA, initial_coeffs, sizeof(initial_coeffs));
    memset(p->coeffsB, 0, sizeof(p->coeffsB));

    p->filterA = 0;
    p->filterB = 0;
    
    p->lastA = 0;
}

static int do_predictor_decode(struct predictor_t* p, int32_t A, int32_t nB)
{
    int32_t predictionA, predictionB, currentA;

    p->delayA[0] = p->lastA;
    p->delayA[-1] = p->delayA[0] - p->delayA[-1];

    predictionA = scalarproduct4_rev32(p->coeffsA,p->delayA);

    /*  Apply a scaled first-order filter compression */
    p->delayB[0] = nB - ((p->filterB * 31) >> 5);
    p->filterB = nB;

    p->delayB[-1] = p->delayB[0] - p->delayB[-1];

    predictionB = scalarproduct5_rev32(p->coeffsB,p->delayB);

    currentA = A + ((predictionA + (predictionB >> 1)) >> 10);

    p->adaptcoeffsA[0] = SIGN(p->delayA[0]);
    p->adaptcoeffsA[-1] = SIGN(p->delayA[-1]);

    p->adaptcoeffsB[0] = SIGN(p->delayB[0]);
    p->adaptcoeffsB[-1] = SIGN(p->delayB[-1]);

    if (A > 0) 
    {
        vector_sub4_rev32(p->coeffsA, p->adaptcoeffsA);
        vector_sub5_rev32(p->coeffsB, p->adaptcoeffsB);
    }
    else if (A < 0) 
    {
        vector_add4_rev32(p->coeffsA, p->adaptcoeffsA);
        vector_add5_rev32(p->coeffsB, p->adaptcoeffsB);
    }

    p->delayA++;
    p->delayB++;
    p->adaptcoeffsA++;
    p->adaptcoeffsB++;

    /* Have we filled the history buffer? */
    if (p->delayA == p->historybuffer + HISTORY_SIZE + (PREDICTOR_ORDER*4)) {
        memmove(p->historybuffer, p->delayA - (PREDICTOR_ORDER*4), 
                (PREDICTOR_ORDER*4) * sizeof(int32_t));
        p->delayA = p->historybuffer + PREDICTOR_ORDER*4;
        p->delayB = p->historybuffer + PREDICTOR_ORDER*3;
        p->adaptcoeffsA = p->historybuffer + PREDICTOR_ORDER*2;
        p->adaptcoeffsB = p->historybuffer + PREDICTOR_ORDER;
    }

    p->lastA = currentA;
    p->filterA =  currentA + ((p->filterA * 31) >> 5);

    return p->filterA;
}

static int32_t X;

void init_predictor_decoder(struct ape_ctx_t* ape_ctx)
{
    X = 0;

    init_predictor(&ape_ctx->predictorY);
    init_predictor(&ape_ctx->predictorX);
}

int predictor_decode_stereo(struct ape_ctx_t* ape_ctx, int32_t* decoded0, int32_t* decoded1, int count) ICODE_ATTR;
int predictor_decode_stereo(struct ape_ctx_t* ape_ctx, int32_t* decoded0, int32_t* decoded1, int count)
{
    while (count--)
    {
        *decoded0 = do_predictor_decode(&ape_ctx->predictorY, *decoded0, X);
        X = do_predictor_decode(&ape_ctx->predictorX, *decoded1, *(decoded0)++);
        *(decoded1++) = X;
    }

    return 0;
}

int predictor_decode_mono(struct ape_ctx_t* ape_ctx, int32_t* decoded0, int count)
{
    struct predictor_t* p = &ape_ctx->predictorY;
    int32_t predictionA, currentA, A;

    currentA = p->lastA;

    while (count--)
    {
        A = *decoded0;

        p->delayA[0] = currentA;
        p->delayA[-1] = p->delayA[0] - p->delayA[-1];

        predictionA = (p->delayA[0] * p->coeffsA[0]) + 
                      (p->delayA[-1] * p->coeffsA[1]) + 
                      (p->delayA[-2] * p->coeffsA[2]) + 
                      (p->delayA[-3] * p->coeffsA[3]);

        currentA = A + (predictionA >> 10);

        p->adaptcoeffsA[0] = (p->delayA[0]) ? ((p->delayA[0] >> 30) & 2) - 1 : 0;
        p->adaptcoeffsA[-1] = (p->delayA[-1]) ? ((p->delayA[-1] >> 30) & 2) - 1 : 0;
        
        if (A > 0) 
        {
            p->coeffsA[0] -= p->adaptcoeffsA[0];
            p->coeffsA[1] -= p->adaptcoeffsA[-1];
            p->coeffsA[2] -= p->adaptcoeffsA[-2];
            p->coeffsA[3] -= p->adaptcoeffsA[-3];
        }
        else if (A < 0) 
        {
            p->coeffsA[0] += p->adaptcoeffsA[0];
            p->coeffsA[1] += p->adaptcoeffsA[-1];
            p->coeffsA[2] += p->adaptcoeffsA[-2];
            p->coeffsA[3] += p->adaptcoeffsA[-3];
        }

        p->delayA++;
        p->adaptcoeffsA++;

        /* Have we filled the history buffer? */
        if (p->delayA == p->historybuffer + HISTORY_SIZE + (PREDICTOR_ORDER*4)) {
            memmove(p->historybuffer, p->delayA - (PREDICTOR_ORDER*4), 
                    (PREDICTOR_ORDER*4) * sizeof(int32_t));
            p->delayA = p->historybuffer + PREDICTOR_ORDER*4;
            p->adaptcoeffsA = p->historybuffer + PREDICTOR_ORDER*2;
        }

        p->filterA =  currentA + ((p->filterA * 31) >> 5);
        *(decoded0++) = p->filterA;
    }

    p->lastA = currentA;

    return 0;
}
