From b237248e297760648307356efa5fcbfe16844829 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Sun, 20 Nov 2011 14:21:32 -0500 Subject: [PATCH] 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. --- libavcodec/Makefile | 2 +- libavcodec/adx.c | 34 ++++++++++++++++++++++++++++++++++ libavcodec/adx.h | 14 ++++++++++++-- libavcodec/adxdec.c | 7 +++++-- libavcodec/adxenc.c | 27 ++++++++++++++++++--------- 5 files changed, 70 insertions(+), 14 deletions(-) create mode 100644 libavcodec/adx.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 37aa8ee331..2cdcca2cfc 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -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 diff --git a/libavcodec/adx.c b/libavcodec/adx.c new file mode 100644 index 0000000000..bc3e8825ca --- /dev/null +++ b/libavcodec/adx.c @@ -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)); +} diff --git a/libavcodec/adx.h b/libavcodec/adx.h index ae5eb6a434..cd8c45bf6d 100644 --- a/libavcodec/adx.h +++ b/libavcodec/adx.h @@ -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 */ diff --git a/libavcodec/adxdec.c b/libavcodec/adxdec.c index 93bbc6b51b..f9f17cde95 100644 --- a/libavcodec/adxdec.c +++ b/libavcodec/adxdec.c @@ -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; } diff --git a/libavcodec/adxenc.c b/libavcodec/adxenc.c index 7225c3159d..b85a70d7b2 100644 --- a/libavcodec/adxenc.c +++ b/libavcodec/adxenc.c @@ -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 (maxd) 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;