[FFmpeg-cvslog] g723_1: add comfort noise generation

Kostya Shishkov git at videolan.org
Fri Aug 31 13:08:35 CEST 2012


ffmpeg | branch: master | Kostya Shishkov <kostya.shishkov at gmail.com> | Thu Aug 23 19:51:11 2012 +0200| [04fc5c6bde5da842e8b40a9a76eb72c8327ae40b] | committer: Kostya Shishkov

g723_1: add comfort noise generation

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=04fc5c6bde5da842e8b40a9a76eb72c8327ae40b
---

 libavcodec/g723_1.c         |  226 +++++++++++++++++++++++++++++++++++++++++--
 libavcodec/g723_1_data.h    |    6 ++
 tests/fate/voice.mak        |    6 ++
 tests/ref/fate/g723_1-dec-7 |   12 +++
 tests/ref/fate/g723_1-dec-8 |  121 +++++++++++++++++++++++
 5 files changed, 364 insertions(+), 7 deletions(-)

diff --git a/libavcodec/g723_1.c b/libavcodec/g723_1.c
index 793b2d3..03dd62d 100644
--- a/libavcodec/g723_1.c
+++ b/libavcodec/g723_1.c
@@ -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;
diff --git a/libavcodec/g723_1_data.h b/libavcodec/g723_1_data.h
index 82446b3..04f8a06 100644
--- a/libavcodec/g723_1_data.h
+++ b/libavcodec/g723_1_data.h
@@ -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 */
diff --git a/tests/fate/voice.mak b/tests/fate/voice.mak
index ea765d2..b9b8aa6 100644
--- a/tests/fate/voice.mak
+++ b/tests/fate/voice.mak
@@ -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)
 
diff --git a/tests/ref/fate/g723_1-dec-7 b/tests/ref/fate/g723_1-dec-7
new file mode 100644
index 0000000..cc30187
--- /dev/null
+++ b/tests/ref/fate/g723_1-dec-7
@@ -0,0 +1,12 @@
+#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
diff --git a/tests/ref/fate/g723_1-dec-8 b/tests/ref/fate/g723_1-dec-8
new file mode 100644
index 0000000..fc4d9f3
--- /dev/null
+++ b/tests/ref/fate/g723_1-dec-8
@@ -0,0 +1,121 @@
+#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



More information about the ffmpeg-cvslog mailing list