Commit b237248e authored by Justin Ruggles's avatar Justin Ruggles

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.
parent 954d94dd
...@@ -489,7 +489,7 @@ OBJS-$(CONFIG_PCM_U32LE_ENCODER) += pcm.o ...@@ -489,7 +489,7 @@ OBJS-$(CONFIG_PCM_U32LE_ENCODER) += pcm.o
OBJS-$(CONFIG_PCM_ZORK_DECODER) += pcm.o OBJS-$(CONFIG_PCM_ZORK_DECODER) += pcm.o
OBJS-$(CONFIG_ADPCM_4XM_DECODER) += adpcm.o adpcm_data.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_ADX_ENCODER) += adxenc.o
OBJS-$(CONFIG_ADPCM_CT_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_CT_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_EA_DECODER) += adpcm.o OBJS-$(CONFIG_ADPCM_EA_DECODER) += adpcm.o
......
/*
* 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));
}
...@@ -41,10 +41,20 @@ typedef struct { ...@@ -41,10 +41,20 @@ typedef struct {
int header_parsed; int header_parsed;
unsigned char dec_temp[18*2]; unsigned char dec_temp[18*2];
int in_temp; int in_temp;
int cutoff;
int coeff[2];
} ADXContext; } ADXContext;
#define COEFF_BITS 12 #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 */ #endif /* AVCODEC_ADX_H */
...@@ -59,7 +59,7 @@ static void adx_decode(ADXContext *c, int16_t *out, const uint8_t *in, int ch) ...@@ -59,7 +59,7 @@ static void adx_decode(ADXContext *c, int16_t *out, const uint8_t *in, int ch)
s2 = prev->s2; s2 = prev->s2;
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
d = get_sbits(&gb, 4); 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; s2 = s1;
s1 = av_clip_int16(s0); s1 = av_clip_int16(s0);
*out = s1; *out = s1;
...@@ -81,7 +81,7 @@ static int adx_decode_header(AVCodecContext *avctx, const uint8_t *buf, ...@@ -81,7 +81,7 @@ static int adx_decode_header(AVCodecContext *avctx, const uint8_t *buf,
int bufsize) int bufsize)
{ {
ADXContext *c = avctx->priv_data; ADXContext *c = avctx->priv_data;
int offset; int offset, cutoff;
if (AV_RB16(buf) != 0x8000) if (AV_RB16(buf) != 0x8000)
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
...@@ -98,6 +98,9 @@ static int adx_decode_header(AVCodecContext *avctx, const uint8_t *buf, ...@@ -98,6 +98,9 @@ static int adx_decode_header(AVCodecContext *avctx, const uint8_t *buf,
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
avctx->bit_rate = avctx->sample_rate * avctx->channels * 18 * 8 / 32; 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; return offset;
} }
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
/* 18 bytes <-> 32 samples */ /* 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) ADXChannelState *prev)
{ {
int scale; int scale;
...@@ -48,7 +48,7 @@ static void adx_encode(unsigned char *adx,const short *wav, ...@@ -48,7 +48,7 @@ static void adx_encode(unsigned char *adx,const short *wav,
s2 = prev->s2; s2 = prev->s2;
for(i=0;i<32;i++) { for(i=0;i<32;i++) {
s0 = wav[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; data[i]=d;
if (max<d) max=d; if (max<d) max=d;
if (min>d) min=d; if (min>d) min=d;
...@@ -102,19 +102,24 @@ static int adx_encode_header(AVCodecContext *avctx,unsigned char *buf,size_t buf ...@@ -102,19 +102,24 @@ static int adx_encode_header(AVCodecContext *avctx,unsigned char *buf,size_t buf
} adxhdr; /* big endian */ } adxhdr; /* big endian */
/* offset-6 "(c)CRI" */ /* offset-6 "(c)CRI" */
#endif #endif
ADXContext *c = avctx->priv_data;
AV_WB32(buf+0x00,0x80000000|0x20); AV_WB32(buf+0x00,0x80000000|0x20);
AV_WB32(buf+0x04,0x03120400|avctx->channels); AV_WB32(buf+0x04,0x03120400|avctx->channels);
AV_WB32(buf+0x08,avctx->sample_rate); AV_WB32(buf+0x08,avctx->sample_rate);
AV_WB32(buf+0x0c,0); /* FIXME: set after */ AV_WB32(buf+0x0c,0); /* FIXME: set after */
AV_WB32(buf+0x10,0x01040300); AV_WB16(buf + 0x10, c->cutoff);
AV_WB32(buf+0x14,0x00000000); AV_WB32(buf + 0x12, 0x03000000);
AV_WB32(buf+0x18,0x00000000); AV_WB32(buf + 0x16, 0x00000000);
memcpy(buf+0x1c,"\0\0(c)CRI",8); AV_WB32(buf + 0x1a, 0x00000000);
memcpy (buf + 0x1e, "(c)CRI", 6);
return 0x20+4; return 0x20+4;
} }
static av_cold int adx_encode_init(AVCodecContext *avctx) static av_cold int adx_encode_init(AVCodecContext *avctx)
{ {
ADXContext *c = avctx->priv_data;
if (avctx->channels > 2) if (avctx->channels > 2)
return -1; /* only stereo or mono =) */ return -1; /* only stereo or mono =) */
avctx->frame_size = 32; avctx->frame_size = 32;
...@@ -124,6 +129,10 @@ static av_cold int adx_encode_init(AVCodecContext *avctx) ...@@ -124,6 +129,10 @@ static av_cold int adx_encode_init(AVCodecContext *avctx)
// avctx->bit_rate = avctx->sample_rate*avctx->channels*18*8/32; // 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"); av_log(avctx, AV_LOG_DEBUG, "adx encode init\n");
return 0; return 0;
...@@ -159,7 +168,7 @@ static int adx_encode_frame(AVCodecContext *avctx, ...@@ -159,7 +168,7 @@ static int adx_encode_frame(AVCodecContext *avctx,
if (avctx->channels==1) { if (avctx->channels==1) {
while(rest>=32) { while(rest>=32) {
adx_encode(dst,samples,c->prev); adx_encode(c, dst, samples, c->prev);
dst+=18; dst+=18;
samples+=32; samples+=32;
rest-=32; rest-=32;
...@@ -174,8 +183,8 @@ static int adx_encode_frame(AVCodecContext *avctx, ...@@ -174,8 +183,8 @@ static int adx_encode_frame(AVCodecContext *avctx,
tmpbuf[i+32] = samples[i*2+1]; tmpbuf[i+32] = samples[i*2+1];
} }
adx_encode(dst,tmpbuf,c->prev); adx_encode(c, dst, tmpbuf, c->prev);
adx_encode(dst+18,tmpbuf+32,c->prev+1); adx_encode(c, dst + 18, tmpbuf + 32, c->prev + 1);
dst+=18*2; dst+=18*2;
samples+=32*2; samples+=32*2;
rest-=32*2; rest-=32*2;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment