Commit 04fc5c6b authored by Kostya Shishkov's avatar Kostya Shishkov

g723_1: add comfort noise generation

parent 040405b5
......@@ -35,6 +35,8 @@
#include "celp_filters.h"
#include "g723_1_data.h"
#define CNG_RANDOM_SEED 12345
/**
* G723.1 frame types
*/
......@@ -84,6 +86,7 @@ typedef struct g723_1_context {
int erased_frames;
int16_t prev_lsp[LPC_ORDER];
int16_t sid_lsp[LPC_ORDER];
int16_t prev_excitation[PITCH_MAX];
int16_t excitation[PITCH_MAX + FRAME_LEN + 4];
int16_t synth_mem[LPC_ORDER];
......@@ -91,6 +94,7 @@ typedef struct g723_1_context {
int iir_mem[LPC_ORDER];
int random_seed;
int cng_random_seed;
int interp_index;
int interp_gain;
int sid_gain;
......@@ -99,7 +103,7 @@ typedef struct g723_1_context {
int pf_gain;
int postfilter;
int16_t audio[FRAME_LEN + LPC_ORDER + PITCH_MAX];
int16_t audio[FRAME_LEN + LPC_ORDER + PITCH_MAX + 4];
} G723_1_Context;
static av_cold int g723_1_decode_init(AVCodecContext *avctx)
......@@ -116,6 +120,10 @@ static av_cold int g723_1_decode_init(AVCodecContext *avctx)
avctx->coded_frame = &p->frame;
memcpy(p->prev_lsp, dc_lsp, LPC_ORDER * sizeof(*p->prev_lsp));
memcpy(p->sid_lsp, dc_lsp, LPC_ORDER * sizeof(*p->sid_lsp));
p->cng_random_seed = CNG_RANDOM_SEED;
p->past_frame_type = SID_FRAME;
return 0;
}
......@@ -983,6 +991,201 @@ static void formant_postfilter(G723_1_Context *p, int16_t *lpc,
}
}
static int sid_gain_to_lsp_index(int gain)
{
if (gain < 0x10)
return gain << 6;
else if (gain < 0x20)
return gain - 8 << 7;
else
return gain - 20 << 8;
}
static inline int cng_rand(int *state, int base)
{
*state = (*state * 521 + 259) & 0xFFFF;
return (*state & 0x7FFF) * base >> 15;
}
static int estimate_sid_gain(G723_1_Context *p)
{
int i, shift, seg, seg2, t, val, val_add, x, y;
shift = 16 - p->cur_gain * 2;
if (shift > 0)
t = p->sid_gain << shift;
else
t = p->sid_gain >> -shift;
x = t * cng_filt[0] >> 16;
if (x >= cng_bseg[2])
return 0x3F;
if (x >= cng_bseg[1]) {
shift = 4;
seg = 3;
} else {
shift = 3;
seg = (x >= cng_bseg[0]);
}
seg2 = FFMIN(seg, 3);
val = 1 << shift;
val_add = val >> 1;
for (i = 0; i < shift; i++) {
t = seg * 32 + (val << seg2);
t *= t;
if (x >= t)
val += val_add;
else
val -= val_add;
val_add >>= 1;
}
t = seg * 32 + (val << seg2);
y = t * t - x;
if (y <= 0) {
t = seg * 32 + (val + 1 << seg2);
t = t * t - x;
val = (seg2 - 1 << 4) + val;
if (t >= y)
val++;
} else {
t = seg * 32 + (val - 1 << seg2);
t = t * t - x;
val = (seg2 - 1 << 4) + val;
if (t >= y)
val--;
}
return val;
}
static void generate_noise(G723_1_Context *p)
{
int i, j, idx, t;
int off[SUBFRAMES];
int signs[SUBFRAMES / 2 * 11], pos[SUBFRAMES / 2 * 11];
int tmp[SUBFRAME_LEN * 2];
int16_t *vector_ptr;
int64_t sum;
int b0, c, delta, x, shift;
p->pitch_lag[0] = cng_rand(&p->cng_random_seed, 21) + 123;
p->pitch_lag[1] = cng_rand(&p->cng_random_seed, 19) + 123;
for (i = 0; i < SUBFRAMES; i++) {
p->subframe[i].ad_cb_gain = cng_rand(&p->cng_random_seed, 50) + 1;
p->subframe[i].ad_cb_lag = cng_adaptive_cb_lag[i];
}
for (i = 0; i < SUBFRAMES / 2; i++) {
t = cng_rand(&p->cng_random_seed, 1 << 13);
off[i * 2] = t & 1;
off[i * 2 + 1] = ((t >> 1) & 1) + SUBFRAME_LEN;
t >>= 2;
for (j = 0; j < 11; j++) {
signs[i * 11 + j] = (t & 1) * 2 - 1 << 14;
t >>= 1;
}
}
idx = 0;
for (i = 0; i < SUBFRAMES; i++) {
for (j = 0; j < SUBFRAME_LEN / 2; j++)
tmp[j] = j;
t = SUBFRAME_LEN / 2;
for (j = 0; j < pulses[i]; j++, idx++) {
int idx2 = cng_rand(&p->cng_random_seed, t);
pos[idx] = tmp[idx2] * 2 + off[i];
tmp[idx2] = tmp[--t];
}
}
vector_ptr = p->audio + LPC_ORDER;
memcpy(vector_ptr, p->prev_excitation,
PITCH_MAX * sizeof(*p->excitation));
for (i = 0; i < SUBFRAMES; i += 2) {
gen_acb_excitation(vector_ptr, vector_ptr,
p->pitch_lag[i >> 1], &p->subframe[i],
p->cur_rate);
gen_acb_excitation(vector_ptr + SUBFRAME_LEN,
vector_ptr + SUBFRAME_LEN,
p->pitch_lag[i >> 1], &p->subframe[i + 1],
p->cur_rate);
t = 0;
for (j = 0; j < SUBFRAME_LEN * 2; j++)
t |= FFABS(vector_ptr[j]);
t = FFMIN(t, 0x7FFF);
if (!t) {
shift = 0;
} else {
shift = -10 + av_log2(t);
if (shift < -2)
shift = -2;
}
sum = 0;
if (shift < 0) {
for (j = 0; j < SUBFRAME_LEN * 2; j++) {
t = vector_ptr[j] << -shift;
sum += t * t;
tmp[j] = t;
}
} else {
for (j = 0; j < SUBFRAME_LEN * 2; j++) {
t = vector_ptr[j] >> shift;
sum += t * t;
tmp[j] = t;
}
}
b0 = 0;
for (j = 0; j < 11; j++)
b0 += tmp[pos[(i / 2) * 11 + j]] * signs[(i / 2) * 11 + j];
b0 = b0 * 2 * 2979LL + (1 << 29) >> 30; // approximated division by 11
c = p->cur_gain * (p->cur_gain * SUBFRAME_LEN >> 5);
if (shift * 2 + 3 >= 0)
c >>= shift * 2 + 3;
else
c <<= -(shift * 2 + 3);
c = (av_clipl_int32(sum << 1) - c) * 2979LL >> 15;
delta = b0 * b0 * 2 - c;
if (delta <= 0) {
x = -b0;
} else {
delta = square_root(delta);
x = delta - b0;
t = delta + b0;
if (FFABS(t) < FFABS(x))
x = -t;
}
shift++;
if (shift < 0)
x >>= -shift;
else
x <<= shift;
x = av_clip(x, -10000, 10000);
for (j = 0; j < 11; j++) {
idx = (i / 2) * 11 + j;
vector_ptr[pos[idx]] = av_clip_int16(vector_ptr[pos[idx]] +
(x * signs[idx] >> 15));
}
/* copy decoded data to serve as a history for the next decoded subframes */
memcpy(vector_ptr + PITCH_MAX, vector_ptr,
sizeof(*vector_ptr) * SUBFRAME_LEN * 2);
vector_ptr += SUBFRAME_LEN * 2;
}
/* Save the excitation for the next frame */
memcpy(p->prev_excitation, p->audio + LPC_ORDER + FRAME_LEN,
PITCH_MAX * sizeof(*p->excitation));
}
static int g723_1_decode_frame(AVCodecContext *avctx, void *data,
int *got_frame_ptr, AVPacket *avpkt)
{
......@@ -1107,14 +1310,23 @@ static int g723_1_decode_frame(AVCodecContext *avctx, void *data,
PITCH_MAX * sizeof(*p->excitation));
}
}
p->cng_random_seed = CNG_RANDOM_SEED;
} else {
memset(out, 0, FRAME_LEN * 2);
av_log(avctx, AV_LOG_WARNING,
"G.723.1: Comfort noise generation not supported yet\n");
if (p->cur_frame_type == SID_FRAME) {
p->sid_gain = sid_gain_to_lsp_index(p->subframe[0].amp_index);
inverse_quant(p->sid_lsp, p->prev_lsp, p->lsp_index, 0);
} else if (p->past_frame_type == ACTIVE_FRAME) {
p->sid_gain = estimate_sid_gain(p);
}
*got_frame_ptr = 1;
*(AVFrame *)data = p->frame;
return frame_size[dec_mode];
if (p->past_frame_type == ACTIVE_FRAME)
p->cur_gain = p->sid_gain;
else
p->cur_gain = (p->cur_gain * 7 + p->sid_gain) >> 3;
generate_noise(p);
lsp_interpolate(lpc, p->sid_lsp, p->prev_lsp);
/* Save the lsp_vector for the next frame */
memcpy(p->prev_lsp, p->sid_lsp, LPC_ORDER * sizeof(*p->prev_lsp));
}
p->past_frame_type = p->cur_frame_type;
......
......@@ -1191,4 +1191,10 @@ static const int16_t postfilter_tbl[2][LPC_ORDER] = {
{ 24576, 18432, 13824, 10368, 7776, 5832, 4374, 3281, 2460, 1845 }
};
static const int cng_adaptive_cb_lag[4] = { 1, 0, 1, 3 };
static const int cng_filt[4] = { 273, 998, 499, 333 };
static const int cng_bseg[3] = { 2048, 18432, 231233 };
#endif /* AVCODEC_G723_1_DATA_H */
......@@ -27,6 +27,12 @@ fate-g723_1-dec-5: CMD = framecrc -postfilter 1 -i $(SAMPLES)/g723_1/pathd63p.tc
FATE_G723_1 += fate-g723_1-dec-6
fate-g723_1-dec-6: CMD = framecrc -postfilter 1 -i $(SAMPLES)/g723_1/tamed63p.tco
FATE_G723_1 += fate-g723_1-dec-7
fate-g723_1-dec-7: CMD = framecrc -postfilter 1 -i $(SAMPLES)/g723_1/dtx63b.tco
FATE_G723_1 += fate-g723_1-dec-8
fate-g723_1-dec-8: CMD = framecrc -postfilter 1 -i $(SAMPLES)/g723_1/dtx63e.tco
FATE_SAMPLES_AVCONV += $(FATE_G723_1)
fate-g723_1: $(FATE_G723_1)
......
#tb 0: 1/8000
0, 0, 0, 240, 480, 0x35e4a1fd
0, 240, 240, 240, 480, 0x2f7bdd60
0, 480, 480, 240, 480, 0x0407e499
0, 720, 720, 240, 480, 0x5f5ef209
0, 960, 960, 240, 480, 0xe936e8d1
0, 1200, 1200, 240, 480, 0x0896ddba
0, 1440, 1440, 240, 480, 0xa885ea94
0, 1680, 1680, 240, 480, 0x40bff3d0
0, 1920, 1920, 240, 480, 0xe05ce4c3
0, 2160, 2160, 240, 480, 0x80c4f790
0, 2400, 2400, 240, 480, 0x65d5e8f9
#tb 0: 1/8000
0, 0, 0, 240, 480, 0x17930e0f
0, 240, 240, 240, 480, 0x7c7f4247
0, 480, 480, 240, 480, 0xbf3489e5
0, 720, 720, 240, 480, 0x24319fc9
0, 960, 960, 240, 480, 0xb327eec0
0, 1200, 1200, 240, 480, 0xc2ddcbca
0, 1440, 1440, 240, 480, 0xeebad740
0, 1680, 1680, 240, 480, 0x77fcb933
0, 1920, 1920, 240, 480, 0x9677c5b7
0, 2160, 2160, 240, 480, 0xb49dcb9e
0, 2400, 2400, 240, 480, 0x0e78d7e6
0, 2640, 2640, 240, 480, 0xf752dc3e
0, 2880, 2880, 240, 480, 0xc95af091
0, 3120, 3120, 240, 480, 0xa25de399
0, 3360, 3360, 240, 480, 0x34e7e0da
0, 3600, 3600, 240, 480, 0x6c84e3f4
0, 3840, 3840, 240, 480, 0x2c7dda20
0, 4080, 4080, 240, 480, 0x00a5f112
0, 4320, 4320, 240, 480, 0x943ddd89
0, 4560, 4560, 240, 480, 0x4ad4ebac
0, 4800, 4800, 240, 480, 0xa4ff0aa8
0, 5040, 5040, 240, 480, 0xc0f805f2
0, 5280, 5280, 240, 480, 0x859ce987
0, 5520, 5520, 240, 480, 0x9ebcd0de
0, 5760, 5760, 240, 480, 0x3de2db0b
0, 6000, 6000, 240, 480, 0x0affea9c
0, 6240, 6240, 240, 480, 0xcb1bf81e
0, 6480, 6480, 240, 480, 0x8a72d71d
0, 6720, 6720, 240, 480, 0x583cd5cd
0, 6960, 6960, 240, 480, 0x4be7dc7b
0, 7200, 7200, 240, 480, 0xb08108c0
0, 7440, 7440, 240, 480, 0xd0b3ed59
0, 7680, 7680, 240, 480, 0x7d33f822
0, 7920, 7920, 240, 480, 0x199c0111
0, 8160, 8160, 240, 480, 0x7d29f2a8
0, 8400, 8400, 240, 480, 0x424dec5e
0, 8640, 8640, 240, 480, 0x946cf258
0, 8880, 8880, 240, 480, 0xd429da7a
0, 9120, 9120, 240, 480, 0x0f11df46
0, 9360, 9360, 240, 480, 0xf4dce502
0, 9600, 9600, 240, 480, 0x01c1de78
0, 9840, 9840, 240, 480, 0xd1d3da59
0, 10080, 10080, 240, 480, 0x5822f3ec
0, 10320, 10320, 240, 480, 0xadd5fe67
0, 10560, 10560, 240, 480, 0xdcf5f2c3
0, 10800, 10800, 240, 480, 0x5176e39b
0, 11040, 11040, 240, 480, 0xf947e0b1
0, 11280, 11280, 240, 480, 0x33b1eb36
0, 11520, 11520, 240, 480, 0x57bce9bd
0, 11760, 11760, 240, 480, 0x806eec1f
0, 12000, 12000, 240, 480, 0x0a60f94a
0, 12240, 12240, 240, 480, 0x9eddf27d
0, 12480, 12480, 240, 480, 0x3d28ef2f
0, 12720, 12720, 240, 480, 0x52f0e562
0, 12960, 12960, 240, 480, 0xf2d6c8a0
0, 13200, 13200, 240, 480, 0xfa0df4a1
0, 13440, 13440, 240, 480, 0x9cccfda9
0, 13680, 13680, 240, 480, 0xa7c1e528
0, 13920, 13920, 240, 480, 0xe130e8f9
0, 14160, 14160, 240, 480, 0x80f6eabe
0, 14400, 14400, 240, 480, 0x9bbb027e
0, 14640, 14640, 240, 480, 0x33cdea7f
0, 14880, 14880, 240, 480, 0x84d8e761
0, 15120, 15120, 240, 480, 0xb99ce457
0, 15360, 15360, 240, 480, 0x5dc1e324
0, 15600, 15600, 240, 480, 0xc914e6c3
0, 15840, 15840, 240, 480, 0x8e77f5c2
0, 16080, 16080, 240, 480, 0x3997034d
0, 16320, 16320, 240, 480, 0x820cfd49
0, 16560, 16560, 240, 480, 0x8ad5f24c
0, 16800, 16800, 240, 480, 0xe21be71c
0, 17040, 17040, 240, 480, 0x516ae8c8
0, 17280, 17280, 240, 480, 0x595bdc3d
0, 17520, 17520, 240, 480, 0x8a4bee79
0, 17760, 17760, 240, 480, 0x307fed64
0, 18000, 18000, 240, 480, 0xe71cf219
0, 18240, 18240, 240, 480, 0xdb0be1a1
0, 18480, 18480, 240, 480, 0x7947dfbd
0, 18720, 18720, 240, 480, 0x5d90fbf0
0, 18960, 18960, 240, 480, 0xa449fc55
0, 19200, 19200, 240, 480, 0x45b2f979
0, 19440, 19440, 240, 480, 0x2b2be378
0, 19680, 19680, 240, 480, 0x2d2edf42
0, 19920, 19920, 240, 480, 0x568ee04f
0, 20160, 20160, 240, 480, 0x66f0debe
0, 20400, 20400, 240, 480, 0xc943eab7
0, 20640, 20640, 240, 480, 0xc9ade3c9
0, 20880, 20880, 240, 480, 0x6971f92d
0, 21120, 21120, 240, 480, 0x48d0ecbc
0, 21360, 21360, 240, 480, 0xf641dc98
0, 21600, 21600, 240, 480, 0xbb18e167
0, 21840, 21840, 240, 480, 0x72ce0968
0, 22080, 22080, 240, 480, 0x15bee6f6
0, 22320, 22320, 240, 480, 0x93d5e91f
0, 22560, 22560, 240, 480, 0x7aee010b
0, 22800, 22800, 240, 480, 0x9e82dc87
0, 23040, 23040, 240, 480, 0x4ee6f547
0, 23280, 23280, 240, 480, 0x3072d102
0, 23520, 23520, 240, 480, 0x74d4fb04
0, 23760, 23760, 240, 480, 0xc670f958
0, 24000, 24000, 240, 480, 0x3965c41f
0, 24240, 24240, 240, 480, 0x6a2de869
0, 24480, 24480, 240, 480, 0xa757f44b
0, 24720, 24720, 240, 480, 0x94a5168c
0, 24960, 24960, 240, 480, 0xef0f0c28
0, 25200, 25200, 240, 480, 0x3770ebb3
0, 25440, 25440, 240, 480, 0x4343de6f
0, 25680, 25680, 240, 480, 0x3ec8d816
0, 25920, 25920, 240, 480, 0x1661e3d3
0, 26160, 26160, 240, 480, 0x077cd9fd
0, 26400, 26400, 240, 480, 0xb5ece07e
0, 26640, 26640, 240, 480, 0xf303e151
0, 26880, 26880, 240, 480, 0x95e4d019
0, 27120, 27120, 240, 480, 0x4bd0ddc0
0, 27360, 27360, 240, 480, 0x6cebd341
0, 27600, 27600, 240, 480, 0xea3fea9e
0, 27840, 27840, 240, 480, 0x5ad30c3f
0, 28080, 28080, 240, 480, 0x218c02a5
0, 28320, 28320, 240, 480, 0x662decd0
0, 28560, 28560, 240, 480, 0x6865e2f2
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