/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 *
 * Copyright (C) 2010 Yoshihisa Uchida
 *
 * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/
#include "codeclib.h"
#include "pcm_common.h"
#include "ima_adpcm_common.h"

/*
 * Functions for IMA ADPCM and IMA ADPCM series format
 *
 * References
 * [1] The IMA Digital Audio Focus and Technical Working Groups,
 *     Recommended Practices for Enhancing Digital Audio Compatibility
 *     in Multimedia Systems Revision 3.00, 1992
 * [2] Microsoft Corporation, New Multimedia Data Types and Data Techniques,
 *     Revision:3.0, 1994
 * [3] ffmpeg source code, libavcodec/adpcm.c
 */

/* step table */
static const uint16_t step_table[89] ICONST_ATTR = {
    7, 8, 9, 10, 11, 12, 13, 14,
    16, 17, 19, 21, 23, 25, 28, 31,
    34, 37, 41, 45, 50, 55, 60, 66,
    73, 80, 88, 97, 107, 118, 130, 143,
    157, 173, 190, 209, 230, 253, 279, 307,
    337, 371, 408, 449, 494, 544, 598, 658,
    724, 796, 876, 963, 1060, 1166, 1282, 1411,
    1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
    3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
    7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
    15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
    32767
};

/* step index tables */
static const int index_tables[4][16] ICONST_ATTR = {
    /* adpcm data size is 2 */
    { -1, 2 },
    /* adpcm data size is 3 */
    { -1, -1, 1, 2 },
    /* adpcm data size is 4 */
    { -1, -1, -1, -1, 2, 4, 6, 8 },
    /* adpcm data size is 5 */
    { -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16 },
};

static int32_t pcmdata[2];
static int8_t indices[2];

static int adpcm_data_size;
static uint8_t step_mask;
static uint8_t step_sign_mask;
static int8_t step_shift;
static const int *use_index_table;

/*
 * Before first decoding, this function must be executed.
 *
 * params
 *     bit: adpcm data size (2 <= bit <= 5).
 *     index_table: step index table
 *                  if index_table is null, then step index table
 *                  is used index_tables[bit-2].
 */
void init_ima_adpcm_decoder(int bit, const int *index_table)
{
    adpcm_data_size = bit;
    step_sign_mask = 1 << (adpcm_data_size - 1);
    step_mask = step_sign_mask - 1;
    step_shift = adpcm_data_size - 2;
    if (index_table)
        use_index_table = index_table;
    else
        use_index_table = index_tables[adpcm_data_size - 2];
}

/*
 * When starting decoding for each block, this function must be executed.
 *
 * params
 *     channels: channel count
 *     init_pcmdata: array of init pcmdata
 *     init_index:   array of init step indexes
 */
void set_decode_parameters(int channels, int32_t *init_pcmdata, int8_t *init_index)
{
    int ch;

    for (ch = 0; ch < channels; ch++)
    {
        pcmdata[ch] = init_pcmdata[ch];
        indices[ch] = init_index[ch];
    }
}

/*
 * convert ADPCM to PCM for any adpcm data size.
 *
 * If adpcm_data_size is 4, then you use create_pcmdata_size4()
 * in place of this functon.
 */
int16_t create_pcmdata(int ch, uint8_t nibble)
{
    int check_bit = 1 << step_shift;
    int32_t delta = 0;
    int16_t step = step_table[indices[ch]];

    do {
        if (nibble & check_bit)
            delta += step;
        step >>= 1;
        check_bit >>= 1;
    } while (check_bit);
    delta += step;

    if (nibble & step_sign_mask)
        pcmdata[ch] -= delta;
    else
        pcmdata[ch] += delta;

    indices[ch] += use_index_table[nibble & step_mask];
    CLIP(indices[ch], 0, 88);

    CLIP(pcmdata[ch], -32768, 32767);

    return (int16_t)pcmdata[ch];
}

/*
 * convert ADPCM to PCM when adpcm data size is 4.
 */
int16_t create_pcmdata_size4(int ch, uint8_t nibble)
{
    int32_t delta;
    int16_t step = step_table[indices[ch]];

    delta = (step >> 3);
    if (nibble & 4) delta += step;
    if (nibble & 2) delta += (step >> 1);
    if (nibble & 1) delta += (step >> 2);

    if (nibble & 0x08)
        pcmdata[ch] -= delta;
    else
        pcmdata[ch] += delta;

    indices[ch] += use_index_table[nibble & 0x07];
    CLIP(indices[ch], 0, 88);

    CLIP(pcmdata[ch], -32768, 32767);

    return (int16_t)pcmdata[ch];
}
