cee61b57c8
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13630 a1c6a512-1295-4272-9138-f99709370657
266 lines
8.9 KiB
C
266 lines
8.9 KiB
C
/*
|
|
|
|
libdemac - A Monkey's Audio decoder
|
|
|
|
$Id$
|
|
|
|
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"
|
|
|
|
/* 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
|
|
};
|
|
|
|
#define YDELAYA (18 + PREDICTOR_ORDER*4)
|
|
#define YDELAYB (18 + PREDICTOR_ORDER*3)
|
|
#define XDELAYA (18 + PREDICTOR_ORDER*2)
|
|
#define XDELAYB (18 + PREDICTOR_ORDER)
|
|
|
|
#define YADAPTCOEFFSA (18)
|
|
#define XADAPTCOEFFSA (14)
|
|
#define YADAPTCOEFFSB (10)
|
|
#define XADAPTCOEFFSB (5)
|
|
|
|
void init_predictor_decoder(struct predictor_t* p)
|
|
{
|
|
/* Zero the history buffers */
|
|
memset(p->historybuffer, 0, PREDICTOR_SIZE * sizeof(int32_t));
|
|
p->buf = p->historybuffer;
|
|
|
|
/* Initialise and zero the co-efficients */
|
|
memcpy(p->YcoeffsA, initial_coeffs, sizeof(initial_coeffs));
|
|
memcpy(p->XcoeffsA, initial_coeffs, sizeof(initial_coeffs));
|
|
memset(p->YcoeffsB, 0, sizeof(p->YcoeffsB));
|
|
memset(p->XcoeffsB, 0, sizeof(p->XcoeffsB));
|
|
|
|
p->YfilterA = 0;
|
|
p->YfilterB = 0;
|
|
p->YlastA = 0;
|
|
|
|
p->XfilterA = 0;
|
|
p->XfilterB = 0;
|
|
p->XlastA = 0;
|
|
}
|
|
|
|
#ifdef CPU_COLDFIRE
|
|
/* Putting this in IRAM makes a small speedup (e.g. 186% -> 187%
|
|
realtime for a -c1000 file on Coldfire, but is slower on PP. */
|
|
int predictor_decode_stereo(struct predictor_t* p, int32_t* decoded0, int32_t* decoded1, int count) ICODE_ATTR;
|
|
#endif
|
|
|
|
#ifndef CPU_ARM
|
|
int predictor_decode_stereo(struct predictor_t* p, int32_t* decoded0, int32_t* decoded1, int count)
|
|
{
|
|
int32_t predictionA, predictionB;
|
|
|
|
while (count--)
|
|
{
|
|
/* Predictor Y */
|
|
p->buf[YDELAYA] = p->YlastA;
|
|
p->buf[YADAPTCOEFFSA] = SIGN(p->buf[YDELAYA]);
|
|
|
|
p->buf[YDELAYA-1] = p->buf[YDELAYA] - p->buf[YDELAYA-1];
|
|
p->buf[YADAPTCOEFFSA-1] = SIGN(p->buf[YDELAYA-1]);
|
|
|
|
predictionA = (p->buf[YDELAYA] * p->YcoeffsA[0]) +
|
|
(p->buf[YDELAYA-1] * p->YcoeffsA[1]) +
|
|
(p->buf[YDELAYA-2] * p->YcoeffsA[2]) +
|
|
(p->buf[YDELAYA-3] * p->YcoeffsA[3]);
|
|
|
|
/* Apply a scaled first-order filter compression */
|
|
p->buf[YDELAYB] = p->XfilterA - ((p->YfilterB * 31) >> 5);
|
|
p->buf[YADAPTCOEFFSB] = SIGN(p->buf[YDELAYB]);
|
|
p->YfilterB = p->XfilterA;
|
|
|
|
p->buf[YDELAYB-1] = p->buf[YDELAYB] - p->buf[YDELAYB-1];
|
|
p->buf[YADAPTCOEFFSB-1] = SIGN(p->buf[YDELAYB-1]);
|
|
|
|
predictionB = (p->buf[YDELAYB] * p->YcoeffsB[0]) +
|
|
(p->buf[YDELAYB-1] * p->YcoeffsB[1]) +
|
|
(p->buf[YDELAYB-2] * p->YcoeffsB[2]) +
|
|
(p->buf[YDELAYB-3] * p->YcoeffsB[3]) +
|
|
(p->buf[YDELAYB-4] * p->YcoeffsB[4]);
|
|
|
|
p->YlastA = *decoded0 + ((predictionA + (predictionB >> 1)) >> 10);
|
|
p->YfilterA = p->YlastA + ((p->YfilterA * 31) >> 5);
|
|
|
|
/* Predictor X */
|
|
|
|
p->buf[XDELAYA] = p->XlastA;
|
|
p->buf[XADAPTCOEFFSA] = SIGN(p->buf[XDELAYA]);
|
|
p->buf[XDELAYA-1] = p->buf[XDELAYA] - p->buf[XDELAYA-1];
|
|
p->buf[XADAPTCOEFFSA-1] = SIGN(p->buf[XDELAYA-1]);
|
|
|
|
predictionA = (p->buf[XDELAYA] * p->XcoeffsA[0]) +
|
|
(p->buf[XDELAYA-1] * p->XcoeffsA[1]) +
|
|
(p->buf[XDELAYA-2] * p->XcoeffsA[2]) +
|
|
(p->buf[XDELAYA-3] * p->XcoeffsA[3]);
|
|
|
|
/* Apply a scaled first-order filter compression */
|
|
p->buf[XDELAYB] = p->YfilterA - ((p->XfilterB * 31) >> 5);
|
|
p->buf[XADAPTCOEFFSB] = SIGN(p->buf[XDELAYB]);
|
|
p->XfilterB = p->YfilterA;
|
|
p->buf[XDELAYB-1] = p->buf[XDELAYB] - p->buf[XDELAYB-1];
|
|
p->buf[XADAPTCOEFFSB-1] = SIGN(p->buf[XDELAYB-1]);
|
|
|
|
predictionB = (p->buf[XDELAYB] * p->XcoeffsB[0]) +
|
|
(p->buf[XDELAYB-1] * p->XcoeffsB[1]) +
|
|
(p->buf[XDELAYB-2] * p->XcoeffsB[2]) +
|
|
(p->buf[XDELAYB-3] * p->XcoeffsB[3]) +
|
|
(p->buf[XDELAYB-4] * p->XcoeffsB[4]);
|
|
|
|
p->XlastA = *decoded1 + ((predictionA + (predictionB >> 1)) >> 10);
|
|
p->XfilterA = p->XlastA + ((p->XfilterA * 31) >> 5);
|
|
|
|
if (*decoded0 > 0)
|
|
{
|
|
p->YcoeffsA[0] -= p->buf[YADAPTCOEFFSA];
|
|
p->YcoeffsA[1] -= p->buf[YADAPTCOEFFSA-1];
|
|
p->YcoeffsA[2] -= p->buf[YADAPTCOEFFSA-2];
|
|
p->YcoeffsA[3] -= p->buf[YADAPTCOEFFSA-3];
|
|
|
|
p->YcoeffsB[0] -= p->buf[YADAPTCOEFFSB];
|
|
p->YcoeffsB[1] -= p->buf[YADAPTCOEFFSB-1];
|
|
p->YcoeffsB[2] -= p->buf[YADAPTCOEFFSB-2];
|
|
p->YcoeffsB[3] -= p->buf[YADAPTCOEFFSB-3];
|
|
p->YcoeffsB[4] -= p->buf[YADAPTCOEFFSB-4];
|
|
}
|
|
else if (*decoded0 < 0)
|
|
{
|
|
p->YcoeffsA[0] += p->buf[YADAPTCOEFFSA];
|
|
p->YcoeffsA[1] += p->buf[YADAPTCOEFFSA-1];
|
|
p->YcoeffsA[2] += p->buf[YADAPTCOEFFSA-2];
|
|
p->YcoeffsA[3] += p->buf[YADAPTCOEFFSA-3];
|
|
|
|
p->YcoeffsB[0] += p->buf[YADAPTCOEFFSB];
|
|
p->YcoeffsB[1] += p->buf[YADAPTCOEFFSB-1];
|
|
p->YcoeffsB[2] += p->buf[YADAPTCOEFFSB-2];
|
|
p->YcoeffsB[3] += p->buf[YADAPTCOEFFSB-3];
|
|
p->YcoeffsB[4] += p->buf[YADAPTCOEFFSB-4];
|
|
}
|
|
|
|
*(decoded0++) = p->YfilterA;
|
|
|
|
if (*decoded1 > 0)
|
|
{
|
|
p->XcoeffsA[0] -= p->buf[XADAPTCOEFFSA];
|
|
p->XcoeffsA[1] -= p->buf[XADAPTCOEFFSA-1];
|
|
p->XcoeffsA[2] -= p->buf[XADAPTCOEFFSA-2];
|
|
p->XcoeffsA[3] -= p->buf[XADAPTCOEFFSA-3];
|
|
|
|
p->XcoeffsB[0] -= p->buf[XADAPTCOEFFSB];
|
|
p->XcoeffsB[1] -= p->buf[XADAPTCOEFFSB-1];
|
|
p->XcoeffsB[2] -= p->buf[XADAPTCOEFFSB-2];
|
|
p->XcoeffsB[3] -= p->buf[XADAPTCOEFFSB-3];
|
|
p->XcoeffsB[4] -= p->buf[XADAPTCOEFFSB-4];
|
|
}
|
|
else if (*decoded1 < 0)
|
|
{
|
|
p->XcoeffsA[0] += p->buf[XADAPTCOEFFSA];
|
|
p->XcoeffsA[1] += p->buf[XADAPTCOEFFSA-1];
|
|
p->XcoeffsA[2] += p->buf[XADAPTCOEFFSA-2];
|
|
p->XcoeffsA[3] += p->buf[XADAPTCOEFFSA-3];
|
|
|
|
p->XcoeffsB[0] += p->buf[XADAPTCOEFFSB];
|
|
p->XcoeffsB[1] += p->buf[XADAPTCOEFFSB-1];
|
|
p->XcoeffsB[2] += p->buf[XADAPTCOEFFSB-2];
|
|
p->XcoeffsB[3] += p->buf[XADAPTCOEFFSB-3];
|
|
p->XcoeffsB[4] += p->buf[XADAPTCOEFFSB-4];
|
|
}
|
|
|
|
*(decoded1++) = p->XfilterA;
|
|
|
|
/* Combined */
|
|
p->buf++;
|
|
|
|
/* Have we filled the history buffer? */
|
|
if (p->buf == p->historybuffer + HISTORY_SIZE) {
|
|
memmove(p->historybuffer, p->buf,
|
|
PREDICTOR_SIZE * sizeof(int32_t));
|
|
p->buf = p->historybuffer;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int predictor_decode_mono(struct predictor_t* p, int32_t* decoded0, int count)
|
|
{
|
|
int32_t predictionA, currentA, A;
|
|
|
|
currentA = p->YlastA;
|
|
|
|
while (count--)
|
|
{
|
|
A = *decoded0;
|
|
|
|
p->buf[YDELAYA] = currentA;
|
|
p->buf[YDELAYA-1] = p->buf[YDELAYA] - p->buf[YDELAYA-1];
|
|
|
|
predictionA = (p->buf[YDELAYA] * p->YcoeffsA[0]) +
|
|
(p->buf[YDELAYA-1] * p->YcoeffsA[1]) +
|
|
(p->buf[YDELAYA-2] * p->YcoeffsA[2]) +
|
|
(p->buf[YDELAYA-3] * p->YcoeffsA[3]);
|
|
|
|
currentA = A + (predictionA >> 10);
|
|
|
|
p->buf[YADAPTCOEFFSA] = SIGN(p->buf[YDELAYA]);
|
|
p->buf[YADAPTCOEFFSA-1] = SIGN(p->buf[YDELAYA-1]);
|
|
|
|
if (A > 0)
|
|
{
|
|
p->YcoeffsA[0] -= p->buf[YADAPTCOEFFSA];
|
|
p->YcoeffsA[1] -= p->buf[YADAPTCOEFFSA-1];
|
|
p->YcoeffsA[2] -= p->buf[YADAPTCOEFFSA-2];
|
|
p->YcoeffsA[3] -= p->buf[YADAPTCOEFFSA-3];
|
|
}
|
|
else if (A < 0)
|
|
{
|
|
p->YcoeffsA[0] += p->buf[YADAPTCOEFFSA];
|
|
p->YcoeffsA[1] += p->buf[YADAPTCOEFFSA-1];
|
|
p->YcoeffsA[2] += p->buf[YADAPTCOEFFSA-2];
|
|
p->YcoeffsA[3] += p->buf[YADAPTCOEFFSA-3];
|
|
}
|
|
|
|
p->buf++;
|
|
|
|
/* Have we filled the history buffer? */
|
|
if (p->buf == p->historybuffer + HISTORY_SIZE) {
|
|
memmove(p->historybuffer, p->buf,
|
|
PREDICTOR_SIZE * sizeof(int32_t));
|
|
p->buf = p->historybuffer;
|
|
}
|
|
|
|
p->YfilterA = currentA + ((p->YfilterA * 31) >> 5);
|
|
*(decoded0++) = p->YfilterA;
|
|
}
|
|
|
|
p->YlastA = currentA;
|
|
|
|
return 0;
|
|
}
|