commit 1ad5aa5abdf23bb260595b07f0705c9ede1a37d2 Author: Johan Pascal Date: Wed Feb 15 18:38:21 2012 +0100 ITU G729 annexe A implementation diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f1c751 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +.deps/ +INSTALL +Makefile +Makefile.in +aclocal.m4 +autom4te.cache/ +build-aux/ +config.log +config.status +configure +libtool +*.o +*.lo +*.la +libbcg729.pc +test/src/decoderTest +test/src/encoderTest +.libs + diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..676249f --- /dev/null +++ b/AUTHORS @@ -0,0 +1,4 @@ +Copyright 2012 Belledonne Communications SARL. + +Johan Pascal +Jehan Monnier diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d60c31a --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..19db0be --- /dev/null +++ b/Makefile.am @@ -0,0 +1,13 @@ +ACLOCAL_AMFLAGS = -I m4 +SUBDIRS = src include +if BUILD_MSBCG729 +SUBDIRS += msbcg729 +endif + +SUBDIRS += test + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libbcg729.pc + + + diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/README b/README new file mode 100644 index 0000000..a9a9c55 --- /dev/null +++ b/README @@ -0,0 +1,21 @@ +bcg729 - g729 encoder and decoder implementation, and mediastreamer2 plugin interface. + +By default, the upstream package installs into /usr/local. Please use +'./configure --prefix' to change it + +# Tests suite: +- Tests are defined for each functional bloc (more or less matching a source file) +and for global encoding/decoding + +- Use 'make check' to compile and run all tests available in the test directory. + +- Input tests pattern have been generated by ITU code using ITU tests patterns. +The test patterns are not part of this repository but can be downloaded here: +http://www.belledonne-communications.com/downloads/bcg729-patterns.zip +However, the first run of 'make check' will get them for you. + +- To run partial test, use perl executable 'testCampaign' in the test directory. +'./testCampaign ' +You must first download the tests patterns using 'make check' or manually + + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..32b06e0 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +#AM_VERSION="1.11" +if ! type aclocal-$AM_VERSION 1>/dev/null 2>&1; then + AUTOMAKE=automake + ACLOCAL=aclocal +else + ACLOCAL=aclocal-${AM_VERSION} + AUTOMAKE=automake-${AM_VERSION} +fi + +if test -f /opt/local/bin/glibtoolize ; then + # darwin + LIBTOOLIZE=/opt/local/bin/glibtoolize +else + LIBTOOLIZE=libtoolize +fi +if test -d /opt/local/share/aclocal ; then + ACLOCAL_ARGS="-I /opt/local/share/aclocal" +fi + +echo "Generating build scripts for G729 codec..." +set -x +$LIBTOOLIZE --copy --force +$ACLOCAL $ACLOCAL_ARGS +#autoheader +$AUTOMAKE --force-missing --add-missing --copy +autoconf + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..18684bc --- /dev/null +++ b/configure.ac @@ -0,0 +1,45 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + + + +AC_INIT([bcg729],[0.1]) +AC_PREREQ(2.63) +AC_CONFIG_SRCDIR([src/encoder.c]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_MACRO_DIR([m4]) +AM_INIT_AUTOMAKE([tar-ustar --warnings=no-portability]) +AC_PROG_LIBTOOL +AC_PROG_CC +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_ARG_ENABLE(strict, +[ --enable-strict Enable error on compilation warning [default=yes]], +[wall_werror=$enableval], +[wall_werror=yes] +) + +CFLAGS="$CFLAGS -Wall" + +if test $GCC = yes && test $wall_werror = yes; then + CFLAGS="$CFLAGS -Werror " +fi + +# check for libraries that have pkg-config files installed +PKG_CHECK_MODULES(ORTP, ortp >= 0.16.0,[found_ortp=true],foo=bar) +PKG_CHECK_MODULES(MEDIASTREAMER, mediastreamer >= 2.0.0,[found_ms2=true],foo=bar) +AM_CONDITIONAL(BUILD_MSBCG729, test x$found_ms2 = xtrue && test x$found_ortp = xtrue) + +# Create the following files from their .in counterparts +AC_CONFIG_FILES([ + Makefile + src/Makefile + include/Makefile + include/bcg729/Makefile + msbcg729/Makefile + test/Makefile + test/bin/Makefile + libbcg729.pc +]) + +AC_OUTPUT diff --git a/include/LP2LSPConversion.h b/include/LP2LSPConversion.h new file mode 100644 index 0000000..761b61b --- /dev/null +++ b/include/LP2LSPConversion.h @@ -0,0 +1,34 @@ +/* + LP2LSPConversion.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef LP2LSPCONVERSION_H +#define LP2LSPCONVERSION_H +/*****************************************************************************/ +/* LP2LSPConversion : Compute polynomials, find their roots as in spec A3.2.3*/ +/* parameters: */ +/* -(i) LPCoefficients[] : 10 coefficients in Q12 */ +/* -(o) LSPCoefficients[] : 10 coefficients in Q15 */ +/* */ +/* return value : */ +/* - boolean: 1 if all roots found, 0 if unable to compute 10 roots */ +/* */ +/*****************************************************************************/ +int LP2LSPConversion(word16_t LPCoefficients[], word16_t LSPCoefficients[]); +#endif /* ifndef LP2LSPCONVERSION_H */ diff --git a/include/LPSynthesisFilter.h b/include/LPSynthesisFilter.h new file mode 100644 index 0000000..d4c66a5 --- /dev/null +++ b/include/LPSynthesisFilter.h @@ -0,0 +1,34 @@ +/* + LPSynthesisFilter.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef LPSYNTHESISFILTER_H +#define LPSYNTHESISFILTER_H +/*****************************************************************************/ +/* LPSynthesisFilter : as decribed in spec 4.1.6 eq77 */ +/* parameters: */ +/* -(i) excitationVector: u(n), the excitation, 40 values in Q0 */ +/* -(i) LPCoefficients: 10 LP coefficients in Q12 */ +/* -(i/o) recontructedSpeech: 50 values in Q0 */ +/* [-NB_LSP_COEFF, -1] of previous values as input */ +/* [0, L_SUBFRAME[ as output */ +/* */ +/*****************************************************************************/ +void LPSynthesisFilter (word16_t *excitationVector, word16_t *LPCoefficients, word16_t *reconstructedSpeech); +#endif /* ifndef LPSYNTHESISFILTER_H */ diff --git a/include/LSPQuantization.h b/include/LSPQuantization.h new file mode 100644 index 0000000..7a6168b --- /dev/null +++ b/include/LSPQuantization.h @@ -0,0 +1,36 @@ +/* + LSPQuantization.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef LSPQUANTIZATION_H +#define LSPQUANTIZATION_H +void initLSPQuantization(bcg729EncoderChannelContextStruct *encoderChannelContext); + +/*****************************************************************************/ +/* LSPQuantization : Convert LSP to LSF, Quantize LSF and find L parameters, */ +/* qLSF->qLSP as described in spec A3.2.4 */ +/* parameters: */ +/* -(i/o) encoderChannelContext : the channel context data */ +/* -(i) LSPCoefficients : 10 LSP coefficients in Q15 */ +/* -(i) qLSPCoefficients : 10 qLSP coefficients in Q15 */ +/* -(o) parameters : 4 parameters L0, L1, L2, L3 */ +/* */ +/*****************************************************************************/ +void LSPQuantization(bcg729EncoderChannelContextStruct *encoderChannelContext, word16_t LSPCoefficients[], word16_t qLSPCoefficients[], uint16_t parameters[]); +#endif /* LSPQUANTIZATION_H */ diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 0000000..9f9d70b --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = bcg729 + + + diff --git a/include/adaptativeCodebookSearch.h b/include/adaptativeCodebookSearch.h new file mode 100644 index 0000000..c148cc7 --- /dev/null +++ b/include/adaptativeCodebookSearch.h @@ -0,0 +1,49 @@ +/* + adaptativeCodebookSearch.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef ADAPTATIVECODEBOOKSEARCH_H +#define ADAPTATIVECODEBOOKSEARCH_H +/*****************************************************************************/ +/* adaptativeCodebookSearch: compute parameter P1 and P2 as in spec A.3.7 */ +/* compute also adaptative codebook vector as in spec 3.7.1 */ +/* parameters: */ +/* -(i/o) excitationVector: [-154,0[ previous excitation as input */ +/* Range [0,39[ */ +/* 40 words of LPResidualSignal as substitute for current */ +/* excitation (spec A.3.7) as input */ +/* 40 words of adaptative codebook vector in Q0 as output */ +/* Buffer in Q0 accessed in range [-154, 39] */ +/* -(i/o) intPitchDelayMin: low boundary for pitch delay search */ +/* -(i/o) intPitchDelayMax: low boundary for pitch delay search */ +/* Boundaries are updated during first subframe search */ +/* -(i) impulseResponse: 40 values as in spec A.3.5 in Q12 */ +/* -(i) targetSignal: 40 values as in spec A.3.6 in Q0 */ +/* */ +/* -(o) intPitchDelay: the integer pitch delay */ +/* -(o) fracPitchDelay: the fractionnal part of pitch delay */ +/* -(o) pitchDelayCodeword: P1 or P2 codeword as in spec 3.7.2 */ +/* -(o) adaptativeCodebookVector: 40 words of adaptative codebook vector*/ +/* as described in spec 3.7.1, in Q0. */ +/* -(i) subFrameIndex: 0 for the first subframe, 40 for the second */ +/* */ +/*****************************************************************************/ +void adaptativeCodebookSearch(word16_t excitationVector[], int16_t *intPitchDelayMin, int16_t *intPitchDelayMax, word16_t impulseResponse[], word16_t targetSignal[], + int16_t *intPitchDelay, int16_t *fracPitchDelay, uint16_t *pitchDelayCodeword, uint16_t subFrameIndex); +#endif /* ifndef ADAPTATIVECODEBOOKSEARCH_H */ diff --git a/include/basicOperationsMacros.h b/include/basicOperationsMacros.h new file mode 100644 index 0000000..b48c505 --- /dev/null +++ b/include/basicOperationsMacros.h @@ -0,0 +1,26 @@ +/* + basicOperationsMacros.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef BASICOPERATIONSMACROS_H +#define BASICOPERATIONSMACROS__H + +#include "fixedPointMacros.h" + +#endif /* ifndef BASICOPERATIONSMACROS_H */ diff --git a/include/bcg729/Makefile.am b/include/bcg729/Makefile.am new file mode 100644 index 0000000..13fee4c --- /dev/null +++ b/include/bcg729/Makefile.am @@ -0,0 +1,5 @@ +bcg729_includedir=$(includedir)/bcg729 + +bcg729_include_HEADERS= encoder.h decoder.h + +EXTRA_DIST=$(bcg729_include_HEADERS) diff --git a/include/bcg729/decoder.h b/include/bcg729/decoder.h new file mode 100644 index 0000000..cae1fa2 --- /dev/null +++ b/include/bcg729/decoder.h @@ -0,0 +1,52 @@ +/* + decoder.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef DECODER_H +#define DECODER_H +typedef struct bcg729DecoderChannelContextStruct_struct bcg729DecoderChannelContextStruct; +#include + +/*****************************************************************************/ +/* initBcg729DecoderChannel : create context structure and initialise it */ +/* return value : */ +/* - the decoder channel context data */ +/* */ +/*****************************************************************************/ +__attribute__ ((visibility ("default"))) bcg729DecoderChannelContextStruct *initBcg729DecoderChannel(); + +/*****************************************************************************/ +/* closeBcg729DecoderChannel : free memory of context structure */ +/* parameters: */ +/* -(i) decoderChannelContext : the channel context data */ +/* */ +/*****************************************************************************/ +__attribute__ ((visibility ("default"))) void closeBcg729DecoderChannel(bcg729DecoderChannelContextStruct *decoderChannelContext); + +/*****************************************************************************/ +/* bcg729Decoder : */ +/* parameters: */ +/* -(i) decoderChannelContext : the channel context data */ +/* -(i) bitStream : 15 parameters on 80 bits */ +/* -(i) frameErased: flag: true, frame has been erased */ +/* -(o) signal : a decoded frame 80 samples (16 bits PCM) */ +/* */ +/*****************************************************************************/ +__attribute__ ((visibility ("default"))) void bcg729Decoder(bcg729DecoderChannelContextStruct *decoderChannelContext, uint8_t bitStream[], uint8_t frameErasureFlag, int16_t signal[]); +#endif /* ifndef DECODER_H */ diff --git a/include/bcg729/encoder.h b/include/bcg729/encoder.h new file mode 100644 index 0000000..5967903 --- /dev/null +++ b/include/bcg729/encoder.h @@ -0,0 +1,52 @@ +/* + encoder.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef ENCODER_H +#define ENCODER_H +#include +typedef struct bcg729EncoderChannelContextStruct_struct bcg729EncoderChannelContextStruct; + +/*****************************************************************************/ +/* initBcg729EncoderChannel : create context structure and initialise it */ +/* return value : */ +/* - the encoder channel context data */ +/* */ +/*****************************************************************************/ +__attribute__ ((visibility ("default"))) bcg729EncoderChannelContextStruct *initBcg729EncoderChannel(); + +/*****************************************************************************/ +/* closeBcg729EncoderChannel : free memory of context structure */ +/* parameters: */ +/* -(i) encoderChannelContext : the channel context data */ +/* */ +/*****************************************************************************/ +__attribute__ ((visibility ("default"))) void closeBcg729EncoderChannel(bcg729EncoderChannelContextStruct *encoderChannelContext); + +/*****************************************************************************/ +/* bcg729Encoder : */ +/* parameters: */ +/* -(i) encoderChannelContext : context for this encoder channel */ +/* -(i) inputFrame : 80 samples (16 bits PCM) */ +/* -(o) bitStream : The 15 parameters for a frame on 80 bits */ +/* on 80 bits (5 16bits words) */ +/* */ +/*****************************************************************************/ +__attribute__ ((visibility ("default"))) void bcg729Encoder(bcg729EncoderChannelContextStruct *encoderChannelContext, int16_t inputFrame[], uint8_t bitStream[]); +#endif /* ifndef ENCODER_H */ diff --git a/include/codebooks.h b/include/codebooks.h new file mode 100644 index 0000000..d113770 --- /dev/null +++ b/include/codebooks.h @@ -0,0 +1,50 @@ +/* + codebooks.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef CODEBOOKS_H +#define CODEBOOKS_H + +#include "codecParameters.h" +/* this codebooks are defined in codebook.c */ + +/*** codebooks for quantization of the LSP coefficient - doc: 3.2.4 ***/ +extern word16_t L1[L1_RANGE][NB_LSP_COEFF]; /* The first stage is a 10-dimensional VQ using codebook L1 with 128 entries (7 bits). in Q2.13 */ +extern word16_t L2L3[L2_RANGE][NB_LSP_COEFF]; /* Doc : The second stage is a 10-bit VQ splitted in L2(first 5 values of a vector) and L3(last five value in each vector) containing 32 entries (5 bits). in Q0.13 but max value < 0.5 so fits in 13 bits. */ + +extern word16_t MAPredictor[L0_RANGE][MA_MAX_K][NB_LSP_COEFF]; /* the MA predictor coefficients in Q0.15 but max value < 0.5 so it fits on 15 bits */ +extern word16_t MAPredictorSum[L0_RANGE][NB_LSP_COEFF]; /* 1 - Sum(MAPredictor) in Q0.15 */ +extern word16_t invMAPredictorSum[L0_RANGE][NB_LSP_COEFF]; /* 1/(1 - Sum(MAPredictor)) in Q3.12 */ + +/* codebook for adaptative code vector */ +extern word16_t b30[30]; + +/* codebook for gains */ +extern uint16_t reverseIndexMappingGA[8]; +extern uint16_t reverseIndexMappingGB[16]; +extern uint16_t indexMappingGA[8]; +extern uint16_t indexMappingGB[16]; +extern word16_t GACodebook[8][2]; +extern word16_t GBCodebook[16][2]; +extern word16_t MAPredictionCoefficients[4]; + +/* codebook for LP Analysis */ +extern word16_t wlp[L_LP_ANALYSIS_WINDOW]; +extern word16_t wlag[NB_LSP_COEFF+1]; +#endif /* ifndef CODEBOOKS_H */ diff --git a/include/codecParameters.h b/include/codecParameters.h new file mode 100644 index 0000000..f20b729 --- /dev/null +++ b/include/codecParameters.h @@ -0,0 +1,113 @@ +/* + codecParameters.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef CODECPARAMETERS_H +#define CODECPARAMETERS_H + +#define L_FRAME 80 /* Frame size. */ +#define L_SUBFRAME 40 /* subFrame size. */ + +#define L_LP_ANALYSIS_WINDOW 240 /* Size of the window used in the LP Analysis */ +/******************************************************************************/ +/*** LSP coefficients ***/ +/******************************************************************************/ +/* define each coefficient bit number and range */ +#define L0_LENGTH 1 +#define L1_LENGTH 7 +#define L2_LENGTH 5 +#define L3_LENGTH 5 +#define L0_RANGE (1<> (shift)) +#define SHL(a,shift) ((word32_t)(a) << (shift)) +/* shift right with rounding: used to extract the integer value of a Qa number */ +#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +/* shift right with checking on sign of shift value */ +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) +#define SHR16(a,shift) ((a) >> (shift)) +#define SHL16(a,shift) ((a) << (shift)) +#define SHR32(a,shift) ((a) >> (shift)) +#define SHL32(a,shift) ((a) << (shift)) +#define SHR64(a,shift) ((a) >> (shift)) +#define SHL64(a,shift) ((a) << (shift)) + +/* avoid overflows: a+1 is used to check on negative value because range of a 2n signed bits int is -2pow(n) - 2pow(n)-1 */ +/* SATURATE Macro shall be called with MAXINT(nbits). Ex: SATURATE(x,MAXINT16) with MAXINT16 defined to 2pow(16) - 1 */ +#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a+1) ? -(a+1) : (x))) + +/*** add and sub ***/ +#define ADD16(a,b) ((word16_t)((word16_t)(a)+(word16_t)(b))) +#define SUB16(a,b) ((word16_t)(a)-(word16_t)(b)) +#define ADD32(a,b) ((word32_t)(a)+(word32_t)(b)) +#define SUB32(a,b) ((word32_t)(a)-(word32_t)(b)) + +/*** Multiplications/Accumulations ***/ +/* WARNING: MULT16_32_QX use MULT16_16 macro but the first multiplication must actually be a 16bits * 32bits with result on 32 bits and not a 16*16 */ +/* MULT16_16 is then implemented here as a 32*32 bits giving result on 32 bits */ +#define MULT16_16(a,b) ((word32_t)((word32_t)(a))*((word32_t)(b))) +#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b)))) +#define MSU16_16(c,a,b) (SUB32((c),MULT16_16((a),(b)))) +#define DIV32(a,b) (((word32_t)(a))/((word32_t)(b))) + +/* Q4 operations */ +#define MULT16_16_Q4(a,b) (SHR(MULT16_16((a),(b)),4)) +#define MAC16_16_Q4(c,a,b) ADD32(c,MULT16_16_Q4(a,b)) + +/* Q11 operations */ +#define MULT16_16_Q11(a,b) (SHR(MULT16_16((a),(b)),11)) +#define MULT16_16_P11(a,b) (SHR(ADD32(1024,MULT16_16((a),(b))),11)) + +/* Q12 operations */ +#define MULT16_32_Q12(a,b) ADD32(MULT16_16((a),SHR((b),12)), SHR(MULT16_16((a),((b)&0x00000fff)),12)) +#define MAC16_32_Q12(c,a,b) ADD32(c,MULT16_32_Q12(a,b)) +#define MULT16_16_Q12(a,b) (SHR(MULT16_16((a),(b)),12)) +#define MAC16_16_Q12(c,a,b) ADD32(c,MULT16_16_Q12(a,b)) +#define MSU16_16_Q12(c,a,b) SUB32(c,MULT16_16_Q12(a,b)) + +/* Q13 operations */ +#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13)) +#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13)) +#define MULT16_32_Q13(a,b) ADD32(MULT16_16((a),SHR((b),13)), SHR(MULT16_16((a),((b)&0x00001fff)),13)) +#define MAC16_32_Q13(c,a,b) ADD32(c,MULT16_32_Q13(a,b)) + +/* Q14 operations */ +#define MULT16_32_P14(a,b) ADD32(MULT16_16((a),SHR((b),14)), PSHR(MULT16_16((a),((b)&0x00003fff)),14)) +#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14)) +#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14)) +#define MAC16_16_Q14(c,a,b) ADD32(c,MULT16_16_Q14(a,b)) +#define MSU16_16_Q14(c,a,b) SUB32(c,MULT16_16_Q14(a,b)) + +/* Q15 operations */ +#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15)) +#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15)) +#define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15)) +#define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)) +#define MAC16_32_P15(c,a,b) ADD32(c,MULT16_32_P15(a,b)) + +/* 64 bits operations */ +#define ADD64_32(a,b) ((word64_t)(a)+(word32_t)(b)) +#define MULT32_32(a,b) ((word64_t)((word64_t)(a)*((word64_t)(b)))) +#define DIV64(a,b) ((word64_t)(a)/(word64_t)(b)) +#define MAC64(c,a,b) ((word64_t)c+(word64_t)((word64_t)a*(word64_t)b)) + +/* Divisions: input numbers with similar scale(Q) output according to operation. Warning: Make use of 64 bits variables */ +#define DIV32_32_Q24(a,b) (((word64_t)(a)<<24)/((word32_t)(b))) +#define DIV32_32_Q27(a,b) (((word64_t)(a)<<27)/((word32_t)(b))) +#define DIV32_32_Q31(a,b) (((word64_t)(a)<<31)/((word32_t)(b))) + +#define MULT32_32_Q23(a,b) ((word32_t)(SHR64(((word64_t)a*(word64_t)b),23))) + +#define MULT32_32_Q31(a,b) ((word32_t)(SHR64(((word64_t)a*(word64_t)b),31))) +#define MAC32_32_Q31(c,a,b) ADD32(c,MULT32_32_Q31(a,b)) + +#endif /* ifndef FIXEDPOINTMACROS_H */ diff --git a/include/floatingPointMacros.h b/include/floatingPointMacros.h new file mode 100644 index 0000000..5bb7008 --- /dev/null +++ b/include/floatingPointMacros.h @@ -0,0 +1,52 @@ +/* + floatingPointMacros.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef FLOATINGPOINTMACROS_H +#define FLOATINGPOINTMACROS_H + +#define EXTEND32(x) (x) + +/* shifts */ +#define SHR(a,shift) (a) +#define SHL(a,shift) (a) +#define PSHR(a,shift) (a) + +/* avoid overflows: nothing to do for floats */ +#define SATURATE(x,a) (x) + +/* add and sub */ +#define ADD16(a,b) ((a)+(b)) +#define SUB16(a,b) ((a)-(b)) +#define ADD32(a,b) ((a)+(b)) +#define SUB32(a,b) ((a)-(b)) + + +/* Multiplications/Accumulations */ +#define MULT16_16(a,b) ((word32_t)(a)*(word32_t)(b)) +#define MAC16_16(c,a,b) ((c)+MULT16_16((a),(b))) +#define MULT16_32(a,b) ((a)*(b)) +#define MAC16_32(c,a,b) ((c)+(a)*(b)) + +/* Q12 operations */ +#define MULT16_32_Q12(a,b) MULT16_32(a,b) +#define MAC16_32_Q12(c,a,b) MAC16_32(c,a,b) + + +#endif /* ifndef FLOATINGPOINTMACROS_H */ diff --git a/include/g729FixedPointMath.h b/include/g729FixedPointMath.h new file mode 100644 index 0000000..8778199 --- /dev/null +++ b/include/g729FixedPointMath.h @@ -0,0 +1,316 @@ +/* + g729FixedPointMath.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef G729FIXEDPOINTMATH_H +#define G729FIXEDPOINTMATH_H + +/*****************************************************************************/ +/* */ +/* This library provides the following functions */ +/* */ +/* g729Log2_Q0Q16 : Logarithm base 2 */ +/* g729Exp2_Q11Q16 : Exponentiel base 2 */ +/* g729Sqrt_Q0Q7 : Square Root */ +/* g729Cos_Q13Q15 : Cosine */ +/* g729Atan_Q15Q13 : Arc Tangent */ +/* g729Asin_Q15Q13 : Arc Sine */ +/* g729Acos_Q15Q13 : Arc Cosine */ +/* */ +/* Extention QxxQyy stands for input in Qxx output in Qyy */ +/* */ +/*****************************************************************************/ + +#include "typedef.h" +#include "basicOperationsMacros.h" +#include "utils.h" + +/* constants defined in Q16: actual values: + KL0 = -2.059978 + KL1 = 5.770780 + KL2 = -3.847187 + KL3 = 1.139907 +*/ +#define KL0 -135003 +#define KL1 378194 +#define KL2 -252129 +#define KL3 74705 +/*****************************************************************************/ +/* g729Log2_Q0Q16 : logarithm base 2, frac part computed from Taylor serie */ +/* paremeters: */ +/* -(i) x : 32 bits integer in Q0, expected to be>0(not checked here) */ +/* return value: */ +/* - the log2(x) in Q16 on 32 bits */ +/* */ +/*****************************************************************************/ +static inline word32_t g729Log2_Q0Q16(word32_t x) +{ + /* first get the integer part and put it in the 16 MSB of return value (in Q16) */ + uint16_t leadingZeros = countLeadingZeros(x); /* note: MSB is excluded as considered as sign bit */ + word32_t retValue = SHL32(SUB16(30,leadingZeros), 16); + + /* now shift the number to have it on this form 01XX XXXX XXXX XXXX, and keep only 16 bits -> consider it as a number in range [0.5, 1[ in Q0.15 */ + word16_t acc = (word16_t)VSHR32(x, 16-leadingZeros); + /* So calling int the integer part of the log2, we have: */ + /* int = 30 - leadingZeros */ + /* acc = x*2^(leadingZeros - 16) */ + /* acc = x*2^(14 - int) */ + /* considering the content of acc as a Q15 number eq *2^-15*/ + /* acc = x*2^(14 -int)*2^-15 */ + /* acc = x*2^(-1 -int) */ + /* log2(acc) = log2(x) -1 - int */ + /* log2(x) ~= -3.059978 + 5.770780*x - 3.847187*x^2 + 1.139907*x^3 (for .5 < x < 1) Taylor Serie log2(x) at x near 0.75 */ + /* log2(x) + 1 = -2.059978 + x*(5.770780 +x(-3.847187 + 1.139907*x)) */ + /* with coeff in Q16 : */ + /* log2(acc) +1 = log2(x) - int = */ + /* log2(acc) +1 = -135003 +acc*(378194 +acc*(-252129 + acc*74705)) acc in Q15 and constants in Q16 -> final result will be log2(x) -int in Q16(on 32 bits) */ + word32_t acc32 = ADD32(KL0, MULT16_32_Q15(acc, ADD32(KL1, MULT16_32_Q15(acc, ADD32(KL2, MULT16_32_Q15(acc, KL3)))))); + + return ADD32(retValue,acc32); +} + +/* constants defined in Q15: actual values: + E0 = 1 + E1 = log(2) + E2 = 3-4*log(2) + E3 = 3*log(2) - 2 +*/ +#define E0 16384 +#define E1 11356 +#define E2 3726 +#define E3 1301 +/*****************************************************************************/ +/* g729Exp2_Q11Q16 : Exponentielle base 2 */ +/* paremeters: */ +/* -(i) x : 16 bits integer in Q11 */ +/* return value: */ +/* - exp2(x) in Q16 on 32 bits */ +/* */ +/*****************************************************************************/ +static inline word32_t g729Exp2_Q11Q16(word16_t x) +{ + int integer; + word16_t frac; + integer = SHR16(x,11); + if (integer>14) { + return 0x7fffffff; + } else { + if (integer < -15) { + return 0; + } + } + frac = SHL16(x-SHL16(integer,11),3); + frac = ADD16(E0, MULT16_16_Q14(frac, ADD16(E1, MULT16_16_Q14(frac, ADD16(E2 , MULT16_16_Q14(E3,frac)))))); + return VSHR32(EXTEND32(frac), -integer-2); +} + +/* constants in Q14 */ +#define C0 3634 +#define C1 21173 +#define C2 -12627 +#define C3 4204 +/*****************************************************************************/ +/* g729Sqrt_Q0Q7 : Square root */ +/* x is not tested to be >=0, shall be done by caller function */ +/* paremeters: */ +/* -(i) x : 32 bits integer in Q0 */ +/* return value: */ +/* - sqrt(x) in Q7 on 32 bits */ +/* */ +/*****************************************************************************/ +static inline word32_t g729Sqrt_Q0Q7(word32_t x) +{ + if (x==0) return 0; + int k; + word32_t rt; + /* set x in Q14 in range [0.25,1[ */ + k = (18-countLeadingZeros(x))>>1; + x = VSHR32(x, (k<<1)); /* x = x.2^-2k */ + + /* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25659*x^3 (for .25 < x < 1) */ + /* consider x as in Q14: y = x.2^(-2k-14) -> and give sqrt(y).2^14 = sqrt(x).2^(-k-7).2^14 */ + rt = ADD16(C0, MULT16_16_Q14(x, ADD16(C1, MULT16_16_Q14(x, ADD16(C2, MULT16_16_Q14(x, (C3))))))); /* rt = sqrt(x).2^(7-k)*/ + rt = VSHR32(rt,-k); /* rt = sqrt(x).2^7 */ + return rt; +} + +/*****************************************************************************/ +/* g729InvSqrt_Q0Q31 : Inverse Square root(1/Sqrt(x) */ +/* x is not tested to be >=1, shall be done by caller function */ +/* paremeters: */ +/* -(i) x : 32 bits integer in Q0 in range [1, MAXINT32] */ +/* return value: */ +/* - 1/sqrt(x) in Q31 on 32 bits in range [43341/2^31, MAXINT32] */ +/* */ +/*****************************************************************************/ +static inline word32_t g729InvSqrt_Q0Q31(word32_t x) +{ + if (x==1) return MAXINT32; + return (word32_t)(DIV32_32_Q24(g729Sqrt_Q0Q7(x),x)); /* sqrt(x) in Q7 + Q24 -> Q31 */ +} + +/* constants Q0.15 */ +#define Kcos1 32768 +#define Kcos2 -16384 +#define Kcos3 1365 +#define Kcos4 -46 + +#define Ksin1 32768 +#define Ksin2 -5461 +#define Ksin3 273 +#define Ksin4 -7 + +/*****************************************************************************/ +/* g729Cos_Q13Q15 : Cosine fonction in [0, Pi] */ +/* x is not tested to be in correct range */ +/* paremeters: */ +/* -(i) x : 16 bits integer in Q13 in range [0, Pi(25736)] */ +/* return value: */ +/* - cos(x) in Q0.15 on 16 bits in range [-1, 1[ */ +/* */ +/*****************************************************************************/ +static inline word16_t g729Cos_Q13Q15(word16_t x) +{ + /* input var x in Q2.13 and in ]0, Pi[ */ + word16_t x2,xScaled; + if (x<12868) { + if (x<6434) { /* x in ]0, Pi/4[ */ + x2 = MULT16_16_P11(x,x); /* in Q0.15 */ + return SATURATE(ADD32(Kcos1, MULT16_16_P15(x2, ADD32(Kcos2, MULT16_16_P15(x2, ADD32(Kcos3, MULT16_16_P15(Kcos4, x2)))))), MAXINT16); /* return cos x, must saturate if return value is +1 */ + } else {/* x in [Pi/4, Pi/2[ */ + x = SUB16(12868,x); /* x = pi/2 -x, x in [0, Pi/4] in Q0.13 */ + x2 = MULT16_16_P11(x,x); /* in Q0.15 */ + return (MULT16_16_P13(x,ADD32(Ksin1, MULT16_16_P15(x2, ADD32(Ksin2, MULT16_16_P15(x2, ADD32(Ksin3, MULT16_16_P15(Ksin4, x2)))))))); /* return cos x as sin(pi/2 -x) */ + } + } else { /* x in [Pi/2, Pi[ */ + xScaled = SUB16(25736,x); /* xScaled = Pi - x -> in [0,Pi/2] with cos(Pi-x) = -cos(x) and sin(Pi-x) = */ + if (x<19302) { /* x in [Pi/2, 3Pi/4], xScaled in [Pi/4, Pi/2] */ + xScaled = SUB16(12868,xScaled); /* xScaled = pi/2 - xScaled = x - Pi/2, xScaled in [0, Pi/4] in Q0.13 */ + x2 = MULT16_16_P11(xScaled,xScaled); /* in Q0.15 */ + return (MULT16_16_P13(-xScaled,ADD32(Ksin1, MULT16_16_P15(x2, ADD32(Ksin2, MULT16_16_P15(x2, ADD32(Ksin3, MULT16_16_P15(Ksin4, x2)))))))); /* return cos x as -sin(x - Pi/2) */ + } else { /* x in [3Pi/4, Pi[ -> xScaled in [0, Pi/4], cos(xScaled) = -cos(x) */ + x2 = MULT16_16_P11(xScaled,xScaled); /* in Q0.15 */ + return (SUB32(-Kcos1, MULT16_16_P15(x2, ADD32(Kcos2, MULT16_16_P15(x2, ADD32(Kcos3, MULT16_16_P15(Kcos4, x2))))))); /* return cos x as -cos(Pi -x) */ + } + + } +} +/* KPI6 = pi/6 in Q15 */ +#define KPI6 17157 +/* KtanPI6 = tan(pi/6) in Q15 */ +#define KtanPI6 18919 +/* KtanPI12 = tan(pi/12) in Q15 */ +#define KtanPI12 8780 + +/* B = 0.257977658811405 in Q15 */ +#define atanB 8453 +/* C = 0.59120450521312 in Q15 */ +#define atanC 19373 + +/*****************************************************************************/ +/* g729Atan_Q15Q13: ArcTangent fonction in [-2^16, 2^16[ */ +/* paremeters: */ +/* -(i) x : 32 bits integer in Q15 in range [-2^16, 2^16[ */ +/* return value: */ +/* - atan(x) in Q2.13 on 16 bits in range ]-Pi/2(12868), Pi/2(12868)[ */ +/* */ +/*****************************************************************************/ +static inline word16_t g729Atan_Q15Q13(word32_t x) +{ + /* constants for rational polynomial */ + word32_t angle; + word16_t x2; + int highSegment = 0; + + /* make argument positive */ + int sign = 0; + if (x < 0) { + x = NEG16(x); + sign = 1; + } + + /* limit argument to 0..1 */ + int complement = 0; + if(x > ONE_IN_Q15){ + complement = 1; + x = DIV32(ONE_IN_Q30, x); /* 1/x in Q15 */ + } + + /* determine segmentation */ + if(x > KtanPI12){ + highSegment = 1; + /* x = (x - k)/(1 + k*x); */ + x = DIV32(SHL(SUB32(x, KtanPI6), 15), ADD32(MULT16_16_Q15(KtanPI6, x), ONE_IN_Q15)); + } + + /* argument is now < tan(15 degrees) */ + /* approximate the function */ + x2 = MULT16_16_Q15(x,x); + angle = DIV32(MULT16_16(x, ADD32(ONE_IN_Q15, MULT16_16_Q15(atanB, x2))), ADD32(ONE_IN_Q15, MULT16_16_Q15(atanC, x2))); /* ang = x*(1 + B*x2)/(1 + C*x2) */ + + /* now restore offset if needed */ + if(highSegment) { + angle += KPI6; + } + + /* restore complement if needed */ + if(complement) { + angle = SUB32(HALF_PI_Q15, angle); + } + + /* set result in Q13 */ + angle = PSHR(angle, 2); + + /* restore sign if needed */ + if(sign) { + return NEG16(angle); + } else { + return angle; + } +} + + + +/*****************************************************************************/ +/* g729Asin_Q15Q13: ArcSine fonction */ +/* paremeters: */ +/* -(i) x : 16 bits integer in Q15 in range ]-1, 1[ */ +/* return value: */ +/* - asin(x) in Q2.13 on 16 bits in range ]-Pi/2(12868), Pi/2(12868)[ */ +/* */ +/*****************************************************************************/ +static inline word16_t g729Asin_Q15Q13(word16_t x) +{ + return g729Atan_Q15Q13(DIV32(SHL(x,15), PSHR(g729Sqrt_Q0Q7(SUB32(ONE_IN_Q30, MULT16_16(x,x))),7))); /* atan(x/sqrt(1.0 - x*x)) */ +} + +/*****************************************************************************/ +/* g729Acos_Q15Q13: ArcCosine fonction */ +/* paremeters: */ +/* -(i) x : 16 bits integer in Q15 in range ]-1, 1[ */ +/* return value: */ +/* - acos(x) in Q2.13 on 16 bits in range ]0, Pi(25736)[ */ +/* */ +/*****************************************************************************/ +static inline word16_t g729Acos_Q15Q13(word16_t x) +{ + return(HALF_PI_Q13 - g729Asin_Q15Q13(x)); +} + +#endif /* ifndef G729FIXEDPOINTMATH_H */ diff --git a/include/gainQuantization.h b/include/gainQuantization.h new file mode 100644 index 0000000..a159051 --- /dev/null +++ b/include/gainQuantization.h @@ -0,0 +1,44 @@ +/* + gainQuantization.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef GAINQUANTIZATION_H +#define GAINQUANTIZATION_H +void initGainQuantization(bcg729EncoderChannelContextStruct *encoderChannelContext); +/*****************************************************************************/ +/* gainQuantization : compute quantized adaptative and fixed codebooks gains */ +/* spec 3.9 */ +/* parameters: */ +/* -(i/o) encoderChannelContext : the channel context data */ +/* -(i) targetSignal: 40 values in Q0, x in eq63 */ +/* -(i) filteredAdaptativeCodebookVector: 40 values in Q0, y in eq63 */ +/* -(i) convolvedFixedCodebookVector: 40 values in Q12, z in eq63 */ +/* -(i) fixedCodebookVector: 40 values in Q13 */ +/* -(i) xy in Q0 on 64 bits term of eq63 computed previously */ +/* -(i) yy in Q0 on 64 bits term of eq63 computed previously */ +/* -(o) quantizedAdaptativeCodebookGain : in Q14 */ +/* -(o) quantizedFixedCodebookGain : in Q1 */ +/* -(o) gainCodebookStage1 : GA parameter value (3 bits) */ +/* -(o) gainCodebookStage2 : GB parameter value (4 bits) */ +/* */ +/*****************************************************************************/ +void gainQuantization(bcg729EncoderChannelContextStruct *encoderChannelContext, word16_t targetSignal[], word16_t filteredAdaptativeCodebookVector[], word16_t convolvedFixedCodebookVector[], word16_t fixedCodebookVector[], word64_t Xy64, word64_t Yy64, + word16_t *quantizedAdaptativeCodebookGain, word16_t *quantizedFixedCodebookGain, uint16_t *gainCodebookStage1, uint16_t *gainCodebookStage2); + +#endif /* ifndef GAINQUANTIZATION_H */ diff --git a/include/interpolateqLSP.h b/include/interpolateqLSP.h new file mode 100644 index 0000000..39029ec --- /dev/null +++ b/include/interpolateqLSP.h @@ -0,0 +1,33 @@ +/* + interpolateqLSP.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef INTERPOLATATEQLSP_H +#define INTERPOLATATEQLSP_H +/*****************************************************************************/ +/* interpolateqLSP : interpolate previous and current qLSP according to */ +/* spec. 3.2.5 : interpolated = (current+previous)/2 */ +/* parameters: */ +/* -(i) previousqLSP : 10 values in Q0.15: the qLSP of previous frame */ +/* -(i) currentqLSP : 10 values in Q0.15: the qLSP of current frame */ +/* -(o) interpolatedqLSP : 10 values in Q0.15 : the interpolated qLSP */ +/* */ +/*****************************************************************************/ +void interpolateqLSP(word16_t previousqLSP[], word16_t currentqLSP[], word16_t interpolatedqLSP[]); +#endif /* ifndef INTERPOLATATEQLSP_H */ diff --git a/include/postFilter.h b/include/postFilter.h new file mode 100644 index 0000000..c49be74 --- /dev/null +++ b/include/postFilter.h @@ -0,0 +1,40 @@ +/* + postFilter.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef POSTFILTER_H +#define POSTFILTER_H +/* init function */ +void initPostFilter(bcg729DecoderChannelContextStruct *decoderChannelContext); + +/*****************************************************************************/ +/* postFilter: filter the reconstructed speech according to spec A.4.2 */ +/* parameters: */ +/* -(i/o) decoderChannelContext : the channel context data */ +/* -(i) LPCoefficients: 10 LP coeff for current subframe in Q12 */ +/* -(i) reconstructedSpeech: output of LP Synthesis, 50 values in Q0 */ +/* 10 values of previous subframe, accessed in range [-10, 39] */ +/* -(i) intPitchDelay: the integer part of Pitch Delay in Q0 */ +/* -(i) subframeIndex: 0 or L_SUBFRAME for subframe 0 or 1 */ +/* -(o) postFilteredSignal: 40 values in Q0 */ +/* */ +/*****************************************************************************/ +void postFilter(bcg729DecoderChannelContextStruct *decoderChannelContext, word16_t *LPCoefficients, word16_t *reconstructedSpeech, int16_t intPitchDelay, int subframeIndex, + word16_t *postFilteredSignal); +#endif /* ifndef POSTFILTER_H */ diff --git a/include/postProcessing.h b/include/postProcessing.h new file mode 100644 index 0000000..2ecd811 --- /dev/null +++ b/include/postProcessing.h @@ -0,0 +1,35 @@ +/* + postProcessing.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef POSTPROCESSING_H +#define POSTPROCESSING_H +void initPostProcessing(bcg729DecoderChannelContextStruct *decoderChannelContext); +/*****************************************************************************/ +/* postProcessing : high pass filtering and upscaling Spec 4.2.5 */ +/* Algorithm: */ +/* y[i] = BO*x[i] + B1*x[i-1] + B2*x[i-2] + A1*y[i-1] + A2*y[i-2] */ +/* parameters: */ +/* -(i/o) decoderChannelContext : the channel context data */ +/* -(i/o) signal : 40 values in Q0, reconstructed speech, output */ +/* replaces the input in buffer */ +/* */ +/*****************************************************************************/ +void postProcessing(bcg729DecoderChannelContextStruct *decoderChannelContext, word16_t signal[]); +#endif /* ifndef POSTPROCESSING_H */ diff --git a/include/preProcessing.h b/include/preProcessing.h new file mode 100644 index 0000000..15e8308 --- /dev/null +++ b/include/preProcessing.h @@ -0,0 +1,37 @@ +/* + preProcessing.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef PREPROCESSING_H +#define PREPROCESSING_H +/* internal variable initialisations */ +void initPreProcessing(bcg729EncoderChannelContextStruct *encoderChannelContext); + +/*****************************************************************************/ +/* preProcessing : 2nd order highpass filter with cut off frequency at 140Hz */ +/* Algorithm: */ +/* y[i] = BO*x[i] + B1*x[i-1] + B2*x[i-2] + A1*y[i-1] + A2*y[i-2] */ +/* parameters : */ +/* -(i/o) encoderChannelContext : the channel context data */ +/* -(i) signal : 80 values in Q0 */ +/* -(o) preProcessedSignal : 80 values in Q0 */ +/* */ +/*****************************************************************************/ +void preProcessing(bcg729EncoderChannelContextStruct *encoderChannelContext, word16_t signal[], word16_t preProcessedSignal[]); +#endif /* ifndef PREPROCESSING_H */ diff --git a/include/qLSP2LP.h b/include/qLSP2LP.h new file mode 100644 index 0000000..ddb7f54 --- /dev/null +++ b/include/qLSP2LP.h @@ -0,0 +1,31 @@ +/* + qLSP2LP.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef QLSP2LP_H +#define QLSP2LP_H +/*****************************************************************************/ +/* qLSP2LP : convert qLSP into LP parameters according to spec. 3.2.6 */ +/* parameters: */ +/* -(i) qLSP : 10 LSP to be converted in Q0.15 range [-1, +1[ */ +/* -(o) LP : 10 LP coefficients in Q12 */ +/* */ +/*****************************************************************************/ +void qLSP2LP(word16_t qLSP[], word16_t LP[]); +#endif /* ifndef QLSP2LP_H */ diff --git a/include/typedef.h b/include/typedef.h new file mode 100644 index 0000000..7fa0a3a --- /dev/null +++ b/include/typedef.h @@ -0,0 +1,146 @@ +/* + typedef.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef TYPEDEF_H +#define TYPEDEF_H + +#include +#include "codecParameters.h" +#include "bcg729/encoder.h" +#include "bcg729/decoder.h" + +typedef int16_t word16_t; +typedef uint16_t uword16_t; +typedef int32_t word32_t; +typedef uint32_t uword32_t; +typedef int64_t word64_t; + +/* define the context structure to store all static data for a decoder channel */ +struct bcg729DecoderChannelContextStruct_struct { + /*** buffers used in decoder bloc ***/ + word16_t previousqLSP[NB_LSP_COEFF]; /* previous quantised LSP in Q0.15 */ + word16_t excitationVector[L_PAST_EXCITATION + L_FRAME]; /* in Q0 this vector contains: + 0->153 : the past excitation vector.(length is Max Pitch Delay: 144 + interpolation window size : 10) + 154-> 154+L_FRAME-1 : the current frame adaptative Code Vector first used to compute then the excitation vector */ + word16_t boundedAdaptativeCodebookGain; /* the pitch gain from last subframe bounded in range [0.2,0.8] in Q0.14 */ + word16_t adaptativeCodebookGain; /* the gains needs to be stored in case of frame erasure in Q14 */ + word16_t fixedCodebookGain; /* in Q14.1 */ + word16_t reconstructedSpeech[NB_LSP_COEFF+L_FRAME]; /* in Q0, output of the LP synthesis filter, the first 10 words store the previous frame output */ + uint16_t pseudoRandomSeed; /* seed used in the pseudo random number generator */ + + /*** buffers used in decodeLSP bloc ***/ + word16_t lastqLSF[NB_LSP_COEFF]; /* this buffer stores the last qLSF to be used in case of frame lost in Q2.13 */ + /* buffer to store the last 4 frames codewords, used to compute the current qLSF */ + word16_t previousLCodeWord[MA_MAX_K][NB_LSP_COEFF]; /* in Q2.13, buffer to store the last 4 frames codewords, used to compute the current qLSF */ + /* the values stored are the codewords computed from the codebooks and rearranged */ + word16_t lastValidL0; /* this one store the L0 of last valid frame to be used in case of frame erased */ + + /*** buffer used in decodeAdaptativeCodeVector bloc ***/ + uint16_t previousIntPitchDelay; /* store the last valid Integer Pitch Delay computed, used in case of parity error or frame erased */ + + /*** buffer used in decodeGains bloc ***/ + word16_t previousGainPredictionError[4]; /* the last four gain prediction error U(m) eq69 and eq72, spec3.9.1 in Q10*/ + + /*** buffers used in postFilter bloc ***/ + word16_t residualSignalBuffer[MAXIMUM_INT_PITCH_DELAY+L_FRAME]; /* store the residual signal (current subframe and MAXIMUM_INT_PITCH_DELAY of previous values) in Q0 */ + word16_t scaledResidualSignalBuffer[MAXIMUM_INT_PITCH_DELAY+L_FRAME]; /* same as previous but in Q-2 */ + word16_t longTermFilteredResidualSignalBuffer[1+L_SUBFRAME]; /* the output of long term filter in Q0, need 1 word from previous subframe for tilt compensation filter */ + word16_t *longTermFilteredResidualSignal; /* points to the beginning of current subframe longTermFilteredResidualSignal */ + word16_t shortTermFilteredResidualSignalBuffer[NB_LSP_COEFF+L_SUBFRAME]; /* the output of short term filter(synthesis filter) in Q0, need NB_LSP_COEFF word from previous subframe as filter memory */ + word16_t *shortTermFilteredResidualSignal; /* points to the beginning of current subframe shortTermFilteredResidualSignal */ + word16_t previousAdaptativeGain; /* previous gain for adaptative gain control */ + + /*** buffers used in postProcessing bloc ***/ + word16_t inputX0; + word16_t inputX1; + word32_t outputY2; + word32_t outputY1; + +}; + +/* define the context structure to store all static data for an encoder channel */ +struct bcg729EncoderChannelContextStruct_struct { + /*** buffers used in decoder bloc ***/ + /* Signal buffer mapping : 240 word16_t length */ + /* <---- 120 word16_t -->|<---- 80 word16_t ---->|<---- 40 word16_t --->| */ + /* |----- old signal -----|----------- current frame -------------------|-----next subframe 1 ------------| */ + /* |----- subframe 1 -----|----- subframe 2 -----| */ + /* |--------------- last input frame -----------------------| */ + /* ^ ^ ^ */ + /* | | | */ + /* signalBuffer signalCurrentFrame signalLastInputFrame */ + word16_t signalBuffer[L_LP_ANALYSIS_WINDOW]; /* this buffer stores the input signal */ + word16_t *signalLastInputFrame; /* point to the beginning of the last frame in the signal buffer */ + word16_t *signalCurrentFrame; /* point to the beginning of the current frame in the signal buffer */ + word16_t previousLSPCoefficients[NB_LSP_COEFF]; /* LSP coefficient of previous frame */ + word16_t previousqLSPCoefficients[NB_LSP_COEFF]; /* Quantized LSP coefficient of previous frame */ + word16_t weightedInputSignal[MAXIMUM_INT_PITCH_DELAY+L_FRAME]; /* buffer storing the weightedInputSignal on current frame and MAXIMUM_INT_PITCH_DELAY of previous values */ + word16_t excitationVector[L_PAST_EXCITATION + L_FRAME]; /* in Q0 this vector contains: + 0->153 : the past excitation vector.(length is Max Pitch Delay: 144 + interpolation window size : 10) + 154-> 154+L_FRAME-1 : the current frame adaptative Code Vector first used to compute then the excitation vector */ + word16_t targetSignal[NB_LSP_COEFF+L_SUBFRAME]; /* in Q0, buffer holding the target signal (x[n]) as in spec A.3.6, the first NB_LSP_COEFF values are memory from previous subframe used in filtering(computed according to spec A.3.10), the following values are the target signal for current subframe */ + word16_t lastQuantizedAdaptativeCodebookGain; /* in Q14, the quantized adaptive codebook gain from previous subframe */ + + /*** buffer used in preProcessing ***/ + word16_t inputX0, inputX1; + word32_t outputY2, outputY1; + + /*** buffer used in LSPQuantization ***/ + word16_t previousqLSF[MA_MAX_K][NB_LSP_COEFF]; /* previousqLSF of the last 4(MA pred buffer size) frames in Q13, contains actually quantizer output (l) and not LSF (w)*/ + + /*** buffer used in gainQuantization ***/ + word16_t previousGainPredictionError[4]; /* the last four gain prediction error U(m) eq69 and eq72, spec3.9.1 in Q10*/ + +}; + +/* MAXINTXX define the maximum signed integer value on XX bits(2^(XX-1) - 1) */ +/* used to check on overflows in fixed point mode */ +#define MAXINT16 0x7fff +#define MAXINT28 0x7ffffff +#define MAXINT29 0xfffffff +#define MININT32 0x80000000 +#define MAXINT32 0x7fffffff +#define MAXINT64 0x7fffffffffffffffLL + +/* several values used for inits */ +#define ONE_IN_Q31 0x7FFFFFFF +#define ONE_IN_Q30 0x40000000 +#define ONE_IN_Q27 0x08000000 +#define ONE_IN_Q15 0x00008000 +#define ONE_IN_Q13 0x00002000 +#define ONE_IN_Q12 0x00001000 +#define ONE_IN_Q11 0x00000800 + +#define HALF_PI_Q13 12868 +#define HALF_PI_Q15 51472 + +/* 0.04*Pi + 1 and 0.92*Pi - 1 used by LSPQuantization */ +#define OO4PIPLUS1_IN_Q13 9221 +#define O92PIMINUS1_IN_Q13 15485 +/* 1.2 in Q14 */ +#define ONE_POINT_2_IN_Q14 19661 +/* 0.7 in Q12 */ +#define O7_IN_Q12 2867 +/* 0.2 in Q14 */ +#define O2_IN_Q14 3277 +/* 0.2 in Q15 */ +#define O2_IN_Q15 6554 + +#endif /* ifndef TYPEDEF_H */ diff --git a/include/utils.h b/include/utils.h new file mode 100644 index 0000000..29b4629 --- /dev/null +++ b/include/utils.h @@ -0,0 +1,163 @@ +/* + utils.h + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef UTILS_H +#define UTILS_H + +/*****************************************************************************/ +/* insertionSort : sort an array in growing order using insertion algorithm */ +/* parameters : */ +/* -(i/o) x: the array to be sorted */ +/* -(i) length: the array length */ +/* */ +/*****************************************************************************/ +void insertionSort(word16_t x[], int length); + +/*****************************************************************************/ +/* computeParity : compute parity for pitch delay adaptative codebook index */ +/* XOR of the 6 MSB (pitchDelay on 8 bits) */ +/* parameters : */ +/* -(i) adaptativeCodebookIndex: the pitch delay on 8 bits */ +/* return value : */ +/* the parity bit */ +/* */ +/*****************************************************************************/ +uint16_t computeParity(uint16_t adaptativeCodebookIndex); + +/*****************************************************************************/ +/* rearrangeCoefficients: rearrange coefficients according to spec 3.2.4 */ +/* Have a minimum distance of J beetwen two consecutive coefficients */ +/* parameters: */ +/* -(i/o) qLSP: 10 ordered coefficients in Q13 replaced by new values */ +/* if needed */ +/* -(i) J: minimum distance between coefficients in Q0.13 (10 or 5) */ +/* */ +/*****************************************************************************/ +void rearrangeCoefficients(word16_t qLSP[], word16_t J); + +/*****************************************************************************/ +/* synthesisFilter : compute 1/[A(z)] using the following algorithm */ +/* filteredSignal[n] = inputSignal[n] */ +/* - Sum(i=1..10)filterCoefficients[i]*filteredSignal[n-i] */ +/* for n in [0, L_SUBFRAME[ */ +/* parameters: */ +/* -(i) inputSignal: 40 values in Q0 */ +/* -(i) filterCoefficients: 10 coefficients in Q12 */ +/* -(i/o) filteredSignal: 50 values in Q0 accessed in ranges [-10,-1] */ +/* as input and [0, 39] as output. */ +/* */ +/*****************************************************************************/ +void synthesisFilter(word16_t inputSignal[], word16_t filterCoefficients[], word16_t filteredSignal[]); + +/*****************************************************************************/ +/* correlateVectors : compute the correlations between two vectors of */ +/* L_SUBFRAME length: c[i] = Sum(x[j]*y[j-i]) j in [i..L_SUBFRAME] */ +/* parameters: */ +/* -(i) x : L_SUBFRAME length input vector on 16 bits */ +/* -(i) y : L_SUBFRAME length input vector on 16 bits */ +/* -(o) c : L_SUBFRAME length output vector on 32 bits */ +/* */ +/*****************************************************************************/ +void correlateVectors (word16_t x[], word16_t y[], word32_t c[]); + +/*****************************************************************************/ +/* countLeadingZeros : return the number of zero heading the argument */ +/* MSB is excluded as considered sign bit. */ +/* May be replaced by one asm instruction. */ +/* parameters : */ +/* -(i) x : 32 bits values >= 0 (no checking done by this function) */ +/* return value : */ +/* - number of heading zeros(MSB excluded. Ex: 0x0080 00000 returns 7) */ +/* */ +/*****************************************************************************/ +static inline uint16_t countLeadingZeros(word32_t x) +{ + if (x==0) return 31; + uint16_t leadingZeros = 0; + while (x<(word32_t)0x40000000) { + leadingZeros++; + x <<=1; + } + return leadingZeros; +} + +/*** gain related functions ***/ +/*****************************************************************************/ +/* MACodeGainPrediction : spec 3.9.1 */ +/* parameters: */ +/* -(i) previousGainPredictionError: qU(m) in eq69 4 values in Q10 */ +/* -(i) fixedCodebookVector: the current subframe fixed codebook vector */ +/* 40 values in Q1.13 */ +/* return value : */ +/* - predicted Fixed Codebook gain on 32 bits in Q16 range [3, 1830] */ +/* */ +/*****************************************************************************/ +word32_t MACodeGainPrediction(word16_t *previousGainPredictionError, word16_t *fixedCodebookVector); + +/*****************************************************************************/ +/* computeGainPredictionError : apply eq72 to compute current fixed Codebook */ +/* gain prediction error and store the result in the adhoc array */ +/* parameters : */ +/* -(i) fixedCodebookGainCorrectionFactor: gamma in eq72 in Q3.12 */ +/* -(i/o) previousGainPredictionError: array to be updated in Q10 */ +/* */ +/*****************************************************************************/ +void computeGainPredictionError(word16_t fixedCodebookGainCorrectionFactor, word16_t *previousGainPredictionError); + +/*** bitStream to parameters Array conversions functions ***/ +/* Note: these functions are in utils.c because used by test source code too */ + +/*****************************************************************************/ +/* parametersArray2BitStream : convert array of parameters to bitStream */ +/* according to spec 4 - Table 8 and following mapping of values */ +/* 0 -> L0 (1 bit) */ +/* 1 -> L1 (7 bits) */ +/* 2 -> L2 (5 bits) */ +/* 3 -> L3 (5 bits) */ +/* 4 -> P1 (8 bit) */ +/* 5 -> P0 (1 bits) */ +/* 6 -> C1 (13 bits) */ +/* 7 -> S1 (4 bits) */ +/* 8 -> GA1(3 bits) */ +/* 9 -> GB1(4 bits) */ +/* 10 -> P2 (5 bits) */ +/* 11 -> C2 (13 bits) */ +/* 12 -> S2 (4 bits) */ +/* 13 -> GA2(3 bits) */ +/* 14 -> GB2(4 bits) */ +/* parameters: */ +/* -(i) parameters : 16 values parameters array */ +/* -(o) bitStream : the 16 values streamed on 80 bits in a */ +/* 10*8bits values array */ +/* */ +/*****************************************************************************/ +void parametersArray2BitStream(uint16_t parameters[], uint8_t bitStream[]); + +/*****************************************************************************/ +/* parametersArray2BitStream : convert bitStream to an array of parameters */ +/* reverse operation of previous funtion */ +/* parameters: */ +/* -(i) bitStream : the 16 values streamed on 80 bits in a */ +/* 10*8bits values array */ +/* -(o) parameters : 16 values parameters array */ +/* */ +/*****************************************************************************/ +void parametersBitStream2Array(uint8_t bitStream[], uint16_t parameters[]); +#endif /* ifndef UTILS_H */ diff --git a/libbcg729.pc.in b/libbcg729.pc.in new file mode 100644 index 0000000..8f1115d --- /dev/null +++ b/libbcg729.pc.in @@ -0,0 +1,10 @@ +# This is a comment +prefix=@prefix@ +exec_prefix=@exec_prefix@ +includedir=@includedir@ + +Name: libbcg729 +Description: Implement the ITU G729 speech codec. +Version: @PACKAGE_VERSION@ +Libs: -L@libdir@ -lbcg729 +Cflags: -I@includedir@ diff --git a/msbcg729/Makefile.am b/msbcg729/Makefile.am new file mode 100644 index 0000000..ea76ca9 --- /dev/null +++ b/msbcg729/Makefile.am @@ -0,0 +1,18 @@ + +pluginsdir = $(libdir)/mediastreamer/plugins + +plugins_LTLIBRARIES=libmsbcg729.la + +libmsbcg729_la_SOURCES=bcg729_dec.c bcg729_enc.c + + +libmsbcg729_la_LIBADD=\ + $(ORTP_LIBS) \ + $(MEDIASTREAMER_LIBS) \ + $(top_builddir)/src/libbcg729.la + +libmsbcg729_la_LDFLAGS=-module -no-undefined +INCLUDES = -I$(top_srcdir)/include +libmsbcg729_la_CFLAGS= $(ORTP_CFLAGS) $(MEDIASTREMER2_CFLAGS) + + diff --git a/msbcg729/bcg729_dec.c b/msbcg729/bcg729_dec.c new file mode 100644 index 0000000..30a6584 --- /dev/null +++ b/msbcg729/bcg729_dec.c @@ -0,0 +1,106 @@ +/* + bcg729_dec.c + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Jehan Monnier + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include "mediastreamer2/mscodecutils.h" +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/msticker.h" +#include "bcg729/decoder.h" + +/* signal and bitstream frame size in byte */ +#define SIGNAL_FRAME_SIZE 160 +#define BITSTREAM_FRAME_SIZE 10 + +/* decoder struct: context for decoder channel and concealment */ +struct bcg729Decoder_struct { + bcg729DecoderChannelContextStruct *decoderChannelContext; + MSConcealerContext *concealer; +}; + +static void filter_init(MSFilter *f){ + f->data = ms_new0(struct bcg729Decoder_struct,1); +} + +static void filter_preprocess(MSFilter *f){ + struct bcg729Decoder_struct* obj= (struct bcg729Decoder_struct*) f->data; + obj->decoderChannelContext = initBcg729DecoderChannel(); /* initialize bcg729 decoder, return channel context */ + obj->concealer = ms_concealer_context_new(UINT32_MAX); +} + +static void filter_process(MSFilter *f){ + struct bcg729Decoder_struct* obj= (struct bcg729Decoder_struct*) f->data; + mblk_t *inputMessage, *outputMessage; + + while((inputMessage=ms_queue_get(f->inputs[0]))) { + while(inputMessage->b_rptrb_wptr) { + outputMessage = allocb(SIGNAL_FRAME_SIZE,0); + bcg729Decoder(obj->decoderChannelContext, inputMessage->b_rptr, 0, (int16_t *)(outputMessage->b_wptr)); + outputMessage->b_wptr+=SIGNAL_FRAME_SIZE; + inputMessage->b_rptr+=BITSTREAM_FRAME_SIZE; + ms_queue_put(f->outputs[0],outputMessage); + ms_concealer_inc_sample_time(obj->concealer,f->ticker->time,10, 1); + } + freemsg(inputMessage); + } + + if (ms_concealer_context_is_concealement_required(obj->concealer, f->ticker->time)) { + outputMessage = allocb(SIGNAL_FRAME_SIZE,0); + bcg729Decoder(obj->decoderChannelContext, NULL, 1, (int16_t *)(outputMessage->b_wptr)); + outputMessage->b_wptr+=SIGNAL_FRAME_SIZE; + ms_queue_put(f->outputs[0],outputMessage); + ms_concealer_inc_sample_time(obj->concealer,f->ticker->time,10, 0); + } +} + +static void filter_postprocess(MSFilter *f){ + struct bcg729Decoder_struct* obj= (struct bcg729Decoder_struct*) f->data; + ms_concealer_context_destroy(obj->concealer); + closeBcg729DecoderChannel(obj->decoderChannelContext); +} + +static void filter_uninit(MSFilter *f){ + ms_free(f->data); +} + + +/*filter specific method*/ + +static MSFilterMethod filter_methods[]={ + { 0, NULL} +}; + + + +MSFilterDesc ms_bcg729_dec_desc={ + .id=MS_FILTER_PLUGIN_ID, /* from Allfilters.h*/ + .name="MSBCG729Dec", + .text="G729 decoder filter.", + .category=MS_FILTER_DECODER, + .enc_fmt="G729", + .ninputs=1, /*number of inputs*/ + .noutputs=1, /*number of outputs*/ + .init=filter_init, + .preprocess=filter_preprocess, + .process=filter_process, + .postprocess=filter_postprocess, + .uninit=filter_uninit, + .methods=filter_methods, + .flags=MS_FILTER_IS_PUMP +}; +MS_FILTER_DESC_EXPORT(ms_bcg729_dec_desc) diff --git a/msbcg729/bcg729_enc.c b/msbcg729/bcg729_enc.c new file mode 100644 index 0000000..070e389 --- /dev/null +++ b/msbcg729/bcg729_enc.c @@ -0,0 +1,148 @@ +/* + bcg729_enc.c + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Jehan Monnier + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/mscodecutils.h" +#include "bcg729/encoder.h" + +/*filter common method*/ +struct bcg729Encoder_struct { + bcg729EncoderChannelContextStruct *encoderChannelContext; + MSBufferizer *bufferizer; + unsigned char ptime; + unsigned char max_ptime; + uint32_t ts; +}; + +static void filter_init(MSFilter *f){ + f->data = ms_new0(struct bcg729Encoder_struct,1); + struct bcg729Encoder_struct* obj= (struct bcg729Encoder_struct*) f->data; + obj->ptime=20; + obj->max_ptime=100; +} + +static void filter_preprocess(MSFilter *f){ + struct bcg729Encoder_struct* obj= (struct bcg729Encoder_struct*) f->data; + + obj->encoderChannelContext = initBcg729EncoderChannel(); /* initialize bcg729 encoder, return context */ + obj->bufferizer=ms_bufferizer_new(); +} + +static void filter_process(MSFilter *f){ + struct bcg729Encoder_struct* obj= (struct bcg729Encoder_struct*) f->data; + mblk_t *inputMessage; + mblk_t *outputMessage=NULL; + uint8_t inputBuffer[160]; /* 2bytes per sample at 8000Hz -> 16 bytes per ms */ + uint8_t bufferIndex=0; + /* get all input data into a buffer */ + while((inputMessage=ms_queue_get(f->inputs[0]))!=NULL){ + ms_bufferizer_put(obj->bufferizer,inputMessage); + } + + /* process ptimes ms of data : (ptime in ms)/1000->ptime is seconds * 8000(sample rate) * 2(byte per sample) */ + while(ms_bufferizer_get_avail(obj->bufferizer)>=obj->ptime*16){ + outputMessage = allocb(obj->ptime,0); /* output bitStream is 80 bits long * number of samples */ + /* process buffer in 10 ms frames */ + for (bufferIndex=0; bufferIndexptime; bufferIndex+=10) { + ms_bufferizer_read(obj->bufferizer,inputBuffer,160); + bcg729Encoder(obj->encoderChannelContext, (int16_t *)inputBuffer, outputMessage->b_wptr); + outputMessage->b_wptr+=10; + + } + obj->ts+=obj->ptime*8; + mblk_set_timestamp_info(outputMessage,obj->ts); + ms_queue_put(f->outputs[0],outputMessage); + } + +} + +static void filter_postprocess(MSFilter *f){ + struct bcg729Encoder_struct* obj= (struct bcg729Encoder_struct*) f->data; + ms_bufferizer_destroy(obj->bufferizer); + closeBcg729EncoderChannel(obj->encoderChannelContext); +} + +static void filter_uninit(MSFilter *f){ + ms_free(f->data); +} + + +/*filter specific method*/ + +static int filter_add_fmtp(MSFilter *f, void *arg){ + char buf[64]; + struct bcg729Encoder_struct* obj= (struct bcg729Encoder_struct*) f->data; + const char *fmtp=(const char *)arg; + buf[0] ='\0'; + + if (fmtp_get_value(fmtp,"maxptime:",buf,sizeof(buf))){ + obj->max_ptime=atoi(buf); + if (obj->max_ptime <10 || obj->max_ptime >100 ) { + ms_warning("MSBCG729Enc: unknown value [%i] for maxptime, use default value (100) instead",obj->max_ptime); + obj->max_ptime=100; + } + ms_message("MSBCG729Enc: got maxptime=%i",obj->max_ptime); + } else if (fmtp_get_value(fmtp,"ptime",buf,sizeof(buf))){ + obj->ptime=atoi(buf); + if (obj->ptime > obj->max_ptime) { + obj->ptime=obj->max_ptime; + } else if (obj->ptime%10) { + //if the ptime is not a mulptiple of 10, go to the next multiple + obj->ptime = obj->ptime - obj->ptime%10 + 10; + } + + ms_message("MSBCG729Enc: got ptime=%i",obj->ptime); + } + return 0; +} + +static MSFilterMethod filter_methods[]={ + { MS_FILTER_ADD_FMTP , filter_add_fmtp }, + { 0, NULL} +}; + + + +MSFilterDesc ms_bcg729_enc_desc={ + .id=MS_FILTER_PLUGIN_ID, /* from Allfilters.h*/ + .name="MSBCG729Enc", + .text="G729 audio encoder filter.", + .category=MS_FILTER_ENCODER, + .enc_fmt="G729", + .ninputs=1, /*number of inputs*/ + .noutputs=1, /*number of outputs*/ + .init=filter_init, + .preprocess=filter_preprocess, + .process=filter_process, + .postprocess=filter_postprocess, + .uninit=filter_uninit, + .methods=filter_methods +}; +MS_FILTER_DESC_EXPORT(ms_bcg729_enc_desc) + +extern MSFilterDesc ms_bcg729_dec_desc; +#ifndef VERSION + #define VERSION "debug" +#endif +void libmsbcg729_init(){ + ms_filter_register(&ms_bcg729_enc_desc); + ms_filter_register(&ms_bcg729_dec_desc); + ms_message(" libmsbcg729 " VERSION " plugin loaded"); +} diff --git a/src/LP2LSPConversion.c b/src/LP2LSPConversion.c new file mode 100644 index 0000000..0e17548 --- /dev/null +++ b/src/LP2LSPConversion.c @@ -0,0 +1,162 @@ +/* + LP2LSPConversion.c + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include "typedef.h" +#include "codecParameters.h" +#include "basicOperationsMacros.h" +#include "utils.h" + +#include "LP2LSPConversion.h" + +/* local functions and codebook */ +word32_t ChebyshevPolynomial(word16_t x, word32_t f[]); /* return value in Q24 */ +static const word16_t cosW0pi[NB_COMPUTED_VALUES_CHEBYSHEV_POLYNOMIAL]; /* cos(w) from 0 to Pi in 50 steps */ + +/*****************************************************************************/ +/* LP2LSPConversion : Compute polynomials, find their roots as in spec A3.2.3*/ +/* parameters: */ +/* -(i) LPCoefficients[] : 10 coefficients in Q12 */ +/* -(o) LSPCoefficients[] : 10 coefficients in Q15 */ +/* */ +/* return value : */ +/* - boolean: 1 if all roots found, 0 if unable to compute 10 roots */ +/* */ +/*****************************************************************************/ +int LP2LSPConversion(word16_t LPCoefficients[], word16_t LSPCoefficients[]) +{ + uint8_t i; + + /*** Compute the polynomials coefficients according to spec 3.2.3 eq15 ***/ + word32_t f1[6]; + word32_t f2[6]; /* coefficients for polynomials F1 anf F2 in Q12 for computation, then converted in Q15 for the Chebyshev Polynomial function */ + f1[0] = ONE_IN_Q12; /* values 0 are not part of the output, they are just used for computation purpose */ + f2[0] = ONE_IN_Q12; + /* for (i = 0; i< 5; i++) { */ + /* f1[i+1] = a[i+1] + a[10-i] - f1[i]; */ + /* f2[i+1] = a[i+1] - a[10-i] + f2[i]; */ + /* } */ + for (i=0; i<5; i++) { + f1[i+1] = ADD32(LPCoefficients[i], SUB32(LPCoefficients[9-i], f1[i])); /* note: index on LPCoefficients are -1 respect to spec because the unused value 0 is not stored */ + f2[i+1] = ADD32(f2[i], SUB32(LPCoefficients[i], LPCoefficients[9-i])); /* note: index on LPCoefficients are -1 respect to spec because the unused value 0 is not stored */ + } + /* convert the coefficients from Q12 to Q15 to be used by the Chebyshev Polynomial function (f1/2[0] aren't used so they are not converted) */ + for (i=1; i<6; i++) { + f1[i] = SHL(f1[i], 3); + f2[i] = SHL(f2[i], 3); + } + + /*** Compute at each step(50 steps for the AnnexA version) the Chebyshev polynomial to find the 10 roots ***/ + /* start using f1 polynomials coefficients and altern with f2 after founding each root (spec 3.2.3 eq13 and eq14) */ + uint8_t numberOfRootFound = 0; /* used to check the final number of roots found and exit the loop on each polynomial computation when we have 10 roots */ + word32_t *polynomialCoefficients = f1; /* start with f1 coefficients */ + word32_t previousCx = ChebyshevPolynomial(cosW0pi[0], polynomialCoefficients); /* compute the first point and store it as the previous value for polynomial */ + word32_t Cx; /* value of Chebyshev Polynomial at current point in Q15 */ + + for (i=1; i0; k--) { /* at the end of loop execution we have b1 in bk1 and b2 in bk2 */ + bk = SUB32(ADD32(SHL(MULT16_32_Q15(x,bk1), 1), f[5-k]), bk2); /* bk = 2*x*bk1 − bk2 + f(5-k) all in Q15*/ + bk2 = bk1; + bk1 = bk; + } + + return SUB32(ADD32(MULT16_32_Q15(x,bk1), SHR(f[5],1)), bk2); /* C(x) = x*b1 - b2 + f(5)/2 */ +} + +/*****************************************************************************/ +/* */ +/* Codebook: */ +/* */ +/* x = cos(w) with w in [0,Pi] in 50 steps */ +/* */ +/*****************************************************************************/ +static const word16_t cosW0pi[NB_COMPUTED_VALUES_CHEBYSHEV_POLYNOMIAL] = { /* in Q15 */ + 32760, 32703, 32509, 32187, 31738, 31164, + 30466, 29649, 28714, 27666, 26509, 25248, + 23886, 22431, 20887, 19260, 17557, 15786, + 13951, 12062, 10125, 8149, 6140, 4106, + 2057, 0, -2057, -4106, -6140, -8149, + -10125, -12062, -13951, -15786, -17557, -19260, + -20887, -22431, -23886, -25248, -26509, -27666, + -28714, -29649, -30466, -31164, -31738, -32187, + -32509, -32703, -32760}; diff --git a/src/LPSynthesisFilter.c b/src/LPSynthesisFilter.c new file mode 100644 index 0000000..ea1b14d --- /dev/null +++ b/src/LPSynthesisFilter.c @@ -0,0 +1,49 @@ +/* + LPSynthesisFilter.c + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "typedef.h" +#include "codecParameters.h" +#include "basicOperationsMacros.h" + +/*****************************************************************************/ +/* LPSynthesisFilter : as decribed in spec 4.1.6 eq77 */ +/* parameters: */ +/* -(i) excitationVector: u(n), the excitation, 40 values in Q0 */ +/* -(i) LPCoefficients: 10 LP coefficients in Q12 */ +/* -(i/o) recontructedSpeech: 50 values in Q0 */ +/* [-NB_LSP_COEFF, -1] of previous values as input */ +/* [0, L_SUBFRAME[ as output */ +/* */ +/*****************************************************************************/ +void LPSynthesisFilter (word16_t *excitationVector, word16_t *LPCoefficients, word16_t *reconstructedSpeech) +{ + int i; + /* compute excitationVector[i] - Sum0-9(LPCoefficients[j]*reconstructedSpeech[i-j]) */ + for (i=0; ipreviousqLSF[i], previousqLSFInit, NB_LSP_COEFF*sizeof(word16_t)); + } + return; +} + +/*****************************************************************************/ +/* LSPQuantization : Convert LSP to LSF, Quantize LSF and find L parameters, */ +/* qLSF->qLSP as described in spec A3.2.4 */ +/* parameters: */ +/* -(i/o) encoderChannelContext : the channel context data */ +/* -(i) LSPCoefficients : 10 LSP coefficients in Q15 */ +/* -(i) qLSPCoefficients : 10 qLSP coefficients in Q15 */ +/* -(o) parameters : 4 parameters L0, L1, L2, L3 */ +/* */ +/*****************************************************************************/ +void LSPQuantization(bcg729EncoderChannelContextStruct *encoderChannelContext, word16_t LSPCoefficients[], word16_t qLSPCoefficients[], uint16_t parameters[]) +{ + int i,j; + + /*** compute LSF in Q2.13 : lsf = arcos(lsp) range [0, Pi[ spec 3.2.4 eq18 ***/ + word16_t LSF[NB_LSP_COEFF]; /* LSF coefficients in Q2.13 range [0, Pi[ */ + for (i=0; i0) { + weights[i] = ONE_IN_Q11; + } else { + weights[i] = (word16_t)SATURATE(ADD32(PSHR(MULT16_16(MULT16_16_Q13(weightsThreshold[i], weightsThreshold[i]), 10), 2), ONE_IN_Q11), MAXINT16); + } + } + weights[4] = MULT16_16_Q14(weights[4], ONE_POINT_2_IN_Q14); + weights[5] = MULT16_16_Q14(weights[5], ONE_POINT_2_IN_Q14); + + /*** compute the coefficients for the two MA Predictors ***/ + int L0; + word32_t weightedMeanSquareError[L0_RANGE]; + word16_t L1index[L0_RANGE]; + word16_t L2index[L0_RANGE]; + word16_t L3index[L0_RANGE]; + + for (L0=0; L0previousqLSF[j][i], MAPredictor[L0][j][i]); /* previousqLSF in Q2.13 and MAPredictor in Q0.15-> acc in Q2.28 */ + } + targetVector[i] = MULT16_16_Q12((word16_t)PSHR(acc, 15), invMAPredictorSum[L0][i]); /* acc->Q13 and invMAPredictorSum in Q12 -> targetVector in Q13 */ + } + + /* find closest match for predictionError (minimize mean square diff) in L1 codebook */ + word32_t meanSquareDiff = MAXINT32; + for (i=0; i l[i] - l^[i] = (wi - w^[i])/(1-SumMAPred[i]) but ITU code ignores this denominator */ + /* works on the first five coefficients only */ + meanSquareDiff = MAXINT32; + for (i=0; i result in Q13 */ + word16_t difftargetVectorL1L2 = SATURATE(MULT16_16_Q15(SUB32(SUB32(targetVector[j], L1[L1index[L0]][j]), L2L3[i][j]), MAPredictorSum[L0][j]), MAXINT16); /* targetVector, L1 and L2L3 in Q13 -> result in Q13 */ + acc = MAC16_16(acc, difftargetVectorL1L2, MULT16_16_Q11(difftargetVectorL1L2, weights[j])); /* weights in Q11, diff in Q13 */ + } + + if (acc l[i] - l^[i] = (wi - w^[i])/(1-SumMAPred[i]) but ITU code ignores this denominator */ + /* works on the first five coefficients only */ + meanSquareDiff = MAXINT32; + for (i=0; i result in Q13 */ + word16_t difftargetVectorL1L3 = SATURATE(MULT16_16_Q15(SUB32(SUB32(targetVector[j], L1[L1index[L0]][j]), L2L3[i][j]), MAPredictorSum[L0][j]), MAXINT16); /* targetVector, L1 and L2L3 in Q13 -> result in Q13 */ + acc = MAC16_16(acc, difftargetVectorL1L3, MULT16_16_Q11(difftargetVectorL1L3, weights[j])); /* weights in Q11, diff in Q13 */ + } + + if (accSUB16(quantizedVector[i],GAP1)) { + quantizedVector[i-1] = PSHR(SUB16(ADD16(quantizedVector[i], quantizedVector[i-1]), GAP1), 1); + quantizedVector[i] = PSHR(ADD16(ADD16(quantizedVector[i], quantizedVector[i-1]), GAP1), 1); + } + } + for (i=NB_LSP_COEFF/2+1; iSUB16(quantizedVector[i],GAP1)) { + quantizedVector[i-1] = PSHR(SUB16(ADD16(quantizedVector[i], quantizedVector[i-1]), GAP1), 1); + quantizedVector[i] = PSHR(ADD16(ADD16(quantizedVector[i], quantizedVector[i-1]), GAP1), 1); + } + } + + /* rearrange the whole quantizedVector with a distance of 0.0006 */ + for (i=1; iSUB16(quantizedVector[i],GAP2)) { + quantizedVector[i-1] = PSHR(SUB16(ADD16(quantizedVector[i], quantizedVector[i-1]), GAP2), 1); + quantizedVector[i] = PSHR(ADD16(ADD16(quantizedVector[i], quantizedVector[i-1]), GAP2), 1); + } + } + + /* compute the weighted mean square distance using the final quantized vector according to eq21 */ + weightedMeanSquareError[L0]=0; + for (i=0; i result in Q13 */ + weightedMeanSquareError[L0] = MAC16_16(weightedMeanSquareError[L0], difftargetVectorQuantizedVector, MULT16_16_Q11(difftargetVectorQuantizedVector, weights[i])); /* weights in Q11, diff in Q13 */ + } + } + + /* now select L0 and copy the selected coefficients to the output buffer */ + if (weightedMeanSquareError[0] Q28 */ + for (j=0; jpreviousqLSF[j][i]); + } + /* acc in Q2.28, shift back the acc to a Q2.13 with rounding */ + qLSF[i] = (word16_t)PSHR(acc, 15); /* qLSF in Q2.13 */ + } + + /* update the previousqLSF buffer with current quantizer output */ + for (i=MA_MAX_K-1; i>0; i--) { + memcpy(encoderChannelContext->previousqLSF[i], encoderChannelContext->previousqLSF[i-1], NB_LSP_COEFF*sizeof(word16_t)); + } + memcpy(encoderChannelContext->previousqLSF[0], quantizerOutput, NB_LSP_COEFF*sizeof(word16_t)); + + /*** qLSF stability check ***/ + insertionSort(qLSF, NB_LSP_COEFF); + + /* check for low limit on qLSF[0] */ + if (qLSF[1]qLSF_MAX) { + qLSF[NB_LSP_COEFF-1] = qLSF_MAX; + } + + /* convert qLSF to qLSP: qLSP = cos(qLSF) */ + for (i=0; i + +#include "adaptativeCodebookSearch.h" + +/*** local functions ***/ +void generateAdaptativeCodebookVector(word16_t excitationVector[], int16_t intPitchDelay, int16_t fracPitchDelay); + +/*****************************************************************************/ +/* adaptativeCodebookSearch: compute parameter P1 and P2 as in spec A.3.7 */ +/* compute also adaptative codebook vector as in spec 3.7.1 */ +/* parameters: */ +/* -(i/o) excitationVector: [-154,0[ previous excitation as input */ +/* Range [0,39[ */ +/* 40 words of LPResidualSignal as substitute for current */ +/* excitation (spec A.3.7) as input */ +/* 40 words of adaptative codebook vector in Q0 as output */ +/* Buffer in Q0 accessed in range [-154, 39] */ +/* -(i/o) intPitchDelayMin: low boundary for pitch delay search */ +/* -(i/o) intPitchDelayMax: low boundary for pitch delay search */ +/* Boundaries are updated during first subframe search */ +/* -(i) impulseResponse: 40 values as in spec A.3.5 in Q12 */ +/* -(i) targetSignal: 40 values as in spec A.3.6 in Q0 */ +/* */ +/* -(o) intPitchDelay: the integer pitch delay */ +/* -(o) fracPitchDelay: the fractionnal part of pitch delay */ +/* -(o) pitchDelayCodeword: P1 or P2 codeword as in spec 3.7.2 */ +/* -(o) adaptativeCodebookVector: 40 words of adaptative codebook vector*/ +/* as described in spec 3.7.1, in Q0. */ +/* -(i) subFrameIndex: 0 for the first subframe, 40 for the second */ +/* */ +/*****************************************************************************/ +void adaptativeCodebookSearch(word16_t excitationVector[], int16_t *intPitchDelayMin, int16_t *intPitchDelayMax, word16_t impulseResponse[], word16_t targetSignal[], + int16_t *intPitchDelay, int16_t *fracPitchDelay, uint16_t *pitchDelayCodeword, uint16_t subFrameIndex) +{ + int i,j; + + word32_t backwardFilteredTargetSignal[L_SUBFRAME]; + /* compute the backward Filtered Target Signal as specified in A.3.7: correlation of target signal and impulse response */ + correlateVectors(targetSignal, impulseResponse, backwardFilteredTargetSignal); /* targetSignal in Q0, impulseResponse in Q12 -> backwardFilteredTargetSignal in Q12 */ + + /* maximise the sum as in spec A.3.7, eq A.7 */ + word32_t correlationMax = MININT32; + for (i=*intPitchDelayMin; i<=*intPitchDelayMax; i++) { + word32_t correlation = 0; + for (j=0; jcorrelationMax) { + correlationMax=correlation; + *intPitchDelay = i; + } + } + + /* compute the adaptativeCodebookVector (with fracPitchDelay at 0) */ + /* output is in excitationVector[0,L_SUBRAME[ */ + generateAdaptativeCodebookVector(excitationVector, *intPitchDelay, 0); + + /* if we are at first subframe and intPitchDelay >= 85 -> do not compute fracPitchDelay, set it to 0 */ + *fracPitchDelay=0; + if (!(subFrameIndex==0 && *intPitchDelay>=85)) { + /* compute the fracPitchDelay*/ + word16_t adaptativeCodebookVector[L_SUBFRAME]; /* as the adaptativeCodebookVector is computed in the excitation vector, use this buffer to backup the one giving the highest numerator */ + /* search the fractionnal part to get the best correlation */ + /* we already have in excitationVector for fracPitchDelay = 0 the adaptativeCodebookVector (see specA.3.7) */ + correlationMax = 0; + for (i=0; icorrelationMax) { /* fractional part at -1 gives higher correlation */ + *fracPitchDelay=-1; + correlationMax = correlation; + /* backup the adaptativeCodebookVector */ + memcpy(adaptativeCodebookVector, excitationVector, L_SUBFRAME*sizeof(word16_t)); + } + + /* Fractionnal part = 1 */ + generateAdaptativeCodebookVector(excitationVector, *intPitchDelay, 1); + correlation=0; + for (i=0; icorrelationMax) { /* fractional part at -1 gives higher correlation */ + *fracPitchDelay=1; + } else { /* previously computed fractional part gives better result */ + /* restore the adaptativeCodebookVector*/ + memcpy(excitationVector, adaptativeCodebookVector, L_SUBFRAME*sizeof(word16_t)); + } + } + + /* compute the codeword and intPitchDelayMin/intPitchDelayMax if needed (first subframe only) */ + if (subFrameIndex==0) { /* first subframe */ + /* compute intPitchDelayMin/intPitchDelayMax as in spec A.3.7 */ + *intPitchDelayMin = *intPitchDelay - 5; + if (*intPitchDelayMin < 20) { + *intPitchDelayMin = 20; + } + *intPitchDelayMax = *intPitchDelayMin + 9; + if (*intPitchDelayMax > MAXIMUM_INT_PITCH_DELAY) { + *intPitchDelayMax = MAXIMUM_INT_PITCH_DELAY; + *intPitchDelayMin = MAXIMUM_INT_PITCH_DELAY - 9; + } + + /* compute the codeword as in spec 3.7.2 */ + if (*intPitchDelay<=85) { + *pitchDelayCodeword = 3*(*intPitchDelay) - 58 + *fracPitchDelay; + } else { + *pitchDelayCodeword = *intPitchDelay + 112; + } + } else { /* second subframe */ + /* compute the codeword as in spec 3.7.2 */ + *pitchDelayCodeword = 3*(*intPitchDelay-*intPitchDelayMin) + *fracPitchDelay +2; + } +} + +/*****************************************************************************/ +/* generateAdaptativeCodebookVector : according to spec 3.7.1 eq40: */ +/* generates the adaptative codebook vector by interpolation of past */ +/* excitation */ +/* Note : specA.3.7 mention that excitation vector in range [0,39[ being */ +/* unknown is replaced by LP Residual signal, the ITU code use this */ +/* buffer to store the adaptative codebok vector and then use it in case*/ +/* of intPitchDelay<40. */ +/* parameters : */ +/* -(i/o) excitationVector: in Q0 the past excitation vector accessed */ +/* [-154,0[. Range [0,39[ is the output in Q0 */ +/* -(i) intPitchDelay: the integer pitch delay used to access the past */ +/* excitation */ +/* -(i) fracPitchDelay: fractional part of the pitch delay: -1, 0 or 1 */ +/* */ +/*****************************************************************************/ +void generateAdaptativeCodebookVector(word16_t excitationVector[], int16_t intPitchDelay, int16_t fracPitchDelay) +{ + int n,i,j; + + /* fracPitchDelay is in range [-1, 1], convert it to [0,2] needed by eqA.8 */ + fracPitchDelay = -fracPitchDelay; + if (fracPitchDelay <0) { /* if fracPitchDelay is 1 -> pitchDelay of int+(1/3) -> int+1-(2/3)*/ + intPitchDelay++; + fracPitchDelay = 2; + } + + /**/ + word16_t *delayedExcitationVector = &(excitationVector[-intPitchDelay]); /* delayedExcitationVector is used to address the excitation vector at index -intPitchDelay (-k in eq40) */ + word16_t *b30Increased = &(b30[fracPitchDelay]); /* b30 increased points to b30[fracPitchDelay] : b30[t] in eq40. b30 in Q15 */ + word16_t *b30Decreased = &(b30[3-fracPitchDelay]); /* b30 decreased points to b30[-fracPitchDelay] : b30[3-t] in eq40. b30 in Q15 */ + + + for (n=0; n return 0 */ + /* this test covers the case of yy(denominator)==0 because if yy==0 then all y==0 and thus xy==0 */ + return 0; + } + + /* output shall be in Q14 */ + word32_t gain = DIV64(SHL64(*gainQuantizationXy,14),*gainQuantizationYy); /* gain in Q14 */ + + /* check if it is not above 1.2 */ + if (gain>ONE_POINT_2_IN_Q14) { + gain = ONE_POINT_2_IN_Q14; + } + + return (word16_t)gain; +} diff --git a/src/computeLP.c b/src/computeLP.c new file mode 100644 index 0000000..9a94ac1 --- /dev/null +++ b/src/computeLP.c @@ -0,0 +1,172 @@ +/* + computeLP.c + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include "typedef.h" +#include "codecParameters.h" +#include "basicOperationsMacros.h" +#include "codebooks.h" +#include "utils.h" + +#include "computeLP.h" + +/*****************************************************************************/ +/* computeLP : As described in spec 3.2.1 and 3.2.2 : Windowing, */ +/* Autocorrelation and Levinson-Durbin algorithm */ +/* parameters: */ +/* -(i) signal: 240 samples in Q0, the last 40 are from next frame */ +/* -(o) LPCoefficientsQ12: 10 LP coefficients in Q12 */ +/* */ +/*****************************************************************************/ +void computeLP(word16_t signal[], word16_t LPCoefficientsQ12[]) +{ + int i,j; + + /*********************************************************************/ + /* Compute the windowed signal according to spec 3.2.1 eq4 */ + /*********************************************************************/ + word16_t windowedSignal[L_LP_ANALYSIS_WINDOW]; + for (i=0; iMAXINT32) { + do { + acc64 = SHR(acc64,1); + rightShiftToNormalise++; + } while (acc64>MAXINT32); + autoCorrelationCoefficient[0] = acc64; + } else { + rightShiftToNormalise = -countLeadingZeros((word32_t)acc64); + autoCorrelationCoefficient[0] = SHL((word32_t)acc64, -rightShiftToNormalise); + } + + /* compute autoCorrelationCoefficient 1 to 10 */ + if (rightShiftToNormalise>0) { /* acc64 was not fitting on 32 bits so compute the other sum on 64 bits too */ + for (i=1; i 1) */ + /* sum in Q27 (sum can't be > 1 but intermediate accumulation can) */ + /* a in Q4.27 with full range possible */ + /* Note: during iteration, current a[i] is in Q31 (can't be >1) and is */ + /* set to Q27 at the end of current iteration */ + /* */ + /*********************************************************************************/ + word32_t previousIterationLPCoefficients[NB_LSP_COEFF+1]; /* to compute a[]*/ + word32_t LPCoefficients[NB_LSP_COEFF+1]; /* in Q4.27 */ + + word32_t sum = 0; /* in Q27 */ + word32_t E = 0; /* in Q31 */ + /* init */ + LPCoefficients[0] = ONE_IN_Q27; + LPCoefficients[1] = -DIV32_32_Q27(autoCorrelationCoefficient[1], autoCorrelationCoefficient[0]); /* result in Q27(but<1) */ + /* E = r0(1 - a[1]^2) in Q31 */ + E = MULT32_32_Q31(autoCorrelationCoefficient[0], SUB32(ONE_IN_Q31, MULT32_32_Q23(LPCoefficients[1], LPCoefficients[1]))); /* LPCoefficient[1] is in Q27, using a Q23 operation will result in a Q31 variable */ + + for (i=2; i result in Q27 -> sum in Q27 */ + } + sum = ADD32(SHL(sum, 4), autoCorrelationCoefficient[i]); /* set sum in Q31 and add r[0] */ + + /* a[i] = -sum/E */ + LPCoefficients[i] = -DIV32_32_Q31(sum,E); /* LPCoefficient of current iteration is in Q31 for now, it will be set to Q27 at the end of this iteration */ + + /* iterations j = 1..i-1 */ + /* a[j] += a[i]*a[i-j] */ + for (j=1; j acc in Q12 */ + } + LPResidualSignal[i] = (word16_t)SATURATE(PSHR(acc, 12), MAXINT16); /* shift back acc to Q0 and saturate it to avoid overflow when going back to 16 bits */ + } + /* compute residual signal for the second subframe: use the second part of qLPCoefficients */ + for (i=L_SUBFRAME; i acc in Q12 */ + } + LPResidualSignal[i] = (word16_t)SATURATE(PSHR(acc, 12), MAXINT16); /* shift back acc to Q0 and saturate it to avoid overflow when going back to 16 bits */ + } + + /*** compute weightedqLPLowPassCoefficients and weightedInputSignal for first subframe ***/ + /* spec A3.3.3 a' = weightedqLPLowPassCoefficients[i] = weightedqLP[i] - 0.7*weightedqLP[i-1] */ + word16_t weightedqLPLowPassCoefficients[NB_LSP_COEFF]; /* in Q12 */ + weightedqLPLowPassCoefficients[0] = SUB16(weightedqLPCoefficients[0],O7_IN_Q12); /* weightedqLP[-1] = 1 -> weightedqLPLowPassCoefficients[0] = weightedqLPCoefficients[0] - 0.7 */ + for (i=1; i weightedqLPLowPassCoefficients[0] = weightedqLPCoefficients[0] - 0.7 */ + for (i=1; ipreviousIntPitchDelay = 60; +} + + + +/*****************************************************************************/ +/* decodeAdaptativeCodeVector : as in spec 4.1.3 */ +/* parameters: */ +/* -(i/o) decoderChannelContext : the channel context data */ +/* -(i) subFrameIndex : 0 or 40 for subframe 1 or subframe 2 */ +/* -(i) adaptativeCodebookIndex : parameter P1 or P2 */ +/* -(i) parityFlag : based on P1 parity flag : set if parity error */ +/* -(i) frameErasureFlag : set in case of frame erasure */ +/* -(i/o) intPitchDelay : the integer part of Pitch Delay. Computed from*/ +/* P1 on subframe 1. On Subframe 2, contains the intPitchDelay */ +/* computed on Subframe 1. */ +/* -(i/o) excitationVector : in Q0 excitation accessed from */ +/* [-MAXIMUM_INT_PITCH_DELAY(143), -1] as input */ +/* and [0, L_SUBFRAME[ as output to store the adaptative */ +/* codebook vector */ +/* */ +/*****************************************************************************/ +void decodeAdaptativeCodeVector(bcg729DecoderChannelContextStruct *decoderChannelContext, int subFrameIndex, uint16_t adaptativeCodebookIndex, uint8_t parityFlag, uint8_t frameErasureFlag, + int16_t *intPitchDelay, word16_t *excitationVector) +{ + int16_t fracPitchDelay; + /*** Compute the Pitch Delay from the Codebook index ***/ + /* fracPitchDelay is computed in the range -1,0,1 */ + if (subFrameIndex == 0 ) { /* first subframe */ + if (parityFlag|frameErasureFlag) { /* there is an error (either parity or frame erased) */ + *intPitchDelay = decoderChannelContext->previousIntPitchDelay; /* set the integer part of Pitch Delay to the last second subframe Pitch Delay computed spec: 4.1.2 */ + /* Note: unable to find anything regarding this part in the spec, just copied it from the ITU source code */ + fracPitchDelay = 0; + decoderChannelContext->previousIntPitchDelay++; + if (decoderChannelContext->previousIntPitchDelay>MAXIMUM_INT_PITCH_DELAY) decoderChannelContext->previousIntPitchDelay=MAXIMUM_INT_PITCH_DELAY; + } else { /* parity and frameErasure flags are off, do the normal computation (doc 4.1.3) */ + if (adaptativeCodebookIndex<197) { + /* *intPitchDelay = (P1 + 2 )/ 3 + 19 */ + *intPitchDelay = ADD16(MULT16_16_Q15(ADD16(adaptativeCodebookIndex,2), 10923), 19); /* MULT in Q15: 1/3 in Q15: 10923 */ + /* fracPitchDelay = P1 − 3*intPitchDelay + 58 : fracPitchDelay in -1, 0, 1 */ + fracPitchDelay = ADD16(SUB16(adaptativeCodebookIndex, MULT16_16(*intPitchDelay, 3)), 58); + } else {/* adaptativeCodebookIndex>= 197 */ + *intPitchDelay = SUB16(adaptativeCodebookIndex, 112); + fracPitchDelay = 0; + } + + /* backup the intPitchDelay */ + decoderChannelContext->previousIntPitchDelay = *intPitchDelay; + } + } else { /* second subframe */ + if (frameErasureFlag) { /* there is an error : frame erased, in case of parity error, it has been taken in account at first subframe */ + /* unable to find anything regarding this part in the spec, just copied it from the ITU source code */ + *intPitchDelay = decoderChannelContext->previousIntPitchDelay; + fracPitchDelay = 0; + decoderChannelContext->previousIntPitchDelay++; + if (decoderChannelContext->previousIntPitchDelay>MAXIMUM_INT_PITCH_DELAY) decoderChannelContext->previousIntPitchDelay=MAXIMUM_INT_PITCH_DELAY; + } else { /* frameErasure flags are off, do the normal computation (doc 4.1.3) */ + int16_t tMin = SUB16(*intPitchDelay,5); /* intPitchDelay contains the intPitch computed for subframe one */ + if (tMin<20) { + tMin = 20; + } + if (tMin>134) { + tMin = 134; + } + /* intPitchDelay = (P2 + 2 )/ 3 − 1 */ + *intPitchDelay = SUB16(MULT16_16_Q15(ADD16(adaptativeCodebookIndex, 2), 10923), 1); + /* fracPitchDelay = P2 − 2 − 3((P 2 + 2 )/ 3 − 1) */ + fracPitchDelay = SUB16(SUB16(adaptativeCodebookIndex, MULT16_16(*intPitchDelay, 3)), 2); + /* *intPitchDelay = (P2 + 2 )/ 3 − 1 + tMin */ + *intPitchDelay = ADD16(*intPitchDelay,tMin); + + /* backup the intPitchDelay */ + decoderChannelContext->previousIntPitchDelay = *intPitchDelay; + } + } + + + /* now compute the adaptative codebook vector using the pitch delay we just get and the past excitation vector */ + /* from spec 4.1.3 and 3.7.1 */ + /* shall compute v(n ) = ∑ u (n - k + i )b30 (t + 3i ) + ∑ u (n - k + 1 + i )b30 (3 - t + 3i ) for i=0,...,9 and n = 0,...,39 (t in 0, 1, 2) */ + /* with k = intPitchDelay and t = fracPitchDelay wich must be converted from range -1,0,1 to 0,1,2 */ + /* u the past excitation vector */ + /* v the adaptative codebook vector */ + /* b30 an interpolation filter */ + + word16_t *excitationVectorMinusK; /* pointer to u(-k) */ + + /* scale fracPichDelay from -1,0.1 to 0,1,2 */ + if (fracPitchDelay==1) { + excitationVectorMinusK = &(excitationVector[-(*intPitchDelay+1)]); /* fracPitchDelay being positive -> increase by one the integer part and set to 2 the fractional part : -(k+1/3) -> -(k+1)+2/3 */ + fracPitchDelay = 2; + } else { + fracPitchDelay = -fracPitchDelay; /* 0 unchanged, -1 -> +1 */ + excitationVectorMinusK = &(excitationVector[-(*intPitchDelay)]); /* -(k-1/3) -> -k+1/3 or -(k) -> -k*/ + } + + int n; + for (n=0; npreviousGainPredictionError[0] = -14336; + decoderChannelContext->previousGainPredictionError[1] = -14336; + decoderChannelContext->previousGainPredictionError[2] = -14336; + decoderChannelContext->previousGainPredictionError[3] = -14336; +} + +/*****************************************************************************/ +/* decodeGains : decode adaptive and fixed codebooks gains as in spec 4.1.5 */ +/* parameters: */ +/* -(i/o) decoderChannelContext : the channel context data */ +/* -(i) GA : parameter GA: Gain Codebook Stage 1 (3 bits) */ +/* -(i) GB : paremeter GB: Gain Codebook Stage 2 (4 bits) */ +/* -(i) fixedCodebookVector: 40 values current fixed Codebook vector */ +/* in Q1.13. */ +/* -(i) frameErasureFlag : set in case of frame erasure */ +/* -(i/o) adaptativeCodebookGain : input previous/output current */ +/* subframe Pitch Gain in Q14 */ +/* -(i/o) fixedCodebookGain : input previous/output current Fixed */ +/* Codebook Gain in Q1 */ +/* */ +/*****************************************************************************/ +void decodeGains (bcg729DecoderChannelContextStruct *decoderChannelContext, uint16_t GA, uint16_t GB, word16_t *fixedCodebookVector, uint8_t frameErasureFlag, + word16_t *adaptativeCodebookGain, word16_t *fixedCodebookGain) +{ + /* check the erasure flag */ + if (frameErasureFlag != 0) { /* we have a frame erasure, proceed as described in spec 4.4.2 */ + /* adaptativeCodebookGain as in eq94 */ + if (*adaptativeCodebookGain < 16384) { /* last subframe gain < 1 in Q14 */ + *adaptativeCodebookGain = MULT16_16_Q15(*adaptativeCodebookGain, 29491 ); /* *0.9 in Q15 */ + } else { /* bound current subframe gain to 0.9 (14746 in Q14) */ + *adaptativeCodebookGain = 14746; + } + /* fixedCodebookGain as in eq93 */ + *fixedCodebookGain = MULT16_16_Q15(*fixedCodebookGain, 32113 ); /* *0.98 in Q15 */ + + /* And update the previousGainPredictionError according to spec 4.4.3 */ + int i; + word32_t currentGainPredictionError =0; + for (i=0; i<4; i++) { + currentGainPredictionError = ADD32(currentGainPredictionError, decoderChannelContext->previousGainPredictionError[i]); /* previousGainPredictionError in Q3.10-> Sum in Q5.10 (on 32 bits) */ + } + currentGainPredictionError = PSHR(currentGainPredictionError,2); /* /4 -> Q3.10 */ + + if (currentGainPredictionError < -10240) { /* final result is low bounded by -14, so check before doing -4 if it's over -10(-10240 in Q10) or not */ + currentGainPredictionError = -14336; /* set to -14 in Q10 */ + } else { /* substract 4 */ + currentGainPredictionError = SUB32(currentGainPredictionError,4096); /* in Q10 */ + } + + /* shift the array and insert the current Prediction Error */ + decoderChannelContext->previousGainPredictionError[3] = decoderChannelContext->previousGainPredictionError[2]; + decoderChannelContext->previousGainPredictionError[2] = decoderChannelContext->previousGainPredictionError[1]; + decoderChannelContext->previousGainPredictionError[1] = decoderChannelContext->previousGainPredictionError[0]; + decoderChannelContext->previousGainPredictionError[0] = (word16_t)currentGainPredictionError; + + return; + } + + /* First recover the GA and GB real index from their mapping tables(spec 3.9.3) */ + GA = reverseIndexMappingGA[GA]; + GB = reverseIndexMappingGB[GB]; + + /* Compute the adaptativeCodebookGain from the tables according to eq73 in spec3.9.2 */ + /* adaptativeCodebookGain = GACodebook[GA][0] + GBCodebook[GB][0] */ + *adaptativeCodebookGain = ADD16(GACodebook[GA][0], GBCodebook[GB][0]); /* result in Q1.14 */ + + /* Fixed Codebook: MA code-gain prediction */ + word32_t predictedFixedCodebookGain = MACodeGainPrediction(decoderChannelContext->previousGainPredictionError, fixedCodebookVector); /* predictedFixedCodebookGain on 32 bits in Q11.16 */ + + /* get fixed codebook gain correction factor(gama) from the codebooks GA and GB according to eq74 */ + word16_t fixedCodebookGainCorrectionFactor = ADD16(GACodebook[GA][1], GBCodebook[GB][1]); /* result in Q3.12 (range [0.185, 5.05])*/ + + /* compute fixedCodebookGain according to eq74 */ + *fixedCodebookGain = (word16_t)PSHR(MULT16_32_Q12(fixedCodebookGainCorrectionFactor, predictedFixedCodebookGain), 15); /* Q11.16*Q3.12 -> Q14.16, shift by 15 to get a Q14.1 which fits on 16 bits */ + + /* use eq72 to compute current prediction error in order to update the previousGainPredictionError array */ + computeGainPredictionError(fixedCodebookGainCorrectionFactor, decoderChannelContext->previousGainPredictionError); +} diff --git a/src/decodeLSP.c b/src/decodeLSP.c new file mode 100644 index 0000000..4450592 --- /dev/null +++ b/src/decodeLSP.c @@ -0,0 +1,166 @@ +/* + decodeLSP.c + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "typedef.h" +#include "codecParameters.h" +#include "basicOperationsMacros.h" +#include "codebooks.h" +#include "utils.h" +#include "g729FixedPointMath.h" + +/* define the initialisation vector for qLSP */ +/* previous L Code Word initial values (Pi/11 steps) in Q2.13 */ +static word16_t previousLCodeWordInit[NB_LSP_COEFF] = {2339, 4679, 7018, 9358, 11698, 14037, 16377, 18717, 21056, 23396}; + +/* initialisations */ +void initDecodeLSP(bcg729DecoderChannelContextStruct *decoderChannelContext) +{ + int i,j; + /* init the previousLCodeWord buffer according to doc 3.2.4 -> pi/11 steps */ + for (i=0; ipreviousLCodeWord[i][j] = previousLCodeWordInit[j]; + } + } + + /* init the last valid values just to avoid problem in case the first frame is a lost one */ + decoderChannelContext->lastValidL0 = 0; + for (j=0; jlastqLSF[j] = previousLCodeWordInit[j]; + } +} + +/*****************************************************************************/ +/* decodeLSP : decode LSP coefficients as in spec 4.1.1/3.2.4 */ +/* parameters: */ +/* -(i/o) decoderChannelContext : the channel context data */ +/* -(i) L: 4 elements array containing L[0-3] the first and */ +/* second stage vector of LSP quantizer */ +/* -(i) frameErased : a boolean, when true, frame has been erased */ +/* -(o) qLSP: 10 quantized LSP coefficients in Q15 in range [-1,+1[ */ +/* */ +/*****************************************************************************/ +void decodeLSP(bcg729DecoderChannelContextStruct *decoderChannelContext, uint16_t L[], word16_t qLSP[], uint8_t frameErased) +{ + int i,j; + word16_t currentqLSF[NB_LSP_COEFF]; /* buffer to the current qLSF in Q2.13 */ + + + if (frameErased == 0) { /* frame is ok, proceed according to 3.2.4 section of the doc */ + /*** doc 3.2.4 eq(19) ***/ + /* get the L codewords from the codebooks L1, L2 and L3 */ + /* for easier implementation, L2 and L3 5 dimensional codebooks have been stored in one 10 dimensional L2L3 codebook */ + /* get the 5 first coefficient from the L1 and L2 codebooks */ + /* Note : currentqLSF buffer contains L codewords and not qLSF */ + for (i=0; i acc will end up being in Q2.28*/ + /* Note : previousLCodeWord array containing the last 4 code words is updated during this phase */ + word32_t acc; /* Accumulator in Q2.28 */ + + for (i=0; i=0; j--) { + acc = MAC16_16(acc, MAPredictor[L[0]][j][i], decoderChannelContext->previousLCodeWord[j][i]); + decoderChannelContext->previousLCodeWord[j][i] = (j>0)?decoderChannelContext->previousLCodeWord[j-1][i]:currentqLSF[i]; /* update the previousqLCodeWord array: row[0] = current code word and row[j]=row[j-1] */ + } + /* acc in Q2.28, shift back the acc to a Q2.13 with rounding */ + currentqLSF[i] = (word16_t)PSHR(acc, 15); /* currentqLSF in Q2.13 */ + } + /* Note : currentqLSF buffer now contains qLSF */ + + /*** doc 3.2.4 qLSF stability ***/ + /* qLSF in Q2.13 as are qLSF_MIN and qLSF_MAX and MIN_qLSF_DISTANCE */ + + /* sort the currentqLSF array */ + insertionSort(currentqLSF, NB_LSP_COEFF); + + /* check for low limit on qLSF[0] */ + if (currentqLSF[1]qLSF_MAX) { + currentqLSF[NB_LSP_COEFF-1] = qLSF_MAX; + } + + /* backup the qLSF and L0 to restore them in case of frame erased */ + for (i=0; ilastqLSF[i] = currentqLSF[i]; + } + decoderChannelContext->lastValidL0 = L[0]; + + + } else { /* frame erased indicator is set, proceed according to section 4.4 of the specs */ + /* restore the qLSF of last valid frame */ + for (i=0; ilastqLSF[i]; + } + + word32_t acc; /* acc in Q2.28 */ + /* compute back the codewords from the qLSF and store them in the previousLCodeWord buffer */ + for (i=0; ilastqLSF[i],15); /* Q2.13 -> Q2.28 */ + for (j=0; jlastValidL0][j][i], decoderChannelContext->previousLCodeWord[j][i]); /* acc in Q2.28 - MAPredictor in Q0.15 * previousLCodeWord in Q2.13 -> acc in Q2.28 (because 1-Sum(MAPred) < 0.6) */ + } + acc = MULT16_32_Q12(invMAPredictorSum[decoderChannelContext->lastValidL0][i], acc); /* Q3.12*Q2.28 >>12 -> Q2.28 because invMAPredictor is 1/(1 - Sum(MAPred))*/ + + /* update the array of previoux Code Words */ + for (j=MA_MAX_K-1; j>=0; j--) { + /* acc in Q2.28, shift back the acc to a Q2.13 with rounding */ + decoderChannelContext->previousLCodeWord[j][i] = (j>0)?decoderChannelContext->previousLCodeWord[j-1][i]:(word16_t)PSHR(acc, 15); /* update the previousqLSF array: row[0] = computed code word and row[j]=row[j-1] */ + } + } + } + + /* convert qLSF to qLSP: qLSP = cos(qLSF) */ + for (i=0; i +#include + +#include "typedef.h" +#include "codecParameters.h" +#include "basicOperationsMacros.h" +#include "utils.h" + +#include "bcg729/decoder.h" +#include "decodeLSP.h" +#include "interpolateqLSP.h" +#include "qLSP2LP.h" +#include "decodeAdaptativeCodeVector.h" +#include "decodeFixedCodeVector.h" +#include "decodeGains.h" +#include "LPSynthesisFilter.h" +#include "postFilter.h" +#include "postProcessing.h" + +/* buffers allocation */ +static const word16_t previousqLSPInitialValues[NB_LSP_COEFF] = {30000, 26000, 21000, 15000, 8000, 0, -8000,-15000,-21000,-26000}; /* in Q0.15 the initials values for the previous qLSP buffer */ + +/* internal functions */ +uint16_t pseudoRandom(bcg729DecoderChannelContextStruct *decoderChannelContext); + +/*****************************************************************************/ +/* initBcg729DecoderChannel : create context structure and initialise it */ +/* return value : */ +/* - the decoder channel context data */ +/* */ +/*****************************************************************************/ +bcg729DecoderChannelContextStruct *initBcg729DecoderChannel() +{ + /* create the context structure */ + bcg729DecoderChannelContextStruct *decoderChannelContext = malloc(sizeof(bcg729DecoderChannelContextStruct)); + + /* intialise statics buffers and variables */ + memcpy(decoderChannelContext->previousqLSP, previousqLSPInitialValues, NB_LSP_COEFF*sizeof(word16_t)); /* initialise the previousqLSP buffer */ + memset(decoderChannelContext->excitationVector, 0, L_PAST_EXCITATION*sizeof(word16_t)); /* initialise the part of the excitationVector containing the past excitation */ + decoderChannelContext->boundedAdaptativeCodebookGain = BOUNDED_PITCH_GAIN_MIN; + decoderChannelContext->pseudoRandomSeed = 21845; /* initialise pseudo Random seed according to spec 4.4.4 */ + decoderChannelContext->adaptativeCodebookGain = 0; /* gains are initialised at 0 */ + decoderChannelContext->fixedCodebookGain = 0; + memset(decoderChannelContext->reconstructedSpeech, 0, NB_LSP_COEFF*sizeof(word16_t)); /* initialise to zero all the values used from previous frame to get the current frame reconstructed speech */ + + /* initialisation of the differents blocs which need to be initialised */ + initDecodeLSP(decoderChannelContext); + initDecodeAdaptativeCodeVector(decoderChannelContext); + initDecodeGains(decoderChannelContext); + initPostFilter(decoderChannelContext); + initPostProcessing(decoderChannelContext); + + return decoderChannelContext; +} + +/*****************************************************************************/ +/* closeBcg729DecoderChannel : free memory of context structure */ +/* parameters: */ +/* -(i) decoderChannelContext : the channel context data */ +/* */ +/*****************************************************************************/ +void closeBcg729DecoderChannel(bcg729DecoderChannelContextStruct *decoderChannelContext) +{ + free(decoderChannelContext); + return; +} + +/*****************************************************************************/ +/* bcg729Decoder : */ +/* parameters: */ +/* -(i) decoderChannelContext : the channel context data */ +/* -(i) bitStream : 15 parameters on 80 bits */ +/* -(i) frameErased: flag: true, frame has been erased */ +/* -(o) signal : a decoded frame 80 samples (16 bits PCM) */ +/* */ +/*****************************************************************************/ +void bcg729Decoder(bcg729DecoderChannelContextStruct *decoderChannelContext, uint8_t bitStream[], uint8_t frameErasureFlag, int16_t signal[]) +{ + int i; + uint16_t parameters[NB_PARAMETERS]; + + /*** parse the bitstream and get all parameter into an array as in spec 4 - Table 8 ***/ + /* parameters buffer mapping : */ + /* 0 -> L0 (1 bit) */ + /* 1 -> L1 (7 bits) */ + /* 2 -> L2 (5 bits) */ + /* 3 -> L3 (5 bits) */ + /* 4 -> P1 (8 bit) */ + /* 5 -> P0 (1 bits) */ + /* 6 -> C1 (13 bits) */ + /* 7 -> S1 (4 bits) */ + /* 8 -> GA1(3 bits) */ + /* 9 -> GB1(4 bits) */ + /* 10 -> P2 (5 bits) */ + /* 11 -> C2 (13 bits) */ + /* 12 -> S2 (4 bits) */ + /* 13 -> GA2(3 bits) */ + /* 14 -> GB2(4 bits) */ + if (bitStream!=NULL) { /* bitStream might be null in case of frameErased (which shall be set in the appropriated flag)*/ + parametersBitStream2Array(bitStream, parameters); + } else { /* avoid compiler complaining for non inizialazed use of variable */ + for (i=0; ipreviousqLSP, qLSP, interpolatedqLSP); + /* copy the currentqLSP to previousqLSP buffer */ + for (i=0; ipreviousqLSP[i] = qLSP[i]; + } + + /* call the qLSP2LP function for first subframe */ + qLSP2LP(interpolatedqLSP, LP); + /* call the qLSP2LP function for second subframe */ + qLSP2LP(qLSP, &(LP[NB_LSP_COEFF])); + + /* check the parity on the adaptativeCodebookIndexSubframe1(P1) with the received one (P0)*/ + uint8_t parityErrorFlag = (uint8_t)(computeParity(parameters[4]) ^ parameters[5]); + + /* loop over the two subframes */ + int subframeIndex; + int parametersIndex = 4; /* this is used to select the right parameter according to the subframe currently computed, start pointing to P1 */ + int LPCoefficientsIndex = 0; /* this is used to select the right LP Coefficients according to the subframe currently computed */ + for (subframeIndex=0; subframeIndexexcitationVector[L_PAST_EXCITATION + subframeIndex])); + if (subframeIndex==0) { /* at first subframe we have P0 between P1 and C1 */ + parametersIndex+=2; + } else { + parametersIndex++; + } + + /* in case of frame erasure we shall generate pseudoRandom signs and index for fixed code vector decoding according to spec 4.4.4 */ + if (frameErasureFlag) { + parameters[parametersIndex] = pseudoRandom(decoderChannelContext)&(uint16_t)0x1fff; /* signs are set to the 13 LSB of the first pseudoRandom number */ + parameters[parametersIndex+1] = pseudoRandom(decoderChannelContext)&(uint16_t)0x000f; /* signs are set to the 4 LSB of the second pseudoRandom number */ + } + + /* decode the fixed Code Vector */ + decodeFixedCodeVector(parameters[parametersIndex+1], parameters[parametersIndex], intPitchDelay, decoderChannelContext->boundedAdaptativeCodebookGain, fixedCodebookVector); + parametersIndex+=2; + + /* decode gains */ + decodeGains(decoderChannelContext, parameters[parametersIndex], parameters[parametersIndex+1], fixedCodebookVector, frameErasureFlag, + &(decoderChannelContext->adaptativeCodebookGain), &(decoderChannelContext->fixedCodebookGain)); + parametersIndex+=2; + + /* update bounded Adaptative Codebook Gain (in Q14) according to eq47 */ + decoderChannelContext->boundedAdaptativeCodebookGain = decoderChannelContext->adaptativeCodebookGain; + if (decoderChannelContext->boundedAdaptativeCodebookGain>BOUNDED_PITCH_GAIN_MAX) { + decoderChannelContext->boundedAdaptativeCodebookGain = BOUNDED_PITCH_GAIN_MAX; + } + if (decoderChannelContext->boundedAdaptativeCodebookGainboundedAdaptativeCodebookGain = BOUNDED_PITCH_GAIN_MIN; + } + + /* compute excitation vector according to eq75 */ + /* excitationVector = adaptative Codebook Vector * adaptativeCodebookGain + fixed Codebook Vector * fixedCodebookGain */ + /* the adaptative Codebook Vector is in the excitationVector buffer [L_PAST_EXCITATION + subframeIndex] */ + /* with adaptative Codebook Vector in Q0, adaptativeCodebookGain in Q14, fixed Codebook Vector in Q1.13 and fixedCodebookGain in Q14.1 -> result in Q14 on 32 bits */ + /* -> shift right 14 bits and store the value in Q0 in a 16 bits type */ + for (i=0; iexcitationVector[L_PAST_EXCITATION + subframeIndex + i] = (word16_t)(SATURATE(PSHR( + ADD32( + MULT16_16(decoderChannelContext->excitationVector[L_PAST_EXCITATION + subframeIndex + i], decoderChannelContext->adaptativeCodebookGain), + MULT16_16(fixedCodebookVector[i], decoderChannelContext->fixedCodebookGain) + ), 14), MAXINT16)); + } + + /* reconstruct speech using LP synthesis filter spec 4.1.6 eq77 */ + /* excitationVector in Q0, LP in Q12, recontructedSpeech in Q0 -> +NB_LSP_COEFF on the index of this one because the first NB_LSP_COEFF elements store the previous frame filter output */ + LPSynthesisFilter(&(decoderChannelContext->excitationVector[L_PAST_EXCITATION + subframeIndex]), &(LP[LPCoefficientsIndex]), &(decoderChannelContext->reconstructedSpeech[NB_LSP_COEFF+subframeIndex]) ); + + /* NOTE: ITU code check for overflow after LP Synthesis Filter computation and if it happened, divide excitation buffer by 2 and recompute the LP Synthesis Filter */ + /* here, possible overflows are managed directly inside the Filter by saturation at MAXINT16 on each result */ + + /* postFilter */ + postFilter(decoderChannelContext, &(LP[LPCoefficientsIndex]), /* select the LP coefficients for this subframe */ + &(decoderChannelContext->reconstructedSpeech[NB_LSP_COEFF+subframeIndex]), intPitchDelay, subframeIndex, postFilteredSignal); + + /* postProcessing */ + postProcessing(decoderChannelContext, postFilteredSignal); + + /* copy postProcessing Output to the signal output buffer */ + for (i=0; iexcitationVector, &(decoderChannelContext->excitationVector[L_FRAME]), L_PAST_EXCITATION*sizeof(word16_t)); + /* Copy the last 10 words of reconstructed Speech to the begining of the array for next frame computation */ + memcpy(decoderChannelContext->reconstructedSpeech, &(decoderChannelContext->reconstructedSpeech[L_FRAME]), NB_LSP_COEFF*sizeof(word16_t)); + + return; +} + + +/*****************************************************************************/ +/* pseudoRandom : generate pseudo random number as in spec 4.4.4 eq96 */ +/* parameters: */ +/* -(i) decoderChannelContext : the channel context data */ +/* return value : */ +/* - a unsigned 16 bits pseudo random number */ +/* */ +/*****************************************************************************/ +uint16_t pseudoRandom(bcg729DecoderChannelContextStruct *decoderChannelContext) +{ + /* pseudoRandomSeed is stored in an uint16_t var, we shall not worry about overflow here */ + /* pseudoRandomSeed*31821 + 13849; */ + return decoderChannelContext->pseudoRandomSeed = MAC16_16(13849, (decoderChannelContext->pseudoRandomSeed), 31821); +} diff --git a/src/encoder.c b/src/encoder.c new file mode 100644 index 0000000..ac7ae72 --- /dev/null +++ b/src/encoder.c @@ -0,0 +1,277 @@ +/* + encoder.c + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include +#include + +#include "typedef.h" +#include "codecParameters.h" +#include "basicOperationsMacros.h" +#include "utils.h" + +#include "bcg729/encoder.h" + +#include "interpolateqLSP.h" +#include "qLSP2LP.h" + +#include "preProcessing.h" +#include "computeLP.h" +#include "LP2LSPConversion.h" +#include "LSPQuantization.h" +#include "computeWeightedSpeech.h" +#include "findOpenLoopPitchDelay.h" +#include "adaptativeCodebookSearch.h" +#include "computeAdaptativeCodebookGain.h" +#include "fixedCodebookSearch.h" +#include "gainQuantization.h" + +/* buffers allocation */ +static const word16_t previousLSPInitialValues[NB_LSP_COEFF] = {30000, 26000, 21000, 15000, 8000, 0, -8000,-15000,-21000,-26000}; /* in Q0.15 the initials values for the previous LSP buffer */ + +/*****************************************************************************/ +/* initBcg729EncoderChannel : create context structure and initialise it */ +/* return value : */ +/* - the encoder channel context data */ +/* */ +/*****************************************************************************/ +bcg729EncoderChannelContextStruct *initBcg729EncoderChannel() +{ + /* create the context structure */ + bcg729EncoderChannelContextStruct *encoderChannelContext = malloc(sizeof(bcg729EncoderChannelContextStruct)); + + /* initialise statics buffers and variables */ + memset(encoderChannelContext->signalBuffer, 0, (L_LP_ANALYSIS_WINDOW-L_FRAME)*sizeof(word16_t)); /* set to zero all the past signal */ + encoderChannelContext->signalLastInputFrame = &(encoderChannelContext->signalBuffer[L_LP_ANALYSIS_WINDOW-L_FRAME]); /* point to the last frame in the signal buffer */ + encoderChannelContext->signalCurrentFrame = &(encoderChannelContext->signalBuffer[L_LP_ANALYSIS_WINDOW-L_SUBFRAME-L_FRAME]); /* point to the current frame */ + memcpy(encoderChannelContext->previousLSPCoefficients, previousLSPInitialValues, NB_LSP_COEFF*sizeof(word16_t)); /* reset the previous quantized and unquantized LSP vector with the same value */ + memcpy(encoderChannelContext->previousqLSPCoefficients, previousLSPInitialValues, NB_LSP_COEFF*sizeof(word16_t)); + memset(encoderChannelContext->weightedInputSignal, 0, MAXIMUM_INT_PITCH_DELAY*sizeof(word16_t)); /* set to zero values of previous weighted signal */ + memset(encoderChannelContext->excitationVector, 0, L_PAST_EXCITATION*sizeof(word16_t)); /* set to zero values of previous excitation vector */ + memset(encoderChannelContext->targetSignal, 0, NB_LSP_COEFF*sizeof(word16_t)); /* set to zero values filter memory for the targetSignal computation */ + encoderChannelContext->lastQuantizedAdaptativeCodebookGain = O2_IN_Q14; /* quantized gain is initialized at his minimum value: 0.2 */ + + /* initialisation of the differents blocs which need to be initialised */ + initPreProcessing(encoderChannelContext); + initLSPQuantization(encoderChannelContext); + initGainQuantization(encoderChannelContext); + + return encoderChannelContext; +} + +/*****************************************************************************/ +/* closeBcg729EncoderChannel : free memory of context structure */ +/* parameters: */ +/* -(i) encoderChannelContext : the channel context data */ +/* */ +/*****************************************************************************/ +void closeBcg729EncoderChannel(bcg729EncoderChannelContextStruct *encoderChannelContext) +{ + free(encoderChannelContext); +} + +/*****************************************************************************/ +/* bcg729Encoder : */ +/* parameters: */ +/* -(i) encoderChannelContext : context for this encoder channel */ +/* -(i) inputFrame : 80 samples (16 bits PCM) */ +/* -(o) bitStream : The 15 parameters for a frame on 80 bits */ +/* on 80 bits (10 8bits words) */ +/* */ +/*****************************************************************************/ +void bcg729Encoder(bcg729EncoderChannelContextStruct *encoderChannelContext, int16_t inputFrame[], uint8_t bitStream[]) +{ + int i; + uint16_t parameters[NB_PARAMETERS]; /* the output parameters in an array */ + + /* internal buffers which we do not need to keep between calls */ + word16_t LPCoefficients[NB_LSP_COEFF]; /* the LP coefficients in Q3.12 */ + word16_t qLPCoefficients[2*NB_LSP_COEFF]; /* the quantized LP coefficients in Q3.12 computed from the qLSP one after interpolation: two sets, one for each subframe */ + word16_t weightedqLPCoefficients[2*NB_LSP_COEFF]; /* the qLP coefficients in Q3.12 weighted according to spec A3.3.3 */ + word16_t LSPCoefficients[NB_LSP_COEFF]; /* the LSP coefficients in Q15 */ + word16_t qLSPCoefficients[NB_LSP_COEFF]; /* the quantized LSP coefficients in Q15 */ + word16_t interpolatedqLSP[NB_LSP_COEFF]; /* the interpolated qLSP used for first subframe in Q15 */ + + + /*****************************************************************************************/ + /*** on frame basis : preProcessing, LP Analysis, Open-loop pitch search ***/ + preProcessing(encoderChannelContext, inputFrame, encoderChannelContext->signalLastInputFrame); /* output of the function in the signal buffer */ + + computeLP(encoderChannelContext->signalBuffer, LPCoefficients); /* use the whole signal Buffer for windowing and autocorrelation */ + /*** compute LSP: it might fail, get the previous one in this case ***/ + if (!LP2LSPConversion(LPCoefficients, LSPCoefficients)) { + /* unable to find the 10 roots repeat previous LSP */ + memcpy(LSPCoefficients, encoderChannelContext->previousLSPCoefficients, NB_LSP_COEFF*sizeof(word16_t)); + } + + /*** LSPQuantization and compute L0, L1, L2, L3: the first four parameters ***/ + LSPQuantization(encoderChannelContext, LSPCoefficients, qLSPCoefficients, parameters); + + /*** interpolate qLSP and convert to LP ***/ + interpolateqLSP(encoderChannelContext->previousqLSPCoefficients, qLSPCoefficients, interpolatedqLSP); + /* copy the currentqLSP to previousqLSP buffer */ + for (i=0; ipreviousqLSPCoefficients[i] = qLSPCoefficients[i]; + } + + /* first subframe */ + qLSP2LP(interpolatedqLSP, qLPCoefficients); + /* second subframe */ + qLSP2LP(qLSPCoefficients, &(qLPCoefficients[NB_LSP_COEFF])); + + /*** Compute the weighted Quantized LP Coefficients according to spec A3.3.3 ***/ + /* weightedqLPCoefficients[0] = qLPCoefficients[0]*Gamma^(i+1) (i=0..9) with Gamma = 0.75 in Q15 */ + weightedqLPCoefficients[0] = MULT16_16_P15(qLPCoefficients[0], GAMMA_E1); + weightedqLPCoefficients[1] = MULT16_16_P15(qLPCoefficients[1], GAMMA_E2); + weightedqLPCoefficients[2] = MULT16_16_P15(qLPCoefficients[2], GAMMA_E3); + weightedqLPCoefficients[3] = MULT16_16_P15(qLPCoefficients[3], GAMMA_E4); + weightedqLPCoefficients[4] = MULT16_16_P15(qLPCoefficients[4], GAMMA_E5); + weightedqLPCoefficients[5] = MULT16_16_P15(qLPCoefficients[5], GAMMA_E6); + weightedqLPCoefficients[6] = MULT16_16_P15(qLPCoefficients[6], GAMMA_E7); + weightedqLPCoefficients[7] = MULT16_16_P15(qLPCoefficients[7], GAMMA_E8); + weightedqLPCoefficients[8] = MULT16_16_P15(qLPCoefficients[8], GAMMA_E9); + weightedqLPCoefficients[9] = MULT16_16_P15(qLPCoefficients[9], GAMMA_E10); + weightedqLPCoefficients[10] = MULT16_16_P15(qLPCoefficients[10], GAMMA_E1); + weightedqLPCoefficients[11] = MULT16_16_P15(qLPCoefficients[11], GAMMA_E2); + weightedqLPCoefficients[12] = MULT16_16_P15(qLPCoefficients[12], GAMMA_E3); + weightedqLPCoefficients[13] = MULT16_16_P15(qLPCoefficients[13], GAMMA_E4); + weightedqLPCoefficients[14] = MULT16_16_P15(qLPCoefficients[14], GAMMA_E5); + weightedqLPCoefficients[15] = MULT16_16_P15(qLPCoefficients[15], GAMMA_E6); + weightedqLPCoefficients[16] = MULT16_16_P15(qLPCoefficients[16], GAMMA_E7); + weightedqLPCoefficients[17] = MULT16_16_P15(qLPCoefficients[17], GAMMA_E8); + weightedqLPCoefficients[18] = MULT16_16_P15(qLPCoefficients[18], GAMMA_E9); + weightedqLPCoefficients[19] = MULT16_16_P15(qLPCoefficients[19], GAMMA_E10); + + /*** Compute weighted signal according to spec A3.3.3, this function also set LPResidualSignal(entire frame values) as specified in eq A.3 in excitationVector[L_PAST_EXCITATION] ***/ + computeWeightedSpeech(encoderChannelContext->signalCurrentFrame, qLPCoefficients, weightedqLPCoefficients, &(encoderChannelContext->weightedInputSignal[MAXIMUM_INT_PITCH_DELAY]), &(encoderChannelContext->excitationVector[L_PAST_EXCITATION])); /* weightedInputSignal contains MAXIMUM_INT_PITCH_DELAY values from previous frame, points to current frame */ + + /*** find the open loop pitch delay ***/ + uint16_t openLoopPitchDelay = findOpenLoopPitchDelay(&(encoderChannelContext->weightedInputSignal[MAXIMUM_INT_PITCH_DELAY])); + + /* define boundaries for closed loop pitch delay search as specified in 3.7 */ + int16_t intPitchDelayMin = openLoopPitchDelay-3; + if (intPitchDelayMin < 20) { + intPitchDelayMin = 20; + } + int16_t intPitchDelayMax = intPitchDelayMin + 6; + if (intPitchDelayMax > MAXIMUM_INT_PITCH_DELAY) { + intPitchDelayMax = MAXIMUM_INT_PITCH_DELAY; + intPitchDelayMin = MAXIMUM_INT_PITCH_DELAY - 6; + } + + /*****************************************************************************************/ + /* loop over the two subframes: Closed-loop pitch search(adaptative codebook), fixed codebook, memory update */ + /* set index and buffers */ + int subframeIndex; + int LPCoefficientsIndex = 0; + int parametersIndex = 4; /* index to insert parameters in the parameters output array */ + word16_t impulseResponseInput[L_SUBFRAME]; /* input buffer for the impulse response computation: in Q12, 1 followed by all zeros see spec A3.5*/ + impulseResponseInput[0] = ONE_IN_Q12; + memset(&(impulseResponseInput[1]), 0, (L_SUBFRAME-1)*sizeof(word16_t)); + + for (subframeIndex=0; subframeIndexexcitationVector[L_PAST_EXCITATION+subframeIndex]), &(weightedqLPCoefficients[LPCoefficientsIndex]), &(encoderChannelContext->targetSignal[NB_LSP_COEFF])); + + /*** Adaptative Codebook search : compute the intPitchDelay, fracPitchDelay and associated parameter, compute also the adaptative codebook vector used to generate the excitation ***/ + /* after this call, the excitationVector[L_PAST_EXCITATION + subFrameIndex] contains the adaptative codebook vector as in spec 3.7.1 */ + int16_t intPitchDelay, fracPitchDelay; + adaptativeCodebookSearch(&(encoderChannelContext->excitationVector[L_PAST_EXCITATION + subframeIndex]), &intPitchDelayMin, &intPitchDelayMax, &(impulseResponseBuffer[NB_LSP_COEFF]), &(encoderChannelContext->targetSignal[NB_LSP_COEFF]), + &intPitchDelay, &fracPitchDelay, &(parameters[parametersIndex]), subframeIndex); + + /*** Compute adaptative codebook gain spec 3.7.3, result in Q14 ***/ + /* compute the filtered adaptative codebook vector spec 3.7.3 */ + /* this computation makes use of two partial results used for gainQuantization too (yy and xy in eq63), they are part of the function output */ + /* note spec 3.7.3 eq44 make use of convolution of impulseResponse and adaptative codebook vector to compute the filtered version */ + /* in the Annex A, the filter being simpler, it's faster to directly filter the the vector using the weightedqLPCoefficients */ + word16_t filteredAdaptativeCodebookVector[NB_LSP_COEFF+L_SUBFRAME]; /* in Q0, the first NB_LSP_COEFF words are set to zero and used by filter only */ + memset(filteredAdaptativeCodebookVector, 0, NB_LSP_COEFF*sizeof(word16_t)); + synthesisFilter(&(encoderChannelContext->excitationVector[L_PAST_EXCITATION + subframeIndex]), &(weightedqLPCoefficients[LPCoefficientsIndex]), &(filteredAdaptativeCodebookVector[NB_LSP_COEFF])); + + word64_t gainQuantizationXy, gainQuantizationYy; /* used to store in Q0 values reused in gain quantization */ + + word16_t adaptativeCodebookGain = computeAdaptativeCodebookGain(&(encoderChannelContext->targetSignal[NB_LSP_COEFF]), &(filteredAdaptativeCodebookVector[NB_LSP_COEFF]), &gainQuantizationXy, &gainQuantizationYy); /* gain in Q14 */ + + /* increase parameters index and compute P0 if needed */ + parametersIndex++; + if (subframeIndex==0) { /* first subframe compute P0, the parity bit of P1 */ + parameters[parametersIndex] = computeParity(parameters[parametersIndex-1]); + parametersIndex++; + } + + /*** Fixed Codebook Search : compute the parameters for fixed codebook and the regular and convolved version of the fixed codebook vector ***/ + word16_t fixedCodebookVector[L_SUBFRAME]; /* in Q13 */ + word16_t convolvedFixedCodebookVector[L_SUBFRAME]; /* in Q12 */ + fixedCodebookSearch(&(encoderChannelContext->targetSignal[NB_LSP_COEFF]), &(impulseResponseBuffer[NB_LSP_COEFF]), intPitchDelay, encoderChannelContext->lastQuantizedAdaptativeCodebookGain, &(filteredAdaptativeCodebookVector[NB_LSP_COEFF]), adaptativeCodebookGain, + &(parameters[parametersIndex]), &(parameters[parametersIndex+1]), fixedCodebookVector, convolvedFixedCodebookVector); + parametersIndex+=2; + + /*** gains Quantization ***/ + word16_t quantizedAdaptativeCodebookGain; /* in Q14 */ + word16_t quantizedFixedCodebookGain; /* in Q1 */ + gainQuantization(encoderChannelContext, &(encoderChannelContext->targetSignal[NB_LSP_COEFF]), &(filteredAdaptativeCodebookVector[NB_LSP_COEFF]), convolvedFixedCodebookVector, fixedCodebookVector, gainQuantizationXy, gainQuantizationYy, + &quantizedAdaptativeCodebookGain, &quantizedFixedCodebookGain, &(parameters[parametersIndex]), &(parameters[parametersIndex+1])); + parametersIndex+=2; + + /*** subframe basis indexes and memory updates ***/ + LPCoefficientsIndex+= NB_LSP_COEFF; + encoderChannelContext->lastQuantizedAdaptativeCodebookGain = quantizedAdaptativeCodebookGain; + if (encoderChannelContext->lastQuantizedAdaptativeCodebookGain>ONE_POINT_2_IN_Q14) encoderChannelContext->lastQuantizedAdaptativeCodebookGain = ONE_POINT_2_IN_Q14; + if (encoderChannelContext->lastQuantizedAdaptativeCodebookGainlastQuantizedAdaptativeCodebookGain = O2_IN_Q14; + /* compute excitation for current subframe as in spec A.3.10 */ + /* excitationVector[L_PAST_EXCITATION + subframeIndex] currently contains in Q0 the adaptative codebook vector, quantizedAdaptativeCodebookGain in Q14 */ + /* fixedCodebookVector in Q13, quantizedFixedCodebookGain in Q1 */ + for (i=0; iexcitationVector[L_PAST_EXCITATION + subframeIndex + i] = (word16_t)(SATURATE(PSHR(ADD32(MULT16_16(encoderChannelContext->excitationVector[L_PAST_EXCITATION + subframeIndex + i], quantizedAdaptativeCodebookGain), + MULT16_16(fixedCodebookVector[i], quantizedFixedCodebookGain)), 14), MAXINT16)); /* result in Q0 */ + } + + /* update targetSignal memory as in spec A.3.10 */ + quantizedAdaptativeCodebookGain = PSHR(quantizedAdaptativeCodebookGain, 1); /* quantizedAdaptativeCodebookGain in Q13 */ + for (i=0; itargetSignal[i] = (word16_t)(SATURATE(SUB32(encoderChannelContext->targetSignal[L_SUBFRAME+i], PSHR(acc, 13)), MAXINT16)); + + } + } + + /*****************************************************************************************/ + /*** frame basis memory updates ***/ + /* shift left by L_FRAME the signal buffer */ + memmove(encoderChannelContext->signalBuffer, &(encoderChannelContext->signalBuffer[L_FRAME]), (L_LP_ANALYSIS_WINDOW-L_FRAME)*sizeof(word16_t)); + /* update previousLSP coefficient buffer */ + memcpy(encoderChannelContext->previousLSPCoefficients, LSPCoefficients, NB_LSP_COEFF*sizeof(word16_t)); + memcpy(encoderChannelContext->previousqLSPCoefficients, qLSPCoefficients, NB_LSP_COEFF*sizeof(word16_t)); + /* shift left by L_FRAME the weightedInputSignal buffer */ + memmove(encoderChannelContext->weightedInputSignal, &(encoderChannelContext->weightedInputSignal[L_FRAME]), MAXIMUM_INT_PITCH_DELAY*sizeof(word16_t)); + /* shift left by L_FRAME the excitationVector */ + memmove(encoderChannelContext->excitationVector, &(encoderChannelContext->excitationVector[L_FRAME]), L_PAST_EXCITATION*sizeof(word16_t)); + + /*** Convert array of parameters into bitStream ***/ + parametersArray2BitStream(parameters, bitStream); + + return; +} diff --git a/src/findOpenLoopPitchDelay.c b/src/findOpenLoopPitchDelay.c new file mode 100644 index 0000000..5139802 --- /dev/null +++ b/src/findOpenLoopPitchDelay.c @@ -0,0 +1,198 @@ +/* + findOpenLoopPitchDelay.c + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include +#include + +#include "typedef.h" +#include "codecParameters.h" +#include "basicOperationsMacros.h" +#include "utils.h" +#include "g729FixedPointMath.h" + +/* local functions prototypes */ +/* compute eqA.4 from spec A3.4 on the given range and step(1 compute all the correlation in range, 2 only the even ones) return the maximum and set the index giving it in the first parameter */ +word32_t getCorrelationMax(uint16_t *index, word16_t inputSignal[], uint16_t rangeOpen, uint16_t rangeClose, uint16_t step); +/* compute eqA.4 from spec3.4 */ +word32_t getCorrelation(word16_t inputSignal[], uint16_t index); + +/*****************************************************************************/ +/* findOpenLoopPitchDelay : as specified in specA3.4 */ +/* paremeters: */ +/* -(i) weightedInputSignal: 223 values in Q0, buffer */ +/* accessed in range [-MAXIMUM_INT_PITCH_DELAY(143), L_FRAME(80)[ */ +/* return value: */ +/* - the openLoopIntegerPitchDelay in Q0 range [20, 143] */ +/* */ +/*****************************************************************************/ +uint16_t findOpenLoopPitchDelay(word16_t weightedInputSignal[]) +{ + int i; + /*** scale the signal to avoid overflows ***/ + word16_t scaledWeightedInputSignalBuffer[MAXIMUM_INT_PITCH_DELAY+L_FRAME]; /* this buffer might store the scaled version of input Signal, if scaling is not needed, it is not used */ + word16_t *scaledWeightedInputSignal; /* points to the begining of present frame either scaled or directly the input signal */ + + /* compute on 64 bits the autocorrelation on the input signal and if needed scale to have it on 32 bits */ + word64_t autocorrelation = 0; + for (i=-MAXIMUM_INT_PITCH_DELAY; iMAXINT32) { + scaledWeightedInputSignal = &(scaledWeightedInputSignalBuffer[MAXIMUM_INT_PITCH_DELAY]); + int overflowScale = PSHR(31-countLeadingZeros((word32_t)(autocorrelation>>31)),1); /* count number of bits needed over the 31 bits allowed and divide by 2 to get the right scaling for the signal */ + for (i=-MAXIMUM_INT_PITCH_DELAY; i80) { /* don't test value out of range [80, 143] */ + correlationMaxRange3Odd = getCorrelation(scaledWeightedInputSignal, indexRange3-1); + if (correlationMaxRange3Odd>correlationMaxRange3) { + correlationMaxRange3 = correlationMaxRange3Odd; + indexRange3 = indexRange3Even-1; + } + } + correlationMaxRange3Odd = getCorrelation(scaledWeightedInputSignal, indexRange3+1); + if (correlationMaxRange3Odd>correlationMaxRange3) { + correlationMaxRange3 = correlationMaxRange3Odd; + indexRange3 = indexRange3Even+1; + } + + /*** normalise the correlations ***/ + word32_t autoCorrelationRange1 = getCorrelation(&(scaledWeightedInputSignal[-indexRange1]), 0); + word32_t autoCorrelationRange2 = getCorrelation(&(scaledWeightedInputSignal[-indexRange2]), 0); + word32_t autoCorrelationRange3 = getCorrelation(&(scaledWeightedInputSignal[-indexRange3]), 0); + if (autoCorrelationRange1==0) { + autoCorrelationRange1 = 1; /* avoid division by 0 */ + } + if (autoCorrelationRange2==0) { + autoCorrelationRange2 = 1; /* avoid division by 0 */ + } + if (autoCorrelationRange3==0) { + autoCorrelationRange3 = 1; /* avoid division by 0 */ + } + + /* according to ITU code comments, the normalisedCorrelationMax values fit on 16 bits when in Q0, so keep them in Q8 on 32 bits shall not give any overflow */ + word32_t normalisedCorrelationMaxRange1 = MULT32_32_Q23(correlationMaxRange1, g729InvSqrt_Q0Q31(autoCorrelationRange1)); + word32_t normalisedCorrelationMaxRange2 = MULT32_32_Q23(correlationMaxRange2, g729InvSqrt_Q0Q31(autoCorrelationRange2)); + word32_t normalisedCorrelationMaxRange3 = MULT32_32_Q23(correlationMaxRange3, g729InvSqrt_Q0Q31(autoCorrelationRange3)); + + + + /*** Favouring the delays with the values in the lower range ***/ + /* not clearly documented in spec A3.4, algo from the ITU code */ + uint16_t indexMultiple = SHL(indexRange2,1); /* indexMultiple = 2*indexRange2 */ + if( abs(indexMultiple - indexRange3) < 5) { /* 2*indexRange2 - indexRange3 < 5 */ + normalisedCorrelationMaxRange2 = ADD32(normalisedCorrelationMaxRange2, SHR(normalisedCorrelationMaxRange3,2)); /* Max2 += Max3*0.25 */ + } + + if( abs(indexMultiple + indexRange2 - indexRange3) < 7) { /* 3*indexRange2 - indexRange3 < 5 */ + normalisedCorrelationMaxRange2 = ADD32(normalisedCorrelationMaxRange2, SHR(normalisedCorrelationMaxRange3,2)); /* Max2 += Max3*0.25 */ + } + + indexMultiple = SHL(indexRange1,1); /* indexMultiple = 2*indexRange1 */ + if( abs(indexMultiple - indexRange2) < 5) { /* 2*indexRange1 - indexRange2 < 5 */ + normalisedCorrelationMaxRange1 = MAC16_32_P15(normalisedCorrelationMaxRange1, O2_IN_Q15, normalisedCorrelationMaxRange2); /* Max1 += Max2*0.2 */ + } + + if( abs(indexMultiple + indexRange1 - indexRange2) < 7) { /* 3*indexRange1 - indexRange2 < 7 */ + normalisedCorrelationMaxRange1 = MAC16_32_P15(normalisedCorrelationMaxRange1, O2_IN_Q15, normalisedCorrelationMaxRange2); /* Max1 += Max2*0.2 */ + } + + /*** return the index corresponding to the greatest normalised Correlation */ + if (normalisedCorrelationMaxRange1correlationMax) { + *index = i; + correlationMax = correlation; + } + } + + return correlationMax; +} diff --git a/src/fixedCodebookSearch.c b/src/fixedCodebookSearch.c new file mode 100644 index 0000000..e415bf9 --- /dev/null +++ b/src/fixedCodebookSearch.c @@ -0,0 +1,397 @@ +/* + fixedCodebookSearch.c + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "typedef.h" +#include "codecParameters.h" +#include "basicOperationsMacros.h" +#include "utils.h" +#include + +#include "fixedCodebookSearch.h" + +/*** local functions ***/ +void computeImpulseResponseCorrelationMatrix(word16_t impulseResponse[], word16_t correlationSignal[], int correlationSignalSign[], word32_t Phi[L_SUBFRAME][L_SUBFRAME]); +void computePhiDiagonal(int j, word16_t impulseResponse[], word32_t Phi[L_SUBFRAME][L_SUBFRAME], uint16_t PhiScaling); + +/*****************************************************************************/ +/* fixedCodebookSearch: compute fixed codebook parameters (codeword and sign)*/ +/* compute also fixed codebook vector as in spec 3.8.1 */ +/* parameters: */ +/* -(i) targetSignal: 40 values as in spec A.3.6 in Q0 */ +/* -(i) impulseResponse: 40 values as in spec A.3.5 in Q12 */ +/* -(i) intPitchDelay: current integer pitch delay */ +/* -(i) lastQuantizedAdaptativeCodebookGain: previous subframe pitch */ +/* gain quantized in Q14 */ +/* -(i) filteredAdaptativeCodebookVector : 40 values in Q0 */ +/* -(i) adaptativeCodebookGain : in Q14 */ +/* -(o) fixedCodebookParameter */ +/* -(o) fixedCodebookPulsesSigns */ +/* -(o) fixedCodebookVector : 40 values as in spec 3.8, eq45 in Q13 */ +/* -(o) fixedCodebookVectorConvolved : 40 values as in spec 3.9, eq64 */ +/* in Q12. */ +/* */ +/*****************************************************************************/ +void fixedCodebookSearch(word16_t targetSignal[], word16_t impulseResponse[], int16_t intPitchDelay, word16_t lastQuantizedAdaptativeCodebookGain, word16_t filteredAdaptativeCodebookVector[], word16_t adaptativeCodebookGain, + uint16_t *fixedCodebookParameter, uint16_t *fixedCodebookPulsesSigns, word16_t fixedCodebookVector[], word16_t fixedCodebookVectorConvolved[]) +{ + int i,j,n; + /* compute the target signal for fixed codebook spec 3.8.1 eq50 : fixedCodebookTargetSignal[i] = targetSignal[i] - (adaptativeCodebookGain * filteredAdaptativeCodebookVector[i]) */ + word16_t fixedCodebookTargetSignal[L_SUBFRAME]; + for (i=0; i=0?correlationSignal32[n]:-correlationSignal32[n]; + if (abscCrrelationSignal32>correlationSignalMax) { + correlationSignalMax = abscCrrelationSignal32; + } + } + /* normalise on 13 bits */ + uint16_t correlationSignalMaxNorm = countLeadingZeros(correlationSignalMax); + if (correlationSignalMaxNorm<18) { /* if it doesn't already fit on 13 bits */ + for (i=0; i select m2 */ + if (correlationSignal[j]>correlationM2 && j!=firstM2) { + currentM2 = j; + correlationM2=correlationSignal[j]; + } + } + firstM2 = currentM2; /* to avoid selecting the same maximum at next iteration */ + + word32_t energyM2 = Phi[currentM2][currentM2]; /* compute the energy with terms of eq55 using m2 only: Phi'(m2,m2) */ + + /* with selected m2, test the 8 m3 possibilities for the current m3 track */ + for (j=mSwitch[mIndex][1]; j C^2/E > C^2max/Emax => Emax*C^2 > C^2max*E */ + if (MULT32_32(m3TrackEnergy,correlationM2M3Square) > MULT32_32(energyM2M3, m3TrackCorrelationSquare)) { + m3TrackCorrelationSquare = correlationM2M3Square; + m3TrackEnergy = energyM2M3; + correlationM2M3Max = correlationM2M3; + m3 = j; + m2 = currentM2; + } + } + } + energyM2M3Max = m3TrackEnergy; + + /* reset the current m3 track correlationSquare and energy */ + m3TrackCorrelationSquare = -1; + m3TrackEnergy = 1; + + for (i=mSwitch[mIndex][2]; i C^2/E > C^2max/Emax => Emax*C^2 > C^2max*E */ + if (MULT32_32(m3TrackEnergy,correlationM2M3M0M1Square) > MULT32_32(energyM2M3M0M1, m3TrackCorrelationSquare)) { + m3TrackCorrelationSquare = correlationM2M3M0M1Square; + m3TrackEnergy = energyM2M3M0M1; + m1 = j; + m0 = i; + } + } + } + + /* check with currently selected indexes if this one is better */ + if (MULT32_32(energyMax,m3TrackCorrelationSquare) > MULT32_32(m3TrackEnergy, correlationSquareMax)) { + correlationSquareMax = m3TrackCorrelationSquare; + energyMax = m3TrackEnergy; + if (mIndex==0) { + i0 = m0; + i1 = m1; + i2 = m2; + i3 = m3; + } else { + i0 = m3; + i1 = m0; + i2 = m1; + i3 = m2; + } + jx = m3Base - 3; /* needed for parameter computation apec 3.8.2 eq62 */ + } + + + } + mSwitch[0][1]++; mSwitch[1][0]++; /*increment the m3Base into the mSwitch */ + } + + /* compute the fixedCodebookVector */ + for (i=0; i>1) | /* as in spec 3.8.2 eq61 */ + (uint16_t)(((correlationSignalSign[i1]+1)>>1)<<1) | + (uint16_t)(((correlationSignalSign[i2]+1)>>1)<<2) | + (uint16_t)(((correlationSignalSign[i3]+1)>>1)<<3); + + /* compute the fixedCodebook vector convolved with impulse response spec 3.9 eq64 */ + /* this vector is used in gain quantization but computed here because it's faster doing it having directly the impulses positions */ + /* eq64 make use of fixedCodebook vector adapted by eq48, using the impulse position(and thus fixed codebook vector before the adaptation) but */ + /* the impulse response adapted as in eq49 gives the same output */ + /* reset the vector */ + for (i=0; i 0) { + for(i=i0, j=0; i 0) { + for(i=i1, j=0; i 0) { + for(i=i2, j=0; i 0) { + for(i=i3, j=0; i acc in Q24 */ + Phi[iComp][iComp] = SHR(acc,1); /* divide by 2: eq57*/ + } + + /* check for possible overflow: Phi will be summed 10 times, so max Phi (by construction Phi[0][0]*2 is the max of Phi-> 2*Phi[0][0]*10 must be < 0x7fff ffff -> Phi[0][0]< 0x06666666 - otherwise scale Phi)*/ + uint16_t PhiScaling = 0; + if (Phi[0][0]>0x6666666) { + PhiScaling = 3 - countLeadingZeros((Phi[0][0]<<1) + 0x3333333); /* complement 0xccccccc adding 0x3333333 to shift by one when max(2*Phi[0][0]) is in 0x0fffffff < max < 0xcccccc */ + for (i=0; i absolute value and get sign (and his inverse in an array) */ + int correlationSignalSignInv[L_SUBFRAME]; + for (i=0; i= 0) { + correlationSignalSign[i] = 1; + correlationSignalSignInv[i] = -1; + } else { /* correlationSignal < 0 */ + correlationSignalSign[i] = -1; + correlationSignalSignInv[i] = 1; + correlationSignal[i] = -correlationSignal[i]; + } + } + + /* modify the signs according to eq56 */ + for (i=0; i0) { /* is sign(correlationSignal[i]) is positive, use the correlationSignalSign otherwise the inverted one */ + signOfCorrelationSignalJ = correlationSignalSign; + } else { + signOfCorrelationSignalJ = correlationSignalSignInv; + } + for (j=0; j<=i; j++) { /* multiply by the selected sign the matrix element */ + /* Note : even the not needed and thus not computed elements are multiplicated... might found other way to do this sign stuff to be more efficient */ + Phi[i][j] = Phi[i][j] * signOfCorrelationSignalJ[j]; + } + } + + /* duplicate the usefull values to their symetric part to get easier acces to the matrix elements */ + for (i=0; i<8; i++) { + for (j=0; j<4; j++) { + int k; + int startIndex = 5*i+j; + for(k=0; k<=startIndex; k++) { + Phi[startIndex-k][L_SUBFRAME-1-k] = Phi[L_SUBFRAME-1-k][startIndex-k]; + } + } + } + return; +} + +/* compute a diagonal of Phi values: start from Phi(39,j) and step Phi(38, j-1) down to Phi(39-j, 0) */ +/* Phi(i,j) = Phi(i+1,j+1) + h(39-i)*h(39-j) */ +void computePhiDiagonal(int j, word16_t impulseResponse[], word32_t Phi[L_SUBFRAME][L_SUBFRAME], uint16_t PhiScaling) +{ + word32_t acc = 0; + int i=L_SUBFRAME -1; + int iComp = 0; + int jComp = L_SUBFRAME - 1 - j; + + if (PhiScaling == 0) { + for (; j>=0; j--, i--, jComp++, iComp++) { + acc = MAC16_16(acc, impulseResponse[iComp], impulseResponse[jComp]); + Phi[i][j] = acc; + } + } else { + for (; j>=0; j--, i--, jComp++, iComp++) { + acc = MAC16_16(acc, impulseResponse[iComp], impulseResponse[jComp]); + Phi[i][j] = SHR(acc,PhiScaling); + } + } +} diff --git a/src/gainQuantization.c b/src/gainQuantization.c new file mode 100644 index 0000000..5976fc7 --- /dev/null +++ b/src/gainQuantization.c @@ -0,0 +1,225 @@ +/* + gainQuantization.c + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "typedef.h" +#include "codecParameters.h" +#include "basicOperationsMacros.h" +#include "utils.h" +#include "codebooks.h" + +#include "gainQuantization.h" + +void initGainQuantization(bcg729EncoderChannelContextStruct *encoderChannelContext) +{ + /*init previousGainPredictionError to -14 in Q10 */ + encoderChannelContext->previousGainPredictionError[0] = -14336; + encoderChannelContext->previousGainPredictionError[1] = -14336; + encoderChannelContext->previousGainPredictionError[2] = -14336; + encoderChannelContext->previousGainPredictionError[3] = -14336; +} + +/*****************************************************************************/ +/* gainQuantization : compute quantized adaptative and fixed codebooks gains */ +/* spec 3.9 */ +/* parameters: */ +/* -(i/o) encoderChannelContext : the channel context data */ +/* -(i) targetSignal: 40 values in Q0, x in eq63 */ +/* -(i) filteredAdaptativeCodebookVector: 40 values in Q0, y in eq63 */ +/* -(i) convolvedFixedCodebookVector: 40 values in Q12, z in eq63 */ +/* -(i) fixedCodebookVector: 40 values in Q13 */ +/* -(i) xy in Q0 on 64 bits term of eq63 computed previously */ +/* -(i) yy in Q0 on 64 bits term of eq63 computed previously */ +/* -(o) quantizedAdaptativeCodebookGain : in Q14 */ +/* -(o) quantizedFixedCodebookGain : in Q1 */ +/* -(o) gainCodebookStage1 : GA parameter value (3 bits) */ +/* -(o) gainCodebookStage2 : GB parameter value (4 bits) */ +/* */ +/*****************************************************************************/ +void gainQuantization(bcg729EncoderChannelContextStruct *encoderChannelContext, word16_t targetSignal[], word16_t filteredAdaptativeCodebookVector[], word16_t convolvedFixedCodebookVector[], word16_t fixedCodebookVector[], word64_t xy64, word64_t yy64, + word16_t *quantizedAdaptativeCodebookGain, word16_t *quantizedFixedCodebookGain, uint16_t *gainCodebookStage1, uint16_t *gainCodebookStage2) +{ + int i,j; + + /*** compute spec 3.9 eq63 terms first on 64 bits and then scale them if needed to fit on 32 ***/ + /* Xy64 and Yy64 already computed during adaptativeCodebookGain computation */ + word64_t xz64=0, yz64=0, zz64=0; + for (i=0; i= 0)*/ + /* avoid division by zero */ + if (denominator==0) { /* consider it to be one */ + bestAdaptativeCodebookGain = (word32_t)(SHR64(MAC64(MULT32_32(zz, xy), -xz, yz), 15)); /* MAC in Q24 -> Q9 */ + bestFixedCodebookGain = (word32_t)(SHR64(MAC64(MULT32_32(yy, xz), -xy, yz), 10)); /* MAC in Q12 -> Q2 */ + } else { + /* bestAdaptativeCodebookGain in Q9 */ + word64_t numerator = MAC64(MULT32_32(zz, xy), -xz, yz); /* in Q24 */ + /* check if we can shift it by 9 without overflow as the bestAdaptativeCodebookGain in computed in Q9 */ + word32_t numeratorH = (word32_t)(SHR64(numerator,32)); + numeratorH = (numeratorH>0)?numeratorH:-numeratorH; + uint16_t numeratorNorm = countLeadingZeros(numeratorH); + if (numeratorNorm >= 9) { + bestAdaptativeCodebookGain = (word32_t)(DIV64(SHL64(numerator,9), denominator)); /* bestAdaptativeCodebookGain in Q9 */ + } else { + word64_t shiftedDenominator = SHR64(denominator, 9-numeratorNorm); + if (shiftedDenominator>0) { /* can't shift left by 9 the numerator, can we shift right by 9-numeratorNorm the denominator without hiting 0 */ + bestAdaptativeCodebookGain = (word32_t)(DIV64(SHL64(numerator, numeratorNorm),shiftedDenominator)); /* bestAdaptativeCodebookGain in Q9 */ + } else { + bestAdaptativeCodebookGain = SHL((word32_t)(DIV64(SHL64(numerator, numeratorNorm), denominator)), 9-numeratorNorm); /* shift left the division result to reach Q9 */ + } + } + + numerator = MAC64(MULT32_32(yy, xz), -xy, yz); /* in Q12 */ + /* check if we can shift it by 14(it's in Q12 and denominator in Q24) without overflow as the bestFixedCodebookGain in computed in Q2 */ + numeratorH = (word32_t)(SHR64(numerator,32)); + numeratorH = (numeratorH>0)?numeratorH:-numeratorH; + numeratorNorm = countLeadingZeros(numeratorH); + + if (numeratorNorm >= 14) { + bestFixedCodebookGain = (word32_t)(DIV64(SHL64(numerator,14), denominator)); + } else { + word64_t shiftedDenominator = SHR64(denominator, 14-numeratorNorm); /* bestFixedCodebookGain in Q14 */ + if (shiftedDenominator>0) { /* can't shift left by 9 the numerator, can we shift right by 9-numeratorNorm the denominator without hiting 0 */ + bestFixedCodebookGain = (word32_t)(DIV64(SHL64(numerator, numeratorNorm),shiftedDenominator)); /* bestFixedCodebookGain in Q14 */ + } else { + bestFixedCodebookGain = SHL((word32_t)(DIV64(SHL64(numerator, numeratorNorm), denominator)), 14-numeratorNorm); /* shift left the division result to reach Q14 */ + } + } + } + + /*** Compute the predicted gain as in spec 3.9.1 eq71 in Q6 ***/ + word16_t predictedFixedCodebookGain = (word16_t)(SHR32(MACodeGainPrediction(encoderChannelContext->previousGainPredictionError, fixedCodebookVector), 12)); /* in Q16 -> Q4 range [3,1830] */ + + /*** preselection spec 3.9.2 ***/ + /* Note: spec just says to select the best 50% of each vector, ITU code go through magical constant computation to select the begining of a continuous range */ + /* much more simple here : vector are ordened in growing order so just select 2 (4 for Gb) indexes before the first value to be superior to the best gain previously computed */ + uint16_t indexBaseGa=0; + uint16_t indexBaseGb=0; + + while (indexBaseGa<6 && bestFixedCodebookGain>(MULT16_16_Q14(GACodebook[indexBaseGa][1],predictedFixedCodebookGain))) { /* bestFixedCodebookGain> in Q2, GACodebook in Q12 *predictedFixedCodebookGain in Q4 -> Q16-14 */ + indexBaseGa++; + } + if (indexBaseGa>0) indexBaseGa--; + if (indexBaseGa>0) indexBaseGa--; + while (indexBaseGb<12 && bestAdaptativeCodebookGain>(SHR(GBCodebook[indexBaseGb][0],5))) { + indexBaseGb++; + } + if (indexBaseGb>0) indexBaseGb--; + if (indexBaseGb>0) indexBaseGb--; + if (indexBaseGb>0) indexBaseGb--; + if (indexBaseGb>0) indexBaseGb--; + + /*** test all possibilities of Ga and Gb indexes and select the best one ***/ + uint16_t indexGa=0, indexGb=0; + xy = -SHL(xy,1); /* xy term is always used with a -2 factor */ + xz = -SHL(xz,1); /* xz term is always used with a -2 factor */ + yz = SHL(yz,1); /* yz term is always used with a 2 factor */ + word64_t distanceMin = MAXINT64; + + for (i=0; i<4; i++) { + for (j=0; j<8; j++) { + /* compute gamma->gc and gp */ + word16_t gp = ADD16(GACodebook[i+indexBaseGa][0], GBCodebook[j+indexBaseGb][0]); /* result in Q14 */ + word16_t gamma = ADD16(GACodebook[i+indexBaseGa][1], GBCodebook[j+indexBaseGb][1]); /* result in Q3.12 (range [0.185, 5.05])*/ + word32_t gc = MULT16_16_Q14(gamma, predictedFixedCodebookGain); /* gamma in Q12, predictedFixedCodebookGain in Q4 -> Q16 -14 -> Q2 */ + + /* compute E as in eq63 (first term excluded) */ + word64_t acc = MULT32_32(MULT16_16(gp, gp), yy); /* acc = gp^2*yy gp in Q14, yy in Q0 -> acc in Q28 */ + acc = MAC64(acc, MULT16_16(gc, gc), zz); /* gc in Q2, zz in Q24 -> acc in Q28, note gc is on 32 bits but in a range making gc^2 fitting on 32 bits */ + acc = MAC64(acc, SHL32((word32_t)gp, 14), xy); /* gp in Q14 shifted to Q28, xy in Q0 -> acc in Q28 */ + acc = MAC64(acc, SHL32(gc, 14), xz); /* gc in Q2 shifted to Q16, xz in Q12 -> acc in Q28 */ + acc = MAC64(acc, MULT16_16(gp,gc), yz); /* gp in Q14, gc in Q2 yz in Q12 -> acc in Q28 */ + + if (accpreviousGainPredictionError); + + /* mapping of indexes */ + *gainCodebookStage1 = indexMappingGA[indexGa]; + *gainCodebookStage2 = indexMappingGB[indexGb]; + + return; +} diff --git a/src/interpolateqLSP.c b/src/interpolateqLSP.c new file mode 100644 index 0000000..742af9c --- /dev/null +++ b/src/interpolateqLSP.c @@ -0,0 +1,41 @@ +/* + interpolateqLSP.c + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "typedef.h" +#include "codecParameters.h" +#include "basicOperationsMacros.h" + +/*****************************************************************************/ +/* interpolateqLSP : interpolate previous and current qLSP according to */ +/* spec. 3.2.5 : interpolated = (current+previous)/2 */ +/* parameters: */ +/* -(i) previousqLSP : 10 values in Q0.15: the qLSP of previous frame */ +/* -(i) currentqLSP : 10 values in Q0.15: the qLSP of current frame */ +/* -(o) interpolatedqLSP : 10 values in Q0.15 : the interpolated qLSP */ +/* */ +/*****************************************************************************/ +void interpolateqLSP(word16_t previousqLSP[], word16_t currentqLSP[], word16_t interpolatedqLSP[]) +{ /* interpolate previous and current qLSP according to spec. 3.2.5 : interpolated = (current+previous)/2 */ + int i; + for (i=0; i + +#include "typedef.h" +#include "codecParameters.h" +#include "basicOperationsMacros.h" +#include "utils.h" +#include "g729FixedPointMath.h" + +/* init function */ +void initPostFilter(bcg729DecoderChannelContextStruct *decoderChannelContext) +{ + /* set to zero the residual signal memory */ + memset(decoderChannelContext->residualSignalBuffer, 0, MAXIMUM_INT_PITCH_DELAY*sizeof(word16_t)); + memset(decoderChannelContext->scaledResidualSignalBuffer, 0, MAXIMUM_INT_PITCH_DELAY*sizeof(word16_t)); + /* set to zero the one word of longTermFilteredResidualSignal needed as memory for tilt compensation filter */ + decoderChannelContext->longTermFilteredResidualSignalBuffer[0] = 0; + decoderChannelContext->longTermFilteredResidualSignal = &(decoderChannelContext->longTermFilteredResidualSignalBuffer[1]); /* init the pointer to the begining of longTermFilteredResidualSignal current subframe */ + /* intialise the shortTermFilteredResidualSignal filter memory and pointer*/ + memset(decoderChannelContext->shortTermFilteredResidualSignalBuffer, 0, NB_LSP_COEFF*sizeof(word16_t)); + decoderChannelContext->shortTermFilteredResidualSignal = &(decoderChannelContext->shortTermFilteredResidualSignalBuffer[NB_LSP_COEFF]); + /* initialise the previous Gain for adaptative gain control */ + decoderChannelContext->previousAdaptativeGain = 4096; /* 1 in Q12 */ +} + +/*****************************************************************************/ +/* postFilter: filter the reconstructed speech according to spec A.4.2 */ +/* parameters: */ +/* -(i/o) decoderChannelContext : the channel context data */ +/* -(i) LPCoefficients: 10 LP coeff for current subframe in Q12 */ +/* -(i) reconstructedSpeech: output of LP Synthesis, 50 values in Q0 */ +/* 10 values of previous subframe, accessed in range [-10, 39] */ +/* -(i) intPitchDelay: the integer part of Pitch Delay in Q0 */ +/* -(i) subframeIndex: 0 or L_SUBFRAME for subframe 0 or 1 */ +/* -(o) postFilteredSignal: 40 values in Q0 */ +/* */ +/*****************************************************************************/ +void postFilter(bcg729DecoderChannelContextStruct *decoderChannelContext, word16_t *LPCoefficients, word16_t *reconstructedSpeech, int16_t intPitchDelay, int subframeIndex, + word16_t *postFilteredSignal) +{ + int i,j; + + /********************************************************************/ + /* Long Term Post Filter */ + /********************************************************************/ + /*** Compute LPGammaN and LPGammaD coefficients : LPGamma[0] = LP[0]*Gamma^(i+1) (i=0..9) ***/ + word16_t LPGammaNCoefficients[NB_LSP_COEFF]; /* in Q12 */ + /* GAMMA_XX constants are in Q15 */ + LPGammaNCoefficients[0] = MULT16_16_P15(LPCoefficients[0], GAMMA_N1); + LPGammaNCoefficients[1] = MULT16_16_P15(LPCoefficients[1], GAMMA_N2); + LPGammaNCoefficients[2] = MULT16_16_P15(LPCoefficients[2], GAMMA_N3); + LPGammaNCoefficients[3] = MULT16_16_P15(LPCoefficients[3], GAMMA_N4); + LPGammaNCoefficients[4] = MULT16_16_P15(LPCoefficients[4], GAMMA_N5); + LPGammaNCoefficients[5] = MULT16_16_P15(LPCoefficients[5], GAMMA_N6); + LPGammaNCoefficients[6] = MULT16_16_P15(LPCoefficients[6], GAMMA_N7); + LPGammaNCoefficients[7] = MULT16_16_P15(LPCoefficients[7], GAMMA_N8); + LPGammaNCoefficients[8] = MULT16_16_P15(LPCoefficients[8], GAMMA_N9); + LPGammaNCoefficients[9] = MULT16_16_P15(LPCoefficients[9], GAMMA_N10); + + /*** Compute the residual signal as described in spec 4.2.1 eq79 ***/ + /* Compute also a scaled residual signal: shift right by 2 to avoid overflows on 32 bits when computing correlation and energy */ + + /* pointers to current subframe beginning */ + word16_t *residualSignal = &(decoderChannelContext->residualSignalBuffer[MAXIMUM_INT_PITCH_DELAY+subframeIndex]); + word16_t *scaledResidualSignal = &(decoderChannelContext->scaledResidualSignalBuffer[MAXIMUM_INT_PITCH_DELAY+subframeIndex]); + + for (i=0; i acc in Q12 */ + } + residualSignal[i] = (word16_t)SATURATE(PSHR(acc, 12), MAXINT16); /* shift back acc to Q0 and saturate it to avoid overflow when going back to 16 bits */ + scaledResidualSignal[i] = PSHR(residualSignal[i], 2); /* shift acc to Q-2 and saturate it to get the scaled version of the signal */ + } + + /*** Compute the maximum correlation on scaledResidualSignal delayed by intPitchDelay +/- 3 to get the best delay. Spec 4.2.1 eq80 ***/ + /* using a scaled(Q-2) signals gives correlation in Q-4. */ + word32_t correlationMax = (word32_t)MININT32; + int16_t intPitchDelayMax = intPitchDelay+3; /* intPitchDelayMax shall be < MAXIMUM_INT_PITCH_DELAY(143) */ + int16_t bestIntPitchDelay = 0; + word16_t *delayedResidualSignal; + if (intPitchDelayMax>MAXIMUM_INT_PITCH_DELAY) { + intPitchDelayMax = MAXIMUM_INT_PITCH_DELAY; + } + + for (i=intPitchDelay-3; i<=intPitchDelayMax; i++) { + word32_t correlation = 0; + delayedResidualSignal = &(scaledResidualSignal[-i]); /* delayedResidualSignal points to scaledResidualSignal[-i] */ + + /* compute correlation: ∑r(n)*rk(n) */ + for (j=0; jcorrelationMax) { + correlationMax = correlation; + bestIntPitchDelay = i; /* get the intPitchDelay */ + } + } + + /* saturate correlation to a positive integer */ + if (correlationMax<0) { + correlationMax = 0; + } + + /*** Compute the signal energy ∑r(n)*r(n) and delayed signal energy ∑rk(n)*rk(n) which shall be used to compute gl spec 4.2.1 eq81, eq 82 and eq83 ***/ + word32_t residualSignalEnergy = 0; /* in Q-4 */ + word32_t delayedResidualSignalEnergy = 0; /* in Q-4 */ + delayedResidualSignal = &(scaledResidualSignal[-bestIntPitchDelay]); /* in Q-2, points to the residual signal delayed to give the higher correlation: rk(n) */ + for (i=0; i= 0 */ + word32_t maximumThree = correlationMax; + if (maximumThree0) { /* if all of them a null, just do nothing otherwise shift right to get the max number in range [0x4000,0x8000[ */ + leadingZeros = countLeadingZeros(maximumThree); + if (leadingZeros<16) { + correlationMaxWord16 = (word16_t)SHR32(correlationMax, 16-leadingZeros); + residualSignalEnergyWord16 = (word16_t)SHR32(residualSignalEnergy, 16-leadingZeros); + delayedResidualSignalEnergyWord16 = (word16_t)SHR32(delayedResidualSignalEnergy, 16-leadingZeros); + } else { /* if the values already fit on 16 bits, no need to shift */ + correlationMaxWord16 = (word16_t)correlationMax; + residualSignalEnergyWord16 = (word16_t)residualSignalEnergy; + delayedResidualSignalEnergyWord16 = (word16_t)delayedResidualSignalEnergy; + } + } + + /* eq78: Hp(z)=(1 + γp*gl*z(−T))/(1 + γp*gl) -> (with g=γp*gl) Hp(z)=1/(1+g) + (g/(1+g))*z(-T) = g0 + g1*z(-T) */ + /* g = gl/2 (as γp=0.5)= (eq83) correlationMax/(2*delayedResidualSignalEnergy) */ + /* compute g0 = 1/(1+g)= delayedResidualSignalEnergy/(delayedResidualSignalEnergy+correlationMax/2) = 1-g1*/ + /* compute g1 = g/(1+g) = correlationMax/(2*delayedResidualSignalEnergy+correlationMax) = 1-g0 */ + + /*** eq82 -> (correlationMax^2)/(residualSignalEnergy*delayedResidualSignalEnergy)<0.5 ***/ + /* (correlationMax^2) < (residualSignalEnergy*delayedResidualSignalEnergy)*0.5 */ + if ((MULT16_16(correlationMaxWord16, correlationMaxWord16) < SHR(MULT16_16(residualSignalEnergyWord16, delayedResidualSignalEnergyWord16), 1)) /* eq82 */ + || ((correlationMax==0) && (delayedResidualSignalEnergy==0))) { /* correlationMax and delayedResidualSignalEnergy values are 0 -> unable to compute g0 and g1 -> disable filter */ + /* long term post filter disabled */ + for (i=0; ilongTermFilteredResidualSignal[i] = residualSignal[i]; + } + } else { /* eq82 gives long term filter enabled, */ + word16_t g0, g1; + /* eq83: gl = correlationMax/delayedResidualSignalEnergy bounded in ]0,1] */ + /* check if gl > 1 -> gl=1 -> g=1/2 -> g0=2/3 and g1=1/3 */ + if (correlationMax > delayedResidualSignalEnergy) { + g0 = 21845; /* 2/3 in Q15 */ + g1 = 10923; /* 1/3 in Q15 */ + } else { + /* g1 = correlationMax/(2*delayedResidualSignalEnergy+correlationMax) */ + g1 = DIV32((word32_t)SHL32(correlationMaxWord16,15),(word32_t)ADD32(SHL32(delayedResidualSignalEnergyWord16,1), correlationMaxWord16)); /* g1 in Q15 */ + g0 = SUB16(32767, g1); /* g0 = 1 - g1 in Q15 */ + } + + /* longTermFilteredResidualSignal[i] = g0*residualSignal[i] + g1*delayedResidualSignal[i]*/ + delayedResidualSignal = &(residualSignal[-bestIntPitchDelay]); + for (i=0; ilongTermFilteredResidualSignal[i] = (word16_t)SATURATE(PSHR(ADD32(MULT16_16(g0, residualSignal[i]), MULT16_16(g1, delayedResidualSignal[i])), 15), MAXINT16); + } + } + + /********************************************************************/ + /* Tilt Compensation Filter */ + /********************************************************************/ + + /* compute hf the truncated (to 22 coefficients) impulse response of the filter A(z/γn)/A(z/γd) described in spec 4.2.2 eq84 */ + /* hf(i) = LPGammaNCoeff[i] - ∑[j:0..9]LPGammaDCoeff[j]*hf[i-j-1]) */ + word16_t LPGammaDCoefficients[NB_LSP_COEFF]; /* in Q12 */ + /* GAMMA_XX constants are in Q15 */ + LPGammaDCoefficients[0] = MULT16_16_P15(LPCoefficients[0], GAMMA_D1); + LPGammaDCoefficients[1] = MULT16_16_P15(LPCoefficients[1], GAMMA_D2); + LPGammaDCoefficients[2] = MULT16_16_P15(LPCoefficients[2], GAMMA_D3); + LPGammaDCoefficients[3] = MULT16_16_P15(LPCoefficients[3], GAMMA_D4); + LPGammaDCoefficients[4] = MULT16_16_P15(LPCoefficients[4], GAMMA_D5); + LPGammaDCoefficients[5] = MULT16_16_P15(LPCoefficients[5], GAMMA_D6); + LPGammaDCoefficients[6] = MULT16_16_P15(LPCoefficients[6], GAMMA_D7); + LPGammaDCoefficients[7] = MULT16_16_P15(LPCoefficients[7], GAMMA_D8); + LPGammaDCoefficients[8] = MULT16_16_P15(LPCoefficients[8], GAMMA_D9); + LPGammaDCoefficients[9] = MULT16_16_P15(LPCoefficients[9], GAMMA_D10); + + word16_t hf[22]; /* the truncated impulse response to short term filter Hf in Q12 */ + hf[0] = 4096; /* 1 in Q12 as LPGammaNCoefficients and LPGammaDCoefficient doesn't contain the first element which is 1 and past values of hf are 0 */ + for (i=1; i<11; i++) { + word32_t acc = (word32_t)SHL(LPGammaNCoefficients[i-1],12); /* LPGammaNCoefficients in Q12 -> acc in Q24 */ + for (j=0; j Q24 TODO: Possible overflow?? */ + } + hf[i] = (word16_t)SATURATE(PSHR(acc, 12), MAXINT16); /* get result back in Q12 and saturate on 16 bits */ + } + for (i=11; i<22; i++) { + word32_t acc = 0; + for (j=0; j Q24 TODO: Possible overflow?? */ + } + hf[i] = (word16_t)SATURATE(PSHR(acc, 12), MAXINT16); /* get result back in Q12 and saturate on 16 bits */ + } + + /* hf is then used to compute k'1 spec 4.2.3 eq87: k'1 = -rh1/rh0 */ + /* rh0 = ∑[i:0..21]hf[i]*hf[i] */ + /* rh1 = ∑[i:0..20]hf[i]*hf[i+1] */ + word32_t rh1 = MULT16_16(hf[0], hf[1]); + for (i=1; i<21; i++) { + rh1 = MAC16_16(rh1, hf[i], hf[i+1]); /* rh1 in Q24 */ + } + + /* tiltCompensationGain is set to 0 if k'1>0 -> rh1<0 (as rh0 is always>0) */ + word16_t tiltCompensatedSignal[L_SUBFRAME]; /* in Q0 */ + if (rh1<0) { /* tiltCompensationGain = 0 -> no gain filter is off, just copy the input */ + memcpy(tiltCompensatedSignal, decoderChannelContext->longTermFilteredResidualSignal, L_SUBFRAME*sizeof(word16_t)); + } else { /*compute tiltCompensationGain = k'1*γt */ + word32_t rh0 = MULT16_16(hf[0], hf[0]); + for (i=1; i<22; i++) { + rh0 = MAC16_16(rh0, hf[i], hf[i]); /* rh0 in Q24 */ + } + rh1 = MULT16_32_Q15(GAMMA_T, rh1); /* GAMMA_T in Q15, rh1 in Q24*/ + word16_t tiltCompensationGain = (word16_t)SATURATE((word32_t)(DIV32(rh1,PSHR(rh0,12))), MAXINT16); /* rh1 in Q24, PSHR(rh0,12) in Q12 -> tiltCompensationGain in Q12 */ + + /* compute filter Ht (spec A.4.2.3 eqA14) = 1 + gain*z(-1) */ + for (i=0; ilongTermFilteredResidualSignal[i], tiltCompensationGain, decoderChannelContext->longTermFilteredResidualSignal[i-1]); + } + } + /* update memory word of longTermFilteredResidualSignal for next subframe */ + decoderChannelContext->longTermFilteredResidualSignal[-1] = decoderChannelContext->longTermFilteredResidualSignal[L_SUBFRAME-1]; + + /********************************************************************/ + /* synthesis filter 1/[Â(z /γd)] spec A.4.2.2 */ + /* */ + /* Note: Â(z/γn) was done before when computing residual signal */ + /********************************************************************/ + /* shortTermFilteredResidualSignal is accessed in range [-NB_LSP_COEFF,L_SUBFRAME[ */ + synthesisFilter(tiltCompensatedSignal, LPGammaDCoefficients, decoderChannelContext->shortTermFilteredResidualSignal); + /* get the last NB_LSP_COEFF of shortTermFilteredResidualSignal and set them as memory for next subframe(they do not overlap so use memcpy) */ + memcpy(decoderChannelContext->shortTermFilteredResidualSignalBuffer, &(decoderChannelContext->shortTermFilteredResidualSignalBuffer[L_SUBFRAME]), NB_LSP_COEFF*sizeof(word16_t)); + + /********************************************************************/ + /* Adaptive Gain Control spec A.4.2.4 */ + /* */ + /********************************************************************/ + + /*** compute G(gain scaling factor) according to eqA15 : G = Sqrt((∑s(n)^2)/∑sf(n)^2 ) ***/ + word16_t gainScalingFactor; /* in Q12 */ + /* compute ∑sf(n)^2 scale the signal shifting left by 2 to avoid overflow on 32 bits sum */ + word32_t shortTermFilteredResidualSignalSquareSum = 0; + for (i=0; ishortTermFilteredResidualSignal[i], decoderChannelContext->shortTermFilteredResidualSignal[i]); + } + + /* if the sum is null we can't compute gain -> output of postfiltering is the output of shortTermFilter and previousAdaptativeGain is set to 0 */ + /* the reset of previousAdaptativeGain is not mentionned in the spec but in ITU code only */ + if (shortTermFilteredResidualSignalSquareSum == 0) { + decoderChannelContext->previousAdaptativeGain = 0; + for (i=0; ishortTermFilteredResidualSignal[i]; + } + } else { /* we can compute adaptativeGain and output signal */ + + /* compute ∑s(n)^2 scale the signal shifting left by 2 to avoid overflow on 32 bits sum */ + word32_t reconstructedSpeechSquareSum = 0; + for (i=0; i current gain is null */ + gainScalingFactor = 0; + } else { + /* Compute ∑s(n)^2)/∑sf(n)^2 result shall be in Q10 */ + /* normalise the numerator on 32 bits */ + word16_t numeratorShift = countLeadingZeros(reconstructedSpeechSquareSum); + reconstructedSpeechSquareSum = SHL(reconstructedSpeechSquareSum, numeratorShift); /* reconstructedSpeechSquareSum*2^numeratorShift */ + + /* normalise denominator to get the result directly in Q10 if possible */ + word32_t fractionResult; /* stores ∑s(n)^2)/∑sf(n)^2 */ + word32_t scaledShortTermFilteredResidualSignalSquareSum = VSHR32(shortTermFilteredResidualSignalSquareSum, 10-numeratorShift); /* shortTermFilteredResidualSignalSquareSum*2^(numeratorShift-10)*/ + + if (scaledShortTermFilteredResidualSignalSquareSum==0) {/* shift might have sent to zero the denominator */ + fractionResult = DIV32(reconstructedSpeechSquareSum, shortTermFilteredResidualSignalSquareSum); /* result in QnumeratorShift */ + fractionResult = VSHR32(fractionResult, numeratorShift-10); /* result in Q10 */ + } else { /* ok denominator is still > 0 */ + fractionResult = DIV32(reconstructedSpeechSquareSum, scaledShortTermFilteredResidualSignalSquareSum); /* result in Q10 */ + } + /* now compute current Gain = Sqrt((∑s(n)^2)/∑sf(n)^2 ) */ + /* g729Sqrt_Q0Q7(Q0)->Q7, by giving a Q10 as input, output is in Q12 */ + gainScalingFactor = (word16_t)SATURATE(g729Sqrt_Q0Q7(fractionResult), MAXINT16); + + /* multiply by 0.1 as described in spec A.4.2.4 */ + gainScalingFactor = MULT16_16_P15(gainScalingFactor, 3277); /* in Q12, 3277 = 0.1 in Q15*/ + } + /* Compute the signal according to eq89 (spec 4.2.4 and section A4.2.4) */ + /* currentGain = 0.9*previousGain + 0.1*gainScalingFactor the 0.1 factor has already been integrated in the variable gainScalingFactor */ + /* outputsignal = currentGain*shortTermFilteredResidualSignal */ + word16_t currentAdaptativeGain = decoderChannelContext->previousAdaptativeGain; + for (i=0; ishortTermFilteredResidualSignal[i]); + } + decoderChannelContext->previousAdaptativeGain = currentAdaptativeGain; + } + + /* shift buffers if needed */ + if (subframeIndex>0) { /* only after 2nd subframe treatment */ + /* shift left by L_FRAME the residualSignal and scaledResidualSignal buffers */ + memmove(decoderChannelContext->residualSignalBuffer, &(decoderChannelContext->residualSignalBuffer[L_FRAME]), MAXIMUM_INT_PITCH_DELAY*sizeof(word16_t)); + memmove(decoderChannelContext->scaledResidualSignalBuffer, &(decoderChannelContext->scaledResidualSignalBuffer[L_FRAME]), MAXIMUM_INT_PITCH_DELAY*sizeof(word16_t)); + } + return; +} diff --git a/src/postProcessing.c b/src/postProcessing.c new file mode 100644 index 0000000..32b1039 --- /dev/null +++ b/src/postProcessing.c @@ -0,0 +1,91 @@ +/* + postProcessing.c + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include "typedef.h" +#include "codecParameters.h" +#include "basicOperationsMacros.h" + +#include "preProcessing.h" + +/*****************************************************************************/ +/* */ +/* Define filter coefficients */ +/* Coefficient are given by the filter transfert function : */ +/* */ +/* 0.46363718 - 0.92724705z(-1) + 0.46363718z(-2) */ +/* H(z) = −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− */ +/* 1 - 1.9059465z(-1) + 0.9114024z(-2) */ +/* */ +/* giving: */ +/* y[i] = B0*x[i] + B1*x[i-1] + B2*x[i-2] */ +/* + A1*y[i-1] + A2*y[i-2] */ +/* */ +/*****************************************************************************/ + +/* coefficients are stored in Q1.13 */ +#define A1 ((word16_t)(15836)) +#define A2 ((word16_t)(-7667)) +#define B0 ((word16_t)(7699)) +#define B1 ((word16_t)(-15398)) +#define B2 ((word16_t)(7699)) + +/* Initialization of context values */ +void initPostProcessing(bcg729DecoderChannelContextStruct *decoderChannelContext) { + decoderChannelContext->outputY2 = 0; + decoderChannelContext->outputY1 = 0; + decoderChannelContext->inputX0 = 0; + decoderChannelContext->inputX1 = 0; +} + + +/*****************************************************************************/ +/* postProcessing : high pass filtering and upscaling Spec 4.2.5 */ +/* Algorithm: */ +/* y[i] = BO*x[i] + B1*x[i-1] + B2*x[i-2] + A1*y[i-1] + A2*y[i-2] */ +/* parameters: */ +/* -(i/o) decoderChannelContext : the channel context data */ +/* -(i/o) signal : 40 values in Q0, reconstructed speech, output */ +/* replaces the input in buffer */ +/* */ +/*****************************************************************************/ +void postProcessing(bcg729DecoderChannelContextStruct *decoderChannelContext, word16_t signal[]) { + int i; + word16_t inputX2; + word32_t acc; /* in Q13 */ + + for(i=0; iinputX1; + decoderChannelContext->inputX1 = decoderChannelContext->inputX0; + decoderChannelContext->inputX0 = signal[i]; + + /* compute with acc and coefficients in Q13 */ + acc = MULT16_32_Q13(A1, decoderChannelContext->outputY1); /* Y1 in Q14.13 * A1 in Q1.13 -> acc in Q17.13*/ + acc = MAC16_32_Q13(acc, A2, decoderChannelContext->outputY2); /* Y2 in Q14.13 * A2 in Q0.13 -> Q15.13 + acc in Q17.13 -> acc in Q18.12 */ + /* 3*(Xi in Q15.0 * Bi in Q0.13)->Q17.13 + acc in Q18.13 -> acc in 19.13(Overflow??) */ + acc = MAC16_16(acc, decoderChannelContext->inputX0, B0); + acc = MAC16_16(acc, decoderChannelContext->inputX1, B1); + acc = SATURATE(MAC16_16(acc, inputX2, B2), MAXINT29); /* saturate the acc to keep in Q15.13 */ + + signal[i] = SATURATE(PSHR(acc,12), MAXINT16); /* acc in Q13 -> *2 and scale back to Q0 */ + decoderChannelContext->outputY2 = decoderChannelContext->outputY1; + decoderChannelContext->outputY1 = acc; + } + return; +} diff --git a/src/preProcessing.c b/src/preProcessing.c new file mode 100644 index 0000000..fec1ce8 --- /dev/null +++ b/src/preProcessing.c @@ -0,0 +1,96 @@ +/* + preProcessing.c + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include "typedef.h" +#include "codecParameters.h" +#include "basicOperationsMacros.h" + +#include "preProcessing.h" + +/*****************************************************************************/ +/* */ +/* Define filter coefficients */ +/* Coefficient are given by the filter transfert function : */ +/* */ +/* 0.46363718 - 0.92724705z(-1) + 0.46363718z(-2) */ +/* H(z) = −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− */ +/* 1 - 1.9059465z(-1) + 0.9114024z(-2) */ +/* */ +/* giving: */ +/* y[i] = B0*x[i] + B1*x[i-1] + B2*x[i-2] */ +/* + A1*y[i-1] + A2*y[i-2] */ +/* */ +/*****************************************************************************/ + +/* coefficients a stored in Q1.12 for A1 (the only one having a float value > 1) and Q0.12 for all the others */ +#define A1 ((word16_t)(7807)) +#define A2 ((word16_t)(-3733)) +#define B0 ((word16_t)(1899)) +#define B1 ((word16_t)(-3798)) +#define B2 ((word16_t)(1899)) + +/* Initialization of context values */ +void initPreProcessing(bcg729EncoderChannelContextStruct *encoderChannelContext) { + encoderChannelContext->outputY2 = 0; + encoderChannelContext->outputY1 = 0; + encoderChannelContext->inputX0 = 0; + encoderChannelContext->inputX1 = 0; +} + + +/*****************************************************************************/ +/* preProcessing : 2nd order highpass filter with cut off frequency at 140Hz */ +/* Algorithm: */ +/* y[i] = BO*x[i] + B1*x[i-1] + B2*x[i-2] + A1*y[i-1] + A2*y[i-2] */ +/* parameters : */ +/* -(i/o) encoderChannelContext : the channel context data */ +/* -(i) signal : 80 values in Q0 */ +/* -(o) preProcessedSignal : 80 values in Q0 */ +/* */ +/*****************************************************************************/ +void preProcessing(bcg729EncoderChannelContextStruct *encoderChannelContext, word16_t signal[], word16_t preProcessedSignal[]) { + int i; + word16_t inputX2; + word32_t acc; /* in Q12 */ + + for(i=0; iinputX1; + encoderChannelContext->inputX1 = encoderChannelContext->inputX0; + encoderChannelContext->inputX0 = signal[i]; + + /* compute with acc and coefficients in Q12 */ + acc = MULT16_32_Q12(A1, encoderChannelContext->outputY1); /* Y1 in Q15.12 * A1 in Q1.12 -> acc in Q17.12*/ + acc = MAC16_32_Q12(acc, A2, encoderChannelContext->outputY2); /* Y2 in Q15.12 * A2 in Q0.12 -> Q15.12 + acc in Q17.12 -> acc in Q18.12 */ + /* 3*(Xi in Q15.0 * Bi in Q0.12)->Q17.12 + acc in Q18.12 -> acc in 19.12 */ + acc = MAC16_16(acc, encoderChannelContext->inputX0, B0); + acc = MAC16_16(acc, encoderChannelContext->inputX1, B1); + acc = MAC16_16(acc, inputX2, B2); + /* acc in Q19.12 : We must check it won't overflow + - the Q15.12 of Y + - the Q15.0 extracted from it by shifting 12 right + -> saturate to 28 bits -> acc in Q15.12 */ + acc = SATURATE(acc, MAXINT28); + + preProcessedSignal[i] = PSHR(acc,12); /* extract integer value of the Q15.12 representation */ + encoderChannelContext->outputY2 = encoderChannelContext->outputY1; + encoderChannelContext->outputY1 = acc; + } + return; +} diff --git a/src/qLSP2LP.c b/src/qLSP2LP.c new file mode 100644 index 0000000..e45ca55 --- /dev/null +++ b/src/qLSP2LP.c @@ -0,0 +1,96 @@ +/* + qLSP2LP.c + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "typedef.h" +#include "codecParameters.h" +#include "basicOperationsMacros.h" + +/* local function */ +void computePolynomialCoefficients(word16_t qLSP[], word32_t f[]); + +/*****************************************************************************/ +/* qLSP2LP : convert qLSP into LP parameters according to spec. 3.2.6 */ +/* parameters: */ +/* -(i) qLSP : 10 LSP to be converted in Q0.15 range [-1, +1[ */ +/* -(o) LP : 10 LP coefficients in Q12 */ +/* */ +/*****************************************************************************/ +void qLSP2LP(word16_t qLSP[], word16_t LP[]) +{ + int i; + word32_t f1[6], f2[6]; /* define two buffer to store the polynomials coefficients (size is 6 for 5 coefficient because fx[0] is used during computation as a buffer) */ + /* pointers to access directly the elements 1 of f1 and f2 */ + word32_t *fp1=&(f1[1]); + word32_t *fp2=&(f2[1]); + computePolynomialCoefficients(qLSP, f1); + + computePolynomialCoefficients(&(qLSP[1]), f2); + + /* convert f coefficient in f' coefficient f'1[i] = f1[i]+f[i-1] and f'2[i] = f2[i] - f2[i-1] */ + for (i=5; i>0; i--) { + f1[i] = ADD32(f1[i], f1[i-1]); /* f1 is still in Q24 */ + f2[i] = SUB32(f2[i], f2[i-1]); /* f1 is still in Q24 */ + } + + /* compute the LP coefficients */ + /* fx[0] is not needed anymore, acces the f1 and f2 buffers via the fp1 and fp2 pointers */ + for (i=0; i<5; i++) { + /* i in [0,5[ : LP[i] = (f1[i] + f2[i])/2 */ + LP[i] = PSHR(ADD32(fp1[i], fp2[i]),13); /* f1 and f2 in Q24, LP in Q12 */ + /* i in [5,9[ : LP[i] = (f1[9-i] - f2[9-i])/2 */ + LP[9-i] = PSHR(SUB32(fp1[i], fp2[i]),13); /* f1 and f2 in Q24, LP in Q12 */ + } + return; +} + + +/*****************************************************************************/ +/* computePolynomialCoefficients : according to spec. 3.2.6 */ +/* parameters: */ +/* -(i) qLSP : 10 LSP to be converted in Q0.15 range [-1, +1[ */ +/* -(o) f : 6 values in Q24 : polynomial coefficients on 32 bits */ +/* */ +/*****************************************************************************/ +void computePolynomialCoefficients(word16_t qLSP[], word32_t f[]) +{ + int i,j; + + /* init values */ + /* f[-1] which is not available is to be egal at 0, it is directly removed in the following when used as a factor */ + f[0] = 16777216; /* 1 in Q24, f[0] is used only for the other coefficient computation */ + + /* correspont to i=1 in the algorithm description in spec. 3.2.6 */ + f[1] = MULT16_16(qLSP[0], -1024); /* f[1] = -2*qLSP[0], with qLSP in Q0.15 * -2*2^9(-1024) -> f[1] in Q1.24 */ + + /* so we start with i=2 */ + /* Note : index of qLSP are -1 respect of what is in the spec because qLSP array is indexed from 0-9 and not 1-10 */ + for (i=2; i<6; i++) { + /* spec: f[i] = 2(f[i-2] - qLSP[2i-1]*f[i-1]) */ + f[i] = SHL(SUB32(f[i-2], MULT16_32_P15(qLSP[2*i-2], f[i-1])),1); /* with qLSP in Q0.15 and f in Q24 */ + for (j=i-1; j>1; j--) { /* case of j=1 is just doing f[1] -= 2*qLSP[2i-1], done after the loop in order to avoid reference to f[-1] */ + /* spec: f[j] = f[j] -2*qLSP[2i-i]*f[j-1] + f[j-2] (all right terms refer to the value at the previous iteration on i indexed loop) */ + f[j] = ADD32(f[j], SUB32(f[j-2], MULT16_32_P14(qLSP[2*i-2], f[j-1]))); /* qLPS in Q0.15 and f in Q24, using MULT16_32_P14 instead of P15 does the *2 on qLSP. Result in Q24 */ + } + /* f[1] -= 2*qLSP[2i-1] */ + f[1] = SUB32(f[1], SHL(qLSP[2*i-2],10)); /* qLSP in Q0.15, must be shift by 9 to get in Q24 and one more to be *2 */ + } + return; +} diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..81ca645 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,327 @@ +/* + utils.c + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "typedef.h" +#include "basicOperationsMacros.h" +#include "codecParameters.h" +#include "g729FixedPointMath.h" +#include "codebooks.h" + +/*****************************************************************************/ +/* insertionSort : sort an array in growing order using insertion algorithm */ +/* parameters : */ +/* -(i/o) x: the array to be sorted */ +/* -(i) length: the array length */ +/* */ +/*****************************************************************************/ +void insertionSort(word16_t x[], int length) +{ + int i, j; + word16_t currentValue; + + for (i=1; i=0) && (x[j]>currentValue)) { + x[j+1] = x[j]; + j--; + } + + x[j+1] = currentValue; + } + + return; +} + +/*****************************************************************************/ +/* computeParity : compute parity for pitch delay adaptative codebook index */ +/* XOR of the 6 MSB (pitchDelay on 8 bits) */ +/* parameters : */ +/* -(i) adaptativeCodebookIndex: the pitch delay on 8 bits */ +/* return value : */ +/* the parity bit */ +/* */ +/*****************************************************************************/ +uint16_t computeParity(uint16_t adaptativeCodebookIndex) +{ + int i; + uint16_t parity = 1; + adaptativeCodebookIndex = SHR(adaptativeCodebookIndex,2); /* ignore the two LSB */ + + for (i=0; i<6; i++) { + parity ^= adaptativeCodebookIndex&(uint16_t)1; /* XOR with the LSB */ + adaptativeCodebookIndex = SHR(adaptativeCodebookIndex,1); + } + + return parity; +} + +/*****************************************************************************/ +/* rearrangeCoefficients: rearrange coefficients according to spec 3.2.4 */ +/* Have a minimum distance of J beetwen two consecutive coefficients */ +/* parameters: */ +/* -(i/o) qLSP: 10 ordered coefficients in Q13 replaced by new values */ +/* if needed */ +/* -(i) J: minimum distance between coefficients in Q0.13 (10 or 5) */ +/* */ +/*****************************************************************************/ +void rearrangeCoefficients(word16_t qLSP[], word16_t J) +{ /* qLSP in Q2.13 and J in Q0.13(fitting on 4 bits: possible values 10 and 5) */ + int i=1; + word16_t delta; /* in Q0.13 */ + + for (i=1; i 0) { + qLSP[i-1] = SUB16(qLSP[i-1], delta); /* qLSP still in Q2.13 */ + qLSP[i] = ADD16(qLSP[i], delta); + } + } + + return; +} + +/*****************************************************************************/ +/* synthesisFilter : compute 1/[A(z)] using the following algorithm */ +/* filteredSignal[n] = inputSignal[n] */ +/* - Sum(i=1..10)filterCoefficients[i]*filteredSignal[n-i] */ +/* for n in [0, L_SUBFRAME[ */ +/* parameters: */ +/* -(i) inputSignal: 40 values in Q0 */ +/* -(i) filterCoefficients: 10 coefficients in Q12 */ +/* -(i/o) filteredSignal: 50 values in Q0 accessed in ranges [-10,-1] */ +/* as input and [0, 39] as output. */ +/* */ +/*****************************************************************************/ +void synthesisFilter(word16_t inputSignal[], word16_t filterCoefficients[], word16_t filteredSignal[]) +{ + int i; + for (i=0; i acc in Q12 */ + } + filteredSignal[i] = (word16_t)SATURATE(PSHR(acc, 12), MAXINT16); /* shift right acc to get it back in Q0 and check overflow on 16 bits */ + } + + return; +} + +/*****************************************************************************/ +/* correlateVectors : compute the correlations between two vectors of */ +/* L_SUBFRAME length: c[i] = Sum(x[j]*y[j-i]) j in [i, L_SUBFRAME[ */ +/* parameters: */ +/* -(i) x : L_SUBFRAME length input vector on 16 bits */ +/* -(i) y : L_SUBFRAME length input vector on 16 bits */ +/* -(o) c : L_SUBFRAME length output vector on 32 bits */ +/* */ +/*****************************************************************************/ +void correlateVectors (word16_t x[], word16_t y[], word32_t c[]) +{ + int i,j; + for (i=0; iQ24, previousGainPredictionError in Q10 and MAPredictionCoefficients in Q0.14*/ + acc = SHL(acc,8); /* acc in Q24 to match the fixed point of next accumulations */ + for (i=0; i<4; i++) { + acc = MAC16_16(acc, previousGainPredictionError[i], MAPredictionCoefficients[i]); + } + /* acc range [10, 65] -> Q6.24 */ + + + /* compute eq71, we already have the exposant in acc so */ + /* g'c = 10^(acc/20) */ + /* = 2^((acc*ln(10))/(20*ln(2))) */ + /* = 2^(0,1661*acc) */ + acc = SHR(acc,2); /* Q24->Q22 */ + acc = MULT16_32_Q15(5442, acc); /* 5442 is 0.1661 in Q15 -> acc now in Q4.22 range [1.6, 10.8] */ + acc = PSHR(acc,11); /* get acc in Q4.11 */ + + return g729Exp2_Q11Q16((word16_t)acc); /* acc fits on 16 bits, cast it to word16_t to send it to the exp2 function, output in Q16*/ +} + + +/*****************************************************************************/ +/* computeGainPredictionError : apply eq72 to compute current fixed Codebook */ +/* gain prediction error and store the result in the adhoc array */ +/* parameters : */ +/* -(i) fixedCodebookGainCorrectionFactor: gamma in eq72 in Q3.12 */ +/* -(i/o) previousGainPredictionError: array to be updated in Q10 */ +/* */ +/*****************************************************************************/ +void computeGainPredictionError(word16_t fixedCodebookGainCorrectionFactor, word16_t *previousGainPredictionError) +{ + /* need to compute eq72: 20log10(fixedCodebookGainCorrectionFactor) */ + /* = (20/log2(10))*log2(fixedCodebookGainCorrectionFactor) */ + /* = 6.0206*log2(fixedCodebookGainCorrectionFactor) */ + /* log2 input in Q0, output in Q16,fixedCodebookGainCorrectionFactor being in Q12, we shall substract 12 in Q16(786432) to the result of log2 function -> final result in Q2.16 */ + word32_t currentGainPredictionError = SUB32(g729Log2_Q0Q16(fixedCodebookGainCorrectionFactor), 786432); + currentGainPredictionError = PSHR(MULT16_32_Q12(24660, currentGainPredictionError),6); /* 24660 = 6.0206 in Q3.12 -> mult result in Q16, precise shift right to get it in Q4.10 */ + + /* shift the array and insert the current Prediction Error */ + previousGainPredictionError[3] = previousGainPredictionError[2]; + previousGainPredictionError[2] = previousGainPredictionError[1]; + previousGainPredictionError[1] = previousGainPredictionError[0]; + previousGainPredictionError[0] = (word16_t)currentGainPredictionError; +} + + +/*** bitStream to parameters Array conversions functions ***/ +/* Note: these functions are in utils.c because used by test source code too */ + +/*****************************************************************************/ +/* parametersArray2BitStream : convert array of parameters to bitStream */ +/* according to spec 4 - Table 8 and following mapping of values */ +/* 0 -> L0 (1 bit) */ +/* 1 -> L1 (7 bits) */ +/* 2 -> L2 (5 bits) */ +/* 3 -> L3 (5 bits) */ +/* 4 -> P1 (8 bit) */ +/* 5 -> P0 (1 bits) */ +/* 6 -> C1 (13 bits) */ +/* 7 -> S1 (4 bits) */ +/* 8 -> GA1(3 bits) */ +/* 9 -> GB1(4 bits) */ +/* 10 -> P2 (5 bits) */ +/* 11 -> C2 (13 bits) */ +/* 12 -> S2 (4 bits) */ +/* 13 -> GA2(3 bits) */ +/* 14 -> GB2(4 bits) */ +/* parameters: */ +/* -(i) parameters : 16 values parameters array */ +/* -(o) bitStream : the 16 values streamed on 80 bits in a */ +/* 10*8bits values array */ +/* */ +/*****************************************************************************/ +void parametersArray2BitStream(uint16_t parameters[], uint8_t bitStream[]) +{ + bitStream[0] = ((parameters[0]&((uint16_t) 0x1))<<7) | + (parameters[1]&((uint16_t) 0x7f)); + + bitStream[1] = ((parameters[2]&((uint16_t) 0x1f))<<3) | + ((parameters[3]>>2)&((uint16_t) 0x7)); + + bitStream[2] = ((parameters[3]&((uint16_t) 0x3))<<6) | + ((parameters[4]>>2)&((uint16_t) 0x3f)); + + bitStream[3] = ((parameters[4]&((uint16_t) 0x3))<<6) | + ((parameters[5]&((uint16_t) 0x1))<<5) | + ((parameters[6]>>8)&((uint16_t) 0x1f)); + + bitStream[4] = ((parameters[6])&((uint16_t) 0xff)); + + bitStream[5] = ((parameters[7]&((uint16_t) 0xf))<<4) | + ((parameters[8]&((uint16_t) 0x7))<<1) | + ((parameters[9]>>3)&((uint16_t) 0x1)); + + bitStream[6] = ((parameters[9]&((uint16_t) 0x7))<<5) | + (parameters[10]&((uint16_t) 0x1f)); + + bitStream[7] = ((parameters[11]>>5)&((uint16_t) 0xff)); + + bitStream[8] = ((parameters[11]&((uint16_t) 0x1f))<<3) | + ((parameters[12]>>1)&((uint16_t) 0x7)); + + bitStream[9] = ((parameters[12]&((uint16_t) 0x1))<<7) | + ((parameters[13]&((uint16_t) 0x7))<<4) | + (parameters[14]&((uint16_t) 0xf)); + + return; +} + +/*****************************************************************************/ +/* parametersArray2BitStream : convert bitStream to an array of parameters */ +/* reverse operation of previous funtion */ +/* parameters: */ +/* -(i) bitStream : the 16 values streamed on 80 bits in a */ +/* 10*8bits values array */ +/* -(o) parameters : 16 values parameters array */ +/* */ +/*****************************************************************************/ +void parametersBitStream2Array(uint8_t bitStream[], uint16_t parameters[]) +{ + parameters[0] = (bitStream[0]>>7)&(uint16_t)0x1; + parameters[1] = bitStream[0]&(uint16_t)0x7f; + parameters[2] = (bitStream[1]>>3)&(uint16_t)0x1f; + parameters[3] = (((uint16_t)bitStream[1]&(uint16_t)0x7)<<2) | ((bitStream[2]>>6)&(uint16_t)0x3); + parameters[4] = (((uint16_t)bitStream[2])&(uint16_t)0x3f)<<2 | ((bitStream[3]>>6)&(uint16_t)0x3);; + parameters[5] = (bitStream[3]>>5)&(uint16_t)0x1; + parameters[6] = (((uint16_t)(bitStream[3]&(uint16_t)0x1f))<<8)| bitStream[4]; + parameters[7] = (bitStream[5]>>4)&(uint16_t)0xf; + parameters[8] = (bitStream[5]>>1)&(uint16_t)0x7; + parameters[9] = (((uint16_t)bitStream[5]&(uint16_t)0x1)<<3)|((bitStream[6]>>5)&(uint16_t)0x7); + parameters[10]= (uint16_t)bitStream[6]&(uint16_t)0x1f; + parameters[11]= (((uint16_t)bitStream[7])<<5)|((bitStream[8]>>3)&(uint16_t)0x1f); + parameters[12]= ((bitStream[8]&(uint16_t)0x7)<<1) | ((bitStream[9]>>7)&(uint16_t)0x1); + parameters[13]= (bitStream[9]>>4)&(uint16_t)0x7; + parameters[14]= bitStream[9]&(uint16_t)0xf; + + return; +} diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 0000000..6465c8c --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = bin + +TESTS_ENVIRONMENT = $(SHELL) +TESTS=testCampaignAll diff --git a/test/bin/.gitignore b/test/bin/.gitignore new file mode 100644 index 0000000..6a7b47a --- /dev/null +++ b/test/bin/.gitignore @@ -0,0 +1,2 @@ +#ignore all test bins +*Test diff --git a/test/bin/Makefile.am b/test/bin/Makefile.am new file mode 100644 index 0000000..0220102 --- /dev/null +++ b/test/bin/Makefile.am @@ -0,0 +1,34 @@ +check_PROGRAMS=adaptativeCodebookSearchTest computeAdaptativeCodebookGainTest computeLPTest computeWeightedSpeechTest decodeAdaptativeCodeVectorTest decodeFixedCodeVectorTest decodeGainsTest decodeLSPTest \ + decoderTest encoderTest decoderMultiChannelTest encoderMultiChannelTest findOpenLoopPitchDelayTest fixedCodebookSearchTest g729FixedPointMathTest gainQuantizationTest interpolateqLSPAndConvert2LPTest \ + LP2LSPConversionTest LPSynthesisFilterTest LSPQuantizationTest postFilterTest postProcessingTest preProcessingTest +util_src=$(top_srcdir)/test/src/testUtils.c + +adaptativeCodebookSearchTest_SOURCES=$(top_srcdir)/test/src/adaptativeCodebookSearchTest.c $(util_src) +computeAdaptativeCodebookGainTest_SOURCES=$(top_srcdir)/test/src/computeAdaptativeCodebookGainTest.c $(util_src) +computeLPTest_SOURCES=$(top_srcdir)/test/src/computeLPTest.c $(util_src) +computeWeightedSpeechTest_SOURCES=$(top_srcdir)/test/src/computeWeightedSpeechTest.c $(util_src) +decodeAdaptativeCodeVectorTest_SOURCES=$(top_srcdir)/test/src/decodeAdaptativeCodeVectorTest.c $(util_src) +decodeFixedCodeVectorTest_SOURCES=$(top_srcdir)/test/src/decodeFixedCodeVectorTest.c $(util_src) +decodeGainsTest_SOURCES=$(top_srcdir)/test/src/decodeGainsTest.c $(util_src) +decodeLSPTest_SOURCES=$(top_srcdir)/test/src/decodeLSPTest.c $(util_src) +decoderTest_SOURCES=$(top_srcdir)/test/src/decoderTest.c $(util_src) +decoderMultiChannelTest_SOURCES=$(top_srcdir)/test/src/decoderMultiChannelTest.c $(util_src) +encoderTest_SOURCES=$(top_srcdir)/test/src/encoderTest.c $(util_src) +encoderMultiChannelTest_SOURCES=$(top_srcdir)/test/src/encoderMultiChannelTest.c $(util_src) +findOpenLoopPitchDelayTest_SOURCES=$(top_srcdir)/test/src/findOpenLoopPitchDelayTest.c $(util_src) +fixedCodebookSearchTest_SOURCES=$(top_srcdir)/test/src/fixedCodebookSearchTest.c $(util_src) +g729FixedPointMathTest_SOURCES=$(top_srcdir)/test/src/g729FixedPointMathTest.c $(util_src) +g729FixedPointMathTest_LDADD=-lm +gainQuantizationTest_SOURCES=$(top_srcdir)/test/src/gainQuantizationTest.c $(util_src) +interpolateqLSPAndConvert2LPTest_SOURCES=$(top_srcdir)/test/src/interpolateqLSPAndConvert2LPTest.c $(util_src) +LP2LSPConversionTest_SOURCES=$(top_srcdir)/test/src/LP2LSPConversionTest.c $(util_src) +LPSynthesisFilterTest_SOURCES=$(top_srcdir)/test/src/LPSynthesisFilterTest.c $(util_src) +LSPQuantizationTest_SOURCES=$(top_srcdir)/test/src/LSPQuantizationTest.c $(util_src) +postFilterTest_SOURCES=$(top_srcdir)/test/src/postFilterTest.c $(util_src) +postProcessingTest_SOURCES=$(top_srcdir)/test/src/postProcessingTest.c $(util_src) +preProcessingTest_SOURCES=$(top_srcdir)/test/src/preProcessingTest.c $(util_src) + +LDADD= $(top_builddir)/src/libbcg729.la +INCLUDES=-I$(top_srcdir)/include/ + + diff --git a/test/src/LP2LSPConversionTest.c b/test/src/LP2LSPConversionTest.c new file mode 100644 index 0000000..3acef77 --- /dev/null +++ b/test/src/LP2LSPConversionTest.c @@ -0,0 +1,108 @@ +/* + LP2LSPConversionTest.c + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/*****************************************************************************/ +/* */ +/* Test Program for LP2LSPConversion bloc */ +/* Input: - 10 LP in Q12 */ +/* */ +/* Ouput: - 10 LSP in Q15 */ +/* */ +/*****************************************************************************/ + +#include +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "LP2LSPConversion.h" + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + /* input file: 10 LP Coefficients(Q12) */ + word16_t LP[NB_LSP_COEFF]; + + /* output file: 10 LSP Coefficients(Q15) */ + word16_t LSP[NB_LSP_COEFF]; + word16_t previousLSP[NB_LSP_COEFF] = /* store previously computed LSP to be reused if we can't find 10 LSP from current LP */ + {30000, 26000, 21000, 15000, 8000, 0, -8000,-15000,-21000,-26000}; + + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "r")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "w")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + + /* initialise buffers */ + + /*** initialisation complete ***/ + + + /*** loop over input file ***/ + while(fscanf(fpInput,"%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd",&LP[0],&LP[1],&LP[2],&LP[3],&LP[4],&LP[5],&LP[6],&LP[7],&LP[8],&LP[9]) == 10) + { + int i; + + /* call the tested funtion */ + if (LP2LSPConversion(LP, LSP)) { + for (i=0; i +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "LPSynthesisFilter.h" + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + /* input file: 10 LP Coefficients(Q12), 40 ExcitationVector(Q0), 10 past reconstructed speech(Q0) */ + word16_t LP[NB_LSP_COEFF]; + word16_t excitationVector[L_SUBFRAME]; /* this vector contains the subframe excitation vector in Q0 */ + + /* output is in the reconstruted speech: for the test purpose it's long just memory+subframe */ + word16_t reconstructedSpeech[NB_LSP_COEFF+L_SUBFRAME]; /* in Q0, output of the LP synthesis filter, the first 10 words store the previous frame output */ + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "r")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "w")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + + /* initialise buffers */ + + /*** initialisation complete ***/ + + + /*** loop over input file ***/ + while(1) /* infinite loop, escape condition is in the reading of data */ + { + int i; + /* read the input data until we have some */ + if (fscanf(fpInput,"%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd",&LP[0],&LP[1],&LP[2],&LP[3],&LP[4],&LP[5],&LP[6],&LP[7],&LP[8],&LP[9]) != 10) break; + for (i=0; i +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "LSPQuantization.h" + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + /* input file: 10 LSP Coefficients(Q15) */ + word16_t LSP[NB_LSP_COEFF]; + + /* output file: 10 qLSP Coefficients(Q15) */ + word16_t qLSP[NB_LSP_COEFF]; + uint16_t parametersL[4]; + + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "r")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "w")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + /* create the context structure */ + bcg729EncoderChannelContextStruct *encoderChannelContext = malloc(sizeof(bcg729EncoderChannelContextStruct)); + + initLSPQuantization(encoderChannelContext); + + /* initialise buffers */ + + /*** initialisation complete ***/ +// LSPQuantization(LSP, qLSP, parametersL); +//exit (0); + + /*** loop over input file ***/ + while(fscanf(fpInput,"%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd",&LSP[0],&LSP[1],&LSP[2],&LSP[3],&LSP[4],&LSP[5],&LSP[6],&LSP[7],&LSP[8],&LSP[9]) == 10) + { + int i; + + /* call the tested funtion */ + LSPQuantization(encoderChannelContext, LSP, qLSP, parametersL); + + /* write the output to the output file */ + fprintf(fpOutput,"%d", qLSP[0]); + for (i=1; i +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "adaptativeCodebookSearch.h" + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + /* input file: pastExcitationVector: 234 values, targetSignal: 40 values, impulseReponse: 40 values, intPitchDelayMin, intPitchDelayMax, subframeIndex */ + word16_t excitationVector[L_PAST_EXCITATION + L_FRAME]; /* this vector contains: note on second subframe we have 40 useless values of past excitation + 0->153 : the past excitation vector.(length is Max Pitch Delay: 144 + interpolation window size : 10) + 154-> 154+L_SUBFRAME-1 : the current LPResidualSignal in input + 154-> 154+L_SUBFRAME-1 : the adaptative codebook vector in Q0 as output */ + word16_t targetSignal[L_SUBFRAME]; + word16_t impulseResponse[L_SUBFRAME]; + int16_t intPitchDelayMin, intPitchDelayMax; + int subFrameIndex; + /* outputs : */ + int16_t intPitchDelay; + int16_t fracPitchDelay; + uint16_t adaptativeCodebookIndex; + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "r")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "w")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + + /* initialise buffers */ + /* actually useless init, because the complete excitation buffer is reload at each subframe from input file, but shall be done in real decoder */ + memset(excitationVector, 0, L_PAST_EXCITATION*sizeof(word16_t)); /* initialise the part of the excitationVector containing the past excitation */ + + + /*** initialisation complete ***/ + + + /*** loop over input file ***/ + while(1) /* infinite loop, escape condition is in the reading of data */ + { + int i; + /* read the input data until we have some */ + for (i=0; i<234; i++) { + if (fscanf(fpInput,"%hd,",&(excitationVector[i])) != 1) break; + } + for (i=0; i<40; i++) { + if (fscanf(fpInput,"%hd,",&(targetSignal[i])) != 1) break; + } + for (i=0; i<40; i++) { + if (fscanf(fpInput,"%hd,",&(impulseResponse[i])) != 1) break; + } + if (fscanf(fpInput,"%hd,",&intPitchDelayMin) != 1) break; + if (fscanf(fpInput,"%hd,",&intPitchDelayMax) != 1) break; + if (fscanf(fpInput,"%d",&subFrameIndex) != 1) break; + + /* call the tested funtion */ + adaptativeCodebookSearch(&(excitationVector[L_PAST_EXCITATION + subFrameIndex]), &intPitchDelayMin, &intPitchDelayMax, impulseResponse, targetSignal, + &intPitchDelay, &fracPitchDelay, &adaptativeCodebookIndex, subFrameIndex); + + /* write the output to the output file : intPitchDelay, fracPitchDelay, intPitchDelayMin, intPitchDelayMax, adaptativeCodebookIndex, adaptative codebook vector */ + fprintf(fpOutput, "%d,%d,%d,%d,%d,%d", intPitchDelay, fracPitchDelay, intPitchDelayMin, intPitchDelayMax, adaptativeCodebookIndex, excitationVector[L_PAST_EXCITATION+subFrameIndex]); + for (i=1; i +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "computeAdaptativeCodebookGain.h" + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + word16_t targetSignal[L_SUBFRAME]; + word16_t filteredAdaptativeCodebookVector[L_SUBFRAME]; + /* outputs : */ + word16_t adaptativeCodebookGain; + + /* these buffers are part of the output but not of the pattern as they aren't scaled the same way the ITU code does. */ + word64_t gainQuantizationXy, gainQuantizationYy; /* used to store in Q0 values reused in gain quantization */ + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "r")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "w")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + + /* initialise buffers */ + + /*** initialisation complete ***/ + + + /*** loop over input file ***/ + while(1) /* infinite loop, escape condition is in the reading of data */ + { + int i; + /* read the input data until we have some */ + if (fscanf(fpInput,"%hd",&(filteredAdaptativeCodebookVector[0])) != 1) break; + for (i=1; i +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "computeLP.h" + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + word16_t inputBuffer[L_LP_ANALYSIS_WINDOW]; + word16_t LPCoefficients[NB_LSP_COEFF]; + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "r")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "w")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + + /*** initialisation complete ***/ + + + /*** loop over input file ***/ + while(1) /* infinite loop, escape condition is in the reading of data */ + { + int i; + /* read the input data until we have some */ + if (fscanf(fpInput,"%hd",&(inputBuffer[0])) != 1) break; + for (i=1; i +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "computeWeightedSpeech.h" + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + word16_t inputBuffer[NB_LSP_COEFF+L_FRAME]; /* buffer containing the input signal including 10 values from last frame in range [-10, 0[ */ + word16_t outputBuffer[NB_LSP_COEFF+L_FRAME]; /* same as input buffer, the values in range [-10,0[ are input */ + word16_t qLPCoefficients[2*NB_LSP_COEFF]; /* qLP coefficients in Q12: input */ + word16_t weightedqLPCoefficients[2*NB_LSP_COEFF]; /* weightedqLP coefficients in Q12: input */ + word16_t LPResidualSignal[L_FRAME]; /* LP Residual signal in Q0: ouput*/ + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "rb")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "wb")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + + /*** initialisation complete ***/ + + + /*** loop over input file ***/ + while(1) /* infinite loop, escape condition is in the reading of data */ + { + int i; + /*** read the input data until we have some ***/ + /* read the input signal */ + if (fscanf(fpInput,"%hd",&(inputBuffer[0])) != 1) break; + for (i=1; i +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "decodeAdaptativeCodeVector.h" + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + /* input file: frameErasureFlag, subframeIndex, P1/2, P0, pastExcitationVector: 154 values */ + /* output is in the excitationVector */ + int16_t frameErasureFlag; + int subFrameIndex; + uint16_t adaptativeCodebookIndex; + int16_t parityFlag; + word16_t excitationVector[L_PAST_EXCITATION + L_FRAME]; /* this vector contains: + 0->153 : the past excitation vector.(length is Max Pitch Delay: 144 + interpolation window size : 10) + 154-> 154+L_FRAME-1 : the current frame adaptative Code Vector first used to compute then the excitation vector */ + int16_t intPitchDelay; /* output of the function when called for subframe wich is sent back as an input for subframe2 */ + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "r")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "w")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + /* create the context structure */ + bcg729DecoderChannelContextStruct *decoderChannelContext = malloc(sizeof(bcg729DecoderChannelContextStruct)); + + initDecodeAdaptativeCodeVector(decoderChannelContext); + + /* initialise buffers */ + /* actually useless init, because the complete excitation buffer is reload at each subframe from input file, but shall be done in real decoder */ + memset(excitationVector, 0, L_PAST_EXCITATION*sizeof(word16_t)); /* initialise the part of the excitationVector containing the past excitation */ + + + /*** initialisation complete ***/ + + + /*** loop over input file ***/ + while(1) /* infinite loop, escape condition is in the reading of data */ + { + int i; + /* read the input data until we have some */ + if (fscanf(fpInput,"%hd",&frameErasureFlag) != 1) break; + if (fscanf(fpInput,",%d",&subFrameIndex) != 1) break; + if (fscanf(fpInput,",%hd",&adaptativeCodebookIndex) != 1) break; + if (fscanf(fpInput,",%hd",&parityFlag) != 1) break; + for (i=0; i<194; i++) { + if (fscanf(fpInput,",%hd",&(excitationVector[i])) != 1) break; + } + + /* call the tested funtion */ + decodeAdaptativeCodeVector(decoderChannelContext, subFrameIndex, adaptativeCodebookIndex, (uint8_t)parityFlag, (uint8_t)frameErasureFlag, + &intPitchDelay, &(excitationVector[L_PAST_EXCITATION + subFrameIndex])); + + + /* write the output to the output file */ + fprintf(fpOutput,"%d",excitationVector[L_PAST_EXCITATION + subFrameIndex]); + for (i=1; i +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "decodeFixedCodeVector.h" + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + /* input file: Positions(C parameter 13 bits), Signs(S parameter 4 bits), boundedPitchGain, intPitchDelay */ + /* output: fixedCodebookVector: subframe length vector in Q13 */ + int16_t signs; + int16_t positions; + word16_t boundedPitchGain; + int16_t intPitchDelay; + + word16_t fixedCodebookVector[L_SUBFRAME]; + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "r")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "w")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + + /* initialise buffers */ + + /*** initialisation complete ***/ + + + /*** loop over input file ***/ + while(fscanf(fpInput,"%hd,%hd,%hd,%hd", &positions, &signs, &boundedPitchGain, &intPitchDelay) == 4) /* loop until end of input data */ + { + int i; + + /* call the tested funtion */ + decodeFixedCodeVector((uint16_t)signs, (uint16_t)positions, (int16_t)intPitchDelay, (word16_t)boundedPitchGain, fixedCodebookVector); + + + /* write the output to the output file */ + fprintf(fpOutput,"%d",fixedCodebookVector[0]); + for (i=1; i +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "decodeGains.h" + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + /* input file: GA, GB, frameErasureFlag, fixedCodebookVector, adaptative codebook gain, fixed codebook gain */ + /* output : adaptative codebook gain, adaptative codebook gain */ + int16_t GA, GB; + int16_t frameErasureFlag; + word16_t fixedCodebookVector[L_SUBFRAME]; + word16_t adaptativeCodebookGain, fixedCodebookGain; + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "r")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "w")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + /* create the context structure */ + bcg729DecoderChannelContextStruct *decoderChannelContext = malloc(sizeof(bcg729DecoderChannelContextStruct)); + + initDecodeGains(decoderChannelContext); + + /* initialise buffers */ + + /*** initialisation complete ***/ + + + /*** loop over input file ***/ + while(1) /* infinite loop, escape condition is in the reading of data */ + { + int i; + /* read the input data until we have some */ + if (fscanf(fpInput,"%hd",&GA) != 1) break; + if (fscanf(fpInput,",%hd",&GB) != 1) break; + if (fscanf(fpInput,",%hd",&frameErasureFlag) != 1) break; + if (fscanf(fpInput,",%hd",&adaptativeCodebookGain) != 1) break; + if (fscanf(fpInput,",%hd",&fixedCodebookGain) != 1) break; + for (i=0; i +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "decodeLSP.h" + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + uint16_t inputBuffer[4]; /* input buffer: an array containing the 4 L coefficients */ + word16_t frameErasedIndicator; /* part of the input file */ + word16_t outputBuffer[NB_LSP_COEFF]; /* output buffer: the quantized LSF coefficients in Q0.15 */ + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "r")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "w")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + /* create the context structure */ + bcg729DecoderChannelContextStruct *decoderChannelContext = malloc(sizeof(bcg729DecoderChannelContextStruct)); + initDecodeLSP(decoderChannelContext); + + /*** initialisation complete ***/ + + + /*** loop over input file ***/ + while(fscanf(fpInput, "%hd,%hd,%hd,%hd,%hd", &frameErasedIndicator, &(inputBuffer[0]), &(inputBuffer[1]), &(inputBuffer[2]), &(inputBuffer[3]))==5) + { + /* call the decodeLSP function */ + decodeLSP(decoderChannelContext, inputBuffer, outputBuffer, frameErasedIndicator); + + /* write the output to the output file */ + fprintf(fpOutput,"%d",outputBuffer[0]); + int i; + for (i=1; i +#include +#include + +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" +#include "utils.h" + +#include "testUtils.h" + +#include "bcg729/decoder.h" + +#define MAX_CHANNEL_NBR 50 +int main(int argc, char *argv[] ) +{ + int i; + /*** get calling argument ***/ + char *filePrefix[MAX_CHANNEL_NBR]; + getArgumentsMultiChannel(argc, argv, filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput[MAX_CHANNEL_NBR]; + FILE *fpOutput[MAX_CHANNEL_NBR]; + FILE *fpBinOutput[MAX_CHANNEL_NBR]; + + /*** input and output buffers ***/ + uint16_t inputBuffer[NB_PARAMETERS+1]; /* input buffer: an array containing the 15 parameters and the frame erasure flag */ + int16_t outputBuffer[L_FRAME]; /* output buffer: the reconstructed signal */ + uint8_t bitStream[10]; /* binary input for the decoder */ + bcg729DecoderChannelContextStruct *decoderChannelContext[MAX_CHANNEL_NBR]; /* context array, one per channel */ + + /*** inits ***/ + for (i=0; i +#include +#include + +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" +#include "utils.h" + +#include "testUtils.h" + +#include "bcg729/decoder.h" + + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + FILE *fpBinOutput; + + /*** input and output buffers ***/ + uint16_t inputBuffer[NB_PARAMETERS+1]; /* input buffer: an array containing the 15 parameters and the frame erasure flag */ + uint8_t bitStream[10]; /* binary input for the decoder */ + int16_t outputBuffer[L_FRAME]; /* output buffer: the reconstructed signal */ + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "r")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "w")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + sprintf(outputFile, "%s.pcm",filePrefix); + if ( (fpBinOutput = fopen(outputFile, "wb")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + bcg729DecoderChannelContextStruct *decoderChannelContext = initBcg729DecoderChannel(); + + /*** initialisation complete ***/ + /* perf measurement */ + clock_t start, end; + double cpu_time_used=0.0; + int framesNbr =0; +/* increase LOOP_N to increase input length and perform a more accurate profiling or perf measurement */ +#define LOOP_N 1 + int j; + for (j=0; j +#include +#include + +#include + + +#include "typedef.h" +#include "codecParameters.h" +#include "utils.h" + +#include "testUtils.h" + +#include "bcg729/encoder.h" + +#define MAX_CHANNEL_NBR 50 +int main(int argc, char *argv[] ) +{ + int i,j,k; + + /*** get calling argument ***/ + char *filePrefix[MAX_CHANNEL_NBR]; + getArgumentsMultiChannel(argc, argv, filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput[MAX_CHANNEL_NBR]; + FILE *fpOutput[MAX_CHANNEL_NBR]; + + /*** input and output buffers ***/ + int16_t inputBuffer[L_FRAME]; /* output buffer: the signal */ + uint16_t outputBuffer[NB_PARAMETERS]; /* output buffer: an array containing the 15 parameters */ + uint8_t bitStream[10]; /* binary output of the encoder */ + bcg729EncoderChannelContextStruct *encoderChannelContext[MAX_CHANNEL_NBR]; /* context, one per channel */ + uint16_t inputIsBinary[MAX_CHANNEL_NBR]; /* store the information on each input file format (CVS or binary PCM) */ + + + /*** inits ***/ + /* open the input file */ + for (i=0; i +#include +#include + +#include + + +#include "typedef.h" +#include "codecParameters.h" +#include "utils.h" + +#include "testUtils.h" + +#include "bcg729/encoder.h" + +FILE *fpOutput; + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + + /*** input and output buffers ***/ + int16_t inputBuffer[L_FRAME]; /* output buffer: the signal */ + uint8_t bitStream[10]; /* binary output of the encoder */ + uint16_t outputBuffer[NB_PARAMETERS]; /* output buffer: an array containing the 15 parameters */ + + /*** inits ***/ + /* open the input file */ + uint16_t inputIsBinary = 0; + if (argv[1][strlen(argv[1])-1] == 'n') { /* input filename and by n, it's probably a .in : CSV file */ + if ( (fpInput = fopen(argv[1], "r")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + } else { /* it's probably a binary file */ + inputIsBinary = 1; + if ( (fpInput = fopen(argv[1], "rb")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "w")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + bcg729EncoderChannelContextStruct *encoderChannelContext = initBcg729EncoderChannel(); + + /*** initialisation complete ***/ + /* perf measurement */ + clock_t start, end; + double cpu_time_used=0.0; + int framesNbr =0; +/* increase LOOP_N to increase input length and perform a more accurate profiling or perf measurement */ +#define LOOP_N 1 + int j; + for (j=0; j +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "findOpenLoopPitchDelay.h" + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + word16_t inputBuffer[MAXIMUM_INT_PITCH_DELAY+L_FRAME]; /* 40 values in Q0 */ + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "rb")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "wb")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + + /*** initialisation complete ***/ + + + /*** loop over input file ***/ + while(1) /* infinite loop, escape condition is in the reading of data */ + { + int i; + /* read the input data until we have some */ + if (fscanf(fpInput,"%hd",&(inputBuffer[0])) != 1) break; + for (i=1; i +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "fixedCodebookSearch.h" + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + /* inputs : */ + word16_t targetSignal[L_SUBFRAME]; /* Q0 */ + word16_t impulseResponse[L_SUBFRAME]; /* Q12 */ + int16_t intPitchDelay; + word16_t lastQuantizedAdaptativeCodebookGain, adaptativeCodebookGain; /* Q14 */ + word16_t filteredAdaptativeCodebookVector[L_SUBFRAME]; /* Q0 */ + /* outputs : */ + uint16_t fixedCodebookParameter, fixedCodebookPulsesSigns; + word16_t fixedCodebookVector[L_SUBFRAME]; + word16_t fixedCodebookVectorConvolved[L_SUBFRAME]; + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "r")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "w")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + + /* initialise buffers */ + + /*** initialisation complete ***/ + + + /*** loop over input file ***/ + while(1) /* infinite loop, escape condition is in the reading of data */ + { + int i; + /* read the input data until we have some */ + for (i=0; i<40; i++) { + if (fscanf(fpInput,"%hd,",&(targetSignal[i])) != 1) break; + } + for (i=0; i<40; i++) { + if (fscanf(fpInput,"%hd,",&(impulseResponse[i])) != 1) break; + } + if (fscanf(fpInput,"%hd,",&intPitchDelay) != 1) break; + if (fscanf(fpInput,"%hd,",&lastQuantizedAdaptativeCodebookGain) != 1) break; + for (i=0; i<40; i++) { + if (fscanf(fpInput,"%hd,",&(filteredAdaptativeCodebookVector[i])) != 1) break; + } + if (fscanf(fpInput,"%hd",&adaptativeCodebookGain) != 1) break; + + /* call the tested funtion */ + fixedCodebookSearch(targetSignal, impulseResponse, intPitchDelay, lastQuantizedAdaptativeCodebookGain, filteredAdaptativeCodebookVector, adaptativeCodebookGain, + &fixedCodebookParameter, &fixedCodebookPulsesSigns, fixedCodebookVector, fixedCodebookVectorConvolved); + + + /* write the output to the output file : fixedCodebookParameter, fixedCodebookPulsesSigns, fixedCodebookVector */ + fprintf(fpOutput, "%d,%d,%d", fixedCodebookParameter, fixedCodebookPulsesSigns, fixedCodebookVector[0]); + for (i=1; i +#include +#include "g729FixedPointMath.h" +#include "math.h" + +#include "typedef.h" +#include "codecParameters.h" + +/* convert the float result from math.h to a fixed point integer in Qxx */ +word32_t float2FixedPoint(float x, int Q) +{ + return (word32_t)round((double)x*(double)(1<maxDiff) { + maxDiff = currentDiff; + maxDiffIndex = i; + } + if (currentDiffPercent>maxDiffPercent) { + maxDiffPercent = currentDiffPercent; + maxDiffIndexPercent = i; + } + } + printf ("Log2 : %d computation\n Mean Diff %f Mean Percent Diff %f\n Max Diff %d(%d) Max Percent Diff %f(%d)\n", + computationNumber, diffSum/computationNumber, diffSumPercent/computationNumber, maxDiff, maxDiffIndex, maxDiffPercent, maxDiffIndexPercent); + + /* g729Exp2_Q11Q16 : Exponentiel base 2 */ + computationNumber = 0; + diffSum = 0; + diffSumPercent = 0; + maxDiff = 0; + maxDiffIndex = -1; + maxDiffPercent = 0; + maxDiffIndexPercent = -1; + + for (i=0; i<2048; i+=0x1) { + computationNumber++; + word32_t resg729 = g729Exp2_Q11Q16((word32_t)i); + word32_t resMath = float2FixedPoint(exp2f(fixedPoint2Float(i,11)), 16); + int currentDiff = abs(resg729-resMath); + double currentDiffPercent = 0; + if (resMath!=0 && resg729!=0 && currentDiff!=0) currentDiffPercent = 100.0*currentDiff/(float)resMath; + diffSum += currentDiff; + diffSumPercent += currentDiffPercent; + if (currentDiff>maxDiff) { + maxDiff = currentDiff; + maxDiffIndex = i; + } + if (currentDiffPercent>maxDiffPercent) { + maxDiffPercent = currentDiffPercent; + maxDiffIndexPercent = i; + } + } + printf ("Exp2 : %d computation\n Mean Diff %f Mean Percent Diff %f\n Max Diff %d(%d) Max Percent Diff %f(%d)\n", + computationNumber, diffSum/computationNumber, diffSumPercent/computationNumber, maxDiff, maxDiffIndex, maxDiffPercent, maxDiffIndexPercent); + + + /* g729Sqrt_Q0Q7 : Square Root */ + computationNumber = 0; + diffSum = 0; + diffSumPercent = 0; + maxDiff = 0; + maxDiffIndex = -1; + maxDiffPercent = 0; + maxDiffIndexPercent = -1; + + for (i=0; i<0x7FFFFFF; i+=0x8) { + computationNumber++; + word32_t resg729 = g729Sqrt_Q0Q7((word32_t)i); + word32_t resMath = float2FixedPoint(sqrtf(i), 7); + int currentDiff = abs(resg729-resMath); + double currentDiffPercent = 0; + if (resMath!=0 && resg729!=0 && currentDiff!=0) currentDiffPercent = 100.0*currentDiff/(float)resMath; + diffSum += currentDiff; + diffSumPercent += currentDiffPercent; + if (currentDiff>maxDiff) { + maxDiff = currentDiff; + maxDiffIndex = i; + } + if (currentDiffPercent>maxDiffPercent) { + maxDiffPercent = currentDiffPercent; + maxDiffIndexPercent = i; + } + } + printf ("Square Root : %d computation\n Mean Diff %f Mean Percent Diff %f\n Max Diff %d(%d) Max Percent Diff %f(%d)\n", + computationNumber, diffSum/computationNumber, diffSumPercent/computationNumber, maxDiff, maxDiffIndex, maxDiffPercent, maxDiffIndexPercent); + + /* g729InvSqrt_Q0Q30 : Inverse Square Root */ + computationNumber = 0; + diffSum = 0; + diffSumPercent = 0; + maxDiff = 0; + maxDiffIndex = -1; + maxDiffPercent = 0; + maxDiffIndexPercent = -1; + + for (i=1; i<0x7FFFFFF; i+=0x8) { + computationNumber++; + word32_t resg729 = g729InvSqrt_Q0Q31((word32_t)i)>>1; + word32_t resMath = float2FixedPoint(1.0/sqrtf(i), 30); + int currentDiff = abs(resg729-resMath); + double currentDiffPercent = 0; + if (resMath!=0 && resg729!=0 && currentDiff!=0) currentDiffPercent = 100.0*currentDiff/(float)resMath; + diffSum += currentDiff; + diffSumPercent += currentDiffPercent; + if (currentDiff>maxDiff) { + maxDiff = currentDiff; + maxDiffIndex = i; + } + if (currentDiffPercent>maxDiffPercent) { + maxDiffPercent = currentDiffPercent; + maxDiffIndexPercent = i; + } + } + printf ("Inverse Square Root : %d computation\n Mean Diff %f Mean Percent Diff %f\n Max Diff %d(%d) Max Percent Diff %f(%d)\n", + computationNumber, diffSum/computationNumber, diffSumPercent/computationNumber, maxDiff, maxDiffIndex, maxDiffPercent, maxDiffIndexPercent); + + /* g729Cos_Q13Q15 : Cosine */ + computationNumber = 0; + diffSum = 0; + diffSumPercent = 0; + maxDiff = 0; + maxDiffIndex = -1; + maxDiffPercent = 0; + maxDiffIndexPercent = -1; + + for (i=0; i<25736; i+=0x1) { + computationNumber++; + word32_t resg729 = g729Cos_Q13Q15((word32_t)i); + word32_t resMath = float2FixedPoint(cosf(fixedPoint2Float(i,13)), 15); + int currentDiff = abs(resg729-resMath); + double currentDiffPercent = 0; + if (resMath!=0 && resg729!=0 && currentDiff!=0) currentDiffPercent = 100.0*currentDiff/(float)resMath; + diffSum += currentDiff; + diffSumPercent += currentDiffPercent; + if (currentDiff>maxDiff) { + maxDiff = currentDiff; + maxDiffIndex = i; + } + if (currentDiffPercent>maxDiffPercent) { + maxDiffPercent = currentDiffPercent; + maxDiffIndexPercent = i; + } + } + printf ("Cosine : %d computation\n Mean Diff %f Mean Percent Diff %f\n Max Diff %d(%d) Max Percent Diff %f(%d)\n", + computationNumber, diffSum/computationNumber, diffSumPercent/computationNumber, maxDiff, maxDiffIndex, maxDiffPercent, maxDiffIndexPercent); + + /* g729Atan_Q15Q13 : Arc Tangent */ + computationNumber = 0; + diffSum = 0; + diffSumPercent = 0; + maxDiff = 0; + maxDiffIndex = -1; + maxDiffPercent = 0; + maxDiffIndexPercent = -1; + + for (i=-0x8000000; i<0x7ffffff; i+=0x1) { + computationNumber++; + word32_t resg729 = g729Atan_Q15Q13((word32_t)i); + word32_t resMath = float2FixedPoint(atanf(fixedPoint2Float(i,15)), 13); + int currentDiff = abs(resg729-resMath); + double currentDiffPercent = 0; + if (resMath!=0 && resg729!=0 && currentDiff!=0) currentDiffPercent = 100.0*currentDiff/(float)resMath; + diffSum += currentDiff; + diffSumPercent += currentDiffPercent; + if (currentDiff>maxDiff) { + maxDiff = currentDiff; + maxDiffIndex = i; + } + if (currentDiffPercent>maxDiffPercent) { + maxDiffPercent = currentDiffPercent; + maxDiffIndexPercent = i; + } + } + printf ("Arc Tangent : %d computation\n Mean Diff %f Mean Percent Diff %f\n Max Diff %d(%d) Max Percent Diff %f(%d)\n", + computationNumber, diffSum/computationNumber, diffSumPercent/computationNumber, maxDiff, maxDiffIndex, maxDiffPercent, maxDiffIndexPercent); + + + /* g729Asin_Q15Q13 : Arc Sine */ + computationNumber = 0; + diffSum = 0; + diffSumPercent = 0; + maxDiff = 0; + maxDiffIndex = -1; + maxDiffPercent = 0; + maxDiffIndexPercent = -1; + + for (i=-0x7fff; i<0x7ffe; i+=0x1) { + computationNumber++; + word32_t resg729 = g729Asin_Q15Q13((word32_t)i); + word32_t resMath = float2FixedPoint(asinf(fixedPoint2Float(i,15)), 13); + int currentDiff = abs(resg729-resMath); + double currentDiffPercent = 0; + if (resMath!=0 && resg729!=0 && currentDiff!=0) currentDiffPercent = 100.0*currentDiff/(float)resMath; + diffSum += currentDiff; + diffSumPercent += currentDiffPercent; + if (currentDiff>maxDiff) { + maxDiff = currentDiff; + maxDiffIndex = i; + } + if (currentDiffPercent>maxDiffPercent) { + maxDiffPercent = currentDiffPercent; + maxDiffIndexPercent = i; + } + } + printf ("Arc Sine : %d computation\n Mean Diff %f Mean Percent Diff %f\n Max Diff %d(%d) Max Percent Diff %f(%d)\n", + computationNumber, diffSum/computationNumber, diffSumPercent/computationNumber, maxDiff, maxDiffIndex, maxDiffPercent, maxDiffIndexPercent); + + + + /* g729Acos_Q15Q13 : Arc Cosine */ + computationNumber = 0; + diffSum = 0; + diffSumPercent = 0; + maxDiff = 0; + maxDiffIndex = -1; + maxDiffPercent = 0; + maxDiffIndexPercent = -1; + + for (i=-0x7fff; i<0x7ffe; i+=0x1) { + computationNumber++; + word32_t resg729 = g729Acos_Q15Q13((word32_t)i); + word32_t resMath = float2FixedPoint(acosf(fixedPoint2Float(i,15)), 13); + int currentDiff = abs(resg729-resMath); + double currentDiffPercent = 0; + if (resMath!=0 && resg729!=0 && currentDiff!=0) currentDiffPercent = 100.0*currentDiff/(float)resMath; + diffSum += currentDiff; + diffSumPercent += currentDiffPercent; + if (currentDiff>maxDiff) { + maxDiff = currentDiff; + maxDiffIndex = i; + } + if (currentDiffPercent>maxDiffPercent) { + maxDiffPercent = currentDiffPercent; + maxDiffIndexPercent = i; + } + } + printf ("Arc Cosine : %d computation\n Mean Diff %f Mean Percent Diff %f\n Max Diff %d(%d) Max Percent Diff %f(%d)\n", + computationNumber, diffSum/computationNumber, diffSumPercent/computationNumber, maxDiff, maxDiffIndex, maxDiffPercent, maxDiffIndexPercent); + + + + +exit (0); +} diff --git a/test/src/gainQuantizationTest.c b/test/src/gainQuantizationTest.c new file mode 100644 index 0000000..25200a4 --- /dev/null +++ b/test/src/gainQuantizationTest.c @@ -0,0 +1,128 @@ +/* + gainQuantizationTest.c + + Copyright (C) 2011 Belledonne Communications, Grenoble, France + Author : Johan Pascal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/*****************************************************************************/ +/* */ +/* Test Program for gainQuantization bloc */ +/* Input: */ +/* -(i) targetSignal: 40 values in Q0, x in eq63 */ +/* -(i) filteredAdaptativeCodebookVector: 40 values in Q0, y in eq63 */ +/* -(i) convolvedFixedCodebookVector: 40 values in Q12, z in eq63 */ +/* -(i) fixedCodebookVector: 40 values in Q13 */ +/* -(i) xy in Q0 on 64 bits term of eq63 computed previously */ +/* -(i) yy in Q0 on 64 bits term of eq63 computed previously */ +/* */ +/* Ouput: */ +/* -(o) quantizedAdaptativeCodebookGain : in Q14 */ +/* -(o) quantizedFixedCodebookGain : in Q1 */ +/* -(o) gainCodebookStage1 : GA parameter value (3 bits) */ +/* -(o) gainCodebookStage2 : GB parameter value (4 bits) */ +/* */ +/*****************************************************************************/ + +#include +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "gainQuantization.h" + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + /* inputs : */ + word16_t targetSignal[L_SUBFRAME]; /* Q0 */ + word16_t filteredAdaptativeCodebookVector[L_SUBFRAME]; /* Q0 */ + word16_t convolvedFixedCodebookVector[L_SUBFRAME]; /* Q12 */ + word16_t fixedCodebookVector[L_SUBFRAME]; /* Q13 */ + word64_t xy, yy; /* Q0 */ + /* outputs : */ + word16_t quantizedAdaptativeCodebookGain, quantizedFixedCodebookGain; /* Q14 */ + uint16_t gainCodebookStage1, gainCodebookStage2; + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "r")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "w")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + /* create the context structure */ + bcg729EncoderChannelContextStruct *encoderChannelContext = malloc(sizeof(bcg729EncoderChannelContextStruct)); + + initGainQuantization(encoderChannelContext); + + /* initialise buffers */ + + /*** initialisation complete ***/ + + + /*** loop over input file ***/ + while(1) /* infinite loop, escape condition is in the reading of data */ + { + int i; + /* read the input data until we have some */ + if (fscanf(fpInput,"%lld,%lld",(long long*)&xy,(long long*) &yy) != 2) break; + for (i=0; i +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "interpolateqLSP.h" +#include "qLSP2LP.h" + +/* buffers allocation */ +static word16_t previousqLSP[NB_LSP_COEFF]; +static const word16_t previousqLSPInitialValues[NB_LSP_COEFF] = {30000, 26000, 21000, 15000, 8000, 0, -8000,-15000,-21000,-26000}; /* in Q0.15 the initials values for the previous qLSP buffer */ + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + word16_t inputBuffer[NB_LSP_COEFF]; /* input buffer: an array containing the 10 qLSP coefficients for the current frame */ + word16_t outputBuffer[2*NB_LSP_COEFF]; /* output buffer: the LP coefficients in Q2.13 for subframe 1 and 2 (20 LP coefficients)*/ + + word16_t interpolatedqLSP[NB_LSP_COEFF]; /* the interpolated qLSP used to produce 1st subframe LP */ + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "r")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "w")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + /* initialise buffers */ + memcpy(previousqLSP, previousqLSPInitialValues, NB_LSP_COEFF*sizeof(word16_t)); /* initialise the previousqLSP buffer */ + + /*** initialisation complete ***/ + + + /*** loop over input file ***/ + while(fscanf(fpInput, "%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd", &(inputBuffer[0]), &(inputBuffer[1]), &(inputBuffer[2]), &(inputBuffer[3]), &(inputBuffer[4]), &(inputBuffer[5]), &(inputBuffer[6]), &(inputBuffer[7]), &(inputBuffer[8]), &(inputBuffer[9]))==10) + { /* input buffer contains current qLSP */ + + /* call the interpolate function, result will be stored in the interpolatedqLSP buffer */ + interpolateqLSP(previousqLSP, inputBuffer, interpolatedqLSP); + + int i; + /* copy the currentqLSP to previousqLSP buffer */ + for (i=0; i +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "postFilter.h" + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + /* input file: 10 LP Coefficients(Q12), 50 reconstructedSpeech, intPitchDelay (Q0), subframeIndex(0/40) */ + word16_t LP[NB_LSP_COEFF]; + word16_t reconstructedSpeech[NB_LSP_COEFF+L_SUBFRAME]; /* in Q0, output of the LP synthesis filter, the first 10 words store the previous subframe output */ + int16_t intPitchDelay; + int16_t subframeIndex; + + /* output postFiltered signal(40 values in Q0) */ + word16_t postFilteredSignal[L_SUBFRAME]; + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "r")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "w")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + /* create the context structure */ + bcg729DecoderChannelContextStruct *decoderChannelContext = malloc(sizeof(bcg729DecoderChannelContextStruct)); + + initPostFilter(decoderChannelContext); + + /* initialise buffers */ + /* past reconstructedSpeech values shall be initialised, but we read them directly from input file */ + + /*** initialisation complete ***/ + + + /*** loop over input file ***/ + while(1) /* infinite loop, escape condition is in the reading of data */ + { + int i; + /* read the input data as long as we find some */ + if (fscanf(fpInput,"%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd",&LP[0],&LP[1],&LP[2],&LP[3],&LP[4],&LP[5],&LP[6],&LP[7],&LP[8],&LP[9]) != 10) break; + for (i=0; i +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "postProcessing.h" + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + /* output buffer is the same than input buffer */ + word16_t inputBuffer[L_SUBFRAME]; /* 40 values in Q0 */ + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "rb")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "wb")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + /* create the context structure */ + bcg729DecoderChannelContextStruct *decoderChannelContext = malloc(sizeof(bcg729DecoderChannelContextStruct)); + + initPostProcessing(decoderChannelContext); + + /*** initialisation complete ***/ + + + /*** loop over input file ***/ + while(1) /* infinite loop, escape condition is in the reading of data */ + { + int i; + /* read the input data until we have some */ + if (fscanf(fpInput,"%hd",&(inputBuffer[0])) != 1) break; + for (i=1; i +#include +#include + + +#include "typedef.h" +#include "codecParameters.h" + +#include "testUtils.h" + +#include "preProcessing.h" + +int main(int argc, char *argv[] ) +{ + /*** get calling argument ***/ + char *filePrefix; + getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */ + + /*** input and output file pointers ***/ + FILE *fpInput; + FILE *fpOutput; + + /*** input and output buffers ***/ + word16_t inputBuffer[L_FRAME]; + word16_t outputBuffer[L_FRAME]; + + /*** inits ***/ + /* open the input file */ + if ( (fpInput = fopen(argv[1], "rb")) == NULL) { + printf("%s - Error: can't open file %s\n", argv[0], argv[1]); + exit(-1); + } + + /* create the output file(filename is the same than input file with the .out extension) */ + char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char)); + sprintf(outputFile, "%s.out",filePrefix); + if ( (fpOutput = fopen(outputFile, "wb")) == NULL) { + printf("%s - Error: can't create file %s\n", argv[0], outputFile); + exit(-1); + } + + /*** init of the tested bloc ***/ + /* create the context structure */ + bcg729EncoderChannelContextStruct *encoderChannelContext = malloc(sizeof(bcg729EncoderChannelContextStruct)); + + initPreProcessing(encoderChannelContext); + + /*** initialisation complete ***/ + + + /*** loop over input file ***/ + while(1) /* infinite loop, escape condition is in the reading of data */ + { + int i; + /* read the input data until we have some */ + if (fscanf(fpInput,"%hd",&(inputBuffer[0])) != 1) break; + for (i=1; i +#include +#include + + +#include "typedef.h" + +void printUsage(char *command) +{ + printf ("Usage:\n %s -p|\n\n This executable request one argument either:\n -p : display the computation type(fixed or floating) and exit\nor\n : process the input file and write the output in a file with the same prefix a .out extension\n\n",command); + exit (-1); + +} + +int getArgument(int argc, char *argv[], char** filePrefix) +{ + /* We have only one argument wich can be either the input filename or -p which will answer either floating or fixed according */ + /* computation mode being fixed or floating point */ + if (argc != 2) { + printUsage(argv[0]); + exit (-1); + } + + if (argv[1][0] == '-') { + if (argv[1][1] == 'p') { /* -p switch, return fixed or floating and exit */ +#ifdef FLOATING_POINT + printf ("floating\n"); +#else /* ifdef FLOATING_POINT */ + printf ("fixed\n"); +#endif /* ifdef FLOATING_POINT */ + exit(0); + } else { /* unknow switch, display usage and exit */ + printUsage(argv[0]); + exit (-1); + } + } else { /* argument is the input file */ + /* get the input file prefix */ + int i = strlen(argv[1])-1; + int pos = 0; + while (pos==0) { + if (argv[1][i]=='.') { + pos = i; + } + i--; + if (i==0) { + printf("%s - Error input file %s doesn't contain any ., impossible to extract prefix\n", argv[0], argv[1]); + exit(-1); + } + } + *filePrefix = malloc((pos+3)*sizeof(char)); + strncpy(*filePrefix, argv[1], pos); + (*filePrefix)[pos]='\0'; + } + + return 0; +} + +int getArgumentsMultiChannel(int argc, char *argv[], char *filePrefix[]) +{ + while (argc>1) { /* loop over all the argument which shall be input file names */ + argc--; + /* get the input file prefix */ + int i = strlen(argv[argc])-1; + int pos = 0; + while (pos==0) { + if (argv[argc][i]=='.') { + pos = i; + } + i--; + if (i==0) { + printf("%s - Error input file %s doesn't contain any ., impossible to extract prefix\n", argv[0], argv[argc]); + exit(-1); + } + } + + filePrefix[argc-1] = malloc((pos+3)*sizeof(char)); + + strncpy(filePrefix[argc-1], argv[argc], pos); + filePrefix[argc-1][pos]='\0'; + } + + return 0; +} diff --git a/test/src/testUtils.h b/test/src/testUtils.h new file mode 100644 index 0000000..b1c27dd --- /dev/null +++ b/test/src/testUtils.h @@ -0,0 +1,3 @@ +void printUsage(char *command); +int getArgument(int argc, char *argv[], char** filePrefix); +int getArgumentsMultiChannel(int argc, char *argv[], char *filePrefix[]); diff --git a/test/testCampaign b/test/testCampaign new file mode 100755 index 0000000..54e5e0f --- /dev/null +++ b/test/testCampaign @@ -0,0 +1,259 @@ +#!/usr/bin/perl -w +use Term::ANSIColor; +# testCampaign +# +# Copyright (C) 2011 Belledonne Communications, Grenoble, France +# Author : Johan Pascal +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# This script allow testing of g729 encoder/decoder functional blocs +# by default each bloc output is supposed to be identical to the pattern +# it can be configured to monitor and accept a (setable) difference between output +# and pattern(which can occur if a bloc or macros are modified). +# Tune the defaultMaxDiff associative array definition to modify +# the behavior of this script for any functional bloc under test + +my $binDirectory = "./bin/"; +my $patternDirectory = "./patterns"; +# softDiff: compare two CSV files with a margin of acceptance between the values found +# arguments : file1, file2, maximumDiff tolerated(value), maximum percentage abs((val1-val2)/val1)*100 tolerated +# maximum condition ignored when set to 0 so it might be used: +# - with one maximum condition +# - with both maximum condition : trigger a warning if both maxima are exceded + +sub softDiff +{ + my $filename1 = shift; + my $filename2 = shift; + my $maxDiff = shift; + my $percentMaxDiff = shift; + my $printStats = shift; + + # open the file1 and file2 + open (FP1, $filename1) or die "Can't open $filename1: $!"; + open (FP2, $filename2) or die "Can't open $filename2: $!"; + + # remove path from filename2 as it might be used in error report + $filename2 =~ s/.*\/(.*?)\..*$/$1/; + + # total values number count variables for stats + my $nbr_values = 0; + my $total_diff = 0; + my $total_values = 0; + my $maxMaxDiff = 0; + my $maxPercentDiff = 0; + + # boolean for return value: 0 no warning, 1 warning(s) + my $warnings = 0; + + # loop over file1 + while() { + # get line number to display in potential message + my $lineNb = $.; + # get file1 and file2 CSV line into an array + my @line1 = (); + my @line2 = (); + @line1 = split (',', $_); + @line2 = split (',', ); + + # check they have the same number of values + my $line1length = @line1; + my $line2length = @line2; + if ($line1length != $line2length) { + die "at line $., $filename1 and $filename2 doesn't have the same number of values"; + } + + # loop on the values and compare them + for (my $i=0; $i<$line1length; $i++) { + chomp($line1[$i]); + chomp($line2[$i]); + my $diff = abs($line1[$i]-$line2[$i]); + + my $percentDiff; + if (abs($line1[$i])+abs($line2[$i]) == 0) { + $percentDiff = 0; + } else { + $percentDiff = $diff/(abs($line1[$i])+abs($line2[$i]))*200; + } + + # Stats if needed + if ($printStats) { + $nbr_values++; # increment values counts + $total_diff += $diff; + $total_values += (abs($line1[$i])+abs($line2[$i]))/2; + if ($diff>$maxMaxDiff) {$maxMaxDiff=$diff;$maxPercentDiff=$percentDiff;} + } + + if ($maxDiff> 0 && $percentMaxDiff> 0) { + if (($diff>$maxDiff) && ($percentDiff>$percentMaxDiff)) { + $warnings =1; + print "WARNING : $filename2: line $lineNb value $i ($line1[$i] and $line2[$i]) differ by $diff(".$percentDiff."%)\n"; + } + } else { # on a une ou zero condition */ + if ($maxDiff> 0) { # if we shall check the absolute value difference + if ($diff>$maxDiff) { + $warnings =1; + print "WARNING : $filename2: line $lineNb value $i ($line1[$i] and $line2[$i]) differ by $diff\n"; + } + } + if ($percentMaxDiff> 0) { # if we shall check the percentage of difference + if ($percentDiff>$percentMaxDiff) { + $warnings =1; + print "WARNING : $filename2: line $lineNb. value $i ($line1[$i] and $line2[$i]) differ by ".$percentDiff."%\n"; + } + } + } + } + } + close (FP1); + close (FP2); + if ($printStats) {printf ("Stats: Max Diff: %d(%f) mean diff: %0.3f mean percent diff : %0.2f\n",$maxMaxDiff, $maxPercentDiff, $total_diff/$nbr_values, $total_diff*100/$total_values);} + + return $warnings; +} + +if ((@ARGV < 1) || (@ARGV > 2)) +{ + print "##############################################################################\n"; + print "# #\n"; + print "# testCampaign [-s] #\n"; + print "# test name in the following list : #\n"; + print "# - decoder #\n"; + print "# - decodeLSP #\n"; + print "# - interpolateqLSPAndConvert2LP #\n"; + print "# - decodeAdaptativeCodeVector #\n"; + print "# - decodeFixedCodeVector #\n"; + print "# - decodeGains #\n"; + print "# - LPSynthesisFilter #\n"; + print "# - postFilter #\n"; + print "# - postProcessing #\n"; + print "# #\n"; + print "# - encoder #\n"; + print "# - preProcessing #\n"; + print "# - computeLP #\n"; + print "# - LP2LSPConversion #\n"; + print "# - LSPQuantization #\n"; + print "# - computeWeightedSpeech #\n"; + print "# - findOpenLoopPitchDelay #\n"; + print "# - adaptativeCodebookSearch #\n"; + print "# - computeAdaptativeCodebookGain #\n"; + print "# - fixedCodebookSearch #\n"; + print "# - gainQuantization #\n"; + print "# #\n"; + print "# - all : perform all tests #\n"; + print "# Options switch: #\n"; + print "# -s : Display stats on each test (when running softDiff) #\n"; + print "# #\n"; + print "##############################################################################\n"; + exit; +} + +# check command validity +# TODO + +my $printStats = 0; + +# Get the test name +my $command=$ARGV[@ARGV-1]; + +# is there a switch? +if ($ARGV[0] eq "-s") { + $printStats= 1; +} + + +# define the default values to use for maxDiff and percentualMaxDiff for each test +# " => [,]" +# if both set to 0, the diff command will be used +%defaultMaxDiff = ( "preProcessing" => [0,0], + "computeLP" => [0,0], + "LP2LSPConversion" => [0,0], + "LSPQuantization" => [0,0], + "computeWeightedSpeech" => [0,0], + "findOpenLoopPitchDelay" => [0,0], + "adaptativeCodebookSearch" => [0,0], + "computeAdaptativeCodebookGain" => [0,0], + "fixedCodebookSearch" => [0,0], + "gainQuantization" => [0,0], + "encoder" => [0,0], + + "decodeLSP" => [0,0], + "interpolateqLSPAndConvert2LP" => [0,0], + "decodeAdaptativeCodeVector" => [0,0], + "decodeFixedCodeVector" => [0,0], + "decodeGains" => [0,0], + "LPSynthesisFilter" => [0,0], + "postFilter" => [0,0], + "postProcessing" => [0,0], + "decoder" => [0,0] + ); + + +# check command: +if ($command eq "all") { # if run all tests, just get the defaultMaxDiff array as testsList as the test directory are retrieved from keys + %testsList = %defaultMaxDiff; +} else { + %testsList = ($command, 0); # we run one test: create an associative array with one element having a key matching the test name +} + +#return value for autotools make check +my $exitVal = 0; + +foreach my $testDirectory (keys %testsList) { + # get the files + opendir(DIR, $patternDirectory."/".$testDirectory) or die "can't open directory $patternDirectory/$testDirectory: $!"; + my @files = grep { /\.in$/ } readdir(DIR); + closedir(DIR); + my $testExec = $binDirectory.$testDirectory."Test"; + + print "Test $testDirectory bloc\n"; + # for each *.in file found in the test directory + foreach my $file (@files) { + # run the testExecutable + my $filebase = $file; + $filebase =~ s/^(.*?)\..*/$1/; + print " $filebase"; + print `$testExec $patternDirectory/$testDirectory/$file`; + + # compare the output file with the pattern file + my $filepattern = $file; + $filepattern =~ s/\.in$/\.pattern/; + my $fileout = $file; + $fileout =~ s/\.in$/\.out/; + + my $maxDiffTolerated = $defaultMaxDiff{$testDirectory}[0]; + my $maxPercentualDiffTolerated = $defaultMaxDiff{$testDirectory}[1]; + if ($maxDiffTolerated==0 && $maxPercentualDiffTolerated==0) { # no difference accepted, use the classic diff function + $differs = `diff $patternDirectory/$testDirectory/$filepattern $patternDirectory/$testDirectory/$fileout`; + if ($differs ne "") { + print " ... "; + print colored("Fail\n", "red"); + $exitVal = 1; + } else { + printf " ... Pass\n" + } + } else { # accept difference => use the softDiff function + if (softDiff($patternDirectory."/".$testDirectory."/".$filepattern, $patternDirectory."/".$testDirectory."/".$fileout, $maxDiffTolerated, $maxPercentualDiffTolerated, $printStats) == 0) { + printf " ... Pass\n" + } else { + printf " $filebase ... "; + print colored("Fail\n", "red"); + $exitVal = 1; + } + } + } +} +exit($exitVal); diff --git a/test/testCampaignAll b/test/testCampaignAll new file mode 100755 index 0000000..41bb5a4 --- /dev/null +++ b/test/testCampaignAll @@ -0,0 +1,31 @@ +#! /bin/sh +# This script check if we have the tests patterns and download them if needed +# then run all available tests + +# Do we have a patterns directory +if [ ! -d "patterns" ]; then + # no pattern directory: download it from + # http://www.belledonne-communications.com/downloads/bcg729-patterns.zip + wget http://www.belledonne-communications.com/downloads/bcg729-patterns.zip + if [ -e bcg729-patterns.zip ]; then + # check file + if [[ `md5sum bcg729-patterns.zip | grep -c 75b4fb8b286485c375c9c326f8b9eb66` -ne 0 ]]; then + # file ok, unzip it + unzip bcg729-patterns.zip + if [[ $? -ne 0 ]]; then + echo "Error: unable to unzip correctly bcg729-patterns.zip, try to do it manually" + else + rm bcg729-patterns.zip + fi + else + echo "Error: bad checksum on bcg729-patterns.zip downloaded from http://www.belledonne-communications.com/downloads/.\nTry again" + exit 1 + fi + else + echo "Error: Unable to download bcg729-patterns.zip pattern archive from http://www.belledonne-communications.com/downloads/" + exit 1 + fi +fi + +# run all the tests +./testCampaign all