adx: calculate correct LPC coeffs

Instead of using fixed coefficients, the correct way is to calculate the
coefficients using the highpass cutoff frequency from the ADX stream header
and the sample rate.
This commit is contained in:
Justin Ruggles 2011-11-20 14:21:32 -05:00
parent 954d94dd5e
commit b237248e29
5 changed files with 70 additions and 14 deletions

View File

@ -489,7 +489,7 @@ OBJS-$(CONFIG_PCM_U32LE_ENCODER) += pcm.o
OBJS-$(CONFIG_PCM_ZORK_DECODER) += pcm.o
OBJS-$(CONFIG_ADPCM_4XM_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_ADX_DECODER) += adxdec.o
OBJS-$(CONFIG_ADPCM_ADX_DECODER) += adxdec.o adx.o
OBJS-$(CONFIG_ADPCM_ADX_ENCODER) += adxenc.o
OBJS-$(CONFIG_ADPCM_CT_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_EA_DECODER) += adpcm.o

34
libavcodec/adx.c Normal file
View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2011 Justin Ruggles
*
* This file is part of Libav.
*
* Libav is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Libav 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/mathematics.h"
#include "adx.h"
void ff_adx_calculate_coeffs(int cutoff, int sample_rate, int bits, int *coeff)
{
double a, b, c;
a = M_SQRT2 - cos(2.0 * M_PI * cutoff / sample_rate);
b = M_SQRT2 - 1.0;
c = (a - sqrt((a + b) * (a - b))) / b;
coeff[0] = lrintf(c * 2.0 * (1 << bits));
coeff[1] = lrintf(-(c * c) * (1 << bits));
}

View File

@ -41,10 +41,20 @@ typedef struct {
int header_parsed;
unsigned char dec_temp[18*2];
int in_temp;
int cutoff;
int coeff[2];
} ADXContext;
#define COEFF_BITS 12
#define COEFF1 0x1CA6
#define COEFF2 0x0CD4
/**
* Calculate LPC coefficients based on cutoff frequency and sample rate.
*
* @param cutoff cutoff frequency
* @param sample_rate sample rate
* @param bits number of bits used to quantize coefficients
* @param[out] coeff 2 quantized LPC coefficients
*/
void ff_adx_calculate_coeffs(int cutoff, int sample_rate, int bits, int *coeff);
#endif /* AVCODEC_ADX_H */

View File

@ -59,7 +59,7 @@ static void adx_decode(ADXContext *c, int16_t *out, const uint8_t *in, int ch)
s2 = prev->s2;
for (i = 0; i < 32; i++) {
d = get_sbits(&gb, 4);
s0 = ((d << COEFF_BITS) * scale + COEFF1 * s1 - COEFF2 * s2) >> COEFF_BITS;
s0 = ((d << COEFF_BITS) * scale + c->coeff[0] * s1 + c->coeff[1] * s2) >> COEFF_BITS;
s2 = s1;
s1 = av_clip_int16(s0);
*out = s1;
@ -81,7 +81,7 @@ static int adx_decode_header(AVCodecContext *avctx, const uint8_t *buf,
int bufsize)
{
ADXContext *c = avctx->priv_data;
int offset;
int offset, cutoff;
if (AV_RB16(buf) != 0x8000)
return AVERROR_INVALIDDATA;
@ -98,6 +98,9 @@ static int adx_decode_header(AVCodecContext *avctx, const uint8_t *buf,
return AVERROR_INVALIDDATA;
avctx->bit_rate = avctx->sample_rate * avctx->channels * 18 * 8 / 32;
cutoff = AV_RB16(buf + 16);
ff_adx_calculate_coeffs(cutoff, avctx->sample_rate, COEFF_BITS, c->coeff);
return offset;
}

View File

@ -34,7 +34,7 @@
/* 18 bytes <-> 32 samples */
static void adx_encode(unsigned char *adx,const short *wav,
static void adx_encode(ADXContext *c, unsigned char *adx, const short *wav,
ADXChannelState *prev)
{
int scale;
@ -48,7 +48,7 @@ static void adx_encode(unsigned char *adx,const short *wav,
s2 = prev->s2;
for(i=0;i<32;i++) {
s0 = wav[i];
d = ((s0 << COEFF_BITS) - COEFF1 * s1 + COEFF2 * s2) >> COEFF_BITS;
d = ((s0 << COEFF_BITS) - c->coeff[0] * s1 - c->coeff[1] * s2) >> COEFF_BITS;
data[i]=d;
if (max<d) max=d;
if (min>d) min=d;
@ -102,19 +102,24 @@ static int adx_encode_header(AVCodecContext *avctx,unsigned char *buf,size_t buf
} adxhdr; /* big endian */
/* offset-6 "(c)CRI" */
#endif
ADXContext *c = avctx->priv_data;
AV_WB32(buf+0x00,0x80000000|0x20);
AV_WB32(buf+0x04,0x03120400|avctx->channels);
AV_WB32(buf+0x08,avctx->sample_rate);
AV_WB32(buf+0x0c,0); /* FIXME: set after */
AV_WB32(buf+0x10,0x01040300);
AV_WB32(buf+0x14,0x00000000);
AV_WB32(buf+0x18,0x00000000);
memcpy(buf+0x1c,"\0\0(c)CRI",8);
AV_WB16(buf + 0x10, c->cutoff);
AV_WB32(buf + 0x12, 0x03000000);
AV_WB32(buf + 0x16, 0x00000000);
AV_WB32(buf + 0x1a, 0x00000000);
memcpy (buf + 0x1e, "(c)CRI", 6);
return 0x20+4;
}
static av_cold int adx_encode_init(AVCodecContext *avctx)
{
ADXContext *c = avctx->priv_data;
if (avctx->channels > 2)
return -1; /* only stereo or mono =) */
avctx->frame_size = 32;
@ -124,6 +129,10 @@ static av_cold int adx_encode_init(AVCodecContext *avctx)
// avctx->bit_rate = avctx->sample_rate*avctx->channels*18*8/32;
/* the cutoff can be adjusted, but this seems to work pretty well */
c->cutoff = 500;
ff_adx_calculate_coeffs(c->cutoff, avctx->sample_rate, COEFF_BITS, c->coeff);
av_log(avctx, AV_LOG_DEBUG, "adx encode init\n");
return 0;
@ -159,7 +168,7 @@ static int adx_encode_frame(AVCodecContext *avctx,
if (avctx->channels==1) {
while(rest>=32) {
adx_encode(dst,samples,c->prev);
adx_encode(c, dst, samples, c->prev);
dst+=18;
samples+=32;
rest-=32;
@ -174,8 +183,8 @@ static int adx_encode_frame(AVCodecContext *avctx,
tmpbuf[i+32] = samples[i*2+1];
}
adx_encode(dst,tmpbuf,c->prev);
adx_encode(dst+18,tmpbuf+32,c->prev+1);
adx_encode(c, dst, tmpbuf, c->prev);
adx_encode(c, dst + 18, tmpbuf + 32, c->prev + 1);
dst+=18*2;
samples+=32*2;
rest-=32*2;