[FFmpeg-devel] [PATCH] Common ACELP routines (3/3) - LPC decoding routines

Vladimir Voroshilov voroshil
Wed Apr 23 21:53:33 CEST 2008


Michael Niedermayer wrote: 
> On Tue, Apr 22, 2008 at 01:21:24AM +0700, Vladimir Voroshilov wrote:
> > Hi, All
> > 
> > This patch contains several routines related to LP filter coefficients
> > decoding (not all, but those which
> > looks like AMR's).
> 
> [...]
> 
> > diff --git a/libavcodec/acelp_lpc.c b/libavcodec/acelp_lpc.c
> > new file mode 100644
> > index 0000000..65b870d
> > --- /dev/null
> > +++ b/libavcodec/acelp_lpc.c
> 
> lsp.c

ok. Keeping LPC/LSP routines in the same file.
I didn't understand had I split them or not (damn English).

> 
> [...]
> > +void ff_acelp_reorder_lsf(int16_t* lsfq, int16_t lsfq_min_distance, int16_t lsfq_min, int16_t lsfq_max)
> > +{
> > +    int i;
> > +
> > +    lsfq[0] = FFMAX(lsfq[0], lsfq_min); //Is warning required ?
> > +
> > +    for(i=0;i<9; i++)
> > +        lsfq[i+1] = FFMAX(lsfq[i+1], lsfq[i] + lsfq_min_distance);
> 
> simplification stolen from soc/amrnbdec.c:
> 
> for(i=0; i<10; i++){
>     lsf[i] = FFMAX(lsf[i], lsf_min);
>     lsf_min = lsf[i] + min_distance;
> }
> 
> also id make lsfq_min_distance and lsfq_min/max int
> 
> ahh, and reorder_lsf() in soc/amrnbdec.c is buggy (uninitalized var)

It also assumes that LSFs already ordered.
G.729 explicitly sorts them.
Should i put sorting code inside routine?

> 
> 
> > +
> > +    lsfq[9] = FFMIN(lsfq[9], lsfq_max);//Is warning required ?
> > +}
> > +
> 
> > +/**
> > + * \brief Convert LSF to LSP
> > + * \param lsf (Q13) LSF coefficients (0 <= lsf < PI)
> 
> ff_acelp_cos() behaves like PI=0x8000 or so IIRC so above is not really
> correct

Fixed by dividing on PI
There is also some unclear part in AMR: spec says about cos(PI*lsf)
while floating point code uses cos(lsf).
Robert, please recheck this part or fix me if i'm wrong
 
> > + * \param lsp [out] (Q15) LSP coefficients (-1 <= lsp < 1)
> > + *
> > + * \remark It is safe to pass the same array in lsf and lsp parameters
> > + */
> > +void ff_acelp_lsf2lsp(const int16_t *lsf, int16_t *lsp, int16_t factor)
> 
> i slightly prefer that the written to argument is left (lsp, lsf, factor)
> same for the other functions (this of course is minor nitpicking ...)

ok. Remaining fixes of ordering will be made while touching code.

> [...]
> > +/**
> > + * \brief decodes polynomial coefficients from LSP
> > + * \param lsp (Q15) LSP coefficients
> > + * \param f [out] (Q24) decoded polynomial coefficients
> > + */
> > +void ff_acelp_lsp2poly(const int16_t* lsp, int* f)
> 
> is this function used from outside this file? if not it could be static

made static

> > +{
> > +    int i, j;
> > +
> > +    f[0] = 0x1000000;          // 1.0 in Q24
> > +    f[1] = -lsp[0] << 10;      // *2 and Q15 -> Q24
> > +
> > +    for(i=2; i<=5; i++)
> > +    {
> > +        f[i] = f[i-2];
> > +
> 
> > +        for(j=i; j>1; j--)
> > +            f[j] -= (mul_24_15(f[j-1]>>1, lsp[2*i-2])<<2) - f[j-2];
> 
> why the >>1 ?  our 64bit multiply wont overflow.

bitexactness, enclosed info #ifdef

> > +
> > +    ff_acelp_lsp2poly(lsp,   f1);
> > +    ff_acelp_lsp2poly(lsp+1, f2);
> > +
> 
> > +    /* 3.2.6, Equations 25 and  26*/
> 
> 3.2.6 of g729 ...

fixed.

> 
> 
> [...]
> > +/**
> > + * \brief Interpolate LSP for the first subframe and convert LSP -> LP for both subframes (3.2.5 and 3.2.6)
> > + * \param (Q15) lsp_2nd LSP coefficients of the second subframe
> > + * \param (Q15) lsp_prev past LSP coefficients
> > + * \param lp_1st [out] (Q12) decoded LP coefficients for 1st subframe
> > + * \param lp_2nd [out] (Q12) decoded LP coefficients for second subframe
> > + */
> > +void ff_acelp_lp_decode(const int16_t* lsp_2nd, const int16_t* lsp_prev, int16_t* lp_1st, int16_t* lp_2nd)
> > +{
> > +    int16_t lsp_1st[10]; // Q15
> > +    int i;
> > +
> > +    /* LSP values for first subframe (3.2.5, Equation 24)*/
> 
> > +    for(i=0;i<10;i++)
> > +        lsp_1st[i] = (lsp_2nd[i] >> 1) + (lsp_prev[i] >> 1);
> 
> (a+b)>>1

bitexactness, enclosed into #ifdef

-- 
Regards,
Vladimir Voroshilov mailto:voroshil at gmail.com
Omsk State University
JID: voroshil at jabber.ru
ICQ: 95587719
-------------- next part --------------
diff --git a/libavcodec/lsp.c b/libavcodec/lsp.c
new file mode 100644
index 0000000..500b6f4
--- /dev/null
+++ b/libavcodec/lsp.c
@@ -0,0 +1,117 @@
+/*
+ * LSP routines for ACELP-based codecs
+ *
+ * Copyright (c) 2008 Vladimir Voroshilov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <inttypes.h>
+
+#include "avcodec.h"
+#include "lsp.h"
+#include "acelp_math.h"
+
+void ff_acelp_reorder_lsf(int16_t* lsfq, int lsfq_min_distance, int lsfq_min, int lsfq_max)
+{
+    int i;
+
+    for(i=0;i<10; i++)
+    {
+        lsfq[i] = FFMAX(lsfq[i], lsfq_min);
+        lsfq_min = lsfq[i] + lsfq_min_distance;
+    }
+    lsfq[9] = FFMIN(lsfq[9], lsfq_max);//Is warning required ?
+}
+
+void ff_acelp_lsf2lsp(int16_t *lsp, const int16_t *lsf)
+{
+    int i;
+
+    /* Convert LSF to LSP, lsp=cos(lsf) */
+    for(i=0;i<10; i++)
+        // 20861 = (1<<16) / PI
+        lsp[i] = ff_cos(lsf[i] * 20861 >> 15);
+}
+
+/**
+ * \brief decodes polynomial coefficients from LSP
+ * \param f [out] (Q24) decoded polynomial coefficients
+ * \param lsp (Q15) LSP coefficients
+ */
+static void lsp2poly(int* f, const int16_t* lsp)
+{
+    int i, j;
+
+    f[0] = 0x1000000;          // 1.0 in Q24
+    f[1] = -lsp[0] << 10;      // *2 and Q15 -> Q24
+
+    for(i=2; i<=5; i++)
+    {
+        f[i] = f[i-2];
+
+        for(j=i; j>1; j--)
+#ifdef G729_BITEXACT
+            f[j] -= (mul_24_15(f[j-1]>>1, lsp[2*i-2])<<2) - f[j-2];
+#else
+            f[j] -= (mul_24_15(f[j-1], lsp[2*i-2])<<1) - f[j-2];
+#endif
+
+        f[1] -= lsp[2*i-2]  << 10;
+    }
+}
+
+void ff_acelp_lsp2lpc(int16_t* lp, const int16_t* lsp)
+{
+    int i;
+    int f1[6]; // Q24
+    int f2[6]; // Q24
+
+    lsp2poly(f1, lsp  );
+    lsp2poly(f2, lsp+1);
+
+    /* 3.2.6 of G.729, Equations 25 and  26*/
+    lp[0] = 4096;
+    for(i=1; i<6; i++)
+    {
+        int ff1 = f1[i] + f1[i-1]; // Q24
+        int ff2 = f2[i] - f2[i-1]; // Q24
+
+        ff1 += 1 << 12;
+        lp[i]    = (ff1 + ff2) >> 13;
+        lp[11-i] = (ff1 - ff2) >> 13;
+    }
+}
+
+void ff_acelp_lp_decode(int16_t* lp_1st, int16_t* lp_2nd, const int16_t* lsp_2nd, const int16_t* lsp_prev)
+{
+    int16_t lsp_1st[10]; // Q15
+    int i;
+
+    /* LSP values for first subframe (3.2.5 of G.729, Equation 24)*/
+    for(i=0;i<10;i++)
+#ifdef G729_BITEXACT
+        lsp_1st[i] = (lsp_2nd[i] >> 1) + (lsp_prev[i] >> 1);
+#else
+        lsp_1st[i] = (lsp_2nd[i] + lsp_prev[i]) >> 1;
+#endif
+
+    ff_acelp_lsp2lpc(lp_1st, lsp_1st);
+
+    /* LSP values for second subframe (3.2.5 of G.729)*/
+    ff_acelp_lsp2lpc(lp_2nd, lsp_2nd);
+}
diff --git a/libavcodec/lsp.h b/libavcodec/lsp.h
new file mode 100644
index 0000000..06e9231
--- /dev/null
+++ b/libavcodec/lsp.h
@@ -0,0 +1,60 @@
+/*
+ * LSP computing for ACELP-based codecs
+ *
+ * Copyright (c) 2008 Vladimir Voroshilov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FFMPEG_ACELP_LPC_H
+#define FFMPEG_ACELP_LPC_H
+
+/**
+ * \brief keep distance between LSFs.
+ * \param lsfq [in/out] LSF to check and adjust
+ * \param lsfq_min_distance minimum distance between LSFs
+ * \param lsfq_min minimum allowed LSF value
+ * \param lsfq_max maximum allowed LSF value
+ */
+void ff_acelp_reorder_lsf(int16_t* lsfq, int lsfq_min_distance, int lsqf_min, int lsfq_max);
+
+/**
+ * \brief Convert LSF to LSP
+ * \param lsp [out] LSP coefficients (-(1<<15) <= lsp < (1<<15))
+ * \param lsf LSF coefficients (0 <= lsf < PI * (1<<13))
+ *
+ * \remark It is safe to pass the same array in lsf and lsp parameters
+ */
+void ff_acelp_lsp2lpc(int16_t* lp, const int16_t* lsp);
+
+/**
+ * \brief LSP to LP conversion (3.2.6 of G.729)
+ * \param lp [out] (Q12) decoded LP coefficients
+ * \param lsp (Q15) LSP coefficients
+ */
+void ff_acelp_lsf2lsp(int16_t *lsp, const int16_t *lsf);
+
+/**
+ * \brief Interpolate LSP for the first subframe and convert LSP -> LP for both subframes (3.2.5 and 3.2.6 of G.729)
+ * \param lp_1st [out] (Q12) decoded LP coefficients for 1st subframe
+ * \param lp_2nd [out] (Q12) decoded LP coefficients for second subframe
+ * \param lsp_2nd (Q15) LSP coefficients of the second subframe
+ * \param lsp_prev (Q15) past LSP coefficients
+ */
+void ff_acelp_lp_decode(int16_t* lp_1st, int16_t* lp_2nd, const int16_t* lsp_2nd, const int16_t* lsp_prev);
+
+#endif // FFMPEG_ACELP_LPC_H



More information about the ffmpeg-devel mailing list