diff --git a/libs/voipcodecs/AUTHORS b/libs/voipcodecs/AUTHORS new file mode 100644 index 0000000000..0fbb495099 --- /dev/null +++ b/libs/voipcodecs/AUTHORS @@ -0,0 +1 @@ +Steve Underwood diff --git a/libs/voipcodecs/COPYING b/libs/voipcodecs/COPYING new file mode 100644 index 0000000000..d60c31a97a --- /dev/null +++ b/libs/voipcodecs/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/libs/voipcodecs/ChangeLog b/libs/voipcodecs/ChangeLog new file mode 100644 index 0000000000..fc5ee32173 --- /dev/null +++ b/libs/voipcodecs/ChangeLog @@ -0,0 +1,3 @@ +08.02.08 - 0.0.1 - Steve Underwood + - The first version. + diff --git a/libs/voipcodecs/INSTALL b/libs/voipcodecs/INSTALL new file mode 100644 index 0000000000..ef77c3a46f --- /dev/null +++ b/libs/voipcodecs/INSTALL @@ -0,0 +1,182 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.ac' is used to create `configure' by a program +called `autoconf'. You only need `configure.ac' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. diff --git a/libs/voipcodecs/Makefile.am b/libs/voipcodecs/Makefile.am new file mode 100644 index 0000000000..85d1dcf16b --- /dev/null +++ b/libs/voipcodecs/Makefile.am @@ -0,0 +1,93 @@ +## +## VoIPcodecs - a series of DSP components for telephony +## +## Makefile.am -- Process this file with automake to produce Makefile.in +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2, as +## published by the Free Software Foundation. +## +## 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., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## $Id: Makefile.am,v 1.29 2007/09/23 12:45:15 steveu Exp $ + +AM_CFLAGS = $(COMP_VENDOR_CFLAGS) + +noinst_SCRIPTS = voipcodecs.spec + +MAINTAINERCLEANFILES = Makefile.in + +EXTRA_DIST = voipcodecs.spec \ + wrapper.xsl \ + libvoipcodecs.vcproj \ + doc/libvoipcodecs-doxygen \ + src/float_fudge.h \ + src/voipcodecs/version.h.in \ + src/libvoipcodecs.dsp \ + src/libvoipcodecs.sln \ + src/msvc/gettimeofday.c \ + src/msvc/inttypes.h \ + src/msvc/tgmath.h \ + src/msvc/unistd.h \ + src/msvc/sys/time.h \ + src/msvc/voipcodecs.def \ + src/msvc/msvcproj.head \ + src/msvc/msvcproj.foot \ + src/msvc/vc8proj.head \ + src/msvc/vc8proj.foot \ + debian/changelog \ + debian/compat \ + debian/control \ + debian/copyright \ + debian/libvoipcodecs.install \ + debian/libvoipcodecs-dev.install \ + debian/libvoipcodecs-doc.install \ + debian/rules \ + debian/watch + +if COND_DOC + MAYBE_DOC=doc +endif +if COND_TESTS + MAYBE_TESTS=tests +endif +if COND_ITUTESTS + MAYBE_ITUTESTS=itutests +endif +SUBDIRS = src $(MAYBE_DOC) $(MAYBE_TESTS) $(MAYBE_ITUTESTS) + +DIST_SUBDIRS = src doc tests localtests etsitests itutests + +faq: faq.xml + cd faq ; xsltproc ../wrapper.xsl ../faq.xml + +rpm: rpm-build + +rpm-build: + $(MAKE) -$(MAKEFLAGS) bump.rpm.release + $(MAKE) -$(MAKEFLAGS) dist + rm -rf rpm/BUILD/* + rm -f rpm/RPMS/*/* + rm -f rpm/SOURCES/* + rm -f rpm/SPECS/* + rm -f rpm/SRPMS/* + rpm -ta --sign @PACKAGE@-@VERSION@.tar.gz + +bump.rpm.release: voipcodecs.spec + VERSION="x"; \ + test -f $(srcdir)/rpm.release && . $(srcdir)/rpm.release; \ + NEXT_RELEASE=0; \ + test "$$VERSION" = "@VERSION@" && NEXT_RELEASE="$$RELEASE"; \ + RELEASE=`expr $$NEXT_RELEASE + 1`; \ + echo "VERSION=@VERSION@" >$(srcdir)/rpm.release; \ + echo "RELEASE=$$RELEASE" >>$(srcdir)/rpm.release; \ + sed 's/^Release: .*/Release: '$$RELEASE'/' \ + voipcodecs.spec.new; \ + mv voipcodecs.spec.new voipcodecs.spec diff --git a/libs/voipcodecs/NEWS b/libs/voipcodecs/NEWS new file mode 100644 index 0000000000..0d09503644 --- /dev/null +++ b/libs/voipcodecs/NEWS @@ -0,0 +1 @@ +No news is good news! \ No newline at end of file diff --git a/libs/voipcodecs/README b/libs/voipcodecs/README new file mode 100644 index 0000000000..db6017b305 --- /dev/null +++ b/libs/voipcodecs/README @@ -0,0 +1,4 @@ +VoIPcodecs 0.0.1 - A set of commonly used, unencumbered, codecs for VoIP +------------------------------------------------------------------------ + +Steve Underwood diff --git a/libs/voipcodecs/config-h.in b/libs/voipcodecs/config-h.in new file mode 100644 index 0000000000..0f5758e8e7 --- /dev/null +++ b/libs/voipcodecs/config-h.in @@ -0,0 +1,235 @@ +/* config-h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the header file. */ +#undef HAVE_AUDIOFILE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FFTW3_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FFTW_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FLOAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FL_FL_AUDIO_METER_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FL_FL_CARTESIAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FL_FL_DRAW_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FL_FL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FL_FL_LIGHT_BUTTON_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FL_FL_OVERLAY_WINDOW_H + +/* Define to 1 if you have the `gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `m' library (-lm). */ +#undef HAVE_LIBM + +/* Define to 1 if you have the `tiff' library (-ltiff). */ +#undef HAVE_LIBTIFF + +/* Define to 1 if you have the 'libxml2' library (-lxml2). */ +#undef HAVE_LIBXML2 + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBXML_PARSER_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBXML_XINCLUDE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBXML_XMLMEMORY_H + +/* Define to 1 if the system has the type `long double'. */ +#undef HAVE_LONG_DOUBLE + +/* Define to 1 if the system has the type `long long'. */ +#undef HAVE_LONG_LONG + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#undef HAVE_MALLOC + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MATH_H + +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have the header file. */ +#undef HAVE_PTHREAD_H + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#undef HAVE_REALLOC + +/* Define to 1 if you have the `select' function. */ +#undef HAVE_SELECT + +/* Define to 1 if you have the header file. */ +#undef HAVE_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strstr' function. */ +#undef HAVE_STRSTR + +/* Define to 1 if you have the `strtol' function. */ +#undef HAVE_STRTOL + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_FCNTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_TGMATH_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_TIFFIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNICALL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_X11_X_H + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* Define to the type of arg 1 for `select'. */ +#undef SELECT_TYPE_ARG1 + +/* Define to the type of args 2, 3 and 4 for `select'. */ +#undef SELECT_TYPE_ARG234 + +/* Define to the type of arg 5 for `select'. */ +#undef SELECT_TYPE_ARG5 + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Version number of package */ +#undef VERSION + +/* Enable fixed point processing, where possible, instead of floating point */ +#undef VOIPCODECS_USE_FIXED_POINT + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to rpl_malloc if the replacement function should be used. */ +#undef malloc + +/* Define to rpl_realloc if the replacement function should be used. */ +#undef realloc + +/* Define to empty if the keyword `volatile' does not work. Warning: valid + code using `volatile' can become incorrect without. Disable with care. */ +#undef volatile diff --git a/libs/voipcodecs/configure.ac b/libs/voipcodecs/configure.ac new file mode 100644 index 0000000000..df938b2f04 --- /dev/null +++ b/libs/voipcodecs/configure.ac @@ -0,0 +1,340 @@ +# +# VoIPcodecs - a series of DSP components for telephony +# +# configure.ac -- Process this file with autoconf to produce configure +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# $Id: configure.ac,v 1.38 2007/11/10 11:14:56 steveu Exp $ + +# @start 1 + +AC_INIT + +AC_DEFUN([AX_COMPILER_VENDOR], +[ +AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, + [ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=unknown + # note: don't check for GCC first, since some other compilers define __GNUC__ + for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do + vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[ +#if !($vencpp) + thisisanerror; +#endif +])], [ax_cv_]_AC_LANG_ABBREV[_compiler_vendor=`echo $ventest | cut -d: -f1`; break]) + done + ]) +]) + +VOIPCODECS_MAJOR_VERSION=0 +VOIPCODECS_MINOR_VERSION=0 +VOIPCODECS_MICRO_VERSION=1 + +VOIPCODECS_LT_CURRENT=0 +VOIPCODECS_LT_REVISION=2 +VOIPCODECS_LT_AGE=0 + +VERSION=$VOIPCODECS_MAJOR_VERSION.$VOIPCODECS_MINOR_VERSION.$VOIPCODECS_MICRO_VERSION +PACKAGE=voipcodecs + +AC_SUBST(VOIPCODECS_LT_CURRENT) +AC_SUBST(VOIPCODECS_LT_REVISION) +AC_SUBST(VOIPCODECS_LT_AGE) + +AC_CONFIG_SRCDIR([src/g711.c]) +AC_CONFIG_AUX_DIR(config) +AC_CONFIG_HEADERS([src/config.h:config-h.in]) +AM_INIT_AUTOMAKE($PACKAGE, $VERSION) + +AC_CANONICAL_HOST +AC_CANONICAL_BUILD +AC_PROG_CC +AC_PROG_CXX +AC_PROG_GCC_TRADITIONAL +AC_PROG_LIBTOOL +AC_LANG([C]) + +AX_COMPILER_VENDOR + +if test "${build}" != "${host}" +then + # If we are doing a Canadian Cross, in which the host and build systems + # are not the same, we set reasonable default values for the tools. + + CC=${CC-${host_alias}-gcc} + CFLAGS=${CFLAGS-"-g -O2"} + CXX=${CXX-${host_alias}-c++} + CXXFLAGS=${CXXFLAGS-"-g -O2"} + CC_FOR_BUILD=${CC_FOR_BUILD-gcc} +else + # Set reasonable default values for some tools even if not Canadian. + # Of course, these are different reasonable default values, originally + # specified directly in the Makefile. + # We don't export, so that autoconf can do its job. + # Note that all these settings are above the fragment inclusion point + # in Makefile.in, so can still be overridden by fragments. + # This is all going to change when we autoconfiscate... + CC_FOR_BUILD="\$(CC)" + AC_PROG_CC + + # We must set the default linker to the linker used by gcc for the correct + # operation of libtool. If LD is not defined and we are using gcc, try to + # set the LD default to the ld used by gcc. + if test -z "$LD" + then + if test "$GCC" = yes + then + case $build in + *-*-mingw*) + gcc_prog_ld=`$CC -print-prog-name=ld 2>&1 | tr -d '\015'` ;; + *) + gcc_prog_ld=`$CC -print-prog-name=ld 2>&1` ;; + esac + case $gcc_prog_ld in + # Accept absolute paths. + [[\\/]* | [A-Za-z]:[\\/]*)] + LD="$gcc_prog_ld" ;; + esac + fi + fi + + CXX=${CXX-"c++"} + CFLAGS=${CFLAGS-"-g -O2"} + CXXFLAGS=${CXXFLAGS-"-g -O2"} +fi + +AC_C_CONST +AC_C_INLINE +AC_C_VOLATILE + +AC_CHECK_TYPES(long long) +AC_CHECK_TYPES(long double) + +AC_TYPE_SIGNAL + +AC_ARG_ENABLE(doc, [ --enable-doc Build the documentation]) +AC_ARG_ENABLE(tests, [ --enable-tests Build the test programs]) +AC_ARG_ENABLE(itutests, [ --enable-itutests Build TIFF test files for some ITU test images]) +AC_ARG_ENABLE(mmx, [ --enable-mmx Enable MMX support]) +AC_ARG_ENABLE(sse, [ --enable-sse Enable SSE support]) +AC_ARG_ENABLE(fixed_point, [ --enable-fixed-point Enable fixed point support]) + +AC_FUNC_ERROR_AT_LINE +AC_FUNC_VPRINTF +AC_FUNC_MALLOC +AC_FUNC_MEMCMP +AC_FUNC_REALLOC +AC_FUNC_SELECT_ARGTYPES + +AC_CHECK_FUNCS([memmove]) +AC_CHECK_FUNCS([memset]) +AC_CHECK_FUNCS([select]) +AC_CHECK_FUNCS([strcasecmp]) +AC_CHECK_FUNCS([strchr]) +AC_CHECK_FUNCS([strdup]) +AC_CHECK_FUNCS([strerror]) +AC_CHECK_FUNCS([strstr]) +AC_CHECK_FUNCS([strtol]) +AC_CHECK_FUNCS([gettimeofday]) + +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_HEADER_TIME + +# Check for header files. +AC_CHECK_HEADERS([socket.h]) +AC_CHECK_HEADERS([inttypes.h], [INSERT_INTTYPES_HEADER="#include "]) +AC_CHECK_HEADERS([stdint.h], [INSERT_STDINT_HEADER="#include "]) +AC_CHECK_HEADERS([unistd.h]) +AC_CHECK_HEADERS([stdlib.h]) +AC_CHECK_HEADERS([string.h]) +AC_CHECK_HEADERS([strings.h]) +AC_CHECK_HEADERS([malloc.h]) +AC_CHECK_HEADERS([tgmath.h], [INSERT_TGMATH_HEADER="#include "]) +AC_CHECK_HEADERS([math.h], [INSERT_MATH_HEADER="#include "]) +AC_CHECK_HEADERS([float.h]) +AC_CHECK_HEADERS([fcntl.h]) +AC_CHECK_HEADERS([sys/time.h]) +AC_CHECK_HEADERS([sys/select.h]) +AC_CHECK_HEADERS([sys/ioctl.h]) +AC_CHECK_HEADERS([sys/fcntl.h]) +AC_CHECK_HEADERS([audiofile.h]) +AC_CHECK_HEADERS([fftw.h]) +AC_CHECK_HEADERS([fftw3.h]) +AC_CHECK_HEADERS([tiffio.h]) +AC_CHECK_HEADERS([pthread.h]) +AC_CHECK_HEADERS([unicall.h]) +if test "${build}" == "${host}" +then + AC_CHECK_HEADERS([X11/X.h]) +fi + +# Determine XML2 include path +AC_MSG_CHECKING(for libxml/xmlmemory.h) + +# Can we include headers using system include dirs? +AC_TRY_COMPILE([#include ], [int a = 1;], + XML2_INCLUDE=" ", + XML2_INCLUDE= +) + +# Hunt through several possible directories to find the includes for libxml2 +if test "x$XML2_INCLUDE" = "x"; then + old_CPPFLAGS="$CPPFLAGS" + for i in $xml2_include_dir /usr/include /usr/local/include /usr/include/libxml2 /usr/local/include/libxml2 ; do + CPPFLAGS="$old_CPPFLAGS -I$i" + AC_TRY_COMPILE([#include ], [int a = 1;], + XML2_INCLUDE="-I$i", + XML2_INCLUDE= + ) + if test "x$XML2_INCLUDE" != "x"; then + break; + fi + done + CPPFLAGS="$old_CPPFLAGS $XML2_INCLUDE" +fi + +AC_CHECK_HEADERS([libxml/xmlmemory.h]) +AC_CHECK_HEADERS([libxml/parser.h]) +AC_CHECK_HEADERS([libxml/xinclude.h]) + +AC_LANG([C++]) +AC_CHECK_HEADERS([FL/Fl.H]) +AC_CHECK_HEADERS([FL/Fl_Overlay_Window.H]) +AC_CHECK_HEADERS([FL/Fl_Light_Button.H]) +AC_CHECK_HEADERS([FL/fl_draw.H]) +AC_CHECK_HEADERS([FL/Fl_Cartesian.H], [], [], [],[[#include +]]) +AC_CHECK_HEADERS([FL/Fl_Audio_Meter.H], [], [], [],[[#include +]]) + +if test "${build}" == "${host}" +then + case "${host}" in + x86_64-*) + AC_CHECK_FILE([${prefix}/lib64], libdir='$(exec_prefix)/lib64') + ;; + esac +fi + +AC_LANG([C]) + +if test "${build}" == "${host}" +then + case "${host}" in + x86_64-*) + # X86_64 Linux machines may have both 64 bit and 32 bit libraries. We need to choose the right set + AC_CHECK_FILE([/usr/X11R6/lib64], [TESTLIBS="$TESTLIBS -L/usr/X11R6/lib64"], AC_CHECK_FILE([/usr/X11R6/lib], [TESTLIBS="$TESTLIBS -L/usr/X11R6/lib"])) + ;; + esac +fi + +# Checks for libraries. +AC_CHECK_LIB([Xft], [XftFontOpen], TESTLIBS="$TESTLIBS -lXft",, $TESTLIBS) +AC_CHECK_LIB([Xext], [XextCreateExtension], TESTLIBS="$TESTLIBS -lXext",, $TESTLIBS) +AC_CHECK_LIB([X11], [XOpenDisplay], TESTLIBS="$TESTLIBS -lX11",, $TESTLIBS) +AC_CHECK_LIB([tiff], [TIFFOpen], , AC_MSG_ERROR("Can't build without libtiff (does your system require a libtiff-devel package?)"), -lm) +AC_CHECK_LIB([m], [cos]) +AC_CHECK_LIB([m], [pow]) +AC_CHECK_LIB([m], [sqrt]) +AC_CHECK_LIB([xml2], [xmlParseFile], [AC_DEFINE([HAVE_LIBXML2], [1], [Define to 1 if you have the 'libxml2' library (-lxml2).]) TESTLIBS="$TESTLIBS -lxml2"]) +if test -n "$enable_tests" ; then + AC_LANG([C++]) + AC_CHECK_LIB([fltk], [main], TESTLIBS="$TESTLIBS -lfltk -lsupc++") + AC_CHECK_LIB([fltk_cartesian], [main], TESTLIBS="-lfltk_cartesian $TESTLIBS") + AC_CHECK_LIB([fltk_audio_meter], [main], TESTLIBS="-lfltk_audio_meter $TESTLIBS") + AC_LANG([C]) + AC_CHECK_LIB([audiofile], [afOpenFile], TESTLIBS="$TESTLIBS -laudiofile", AC_MSG_ERROR("Can't make tests without libaudiofile (does your system require a libaudiofile-devel package?)")) + AC_CHECK_LIB([fftw3], [fftw_plan_dft_1d], TESTLIBS="$TESTLIBS -lfftw3") + AC_CHECK_LIB([fftw], [fftw_create_plan], TESTLIBS="$TESTLIBS -lfftw") + AC_CHECK_LIB([pthread], [pthread_attr_init], TESTLIBS="$TESTLIBS -lpthread") + AC_CHECK_LIB([dl], [dlopen], TESTLIBS="$TESTLIBS -ldl") + AC_CHECK_LIB([unicall], [uc_start], TESTLIBS="$TESTLIBS -lunicall",, -ltiff -ldl) +fi + +case "${ax_cv_c_compiler_vendor}" in +gnu) + COMP_VENDOR_CFLAGS="-std=gnu99 -ffast-math -Wall -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes" + if test "$enable_sse" = "yes" ; then + COMP_VENDOR_CFLAGS="-msse $COMP_VENDOR_CFLAGS" + fi + if test "$enable_mmx" = "yes" ; then + COMP_VENDOR_CFLAGS="-mmmx $COMP_VENDOR_CFLAGS" + fi + ;; +*) + COMP_VENDOR_CFLAGS="-std=c99 -Wall -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes" + ;; +esac + +COMP_VENDOR_CFLAGS="-DNDEBUG $COMP_VENDOR_CFLAGS" + +AM_CONDITIONAL([COND_DOC], [test "$enable_doc" = yes]) +AM_CONDITIONAL([COND_TESTS], [test "$enable_tests" = yes]) +AM_CONDITIONAL([COND_ITUTESTS], [test "$enable_itutests" = yes]) +AM_CONDITIONAL([COND_MMX], [test "$enable_mmx" = yes]) +AM_CONDITIONAL([COND_SSE], [test "$enable_sse" = yes]) +if test "$enable_fixed_point" = "yes" ; then + AC_DEFINE([VOIPCODECS_USE_FIXED_POINT], [1], [Enable fixed point processing, where possible, instead of floating point]) + VOIPCODECS_USE_FIXED_POINT="#define VOIPCODECS_USE_FIXED_POINT 1" +else +# +# So far we deal with the embedded ARM, Blackfin, MIPS, TI DSP and XScale processors as +# things which lack fast hardware floating point. +# +# Other candidates would be the small embedded Power PCs. +# + case $basic_machine in + arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] \ + | bfin \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | tic54x | c54x* | tic55x | c55x* | tic6x | c6x* \ + | xscale | xscalee[bl] \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | bfin-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | xscale-* | xscalee[bl]-* ) + AC_DEFINE([VOIPCODECS_USE_FIXED_POINT], [1], [Enable fixed point processing, where possible, instead of floating point]) + VOIPCODECS_USE_FIXED_POINT="#define VOIPCODECS_USE_FIXED_POINT 1" + ;; + *) + VOIPCODECS_USE_FIXED_POINT="#undef VOIPCODECS_USE_FIXED_POINT" + ;; + esac +fi + +AC_SUBST(CC_FOR_BUILD) +AC_SUBST(COMP_VENDOR_CFLAGS) +AC_SUBST(TESTLIBS) +AC_SUBST(VOIPCODECS_USE_FIXED_POINT) +AC_SUBST(INSERT_INTTYPES_HEADER) +AC_SUBST(INSERT_STDINT_HEADER) +AC_SUBST(INSERT_TGMATH_HEADER) +AC_SUBST(INSERT_MATH_HEADER) + +AC_CONFIG_FILES([Makefile + doc/Makefile + etsitests/Makefile + itutests/Makefile + localtests/Makefile + src/Makefile + src/voipcodecs.h + tests/Makefile + voipcodecs.spec]) + +AC_OUTPUT + +# @end 1 diff --git a/libs/voipcodecs/debian/changelog b/libs/voipcodecs/debian/changelog new file mode 100644 index 0000000000..fdc543aa5b --- /dev/null +++ b/libs/voipcodecs/debian/changelog @@ -0,0 +1,6 @@ +voipcodecs (0.0.1) unstable; urgency=low + + [ Steve Underwood ] + * Begun + + -- Steve Underwood Thu, 7 Feb 2008 09:53:06 +0300 diff --git a/libs/voipcodecs/debian/compat b/libs/voipcodecs/debian/compat new file mode 100644 index 0000000000..b8626c4cff --- /dev/null +++ b/libs/voipcodecs/debian/compat @@ -0,0 +1 @@ +4 diff --git a/libs/voipcodecs/debian/control b/libs/voipcodecs/debian/control new file mode 100644 index 0000000000..b2aaa704fe --- /dev/null +++ b/libs/voipcodecs/debian/control @@ -0,0 +1,42 @@ +Source: voipcodecs +Section: libs +Priority: optional +Maintainer: Debian VoIP Team +Uploaders: Jose Carlos Garcia Sogo , Kilian Krause , Santiago Garcia Mantinan , Mark Purcell , Tzafrir Cohen , Santiago Ruano Rincón +Build-Depends: debhelper (>= 4.0.0), libtiff4-dev, libjpeg62-dev, dpatch, doxygen, autotools-dev +Standards-Version: 3.7.2 +XS-Vcs-Svn: svn://svn.debian.org/pkg-voip/ +XS-Vcs-Browser: http://svn.debian.org/wsvn/pkg-voip/ + +Package: libvoipcodecs3 +Architecture: any +Depends: ${shlibs:Depends} +Conflicts: libvoipcodecs0, libvoipcodecs1, libvoipcodecs2 +Description: Telephony signal processing library + This is a low-level signal processing library that modulate and demodulate + signals commonly used in telephony, such as the "noise" generated by a + fax modem or DTMF touchpad. + . + This package contains the shared library. + +Package: libvoipcodecs-dev +Section: libdevel +Architecture: any +Depends: libvoipcodecs3 (= ${Source-Version}), libtiff4-dev, libjpeg62-dev +Description: Telephony signal processing library + This is a low-level signal processing library that modulate and demodulate + signals commonly used in telephony, such as the "noise" generated by a + fax modem or DTMF touchpad. + . + This package contains the static library and development headers. + . + Homepage: http://www.soft-switch.org/ + +Package: libvoipcodecs-doc +Section: doc +Architecture: all +Description: Documentation for the voipcodecs signal processing library + This package contains the online API in HTML for the libvoipcodecs, a low + level signal processing library that modulate and demodulate siignals + commonly used in telephony, such as the "noise" generated by a fax + modem or DTMF touchpad. diff --git a/libs/voipcodecs/debian/copyright b/libs/voipcodecs/debian/copyright new file mode 100644 index 0000000000..ebf63aad47 --- /dev/null +++ b/libs/voipcodecs/debian/copyright @@ -0,0 +1,25 @@ +This package was debianized by Steve Underwood on +Thu, 7 Feb 2008 15:22:58 +0100. + +It was downloaded from http://soft-switch.org/downloads/voipcodecs/ + +Copyright: Steve Underwood + +License: + + This package 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; version 2 dated June, 1991. + + This package 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 package; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + + +On Debian systems, the complete text of the GNU General +Public License can be found in `/usr/share/common-licenses/GPL'. diff --git a/libs/voipcodecs/debian/libvoipcodecs-dev.install b/libs/voipcodecs/debian/libvoipcodecs-dev.install new file mode 100644 index 0000000000..162bf014f7 --- /dev/null +++ b/libs/voipcodecs/debian/libvoipcodecs-dev.install @@ -0,0 +1,4 @@ +debian/tmp/usr/include +debian/tmp/usr/lib/libvoipcodecs.so +debian/tmp/usr/lib/libvoipcodecs.la +debian/tmp/usr/lib/libvoipcodecs.a diff --git a/libs/voipcodecs/debian/libvoipcodecs-doc.install b/libs/voipcodecs/debian/libvoipcodecs-doc.install new file mode 100644 index 0000000000..fbdba498d7 --- /dev/null +++ b/libs/voipcodecs/debian/libvoipcodecs-doc.install @@ -0,0 +1 @@ +doc/api/html usr/share/doc/libvoipcodecs-doc/api/ diff --git a/libs/voipcodecs/debian/libvoipcodecs.install b/libs/voipcodecs/debian/libvoipcodecs.install new file mode 100644 index 0000000000..f7b903c151 --- /dev/null +++ b/libs/voipcodecs/debian/libvoipcodecs.install @@ -0,0 +1,2 @@ +debian/tmp/usr/lib/libvoipcodecs.so.0.* +debian/tmp/usr/lib/libvoipcodecs.so.0 diff --git a/libs/voipcodecs/debian/rules b/libs/voipcodecs/debian/rules new file mode 100755 index 0000000000..8869b07778 --- /dev/null +++ b/libs/voipcodecs/debian/rules @@ -0,0 +1,106 @@ +#!/usr/bin/make -f + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) + +DEBVERSION:=$(shell head -n 1 debian/changelog \ + | sed -e 's/^[^(]*(\([^)]*\)).*/\1/') +ORIGTARVER:=$(shell echo $(DEBVERSION) | sed -e 's/^.*://' -e 's/-[0-9.]*$$//')# -e 's/.dfsg$$//' -e 's/~//') + +UPVERSION:=$(shell echo $(ORIGTARVER) | tr -d '~') + +FILENAME := voipcodecs_$(ORIGTARVER).orig.tar.gz +FULLNAME := voipcodecs-$(UPVERSION) +URL := http://soft-switch.org/downloads/voipcodecs/voipcodecs-$(UPVERSION).tgz + +CFLAGS = -Wall -g + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 +else + CFLAGS += -O2 +endif + +include /usr/share/dpatch/dpatch.make + + +autotools: patch-stamp + ln -s /usr/share/misc/config.sub config.sub + ln -s /usr/share/misc/config.guess config.guess + touch autotools + +config.status: autotools configure + dh_testdir + CFLAGS="$(CFLAGS)" ./configure \ + --host=$(DEB_HOST_GNU_TYPE) \ + --build=$(DEB_BUILD_GNU_TYPE) \ + --prefix=/usr \ + --mandir=\$${prefix}/share/man \ + --infodir=\$${prefix}/share/info \ + --enable-doc + +build: build-stamp + +build-stamp: config.status + dh_testdir + $(MAKE) + touch build-stamp + +clean: clean-patched unpatch +clean-patched: + dh_testdir + dh_testroot + rm -f build-stamp autotools + -$(MAKE) distclean + + -$(RM) -f config.sub + -$(RM) -f config.guess + + dh_clean + +install: build-stamp + dh_testdir + dh_testroot + dh_clean -k + $(MAKE) install DESTDIR=$(CURDIR)/debian/tmp + +binary-indep: build-stamp install + dh_testdir -i + dh_testroot -i + dh_installchangelogs -i ChangeLog + dh_installdocs -i DueDiligence + dh_install -i + dh_compress -i + dh_fixperms -i + dh_installdeb -i + dh_gencontrol -i + dh_md5sums -i + dh_builddeb -i + +binary-arch: build-stamp install + dh_testdir -a + dh_testroot -a + dh_installchangelogs -a ChangeLog + dh_installdocs -a DueDiligence + dh_install -a + dh_strip -a + dh_compress -a + dh_fixperms -a + dh_makeshlibs -a + dh_installdeb -a + dh_shlibdeps -a + dh_gencontrol -a + dh_md5sums -a + dh_builddeb -a + +get-orig-source: + -@@dh_testdir + @@[ -d ../tarballs/. ]||mkdir -p ../tarballs + @@echo Downloading $(FILENAME) from $(URL) ... + @@wget -N -nv -T10 -t3 -O ../tarballs/$(FILENAME) $(URL) + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install patch unpatch diff --git a/libs/voipcodecs/debian/watch b/libs/voipcodecs/debian/watch new file mode 100644 index 0000000000..a4b9b7773f --- /dev/null +++ b/libs/voipcodecs/debian/watch @@ -0,0 +1,7 @@ +# See uscan(1) for format + +# Compulsory line, this is a version 3 file +version=3 + +# +http://soft-switch.org/downloads/voipcodecs/ voipcodecs-(.*)\.tgz debian svn-upgrade diff --git a/libs/voipcodecs/doc/Makefile.am b/libs/voipcodecs/doc/Makefile.am new file mode 100644 index 0000000000..26c52027b3 --- /dev/null +++ b/libs/voipcodecs/doc/Makefile.am @@ -0,0 +1,29 @@ +## +## VoIPcodecs - a series of DSP components for telephony +## +## Makefile.am -- Process this file with automake to produce Makefile.in +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2, as +## published by the Free Software Foundation. +## +## 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., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## $Id: Makefile.am,v 1.7 2007/12/20 15:06:22 steveu Exp $ + +MAINTAINERCLEANFILES = Makefile.in + +EXTRA_DIST = css.css \ + wrapper.xsl + +all: doxydocs + +doxydocs: + doxygen libvoipcodecs-doxygen diff --git a/libs/voipcodecs/doc/css.css b/libs/voipcodecs/doc/css.css new file mode 100644 index 0000000000..2f07200bdc --- /dev/null +++ b/libs/voipcodecs/doc/css.css @@ -0,0 +1,564 @@ +body { + background-image: url("../images/weave.jpg"); + font-family: Verdana, Arial, Helvetica, Sans-serif; + color: black; + margin-right: 20px; + margin-left: 20px; +} + +h1 { + text-align: center; +} + +h2 { + font-family: Verdana, Arial, Helvetica, Sans-serif; + border-color: #c00000; + color : black; + margin-top: 0.8em; + border-style: solid; + border-width: 0px 0px 3px 0.5em; + line-height : 130%; +} + +h3 { + font-family: Verdana, Arial, Helvetica, Sans-serif; + border-color: #f02020; + color : black; + border-width: 0px 0px 2px 0.5em; + border-style: solid; + margin-right: 20%; + line-height : 130%; +} +caption { + font-weight: bold +} +a.qindex {} +a.qindexRef {} +a.el { + text-decoration: none; + font-weight: bold +} +a.elRef { + font-weight: bold +} +a.code { + text-decoration: none; + font-weight: normal; + color: #4444ee +} +a.codeRef { + font-weight: normal; + color: #4444ee +} +a:hover { + text-decoration: none; + background-color: #f2f2ff +} +dl.el { + margin-left: -1cm +} +div.fragment { + width: 100%; + border: none; + background-color: #eeeeee +} +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px +} + +td { + font-family: Verdana, Arial, Helvetica, Sans-serif; + font-weight: bold; +} + +.navheader { + font-family: Verdana, Arial, Helvetica, Sans-serif; + background-color: #B2B2ff; + font-weight: bold; +} + +.navfooter { + font-family: Verdana, Arial, Helvetica, Sans-serif; + background-color: #B2B2ff; + font-weight: bold; +} + +table.menu { + background-color: #000066; + font-weight: bold; + text-align: center; + width: 100%; +} + +tr.menu { + background-color: #ccffff; + font-weight: bold; + text-align: center; +} +td.menu { + background-color: #f2e0d0; + font-weight: bold; + text-align: center; +} + +td.md { + background-color: #f2f2ff; + font-weight: bold; +} +td.mdname1 { + background-color: #f2f2ff; + font-weight: bold; + color: #602020; +} +td.mdname { + background-color: #f2f2ff; + font-weight: bold; + color: #602020; + width: 600px; +} +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold +} +div.groupText { + margin-left: 16px; + font-style: italic; + font-size: smaller +} +td.indexkey { + font-family: Verdana, Arial, Helvetica, Sans-serif; + background-color: #eeeeff; + font-weight: bold; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px +} +td.indexvalue { + font-family: Verdana, Arial, Helvetica, Sans-serif; + background-color: #eeeeff; + font-style: italic; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px +} +span.keyword { + color: #008000 +} +span.keywordtype { + color: #604020 +} +span.keywordflow { + color: #e08000 +} +span.comment { + color: #800000 +} +span.preprocessor { + color: #806020 +} +span.stringliteral { + color: #002080 +} +span.charliteral { + color: #008080 +} +em { + color: #990000; + background-color: transparent; +} +h1,h2,h3,h4,h5,h6,p,center,td,th,ul,dl,div { + font-family: Geneva, Arial, Helvetica, sans-serif; +} +body,td { + font-size: 90%; +} +h1 { + text-align: center; + font-size: 160%; +} +h2 { + font-size: 120%; +} +h3 { + font-size: 100%; +} +caption { + font-weight: bold +} +div.qindex { + width: 100%; + background-color: #eeeeff; + border: 1px solid #b0b0b0; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +div.nav { + width: 100%; + background-color: #eeeeff; + border: 1px solid #b0b0b0; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +div.navtab { + background-color: #eeeeff; + border: 1px solid #b0b0b0; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +td.navtab { + font-size: 70%; +} +a.qindex { + text-decoration: none; + font-weight: bold; + color: #1a419d; +} +a.qindex:visited { + text-decoration: none; + font-weight: bold; + color: #1a419d +} +a.qindex:hover { + text-decoration: none; + background-color: #ddddff; +} +a.qindexHL { + text-decoration: none; + font-weight: bold; + background-color: #6666cc; + color: #ffffff; + border: 1px double #9295C2; +} +a.qindexHL:hover { + text-decoration: none; + background-color: #6666cc; + color: #ffffff; +} +a.qindexHL:visited { + text-decoration: none; + background-color: #6666cc; + color: #ffffff +} +a.el { + text-decoration: none; + font-weight: bold +} +a.elRef { + font-weight: bold +} +a.code:link { + text-decoration: none; + font-weight: normal; + color: #0000FF +} +a.code:visited { + text-decoration: none; + font-weight: normal; + color: #0000FF +} +a.codeRef:link { + font-weight: normal; + color: #0000FF +} +a.codeRef:visited { + font-weight: normal; + color: #0000FF +} +a:hover { + text-decoration: none; + background-color: #f2f2ff +} +dl.el { + margin-left: -1cm +} +.fragment { + font-family: Fixed, monospace; + font-size: 95%; +} +pre.fragment { + border: 1px solid #CCCCCC; + background-color: #f5f5f5; + margin-top: 4px; + margin-bottom: 4px; + margin-left: 2px; + margin-right: 8px; + padding-left: 6px; + padding-right: 6px; + padding-top: 4px; + padding-bottom: 4px; +} +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px +} +td.md { + background-color: #F4F4FB; + font-weight: bold; +} +td.mdPrefix { + background-color: #F4F4FB; + color: #606060; + font-size: 80%; +} +td.mdname1 { + background-color: #F4F4FB; + font-weight: bold; + color: #602020; +} +td.mdname { + background-color: #F4F4FB; + font-weight: bold; + color: #602020; + width: 600px; +} +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold; +} +div.groupText { + margin-left: 16px; + font-style: italic; + font-size: 90% +} +td.indexkey { + background-color: #eeeeff; + font-weight: bold; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +td.indexvalue { + background-color: #eeeeff; + font-style: italic; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +tr.memlist { + background-color: #f0f0f0; +} +p.formulaDsp { + text-align: center; +} +img.formulaDsp { +} +img.formulaInl { + vertical-align: middle; +} +span.keyword { + color: #008000 +} +span.keywordtype { + color: #604020 +} +span.keywordflow { + color: #e08000 +} +span.comment { + color: #800000 +} +span.preprocessor { + color: #806020 +} +span.stringliteral { + color: #002080 +} +span.charliteral { + color: #008080 +} +.mdTable { + border: 1px solid #868686; + background-color: #F4F4FB; +} +.mdRow { + padding: 8px 10px; +} +.mdescLeft { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.mdescRight { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.memItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplParams { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + color: #606060; + background-color: #FAFAFA; + font-size: 80%; +} +.search { + color: #003399; + font-weight: bold; +} +form.search { + margin-bottom: 0px; + margin-top: 0px; +} +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #eeeeff; +} +td.tiny { + font-size: 75%; +} +a { + color: #252e78; +} +a:visited { + color: #3d2185; +} +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #b0b0b0; +} +th.dirtab { + background: #eeeeff; + font-weight: bold; +} +hr { + height: 1px; + border: none; + border-top: 1px solid black; +} diff --git a/libs/voipcodecs/doc/libvoipcodecs-doxygen b/libs/voipcodecs/doc/libvoipcodecs-doxygen new file mode 100644 index 0000000000..99d7fd7448 --- /dev/null +++ b/libs/voipcodecs/doc/libvoipcodecs-doxygen @@ -0,0 +1,1229 @@ +# Doxyfile 1.4.4 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = libvoipcodecs + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 0.0.1 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = api + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, +# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, +# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, +# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, +# Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = YES + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is YES. + +SHOW_DIRECTORIES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the progam writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = .. + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm + +FILE_PATTERNS = *.c \ + *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 2 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = css.css + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that a graph may be further truncated if the graph's +# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH +# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), +# the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/libs/voipcodecs/doc/wrapper.xsl b/libs/voipcodecs/doc/wrapper.xsl new file mode 100644 index 0000000000..89e314d781 --- /dev/null +++ b/libs/voipcodecs/doc/wrapper.xsl @@ -0,0 +1,5 @@ + + + css.css + \ No newline at end of file diff --git a/libs/voipcodecs/etsitests/Makefile.am b/libs/voipcodecs/etsitests/Makefile.am new file mode 100644 index 0000000000..8ef3325b40 --- /dev/null +++ b/libs/voipcodecs/etsitests/Makefile.am @@ -0,0 +1,27 @@ +## +## VoIPcodecs - a series of DSP components for telephony +## +## Makefile.am -- Process this file with automake to produce Makefile.in +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2, as +## published by the Free Software Foundation. +## +## 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., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## $Id: Makefile.am,v 1.1 2008/02/07 10:49:02 steveu Exp $ + +SUBDIRS = + +DIST_SUBDIRS = + +all: + +clean: diff --git a/libs/voipcodecs/itutests/Makefile.am b/libs/voipcodecs/itutests/Makefile.am new file mode 100644 index 0000000000..e097b92dae --- /dev/null +++ b/libs/voipcodecs/itutests/Makefile.am @@ -0,0 +1,28 @@ +## +## SpanDSP - a series of DSP components for telephony +## +## Makefile.am -- Process this file with automake to produce Makefile.in +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2, as +## published by the Free Software Foundation. +## +## 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., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## $Id: Makefile.am,v 1.5 2007/02/10 11:54:57 steveu Exp $ + +SUBDIRS = + +DIST_SUBDIRS = + +all: + +clean: + diff --git a/libs/voipcodecs/libvoipcodecs.vcproj b/libs/voipcodecs/libvoipcodecs.vcproj new file mode 100644 index 0000000000..04f7cf2f50 --- /dev/null +++ b/libs/voipcodecs/libvoipcodecs.vcproj @@ -0,0 +1,657 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/voipcodecs/localtests/Makefile.am b/libs/voipcodecs/localtests/Makefile.am new file mode 100644 index 0000000000..8b5f6d60f6 --- /dev/null +++ b/libs/voipcodecs/localtests/Makefile.am @@ -0,0 +1,32 @@ +## +## VoIPcodecs - a series of DSP components for telephony +## +## Makefile.am -- Process this file with automake to produce Makefile.in +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2, as +## published by the Free Software Foundation. +## +## 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., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## $Id: Makefile.am,v 1.1 2008/02/07 10:49:02 steveu Exp $ + +SUBDIRS = + +DIST_SUBDIRS = + +EXTRA_DIST = dam9_lpc55.wav \ + dam9.wav \ + short_nb_voice.wav \ + short_wb_voice.wav + +all: + +clean: diff --git a/libs/voipcodecs/localtests/dam9.wav b/libs/voipcodecs/localtests/dam9.wav new file mode 100644 index 0000000000..65b6818d3b Binary files /dev/null and b/libs/voipcodecs/localtests/dam9.wav differ diff --git a/libs/voipcodecs/localtests/dam9_lpc55.wav b/libs/voipcodecs/localtests/dam9_lpc55.wav new file mode 100644 index 0000000000..13c8c2030a Binary files /dev/null and b/libs/voipcodecs/localtests/dam9_lpc55.wav differ diff --git a/libs/voipcodecs/localtests/short_nb_voice.wav b/libs/voipcodecs/localtests/short_nb_voice.wav new file mode 100644 index 0000000000..4dd098a2df Binary files /dev/null and b/libs/voipcodecs/localtests/short_nb_voice.wav differ diff --git a/libs/voipcodecs/localtests/short_wb_voice.wav b/libs/voipcodecs/localtests/short_wb_voice.wav new file mode 100644 index 0000000000..c2777183fe Binary files /dev/null and b/libs/voipcodecs/localtests/short_wb_voice.wav differ diff --git a/libs/voipcodecs/src/Makefile.am b/libs/voipcodecs/src/Makefile.am new file mode 100644 index 0000000000..13324a18e0 --- /dev/null +++ b/libs/voipcodecs/src/Makefile.am @@ -0,0 +1,126 @@ +## +## VoIPcodecs - a series of DSP components for telephony +## +## Makefile.am -- Process this file with automake to produce Makefile.in +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2, as +## published by the Free Software Foundation. +## +## 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., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## $Id: Makefile.am,v 1.85 2008/02/06 09:23:26 steveu Exp $ + +AM_CFLAGS = $(COMP_VENDOR_CFLAGS) + +MAINTAINERCLEANFILES = Makefile.in + +INCLUDES = -I$(top_builddir) + +lib_LTLIBRARIES = libvoipcodecs.la + +libvoipcodecs_la_SOURCES = bitstream.c \ + g711.c \ + g722_encode.c \ + g722_decode.c \ + g726.c \ + gsm0610_decode.c \ + gsm0610_encode.c \ + gsm0610_long_term.c \ + gsm0610_lpc.c \ + gsm0610_preprocess.c \ + gsm0610_rpe.c \ + gsm0610_short_term.c \ + ima_adpcm.c \ + lpc10_analyse.c \ + lpc10_decode.c \ + lpc10_encode.c \ + lpc10_placev.c \ + lpc10_voicing.c \ + oki_adpcm.c \ + vector_int.c + +libvoipcodecs_la_LDFLAGS = -version-info @VOIPCODECS_LT_CURRENT@:@VOIPCODECS_LT_REVISION@:@VOIPCODECS_LT_AGE@ + +nobase_include_HEADERS = voipcodecs/bit_operations.h \ + voipcodecs/bitstream.h \ + voipcodecs/dc_restore.h \ + voipcodecs/g711.h \ + voipcodecs/g722.h \ + voipcodecs/g726.h \ + voipcodecs/gsm0610.h \ + voipcodecs/ima_adpcm.h \ + voipcodecs/lpc10.h \ + voipcodecs/oki_adpcm.h \ + voipcodecs/telephony.h \ + voipcodecs/vector_int.h \ + voipcodecs/version.h + +nodist_include_HEADERS = voipcodecs.h + +noinst_HEADERS = gsm0610_local.h \ + lpc10_encdecs.h + +# We need to run at_dictionary_gen, so it generates the +# at_interpreter_dictionary.h file + +DSP = libvoipcodecs.dsp +VCPROJ = libvoipcodecs.vcproj + +WIN32SOURCES = $(libvoipcodecs_la_SOURCES) msvc/gettimeofday.c +WIN32HEADERS = $(nobase_include_HEADERS) voipcodecs.h + +DSPOUT = | awk '{printf("%s\r\n", $$0)}' >> $(DSP) +VCPROJOUT = | awk '{printf("%s\r\n", $$0)}' >> $(VCPROJ) + +$(DSP): msvc/msvcproj.head msvc/msvcproj.foot Makefile.am + echo "creating $(DSP)" + @(cp $(srcdir)/msvc/msvcproj.head $(DSP); \ + echo "# Begin Group \"Source Files\"" $(DSPOUT); \ + for file in $(WIN32SOURCES); do \ + echo "# Begin Source File" $(DSPOUT); \ + echo "" $(DSPOUT); \ + echo "SOURCE=.\\"$$file $(DSPOUT); \ + echo "# End Source File" $(DSPOUT); \ + done; \ + echo "# End Group" $(DSPOUT); \ + echo "# Begin Group \"Header Files\"" $(DSPOUT); \ + for file in $(WIN32HEADERS); do \ + echo "# Begin Source File" $(DSPOUT); \ + echo "" $(DSPOUT); \ + echo "SOURCE=.\\"$$file $(DSPOUT); \ + echo "# End Source File" $(DSPOUT); \ + done; \ + echo "# End Group" $(DSPOUT); \ + cat $(srcdir)/msvc/msvcproj.foot $(DSPOUT) ) + +$(VCPROJ): msvc/vc8proj.head msvc/vc8proj.foot Makefile.am + echo "creating $(VCPROJ)" + @(cp $(srcdir)/msvc/vc8proj.head $(VCPROJ); \ + for file in $(WIN32SOURCES); do \ + echo "" $(VCPROJOUT); \ + done; \ + echo "" $(VCPROJOUT); \ + for file in $(WIN32HEADERS); do \ + echo "" $(VCPROJOUT); \ + done; \ + cat $(srcdir)/msvc/vc8proj.foot $(VCPROJOUT) ) + +voipcodecs/version.h: + NOWDATE=`date --utc +"%Y%m%d"` ; \ + NOWTIME=`date --utc +"%H%M%S"` ; \ + sed 's/$$VOIPCODECS_RELEASE_DATE/'$$NOWDATE'/;s/$$VOIPCODECS_RELEASE_TIME/'$$NOWTIME'/' \ + voipcodecs/version.h + +dist-hook: + NOWDATE=`date --utc +"%Y%m%d"` ; \ + NOWTIME=`date --utc +"%H%M%S"` ; \ + sed 's/$$VOIPCODECS_RELEASE_DATE/'$$NOWDATE'/;s/$$VOIPCODECS_RELEASE_TIME/'$$NOWTIME'/' \ + voipcodecs/version.h diff --git a/libs/voipcodecs/src/bitstream.c b/libs/voipcodecs/src/bitstream.c new file mode 100644 index 0000000000..db8232cd15 --- /dev/null +++ b/libs/voipcodecs/src/bitstream.c @@ -0,0 +1,137 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * bitstream.c - Bitstream composition and decomposition routines. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser Lesser GNU General Public License version 2.1.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: bitstream.c,v 1.8 2007/08/20 15:22:21 steveu Exp $ + */ + +/*! \file */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "voipcodecs/telephony.h" +#include "voipcodecs/bitstream.h" + +void bitstream_put(bitstream_state_t *s, uint8_t **c, unsigned int value, int bits) +{ + value &= ((1 << bits) - 1); + if (s->residue + bits <= 32) + { + s->bitstream |= (value << s->residue); + s->residue += bits; + } + while (s->residue >= 8) + { + s->residue -= 8; + *(*c)++ = (uint8_t) (s->bitstream & 0xFF); + s->bitstream >>= 8; + } +} +/*- End of function --------------------------------------------------------*/ + +void bitstream_put2(bitstream_state_t *s, uint8_t **c, unsigned int value, int bits) +{ + value &= ((1 << bits) - 1); + if (s->residue + bits <= 32) + { + s->bitstream = (s->bitstream << bits) | value; + s->residue += bits; + } + while (s->residue >= 8) + { + s->residue -= 8; + *(*c)++ = (uint8_t) ((s->bitstream >> s->residue) & 0xFF); + } +} +/*- End of function --------------------------------------------------------*/ + +unsigned int bitstream_get(bitstream_state_t *s, const uint8_t **c, int bits) +{ + unsigned int x; + + while (s->residue < (unsigned int) bits) + { + x = (unsigned int) *(*c)++; + s->bitstream |= (x << s->residue); + s->residue += 8; + } + s->residue -= bits; + x = s->bitstream & ((1 << bits) - 1); + s->bitstream >>= bits; + return x; +} +/*- End of function --------------------------------------------------------*/ + +unsigned int bitstream_get2(bitstream_state_t *s, const uint8_t **c, int bits) +{ + unsigned int x; + + while (s->residue < (unsigned int) bits) + { + x = (unsigned int) *(*c)++; + s->bitstream = (s->bitstream << 8) | x; + s->residue += 8; + } + s->residue -= bits; + x = (s->bitstream >> s->residue) & ((1 << bits) - 1); + return x; +} +/*- End of function --------------------------------------------------------*/ + +void bitstream_flush(bitstream_state_t *s, uint8_t **c) +{ + if (s->residue > 0) + { + *(*c)++ = (uint8_t) ((s->bitstream << (8 - s->residue)) & 0xFF); + s->residue = 0; + } +} +/*- End of function --------------------------------------------------------*/ + +void bitstream_flush2(bitstream_state_t *s, uint8_t **c) +{ + if (s->residue > 0) + { + *(*c)++ = (uint8_t) ((s->bitstream << (8 - s->residue)) & 0xFF); + s->residue = 0; + } +} +/*- End of function --------------------------------------------------------*/ + +bitstream_state_t *bitstream_init(bitstream_state_t *s) +{ + if (s == NULL) + return NULL; + s->bitstream = 0; + s->residue = 0; + return s; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/float_fudge.h b/libs/voipcodecs/src/float_fudge.h new file mode 100644 index 0000000000..d3b0860913 --- /dev/null +++ b/libs/voipcodecs/src/float_fudge.h @@ -0,0 +1,123 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * float_fudge.h - A bunch of shims, to use double maths + * functions on platforms which lack the + * float versions with an 'f' at the end. + * + * Written by Steve Underwood + * + * Copyright (C) 2004 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: float_fudge.h,v 1.2 2007/08/13 11:35:32 steveu Exp $ + */ + +#if !defined(_FLOAT_FUDGE_H_) +#define _FLOAT_FUDGE_H_ + +#if defined(__USE_DOUBLE_MATH__) + +#if defined(__cplusplus) +extern "C" +{ +#endif + +static __inline__ float sinf(float x) +{ + return (float) sin((double) x); +} + +static __inline__ float cosf(float x) +{ + return (float) cos((double) x); +} + +static __inline__ float tanf(float x) +{ + return (float) tan((double) x); +} + +static __inline__ float asinf(float x) +{ + return (float) asin((double) x); +} + +static __inline__ float acosf(float x) +{ + return (float) acos((double) x); +} + +static __inline__ float atanf(float x) +{ + return (float) atan((double) x); +} + +static __inline__ float atan2f(float y, float x) +{ + return (float) atan2((double) y, (double) x); +} + +static __inline__ float ceilf(float x) +{ + return (float) ceil((double) x); +} + +static __inline__ float floorf(float x) +{ + return (float) floor((double) x); +} + +static __inline__ float expf(float x) +{ + return (float) expf((double) x); +} + +static __inline__ float logf(float x) +{ + return (float) logf((double) x); +} + +static __inline__ float log10f(float x) +{ + return (float) log10((double) x); +} + +static __inline__ float powf(float x, float y) +{ + return (float) pow((double) x, (double) y); +} + +static __inline__ int rintf(float x) +{ + return (int) rint((double) x); +} + +static __inline__ long int lrintf(float x) +{ + return (long int) lrint((double) x); +} + +#if defined(__cplusplus) +} +#endif + +#endif + +#endif + +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/g711.c b/libs/voipcodecs/src/g711.c new file mode 100644 index 0000000000..6568bd1b4b --- /dev/null +++ b/libs/voipcodecs/src/g711.c @@ -0,0 +1,104 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * g711.c - A-law and u-law transcoding routines + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser Lesser GNU General Public License version 2.1.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: g711.c,v 1.4 2006/11/19 14:07:24 steveu Exp $ + */ + +/*! \file */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif +#include + +#include "voipcodecs/telephony.h" +#include "voipcodecs/bit_operations.h" +#include "voipcodecs/g711.h" + +/* Copied from the CCITT G.711 specification */ +static const uint8_t ulaw_to_alaw_table[256] = +{ + 42, 43, 40, 41, 46, 47, 44, 45, 34, 35, 32, 33, 38, 39, 36, 37, + 58, 59, 56, 57, 62, 63, 60, 61, 50, 51, 48, 49, 54, 55, 52, 53, + 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 26, + 27, 24, 25, 30, 31, 28, 29, 18, 19, 16, 17, 22, 23, 20, 21, 106, + 104, 105, 110, 111, 108, 109, 98, 99, 96, 97, 102, 103, 100, 101, 122, 120, + 126, 127, 124, 125, 114, 115, 112, 113, 118, 119, 116, 117, 75, 73, 79, 77, + 66, 67, 64, 65, 70, 71, 68, 69, 90, 91, 88, 89, 94, 95, 92, 93, + 82, 82, 83, 83, 80, 80, 81, 81, 86, 86, 87, 87, 84, 84, 85, 85, + 170, 171, 168, 169, 174, 175, 172, 173, 162, 163, 160, 161, 166, 167, 164, 165, + 186, 187, 184, 185, 190, 191, 188, 189, 178, 179, 176, 177, 182, 183, 180, 181, + 138, 139, 136, 137, 142, 143, 140, 141, 130, 131, 128, 129, 134, 135, 132, 154, + 155, 152, 153, 158, 159, 156, 157, 146, 147, 144, 145, 150, 151, 148, 149, 234, + 232, 233, 238, 239, 236, 237, 226, 227, 224, 225, 230, 231, 228, 229, 250, 248, + 254, 255, 252, 253, 242, 243, 240, 241, 246, 247, 244, 245, 203, 201, 207, 205, + 194, 195, 192, 193, 198, 199, 196, 197, 218, 219, 216, 217, 222, 223, 220, 221, + 210, 210, 211, 211, 208, 208, 209, 209, 214, 214, 215, 215, 212, 212, 213, 213 +}; + +/* These transcoding tables are copied from the CCITT G.711 specification. To achieve + optimal results, do not change them. */ + +static const uint8_t alaw_to_ulaw_table[256] = +{ + 42, 43, 40, 41, 46, 47, 44, 45, 34, 35, 32, 33, 38, 39, 36, 37, + 57, 58, 55, 56, 61, 62, 59, 60, 49, 50, 47, 48, 53, 54, 51, 52, + 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 5, + 26, 27, 24, 25, 30, 31, 28, 29, 18, 19, 16, 17, 22, 23, 20, 21, + 98, 99, 96, 97, 102, 103, 100, 101, 93, 93, 92, 92, 95, 95, 94, 94, + 116, 118, 112, 114, 124, 126, 120, 122, 106, 107, 104, 105, 110, 111, 108, 109, + 72, 73, 70, 71, 76, 77, 74, 75, 64, 65, 63, 63, 68, 69, 66, 67, + 86, 87, 84, 85, 90, 91, 88, 89, 79, 79, 78, 78, 82, 83, 80, 81, + 170, 171, 168, 169, 174, 175, 172, 173, 162, 163, 160, 161, 166, 167, 164, 165, + 185, 186, 183, 184, 189, 190, 187, 188, 177, 178, 175, 176, 181, 182, 179, 180, + 138, 139, 136, 137, 142, 143, 140, 141, 130, 131, 128, 129, 134, 135, 132, 133, + 154, 155, 152, 153, 158, 159, 156, 157, 146, 147, 144, 145, 150, 151, 148, 149, + 226, 227, 224, 225, 230, 231, 228, 229, 221, 221, 220, 220, 223, 223, 222, 222, + 244, 246, 240, 242, 252, 254, 248, 250, 234, 235, 232, 233, 238, 239, 236, 237, + 200, 201, 198, 199, 204, 205, 202, 203, 192, 193, 191, 191, 196, 197, 194, 195, + 214, 215, 212, 213, 218, 219, 216, 217, 207, 207, 206, 206, 210, 211, 208, 209 +}; + +uint8_t alaw_to_ulaw(uint8_t alaw) +{ + return alaw_to_ulaw_table[alaw]; +} +/*- End of function --------------------------------------------------------*/ + +uint8_t ulaw_to_alaw(uint8_t ulaw) +{ + return ulaw_to_alaw_table[ulaw]; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/g722_decode.c b/libs/voipcodecs/src/g722_decode.c new file mode 100644 index 0000000000..8b52b84342 --- /dev/null +++ b/libs/voipcodecs/src/g722_decode.c @@ -0,0 +1,404 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * g722_decode.c - The ITU G.722 codec, decode part. + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser Lesser GNU General Public License version 2.1.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Based in part on a single channel G.722 codec which is: + * + * Copyright (c) CMU 1993 + * Computer Science, Speech Group + * Chengxiang Lu and Alex Hauptmann + * + * $Id: g722_decode.c,v 1.19 2007/03/14 11:51:01 steveu Exp $ + */ + +/*! \file */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif + +#include "voipcodecs/telephony.h" +#include "voipcodecs/dc_restore.h" +#include "voipcodecs/g722.h" + +static void block4(g722_decode_state_t *s, int band, int d); + +static void block4(g722_decode_state_t *s, int band, int d) +{ + int wd1; + int wd2; + int wd3; + int i; + + /* Block 4, RECONS */ + s->band[band].d[0] = d; + s->band[band].r[0] = saturate(s->band[band].s + d); + + /* Block 4, PARREC */ + s->band[band].p[0] = saturate(s->band[band].sz + d); + + /* Block 4, UPPOL2 */ + for (i = 0; i < 3; i++) + s->band[band].sg[i] = s->band[band].p[i] >> 15; + wd1 = saturate(s->band[band].a[1] << 2); + + wd2 = (s->band[band].sg[0] == s->band[band].sg[1]) ? -wd1 : wd1; + if (wd2 > 32767) + wd2 = 32767; + wd3 = (s->band[band].sg[0] == s->band[band].sg[2]) ? 128 : -128; + wd3 += (wd2 >> 7); + wd3 += (s->band[band].a[2]*32512) >> 15; + if (wd3 > 12288) + wd3 = 12288; + else if (wd3 < -12288) + wd3 = -12288; + s->band[band].ap[2] = wd3; + + /* Block 4, UPPOL1 */ + s->band[band].sg[0] = s->band[band].p[0] >> 15; + s->band[band].sg[1] = s->band[band].p[1] >> 15; + wd1 = (s->band[band].sg[0] == s->band[band].sg[1]) ? 192 : -192; + wd2 = (s->band[band].a[1]*32640) >> 15; + + s->band[band].ap[1] = saturate(wd1 + wd2); + wd3 = saturate(15360 - s->band[band].ap[2]); + if (s->band[band].ap[1] > wd3) + s->band[band].ap[1] = wd3; + else if (s->band[band].ap[1] < -wd3) + s->band[band].ap[1] = -wd3; + + /* Block 4, UPZERO */ + wd1 = (d == 0) ? 0 : 128; + s->band[band].sg[0] = d >> 15; + for (i = 1; i < 7; i++) + { + s->band[band].sg[i] = s->band[band].d[i] >> 15; + wd2 = (s->band[band].sg[i] == s->band[band].sg[0]) ? wd1 : -wd1; + wd3 = (s->band[band].b[i]*32640) >> 15; + s->band[band].bp[i] = saturate(wd2 + wd3); + } + + /* Block 4, DELAYA */ + for (i = 6; i > 0; i--) + { + s->band[band].d[i] = s->band[band].d[i - 1]; + s->band[band].b[i] = s->band[band].bp[i]; + } + + for (i = 2; i > 0; i--) + { + s->band[band].r[i] = s->band[band].r[i - 1]; + s->band[band].p[i] = s->band[band].p[i - 1]; + s->band[band].a[i] = s->band[band].ap[i]; + } + + /* Block 4, FILTEP */ + wd1 = saturate(s->band[band].r[1] + s->band[band].r[1]); + wd1 = (s->band[band].a[1]*wd1) >> 15; + wd2 = saturate(s->band[band].r[2] + s->band[band].r[2]); + wd2 = (s->band[band].a[2]*wd2) >> 15; + s->band[band].sp = saturate(wd1 + wd2); + + /* Block 4, FILTEZ */ + s->band[band].sz = 0; + for (i = 6; i > 0; i--) + { + wd1 = saturate(s->band[band].d[i] + s->band[band].d[i]); + s->band[band].sz += (s->band[band].b[i]*wd1) >> 15; + } + s->band[band].sz = saturate(s->band[band].sz); + + /* Block 4, PREDIC */ + s->band[band].s = saturate(s->band[band].sp + s->band[band].sz); +} +/*- End of function --------------------------------------------------------*/ + +g722_decode_state_t *g722_decode_init(g722_decode_state_t *s, int rate, int options) +{ + if (s == NULL) + { + if ((s = (g722_decode_state_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + memset(s, 0, sizeof(*s)); + if (rate == 48000) + s->bits_per_sample = 6; + else if (rate == 56000) + s->bits_per_sample = 7; + else + s->bits_per_sample = 8; + if ((options & G722_SAMPLE_RATE_8000)) + s->eight_k = TRUE; + if ((options & G722_PACKED) && s->bits_per_sample != 8) + s->packed = TRUE; + else + s->packed = FALSE; + s->band[0].det = 32; + s->band[1].det = 8; + return s; +} +/*- End of function --------------------------------------------------------*/ + +int g722_decode_release(g722_decode_state_t *s) +{ + free(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len) +{ + static const int wl[8] = + { + -60, -30, 58, 172, 334, 538, 1198, 3042 + }; + static const int rl42[16] = + { + 0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3, 2, 1, 0 + }; + static const int ilb[32] = + { + 2048, 2093, 2139, 2186, 2233, 2282, 2332, + 2383, 2435, 2489, 2543, 2599, 2656, 2714, + 2774, 2834, 2896, 2960, 3025, 3091, 3158, + 3228, 3298, 3371, 3444, 3520, 3597, 3676, + 3756, 3838, 3922, 4008 + }; + static const int wh[3] = + { + 0, -214, 798 + }; + static const int rh2[4] = + { + 2, 1, 2, 1 + }; + static const int qm2[4] = + { + -7408, -1616, 7408, 1616 + }; + static const int qm4[16] = + { + 0, -20456, -12896, -8968, + -6288, -4240, -2584, -1200, + 20456, 12896, 8968, 6288, + 4240, 2584, 1200, 0 + }; + static const int qm5[32] = + { + -280, -280, -23352, -17560, + -14120, -11664, -9752, -8184, + -6864, -5712, -4696, -3784, + -2960, -2208, -1520, -880, + 23352, 17560, 14120, 11664, + 9752, 8184, 6864, 5712, + 4696, 3784, 2960, 2208, + 1520, 880, 280, -280 + }; + static const int qm6[64] = + { + -136, -136, -136, -136, + -24808, -21904, -19008, -16704, + -14984, -13512, -12280, -11192, + -10232, -9360, -8576, -7856, + -7192, -6576, -6000, -5456, + -4944, -4464, -4008, -3576, + -3168, -2776, -2400, -2032, + -1688, -1360, -1040, -728, + 24808, 21904, 19008, 16704, + 14984, 13512, 12280, 11192, + 10232, 9360, 8576, 7856, + 7192, 6576, 6000, 5456, + 4944, 4464, 4008, 3576, + 3168, 2776, 2400, 2032, + 1688, 1360, 1040, 728, + 432, 136, -432, -136 + }; + static const int qmf_coeffs[12] = + { + 3, -11, 12, 32, -210, 951, 3876, -805, 362, -156, 53, -11, + }; + int dlowt; + int rlow; + int ihigh; + int dhigh; + int rhigh; + int xout1; + int xout2; + int wd1; + int wd2; + int wd3; + int code; + int outlen; + int i; + int j; + + outlen = 0; + rhigh = 0; + for (j = 0; j < len; ) + { + if (s->packed) + { + /* Unpack the code bits */ + if (s->in_bits < s->bits_per_sample) + { + s->in_buffer |= (g722_data[j++] << s->in_bits); + s->in_bits += 8; + } + code = s->in_buffer & ((1 << s->bits_per_sample) - 1); + s->in_buffer >>= s->bits_per_sample; + s->in_bits -= s->bits_per_sample; + } + else + { + code = g722_data[j++]; + } + + switch (s->bits_per_sample) + { + default: + case 8: + wd1 = code & 0x3F; + ihigh = (code >> 6) & 0x03; + wd2 = qm6[wd1]; + wd1 >>= 2; + break; + case 7: + wd1 = code & 0x1F; + ihigh = (code >> 5) & 0x03; + wd2 = qm5[wd1]; + wd1 >>= 1; + break; + case 6: + wd1 = code & 0x0F; + ihigh = (code >> 4) & 0x03; + wd2 = qm4[wd1]; + break; + } + /* Block 5L, LOW BAND INVQBL */ + wd2 = (s->band[0].det*wd2) >> 15; + /* Block 5L, RECONS */ + rlow = s->band[0].s + wd2; + /* Block 6L, LIMIT */ + if (rlow > 16383) + rlow = 16383; + else if (rlow < -16384) + rlow = -16384; + + /* Block 2L, INVQAL */ + wd2 = qm4[wd1]; + dlowt = (s->band[0].det*wd2) >> 15; + + /* Block 3L, LOGSCL */ + wd2 = rl42[wd1]; + wd1 = (s->band[0].nb*127) >> 7; + wd1 += wl[wd2]; + if (wd1 < 0) + wd1 = 0; + else if (wd1 > 18432) + wd1 = 18432; + s->band[0].nb = wd1; + + /* Block 3L, SCALEL */ + wd1 = (s->band[0].nb >> 6) & 31; + wd2 = 8 - (s->band[0].nb >> 11); + wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2); + s->band[0].det = wd3 << 2; + + block4(s, 0, dlowt); + + if (!s->eight_k) + { + /* Block 2H, INVQAH */ + wd2 = qm2[ihigh]; + dhigh = (s->band[1].det*wd2) >> 15; + /* Block 5H, RECONS */ + rhigh = dhigh + s->band[1].s; + /* Block 6H, LIMIT */ + if (rhigh > 16383) + rhigh = 16383; + else if (rhigh < -16384) + rhigh = -16384; + + /* Block 2H, INVQAH */ + wd2 = rh2[ihigh]; + wd1 = (s->band[1].nb*127) >> 7; + wd1 += wh[wd2]; + if (wd1 < 0) + wd1 = 0; + else if (wd1 > 22528) + wd1 = 22528; + s->band[1].nb = wd1; + + /* Block 3H, SCALEH */ + wd1 = (s->band[1].nb >> 6) & 31; + wd2 = 10 - (s->band[1].nb >> 11); + wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2); + s->band[1].det = wd3 << 2; + + block4(s, 1, dhigh); + } + + if (s->itu_test_mode) + { + amp[outlen++] = (int16_t) (rlow << 1); + amp[outlen++] = (int16_t) (rhigh << 1); + } + else + { + if (s->eight_k) + { + amp[outlen++] = (int16_t) rlow; + } + else + { + /* Apply the receive QMF */ + memcpy(s->x, &s->x[2], 22*sizeof(s->x[0])); + s->x[22] = rlow + rhigh; + s->x[23] = rlow - rhigh; + + xout1 = 0; + xout2 = 0; + for (i = 0; i < 12; i++) + { + xout2 += s->x[2*i]*qmf_coeffs[i]; + xout1 += s->x[2*i + 1]*qmf_coeffs[11 - i]; + } + amp[outlen++] = (int16_t) (xout1 >> 12); + amp[outlen++] = (int16_t) (xout2 >> 12); + } + } + } + return outlen; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/g722_encode.c b/libs/voipcodecs/src/g722_encode.c new file mode 100644 index 0000000000..3612b7d50c --- /dev/null +++ b/libs/voipcodecs/src/g722_encode.c @@ -0,0 +1,390 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * g722_encode.c - The ITU G.722 codec, encode part. + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser Lesser GNU General Public License version 2.1.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Based on a single channel 64kbps only G.722 codec which is: + * + ***** Copyright (c) CMU 1993 ***** + * Computer Science, Speech Group + * Chengxiang Lu and Alex Hauptmann + * + * $Id: g722_encode.c,v 1.17 2007/03/14 11:51:01 steveu Exp $ + */ + +/*! \file */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif + +#include "voipcodecs/telephony.h" +#include "voipcodecs/dc_restore.h" +#include "voipcodecs/g722.h" + +static void block4(g722_encode_state_t *s, int band, int d) +{ + int wd1; + int wd2; + int wd3; + int i; + + /* Block 4, RECONS */ + s->band[band].d[0] = d; + s->band[band].r[0] = saturate(s->band[band].s + d); + + /* Block 4, PARREC */ + s->band[band].p[0] = saturate(s->band[band].sz + d); + + /* Block 4, UPPOL2 */ + for (i = 0; i < 3; i++) + s->band[band].sg[i] = s->band[band].p[i] >> 15; + wd1 = saturate(s->band[band].a[1] << 2); + + wd2 = (s->band[band].sg[0] == s->band[band].sg[1]) ? -wd1 : wd1; + if (wd2 > 32767) + wd2 = 32767; + wd3 = (wd2 >> 7) + ((s->band[band].sg[0] == s->band[band].sg[2]) ? 128 : -128); + wd3 += (s->band[band].a[2]*32512) >> 15; + if (wd3 > 12288) + wd3 = 12288; + else if (wd3 < -12288) + wd3 = -12288; + s->band[band].ap[2] = wd3; + + /* Block 4, UPPOL1 */ + s->band[band].sg[0] = s->band[band].p[0] >> 15; + s->band[band].sg[1] = s->band[band].p[1] >> 15; + wd1 = (s->band[band].sg[0] == s->band[band].sg[1]) ? 192 : -192; + wd2 = (s->band[band].a[1]*32640) >> 15; + + s->band[band].ap[1] = saturate(wd1 + wd2); + wd3 = saturate(15360 - s->band[band].ap[2]); + if (s->band[band].ap[1] > wd3) + s->band[band].ap[1] = wd3; + else if (s->band[band].ap[1] < -wd3) + s->band[band].ap[1] = -wd3; + + /* Block 4, UPZERO */ + wd1 = (d == 0) ? 0 : 128; + s->band[band].sg[0] = d >> 15; + for (i = 1; i < 7; i++) + { + s->band[band].sg[i] = s->band[band].d[i] >> 15; + wd2 = (s->band[band].sg[i] == s->band[band].sg[0]) ? wd1 : -wd1; + wd3 = (s->band[band].b[i]*32640) >> 15; + s->band[band].bp[i] = saturate(wd2 + wd3); + } + + /* Block 4, DELAYA */ + for (i = 6; i > 0; i--) + { + s->band[band].d[i] = s->band[band].d[i - 1]; + s->band[band].b[i] = s->band[band].bp[i]; + } + + for (i = 2; i > 0; i--) + { + s->band[band].r[i] = s->band[band].r[i - 1]; + s->band[band].p[i] = s->band[band].p[i - 1]; + s->band[band].a[i] = s->band[band].ap[i]; + } + + /* Block 4, FILTEP */ + wd1 = saturate(s->band[band].r[1] + s->band[band].r[1]); + wd1 = (s->band[band].a[1]*wd1) >> 15; + wd2 = saturate(s->band[band].r[2] + s->band[band].r[2]); + wd2 = (s->band[band].a[2]*wd2) >> 15; + s->band[band].sp = saturate(wd1 + wd2); + + /* Block 4, FILTEZ */ + s->band[band].sz = 0; + for (i = 6; i > 0; i--) + { + wd1 = saturate(s->band[band].d[i] + s->band[band].d[i]); + s->band[band].sz += (s->band[band].b[i]*wd1) >> 15; + } + s->band[band].sz = saturate(s->band[band].sz); + + /* Block 4, PREDIC */ + s->band[band].s = saturate(s->band[band].sp + s->band[band].sz); +} +/*- End of function --------------------------------------------------------*/ + +g722_encode_state_t *g722_encode_init(g722_encode_state_t *s, int rate, int options) +{ + if (s == NULL) + { + if ((s = (g722_encode_state_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + memset(s, 0, sizeof(*s)); + if (rate == 48000) + s->bits_per_sample = 6; + else if (rate == 56000) + s->bits_per_sample = 7; + else + s->bits_per_sample = 8; + if ((options & G722_SAMPLE_RATE_8000)) + s->eight_k = TRUE; + if ((options & G722_PACKED) && s->bits_per_sample != 8) + s->packed = TRUE; + else + s->packed = FALSE; + s->band[0].det = 32; + s->band[1].det = 8; + return s; +} +/*- End of function --------------------------------------------------------*/ + +int g722_encode_release(g722_encode_state_t *s) +{ + free(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +int g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len) +{ + static const int q6[32] = + { + 0, 35, 72, 110, 150, 190, 233, 276, + 323, 370, 422, 473, 530, 587, 650, 714, + 786, 858, 940, 1023, 1121, 1219, 1339, 1458, + 1612, 1765, 1980, 2195, 2557, 2919, 0, 0 + }; + static const int iln[32] = + { + 0, 63, 62, 31, 30, 29, 28, 27, + 26, 25, 24, 23, 22, 21, 20, 19, + 18, 17, 16, 15, 14, 13, 12, 11, + 10, 9, 8, 7, 6, 5, 4, 0 + }; + static const int ilp[32] = + { + 0, 61, 60, 59, 58, 57, 56, 55, + 54, 53, 52, 51, 50, 49, 48, 47, + 46, 45, 44, 43, 42, 41, 40, 39, + 38, 37, 36, 35, 34, 33, 32, 0 + }; + static const int wl[8] = + { + -60, -30, 58, 172, 334, 538, 1198, 3042 + }; + static const int rl42[16] = + { + 0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3, 2, 1, 0 + }; + static const int ilb[32] = + { + 2048, 2093, 2139, 2186, 2233, 2282, 2332, + 2383, 2435, 2489, 2543, 2599, 2656, 2714, + 2774, 2834, 2896, 2960, 3025, 3091, 3158, + 3228, 3298, 3371, 3444, 3520, 3597, 3676, + 3756, 3838, 3922, 4008 + }; + static const int qm4[16] = + { + 0, -20456, -12896, -8968, + -6288, -4240, -2584, -1200, + 20456, 12896, 8968, 6288, + 4240, 2584, 1200, 0 + }; + static const int qm2[4] = + { + -7408, -1616, 7408, 1616 + }; + static const int qmf_coeffs[12] = + { + 3, -11, 12, 32, -210, 951, 3876, -805, 362, -156, 53, -11, + }; + static const int ihn[3] = {0, 1, 0}; + static const int ihp[3] = {0, 3, 2}; + static const int wh[3] = {0, -214, 798}; + static const int rh2[4] = {2, 1, 2, 1}; + + int dlow; + int dhigh; + int el; + int wd; + int wd1; + int ril; + int wd2; + int il4; + int ih2; + int wd3; + int eh; + int mih; + int i; + int j; + /* Low and high band PCM from the QMF */ + int xlow; + int xhigh; + int g722_bytes; + /* Even and odd tap accumulators */ + int sumeven; + int sumodd; + int ihigh; + int ilow; + int code; + + g722_bytes = 0; + xhigh = 0; + for (j = 0; j < len; ) + { + if (s->itu_test_mode) + { + xlow = + xhigh = amp[j++] >> 1; + } + else + { + if (s->eight_k) + { + xlow = amp[j++]; + } + else + { + /* Apply the transmit QMF */ + /* Shuffle the buffer down */ + memcpy(s->x, &s->x[2], 22*sizeof(s->x[0])); + s->x[22] = amp[j++]; + s->x[23] = amp[j++]; + + /* Discard every other QMF output */ + sumeven = 0; + sumodd = 0; + for (i = 0; i < 12; i++) + { + sumodd += s->x[2*i]*qmf_coeffs[i]; + sumeven += s->x[2*i + 1]*qmf_coeffs[11 - i]; + } + xlow = (sumeven + sumodd) >> 13; + xhigh = (sumeven - sumodd) >> 13; + } + } + /* Block 1L, SUBTRA */ + el = saturate(xlow - s->band[0].s); + + /* Block 1L, QUANTL */ + wd = (el >= 0) ? el : -(el + 1); + + for (i = 1; i < 30; i++) + { + wd1 = (q6[i]*s->band[0].det) >> 12; + if (wd < wd1) + break; + } + ilow = (el < 0) ? iln[i] : ilp[i]; + + /* Block 2L, INVQAL */ + ril = ilow >> 2; + wd2 = qm4[ril]; + dlow = (s->band[0].det*wd2) >> 15; + + /* Block 3L, LOGSCL */ + il4 = rl42[ril]; + wd = (s->band[0].nb*127) >> 7; + s->band[0].nb = wd + wl[il4]; + if (s->band[0].nb < 0) + s->band[0].nb = 0; + else if (s->band[0].nb > 18432) + s->band[0].nb = 18432; + + /* Block 3L, SCALEL */ + wd1 = (s->band[0].nb >> 6) & 31; + wd2 = 8 - (s->band[0].nb >> 11); + wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2); + s->band[0].det = wd3 << 2; + + block4(s, 0, dlow); + + if (s->eight_k) + { + /* Just leave the high bits as zero */ + code = (0xC0 | ilow) >> (8 - s->bits_per_sample); + } + else + { + /* Block 1H, SUBTRA */ + eh = saturate(xhigh - s->band[1].s); + + /* Block 1H, QUANTH */ + wd = (eh >= 0) ? eh : -(eh + 1); + wd1 = (564*s->band[1].det) >> 12; + mih = (wd >= wd1) ? 2 : 1; + ihigh = (eh < 0) ? ihn[mih] : ihp[mih]; + + /* Block 2H, INVQAH */ + wd2 = qm2[ihigh]; + dhigh = (s->band[1].det*wd2) >> 15; + + /* Block 3H, LOGSCH */ + ih2 = rh2[ihigh]; + wd = (s->band[1].nb*127) >> 7; + s->band[1].nb = wd + wh[ih2]; + if (s->band[1].nb < 0) + s->band[1].nb = 0; + else if (s->band[1].nb > 22528) + s->band[1].nb = 22528; + + /* Block 3H, SCALEH */ + wd1 = (s->band[1].nb >> 6) & 31; + wd2 = 10 - (s->band[1].nb >> 11); + wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2); + s->band[1].det = wd3 << 2; + + block4(s, 1, dhigh); + code = ((ihigh << 6) | ilow) >> (8 - s->bits_per_sample); + } + + if (s->packed) + { + /* Pack the code bits */ + s->out_buffer |= (code << s->out_bits); + s->out_bits += s->bits_per_sample; + if (s->out_bits >= 8) + { + g722_data[g722_bytes++] = (uint8_t) (s->out_buffer & 0xFF); + s->out_bits -= 8; + s->out_buffer >>= 8; + } + } + else + { + g722_data[g722_bytes++] = (uint8_t) code; + } + } + return g722_bytes; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/g726.c b/libs/voipcodecs/src/g726.c new file mode 100644 index 0000000000..e7172219ad --- /dev/null +++ b/libs/voipcodecs/src/g726.c @@ -0,0 +1,1178 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * g726.c - The ITU G.726 codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Based on G.721/G.723 code which is: + * + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + * + * $Id: g726.c,v 1.17 2006/11/19 14:07:24 steveu Exp $ + */ + +/*! \file */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif + +#include "voipcodecs/telephony.h" +#include "voipcodecs/dc_restore.h" +#include "voipcodecs/bitstream.h" +#include "voipcodecs/bit_operations.h" +#include "voipcodecs/g711.h" +#include "voipcodecs/g726.h" + +/* + * Maps G.726_16 code word to reconstructed scale factor normalized log + * magnitude values. + */ +static const int g726_16_dqlntab[4] = +{ + 116, 365, 365, 116 +}; + +/* Maps G.726_16 code word to log of scale factor multiplier. */ +static const int g726_16_witab[4] = +{ + -704, 14048, 14048, -704 +}; + +/* + * Maps G.726_16 code words to a set of values whose long and short + * term averages are computed and then compared to give an indication + * how stationary (steady state) the signal is. + */ +static const int g726_16_fitab[4] = +{ + 0x000, 0xE00, 0xE00, 0x000 +}; + +static const int qtab_726_16[1] = +{ + 261 +}; + +/* + * Maps G.726_24 code word to reconstructed scale factor normalized log + * magnitude values. + */ +static const int g726_24_dqlntab[8] = +{ + -2048, 135, 273, 373, 373, 273, 135, -2048 +}; + +/* Maps G.726_24 code word to log of scale factor multiplier. */ +static const int g726_24_witab[8] = +{ + -128, 960, 4384, 18624, 18624, 4384, 960, -128 +}; + +/* + * Maps G.726_24 code words to a set of values whose long and short + * term averages are computed and then compared to give an indication + * how stationary (steady state) the signal is. + */ +static const int g726_24_fitab[8] = +{ + 0x000, 0x200, 0x400, 0xE00, 0xE00, 0x400, 0x200, 0x000 +}; + +static const int qtab_726_24[3] = +{ + 8, 218, 331 +}; + +/* + * Maps G.726_32 code word to reconstructed scale factor normalized log + * magnitude values. + */ +static const int g726_32_dqlntab[16] = +{ + -2048, 4, 135, 213, 273, 323, 373, 425, + 425, 373, 323, 273, 213, 135, 4, -2048 +}; + +/* Maps G.726_32 code word to log of scale factor multiplier. */ +static const int g726_32_witab[16] = +{ + -384, 576, 1312, 2048, 3584, 6336, 11360, 35904, + 35904, 11360, 6336, 3584, 2048, 1312, 576, -384 +}; + +/* + * Maps G.726_32 code words to a set of values whose long and short + * term averages are computed and then compared to give an indication + * how stationary (steady state) the signal is. + */ +static const int g726_32_fitab[16] = +{ + 0x000, 0x000, 0x000, 0x200, 0x200, 0x200, 0x600, 0xE00, + 0xE00, 0x600, 0x200, 0x200, 0x200, 0x000, 0x000, 0x000 +}; + +static const int qtab_726_32[7] = +{ + -124, 80, 178, 246, 300, 349, 400 +}; + +/* + * Maps G.726_40 code word to ructeconstructed scale factor normalized log + * magnitude values. + */ +static const int g726_40_dqlntab[32] = +{ + -2048, -66, 28, 104, 169, 224, 274, 318, + 358, 395, 429, 459, 488, 514, 539, 566, + 566, 539, 514, 488, 459, 429, 395, 358, + 318, 274, 224, 169, 104, 28, -66, -2048 +}; + +/* Maps G.726_40 code word to log of scale factor multiplier. */ +static const int g726_40_witab[32] = +{ + 448, 448, 768, 1248, 1280, 1312, 1856, 3200, + 4512, 5728, 7008, 8960, 11456, 14080, 16928, 22272, + 22272, 16928, 14080, 11456, 8960, 7008, 5728, 4512, + 3200, 1856, 1312, 1280, 1248, 768, 448, 448 +}; + +/* + * Maps G.726_40 code words to a set of values whose long and short + * term averages are computed and then compared to give an indication + * how stationary (steady state) the signal is. + */ +static const int g726_40_fitab[32] = +{ + 0x000, 0x000, 0x000, 0x000, 0x000, 0x200, 0x200, 0x200, + 0x200, 0x200, 0x400, 0x600, 0x800, 0xA00, 0xC00, 0xC00, + 0xC00, 0xC00, 0xA00, 0x800, 0x600, 0x400, 0x200, 0x200, + 0x200, 0x200, 0x200, 0x000, 0x000, 0x000, 0x000, 0x000 +}; + +static const int qtab_726_40[15] = +{ + -122, -16, 68, 139, 198, 250, 298, 339, + 378, 413, 445, 475, 502, 528, 553 +}; + +/* + * returns the integer product of the 14-bit integer "an" and + * "floating point" representation (4-bit exponent, 6-bit mantessa) "srn". + */ +static int16_t fmult(int16_t an, int16_t srn) +{ + int16_t anmag; + int16_t anexp; + int16_t anmant; + int16_t wanexp; + int16_t wanmant; + int16_t retval; + + anmag = (an > 0) ? an : ((-an) & 0x1FFF); + anexp = (int16_t) (top_bit(anmag) - 5); + anmant = (anmag == 0) ? 32 : (anexp >= 0) ? (anmag >> anexp) : (anmag << -anexp); + wanexp = anexp + ((srn >> 6) & 0xF) - 13; + + wanmant = (anmant*(srn & 0x3F) + 0x30) >> 4; + retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) : (wanmant >> -wanexp); + + return (((an ^ srn) < 0) ? -retval : retval); +} +/*- End of function --------------------------------------------------------*/ + +/* + * Compute the estimated signal from the 6-zero predictor. + */ +static __inline__ int16_t predictor_zero(g726_state_t *s) +{ + int i; + int sezi; + + sezi = fmult(s->b[0] >> 2, s->dq[0]); + /* ACCUM */ + for (i = 1; i < 6; i++) + sezi += fmult(s->b[i] >> 2, s->dq[i]); + return (int16_t) sezi; +} +/*- End of function --------------------------------------------------------*/ + +/* + * Computes the estimated signal from the 2-pole predictor. + */ +static __inline__ int16_t predictor_pole(g726_state_t *s) +{ + return (fmult(s->a[1] >> 2, s->sr[1]) + fmult(s->a[0] >> 2, s->sr[0])); +} +/*- End of function --------------------------------------------------------*/ + +/* + * Computes the quantization step size of the adaptive quantizer. + */ +static int step_size(g726_state_t *s) +{ + int y; + int dif; + int al; + + if (s->ap >= 256) + return s->yu; + y = s->yl >> 6; + dif = s->yu - y; + al = s->ap >> 2; + if (dif > 0) + y += (dif*al) >> 6; + else if (dif < 0) + y += (dif*al + 0x3F) >> 6; + return y; +} +/*- End of function --------------------------------------------------------*/ + +/* + * Given a raw sample, 'd', of the difference signal and a + * quantization step size scale factor, 'y', this routine returns the + * ADPCM codeword to which that sample gets quantized. The step + * size scale factor division operation is done in the log base 2 domain + * as a subtraction. + */ +static int16_t quantize(int d, /* Raw difference signal sample */ + int y, /* Step size multiplier */ + const int table[], /* quantization table */ + int quantizer_states) /* table size of int16_t integers */ +{ + int16_t dqm; /* Magnitude of 'd' */ + int16_t exp; /* Integer part of base 2 log of 'd' */ + int16_t mant; /* Fractional part of base 2 log */ + int16_t dl; /* Log of magnitude of 'd' */ + int16_t dln; /* Step size scale factor normalized log */ + int i; + int size; + + /* + * LOG + * + * Compute base 2 log of 'd', and store in 'dl'. + */ + dqm = (int16_t) abs(d); + exp = (int16_t) (top_bit(dqm >> 1) + 1); + /* Fractional portion. */ + mant = ((dqm << 7) >> exp) & 0x7F; + dl = (exp << 7) + mant; + + /* + * SUBTB + * + * "Divide" by step size multiplier. + */ + dln = dl - (int16_t) (y >> 2); + + /* + * QUAN + * + * Search for codword i for 'dln'. + */ + size = (quantizer_states - 1) >> 1; + for (i = 0; i < size; i++) + { + if (dln < table[i]) + break; + } + if (d < 0) + { + /* Take 1's complement of i */ + return (int16_t) ((size << 1) + 1 - i); + } + if (i == 0 && (quantizer_states & 1)) + { + /* Zero is only valid if there are an even number of states, so + take the 1's complement if the code is zero. */ + return (int16_t) quantizer_states; + } + return (int16_t) i; +} +/*- End of function --------------------------------------------------------*/ + +/* + * Returns reconstructed difference signal 'dq' obtained from + * codeword 'i' and quantization step size scale factor 'y'. + * Multiplication is performed in log base 2 domain as addition. + */ +static int16_t reconstruct(int sign, /* 0 for non-negative value */ + int dqln, /* G.72x codeword */ + int y) /* Step size multiplier */ +{ + int16_t dql; /* Log of 'dq' magnitude */ + int16_t dex; /* Integer part of log */ + int16_t dqt; + int16_t dq; /* Reconstructed difference signal sample */ + + dql = (int16_t) (dqln + (y >> 2)); /* ADDA */ + + if (dql < 0) + return ((sign) ? -0x8000 : 0); + /* ANTILOG */ + dex = (dql >> 7) & 15; + dqt = 128 + (dql & 127); + dq = (dqt << 7) >> (14 - dex); + return ((sign) ? (dq - 0x8000) : dq); +} +/*- End of function --------------------------------------------------------*/ + +/* + * updates the state variables for each output code + */ +static void update(g726_state_t *s, + int y, /* quantizer step size */ + int wi, /* scale factor multiplier */ + int fi, /* for long/short term energies */ + int dq, /* quantized prediction difference */ + int sr, /* reconstructed signal */ + int dqsez) /* difference from 2-pole predictor */ +{ + int16_t mag; + int16_t exp; + int16_t a2p; /* LIMC */ + int16_t a1ul; /* UPA1 */ + int16_t pks1; /* UPA2 */ + int16_t fa1; + int16_t ylint; + int16_t dqthr; + int16_t ylfrac; + int16_t thr; + int16_t pk0; + int i; + int tr; + + a2p = 0; + /* Needed in updating predictor poles */ + pk0 = (dqsez < 0) ? 1 : 0; + + /* prediction difference magnitude */ + mag = (int16_t) (dq & 0x7FFF); + /* TRANS */ + ylint = (int16_t) (s->yl >> 15); /* exponent part of yl */ + ylfrac = (int16_t) ((s->yl >> 10) & 0x1F); /* fractional part of yl */ + /* Limit threshold to 31 << 10 */ + thr = (ylint > 9) ? (31 << 10) : ((32 + ylfrac) << ylint); + dqthr = (thr + (thr >> 1)) >> 1; /* dqthr = 0.75 * thr */ + if (!s->td) /* signal supposed voice */ + tr = FALSE; + else if (mag <= dqthr) /* supposed data, but small mag */ + tr = FALSE; /* treated as voice */ + else /* signal is data (modem) */ + tr = TRUE; + + /* + * Quantizer scale factor adaptation. + */ + + /* FUNCTW & FILTD & DELAY */ + /* update non-steady state step size multiplier */ + s->yu = (int16_t) (y + ((wi - y) >> 5)); + + /* LIMB */ + if (s->yu < 544) + s->yu = 544; + else if (s->yu > 5120) + s->yu = 5120; + + /* FILTE & DELAY */ + /* update steady state step size multiplier */ + s->yl += s->yu + ((-s->yl) >> 6); + + /* + * Adaptive predictor coefficients. + */ + if (tr) + { + /* Reset the a's and b's for a modem signal */ + s->a[0] = 0; + s->a[1] = 0; + s->b[0] = 0; + s->b[1] = 0; + s->b[2] = 0; + s->b[3] = 0; + s->b[4] = 0; + s->b[5] = 0; + } + else + { + /* Update the a's and b's */ + /* UPA2 */ + pks1 = pk0 ^ s->pk[0]; + + /* Update predictor pole a[1] */ + a2p = s->a[1] - (s->a[1] >> 7); + if (dqsez != 0) + { + fa1 = (pks1) ? s->a[0] : -s->a[0]; + /* a2p = function of fa1 */ + if (fa1 < -8191) + a2p -= 0x100; + else if (fa1 > 8191) + a2p += 0xFF; + else + a2p += fa1 >> 5; + + if (pk0 ^ s->pk[1]) + { + /* LIMC */ + if (a2p <= -12160) + a2p = -12288; + else if (a2p >= 12416) + a2p = 12288; + else + a2p -= 0x80; + } + else if (a2p <= -12416) + a2p = -12288; + else if (a2p >= 12160) + a2p = 12288; + else + a2p += 0x80; + } + + /* TRIGB & DELAY */ + s->a[1] = a2p; + + /* UPA1 */ + /* Update predictor pole a[0] */ + s->a[0] -= s->a[0] >> 8; + if (dqsez != 0) + { + if (pks1 == 0) + s->a[0] += 192; + else + s->a[0] -= 192; + } + /* LIMD */ + a1ul = 15360 - a2p; + if (s->a[0] < -a1ul) + s->a[0] = -a1ul; + else if (s->a[0] > a1ul) + s->a[0] = a1ul; + + /* UPB : update predictor zeros b[6] */ + for (i = 0; i < 6; i++) + { + /* Distinguish 40Kbps mode from the others */ + s->b[i] -= s->b[i] >> ((s->bits_per_sample == 5) ? 9 : 8); + if (dq & 0x7FFF) + { + /* XOR */ + if ((dq ^ s->dq[i]) >= 0) + s->b[i] += 128; + else + s->b[i] -= 128; + } + } + } + + for (i = 5; i > 0; i--) + s->dq[i] = s->dq[i - 1]; + /* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */ + if (mag == 0) + { + s->dq[0] = (dq >= 0) ? 0x20 : 0xFC20; + } + else + { + exp = (int16_t) (top_bit(mag) + 1); + s->dq[0] = (dq >= 0) + ? ((exp << 6) + ((mag << 6) >> exp)) + : ((exp << 6) + ((mag << 6) >> exp) - 0x400); + } + + s->sr[1] = s->sr[0]; + /* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */ + if (sr == 0) + { + s->sr[0] = 0x20; + } + else if (sr > 0) + { + exp = (int16_t) (top_bit(sr) + 1); + s->sr[0] = (int16_t) ((exp << 6) + ((sr << 6) >> exp)); + } + else if (sr > -32768) + { + mag = (int16_t) -sr; + exp = (int16_t) (top_bit(mag) + 1); + s->sr[0] = (exp << 6) + ((mag << 6) >> exp) - 0x400; + } + else + { + s->sr[0] = (uint16_t) 0xFC20; + } + + /* DELAY A */ + s->pk[1] = s->pk[0]; + s->pk[0] = pk0; + + /* TONE */ + if (tr) /* this sample has been treated as data */ + s->td = FALSE; /* next one will be treated as voice */ + else if (a2p < -11776) /* small sample-to-sample correlation */ + s->td = TRUE; /* signal may be data */ + else /* signal is voice */ + s->td = FALSE; + + /* Adaptation speed control. */ + /* FILTA */ + s->dms += ((int16_t) fi - s->dms) >> 5; + /* FILTB */ + s->dml += (((int16_t) (fi << 2) - s->dml) >> 7); + + if (tr) + s->ap = 256; + else if (y < 1536) /* SUBTC */ + s->ap += (0x200 - s->ap) >> 4; + else if (s->td) + s->ap += (0x200 - s->ap) >> 4; + else if (abs((s->dms << 2) - s->dml) >= (s->dml >> 3)) + s->ap += (0x200 - s->ap) >> 4; + else + s->ap += (-s->ap) >> 4; +} +/*- End of function --------------------------------------------------------*/ + +static int16_t tandem_adjust_alaw(int16_t sr, /* decoder output linear PCM sample */ + int se, /* predictor estimate sample */ + int y, /* quantizer step size */ + int i, /* decoder input code */ + int sign, + const int qtab[], + int quantizer_states) +{ + uint8_t sp; /* A-law compressed 8-bit code */ + int16_t dx; /* prediction error */ + int id; /* quantized prediction error */ + int sd; /* adjusted A-law decoded sample value */ + + if (sr <= -32768) + sr = -1; + sp = linear_to_alaw((sr >> 1) << 3); + /* 16-bit prediction error */ + dx = (int16_t) ((alaw_to_linear(sp) >> 2) - se); + id = quantize(dx, y, qtab, quantizer_states); + if (id == i) + { + /* No adjustment of sp required */ + return (int16_t) sp; + } + /* sp adjustment needed */ + /* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */ + /* 2's complement to biased unsigned */ + if ((id ^ sign) > (i ^ sign)) + { + /* sp adjusted to next lower value */ + if (sp & 0x80) + sd = (sp == 0xD5) ? 0x55 : (((sp ^ 0x55) - 1) ^ 0x55); + else + sd = (sp == 0x2A) ? 0x2A : (((sp ^ 0x55) + 1) ^ 0x55); + } + else + { + /* sp adjusted to next higher value */ + if (sp & 0x80) + sd = (sp == 0xAA) ? 0xAA : (((sp ^ 0x55) + 1) ^ 0x55); + else + sd = (sp == 0x55) ? 0xD5 : (((sp ^ 0x55) - 1) ^ 0x55); + } + return (int16_t) sd; +} +/*- End of function --------------------------------------------------------*/ + +static int16_t tandem_adjust_ulaw(int16_t sr, /* decoder output linear PCM sample */ + int se, /* predictor estimate sample */ + int y, /* quantizer step size */ + int i, /* decoder input code */ + int sign, + const int qtab[], + int quantizer_states) +{ + uint8_t sp; /* u-law compressed 8-bit code */ + int16_t dx; /* prediction error */ + int id; /* quantized prediction error */ + int sd; /* adjusted u-law decoded sample value */ + + if (sr <= -32768) + sr = 0; + sp = linear_to_ulaw(sr << 2); + /* 16-bit prediction error */ + dx = (int16_t) ((ulaw_to_linear(sp) >> 2) - se); + id = quantize(dx, y, qtab, quantizer_states); + if (id == i) + { + /* No adjustment of sp required. */ + return (int16_t) sp; + } + /* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */ + /* 2's complement to biased unsigned */ + if ((id ^ sign) > (i ^ sign)) + { + /* sp adjusted to next lower value */ + if (sp & 0x80) + sd = (sp == 0xFF) ? 0x7E : (sp + 1); + else + sd = (sp == 0x00) ? 0x00 : (sp - 1); + } + else + { + /* sp adjusted to next higher value */ + if (sp & 0x80) + sd = (sp == 0x80) ? 0x80 : (sp - 1); + else + sd = (sp == 0x7F) ? 0xFE : (sp + 1); + } + return (int16_t) sd; +} +/*- End of function --------------------------------------------------------*/ + +/* + * Encodes a linear PCM, A-law or u-law input sample and returns its 3-bit code. + */ +static uint8_t g726_16_encoder(g726_state_t *s, int16_t amp) +{ + int y; + int16_t sei; + int16_t sezi; + int16_t se; + int16_t d; + int16_t sr; + int16_t dqsez; + int16_t dq; + int16_t i; + + sezi = predictor_zero(s); + sei = sezi + predictor_pole(s); + se = sei >> 1; + d = amp - se; + + /* Quantize prediction difference */ + y = step_size(s); + i = quantize(d, y, qtab_726_16, 4); + dq = reconstruct(i & 2, g726_16_dqlntab[i], y); + + /* Reconstruct the signal */ + sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); + + /* Pole prediction difference */ + dqsez = sr + (sezi >> 1) - se; + + update(s, y, g726_16_witab[i], g726_16_fitab[i], dq, sr, dqsez); + return (uint8_t) i; +} +/*- End of function --------------------------------------------------------*/ + +/* + * Decodes a 2-bit CCITT G.726_16 ADPCM code and returns + * the resulting 16-bit linear PCM, A-law or u-law sample value. + */ +static int16_t g726_16_decoder(g726_state_t *s, uint8_t code) +{ + int16_t sezi; + int16_t sei; + int16_t se; + int16_t sr; + int16_t dq; + int16_t dqsez; + int y; + + /* Mask to get proper bits */ + code &= 0x03; + sezi = predictor_zero(s); + sei = sezi + predictor_pole(s); + + y = step_size(s); + dq = reconstruct(code & 2, g726_16_dqlntab[code], y); + + /* Reconstruct the signal */ + se = sei >> 1; + sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); + + /* Pole prediction difference */ + dqsez = sr + (sezi >> 1) - se; + + update(s, y, g726_16_witab[code], g726_16_fitab[code], dq, sr, dqsez); + + switch (s->ext_coding) + { + case G726_ENCODING_ALAW: + return tandem_adjust_alaw(sr, se, y, code, 2, qtab_726_16, 4); + case G726_ENCODING_ULAW: + return tandem_adjust_ulaw(sr, se, y, code, 2, qtab_726_16, 4); + } + return (sr << 2); +} +/*- End of function --------------------------------------------------------*/ + +/* + * Encodes a linear PCM, A-law or u-law input sample and returns its 3-bit code. + */ +static uint8_t g726_24_encoder(g726_state_t *s, int16_t amp) +{ + int16_t sei; + int16_t sezi; + int16_t se; + int16_t d; + int16_t sr; + int16_t dqsez; + int16_t dq; + int16_t i; + int y; + + sezi = predictor_zero(s); + sei = sezi + predictor_pole(s); + se = sei >> 1; + d = amp - se; + + /* Quantize prediction difference */ + y = step_size(s); + i = quantize(d, y, qtab_726_24, 7); + dq = reconstruct(i & 4, g726_24_dqlntab[i], y); + + /* Reconstruct the signal */ + sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); + + /* Pole prediction difference */ + dqsez = sr + (sezi >> 1) - se; + + update(s, y, g726_24_witab[i], g726_24_fitab[i], dq, sr, dqsez); + return (uint8_t) i; +} +/*- End of function --------------------------------------------------------*/ + +/* + * Decodes a 3-bit CCITT G.726_24 ADPCM code and returns + * the resulting 16-bit linear PCM, A-law or u-law sample value. + */ +static int16_t g726_24_decoder(g726_state_t *s, uint8_t code) +{ + int16_t sezi; + int16_t sei; + int16_t se; + int16_t sr; + int16_t dq; + int16_t dqsez; + int y; + + /* Mask to get proper bits */ + code &= 0x07; + sezi = predictor_zero(s); + sei = sezi + predictor_pole(s); + + y = step_size(s); + dq = reconstruct(code & 4, g726_24_dqlntab[code], y); + + /* Reconstruct the signal */ + se = sei >> 1; + sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); + + /* Pole prediction difference */ + dqsez = sr + (sezi >> 1) - se; + + update(s, y, g726_24_witab[code], g726_24_fitab[code], dq, sr, dqsez); + + switch (s->ext_coding) + { + case G726_ENCODING_ALAW: + return tandem_adjust_alaw(sr, se, y, code, 4, qtab_726_24, 7); + case G726_ENCODING_ULAW: + return tandem_adjust_ulaw(sr, se, y, code, 4, qtab_726_24, 7); + } + return (sr << 2); +} +/*- End of function --------------------------------------------------------*/ + +/* + * Encodes a linear input sample and returns its 4-bit code. + */ +static uint8_t g726_32_encoder(g726_state_t *s, int16_t amp) +{ + int16_t sei; + int16_t sezi; + int16_t se; + int16_t d; + int16_t sr; + int16_t dqsez; + int16_t dq; + int16_t i; + int y; + + sezi = predictor_zero(s); + sei = sezi + predictor_pole(s); + se = sei >> 1; + d = amp - se; + + /* Quantize the prediction difference */ + y = step_size(s); + i = quantize(d, y, qtab_726_32, 15); + dq = reconstruct(i & 8, g726_32_dqlntab[i], y); + + /* Reconstruct the signal */ + sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); + + /* Pole prediction difference */ + dqsez = sr + (sezi >> 1) - se; + + update(s, y, g726_32_witab[i], g726_32_fitab[i], dq, sr, dqsez); + return (uint8_t) i; +} +/*- End of function --------------------------------------------------------*/ + +/* + * Decodes a 4-bit CCITT G.726_32 ADPCM code and returns + * the resulting 16-bit linear PCM, A-law or u-law sample value. + */ +static int16_t g726_32_decoder(g726_state_t *s, uint8_t code) +{ + int16_t sezi; + int16_t sei; + int16_t se; + int16_t sr; + int16_t dq; + int16_t dqsez; + int y; + + /* Mask to get proper bits */ + code &= 0x0F; + sezi = predictor_zero(s); + sei = sezi + predictor_pole(s); + + y = step_size(s); + dq = reconstruct(code & 8, g726_32_dqlntab[code], y); + + /* Reconstruct the signal */ + se = sei >> 1; + sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); + + /* Pole prediction difference */ + dqsez = sr + (sezi >> 1) - se; + + update(s, y, g726_32_witab[code], g726_32_fitab[code], dq, sr, dqsez); + + switch (s->ext_coding) + { + case G726_ENCODING_ALAW: + return tandem_adjust_alaw(sr, se, y, code, 8, qtab_726_32, 15); + case G726_ENCODING_ULAW: + return tandem_adjust_ulaw(sr, se, y, code, 8, qtab_726_32, 15); + } + return (sr << 2); +} +/*- End of function --------------------------------------------------------*/ + +/* + * Encodes a 16-bit linear PCM, A-law or u-law input sample and retuens + * the resulting 5-bit CCITT G.726 40Kbps code. + */ +static uint8_t g726_40_encoder(g726_state_t *s, int16_t amp) +{ + int16_t sei; + int16_t sezi; + int16_t se; + int16_t d; + int16_t sr; + int16_t dqsez; + int16_t dq; + int16_t i; + int y; + + sezi = predictor_zero(s); + sei = sezi + predictor_pole(s); + se = sei >> 1; + d = amp - se; + + /* Quantize prediction difference */ + y = step_size(s); + i = quantize(d, y, qtab_726_40, 31); + dq = reconstruct(i & 0x10, g726_40_dqlntab[i], y); + + /* Reconstruct the signal */ + sr = (dq < 0) ? (se - (dq & 0x7FFF)) : (se + dq); + + /* Pole prediction difference */ + dqsez = sr + (sezi >> 1) - se; + + update(s, y, g726_40_witab[i], g726_40_fitab[i], dq, sr, dqsez); + return (uint8_t) i; +} +/*- End of function --------------------------------------------------------*/ + +/* + * Decodes a 5-bit CCITT G.726 40Kbps code and returns + * the resulting 16-bit linear PCM, A-law or u-law sample value. + */ +static int16_t g726_40_decoder(g726_state_t *s, uint8_t code) +{ + int16_t sezi; + int16_t sei; + int16_t se; + int16_t sr; + int16_t dq; + int16_t dqsez; + int y; + + /* Mask to get proper bits */ + code &= 0x1F; + sezi = predictor_zero(s); + sei = sezi + predictor_pole(s); + + y = step_size(s); + dq = reconstruct(code & 0x10, g726_40_dqlntab[code], y); + + /* Reconstruct the signal */ + se = sei >> 1; + sr = (dq < 0) ? (se - (dq & 0x7FFF)) : (se + dq); + + /* Pole prediction difference */ + dqsez = sr + (sezi >> 1) - se; + + update(s, y, g726_40_witab[code], g726_40_fitab[code], dq, sr, dqsez); + + switch (s->ext_coding) + { + case G726_ENCODING_ALAW: + return tandem_adjust_alaw(sr, se, y, code, 0x10, qtab_726_40, 31); + case G726_ENCODING_ULAW: + return tandem_adjust_ulaw(sr, se, y, code, 0x10, qtab_726_40, 31); + } + return (sr << 2); +} +/*- End of function --------------------------------------------------------*/ + +g726_state_t *g726_init(g726_state_t *s, int bit_rate, int ext_coding, int packing) +{ + int i; + + if (bit_rate != 16000 && bit_rate != 24000 && bit_rate != 32000 && bit_rate != 40000) + return NULL; + if (s == NULL) + { + if ((s = (g726_state_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + s->yl = 34816; + s->yu = 544; + s->dms = 0; + s->dml = 0; + s->ap = 0; + s->rate = bit_rate; + s->ext_coding = ext_coding; + s->packing = packing; + for (i = 0; i < 2; i++) + { + s->a[i] = 0; + s->pk[i] = 0; + s->sr[i] = 32; + } + for (i = 0; i < 6; i++) + { + s->b[i] = 0; + s->dq[i] = 32; + } + s->td = FALSE; + switch (bit_rate) + { + case 16000: + s->enc_func = g726_16_encoder; + s->dec_func = g726_16_decoder; + s->bits_per_sample = 2; + break; + case 24000: + s->enc_func = g726_24_encoder; + s->dec_func = g726_24_decoder; + s->bits_per_sample = 3; + break; + case 32000: + default: + s->enc_func = g726_32_encoder; + s->dec_func = g726_32_decoder; + s->bits_per_sample = 4; + break; + case 40000: + s->enc_func = g726_40_encoder; + s->dec_func = g726_40_decoder; + s->bits_per_sample = 5; + break; + } + bitstream_init(&s->bs); + return s; +} +/*- End of function --------------------------------------------------------*/ + +int g726_release(g726_state_t *s) +{ + free(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +int g726_decode(g726_state_t *s, + int16_t amp[], + const uint8_t g726_data[], + int g726_bytes) +{ + int i; + int samples; + uint8_t code; + int sl; + + for (samples = i = 0; ; ) + { + if (s->packing != G726_PACKING_NONE) + { + /* Unpack the code bits */ + if (s->packing != G726_PACKING_LEFT) + { + if (s->bs.residue < s->bits_per_sample) + { + if (i >= g726_bytes) + break; + s->bs.bitstream |= (g726_data[i++] << s->bs.residue); + s->bs.residue += 8; + } + code = (uint8_t) (s->bs.bitstream & ((1 << s->bits_per_sample) - 1)); + s->bs.bitstream >>= s->bits_per_sample; + } + else + { + if (s->bs.residue < s->bits_per_sample) + { + if (i >= g726_bytes) + break; + s->bs.bitstream = (s->bs.bitstream << 8) | g726_data[i++]; + s->bs.residue += 8; + } + code = (uint8_t) ((s->bs.bitstream >> (s->bs.residue - s->bits_per_sample)) & ((1 << s->bits_per_sample) - 1)); + } + s->bs.residue -= s->bits_per_sample; + } + else + { + if (i >= g726_bytes) + break; + code = g726_data[i++]; + } + sl = s->dec_func(s, code); + if (s->ext_coding != G726_ENCODING_LINEAR) + ((uint8_t *) amp)[samples++] = (uint8_t) sl; + else + amp[samples++] = (int16_t) sl; + } + return samples; +} +/*- End of function --------------------------------------------------------*/ + +int g726_encode(g726_state_t *s, + uint8_t g726_data[], + const int16_t amp[], + int len) +{ + int i; + int g726_bytes; + int16_t sl; + uint8_t code; + + for (g726_bytes = i = 0; i < len; i++) + { + /* Linearize the input sample to 14-bit PCM */ + switch (s->ext_coding) + { + case G726_ENCODING_ALAW: + sl = alaw_to_linear(((const uint8_t *) amp)[i]) >> 2; + break; + case G726_ENCODING_ULAW: + sl = ulaw_to_linear(((const uint8_t *) amp)[i]) >> 2; + break; + default: + sl = amp[i] >> 2; + break; + } + code = s->enc_func(s, sl); + if (s->packing != G726_PACKING_NONE) + { + /* Pack the code bits */ + if (s->packing != G726_PACKING_LEFT) + { + s->bs.bitstream |= (code << s->bs.residue); + s->bs.residue += s->bits_per_sample; + if (s->bs.residue >= 8) + { + g726_data[g726_bytes++] = (uint8_t) (s->bs.bitstream & 0xFF); + s->bs.bitstream >>= 8; + s->bs.residue -= 8; + } + } + else + { + s->bs.bitstream = (s->bs.bitstream << s->bits_per_sample) | code; + s->bs.residue += s->bits_per_sample; + if (s->bs.residue >= 8) + { + g726_data[g726_bytes++] = (uint8_t) ((s->bs.bitstream >> (s->bs.residue - 8)) & 0xFF); + s->bs.residue -= 8; + } + } + } + else + { + g726_data[g726_bytes++] = (uint8_t) code; + } + } + return g726_bytes; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/gsm0610_decode.c b/libs/voipcodecs/src/gsm0610_decode.c new file mode 100644 index 0000000000..a4d26371af --- /dev/null +++ b/libs/voipcodecs/src/gsm0610_decode.c @@ -0,0 +1,358 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * gsm0610_decode.c - GSM 06.10 full rate speech codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This code is based on the widely used GSM 06.10 code available from + * http://kbs.cs.tu-berlin.de/~jutta/toast.html + * + * $Id: gsm0610_decode.c,v 1.14 2007/08/21 14:25:54 steveu Exp $ + */ + +/*! \file */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif +#include +#include + +#include "voipcodecs/telephony.h" +#include "voipcodecs/bitstream.h" +#include "voipcodecs/dc_restore.h" +#include "voipcodecs/gsm0610.h" + +#include "gsm0610_local.h" + +/* 4.3 FIXED POINT IMPLEMENTATION OF THE RPE-LTP DECODER */ + +static void postprocessing(gsm0610_state_t *s, int16_t amp[]) +{ + int k; + int16_t msr; + int16_t tmp; + + msr = s->msr; + for (k = 0; k < GSM0610_FRAME_LEN; k++) + { + tmp = gsm_mult_r(msr, 28180); + /* De-emphasis */ + msr = gsm_add(amp[k], tmp); + /* Truncation & upscaling */ + amp[k] = (int16_t) (gsm_add(msr, msr) & 0xFFF8); + } + /*endfor*/ + s->msr = msr; +} +/*- End of function --------------------------------------------------------*/ + +static void decode_a_frame(gsm0610_state_t *s, + int16_t amp[GSM0610_FRAME_LEN], + gsm0610_frame_t *f) +{ + int j; + int k; + int16_t erp[40]; + int16_t wt[GSM0610_FRAME_LEN]; + int16_t *drp; + + drp = s->dp0 + 120; + for (j = 0; j < 4; j++) + { + gsm0610_rpe_decoding(s, f->xmaxc[j], f->Mc[j], f->xMc[j], erp); + gsm0610_long_term_synthesis_filtering(s, f->Nc[j], f->bc[j], erp, drp); + for (k = 0; k < 40; k++) + wt[j*40 + k] = drp[k]; + /*endfor*/ + } + /*endfor*/ + + gsm0610_short_term_synthesis_filter(s, f->LARc, wt, amp); + postprocessing(s, amp); +} +/*- End of function --------------------------------------------------------*/ + +int gsm0610_unpack_none(gsm0610_frame_t *s, const uint8_t c[]) +{ + int i; + int j; + int k; + + i = 0; + for (j = 0; j < 8; j++) + s->LARc[j] = c[i++]; + for (j = 0; j < 4; j++) + { + s->Nc[j] = c[i++]; + s->bc[j] = c[i++]; + s->Mc[j] = c[i++]; + s->xmaxc[j] = c[i++]; + for (k = 0; k < 13; k++) + s->xMc[j][k] = c[i++]; + } + return 76; +} +/*- End of function --------------------------------------------------------*/ + +int gsm0610_unpack_wav49(gsm0610_frame_t *s, const uint8_t c[]) +{ + uint16_t sr; + int i; + + sr = *c++; + s->LARc[0] = sr & 0x3F; + sr >>= 6; + sr |= (uint16_t) *c++ << 2; + s->LARc[1] = sr & 0x3F; + sr >>= 6; + sr |= (uint16_t) *c++ << 4; + s->LARc[2] = sr & 0x1F; + sr >>= 5; + s->LARc[3] = sr & 0x1F; + sr >>= 5; + sr |= (uint16_t) *c++ << 2; + s->LARc[4] = sr & 0xF; + sr >>= 4; + s->LARc[5] = sr & 0xF; + sr >>= 4; + sr |= (uint16_t) *c++ << 2; + s->LARc[6] = sr & 0x7; + sr >>= 3; + s->LARc[7] = sr & 0x7; + sr >>= 3; + + for (i = 0; i < 4; i++) + { + sr |= (uint16_t) *c++ << 4; + s->Nc[i] = sr & 0x7F; + sr >>= 7; + s->bc[i] = sr & 0x3; + sr >>= 2; + s->Mc[i] = sr & 0x3; + sr >>= 2; + sr |= (uint16_t) *c++ << 1; + s->xmaxc[i] = sr & 0x3F; + sr >>= 6; + s->xMc[i][0] = sr & 0x7; + sr >>= 3; + sr = *c++; + s->xMc[i][1] = sr & 0x7; + sr >>= 3; + s->xMc[i][2] = sr & 0x7; + sr >>= 3; + sr |= (uint16_t) *c++ << 2; + s->xMc[i][3] = sr & 0x7; + sr >>= 3; + s->xMc[i][4] = sr & 0x7; + sr >>= 3; + s->xMc[i][5] = sr & 0x7; + sr >>= 3; + sr |= (uint16_t) *c++ << 1; + s->xMc[i][6] = sr & 0x7; + sr >>= 3; + s->xMc[i][7] = sr & 0x7; + sr >>= 3; + s->xMc[i][8] = sr & 0x7; + sr >>= 3; + sr = *c++; + s->xMc[i][9] = sr & 0x7; + sr >>= 3; + s->xMc[i][10] = sr & 0x7; + sr >>= 3; + sr |= (uint16_t) *c++ << 2; + s->xMc[i][11] = sr & 0x7; + sr >>= 3; + s->xMc[i][12] = sr & 0x7; + sr >>= 3; + } + + s++; + sr |= (uint16_t) *c++ << 4; + s->LARc[0] = sr & 0x3F; + sr >>= 6; + s->LARc[1] = sr & 0x3F; + sr >>= 6; + sr = *c++; + s->LARc[2] = sr & 0x1F; + sr >>= 5; + sr |= (uint16_t) *c++ << 3; + s->LARc[3] = sr & 0x1F; + sr >>= 5; + s->LARc[4] = sr & 0xF; + sr >>= 4; + sr |= (uint16_t) *c++ << 2; + s->LARc[5] = sr & 0xF; + sr >>= 4; + s->LARc[6] = sr & 0x7; + sr >>= 3; + s->LARc[7] = sr & 0x7; + sr >>= 3; + + for (i = 0; i < 4; i++) + { + sr = *c++; + s->Nc[i] = sr & 0x7F; + sr >>= 7; + sr |= (uint16_t) *c++ << 1; + s->bc[i] = sr & 0x3; + sr >>= 2; + s->Mc[i] = sr & 0x3; + sr >>= 2; + sr |= (uint16_t) *c++ << 5; + s->xmaxc[i] = sr & 0x3F; + sr >>= 6; + s->xMc[i][0] = sr & 0x7; + sr >>= 3; + s->xMc[i][1] = sr & 0x7; + sr >>= 3; + sr |= (uint16_t) *c++ << 1; + s->xMc[i][2] = sr & 0x7; + sr >>= 3; + s->xMc[i][3] = sr & 0x7; + sr >>= 3; + s->xMc[i][4] = sr & 0x7; + sr >>= 3; + sr = *c++; + s->xMc[i][5] = sr & 0x7; + sr >>= 3; + s->xMc[i][6] = sr & 0x7; + sr >>= 3; + sr |= (uint16_t) *c++ << 2; + s->xMc[i][7] = sr & 0x7; + sr >>= 3; + s->xMc[i][8] = sr & 0x7; + sr >>= 3; + s->xMc[i][9] = sr & 0x7; + sr >>= 3; + sr |= (uint16_t) *c++ << 1; + s->xMc[i][10] = sr & 0x7; + sr >>= 3; + s->xMc[i][11] = sr & 0x7; + sr >>= 3; + s->xMc[i][12] = sr & 0x7; + sr >>= 3; + } + return 65; +} +/*- End of function --------------------------------------------------------*/ + +int gsm0610_unpack_voip(gsm0610_frame_t *s, const uint8_t c[33]) +{ + int i; + + s->LARc[0] = (*c++ & 0xF) << 2; + s->LARc[0] |= (*c >> 6) & 0x3; + s->LARc[1] = *c++ & 0x3F; + s->LARc[2] = (*c >> 3) & 0x1F; + s->LARc[3] = (*c++ & 0x7) << 2; + s->LARc[3] |= (*c >> 6) & 0x3; + s->LARc[4] = (*c >> 2) & 0xF; + s->LARc[5] = (*c++ & 0x3) << 2; + s->LARc[5] |= (*c >> 6) & 0x3; + s->LARc[6] = (*c >> 3) & 0x7; + s->LARc[7] = *c++ & 0x7; + + for (i = 0; i < 4; i++) + { + s->Nc[i] = (*c >> 1) & 0x7F; + s->bc[i] = (*c++ & 0x1) << 1; + s->bc[i] |= (*c >> 7) & 0x1; + s->Mc[i] = (*c >> 5) & 0x3; + s->xmaxc[i] = (*c++ & 0x1F) << 1; + s->xmaxc[i] |= (*c >> 7) & 0x1; + s->xMc[i][0] = (*c >> 4) & 0x7; + s->xMc[i][1] = (*c >> 1) & 0x7; + s->xMc[i][2] = (*c++ & 0x1) << 2; + s->xMc[i][2] |= (*c >> 6) & 0x3; + s->xMc[i][3] = (*c >> 3) & 0x7; + s->xMc[i][4] = *c++ & 0x7; + s->xMc[i][5] = (*c >> 5) & 0x7; + s->xMc[i][6] = (*c >> 2) & 0x7; + s->xMc[i][7] = (*c++ & 0x3) << 1; + s->xMc[i][7] |= (*c >> 7) & 0x1; + s->xMc[i][8] = (*c >> 4) & 0x7; + s->xMc[i][9] = (*c >> 1) & 0x7; + s->xMc[i][10] = (*c++ & 0x1) << 2; + s->xMc[i][10] |= (*c >> 6) & 0x3; + s->xMc[i][11] = (*c >> 3) & 0x7; + s->xMc[i][12] = *c++ & 0x7; + } + return 33; +} +/*- End of function --------------------------------------------------------*/ + +int gsm0610_decode(gsm0610_state_t *s, int16_t amp[], const uint8_t code[], int quant) +{ + gsm0610_frame_t frame[2]; + const uint8_t *c; + int bytes; + int i; + + c = code; + for (i = 0; i < quant; i++) + { + switch (s->packing) + { + default: + case GSM0610_PACKING_NONE: + if ((bytes = gsm0610_unpack_none(frame, c)) >= 0) + { + decode_a_frame(s, amp, frame); + amp += GSM0610_FRAME_LEN; + } + break; + case GSM0610_PACKING_WAV49: + if ((bytes = gsm0610_unpack_wav49(frame, c)) >= 0) + { + decode_a_frame(s, amp, frame); + amp += GSM0610_FRAME_LEN; + decode_a_frame(s, amp, frame + 1); + amp += GSM0610_FRAME_LEN; + } + break; + case GSM0610_PACKING_VOIP: + if ((bytes = gsm0610_unpack_voip(frame, c)) >= 0) + { + decode_a_frame(s, amp, frame); + amp += GSM0610_FRAME_LEN; + } + break; + } + /*endswitch*/ + if (bytes < 0) + return 0; + c += bytes; + } + /*endwhile*/ + return quant*GSM0610_FRAME_LEN; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/gsm0610_encode.c b/libs/voipcodecs/src/gsm0610_encode.c new file mode 100644 index 0000000000..b0ce3004b8 --- /dev/null +++ b/libs/voipcodecs/src/gsm0610_encode.c @@ -0,0 +1,334 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * gsm0610_encode.c - GSM 06.10 full rate speech codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This code is based on the widely used GSM 06.10 code available from + * http://kbs.cs.tu-berlin.de/~jutta/toast.html + * + * $Id: gsm0610_encode.c,v 1.17 2007/11/26 13:28:59 steveu Exp $ + */ + +/*! \file */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif +#include +#include + +#include "voipcodecs/telephony.h" +#include "voipcodecs/bitstream.h" +#include "voipcodecs/dc_restore.h" +#include "voipcodecs/gsm0610.h" + +#include "gsm0610_local.h" + +/* 4.2 FIXED POINT IMPLEMENTATION OF THE RPE-LTP CODER */ + +/* The RPE-LTD coder works on a frame by frame basis. The length of + the frame is equal to 160 samples. Some computations are done + once per frame to produce at the output of the coder the + LARc[1..8] parameters which are the coded LAR coefficients and + also to realize the inverse filtering operation for the entire + frame (160 samples of signal d[0..159]). These parts produce at + the output of the coder: + + Procedure 4.2.11 to 4.2.18 are to be executed four times per + frame. That means once for each sub-segment RPE-LTP analysis of + 40 samples. These parts produce at the output of the coder. +*/ +static void encode_a_frame(gsm0610_state_t *s, gsm0610_frame_t *f, const int16_t amp[]) +{ + int k; + int16_t *dp; + int16_t *dpp; + int16_t so[GSM0610_FRAME_LEN]; + int i; + + dp = s->dp0 + 120; + dpp = dp; + gsm0610_preprocess(s, amp, so); + gsm0610_lpc_analysis(s, so, f->LARc); + gsm0610_short_term_analysis_filter(s, f->LARc, so); + + for (k = 0; k < 4; k++) + { + gsm0610_long_term_predictor(s, + so + k*40, + dp, + s->e + 5, + dpp, + &f->Nc[k], + &f->bc[k]); + gsm0610_rpe_encoding(s, s->e + 5, &f->xmaxc[k], &f->Mc[k], f->xMc[k]); + + for (i = 0; i < 40; i++) + dp[i] = gsm_add(s->e[5 + i], dpp[i]); + /*endfor*/ + dp += 40; + dpp += 40; + } + /*endfor*/ + memcpy((char *) s->dp0, + (char *) (s->dp0 + GSM0610_FRAME_LEN), + 120*sizeof(*s->dp0)); +} +/*- End of function --------------------------------------------------------*/ + +gsm0610_state_t *gsm0610_init(gsm0610_state_t *s, int packing) +{ + if (s == NULL) + { + s = (gsm0610_state_t *) malloc(sizeof (*s)); + if (s == NULL) + return NULL; + /*endif*/ + } + /*endif*/ + memset((char *) s, '\0', sizeof (gsm0610_state_t)); + s->nrp = 40; + s->packing = packing; + return s; +} +/*- End of function --------------------------------------------------------*/ + +int gsm0610_set_packing(gsm0610_state_t *s, int packing) +{ + s->packing = packing; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +int gsm0610_release(gsm0610_state_t *s) +{ + if (s) + free(s); + /*endif*/ + return 0; +} +/*- End of function --------------------------------------------------------*/ + +int gsm0610_pack_none(uint8_t c[], const gsm0610_frame_t *s) +{ + int i; + int j; + int k; + + i = 0; + for (j = 0; j < 8; j++) + c[i++] = (uint8_t) s->LARc[j]; + for (j = 0; j < 4; j++) + { + c[i++] = (uint8_t) s->Nc[j]; + c[i++] = (uint8_t) s->bc[j]; + c[i++] = (uint8_t) s->Mc[j]; + c[i++] = (uint8_t) s->xmaxc[j]; + for (k = 0; k < 13; k++) + c[i++] = (uint8_t) s->xMc[j][k]; + } + return 76; +} +/*- End of function --------------------------------------------------------*/ + +int gsm0610_pack_wav49(uint8_t c[], const gsm0610_frame_t *s) +{ + uint16_t sr; + int i; + + sr = 0; + sr = (sr >> 6) | (s->LARc[0] << 10); + sr = (sr >> 6) | (s->LARc[1] << 10); + *c++ = sr >> 4; + sr = (sr >> 5) | (s->LARc[2] << 11); + *c++ = sr >> 7; + sr = (sr >> 5) | (s->LARc[3] << 11); + sr = (sr >> 4) | (s->LARc[4] << 12); + *c++ = sr >> 6; + sr = (sr >> 4) | (s->LARc[5] << 12); + sr = (sr >> 3) | (s->LARc[6] << 13); + *c++ = sr >> 7; + sr = (sr >> 3) | (s->LARc[7] << 13); + + for (i = 0; i < 4; i++) + { + sr = (sr >> 7) | (s->Nc[i] << 9); + *c++ = sr >> 5; + sr = (sr >> 2) | (s->bc[i] << 14); + sr = (sr >> 2) | (s->Mc[i] << 14); + sr = (sr >> 6) | (s->xmaxc[i] << 10); + *c++ = sr >> 3; + sr = (sr >> 3) | (s->xMc[i][0] << 13); + *c++ = sr >> 8; + sr = (sr >> 3) | (s->xMc[i][1] << 13); + sr = (sr >> 3) | (s->xMc[i][2] << 13); + sr = (sr >> 3) | (s->xMc[i][3] << 13); + *c++ = sr >> 7; + sr = (sr >> 3) | (s->xMc[i][4] << 13); + sr = (sr >> 3) | (s->xMc[i][5] << 13); + sr = (sr >> 3) | (s->xMc[i][6] << 13); + *c++ = sr >> 6; + sr = (sr >> 3) | (s->xMc[i][7] << 13); + sr = (sr >> 3) | (s->xMc[i][8] << 13); + *c++ = sr >> 8; + sr = (sr >> 3) | (s->xMc[i][9] << 13); + sr = (sr >> 3) | (s->xMc[i][10] << 13); + sr = (sr >> 3) | (s->xMc[i][11] << 13); + *c++ = sr >> 7; + sr = (sr >> 3) | (s->xMc[i][12] << 13); + } + + s++; + sr = (sr >> 6) | (s->LARc[0] << 10); + *c++ = sr >> 6; + sr = (sr >> 6) | (s->LARc[1] << 10); + *c++ = sr >> 8; + sr = (sr >> 5) | (s->LARc[2] << 11); + sr = (sr >> 5) | (s->LARc[3] << 11); + *c++ = sr >> 6; + sr = (sr >> 4) | (s->LARc[4] << 12); + sr = (sr >> 4) | (s->LARc[5] << 12); + *c++ = sr >> 6; + sr = (sr >> 3) | (s->LARc[6] << 13); + sr = (sr >> 3) | (s->LARc[7] << 13); + *c++ = sr >> 8; + + for (i = 0; i < 4; i++) + { + sr = (sr >> 7) | (s->Nc[i] << 9); + sr = (sr >> 2) | (s->bc[i] << 14); + *c++ = sr >> 7; + sr = (sr >> 2) | (s->Mc[i] << 14); + sr = (sr >> 6) | (s->xmaxc[i] << 10); + *c++ = sr >> 7; + sr = (sr >> 3) | (s->xMc[i][0] << 13); + sr = (sr >> 3) | (s->xMc[i][1] << 13); + sr = (sr >> 3) | (s->xMc[i][2] << 13); + *c++ = sr >> 6; + sr = (sr >> 3) | (s->xMc[i][3] << 13); + sr = (sr >> 3) | (s->xMc[i][4] << 13); + *c++ = sr >> 8; + sr = (sr >> 3) | (s->xMc[i][5] << 13); + sr = (sr >> 3) | (s->xMc[i][6] << 13); + sr = (sr >> 3) | (s->xMc[i][7] << 13); + *c++ = sr >> 7; + sr = (sr >> 3) | (s->xMc[i][8] << 13); + sr = (sr >> 3) | (s->xMc[i][9] << 13); + sr = (sr >> 3) | (s->xMc[i][10] << 13); + *c++ = sr >> 6; + sr = (sr >> 3) | (s->xMc[i][11] << 13); + sr = (sr >> 3) | (s->xMc[i][12] << 13); + *c++ = sr >> 8; + } + return 65; +} +/*- End of function --------------------------------------------------------*/ + +int gsm0610_pack_voip(uint8_t c[33], const gsm0610_frame_t *s) +{ + int i; + + *c++ = ((GSM0610_MAGIC & 0xF) << 4) + | ((s->LARc[0] >> 2) & 0xF); + *c++ = ((s->LARc[0] & 0x3) << 6) + | (s->LARc[1] & 0x3F); + *c++ = ((s->LARc[2] & 0x1F) << 3) + | ((s->LARc[3] >> 2) & 0x7); + *c++ = ((s->LARc[3] & 0x3) << 6) + | ((s->LARc[4] & 0xF) << 2) + | ((s->LARc[5] >> 2) & 0x3); + *c++ = ((s->LARc[5] & 0x3) << 6) + | ((s->LARc[6] & 0x7) << 3) + | (s->LARc[7] & 0x7); + + for (i = 0; i < 4; i++) + { + *c++ = ((s->Nc[i] & 0x7F) << 1) + | ((s->bc[i] >> 1) & 0x1); + *c++ = ((s->bc[i] & 0x1) << 7) + | ((s->Mc[i] & 0x3) << 5) + | ((s->xmaxc[i] >> 1) & 0x1F); + *c++ = ((s->xmaxc[i] & 0x1) << 7) + | ((s->xMc[i][0] & 0x7) << 4) + | ((s->xMc[i][1] & 0x7) << 1) + | ((s->xMc[i][2] >> 2) & 0x1); + *c++ = ((s->xMc[i][2] & 0x3) << 6) + | ((s->xMc[i][3] & 0x7) << 3) + | (s->xMc[i][4] & 0x7); + *c++ = ((s->xMc[i][5] & 0x7) << 5) + | ((s->xMc[i][6] & 0x7) << 2) + | ((s->xMc[i][7] >> 1) & 0x3); + *c++ = ((s->xMc[i][7] & 0x1) << 7) + | ((s->xMc[i][8] & 0x7) << 4) + | ((s->xMc[i][9] & 0x7) << 1) + | ((s->xMc[i][10] >> 2) & 0x1); + *c++ = ((s->xMc[i][10] & 0x3) << 6) + | ((s->xMc[i][11] & 0x7) << 3) + | (s->xMc[i][12] & 0x7); + } + return 33; +} +/*- End of function --------------------------------------------------------*/ + +int gsm0610_encode(gsm0610_state_t *s, uint8_t code[], const int16_t amp[], int quant) +{ + gsm0610_frame_t frame[2]; + uint8_t *c; + int i; + + c = code; + for (i = 0; i < quant; i++) + { + encode_a_frame(s, frame, amp); + switch (s->packing) + { + case GSM0610_PACKING_NONE: + c += gsm0610_pack_none(c, frame); + amp += GSM0610_FRAME_LEN; + break; + case GSM0610_PACKING_WAV49: + amp += GSM0610_FRAME_LEN; + encode_a_frame(s, frame + 1, amp); + amp += GSM0610_FRAME_LEN; + c += gsm0610_pack_wav49(c, frame); + break; + case GSM0610_PACKING_VOIP: + c += gsm0610_pack_voip(c, frame); + amp += GSM0610_FRAME_LEN; + break; + } + /*endswitch*/ + } + /*endwhile*/ + return (int) (c - code); +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/gsm0610_local.h b/libs/voipcodecs/src/gsm0610_local.h new file mode 100644 index 0000000000..066ec4184d --- /dev/null +++ b/libs/voipcodecs/src/gsm0610_local.h @@ -0,0 +1,229 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * gsm0610_local.h - GSM 06.10 full rate speech codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This code is based on the widely used GSM 06.10 code available from + * http://kbs.cs.tu-berlin.de/~jutta/toast.html + * + * $Id: gsm0610_local.h,v 1.7 2007/01/03 14:15:35 steveu Exp $ + */ + +#if !defined(_GSM0610_LOCAL_H_) +#define _GSM0610_LOCAL_H_ + +#define GSM0610_FRAME_LEN 160 + +#define GSM0610_MAGIC 0xD + +static __inline__ int16_t gsm_add(int16_t a, int16_t b) +{ +#if defined(__GNUC__) && defined(__i386__) + __asm__ __volatile__( + " addw %2,%0;\n" + " jno 0f;\n" + " movw $0x7fff,%0;\n" + " adcw $0,%0;\n" + "0:" + : "=r" (a) + : "0" (a), "ir" (b) + : "cc" + ); + return a; +#else + int32_t sum; + + sum = (int32_t) a + (int32_t) b; + return saturate(sum); +#endif +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int32_t gsm_l_add(int32_t a, int32_t b) +{ +#if defined(__i386__) + __asm__ __volatile__( + " addl %2,%0;\n" + " jno 0f;\n" + " movl $0x7fffffff,%0;\n" + " adcl $0,%0;\n" + "0:" + : "=r" (a) + : "0" (a), "ir" (b) + : "cc" + ); + return a; +#else + uint32_t A; + + if (a < 0) + { + if (b >= 0) + return a + b; + /*endif*/ + A = (uint32_t) -(a + 1) + (uint32_t) -(b + 1); + return (A >= INT32_MAX) ? INT32_MIN : -(int32_t) A - 2; + } + /*endif*/ + if (b <= 0) + return a + b; + /*endif*/ + A = (uint32_t) a + (uint32_t) b; + return (A > INT32_MAX) ? INT32_MAX : A; +#endif +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int16_t gsm_sub(int16_t a, int16_t b) +{ + int32_t diff; + + diff = (int32_t) a - (int32_t) b; + return saturate(diff); +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int16_t gsm_mult(int16_t a, int16_t b) +{ + if (a == INT16_MIN && b == INT16_MIN) + return INT16_MAX; + /*endif*/ + return (int16_t) (((int32_t) a * (int32_t) b) >> 15); +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int32_t gsm_l_mult(int16_t a, int16_t b) +{ + assert (a != INT16_MIN || b != INT16_MIN); + return ((int32_t) a * (int32_t) b) << 1; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int16_t gsm_mult_r(int16_t a, int16_t b) +{ + int32_t prod; + + if (b == INT16_MIN && a == INT16_MIN) + return INT16_MAX; + /*endif*/ + prod = (int32_t) a * (int32_t) b + 16384; + prod >>= 15; + return (int16_t) (prod & 0xFFFF); +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int16_t gsm_abs(int16_t a) +{ + return (a == INT16_MIN) ? INT16_MAX : (int16_t) abs(a); +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int16_t gsm_asr(int16_t a, int n) +{ + if (n >= 16) + return -(a < 0); + /*endif*/ + if (n <= -16) + return 0; + /*endif*/ + if (n < 0) + return a << -n; + /*endif*/ + return a >> n; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int16_t gsm_asl(int16_t a, int n) +{ + if (n >= 16) + return 0; + /*endif*/ + if (n <= -16) + return -(a < 0); + /*endif*/ + if (n < 0) + return gsm_asr(a, -n); + /*endif*/ + return a << n; +} +/*- End of function --------------------------------------------------------*/ + +extern void gsm0610_long_term_predictor(gsm0610_state_t *s, + int16_t d[40], + int16_t *dp, /* [-120..-1] d' IN */ + int16_t e[40], + int16_t dpp[40], + int16_t *Nc, + int16_t *bc); + +extern void gsm0610_lpc_analysis(gsm0610_state_t *s, + int16_t amp[160], + int16_t LARc[8]); + +extern void gsm0610_preprocess(gsm0610_state_t *s, + const int16_t amp[], + int16_t so[]); + +extern void gsm0610_short_term_analysis_filter(gsm0610_state_t *s, + int16_t LARc[8], + int16_t amp[160]); + +extern void gsm0610_long_term_synthesis_filtering(gsm0610_state_t *s, + int16_t Ncr, + int16_t bcr, + int16_t erp[40], + int16_t *drp); /* [-120..-1] IN, [0..40] OUT */ + +extern void gsm0610_rpe_decoding(gsm0610_state_t *s, + int16_t xmaxcr, + int16_t Mcr, + int16_t *xMcr, /* [0..12], 3 bits IN */ + int16_t erp[40]); + +extern void gsm0610_rpe_encoding(gsm0610_state_t *s, + int16_t *e, /* [-5..-1][0..39][40..44] IN/OUT */ + int16_t *xmaxc, + int16_t *Mc, + int16_t xMc[13]); + +extern void gsm0610_short_term_synthesis_filter(gsm0610_state_t *s, + int16_t LARcr[8], + int16_t drp[40], + int16_t amp[160]); + +extern int16_t gsm0610_norm(int32_t a); + +#if defined(__GNUC__) && defined(__i386__) + +void gsm0610_vec_vsraw(const int16_t *p, int n, int bits); + +int32_t gsm0610_vec_iprod(const int16_t *p, const int16_t *q, int n); + +int32_t gsm0610_vec_maxmin(const int16_t *p, int n, int16_t *out); + +int32_t gsm0610_max_cross_corr(const int16_t *wt, const int16_t *dp, int16_t *Nc_out); + +#endif + +#endif + +/*- End of include ---------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/gsm0610_long_term.c b/libs/voipcodecs/src/gsm0610_long_term.c new file mode 100644 index 0000000000..f8bc8902be --- /dev/null +++ b/libs/voipcodecs/src/gsm0610_long_term.c @@ -0,0 +1,408 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * gsm0610_long_term.c - GSM 06.10 full rate speech codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This code is based on the widely used GSM 06.10 code available from + * http://kbs.cs.tu-berlin.de/~jutta/toast.html + * + * $Id: gsm0610_long_term.c,v 1.10 2007/08/20 15:22:22 steveu Exp $ + */ + +/*! \file */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif +#include + +#include "voipcodecs/telephony.h" +#include "voipcodecs/bitstream.h" +#include "voipcodecs/dc_restore.h" +#include "voipcodecs/gsm0610.h" + +#include "gsm0610_local.h" + +/* Table 4.3a Decision level of the LTP gain quantizer */ +static const int16_t gsm_DLB[4] = +{ + 6554, 16384, 26214, 32767 +}; + +/* Table 4.3b Quantization levels of the LTP gain quantizer */ +static const int16_t gsm_QLB[4] = +{ + 3277, 11469, 21299, 32767 +}; + +/* 4.2.11 .. 4.2.12 LONG TERM PREDICTOR (LTP) SECTION */ + +#if defined(__GNUC__) && defined(__i386__) +int32_t gsm0610_max_cross_corr(const int16_t *wt, const int16_t *dp, int16_t *Nc_out) +{ + int32_t lmax; + int32_t out; + + __asm__ __volatile__( + " emms;\n" + " pushl %%ebx;\n" + " movl $0,%%edx;\n" /* Will be maximum inner-product */ + " movl $40,%%ebx;\n" + " movl %%ebx,%%ecx;\n" /* Will be index of max inner-product */ + " subl $80,%%esi;\n" + " .p2align 2;\n" + "1:\n" + " movq (%%edi),%%mm0;\n" + " movq (%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm0;\n" + " movq 8(%%edi),%%mm1;\n" + " movq 8(%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq 16(%%edi),%%mm1;\n" + " movq 16(%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq 24(%%edi),%%mm1;\n" + " movq 24(%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq 32(%%edi),%%mm1;\n" + " movq 32(%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq 40(%%edi),%%mm1;\n" + " movq 40(%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq 48(%%edi),%%mm1;\n" + " movq 48(%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq 56(%%edi),%%mm1;\n" + " movq 56(%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq 64(%%edi),%%mm1;\n" + " movq 64(%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq 72(%%edi),%%mm1;\n" + " movq 72(%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq %%mm0,%%mm1;\n" + " punpckhdq %%mm0,%%mm1;\n" /* mm1 has high int32 of mm0 dup'd */ + " paddd %%mm1,%%mm0;\n" + " movd %%mm0,%%eax;\n" /* eax has result */ + " cmpl %%edx,%%eax;\n" + " jle 2f;\n" + " movl %%eax,%%edx;\n" + " movl %%ebx,%%ecx;\n" + " .p2align 2;\n" + "2:\n" + " subl $2,%%esi;\n" + " incl %%ebx;\n" + " cmpl $120,%%ebx;\n" + " jle 1b;\n" + " popl %%ebx;\n" + " emms;\n" + : "=d" (lmax), "=c" (out) + : "D" (wt), "S" (dp) + : "eax" + ); + *Nc_out = out; + return lmax; +} +/*- End of function --------------------------------------------------------*/ +#endif + +/* This procedure computes the LTP gain (bc) and the LTP lag (Nc) + for the long term analysis filter. This is done by calculating a + maximum of the cross-correlation function between the current + sub-segment short term residual signal d[0..39] (output of + the short term analysis filter; for simplification the index + of this array begins at 0 and ends at 39 for each sub-segment of the + RPE-LTP analysis) and the previous reconstructed short term + residual signal dp[ -120 .. -1 ]. A dynamic scaling must be + performed to avoid overflow. */ + +/* This procedure exists in three versions. First, the integer + version; then, the two floating point versions (as another + function), with or without scaling. */ + +static int16_t evaluate_ltp_parameters(int16_t d[40], + int16_t *dp, // [-120..-1] IN + int16_t *Nc_out) +{ + int k; + int16_t Nc; + int16_t bc; + int16_t wt[40]; + int32_t L_max; + int32_t L_power; + int16_t R; + int16_t S; + int16_t dmax; + int16_t scale; + int16_t temp; + int32_t L_temp; +#if !(defined(__GNUC__) && defined(__i386__)) + int16_t lambda; +#endif + + /* Search of the optimum scaling of d[0..39]. */ + dmax = 0; + for (k = 0; k < 40; k++) + { + temp = d[k]; + temp = gsm_abs(temp); + if (temp > dmax) + dmax = temp; + /*endif*/ + } + /*endfor*/ + + if (dmax == 0) + { + temp = 0; + } + else + { + assert(dmax > 0); + temp = gsm0610_norm((int32_t) dmax << 16); + } + /*endif*/ + + if (temp > 6) + scale = 0; + else + scale = (int16_t) (6 - temp); + /*endif*/ + assert(scale >= 0); + + /* Initialization of a working array wt */ + for (k = 0; k < 40; k++) + wt[k] = d[k] >> scale; + /*endfor*/ + + /* Search for the maximum cross-correlation and coding of the LTP lag */ +#if defined(__GNUC__) && defined(__i386__) + L_max = gsm0610_max_cross_corr(wt, dp, &Nc); +#else + L_max = 0; + Nc = 40; /* index for the maximum cross-correlation */ + + for (lambda = 40; lambda <= 120; lambda++) + { + int32_t L_result; + + L_result = (wt[0]*dp[0 - lambda]) + + (wt[1]*dp[1 - lambda]) + + (wt[2]*dp[2 - lambda]) + + (wt[3]*dp[3 - lambda]) + + (wt[4]*dp[4 - lambda]) + + (wt[5]*dp[5 - lambda]) + + (wt[6]*dp[6 - lambda]) + + (wt[7]*dp[7 - lambda]) + + (wt[8]*dp[8 - lambda]) + + (wt[9]*dp[9 - lambda]) + + (wt[10]*dp[10 - lambda]) + + (wt[11]*dp[11 - lambda]) + + (wt[12]*dp[12 - lambda]) + + (wt[13]*dp[13 - lambda]) + + (wt[14]*dp[14 - lambda]) + + (wt[15]*dp[15 - lambda]) + + (wt[16]*dp[16 - lambda]) + + (wt[17]*dp[17 - lambda]) + + (wt[18]*dp[18 - lambda]) + + (wt[19]*dp[19 - lambda]) + + (wt[20]*dp[20 - lambda]) + + (wt[21]*dp[21 - lambda]) + + (wt[22]*dp[22 - lambda]) + + (wt[23]*dp[23 - lambda]) + + (wt[24]*dp[24 - lambda]) + + (wt[25]*dp[25 - lambda]) + + (wt[26]*dp[26 - lambda]) + + (wt[27]*dp[27 - lambda]) + + (wt[28]*dp[28 - lambda]) + + (wt[29]*dp[29 - lambda]) + + (wt[30]*dp[30 - lambda]) + + (wt[31]*dp[31 - lambda]) + + (wt[32]*dp[32 - lambda]) + + (wt[33]*dp[33 - lambda]) + + (wt[34]*dp[34 - lambda]) + + (wt[35]*dp[35 - lambda]) + + (wt[36]*dp[36 - lambda]) + + (wt[37]*dp[37 - lambda]) + + (wt[38]*dp[38 - lambda]) + + (wt[39]*dp[39 - lambda]); + + if (L_result > L_max) + { + Nc = lambda; + L_max = L_result; + } + /*endif*/ + } + /*endfor*/ +#endif + *Nc_out = Nc; + + L_max <<= 1; + + /* Rescaling of L_max */ + assert(scale <= 100 && scale >= -100); + L_max = L_max >> (6 - scale); + + assert(Nc <= 120 && Nc >= 40); + + /* Compute the power of the reconstructed short term residual signal dp[..] */ + L_power = 0; + for (k = 0; k < 40; k++) + { + L_temp = dp[k - Nc] >> 3; + L_power += L_temp*L_temp; + } + /*endfor*/ + L_power <<= 1; /* from L_MULT */ + + /* Normalization of L_max and L_power */ + if (L_max <= 0) + return 0; + /*endif*/ + if (L_max >= L_power) + return 3; + /*endif*/ + temp = gsm0610_norm(L_power); + + R = (int16_t) ((L_max << temp) >> 16); + S = (int16_t) ((L_power << temp) >> 16); + + /* Coding of the LTP gain */ + + /* Table 4.3a must be used to obtain the level DLB[i] for the + quantization of the LTP gain b to get the coded version bc. */ + for (bc = 0; bc <= 2; bc++) + { + if (R <= gsm_mult(S, gsm_DLB[bc])) + break; + /*endif*/ + } + /*endfor*/ + return bc; +} +/*- End of function --------------------------------------------------------*/ + +/* 4.2.12 */ +static void long_term_analysis_filtering(int16_t bc, + int16_t Nc, + int16_t *dp, // previous d [-120..-1] IN + int16_t d[40], + int16_t dpp[40], + int16_t e[40]) +{ + int k; + + /* In this part, we have to decode the bc parameter to compute + the samples of the estimate dpp[0..39]. The decoding of bc needs the + use of table 4.3b. The long term residual signal e[0..39] + is then calculated to be fed to the RPE encoding section. */ + for (k = 0; k < 40; k++) + { + dpp[k] = gsm_mult_r(gsm_QLB[bc], dp[k - Nc]); + e[k] = gsm_sub(d[k], dpp[k]); + } + /*endfor*/ +} +/*- End of function --------------------------------------------------------*/ + +/* 4x for 160 samples */ +void gsm0610_long_term_predictor(gsm0610_state_t *s, + int16_t d[40], + int16_t *dp, // [-120..-1] d' IN + int16_t e[40], + int16_t dpp[40], + int16_t *Nc, + int16_t *bc) +{ + assert(d); + assert(dp); + assert(e); + assert(dpp); + assert(Nc); + assert(bc); + + *bc = evaluate_ltp_parameters(d, dp, Nc); + long_term_analysis_filtering(*bc, *Nc, dp, d, dpp, e); +} +/*- End of function --------------------------------------------------------*/ + +/* 4.3.2 */ +void gsm0610_long_term_synthesis_filtering(gsm0610_state_t *s, + int16_t Ncr, + int16_t bcr, + int16_t erp[40], + int16_t *drp) // [-120..-1] IN, [0..40] OUT +{ + int k; + int16_t brp; + int16_t drpp; + int16_t Nr; + + /* This procedure uses the bcr and Ncr parameter to realize the + long term synthesis filter. The decoding of bcr needs + table 4.3b. */ + + /* Check the limits of Nr. */ + Nr = (Ncr < 40 || Ncr > 120) ? s->nrp : Ncr; + s->nrp = Nr; + assert (Nr >= 40 && Nr <= 120); + + /* Decode the LTP gain, bcr */ + brp = gsm_QLB[bcr]; + + /* Compute the reconstructed short term residual signal, drp[0..39] */ + assert(brp != INT16_MIN); + for (k = 0; k < 40; k++) + { + drpp = gsm_mult_r(brp, drp[k - Nr]); + drp[k] = gsm_add(erp[k], drpp); + } + /*endfor*/ + + /* Update the reconstructed short term residual signal, drp[-1..-120] */ + for (k = 0; k < 120; k++) + drp[k - 120] = drp[k - 80]; + /*endfor*/ +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/gsm0610_lpc.c b/libs/voipcodecs/src/gsm0610_lpc.c new file mode 100644 index 0000000000..c53e64c7e4 --- /dev/null +++ b/libs/voipcodecs/src/gsm0610_lpc.c @@ -0,0 +1,533 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * gsm0610_lpc.c - GSM 06.10 full rate speech codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This code is based on the widely used GSM 06.10 code available from + * http://kbs.cs.tu-berlin.de/~jutta/toast.html + * + * $Id: gsm0610_lpc.c,v 1.15 2007/08/20 15:22:22 steveu Exp $ + */ + +/*! \file */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif +#include + +#include "voipcodecs/telephony.h" +#include "voipcodecs/bitstream.h" +#include "voipcodecs/bit_operations.h" +#include "voipcodecs/dc_restore.h" +#include "voipcodecs/vector_int.h" +#include "voipcodecs/gsm0610.h" + +#include "gsm0610_local.h" + +/* 4.2.4 .. 4.2.7 LPC ANALYSIS SECTION */ + +/* The number of left shifts needed to normalize the 32 bit + variable x for positive values on the interval + with minimum of + minimum of 1073741824 (01000000000000000000000000000000) and + maximum of 2147483647 (01111111111111111111111111111111) + and for negative values on the interval with + minimum of -2147483648 (-10000000000000000000000000000000) and + maximum of -1073741824 ( -1000000000000000000000000000000). + + In order to normalize the result, the following + operation must be done: norm_var1 = x << gsm0610_norm(x); + + (That's 'ffs', only from the left, not the right..) +*/ + +int16_t gsm0610_norm(int32_t x) +{ + assert(x != 0); + + if (x < 0) + { + if (x <= -1073741824) + return 0; + /*endif*/ + x = ~x; + } + /*endif*/ + return (int16_t) (30 - top_bit(x)); +} +/*- End of function --------------------------------------------------------*/ + +/* + (From p. 46, end of section 4.2.5) + + NOTE: The following lines gives [sic] one correct implementation + of the div(num, denum) arithmetic operation. Compute div + which is the integer division of num by denom: with + denom >= num > 0 +*/ +static int16_t gsm_div(int16_t num, int16_t denom) +{ + int32_t num32; + int32_t denom32; + int16_t div; + int k; + + /* The parameter num sometimes becomes zero. + Although this is explicitly guarded against in 4.2.5, + we assume that the result should then be zero as well. */ + + assert(num >= 0 && denom >= num); + if (num == 0) + return 0; + /*endif*/ + num32 = num; + denom32 = denom; + div = 0; + k = 15; + while (k--) + { + div <<= 1; + num32 <<= 1; + + if (num32 >= denom32) + { + num32 -= denom32; + div++; + } + /*endif*/ + } + /*endwhile*/ + + return div; +} +/*- End of function --------------------------------------------------------*/ + +#if defined(__GNUC__) && defined(__i386__) +void gsm0610_vec_vsraw(const int16_t *p, int n, int bits) +{ + static const int64_t ones = 0x0001000100010001LL; + + if (n == 0) + return; + /*endif*/ + __asm__ __volatile__( + " leal -16(%%esi,%%eax,2),%%edx;\n" /* edx = top - 16 */ + " emms;\n" + " movd %%ecx,%%mm3;\n" + " movq %[ones],%%mm2;\n" + " psllw %%mm3,%%mm2;\n" + " psrlw $1,%%mm2;\n" + " cmpl %%edx,%%esi;" + " ja 4f;\n" + + " .p2align 2;\n" + /* 8 words per iteration */ + "6:\n" + " movq (%%esi),%%mm0;\n" + " movq 8(%%esi),%%mm1;\n" + " paddsw %%mm2,%%mm0;\n" + " psraw %%mm3,%%mm0;\n" + " paddsw %%mm2,%%mm1;\n" + " psraw %%mm3,%%mm1;\n" + " movq %%mm0,(%%esi);\n" + " movq %%mm1,8(%%esi);\n" + " addl $16,%%esi;\n" + " cmpl %%edx,%%esi;\n" + " jbe 6b;\n" + + " .p2align 2;\n" + "4:\n" + " addl $12,%%edx;\n" /* now edx = top-4 */ + " cmpl %%edx,%%esi;\n" + " ja 3f;\n" + + " .p2align 2;\n" + /* do up to 6 words, two per iteration */ + "5:\n" + " movd (%%esi),%%mm0;\n" + " paddsw %%mm2,%%mm0;\n" + " psraw %%mm3,%%mm0;\n" + " movd %%mm0,(%%esi);\n" + " addl $4,%%esi;\n" + " cmpl %%edx,%%esi;\n" + " jbe 5b;\n" + + " .p2align 2;\n" + "3:\n" + " addl $2,%%edx;\n" /* now edx = top-2 */ + " cmpl %%edx,%%esi;\n" + " ja 2f;\n" + + " movzwl (%%esi),%%eax;\n" + " movd %%eax,%%mm0;\n" + " paddsw %%mm2,%%mm0;\n" + " psraw %%mm3,%%mm0;\n" + " movd %%mm0,%%eax;\n" + " movw %%ax,(%%esi);\n" + + " .p2align 2;\n" + "2:\n" + " emms;\n" + : + : "S" (p), "a" (n), "c" (bits), [ones] "m" (ones) + : "edx" + ); +} +/*- End of function --------------------------------------------------------*/ +#endif + +/* 4.2.4 */ +static void autocorrelation(int16_t amp[GSM0610_FRAME_LEN], int32_t L_ACF[9]) +{ + int k; + int16_t smax; + int16_t scalauto; +#if !(defined(__GNUC__) && defined(__i386__)) + int i; + int temp; + int16_t *sp; + int16_t sl; +#endif + + /* The goal is to compute the array L_ACF[k]. The signal s[i] must + be scaled in order to avoid an overflow situation. */ + + /* Dynamic scaling of the array s[0..159] */ + /* Search for the maximum. */ +#if defined(__GNUC__) && defined(__i386__) + smax = saturate(vec_min_maxi16(amp, GSM0610_FRAME_LEN, NULL)); +#else + for (smax = 0, k = 0; k < GSM0610_FRAME_LEN; k++) + { + temp = gsm_abs(amp[k]); + if (temp > smax) + smax = (int16_t) temp; + /*endif*/ + } + /*endfor*/ +#endif + + /* Computation of the scaling factor. */ + if (smax == 0) + { + scalauto = 0; + } + else + { + assert(smax > 0); + scalauto = (int16_t) (4 - gsm0610_norm((int32_t) smax << 16)); + } + /*endif*/ + + /* Scaling of the array s[0...159] */ +#if defined(__GNUC__) && defined(__i386__) + if (scalauto > 0) + gsm0610_vec_vsraw(amp, GSM0610_FRAME_LEN, scalauto); + /*endif*/ +#else + if (scalauto > 0) + { + for (k = 0; k < GSM0610_FRAME_LEN; k++) + amp[k] = gsm_mult_r(amp[k], 16384 >> (scalauto - 1)); + /*endfor*/ + } + /*endif*/ +#endif + + /* Compute the L_ACF[..]. */ +#if defined(__GNUC__) && defined(__i386__) + for (k = 0; k < 9; k++) + L_ACF[k] = vec_dot_prodi16(amp, amp + k, GSM0610_FRAME_LEN - k) << 1; + /*endfor*/ +#else + sp = amp; + sl = *sp; + L_ACF[0] = ((int32_t) sl*sp[0]); + sl = *++sp; + L_ACF[0] += ((int32_t) sl*sp[0]); + L_ACF[1] = ((int32_t) sl*sp[-1]); + sl = *++sp; + L_ACF[0] += ((int32_t) sl*sp[0]); + L_ACF[1] += ((int32_t) sl*sp[-1]); + L_ACF[2] = ((int32_t) sl*sp[-2]); + sl = *++sp; + L_ACF[0] += ((int32_t) sl*sp[0]); + L_ACF[1] += ((int32_t) sl*sp[-1]); + L_ACF[2] += ((int32_t) sl*sp[-2]); + L_ACF[3] = ((int32_t) sl*sp[-3]); + sl = *++sp; + L_ACF[0] += ((int32_t) sl*sp[0]); + L_ACF[1] += ((int32_t) sl*sp[-1]); + L_ACF[2] += ((int32_t) sl*sp[-2]); + L_ACF[3] += ((int32_t) sl*sp[-3]); + L_ACF[4] = ((int32_t) sl*sp[-4]); + sl = *++sp; + L_ACF[0] += ((int32_t) sl*sp[0]); + L_ACF[1] += ((int32_t) sl*sp[-1]); + L_ACF[2] += ((int32_t) sl*sp[-2]); + L_ACF[3] += ((int32_t) sl*sp[-3]); + L_ACF[4] += ((int32_t) sl*sp[-4]); + L_ACF[5] = ((int32_t) sl*sp[-5]); + sl = *++sp; + L_ACF[0] += ((int32_t) sl*sp[0]); + L_ACF[1] += ((int32_t) sl*sp[-1]); + L_ACF[2] += ((int32_t) sl*sp[-2]); + L_ACF[3] += ((int32_t) sl*sp[-3]); + L_ACF[4] += ((int32_t) sl*sp[-4]); + L_ACF[5] += ((int32_t) sl*sp[-5]); + L_ACF[6] = ((int32_t) sl*sp[-6]); + sl = *++sp; + L_ACF[0] += ((int32_t) sl*sp[0]); + L_ACF[1] += ((int32_t) sl*sp[-1]); + L_ACF[2] += ((int32_t) sl*sp[-2]); + L_ACF[3] += ((int32_t) sl*sp[-3]); + L_ACF[4] += ((int32_t) sl*sp[-4]); + L_ACF[5] += ((int32_t) sl*sp[-5]); + L_ACF[6] += ((int32_t) sl*sp[-6]); + L_ACF[7] = ((int32_t) sl*sp[-7]); + sl = *++sp; + L_ACF[0] += ((int32_t) sl*sp[0]); + L_ACF[1] += ((int32_t) sl*sp[-1]); + L_ACF[2] += ((int32_t) sl*sp[-2]); + L_ACF[3] += ((int32_t) sl*sp[-3]); + L_ACF[4] += ((int32_t) sl*sp[-4]); + L_ACF[5] += ((int32_t) sl*sp[-5]); + L_ACF[6] += ((int32_t) sl*sp[-6]); + L_ACF[7] += ((int32_t) sl*sp[-7]); + L_ACF[8] = ((int32_t) sl*sp[-8]); + for (i = 9; i < GSM0610_FRAME_LEN; i++) + { + sl = *++sp; + L_ACF[0] += ((int32_t) sl*sp[0]); + L_ACF[1] += ((int32_t) sl*sp[-1]); + L_ACF[2] += ((int32_t) sl*sp[-2]); + L_ACF[3] += ((int32_t) sl*sp[-3]); + L_ACF[4] += ((int32_t) sl*sp[-4]); + L_ACF[5] += ((int32_t) sl*sp[-5]); + L_ACF[6] += ((int32_t) sl*sp[-6]); + L_ACF[7] += ((int32_t) sl*sp[-7]); + L_ACF[8] += ((int32_t) sl*sp[-8]); + } + /*endfor*/ + for (k = 0; k < 9; k++) + L_ACF[k] <<= 1; + /*endfor*/ +#endif + /* Rescaling of the array s[0..159] */ + if (scalauto > 0) + { + assert(scalauto <= 4); + for (k = 0; k < GSM0610_FRAME_LEN; k++) + amp[k] <<= scalauto; + /*endfor*/ + } + /*endif*/ +} +/*- End of function --------------------------------------------------------*/ + +/* 4.2.5 */ +static void reflection_coefficients(int32_t L_ACF[9], int16_t r[8]) +{ + int i; + int m; + int n; + int16_t temp; + int16_t ACF[9]; + int16_t P[9]; + int16_t K[9]; + + /* Schur recursion with 16 bits arithmetic. */ + if (L_ACF[0] == 0) + { + for (i = 8; i--; *r++ = 0) + ; + /*endfor*/ + return; + } + /*endif*/ + + assert(L_ACF[0] != 0); + temp = gsm0610_norm(L_ACF[0]); + + assert(temp >= 0 && temp < 32); + + /* ? overflow ? */ + for (i = 0; i <= 8; i++) + ACF[i] = (int16_t) ((L_ACF[i] << temp) >> 16); + /*endfor*/ + + /* Initialize array P[..] and K[..] for the recursion. */ + for (i = 1; i <= 7; i++) + K[i] = ACF[i]; + /*endfor*/ + for (i = 0; i <= 8; i++) + P[i] = ACF[i]; + /*endfor*/ + /* Compute reflection coefficients */ + for (n = 1; n <= 8; n++, r++) + { + temp = P[1]; + temp = gsm_abs (temp); + if (P[0] < temp) + { + for (i = n; i <= 8; i++) + *r++ = 0; + /*endfor*/ + return; + } + /*endif*/ + + *r = gsm_div(temp, P[0]); + + assert(*r >= 0); + if (P[1] > 0) + *r = -*r; /* r[n] = sub(0, r[n]) */ + /*endif*/ + assert(*r != INT16_MIN); + if (n == 8) + return; + /*endif*/ + + /* Schur recursion */ + temp = gsm_mult_r(P[1], *r); + P[0] = gsm_add(P[0], temp); + + for (m = 1; m <= 8 - n; m++) + { + temp = gsm_mult_r(K[m], *r); + P[m] = gsm_add(P[m + 1], temp); + + temp = gsm_mult_r(P[m + 1], *r); + K[m] = gsm_add(K[m], temp); + } + /*endfor*/ + } + /*endfor*/ +} +/*- End of function --------------------------------------------------------*/ + +/* 4.2.6 */ +static void transform_to_log_area_ratios(int16_t r[8]) +{ + int16_t temp; + int i; + + /* The following scaling for r[..] and LAR[..] has been used: + + r[..] = integer (real_r[..]*32768.); -1 <= real_r < 1. + LAR[..] = integer (real_LAR[..] * 16384); + with -1.625 <= real_LAR <= 1.625 + */ + + /* Computation of the LAR[0..7] from the r[0..7] */ + for (i = 1; i <= 8; i++, r++) + { + temp = *r; + temp = gsm_abs(temp); + assert(temp >= 0); + + if (temp < 22118) + { + temp >>= 1; + } + else if (temp < 31130) + { + assert(temp >= 11059); + temp -= 11059; + } + else + { + assert(temp >= 26112); + temp -= 26112; + temp <<= 2; + } + /*endif*/ + + *r = (*r < 0) ? -temp : temp; + assert(*r != INT16_MIN); + } + /*endfor*/ +} +/*- End of function --------------------------------------------------------*/ + +/* 4.2.7 */ +static void quantization_and_coding(int16_t LAR[8]) +{ + int16_t temp; + + /* This procedure needs four tables; the following equations + give the optimum scaling for the constants: + + A[0..7] = integer(real_A[0..7] * 1024) + B[0..7] = integer(real_B[0..7] * 512) + MAC[0..7] = maximum of the LARc[0..7] + MIC[0..7] = minimum of the LARc[0..7] */ + +#undef STEP +#define STEP(A,B,MAC,MIC) \ + temp = gsm_mult(A, *LAR); \ + temp = gsm_add(temp, B); \ + temp = gsm_add(temp, 256); \ + temp >>= 9; \ + *LAR = (int16_t) ((temp > MAC) \ + ? \ + MAC - MIC \ + : \ + ((temp < MIC) ? 0 : temp - MIC)); \ + LAR++; + + STEP(20480, 0, 31, -32); + STEP(20480, 0, 31, -32); + STEP(20480, 2048, 15, -16); + STEP(20480, -2560, 15, -16); + + STEP(13964, 94, 7, -8); + STEP(15360, -1792, 7, -8); + STEP( 8534, -341, 3, -4); + STEP( 9036, -1144, 3, -4); +#undef STEP +} +/*- End of function --------------------------------------------------------*/ + +void gsm0610_lpc_analysis(gsm0610_state_t *s, + int16_t amp[GSM0610_FRAME_LEN], + int16_t LARc[8]) +{ + int32_t L_ACF[9]; + + autocorrelation(amp, L_ACF); + reflection_coefficients(L_ACF, LARc); + transform_to_log_area_ratios(LARc); + quantization_and_coding(LARc); +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/gsm0610_preprocess.c b/libs/voipcodecs/src/gsm0610_preprocess.c new file mode 100644 index 0000000000..cef911a5cc --- /dev/null +++ b/libs/voipcodecs/src/gsm0610_preprocess.c @@ -0,0 +1,149 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * gsm0610_preprocess.c - GSM 06.10 full rate speech codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This code is based on the widely used GSM 06.10 code available from + * http://kbs.cs.tu-berlin.de/~jutta/toast.html + * + * $Id: gsm0610_preprocess.c,v 1.8 2007/08/20 15:22:22 steveu Exp $ + */ + +/*! \file */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif +#include + +#include "voipcodecs/telephony.h" +#include "voipcodecs/bitstream.h" +#include "voipcodecs/dc_restore.h" +#include "voipcodecs/gsm0610.h" + +#include "gsm0610_local.h" + +/* + 4.2.0 .. 4.2.3 PREPROCESSING SECTION + + After A-law to linear conversion (or directly from the + A to D converter) the following scaling is assumed for + input to the RPE-LTP algorithm: + + in: 0.1.....................12 + S.v.v.v.v.v.v.v.v.v.v.v.v.*.*.* + + Where S is the sign bit, v a valid bit, and * a "don't care" bit. + The original signal is called sop[..] + + out: 0.1................... 12 + S.S.v.v.v.v.v.v.v.v.v.v.v.v.0.0 +*/ + +void gsm0610_preprocess(gsm0610_state_t *s, const int16_t amp[GSM0610_FRAME_LEN], int16_t so[GSM0610_FRAME_LEN]) +{ + int16_t z1; + int16_t mp; + int16_t s1; + int16_t msp; + int16_t SO; + int32_t L_z2; + int32_t L_s2; + int32_t L_temp; +#if !defined(__GNUC__) + int16_t lsp; +#endif + int k; + + z1 = s->z1; + L_z2 = s->L_z2; + mp = s->mp; + for (k = 0; k < GSM0610_FRAME_LEN; k++) + { + /* 4.2.1 Downscaling of the input signal */ + SO = (amp[k] >> 1) & ~3; + + assert(SO >= -0x4000); // downscaled by + assert(SO <= 0x3FFC); // previous routine. + + /* 4.2.2 Offset compensation */ + + /* This part implements a high-pass filter and requires extended + arithmetic precision for the recursive part of this filter. + The input of this procedure is the array so[0...159] and the + output the array sof[ 0...159 ]. + */ + /* Compute the non-recursive part */ + s1 = SO - z1; + z1 = SO; + + assert(s1 != INT16_MIN); + + /* Compute the recursive part */ + L_s2 = s1; + L_s2 <<= 15; + + /* Perform a 31 by 16 bits multiplication */ +#if defined(__GNUC__) + L_z2 = ((int64_t) L_z2*32735 + 0x4000) >> 15; + /* Alternate (ANSI) version of below line does slightly different rounding: + * L_temp = L_z2 >> 9; + * L_temp += L_temp >> 5; + * L_temp = (++L_temp) >> 1; + * L_z2 = L_z2 - L_temp; + */ + L_z2 = gsm_l_add(L_z2, L_s2); +#else + /* This does L_z2 = L_z2 * 0x7FD5/0x8000 + L_s2 */ + msp = (int16_t) (L_z2 >> 15); + lsp = (int16_t) (L_z2 - ((int32_t) msp << 15)); + + L_s2 += gsm_mult_r(lsp, 32735); + L_temp = (int32_t) msp*32735; + L_z2 = gsm_l_add(L_temp, L_s2); +#endif + + /* Compute sof[k] with rounding */ + L_temp = gsm_l_add(L_z2, 16384); + + /* 4.2.3 Preemphasis */ + msp = gsm_mult_r(mp, -28180); + mp = (int16_t) (L_temp >> 15); + so[k] = gsm_add(mp, msp); + } + /*endfor*/ + + s->z1 = z1; + s->L_z2 = L_z2; + s->mp = mp; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/gsm0610_rpe.c b/libs/voipcodecs/src/gsm0610_rpe.c new file mode 100644 index 0000000000..2e03fd9098 --- /dev/null +++ b/libs/voipcodecs/src/gsm0610_rpe.c @@ -0,0 +1,531 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * gsm0610_rpe.c - GSM 06.10 full rate speech codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This code is based on the widely used GSM 06.10 code available from + * http://kbs.cs.tu-berlin.de/~jutta/toast.html + * + * $Id: gsm0610_rpe.c,v 1.14 2007/08/20 15:22:22 steveu Exp $ + */ + +/*! \file */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif +#include + +#include "voipcodecs/telephony.h" +#include "voipcodecs/bitstream.h" +#include "voipcodecs/dc_restore.h" +#include "voipcodecs/gsm0610.h" + +#include "gsm0610_local.h" + +/* 4.2.13 .. 4.2.17 RPE ENCODING SECTION */ + +/* 4.2.13 */ +static void weighting_filter(const int16_t *e, // signal [-5..0.39.44] IN + int16_t x[40]) +{ +#if defined(__GNUC__) && defined(__i386__) + /* Table 4.4 Coefficients of the weighting filter */ + /* This must be padded to a multiple of 4 for MMX to work */ + static const int16_t gsm_H[12] = + { + -134, -374, 0, 2054, 5741, 8192, 5741, 2054, 0, -374, -134, 0 + }; + + __asm__ __volatile__( + " emms;\n" + " addl $-10,%%ecx;\n" + " movl $0x1000,%%eax;\n" + " movd %%eax,%%mm5;\n" /* for rounding */ + " movq %[gsm_H],%%mm1;\n" + " movq %[gsm_H8],%%mm2;\n" + " movq %[gsm_H16],%%mm3;\n" + " xorl %%esi,%%esi;\n" + " .p2align 2;\n" + "1:;\n" + " movq (%%ecx,%%esi,2),%%mm0;\n" + " pmaddwd %%mm1,%%mm0;\n" + + " movq 8(%%ecx,%%esi,2),%%mm4;\n" + " pmaddwd %%mm2,%%mm4;\n" + " paddd %%mm4,%%mm0;\n" + + " movq 16(%%ecx,%%esi,2),%%mm4;\n" + " pmaddwd %%mm3,%%mm4;\n" + " paddd %%mm4,%%mm0;\n" + + " movq %%mm0,%%mm4;\n" + " punpckhdq %%mm0,%%mm4;\n" /* mm4 has high int32 of mm0 dup'd */ + " paddd %%mm4,%%mm0;\n" + + " paddd %%mm5,%%mm0;\n" /* Add for roundoff */ + " psrad $13,%%mm0;\n" + " packssdw %%mm0,%%mm0;\n" + " movd %%mm0,%%eax;\n" /* eax has result */ + " movw %%ax,(%%edi,%%esi,2);\n" + " incl %%esi;\n" + " cmpl $39,%%esi;\n" + " jle 1b;\n" + " emms;\n" + : + : "c" (e), "D" (x), [gsm_H] "X" (*((int64_t *) gsm_H)), [gsm_H8] "X" (*((int64_t *) (gsm_H + 4))), [gsm_H16] "X" (*((int64_t *) (gsm_H + 8))) + : "eax", "edx", "esi" + ); +#else + int32_t L_result; + int k; + + /* The coefficients of the weighting filter are stored in a table + (see table 4.4). The following scaling is used: + + H[0..10] = integer(real_H[0..10] * 8192); + */ + /* Initialization of a temporary working array wt[0...49] */ + + /* for (k = 0; k <= 4; k++) wt[k] = 0; + * for (k = 5; k <= 44; k++) wt[k] = *e++; + * for (k = 45; k <= 49; k++) wt[k] = 0; + * + * (e[-5..-1] and e[40..44] are allocated by the caller, + * are initially zero and are not written anywhere.) + */ + e -= 5; + + /* Compute the signal x[0..39] */ + for (k = 0; k < 40; k++) + { + L_result = 8192 >> 1; + + /* for (i = 0; i <= 10; i++) + * { + * L_temp = gsm_l_mult(wt[k + i], gsm_H[i]); + * L_result = gsm_l_add(L_result, L_temp); + * } + */ + +#undef STEP +#define STEP(i,H) (e[k + i] * (int32_t) H) + + /* Every one of these multiplications is done twice, + but I don't see an elegant way to optimize this. + Do you? + */ + L_result += STEP( 0, -134); + L_result += STEP( 1, -374); + // += STEP( 2, 0 ); + L_result += STEP( 3, 2054); + L_result += STEP( 4, 5741); + L_result += STEP( 5, 8192); + L_result += STEP( 6, 5741); + L_result += STEP( 7, 2054); + // += STEP( 8, 0 ); + L_result += STEP( 9, -374); + L_result += STEP(10, -134); + + /* 2 adds vs. >> 16 => 14, minus one shift to compensate for + those we lost when replacing L_MULT by '*'. */ + L_result >>= 13; + x[k] = saturate(L_result); + } + /*endfor*/ +#endif +} +/*- End of function --------------------------------------------------------*/ + +/* 4.2.14 */ +static void rpe_grid_selection(int16_t x[40], int16_t xM[13], int16_t *Mc_out) +{ + int i; + int32_t L_result; + int32_t L_temp; + int32_t EM; /* xxx should be L_EM? */ + int16_t Mc; + int32_t L_common_0_3; + + /* The signal x[0..39] is used to select the RPE grid which is + represented by Mc. */ + + EM = 0; + Mc = 0; + +#undef STEP +#define STEP(m,i) \ + L_temp = x[m + 3*i] >> 2; \ + L_result += L_temp*L_temp; + + /* Common part of 0 and 3 */ + L_result = 0; + STEP(0, 1); + STEP(0, 2); + STEP(0, 3); + STEP(0, 4); + STEP(0, 5); + STEP(0, 6); + STEP(0, 7); + STEP(0, 8); + STEP(0, 9); + STEP(0, 10); + STEP(0, 11); + STEP(0, 12); + L_common_0_3 = L_result; + + /* i = 0 */ + + STEP(0, 0); + L_result <<= 1; /* implicit in L_MULT */ + EM = L_result; + + /* i = 1 */ + + L_result = 0; + STEP(1, 0); + STEP(1, 1); + STEP(1, 2); + STEP(1, 3); + STEP(1, 4); + STEP(1, 5); + STEP(1, 6); + STEP(1, 7); + STEP(1, 8); + STEP(1, 9); + STEP(1, 10); + STEP(1, 11); + STEP(1, 12); + L_result <<= 1; + if (L_result > EM) + { + Mc = 1; + EM = L_result; + } + /*endif*/ + + /* i = 2 */ + + L_result = 0; + STEP(2, 0); + STEP(2, 1); + STEP(2, 2); + STEP(2, 3); + STEP(2, 4); + STEP(2, 5); + STEP(2, 6); + STEP(2, 7); + STEP(2, 8); + STEP(2, 9); + STEP(2, 10); + STEP(2, 11); + STEP(2, 12); + L_result <<= 1; + if (L_result > EM) + { + Mc = 2; + EM = L_result; + } + /*endif*/ + + /* i = 3 */ + + L_result = L_common_0_3; + STEP(3, 12); + L_result <<= 1; + if (L_result > EM) + { + Mc = 3; + EM = L_result; + } + /*endif*/ + + /* Down-sampling by a factor 3 to get the selected xM[0..12] + RPE sequence. */ + for (i = 0; i < 13; i++) + xM[i] = x[Mc + 3*i]; + /*endfor*/ + *Mc_out = Mc; +} +/*- End of function --------------------------------------------------------*/ + +/* 4.12.15 */ +static void apcm_quantization_xmaxc_to_exp_mant(int16_t xmaxc, + int16_t *exp_out, + int16_t *mant_out) +{ + int16_t exp; + int16_t mant; + + /* Compute exponent and mantissa of the decoded version of xmaxc */ + exp = 0; + if (xmaxc > 15) + exp = (int16_t) ((xmaxc >> 3) - 1); + /*endif*/ + mant = xmaxc - (exp << 3); + + if (mant == 0) + { + exp = -4; + mant = 7; + } + else + { + while (mant <= 7) + { + mant = (int16_t) (mant << 1 | 1); + exp--; + } + /*endwhile*/ + mant -= 8; + } + /*endif*/ + + assert(exp >= -4 && exp <= 6); + assert(mant >= 0 && mant <= 7); + + *exp_out = exp; + *mant_out = mant; +} +/*- End of function --------------------------------------------------------*/ + +static void apcm_quantization(int16_t xM[13], + int16_t xMc[13], + int16_t *mant_out, + int16_t *exp_out, + int16_t *xmaxc_out) +{ + /* Table 4.5 Normalized inverse mantissa used to compute xM/xmax */ + static const int16_t gsm_NRFAC[8] = + { + 29128, 26215, 23832, 21846, 20165, 18725, 17476, 16384 + }; + int i; + int itest; + int16_t xmax; + int16_t xmaxc; + int16_t temp; + int16_t temp1; + int16_t temp2; + int16_t exp; + int16_t mant; + + /* Find the maximum absolute value xmax of xM[0..12]. */ + xmax = 0; + for (i = 0; i < 13; i++) + { + temp = xM[i]; + temp = gsm_abs(temp); + if (temp > xmax) + xmax = temp; + /*endif*/ + } + /*endfor*/ + + /* Quantizing and coding of xmax to get xmaxc. */ + exp = 0; + temp = xmax >> 9; + itest = 0; + + for (i = 0; i <= 5; i++) + { + itest |= (temp <= 0); + temp >>= 1; + + assert(exp <= 5); + if (itest == 0) + exp++; + /*endif*/ + } + /*endfor*/ + + assert(exp <= 6 && exp >= 0); + temp = (int16_t) (exp + 5); + + assert(temp <= 11 && temp >= 0); + xmaxc = gsm_add((xmax >> temp), exp << 3); + + /* Quantizing and coding of the xM[0..12] RPE sequence + to get the xMc[0..12] */ + apcm_quantization_xmaxc_to_exp_mant(xmaxc, &exp, &mant); + + /* This computation uses the fact that the decoded version of xmaxc + can be calculated by using the exponent and the mantissa part of + xmaxc (logarithmic table). + So, this method avoids any division and uses only a scaling + of the RPE samples by a function of the exponent. A direct + multiplication by the inverse of the mantissa (NRFAC[0..7] + found in table 4.5) gives the 3 bit coded version xMc[0..12] + of the RPE samples. + */ + /* Direct computation of xMc[0..12] using table 4.5 */ + assert(exp <= 4096 && exp >= -4096); + assert(mant >= 0 && mant <= 7); + + temp1 = (int16_t) (6 - exp); /* Normalization by the exponent */ + temp2 = gsm_NRFAC[mant]; /* Inverse mantissa */ + + for (i = 0; i < 13; i++) + { + assert(temp1 >= 0 && temp1 < 16); + + temp = xM[i] << temp1; + temp = gsm_mult(temp, temp2); + temp >>= 12; + xMc[i] = (int16_t) (temp + 4); /* See note below */ + } + /*endfor*/ + + /* NOTE: This equation is used to make all the xMc[i] positive. */ + *mant_out = mant; + *exp_out = exp; + *xmaxc_out = xmaxc; +} +/*- End of function --------------------------------------------------------*/ + +/* 4.2.16 */ +static void apcm_inverse_quantization(int16_t xMc[13], + int16_t mant, + int16_t exp, + int16_t xMp[13]) +{ + /* Table 4.6 Normalized direct mantissa used to compute xM/xmax */ + static const int16_t gsm_FAC[8] = + { + 18431, 20479, 22527, 24575, 26623, 28671, 30719, 32767 + }; + int i; + int16_t temp; + int16_t temp1; + int16_t temp2; + int16_t temp3; + + /* This part is for decoding the RPE sequence of coded xMc[0..12] + samples to obtain the xMp[0..12] array. Table 4.6 is used to get + the mantissa of xmaxc (FAC[0..7]). + */ + assert(mant >= 0 && mant <= 7); + + temp1 = gsm_FAC[mant]; /* See 4.2-15 for mant */ + temp2 = gsm_sub(6, exp); /* See 4.2-15 for exp */ + temp3 = gsm_asl(1, gsm_sub (temp2, 1)); + + for (i = 0; i < 13; i++) + { + assert(xMc[i] >= 0 && xMc[i] <= 7); /* 3 bit unsigned */ + + temp = (int16_t) ((xMc[i] << 1) - 7); /* Restore sign */ + assert(temp <= 7 && temp >= -7); /* 4 bit signed */ + + temp <<= 12; /* 16 bit signed */ + temp = gsm_mult_r(temp1, temp); + temp = gsm_add(temp, temp3); + xMp[i] = gsm_asr(temp, temp2); + } + /*endfor*/ +} +/*- End of function --------------------------------------------------------*/ + +/* 4.2.17 */ +static void rpe_grid_positioning(int16_t Mc, + int16_t xMp[13], + int16_t ep[40]) +{ + int i = 13; + + /* This procedure computes the reconstructed long term residual signal + ep[0..39] for the LTP analysis filter. The inputs are the Mc + which is the grid position selection and the xMp[0..12] decoded + RPE samples which are upsampled by a factor of 3 by inserting zero + values. + */ + assert(0 <= Mc && Mc <= 3); + + switch (Mc) + { + case 3: + *ep++ = 0; + case 2: + do + { + *ep++ = 0; + case 1: + *ep++ = 0; + case 0: + *ep++ = *xMp++; + } + while (--i); + } + /*endswitch*/ + while (++Mc < 4) + *ep++ = 0; + /*endwhile*/ +} +/*- End of function --------------------------------------------------------*/ + +void gsm0610_rpe_encoding(gsm0610_state_t *s, + int16_t *e, // [-5..-1][0..39][40..44] + int16_t *xmaxc, + int16_t *Mc, + int16_t xMc[13]) +{ + int16_t x[40]; + int16_t xM[13]; + int16_t xMp[13]; + int16_t mant; + int16_t exp; + + weighting_filter(e, x); + rpe_grid_selection(x, xM, Mc); + + apcm_quantization(xM, xMc, &mant, &exp, xmaxc); + apcm_inverse_quantization(xMc, mant, exp, xMp); + + rpe_grid_positioning(*Mc, xMp, e); +} +/*- End of function --------------------------------------------------------*/ + +void gsm0610_rpe_decoding(gsm0610_state_t *s, + int16_t xmaxc, + int16_t Mcr, + int16_t xMcr[13], + int16_t erp[40]) +{ + int16_t exp; + int16_t mant; + int16_t xMp[13]; + + apcm_quantization_xmaxc_to_exp_mant(xmaxc, &exp, &mant); + apcm_inverse_quantization(xMcr, mant, exp, xMp); + rpe_grid_positioning(Mcr, xMp, erp); +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/gsm0610_short_term.c b/libs/voipcodecs/src/gsm0610_short_term.c new file mode 100644 index 0000000000..fb0cbab65c --- /dev/null +++ b/libs/voipcodecs/src/gsm0610_short_term.c @@ -0,0 +1,361 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * gsm0610_short_term.c - GSM 06.10 full rate speech codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This code is based on the widely used GSM 06.10 code available from + * http://kbs.cs.tu-berlin.de/~jutta/toast.html + * + * $Id: gsm0610_short_term.c,v 1.10 2007/08/20 15:22:22 steveu Exp $ + */ + +/*! \file */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif +#include + +#include "voipcodecs/telephony.h" +#include "voipcodecs/bitstream.h" +#include "voipcodecs/dc_restore.h" +#include "voipcodecs/gsm0610.h" + +#include "gsm0610_local.h" + +/* SHORT TERM ANALYSIS FILTERING SECTION */ + +/* 4.2.8 */ +static void decode_log_area_ratios(int16_t LARc[8], int16_t *LARpp) +{ + int16_t temp1; + + /* This procedure requires for efficient implementation + two tables. + INVA[1..8] = integer((32768*8)/real_A[1..8]) + MIC[1..8] = minimum value of the LARc[1..8] + */ + + /* Compute the LARpp[1..8] */ + +#undef STEP +#define STEP(B,MIC,INVA) \ + temp1 = gsm_add(*LARc++, MIC) << 10; \ + temp1 = gsm_sub(temp1, B << 1); \ + temp1 = gsm_mult_r (INVA, temp1); \ + *LARpp++ = gsm_add(temp1, temp1); + + STEP( 0, -32, 13107); + STEP( 0, -32, 13107); + STEP( 2048, -16, 13107); + STEP(-2560, -16, 13107); + + STEP( 94, -8, 19223); + STEP(-1792, -8, 17476); + STEP( -341, -4, 31454); + STEP(-1144, -4, 29708); + + /* NOTE: the addition of *MIC is used to restore the sign of *LARc. */ +} +/*- End of function --------------------------------------------------------*/ + +/* 4.2.9 */ + +/* Computation of the quantized reflection coefficients */ + +/* 4.2.9.1 Interpolation of the LARpp[1..8] to get the LARp[1..8] */ + +/* Within each frame of 160 analyzed speech samples the short term + analysis and synthesis filters operate with four different sets of + coefficients, derived from the previous set of decoded LARs(LARpp(j - 1)) + and the actual set of decoded LARs (LARpp(j)) + + (Initial value: LARpp(j - 1)[1..8] = 0.) +*/ + +static void coefficients_0_12(int16_t *LARpp_j_1, + int16_t *LARpp_j, + int16_t *LARp) +{ + int i; + + for (i = 1; i <= 8; i++, LARp++, LARpp_j_1++, LARpp_j++) + { + *LARp = gsm_add(*LARpp_j_1 >> 2, *LARpp_j >> 2); + *LARp = gsm_add(*LARp, *LARpp_j_1 >> 1); + } + /*endfor*/ +} +/*- End of function --------------------------------------------------------*/ + +static void coefficients_13_26(int16_t *LARpp_j_1, + int16_t *LARpp_j, + int16_t *LARp) +{ + int i; + + for (i = 1; i <= 8; i++, LARpp_j_1++, LARpp_j++, LARp++) + *LARp = gsm_add(*LARpp_j_1 >> 1, *LARpp_j >> 1); + /*endfor*/ +} +/*- End of function --------------------------------------------------------*/ + +static void coefficients_27_39(int16_t *LARpp_j_1, + int16_t *LARpp_j, + int16_t *LARp) +{ + int i; + + for (i = 1; i <= 8; i++, LARpp_j_1++, LARpp_j++, LARp++) + { + *LARp = gsm_add(*LARpp_j_1 >> 2, *LARpp_j >> 2); + *LARp = gsm_add(*LARp, *LARpp_j >> 1); + } + /*endfor*/ +} +/*- End of function --------------------------------------------------------*/ + +static void coefficients_40_159(int16_t *LARpp_j, int16_t *LARp) +{ + int i; + + for (i = 1; i <= 8; i++) + *LARp++ = *LARpp_j++; + /*endfor*/ +} +/*- End of function --------------------------------------------------------*/ + +/* 4.2.9.2 */ +static void larp_to_rp(int16_t LARp[8]) +{ + int i; + int16_t *LARpx; + int16_t temp; + + /* The input to this procedure is the interpolated LARp[0..7] array. + The reflection coefficients, rp[i], are used in the analysis + filter and in the synthesis filter. + */ + + LARpx = LARp; + for (i = 1; i <= 8; i++, LARpx++) + { + temp = *LARpx; + if (temp < 0) + { + if (temp == INT16_MIN) + temp = INT16_MAX; + else + temp = -temp; + /*endif*/ + if (temp < 11059) + temp <<= 1; + else if (temp < 20070) + temp += 11059; + else + temp = gsm_add(temp >> 2, 26112); + /*endif*/ + *LARpx = -temp; + } + else + { + if (temp < 11059) + temp <<= 1; + else if (temp < 20070) + temp += 11059; + else + temp = gsm_add(temp >> 2, 26112); + /*endif*/ + *LARpx = temp; + } + /*endif*/ + } + /*endfor*/ +} +/*- End of function --------------------------------------------------------*/ + +/* 4.2.10 */ +static void short_term_analysis_filtering(gsm0610_state_t *s, + int16_t rp[8], + int k_n, // k_end - k_start + int16_t amp[]) // [0..n-1] IN/OUT +{ + /* This procedure computes the short term residual signal d[..] to be fed + to the RPE-LTP loop from the s[..] signal and from the local rp[..] + array (quantized reflection coefficients). As the call of this + procedure can be done in many ways (see the interpolation of the LAR + coefficient), it is assumed that the computation begins with index + k_start (for arrays d[..] and s[..]) and stops with index k_end + (k_start and k_end are defined in 4.2.9.1). This procedure also + needs to keep the array u[0..7] in memory for each call. + */ + int16_t *u0; + int16_t *u_top; + int i; + int16_t *u; + int16_t *rpx; + int32_t di; + int32_t u_out; + + u0 = s->u; + u_top = u0 + 8; + + for (i = 0; i < k_n; i++) + { + di = + u_out = amp[i]; + for (rpx = rp, u = u0; u < u_top; ) + { + int32_t ui; + int32_t rpi; + + ui = *u; + *u++ = (int16_t) u_out; + rpi = *rpx++; + u_out = ui + (((rpi*di) + 0x4000) >> 15); + di = di + (((rpi*ui) + 0x4000) >> 15); + u_out = saturate(u_out); + di = saturate(di); + } + /*endfor*/ + amp[i] = (int16_t) di; + } + /*endfor*/ +} +/*- End of function --------------------------------------------------------*/ + +static void short_term_synthesis_filtering(gsm0610_state_t *s, + int16_t rrp[8], + int k, // k_end - k_start + int16_t *wt, // [0..k - 1] + int16_t *sr) // [0..k - 1] +{ + int16_t *v; + int i; + int16_t sri; + int16_t tmp1; + int16_t tmp2; + + v = s->v; + while (k--) + { + sri = *wt++; + for (i = 8; i--; ) + { + tmp1 = rrp[i]; + tmp2 = v[i]; + tmp2 = ((tmp1 == INT16_MIN && tmp2 == INT16_MIN) + ? + INT16_MAX + : + (int16_t) (((int32_t) tmp1*(int32_t) tmp2 + 16384) >> 15) & 0xFFFF); + + sri = gsm_sub(sri, tmp2); + + tmp1 = ((tmp1 == INT16_MIN && sri == INT16_MIN) + ? + INT16_MAX + : + (int16_t) (((int32_t) tmp1*(int32_t) sri + 16384) >> 15) & 0xFFFF); + + v[i + 1] = gsm_add(v[i], tmp1); + } + /*endfor*/ + *sr++ = + v[0] = sri; + } + /*endwhile*/ +} +/*- End of function --------------------------------------------------------*/ + +void gsm0610_short_term_analysis_filter(gsm0610_state_t *s, + int16_t LARc[8], + int16_t amp[GSM0610_FRAME_LEN]) +{ + int16_t *LARpp_j; + int16_t *LARpp_j_1; + int16_t LARp[8]; + + LARpp_j = s->LARpp[s->j]; + LARpp_j_1 = s->LARpp[s->j ^= 1]; + + decode_log_area_ratios(LARc, LARpp_j); + + coefficients_0_12(LARpp_j_1, LARpp_j, LARp); + larp_to_rp(LARp); + short_term_analysis_filtering(s, LARp, 13, amp); + + coefficients_13_26(LARpp_j_1, LARpp_j, LARp); + larp_to_rp(LARp); + short_term_analysis_filtering(s, LARp, 14, amp + 13); + + coefficients_27_39(LARpp_j_1, LARpp_j, LARp); + larp_to_rp(LARp); + short_term_analysis_filtering(s, LARp, 13, amp + 27); + + coefficients_40_159(LARpp_j, LARp); + larp_to_rp(LARp); + short_term_analysis_filtering(s, LARp, 120, amp + 40); +} +/*- End of function --------------------------------------------------------*/ + +void gsm0610_short_term_synthesis_filter(gsm0610_state_t *s, + int16_t LARcr[8], + int16_t wt[GSM0610_FRAME_LEN], + int16_t amp[GSM0610_FRAME_LEN]) +{ + int16_t *LARpp_j; + int16_t *LARpp_j_1; + int16_t LARp[8]; + + LARpp_j = s->LARpp[s->j]; + LARpp_j_1 = s->LARpp[s->j ^= 1]; + + decode_log_area_ratios(LARcr, LARpp_j); + + coefficients_0_12(LARpp_j_1, LARpp_j, LARp); + larp_to_rp(LARp); + short_term_synthesis_filtering(s, LARp, 13, wt, amp); + + coefficients_13_26(LARpp_j_1, LARpp_j, LARp); + larp_to_rp(LARp); + short_term_synthesis_filtering(s, LARp, 14, wt + 13, amp + 13); + + coefficients_27_39(LARpp_j_1, LARpp_j, LARp); + larp_to_rp(LARp); + short_term_synthesis_filtering(s, LARp, 13, wt + 27, amp + 27); + + coefficients_40_159(LARpp_j, LARp); + larp_to_rp(LARp); + short_term_synthesis_filtering(s, LARp, 120, wt + 40, amp + 40); +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/ima_adpcm.c b/libs/voipcodecs/src/ima_adpcm.c new file mode 100644 index 0000000000..7c8c11dd06 --- /dev/null +++ b/libs/voipcodecs/src/ima_adpcm.c @@ -0,0 +1,387 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * ima_adpcm.c - Conversion routines between linear 16 bit PCM data and + * IMA/DVI/Intel ADPCM format. + * + * Written by Steve Underwood + * + * Copyright (C) 2001, 2004 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: ima_adpcm.c,v 1.18 2006/11/30 15:41:47 steveu Exp $ + */ + +/*! \file */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif + +#include "voipcodecs/telephony.h" +#include "voipcodecs/dc_restore.h" +#include "voipcodecs/ima_adpcm.h" + +/* + * Intel/DVI ADPCM coder/decoder. + * + * The algorithm for this coder was taken from the IMA Compatability Project + * proceedings, Vol 2, Number 2; May 1992. + * + * The RTP payload specs. reference a variant of DVI, called VDVI. This attempts to + * further compresses, in a variable bit rate manner, by expressing the 4 bit codes + * from the DVI codec as: + * + * 0 00 + * 1 010 + * 2 1100 + * 3 11100 + * 4 111100 + * 5 1111100 + * 6 11111100 + * 7 11111110 + * 8 10 + * 9 011 + * 10 1101 + * 11 11101 + * 12 111101 + * 13 1111101 + * 14 11111101 + * 15 11111111 + * + * Any left over bits in the last octet of an encoded burst are set to one. + */ + +/* Intel ADPCM step variation table */ +static const int step_size[89] = +{ + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 +}; + +static const int step_adjustment[8] = +{ + -1, -1, -1, -1, 2, 4, 6, 8 +}; + +static const struct +{ + uint8_t code; + uint8_t bits; +} vdvi_encode[] = +{ + {0x00, 2}, + {0x02, 3}, + {0x0C, 4}, + {0x1C, 5}, + {0x3C, 6}, + {0x7C, 7}, + {0xFC, 8}, + {0xFE, 8}, + {0x02, 2}, + {0x03, 3}, + {0x0D, 4}, + {0x1D, 5}, + {0x3D, 6}, + {0x7D, 7}, + {0xFD, 8}, + {0xFF, 8} +}; + +static const struct +{ + uint16_t code; + uint16_t mask; + uint8_t bits; +} vdvi_decode[] = +{ + {0x0000, 0xC000, 2}, + {0x4000, 0xE000, 3}, + {0xC000, 0xF000, 4}, + {0xE000, 0xF800, 5}, + {0xF000, 0xFC00, 6}, + {0xF800, 0xFE00, 7}, + {0xFC00, 0xFF00, 8}, + {0xFE00, 0xFF00, 8}, + {0x8000, 0xC000, 2}, + {0x6000, 0xE000, 3}, + {0xD000, 0xF000, 4}, + {0xE800, 0xF800, 5}, + {0xF400, 0xFC00, 6}, + {0xFA00, 0xFE00, 7}, + {0xFD00, 0xFF00, 8}, + {0xFF00, 0xFF00, 8} +}; + +static int16_t decode(ima_adpcm_state_t *s, uint8_t adpcm) +{ + int e; + int ss; + int16_t linear; + + /* e = (adpcm+0.5)*step/4 */ + + ss = step_size[s->step_index]; + e = ss >> 3; + if (adpcm & 0x01) + e += (ss >> 2); + /*endif*/ + if (adpcm & 0x02) + e += (ss >> 1); + /*endif*/ + if (adpcm & 0x04) + e += ss; + /*endif*/ + if (adpcm & 0x08) + e = -e; + /*endif*/ + linear = saturate(s->last + e); + s->last = linear; + s->step_index += step_adjustment[adpcm & 0x07]; + if (s->step_index < 0) + s->step_index = 0; + else if (s->step_index > 88) + s->step_index = 88; + /*endif*/ + return linear; +} +/*- End of function --------------------------------------------------------*/ + +static uint8_t encode(ima_adpcm_state_t *s, int16_t linear) +{ + int e; + int ss; + int adpcm; + int diff; + int initial_e; + + ss = step_size[s->step_index]; + initial_e = + e = linear - s->last; + diff = ss >> 3; + adpcm = (uint8_t) 0x00; + if (e < 0) + { + adpcm = (uint8_t) 0x08; + e = -e; + } + /*endif*/ + if (e >= ss) + { + adpcm |= (uint8_t) 0x04; + e -= ss; + } + /*endif*/ + ss >>= 1; + if (e >= ss) + { + adpcm |= (uint8_t) 0x02; + e -= ss; + } + /*endif*/ + ss >>= 1; + if (e >= ss) + { + adpcm |= (uint8_t) 0x01; + e -= ss; + } + /*endif*/ + + if (initial_e < 0) + diff = -(diff - initial_e - e); + else + diff = diff + initial_e - e; + /*endif*/ + s->last = saturate(diff + s->last); + s->step_index += step_adjustment[adpcm & 0x07]; + if (s->step_index < 0) + s->step_index = 0; + else if (s->step_index > 88) + s->step_index = 88; + /*endif*/ + return (uint8_t) adpcm; +} +/*- End of function --------------------------------------------------------*/ + +ima_adpcm_state_t *ima_adpcm_init(ima_adpcm_state_t *s, int variant) +{ + if (s == NULL) + { + if ((s = (ima_adpcm_state_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + /*endif*/ + memset(s, 0, sizeof(*s)); + s->variant = variant; + return s; +} +/*- End of function --------------------------------------------------------*/ + +int ima_adpcm_release(ima_adpcm_state_t *s) +{ + free(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +int ima_adpcm_decode(ima_adpcm_state_t *s, + int16_t amp[], + const uint8_t ima_data[], + int ima_bytes) +{ + int i; + int j; + int samples; + uint16_t code; + + samples = 0; + if (s->variant == IMA_ADPCM_VDVI) + { + code = 0; + s->bits = 0; + for (i = 0; ; ) + { + if (s->bits <= 8) + { + if (i >= ima_bytes) + break; + /*endif*/ + code |= ((uint16_t) ima_data[i++] << (8 - s->bits)); + s->bits += 8; + } + /*endif*/ + for (j = 0; j < 8; j++) + { + if ((vdvi_decode[j].mask & code) == vdvi_decode[j].code) + break; + if ((vdvi_decode[j + 8].mask & code) == vdvi_decode[j + 8].code) + { + j += 8; + break; + } + /*endif*/ + } + /*endfor*/ + amp[samples++] = decode(s, (uint8_t) j); + code <<= vdvi_decode[j].bits; + s->bits -= vdvi_decode[j].bits; + } + /*endfor*/ + /* Use up the remanents of the last octet */ + while (s->bits > 0) + { + for (j = 0; j < 8; j++) + { + if ((vdvi_decode[j].mask & code) == vdvi_decode[j].code) + break; + /*endif*/ + if ((vdvi_decode[j + 8].mask & code) == vdvi_decode[j + 8].code) + { + j += 8; + break; + } + /*endif*/ + } + /*endfor*/ + if (vdvi_decode[j].bits > s->bits) + break; + /*endif*/ + amp[samples++] = decode(s, (uint8_t) j); + code <<= vdvi_decode[j].bits; + s->bits -= vdvi_decode[j].bits; + } + /*endfor*/ + } + else + { + for (i = 0; i < ima_bytes; i++) + { + amp[samples++] = decode(s, ima_data[i] & 0xF); + amp[samples++] = decode(s, (ima_data[i] >> 4) & 0xF); + } + /*endwhile*/ + } + /*endif*/ + return samples; +} +/*- End of function --------------------------------------------------------*/ + +int ima_adpcm_encode(ima_adpcm_state_t *s, + uint8_t ima_data[], + const int16_t amp[], + int len) +{ + int i; + int bytes; + uint8_t code; + + bytes = 0; + if (s->variant == IMA_ADPCM_VDVI) + { + s->bits = 0; + for (i = 0; i < len; i++) + { + code = encode(s, amp[i]); + s->ima_byte = (s->ima_byte << vdvi_encode[code].bits) | vdvi_encode[code].code; + s->bits += vdvi_encode[code].bits; + if (s->bits >= 8) + { + s->bits -= 8; + ima_data[bytes++] = (uint8_t) (s->ima_byte >> s->bits); + } + /*endif*/ + } + /*endfor*/ + if (s->bits) + { + ima_data[bytes++] = (uint8_t) (((s->ima_byte << 8) | 0xFF) >> s->bits); + } + /*endif*/ + } + else + { + for (i = 0; i < len; i++) + { + s->ima_byte = (uint8_t) ((s->ima_byte >> 4) | (encode(s, amp[i]) << 4)); + if ((s->bits++ & 1)) + ima_data[bytes++] = (uint8_t) s->ima_byte; + /*endif*/ + } + /*endfor*/ + } + /*endif*/ + return bytes; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/libvoipcodecs.dsp b/libs/voipcodecs/src/libvoipcodecs.dsp new file mode 100644 index 0000000000..c91480bb90 --- /dev/null +++ b/libs/voipcodecs/src/libvoipcodecs.dsp @@ -0,0 +1,241 @@ +# Microsoft Developer Studio Project File - Name="voipcodecs" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=voipcodecs - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "voipcodecs.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "voipcodecs.mak" CFG="voipcodecs - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "voipcodecs - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "voipcodecs - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "voipcodecs - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /Zi /O2 /I "." /I "..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /D "_WINDLL" /FR /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib ws2_32.lib winmm.lib /nologo /dll /map /debug /machine:I386 /out:"Release/libvoipcodecs.dll" + +!ELSEIF "$(CFG)" == "voipcodecs - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "." /I "..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /FR /FD /GZ /c +# SUBTRACT CPP /WX /YX +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib ws2_32.lib winmm.lib /nologo /dll /incremental:no /map /debug /machine:I386 /out:"Debug/libvoipcodecs.dll" /pdbtype:sept +# SUBTRACT LINK32 /nodefaultlib + +!ENDIF + +# Begin Target + +# Name "voipcodecs - Win32 Release" +# Name "voipcodecs - Win32 Debug" +# Begin Group "Source Files" +# Begin Source File + +SOURCE=.\bit_operations.c +# End Source File +# Begin Source File + +SOURCE=.\bitstream.c +# End Source File +# Begin Source File + +SOURCE=.\g711.c +# End Source File +# Begin Source File + +SOURCE=.\g722_encode.c +# End Source File +# Begin Source File + +SOURCE=.\g722_decode.c +# End Source File +# Begin Source File + +SOURCE=.\g726.c +# End Source File +# Begin Source File + +SOURCE=.\gsm0610_decode.c +# End Source File +# Begin Source File + +SOURCE=.\gsm0610_encode.c +# End Source File +# Begin Source File + +SOURCE=.\gsm0610_long_term.c +# End Source File +# Begin Source File + +SOURCE=.\gsm0610_lpc.c +# End Source File +# Begin Source File + +SOURCE=.\gsm0610_preprocess.c +# End Source File +# Begin Source File + +SOURCE=.\gsm0610_rpe.c +# End Source File +# Begin Source File + +SOURCE=.\gsm0610_short_term.c +# End Source File +# Begin Source File + +SOURCE=.\ima_adpcm.c +# End Source File +# Begin Source File + +SOURCE=.\lpc10_analyse.c +# End Source File +# Begin Source File + +SOURCE=.\lpc10_decode.c +# End Source File +# Begin Source File + +SOURCE=.\lpc10_encode.c +# End Source File +# Begin Source File + +SOURCE=.\lpc10_placev.c +# End Source File +# Begin Source File + +SOURCE=.\lpc10_voicing.c +# End Source File +# Begin Source File + +SOURCE=.\oki_adpcm.c +# End Source File +# Begin Source File + +SOURCE=.\vector_int.c +# End Source File +# Begin Source File + +SOURCE=.\voipcodecs/bit_operations.h +# End Source File +# Begin Source File + +SOURCE=.\voipcodecs/bitstream.h +# End Source File +# Begin Source File + +SOURCE=.\voipcodecs/dc_restore.h +# End Source File +# Begin Source File + +SOURCE=.\voipcodecs/g711.h +# End Source File +# Begin Source File + +SOURCE=.\voipcodecs/g722.h +# End Source File +# Begin Source File + +SOURCE=.\voipcodecs/g726.h +# End Source File +# Begin Source File + +SOURCE=.\voipcodecs/gsm0610.h +# End Source File +# Begin Source File + +SOURCE=.\voipcodecs/ima_adpcm.h +# End Source File +# Begin Source File + +SOURCE=.\voipcodecs/lpc10.h +# End Source File +# Begin Source File + +SOURCE=.\voipcodecs/oki_adpcm.h +# End Source File +# Begin Source File + +SOURCE=.\voipcodecs/telephony.h +# End Source File +# Begin Source File + +SOURCE=.\voipcodecs/vector_int.h +# End Source File +# Begin Source File + +SOURCE=.\voipcodecs.h +# End Source File +# Begin Source File + +SOURCE=.\voipcodecs.h +# End Source File +# End Group + +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/libs/voipcodecs/src/libvoipcodecs.sln b/libs/voipcodecs/src/libvoipcodecs.sln new file mode 100644 index 0000000000..dd5df26ba4 --- /dev/null +++ b/libs/voipcodecs/src/libvoipcodecs.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libvoipcodecs", "libvoipcodecs.vcproj", "{CF70F278-3364-4395-A2E1-23501C9B8AD2}" + ProjectSection(ProjectDependencies) = postProject + {1CED5987-A529-46DC-B30F-870D85FF9C94} = {1CED5987-A529-46DC-B30F-870D85FF9C94} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "at_dictionary_gen", "src\msvc\at_dictionary_gen.vcproj", "{1CED5987-A529-46DC-B30F-870D85FF9C94}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Debug|Win32.ActiveCfg = Debug|Win32 + {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Debug|Win32.Build.0 = Debug|Win32 + {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Release|Win32.ActiveCfg = Release|Win32 + {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Release|Win32.Build.0 = Release|Win32 + {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|Win32.ActiveCfg = Debug|Win32 + {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|Win32.Build.0 = Debug|Win32 + {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|Win32.ActiveCfg = Release|Win32 + {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/libs/voipcodecs/src/lpc10_analyse.c b/libs/voipcodecs/src/lpc10_analyse.c new file mode 100644 index 0000000000..b88eb06ccb --- /dev/null +++ b/libs/voipcodecs/src/lpc10_analyse.c @@ -0,0 +1,712 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * lpc10_analyse.c - LPC10 low bit rate speech codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This code is based on the U.S. Department of Defense reference + * implementation of the LPC-10 2400 bps Voice Coder. They do not + * exert copyright claims on their code, and it may be freely used. + * + * $Id: lpc10_analyse.c,v 1.13 2007/01/03 14:15:35 steveu Exp $ + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif + +#include "voipcodecs/telephony.h" +#include "voipcodecs/dc_restore.h" +#include "voipcodecs/lpc10.h" + +#include "lpc10_encdecs.h" + +static __inline__ float energyf(float amp[], int len) +{ + int i; + float rms; + + rms = 0.0f; + for (i = 0; i < len; i++) + rms += amp[i]*amp[i]; + rms = sqrtf(rms/len); + return rms; +} +/*- End of function --------------------------------------------------------*/ + +static void remove_dc_bias(float speech[], int len, float sigout[]) +{ + float bias; + int i; + + bias = 0.0f; + for (i = 0; i < len; i++) + bias += speech[i]; + bias /= len; + for (i = 0; i < len; i++) + sigout[i] = speech[i] - bias; +} +/*- End of function --------------------------------------------------------*/ + +static void eval_amdf(float speech[], + int32_t lpita, + const int32_t tau[], + int32_t ltau, + int32_t maxlag, + float amdf[], + int32_t *minptr, + int32_t *maxptr) +{ + float sum; + int i; + int j; + int n1; + int n2; + + *minptr = 0; + *maxptr = 0; + for (i = 0; i < ltau; i++) + { + n1 = (maxlag - tau[i])/2 + 1; + n2 = n1 + lpita - 1; + sum = 0.0f; + for (j = n1; j <= n2; j += 4) + sum += fabsf(speech[j - 1] - speech[j + tau[i] - 1]); + amdf[i] = sum; + if (amdf[i] < amdf[*minptr]) + *minptr = i; + if (amdf[i] > amdf[*maxptr]) + *maxptr = i; + } +} +/*- End of function --------------------------------------------------------*/ + +static void eval_highres_amdf(float speech[], + int32_t lpita, + const int32_t tau[], + int32_t ltau, + float amdf[], + int32_t *minptr, + int32_t *maxptr, + int32_t *mintau) +{ + float amdf2[6]; + int32_t tau2[6]; + int32_t minp2; + int32_t ltau2; + int32_t maxp2; + int32_t minamd; + int i; + int i2; + int ptr; + + /* Compute full AMDF using log spaced lags, find coarse minimum */ + eval_amdf(speech, lpita, tau, ltau, tau[ltau - 1], amdf, minptr, maxptr); + *mintau = tau[*minptr]; + minamd = (int32_t) amdf[*minptr]; + + /* Build table containing all lags within +/- 3 of the AMDF minimum, + excluding all that have already been computed */ + ltau2 = 0; + ptr = *minptr - 2; + i2 = min(*mintau + 4, tau[ltau - 1]); + for (i = max(*mintau - 3, 41); i < i2; i++) + { + while (tau[ptr] < i) + ptr++; + if (tau[ptr] != i) + tau2[ltau2++] = i; + } + /* Compute AMDF of the new lags, if there are any, and choose one + if it is better than the coarse minimum */ + if (ltau2 > 0) + { + eval_amdf(speech, lpita, tau2, ltau2, tau[ltau - 1], amdf2, &minp2, &maxp2); + if (amdf2[minp2] < (float) minamd) + { + *mintau = tau2[minp2]; + minamd = (int32_t) amdf2[minp2]; + } + } + /* Check one octave up, if there are any lags not yet computed */ + if (*mintau >= 80) + { + i = *mintau/2; + if ((i & 1) == 0) + { + ltau2 = 2; + tau2[0] = i - 1; + tau2[1] = i + 1; + } + else + { + ltau2 = 1; + tau2[0] = i; + } + eval_amdf(speech, lpita, tau2, ltau2, tau[ltau - 1], amdf2, &minp2, &maxp2); + if (amdf2[minp2] < (float) minamd) + { + *mintau = tau2[minp2]; + minamd = (int32_t) amdf2[minp2]; + *minptr -= 20; + } + } + /* Force minimum of the AMDF array to the high resolution minimum */ + amdf[*minptr] = (float) minamd; + /* Find maximum of AMDF within 1/2 octave of minimum */ + *maxptr = max(*minptr - 5, 0); + i2 = min(*minptr + 6, ltau); + for (i = *maxptr; i < i2; i++) + { + if (amdf[i] > amdf[*maxptr]) + *maxptr = i; + } +} +/*- End of function --------------------------------------------------------*/ + +static void dynamic_pitch_tracking(lpc10_encode_state_t *s, + float amdf[], + int32_t ltau, + int32_t *minptr, + int32_t voice, + int32_t *pitch, + int32_t *midx) +{ + int32_t pbar; + float sbar; + int32_t path[2]; + int32_t i; + int32_t j; + float alpha; + float minsc; + float maxsc; + + /* Calculate the confidence factor ALPHA, used as a threshold slope in */ + /* SEESAW. If unvoiced, set high slope so that every point in P array */ + /*is marked as a potential pitch frequency. A scaled up version (ALPHAX )*/ + /* is used to maintain arithmetic precision. */ + if (voice == 1) + s->alphax = s->alphax*0.75f + amdf[*minptr - 1]*0.5f; + else + s->alphax *= 0.984375f; + alpha = s->alphax/16; + if (voice == 0 && s->alphax < 128.0f) + alpha = 8.0f; + /* SEESAW: Construct a pitch pointer array and intermediate winner function */ + /* Left to right pass: */ + s->p[s->ipoint][0] = 1; + pbar = 1; + sbar = s->s[0]; + for (i = 0; i < ltau; i++) + { + sbar += alpha; + if (sbar < s->s[i]) + { + s->s[i] = sbar; + } + else + { + pbar = i + 1; + sbar = s->s[i]; + } + s->p[s->ipoint][i] = pbar; + } + /* Right to left pass: */ + sbar = s->s[pbar - 1]; + for (i = pbar - 2; i >= 0; i--) + { + sbar += alpha; + if (sbar < s->s[i]) + { + s->s[i] = sbar; + s->p[s->ipoint][i] = pbar; + } + else + { + pbar = s->p[s->ipoint][i]; + i = pbar - 1; + sbar = s->s[i]; + } + } + /* Update S using AMDF */ + /* Find maximum, minimum, and location of minimum */ + s->s[0] += amdf[0]/2; + minsc = s->s[0]; + maxsc = minsc; + *midx = 1; + for (i = 1; i < ltau; i++) + { + s->s[i] += amdf[i]/2; + if (s->s[i] > maxsc) + maxsc = s->s[i]; + if (s->s[i] < minsc) + { + *midx = i + 1; + minsc = s->s[i]; + } + } + /* Subtract MINSC from S to prevent overflow */ + for (i = 0; i < ltau; i++) + s->s[i] -= minsc; + maxsc -= minsc; + /* Use higher octave pitch if significant null there */ + j = 0; + for (i = 20; i <= 40; i += 10) + { + if (*midx > i) + { + if (s->s[*midx - i - 1] < maxsc / 4) + j = i; + } + } + *midx -= j; + /* TRACE: look back two frames to find minimum cost pitch estimate */ + *pitch = *midx; + for (i = 0, j = s->ipoint; i < 2; i++, j++) + { + *pitch = s->p[j & 1][*pitch - 1]; + path[i] = *pitch; + } + + /* The following statement subtracts one from IPOINT, mod DEPTH. I */ + /* think the author chose to add DEPTH-1, instead of subtracting 1, */ + /* because then it will work even if MOD doesn't work as desired on */ + /* negative arguments. */ + s->ipoint = (s->ipoint + 1) & 1; +} +/*- End of function --------------------------------------------------------*/ + +/* Detection of onsets in (or slightly preceding) the futuremost frame of speech. */ +static void onset(lpc10_encode_state_t *s, + float *pebuf, + int32_t osbuf[], + int32_t *osptr, + int32_t oslen, + int32_t sbufl, + int32_t sbufh, + int32_t lframe) +{ + int32_t i; + float r1; + float l2sum2; + + pebuf -= sbufl; + + if (s->hyst) + s->lasti -= lframe; + for (i = sbufh - lframe + 1; i <= sbufh; i++) + { + /* Compute FPC; Use old FPC on divide by zero; Clamp FPC to +/- 1. */ + s->n = (pebuf[i]*pebuf[i - 1] + s->n*63.0f)/64.0f; + /* Computing 2nd power */ + r1 = pebuf[i - 1]; + s->d__ = (r1*r1 + s->d__*63.0f)/64.0f; + if (s->d__ != 0.0f) + { + if (fabsf(s->n) > s->d__) + s->fpc = r_sign(1.0f, s->n); + else + s->fpc = s->n/s->d__; + } + /* Filter FPC */ + l2sum2 = s->l2buf[s->l2ptr1 - 1]; + s->l2sum1 = s->l2sum1 - s->l2buf[s->l2ptr2 - 1] + s->fpc; + s->l2buf[s->l2ptr2 - 1] = s->l2sum1; + s->l2buf[s->l2ptr1 - 1] = s->fpc; + s->l2ptr1 = (s->l2ptr1 & 0xF) + 1; + s->l2ptr2 = (s->l2ptr2 & 0xF) + 1; + if (fabsf(s->l2sum1 - l2sum2) > 1.7f) + { + if (!s->hyst) + { + /* Ignore if buffer full */ + if (*osptr <= oslen) + { + osbuf[*osptr - 1] = i - 9; + (*osptr)++; + } + s->hyst = TRUE; + } + s->lasti = i; + /* After one onset detection, at least OSHYST sample times must go */ + /* by before another is allowed to occur. */ + } + else if (s->hyst && i - s->lasti >= 10) + { + s->hyst = FALSE; + } + } +} +/*- End of function --------------------------------------------------------*/ + +/* Load a covariance matrix. */ +static void mload(int32_t order, int32_t awins, int32_t awinf, float speech[], float phi[], float psi[]) +{ + int32_t start; + int i; + int r; + + start = awins + order; + for (r = 1; r <= order; r++) + { + phi[r - 1] = 0.0f; + for (i = start; i <= awinf; i++) + phi[r - 1] += speech[i - 2]*speech[i - r - 1]; + } + + /* Load last element of vector PSI */ + psi[order - 1] = 0.0f; + for (i = start - 1; i < awinf; i++) + psi[order - 1] += speech[i]*speech[i - order]; + /* End correct to get additional columns of phi */ + for (r = 1; r < order; r++) + { + for (i = 1; i <= r; i++) + { + phi[i*order + r] = phi[(i - 1)*order + r - 1] + - speech[awinf - (r + 1)]*speech[awinf - (i + 1)] + + speech[start - (r + 2)]*speech[start - (i + 2)]; + } + } + /* End correct to get additional elements of PSI */ + for (i = 0; i < order - 1; i++) + { + psi[i] = phi[i + 1] + - speech[start - 2]*speech[start - i - 3] + + speech[awinf - 1]*speech[awinf - i - 2]; + } +} +/*- End of function --------------------------------------------------------*/ + +/* Preemphasize speech with a single-zero filter. */ +/* (When coef = .9375, preemphasis is as in LPC43.) */ +static float preemp(float inbuf[], float pebuf[], int nsamp, float coeff, float z) +{ + float temp; + int i; + + for (i = 0; i < nsamp; i++) + { + temp = inbuf[i] - coeff*z; + z = inbuf[i]; + pebuf[i] = temp; + } + return z; +} +/*- End of function --------------------------------------------------------*/ + +/* Invert a covariance matrix using Choleski decomposition method. */ +static void invert(int32_t order, float phi[], float psi[], float rc[]) +{ + float r1; + int32_t i; + int32_t j; + int32_t k; + float v[10][10]; + + for (j = 0; j < order; j++) + { + for (i = j; i < order; i++) + v[j][i] = phi[i + j*order]; + for (k = 0; k < j; k++) + { + r1 = v[k][j]*v[k][k]; + for (i = j; i <= order; i++) + v[j][i] -= v[k][i]*r1; + } + /* Compute intermediate results, which are similar to RC's */ + if (fabsf(v[j][j]) < 1.0e-10f) + { + for (i = j; i < order; i++) + rc[i] = 0.0f; + return; + } + rc[j] = psi[j]; + for (k = 0; k < j; k++) + rc[j] -= rc[k]*v[k][j]; + v[j][j] = 1.0f/v[j][j]; + rc[j] *= v[j][j]; + r1 = min(rc[j], 0.999f); + rc[j] = max(r1, -0.999f); + } +} +/*- End of function --------------------------------------------------------*/ + +/* Check RC's, repeat previous frame's RC's if unstable */ +static int rcchk(int order, float rc1f[], float rc2f[]) +{ + int i; + + for (i = 0; i < order; i++) + { + if (fabsf(rc2f[i]) > 0.99f) + { + for (i = 0; i < order; i++) + rc2f[i] = rc1f[i]; + break; + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static void lpfilt(float inbuf[], float lpbuf[], int32_t len, int32_t nsamp) +{ + int32_t j; + float t; + + /* 31 point equiripple FIR LPF */ + /* Linear phase, delay = 15 samples */ + /* Passband: ripple = 0.25 dB, cutoff = 800 Hz */ + /* Stopband: atten. = 40. dB, cutoff = 1240 Hz */ + + for (j = len - nsamp; j < len; j++) + { + t = (inbuf[j] + inbuf[j - 30]) * -0.0097201988f; + t += (inbuf[j - 1] + inbuf[j - 29]) * -0.0105179986f; + t += (inbuf[j - 2] + inbuf[j - 28]) * -0.0083479648f; + t += (inbuf[j - 3] + inbuf[j - 27]) * 5.860774e-4f; + t += (inbuf[j - 4] + inbuf[j - 26]) * 0.0130892089f; + t += (inbuf[j - 5] + inbuf[j - 25]) * 0.0217052232f; + t += (inbuf[j - 6] + inbuf[j - 24]) * 0.0184161253f; + t += (inbuf[j - 7] + inbuf[j - 23]) * 3.39723e-4f; + t += (inbuf[j - 8] + inbuf[j - 22]) * -0.0260797087f; + t += (inbuf[j - 9] + inbuf[j - 21]) * -0.0455563702f; + t += (inbuf[j - 10] + inbuf[j - 20]) * -0.040306855f; + t += (inbuf[j - 11] + inbuf[j - 19]) * 5.029835e-4f; + t += (inbuf[j - 12] + inbuf[j - 18]) * 0.0729262903f; + t += (inbuf[j - 13] + inbuf[j - 17]) * 0.1572008878f; + t += (inbuf[j - 14] + inbuf[j - 16]) * 0.2247288674f; + t += inbuf[j - 15] * 0.250535965f; + lpbuf[j] = t; + } +} +/*- End of function --------------------------------------------------------*/ + +/* 2nd order inverse filter, speech is decimated 4:1 */ +static void ivfilt(float lpbuf[], float ivbuf[], int32_t len, int32_t nsamp, float ivrc[]) +{ + int32_t i; + int32_t j; + int32_t k; + float r[3]; + float pc1; + float pc2; + + /* Calculate autocorrelations */ + for (i = 1; i <= 3; i++) + { + r[i - 1] = 0.0f; + k = (i - 1) << 2; + for (j = (i << 2) + len - nsamp; j <= len; j += 2) + r[i - 1] += lpbuf[j - 1]*lpbuf[j - k - 1]; + } + /* Calculate predictor coefficients */ + pc1 = 0.0f; + pc2 = 0.0f; + ivrc[0] = 0.0f; + ivrc[1] = 0.0f; + if (r[0] > 1.0e-10f) + { + ivrc[0] = r[1]/r[0]; + ivrc[1] = (r[2] - ivrc[0]*r[1])/(r[0] - ivrc[0]*r[1]); + pc1 = ivrc[0] - ivrc[0]*ivrc[1]; + pc2 = ivrc[1]; + } + /* Inverse filter LPBUF into IVBUF */ + for (i = len - nsamp; i < len; i++) + ivbuf[i] = lpbuf[i] - pc1*lpbuf[i - 4] - pc2*lpbuf[i - 8]; +} +/*- End of function --------------------------------------------------------*/ + +void lpc10_analyse(lpc10_encode_state_t *s, float speech[], int32_t voice[], int32_t *pitch, float *rms, float rc[]) +{ + static const int32_t tau[60] = + { + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, + 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 84, 88, 92, 96, + 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, + 148, 152, 156 + }; + static const int32_t buflim[4] = + { + 181, 720, 25, 720 + }; + static const float precoef = 0.9375f; + + float amdf[60]; + float abuf[156]; + float ivrc[2]; + float temp; + float phi[100] /* was [10][10] */; + float psi[10]; + int32_t half; + int32_t midx; + int32_t ewin[3][2]; + int32_t i; + int32_t j; + int32_t lanal; + int32_t ipitch; + int32_t mintau; + int32_t minptr; + int32_t maxptr; + + /* Calculations are done on future frame due to requirements + of the pitch tracker. Delay RMS and RC's 2 frames to give + current frame parameters on return. */ + + for (i = 0; i <= 720 - LPC10_SAMPLES_PER_FRAME - 181; i++) + { + s->inbuf[i] = s->inbuf[LPC10_SAMPLES_PER_FRAME + i]; + s->pebuf[i] = s->pebuf[LPC10_SAMPLES_PER_FRAME + i]; + } + for (i = 0; i <= 540 - LPC10_SAMPLES_PER_FRAME - 229; i++) + s->ivbuf[i] = s->ivbuf[LPC10_SAMPLES_PER_FRAME + i]; + for (i = 0; i <= 720 - LPC10_SAMPLES_PER_FRAME - 25; i++) + s->lpbuf[i] = s->lpbuf[LPC10_SAMPLES_PER_FRAME + i]; + for (i = 0, j = 0; i < s->osptr - 1; i++) + { + if (s->osbuf[i] > LPC10_SAMPLES_PER_FRAME) + s->osbuf[j++] = s->osbuf[i] - LPC10_SAMPLES_PER_FRAME; + } + s->osptr = j + 1; + s->voibuf[0][0] = s->voibuf[1][0]; + s->voibuf[0][1] = s->voibuf[1][1]; + for (i = 0; i < 2; i++) + { + s->vwin[i][0] = s->vwin[i + 1][0] - LPC10_SAMPLES_PER_FRAME; + s->vwin[i][1] = s->vwin[i + 1][1] - LPC10_SAMPLES_PER_FRAME; + s->awin[i][0] = s->awin[i + 1][0] - LPC10_SAMPLES_PER_FRAME; + s->awin[i][1] = s->awin[i + 1][1] - LPC10_SAMPLES_PER_FRAME; + s->obound[i] = s->obound[i + 1]; + s->voibuf[i + 1][0] = s->voibuf[i + 2][0]; + s->voibuf[i + 1][1] = s->voibuf[i + 2][1]; + s->rmsbuf[i] = s->rmsbuf[i + 1]; + for (j = 0; j < LPC10_ORDER; j++) + s->rcbuf[i][j] = s->rcbuf[i + 1][j]; + } + /* If the average value in the frame was over 1/4096 (after current + BIAS correction), then subtract that much more from samples in the + next frame. If the average value in the frame was under + -1/4096, add 1/4096 more to samples in next frame. In all other + cases, keep BIAS the same. */ + temp = 0.0f; + for (i = 0; i < LPC10_SAMPLES_PER_FRAME; i++) + { + s->inbuf[720 - 2*LPC10_SAMPLES_PER_FRAME + i] = speech[i]*4096.0f - s->bias; + temp += s->inbuf[720 - 2*LPC10_SAMPLES_PER_FRAME + i]; + } + if (temp > (float) LPC10_SAMPLES_PER_FRAME) + s->bias++; + else if (temp < (float) (-LPC10_SAMPLES_PER_FRAME)) + s->bias--; + /* Place voicing window */ + i = 721 - LPC10_SAMPLES_PER_FRAME; + s->zpre = preemp(&s->inbuf[i - 181], &s->pebuf[i - 181], LPC10_SAMPLES_PER_FRAME, precoef, s->zpre); + onset(s, s->pebuf, s->osbuf, &s->osptr, 10, 181, 720, LPC10_SAMPLES_PER_FRAME); + + lpc10_placev(s->osbuf, &s->osptr, 10, &s->obound[2], s->vwin, 3, LPC10_SAMPLES_PER_FRAME, 90, 156, 307, 462); + /* The Pitch Extraction algorithm estimates the pitch for a frame + of speech by locating the minimum of the average magnitude difference + function (AMDF). The AMDF operates on low-pass, inverse filtered + speech. (The low-pass filter is an 800 Hz, 19 tap, equiripple, FIR + filter and the inverse filter is a 2nd-order LPC filter.) The pitch + estimate is later refined by dynamic tracking. However, since some + of the tracking parameters are a function of the voicing decisions, + a voicing decision must precede the final pitch estimation. */ + /* See subroutines LPFILT, IVFILT, and eval_highres_amdf. */ + /* LPFILT reads indices LBUFH-LFRAME-29 = 511 through LBUFH = 720 + of INBUF, and writes indices LBUFH+1-LFRAME = 541 through LBUFH + = 720 of LPBUF. */ + lpfilt(&s->inbuf[228], &s->lpbuf[384], 312, LPC10_SAMPLES_PER_FRAME); + /* IVFILT reads indices (PWINH-LFRAME-7) = 353 through PWINH = 540 + of LPBUF, and writes indices (PWINH-LFRAME+1) = 361 through + PWINH = 540 of IVBUF. */ + ivfilt(&s->lpbuf[204], s->ivbuf, 312, LPC10_SAMPLES_PER_FRAME, ivrc); + /* eval_highres_amdf reads indices PWINL = 229 through + (PWINL-1)+MAXWIN+(TAU(LTAU)-TAU(1))/2 = 452 of IVBUF, and writes + indices 1 through LTAU = 60 of AMDF. */ + eval_highres_amdf(s->ivbuf, 156, tau, 60, amdf, &minptr, &maxptr, &mintau); + /* Voicing decisions are made for each half frame of input speech. + An initial voicing classification is made for each half of the + analysis frame, and the voicing decisions for the present frame + are finalized. See subroutine VOICIN. */ + /* The voicing detector (VOICIN) classifies the input signal as + unvoiced (including silence) or voiced using the AMDF windowed + maximum-to-minimum ratio, the zero crossing rate, energy measures, + reflection coefficients, and prediction gains. */ + /* The pitch and voicing rules apply smoothing and isolated + corrections to the pitch and voicing estimates and, in the process, + introduce two frames of delay into the corrected pitch estimates and + voicing decisions. */ + for (half = 0; half < 2; half++) + { + lpc10_voicing(s, + &s->vwin[2][0], + s->inbuf, + s->lpbuf, + buflim, + half, + &amdf[minptr], + &amdf[maxptr], + &mintau, + ivrc, + s->obound); + } + /* Find the minimum cost pitch decision over several frames, + given the current voicing decision and the AMDF array */ + minptr++; + dynamic_pitch_tracking(s, amdf, 60, &minptr, s->voibuf[3][1], pitch, &midx); + ipitch = tau[midx - 1]; + /* Place spectrum analysis and energy windows */ + lpc10_placea(&ipitch, s->voibuf, &s->obound[2], 3, s->vwin, s->awin, ewin, LPC10_SAMPLES_PER_FRAME, 156); + /* Remove short term DC bias over the analysis window. */ + lanal = s->awin[2][1] + 1 - s->awin[2][0]; + remove_dc_bias(&s->pebuf[s->awin[2][0] - 181], lanal, abuf); + /* Compute RMS over integer number of pitch periods within the analysis window. */ + /* Note that in a hardware implementation this computation may be + simplified by using diagonal elements of phi computed by mload(). */ + s->rmsbuf[2] = energyf(&abuf[ewin[2][0] - s->awin[2][0]], ewin[2][1] - ewin[2][0] + 1); + /* Matrix load and invert, check RC's for stability */ + mload(LPC10_ORDER, 1, lanal, abuf, phi, psi); + invert(LPC10_ORDER, phi, psi, &s->rcbuf[2][0]); + rcchk(LPC10_ORDER, &s->rcbuf[1][0], &s->rcbuf[2][0]); + /* Set return parameters */ + voice[0] = s->voibuf[1][0]; + voice[1] = s->voibuf[1][1]; + *rms = s->rmsbuf[0]; + for (i = 0; i < LPC10_ORDER; i++) + rc[i] = s->rcbuf[0][i]; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/lpc10_decode.c b/libs/voipcodecs/src/lpc10_decode.c new file mode 100644 index 0000000000..e58ab02047 --- /dev/null +++ b/libs/voipcodecs/src/lpc10_decode.c @@ -0,0 +1,1106 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * lpc10_decode.c - LPC10 low bit rate speech codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This code is based on the U.S. Department of Defense reference + * implementation of the LPC-10 2400 bps Voice Coder. They do not + * exert copyright claims on their code, and it may be freely used. + * + * $Id: lpc10_decode.c,v 1.16 2007/11/26 13:28:59 steveu Exp $ + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif +#include + +#include "voipcodecs/telephony.h" +#include "voipcodecs/dc_restore.h" +#include "voipcodecs/lpc10.h" + +#define LPC10_ORDER 10 + +#if !defined(min) +#define min(a,b) ((a) <= (b) ? (a) : (b)) +#endif +#if !defined(max) +#define max(a,b) ((a) >= (b) ? (a) : (b)) +#endif + +/* Pseudo random number generator based on Knuth, Vol 2, p. 27. */ +/* lpc10_random - int32_t variable, uniformly distributed over -32768 to 32767 */ +static int32_t lpc10_random(lpc10_decode_state_t *s) +{ + int32_t ret_val; + + /* The following is a 16 bit 2's complement addition, + with overflow checking disabled */ + s->y[s->k] += s->y[s->j]; + ret_val = s->y[s->k]; + if (--s->k < 0) + s->k = 4; + if (--s->j < 0) + s->j = 4; + return ret_val; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int32_t pow_ii(int32_t x, int32_t n) +{ + int32_t pow; + uint32_t u; + + if (n <= 0) + { + if (n == 0 || x == 1) + return 1; + if (x != -1) + return (x == 0) ? 1/x : 0; + n = -n; + } + u = n; + for (pow = 1; ; ) + { + if ((u & 1)) + pow *= x; + if ((u >>= 1) == 0) + break; + x *= x; + } + return pow; +} +/*- End of function --------------------------------------------------------*/ + +/* Synthesize one pitch epoch */ +static void bsynz(lpc10_decode_state_t *s, + float coef[], + int32_t ip, + int32_t *iv, + float sout[], + float rms, + float ratio, + float g2pass) +{ + static const int32_t kexc[25] = + { + 8, -16, 26, -48, 86, -162, 294, -502, 718, -728, 184, + 672, -610, -672, 184, 728, 718, 502, 294, 162, 86, 48, 26, 16, 8 + }; + int32_t i; + int32_t j; + int32_t k; + int32_t px; + float noise[166]; + float pulse; + float r1; + float gain; + float xssq; + float sscale; + float xy; + float sum; + float ssq; + float lpi0; + float hpi0; + + /* MAXPIT + MAXORD = 166 */ + /* Calculate history scale factor XY and scale filter state */ + /* Computing MIN */ + r1 = s->rmso_bsynz/(rms + 1.0e-6f); + xy = min(r1, 8.0f); + s->rmso_bsynz = rms; + for (i = 0; i < LPC10_ORDER; i++) + s->exc2[i] = s->exc2[s->ipo + i]*xy; + s->ipo = ip; + if (*iv == 0) + { + /* Generate white noise for unvoiced */ + for (i = 0; i < ip; i++) + s->exc[LPC10_ORDER + i] = (float) (lpc10_random(s)/64); + /* Impulse double excitation for plosives */ + px = (lpc10_random(s) + 32768)*(ip - 1)/65536 + LPC10_ORDER + 1; + r1 = ratio/4.0f; + pulse = r1*342; + if (pulse > 2.0e3f) + pulse = 2.0e3f; + s->exc[px - 1] += pulse; + s->exc[px] -= pulse; + } + else + { + sscale = sqrtf((float) ip)/6.928f; + for (i = 0; i < ip; i++) + { + s->exc[LPC10_ORDER + i] = 0.0f; + if (i < 25) + s->exc[LPC10_ORDER + i] = sscale*kexc[i]; + lpi0 = s->exc[LPC10_ORDER + i]; + s->exc[LPC10_ORDER + i] = s->exc[LPC10_ORDER + i]*0.125f + s->lpi[0]*0.75f + s->lpi[1]*0.125f; + s->lpi[1] = s->lpi[0]; + s->lpi[0] = lpi0; + } + for (i = 0; i < ip; i++) + { + noise[LPC10_ORDER + i] = lpc10_random(s)/64.0f; + hpi0 = noise[LPC10_ORDER + i]; + noise[LPC10_ORDER + i] = noise[LPC10_ORDER + i]*-0.125f + s->hpi[0]*0.25f + s->hpi[1]*-0.125f; + s->hpi[1] = s->hpi[0]; + s->hpi[0] = hpi0; + } + for (i = 0; i < ip; i++) + s->exc[LPC10_ORDER + i] += noise[LPC10_ORDER + i]; + } + /* Synthesis filters: */ + /* Modify the excitation with all-zero filter 1 + G*SUM */ + xssq = 0.0f; + for (i = 0; i < ip; i++) + { + k = LPC10_ORDER + i; + sum = 0.0f; + for (j = 0; j < LPC10_ORDER; j++) + sum += coef[j]*s->exc[k - j - 1]; + sum *= g2pass; + s->exc2[k] = sum + s->exc[k]; + } + /* Synthesize using the all pole filter 1/(1 - SUM) */ + for (i = 0; i < ip; i++) + { + k = LPC10_ORDER + i; + sum = 0.0f; + for (j = 0; j < LPC10_ORDER; j++) + sum += coef[j]*s->exc2[k - j - 1]; + s->exc2[k] = sum + s->exc2[k]; + xssq += s->exc2[k]*s->exc2[k]; + } + /* Save filter history for next epoch */ + for (i = 0; i < LPC10_ORDER; i++) + { + s->exc[i] = s->exc[ip + i]; + s->exc2[i] = s->exc2[ip + i]; + } + /* Apply gain to match RMS */ + ssq = rms*rms*ip; + gain = sqrtf(ssq/xssq); + for (i = 0; i < ip; i++) + sout[i] = gain*s->exc2[LPC10_ORDER + i]; +} +/*- End of function --------------------------------------------------------*/ + +/* Synthesize a single pitch epoch */ +static int pitsyn(lpc10_decode_state_t *s, + int voice[], + int32_t *pitch, + float *rms, + float *rc, + int32_t ivuv[], + int32_t ipiti[], + float *rmsi, + float *rci, + int32_t *nout, + float *ratio) +{ + int32_t rci_dim1; + int32_t rci_offset; + int32_t i1; + int32_t i; + int32_t j; + int32_t vflag; + int32_t jused; + int32_t lsamp; + int32_t ip; + int32_t nl; + int32_t ivoice; + int32_t istart; + float r1; + float alrn; + float alro; + float yarc[10]; + float prop; + float slope; + float uvpit; + float xxy; + + rci_dim1 = LPC10_ORDER; + rci_offset = rci_dim1 + 1; + rci -= rci_offset; + + if (*rms < 1.0f) + *rms = 1.0f; + if (s->rmso < 1.0f) + s->rmso = 1.0f; + uvpit = 0.0f; + *ratio = *rms/(s->rmso + 8.0f); + if (s->first_pitsyn) + { + lsamp = 0; + ivoice = voice[1]; + if (ivoice == 0) + *pitch = LPC10_SAMPLES_PER_FRAME/4; + *nout = LPC10_SAMPLES_PER_FRAME / *pitch; + s->jsamp = LPC10_SAMPLES_PER_FRAME - *nout * *pitch; + + i1 = *nout; + for (i = 0; i < i1; i++) + { + for (j = 0; j < LPC10_ORDER; j++) + rci[j + (i + 1)*rci_dim1 + 1] = rc[j]; + ivuv[i] = ivoice; + ipiti[i] = *pitch; + rmsi[i] = *rms; + } + s->first_pitsyn = FALSE; + } + else + { + vflag = 0; + lsamp = LPC10_SAMPLES_PER_FRAME + s->jsamp; + slope = (*pitch - s->ipito)/(float) lsamp; + *nout = 0; + jused = 0; + istart = 1; + if (voice[0] == s->ivoico && voice[1] == voice[0]) + { + if (voice[1] == 0) + { + /* SSUV - - 0 , 0 , 0 */ + *pitch = LPC10_SAMPLES_PER_FRAME/4; + s->ipito = *pitch; + if (*ratio > 8.0f) + s->rmso = *rms; + } + /* SSVC - - 1 , 1 , 1 */ + slope = (*pitch - s->ipito)/(float) lsamp; + ivoice = voice[1]; + } + else + { + if (s->ivoico != 1) + { + if (s->ivoico == voice[0]) + { + /* UV2VC2 - - 0 , 0 , 1 */ + nl = lsamp - LPC10_SAMPLES_PER_FRAME/4; + } + else + { + /* UV2VC1 - - 0 , 1 , 1 */ + nl = lsamp - LPC10_SAMPLES_PER_FRAME*3/4; + } + ipiti[0] = nl/2; + ipiti[1] = nl - ipiti[0]; + ivuv[0] = 0; + ivuv[1] = 0; + rmsi[0] = s->rmso; + rmsi[1] = s->rmso; + for (i = 0; i < LPC10_ORDER; i++) + { + rci[i + rci_dim1 + 1] = s->rco[i]; + rci[i + (rci_dim1 << 1) + 1] = s->rco[i]; + s->rco[i] = rc[i]; + } + slope = 0.0f; + *nout = 2; + s->ipito = *pitch; + jused = nl; + istart = nl + 1; + ivoice = 1; + } + else + { + if (s->ivoico != voice[0]) + { + /* VC2UV1 - - 1 , 0 , 0 */ + lsamp = LPC10_SAMPLES_PER_FRAME/4 + s->jsamp; + } + else + { + /* VC2UV2 - - 1 , 1 , 0 */ + lsamp = LPC10_SAMPLES_PER_FRAME*3/4 + s->jsamp; + } + for (i = 0; i < LPC10_ORDER; i++) + { + yarc[i] = rc[i]; + rc[i] = s->rco[i]; + } + ivoice = 1; + slope = 0.0f; + vflag = 1; + } + } + /* Here is the value of most variables that are used below, depending on */ + /* the values of IVOICO, VOICE(1), and VOICE(2). VOICE(1) and VOICE(2) */ + /* are input arguments, and IVOICO is the value of VOICE(2) on the */ + /* previous call (see notes for the IF (NOUT .NE. 0) statement near the */ + /* end). Each of these three values is either 0 or 1. These three */ + /* values below are given as 3-bit long strings, in the order IVOICO, */ + /* VOICE(1), and VOICE(2). It appears that the code above assumes that */ + /* the bit sequences 010 and 101 never occur, but I wonder whether a */ + /* large enough number of bit errors in the channel could cause such a */ + /* thing to happen, and if so, could that cause NOUT to ever go over 11? */ + + /* Note that all of the 180 values in the table are floatly LFRAME, but */ + /* 180 has fewer characters, and it makes the table a little more */ + /* concrete. If LFRAME is ever changed, keep this in mind. Similarly, */ + /* 135's are 3*LFRAME/4, and 45's are LFRAME/4. If LFRAME is not a */ + /* multiple of 4, then the 135 for NL-JSAMP is actually LFRAME-LFRAME/4, */ + /* and the 45 for NL-JSAMP is actually LFRAME-3*LFRAME/4. */ + + /* Note that LSAMP-JSAMP is given as the variable. This was just for */ + /* brevity, to avoid adding "+JSAMP" to all of the column entries. */ + /* Similarly for NL-JSAMP. */ + + /* Variable | 000 001 011,010 111 110 100,101 */ + /* ------------+-------------------------------------------------- */ + /* ISTART | 1 NL+1 NL+1 1 1 1 */ + /* LSAMP-JSAMP | 180 180 180 180 135 45 */ + /* IPITO | 45 PITCH PITCH oldPITCH oldPITCH oldPITCH */ + /* SLOPE | 0 0 0 seebelow 0 0 */ + /* JUSED | 0 NL NL 0 0 0 */ + /* PITCH | 45 PITCH PITCH PITCH PITCH PITCH */ + /* NL-JSAMP | -- 135 45 -- -- -- */ + /* VFLAG | 0 0 0 0 1 1 */ + /* NOUT | 0 2 2 0 0 0 */ + /* IVOICE | 0 1 1 1 1 1 */ + + /* while_loop | once once once once twice twice */ + + /* ISTART | -- -- -- -- JUSED+1 JUSED+1 */ + /* LSAMP-JSAMP | -- -- -- -- 180 180 */ + /* IPITO | -- -- -- -- oldPITCH oldPITCH */ + /* SLOPE | -- -- -- -- 0 0 */ + /* JUSED | -- -- -- -- ?? ?? */ + /* PITCH | -- -- -- -- PITCH PITCH */ + /* NL-JSAMP | -- -- -- -- -- -- */ + /* VFLAG | -- -- -- -- 0 0 */ + /* NOUT | -- -- -- -- ?? ?? */ + /* IVOICE | -- -- -- -- 0 0 */ + + /* UVPIT is always 0.0 on the first pass through the DO WHILE (TRUE) + loop below. */ + + /* The only possible non-0 value of SLOPE (in column 111) is + (PITCH-IPITO)/FLOAT(LSAMP) */ + + /* Column 101 is identical to 100. Any good properties we can prove + for 100 will also hold for 101. Similarly for 010 and 011. */ + + /* synths() calls this subroutine with PITCH restricted to the range 20 to + 156. IPITO is similarly restricted to this range, after the first + call. IP below is also restricted to this range, given the + definitions of IPITO, SLOPE, UVPIT, and that I is in the range ISTART + to LSAMP. */ + + for (;;) + { + for (i = istart; i <= lsamp; i++) + { + r1 = s->ipito + slope*i; + ip = (int32_t) (r1 + 0.5f); + if (uvpit != 0.0f) + ip = (int32_t) uvpit; + if (ip <= i - jused) + { + ++(*nout); + ipiti[*nout - 1] = ip; + *pitch = ip; + ivuv[*nout - 1] = ivoice; + jused += ip; + prop = (jused - ip/2)/(float) lsamp; + for (j = 0; j < LPC10_ORDER; j++) + { + alro = logf((s->rco[j] + 1)/(1 - s->rco[j])); + alrn = logf((rc[j] + 1)/(1 - rc[j])); + xxy = alro + prop*(alrn - alro); + xxy = expf(xxy); + rci[j + *nout*rci_dim1 + 1] = (xxy - 1.0f)/(xxy + 1.0f); + } + rmsi[*nout - 1] = logf(s->rmso) + prop*(logf(*rms) - logf(s->rmso)); + rmsi[*nout - 1] = expf(rmsi[*nout - 1]); + } + } + if (vflag != 1) + break; + + vflag = 0; + istart = jused + 1; + lsamp = LPC10_SAMPLES_PER_FRAME + s->jsamp; + slope = 0.0f; + ivoice = 0; + uvpit = (float) ((lsamp - istart)/2); + if (uvpit > 90.0f) + uvpit /= 2; + s->rmso = *rms; + for (i = 0; i < LPC10_ORDER; i++) + { + rc[i] = yarc[i]; + s->rco[i] = yarc[i]; + } + } + s->jsamp = lsamp - jused; + } + if (*nout != 0) + { + s->ivoico = voice[1]; + s->ipito = *pitch; + s->rmso = *rms; + for (i = 0; i < LPC10_ORDER; i++) + s->rco[i] = rc[i]; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static void deemp(lpc10_decode_state_t *s, float x[], int len) +{ + int i; + float r1; + float dei0; + + for (i = 0; i < len; i++) + { + dei0 = x[i]; + r1 = x[i] - s->dei[0]*1.9998f + s->dei[1]; + x[i] = r1 + s->deo[0]*2.5f - s->deo[1]*2.0925f + s->deo[2]*0.585f; + s->dei[1] = s->dei[0]; + s->dei[0] = dei0; + s->deo[2] = s->deo[1]; + s->deo[1] = s->deo[0]; + s->deo[0] = x[i]; + } +} +/*- End of function --------------------------------------------------------*/ + +/* Convert reflection coefficients to predictor coefficients */ +static float reflection_coeffs_to_predictor_coeffs(float rc[], float pc[], float gprime) +{ + float temp[10]; + float g2pass; + int i; + int j; + + g2pass = 1.0f; + for (i = 0; i < LPC10_ORDER; i++) + g2pass *= 1.0f - rc[i]*rc[i]; + g2pass = gprime*sqrtf(g2pass); + pc[0] = rc[0]; + for (i = 1; i < LPC10_ORDER; i++) + { + for (j = 0; j < i; j++) + temp[j] = pc[j] - rc[i]*pc[i - j - 1]; + for (j = 0; j < i; j++) + pc[j] = temp[j]; + pc[i] = rc[i]; + } + return g2pass; +} +/*- End of function --------------------------------------------------------*/ + +static int synths(lpc10_decode_state_t *s, + int voice[], + int32_t *pitch, + float *rms, + float *rc, + float speech[]) +{ + int32_t i1; + int32_t ivuv[16]; + int32_t ipiti[16]; + int32_t nout; + int32_t i; + int32_t j; + float rmsi[16]; + float ratio; + float g2pass; + float pc[10]; + float rci[160]; + + i1 = min(*pitch, 156); + *pitch = max(i1, 20); + for (i = 0; i < LPC10_ORDER; i++) + rc[i] = max(min(rc[i], 0.99f), -0.99f); + pitsyn(s, voice, pitch, rms, rc, ivuv, ipiti, rmsi, rci, &nout, &ratio); + if (nout > 0) + { + for (j = 0; j < nout; j++) + { + /* Add synthesized speech for pitch period J to the end of s->buf. */ + g2pass = reflection_coeffs_to_predictor_coeffs(&rci[j*10], pc, 0.7f); + bsynz(s, pc, ipiti[j], &ivuv[j], &s->buf[s->buflen], rmsi[j], ratio, g2pass); + deemp(s, &s->buf[s->buflen], ipiti[j]); + s->buflen += ipiti[j]; + } + /* Copy first MAXFRM samples from BUF to output array speech (scaling them), + and then remove them from the beginning of s->buf. */ + + for (i = 0; i < LPC10_SAMPLES_PER_FRAME; i++) + speech[i] = s->buf[i]/4096.0f; + s->buflen -= LPC10_SAMPLES_PER_FRAME; + for (i = 0; i < s->buflen; i++) + s->buf[i] = s->buf[i + LPC10_SAMPLES_PER_FRAME]; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static void lpc10_unpack(lpc10_frame_t *t, const uint8_t ibits[]) +{ + static const int bit[10] = + { + 2, 4, 8, 8, 8, 8, 16, 16, 16, 16 + }; + static const int iblist[53] = + { + 13, 12, 11, 1, 2, 13, 12, 11, 1, 2, + 13, 10, 11, 2, 1, 10, 13, 12, 11, 10, + 2, 13, 12, 11, 10, 2, 1, 12, 7, 6, + 1, 10, 9, 8, 7, 4, 6, 9, 8, 7, + 5, 1, 9, 8, 4, 6, 1, 5, 9, 8, + 7, 5, 6 + }; + int32_t itab[13]; + int x; + int i; + + /* ibits is 54 bits of LPC data ordered as follows: */ + /* R1-0, R2-0, R3-0, P-0, A-0, */ + /* R1-1, R2-1, R3-1, P-1, A-1, */ + /* R1-2, R4-0, R3-2, A-2, P-2, R4-1, */ + /* R1-3, R2-2, R3-3, R4-2, A-3, */ + /* R1-4, R2-3, R3-4, R4-3, A-4, */ + /* P-3, R2-4, R7-0, R8-0, P-4, R4-4, */ + /* R5-0, R6-0, R7-1,R10-0, R8-1, */ + /* R5-1, R6-1, R7-2, R9-0, P-5, */ + /* R5-2, R6-2,R10-1, R8-2, P-6, R9-1, */ + /* R5-3, R6-3, R7-3, R9-2, R8-3, SYNC */ + + /* Reconstruct ITAB */ + for (i = 0; i < 13; i++) + itab[i] = 0; + for (i = 0; i < 53; i++) + { + x = 52 - i; + x = (ibits[x >> 3] >> (7 - (x & 7))) & 1; + itab[iblist[52 - i] - 1] = (itab[iblist[52 - i] - 1] << 1) | x; + } + /* Sign extend the RC's */ + for (i = 0; i < LPC10_ORDER; i++) + { + if ((itab[i + 3] & bit[i])) + itab[i + 3] -= (bit[i] << 1); + } + /* Restore variables */ + t->ipitch = itab[0]; + t->irms = itab[1]; + for (i = 0; i < LPC10_ORDER; i++) + t->irc[i] = itab[LPC10_ORDER - 1 - i + 3]; +} +/*- End of function --------------------------------------------------------*/ + +/* Hamming 8, 4 decoder - can correct 1 out of seven bits + and can detect up to two errors. */ + +/* This subroutine is entered with an eight bit word in INPUT. The 8th */ +/* bit is parity and is stripped off. The remaining 7 bits address the */ +/* hamming 8, 4 table and the output OUTPUT from the table gives the 4 */ +/* bits of corrected data. If bit 4 is set, no error was detected. */ +/* ERRCNT is the number of errors counted. */ + +static int32_t hamming_84_decode(int32_t input, int *errcnt) +{ + static const uint8_t dactab[128] = + { + 16, 0, 0, 3, 0, 5, 14, 7, 0, 9, 14, 11, 14, 13, 30, 14, + 0, 9, 2, 7, 4, 7, 7, 23, 9, 25, 10, 9, 12, 9, 14, 7, + 0, 5, 2, 11, 5, 21, 6, 5, 8, 11, 11, 27, 12, 5, 14, 11, + 2, 1, 18, 2, 12, 5, 2, 7, 12, 9, 2, 11, 28, 12, 12, 15, + 0, 3, 3, 19, 4, 13, 6, 3, 8, 13, 10, 3, 13, 29, 14, 13, + 4, 1, 10, 3, 20, 4, 4, 7, 10, 9, 26, 10, 4, 13, 10, 15, + 8, 1, 6, 3, 6, 5, 22, 6, 24, 8, 8, 11, 8, 13, 6, 15, + 1, 17 , 2, 1, 4, 1, 6, 15, 8, 1, 10, 15, 12, 15, 15, 31 + }; + int i; + int parity; + int32_t output; + + parity = input & 255; + parity ^= parity >> 4; + parity ^= parity >> 2; + parity ^= parity >> 1; + parity &= 1; + i = dactab[input & 127]; + output = i & 15; + if ((i & 16)) + { + /* No errors detected in seven bits */ + if (parity) + (*errcnt)++; + } + else + { + /* One or two errors detected */ + (*errcnt)++; + if (parity == 0) + { + /* Two errors detected */ + (*errcnt)++; + output = -1; + } + } + return output; +} +/*- End of function --------------------------------------------------------*/ + +static int32_t median(int32_t d1, int32_t d2, int32_t d3) +{ + int32_t ret_val; + + ret_val = d2; + if (d2 > d1 && d2 > d3) + { + ret_val = d1; + if (d3 > d1) + ret_val = d3; + } + else if (d2 < d1 && d2 < d3) + { + ret_val = d1; + if (d3 < d1) + ret_val = d3; + } + return ret_val; +} +/*- End of function --------------------------------------------------------*/ + +static void decode(lpc10_decode_state_t *s, + lpc10_frame_t *t, + int voice[], + int32_t *pitch, + float *rms, + float rc[]) +{ + static const int32_t ivtab[32] = + { + 24960, 24960, 24960, 24960, 25480, 25480, 25483, 25480, + 16640, 1560, 1560, 1560, 16640, 1816, 1563, 1560, + 24960, 24960, 24859, 24856, 26001, 25881, 25915, 25913, + 1560, 1560, 7800, 3640, 1561, 1561, 3643, 3641 + }; + static const float corth[32] = + { + 32767.0f, 10.0f, 5.0f, 0.0f, 32767.0f, 8.0f, 4.0f, 0.0f, + 32.0f, 6.4f, 3.2f, 0.0f, 32.0f, 6.4f, 3.2f, 0.0f, + 32.0f, 11.2f, 6.4f, 0.0f, 32.0f, 11.2f, 6.4f, 0.0f, + 16.0f, 5.6f, 3.2f, 0.0f, 16.0f, 5.6f, 3.2f, 0.0f + }; + static const int32_t detau[128] = + { + 0, 0, 0, 3, 0, 3, 3, 31, + 0, 3, 3, 21, 3, 3, 29, 30, + 0, 3, 3, 20, 3, 25, 27, 26, + 3, 23, 58, 22, 3, 24, 28, 3, + 0, 3, 3, 3, 3, 39, 33, 32, + 3, 37, 35, 36, 3, 38, 34, 3, + 3, 42, 46, 44, 50, 40, 48, 3, + 54, 3, 56, 3, 52, 3, 3, 1, + 0, 3, 3, 108, 3, 78, 100, 104, + 3, 84, 92, 88, 156, 80, 96, 3, + 3, 74, 70, 72, 66, 76, 68, 3, + 62, 3, 60, 3, 64, 3, 3, 1, + 3, 116, 132, 112, 148, 152, 3, 3, + 140, 3, 136, 3, 144, 3, 3, 1, + 124, 120, 128, 3, 3, 3, 3, 1, + 3, 3, 3, 1, 3, 1, 1, 1 + }; + static const int32_t rmst[64] = + { + 1024, 936, 856, 784, 718, 656, 600, 550, + 502, 460, 420, 384, 352, 328, 294, 270, + 246, 226, 206, 188, 172, 158, 144, 132, + 120, 110, 102, 92, 84, 78, 70, 64, + 60, 54, 50, 46, 42, 38, 34, 32, + 30, 26, 24, 22, 20, 18, 17, 16, + 15, 14, 13, 12, 11, 10, 9, 8, + 7, 6, 5, 4, 3, 2, 1, 0 + }; + static const int32_t detab7[32] = + { + 4, 11, 18, 25, 32, 39, 46, 53, + 60, 66, 72, 77, 82, 87, 92, 96, + 101, 104, 108, 111, 114, 115, 117, 119, + 121, 122, 123, 124, 125, 126, 127, 127 + }; + static const float descl[8] = + { + 0.6953f, 0.625f, 0.5781f, 0.5469f, 0.5312f, 0.5391f, 0.4688f, 0.3828f + }; + static const int32_t deadd[8] = + { + 1152, -2816, -1536, -3584, -1280, -2432, 768, -1920 + }; + static const int32_t qb[8] = + { + 511, 511, 1023, 1023, 1023, 1023, 2047, 4095 + }; + static const int32_t nbit[10] = + { + 8, 8, 5, 5, 4, 4, 4, 4, 3, 2 + }; + static const int32_t zrc[10] = + { + 0, 0, 0, 0, 0, 3, 0, 2, 0, 0 + }; + static const int32_t bit[5] = + { + 2, 4, 8, 16, 32 + }; + int32_t ipit; + int32_t iout; + int32_t i; + int32_t icorf; + int32_t index; + int32_t ivoic; + int32_t ixcor; + int32_t i1; + int32_t i2; + int32_t i4; + int32_t ishift; + int32_t lsb; + int errcnt; + + /* If no error correction, do pitch and voicing then jump to decode */ + i4 = detau[t->ipitch]; + if (!s->error_correction) + { + voice[0] = 1; + voice[1] = 1; + if (t->ipitch <= 1) + voice[0] = 0; + if (t->ipitch == 0 || t->ipitch == 2) + voice[1] = 0; + if (i4 <= 4) + i4 = s->iptold; + *pitch = i4; + if (voice[0] == 1 && voice[1] == 1) + s->iptold = *pitch; + if (voice[0] != voice[1]) + *pitch = s->iptold; + } + else + { + /* Do error correction pitch and voicing */ + if (i4 > 4) + { + s->dpit[0] = i4; + ivoic = 2; + s->iavgp = (s->iavgp*15 + i4 + 8)/16; + } + else + { + s->dpit[0] = s->iavgp; + ivoic = i4; + } + s->drms[0] = t->irms; + for (i = 0; i < LPC10_ORDER; i++) + s->drc[i][0] = t->irc[i]; + /* Determine index to IVTAB from V/UV decision */ + /* If error rate is high then use alternate table */ + index = (s->ivp2h << 4) + (s->iovoic << 2) + ivoic + 1; + i1 = ivtab[index - 1]; + ipit = i1 & 3; + icorf = i1 >> 3; + if (s->erate < 2048) + icorf /= 64; + /* Determine error rate: 4=high 1=low */ + ixcor = 4; + if (s->erate < 2048) + ixcor = 3; + if (s->erate < 1024) + ixcor = 2; + if (s->erate < 128) + ixcor = 1; + /* Voice/unvoice decision determined from bits 0 and 1 of IVTAB */ + voice[0] = icorf/2 & 1; + voice[1] = icorf & 1; + /* Skip decoding on first frame because present data not yet available */ + if (s->first) + { + s->first = FALSE; + /* Assign PITCH a "default" value on the first call, since */ + /* otherwise it would be left uninitialized. The two lines */ + /* below were copied from above, since it seemed like a */ + /* reasonable thing to do for the first call. */ + if (i4 <= 4) + i4 = s->iptold; + *pitch = i4; + } + else + { + /* If bit 4 of ICORF is set then correct RMS and RC(1) - RC(4). */ + /* Determine error rate and correct errors using a Hamming 8,4 code */ + /* during transition of unvoiced frames. If IOUT is negative, */ + /* more than 1 error occurred, use previous frame's parameters. */ + if ((icorf & bit[3]) != 0) + { + errcnt = 0; + lsb = s->drms[1] & 1; + index = (s->drc[7][1] << 4) + s->drms[1]/2; + iout = hamming_84_decode(index, &errcnt); + s->drms[1] = s->drms[2]; + if (iout >= 0) + s->drms[1] = (iout << 1) + lsb; + for (i = 1; i <= 4; i++) + { + if (i == 1) + i1 = ((s->drc[8][1] & 7) << 1) + (s->drc[9][1] & 1); + else + i1 = s->drc[8 - i][1] & 15; + i2 = s->drc[4 - i][1] & 31; + lsb = i2 & 1; + index = (i1 << 4) + (i2 >> 1); + iout = hamming_84_decode(index, &errcnt); + if (iout >= 0) + { + iout = (iout << 1) + lsb; + if ((iout & 16) == 16) + iout -= 32; + } + else + { + iout = s->drc[4 - i][2]; + } + s->drc[4 - i][1] = iout; + } + /* Determine error rate */ + s->erate = (int32_t) (s->erate*0.96875f + errcnt*102.0f); + } + /* Get unsmoothed RMS, RC's, and PITCH */ + t->irms = s->drms[1]; + for (i = 0; i < LPC10_ORDER; i++) + t->irc[i] = s->drc[i][1]; + if (ipit == 1) + s->dpit[1] = s->dpit[2]; + if (ipit == 3) + s->dpit[1] = s->dpit[0]; + *pitch = s->dpit[1]; + /* If bit 2 of ICORF is set then smooth RMS and RC's, */ + if ((icorf & bit[1]) != 0) + { + if ((float) abs(s->drms[1] - s->drms[0]) >= corth[ixcor + 3] + && + (float) abs(s->drms[1] - s->drms[2]) >= corth[ixcor + 3]) + { + t->irms = median(s->drms[2], s->drms[1], s->drms[0]); + } + for (i = 0; i < 6; i++) + { + if ((float) abs(s->drc[i][1] - s->drc[i][0]) >= corth[ixcor + ((i + 3) << 2) - 5] + && + (float) abs(s->drc[i][1] - s->drc[i][2]) >= corth[ixcor + ((i + 3) << 2) - 5]) + { + t->irc[i] = median(s->drc[i][2], s->drc[i][1], s->drc[i][0]); + } + } + } + /* If bit 3 of ICORF is set then smooth pitch */ + if ((icorf & bit[2]) != 0) + { + if ((float) abs(s->dpit[1] - s->dpit[0]) >= corth[ixcor - 1] + && + (float) abs(s->dpit[1] - s->dpit[2]) >= corth[ixcor - 1]) + { + *pitch = median(s->dpit[2], s->dpit[1], s->dpit[0]); + } + } + /* If bit 5 of ICORF is set then RC(5) - RC(10) are loaded with + values so that after quantization bias is removed in decode + the values will be zero. */ + } + if ((icorf & bit[4]) != 0) + { + for (i = 4; i < LPC10_ORDER; i++) + t->irc[i] = zrc[i]; + } + /* Housekeeping - one frame delay */ + s->iovoic = ivoic; + s->ivp2h = voice[1]; + s->dpit[2] = s->dpit[1]; + s->dpit[1] = s->dpit[0]; + s->drms[2] = s->drms[1]; + s->drms[1] = s->drms[0]; + for (i = 0; i < LPC10_ORDER; i++) + { + s->drc[i][2] = s->drc[i][1]; + s->drc[i][1] = s->drc[i][0]; + } + } + /* Decode RMS */ + t->irms = rmst[(31 - t->irms)*2]; + /* Decode RC(1) and RC(2) from log-area-ratios */ + /* Protect from illegal coded value (-16) caused by bit errors */ + for (i = 0; i < 2; i++) + { + i2 = t->irc[i]; + i1 = 0; + if (i2 < 0) + { + i1 = 1; + i2 = -i2; + if (i2 > 15) + i2 = 0; + } + i2 = detab7[i2*2]; + if (i1 == 1) + i2 = -i2; + ishift = 15 - nbit[i]; + t->irc[i] = i2*pow_ii(2, ishift); + } + /* Decode RC(3)-RC(10) to sign plus 14 bits */ + for (i = 2; i < LPC10_ORDER; i++) + { + ishift = 15 - nbit[i]; + i2 = t->irc[i]*pow_ii(2, ishift) + qb[i - 2]; + t->irc[i] = (int32_t) (i2*descl[i - 2] + deadd[i - 2]); + } + /* Scale RMS and RC's to floats */ + *rms = (float) t->irms; + for (i = 0; i < LPC10_ORDER; i++) + rc[i] = t->irc[i]/16384.0f; +} +/*- End of function --------------------------------------------------------*/ + +lpc10_decode_state_t *lpc10_decode_init(lpc10_decode_state_t *s, int error_correction) +{ + static const int16_t rand_init[] = + { + -21161, + -8478, + 30892, + -10216, + 16950 + }; + int i; + int j; + + if (s == NULL) + { + if ((s = (lpc10_decode_state_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + + s->error_correction = error_correction; + + /* State used by function decode */ + s->iptold = 60; + s->first = TRUE; + s->ivp2h = 0; + s->iovoic = 0; + s->iavgp = 60; + s->erate = 0; + for (i = 0; i < 3; i++) + { + for (j = 0; j < 10; j++) + s->drc[j][i] = 0; + s->dpit[i] = 0; + s->drms[i] = 0; + } + + /* State used by function synths */ + for (i = 0; i < 360; i++) + s->buf[i] = 0.0f; + s->buflen = LPC10_SAMPLES_PER_FRAME; + + /* State used by function pitsyn */ + s->rmso = 1.0f; + s->first_pitsyn = TRUE; + + /* State used by function bsynz */ + s->ipo = 0; + for (i = 0; i < 166; i++) + { + s->exc[i] = 0.0f; + s->exc2[i] = 0.0f; + } + for (i = 0; i < 3; i++) + { + s->lpi[i] = 0.0f; + s->hpi[i] = 0.0f; + } + s->rmso_bsynz = 0.0f; + + /* State used by function lpc10_random */ + s->j = 1; + s->k = 4; + for (i = 0; i < 5; i++) + s->y[i] = rand_init[i]; + + /* State used by function deemp */ + for (i = 0; i < 2; i++) + s->dei[i] = 0.0f; + for (i = 0; i < 3; i++) + s->deo[i] = 0.0f; + + return s; +} +/*- End of function --------------------------------------------------------*/ + +int lpc10_decode_release(lpc10_decode_state_t *s) +{ + free(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +int lpc10_decode(lpc10_decode_state_t *s, int16_t amp[], const uint8_t code[], int quant) +{ + int voice[2]; + int32_t pitch; + float speech[LPC10_SAMPLES_PER_FRAME]; + float rc[LPC10_ORDER]; + lpc10_frame_t frame; + float rms; + int i; + int j; + + /* Decode 54 bits to LPC10_SAMPLES_PER_FRAME speech samples. */ + for (i = 0; i < quant; i++) + { + lpc10_unpack(&frame, &code[i*7]); + decode(s, &frame, voice, &pitch, &rms, rc); + synths(s, voice, &pitch, &rms, rc, speech); + for (j = 0; j < LPC10_SAMPLES_PER_FRAME; j++) + amp[i*LPC10_SAMPLES_PER_FRAME + j] = (int16_t) rintf(32768.0f*speech[j]); + } + + return quant*LPC10_SAMPLES_PER_FRAME; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/lpc10_encdecs.h b/libs/voipcodecs/src/lpc10_encdecs.h new file mode 100644 index 0000000000..836e570ee3 --- /dev/null +++ b/libs/voipcodecs/src/lpc10_encdecs.h @@ -0,0 +1,107 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * lpc10_encdecs.h - LPC10 low bit rate speech codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: lpc10_encdecs.h,v 1.9 2006/11/30 15:41:47 steveu Exp $ + */ + +#define LPC10_ORDER 10 + +#if !defined(min) +#define min(a,b) ((a) <= (b) ? (a) : (b)) +#endif +#if !defined(max) +#define max(a,b) ((a) >= (b) ? (a) : (b)) +#endif + +void lpc10_placea(int32_t *ipitch, + int32_t voibuf[4][2], + int32_t *obound, + int32_t af, + int32_t vwin[3][2], + int32_t awin[3][2], + int32_t ewin[3][2], + int32_t lframe, + int32_t maxwin); + +void lpc10_placev(int32_t *osbuf, + int32_t *osptr, + int32_t oslen, + int32_t *obound, + int32_t vwin[3][2], + int32_t af, + int32_t lframe, + int32_t minwin, + int32_t maxwin, + int32_t dvwinl, + int32_t dvwinh); + +void lpc10_voicing(lpc10_encode_state_t *st, + int32_t *vwin, + float *inbuf, + float *lpbuf, + const int32_t buflim[], + int32_t half, + float *minamd, + float *maxamd, + int32_t *mintau, + float *ivrc, + int32_t *obound); + +void lpc10_analyse(lpc10_encode_state_t *st, float *speech, int32_t *voice, int32_t *pitch, float *rms, float rc[]); + +static __inline__ int32_t pow_ii(int32_t x, int32_t n) +{ + int32_t pow; + uint32_t u; + + if (n <= 0) + { + if (n == 0 || x == 1) + return 1; + if (x != -1) + return (x == 0) ? 1/x : 0; + n = -n; + } + u = n; + for (pow = 1; ; ) + { + if ((u & 1)) + pow *= x; + if ((u >>= 1) == 0) + break; + x *= x; + } + return pow; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ float r_sign(float a, float b) +{ + float x; + + x = fabsf(a); + return (b >= 0.0f) ? x : -x; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/lpc10_encode.c b/libs/voipcodecs/src/lpc10_encode.c new file mode 100644 index 0000000000..83a15eb428 --- /dev/null +++ b/libs/voipcodecs/src/lpc10_encode.c @@ -0,0 +1,394 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * lpc10_encode.c - LPC10 low bit rate speech codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This code is based on the U.S. Department of Defense reference + * implementation of the LPC-10 2400 bps Voice Coder. They do not + * exert copyright claims on their code, and it may be freely used. + * + * $Id: lpc10_encode.c,v 1.17 2007/11/26 13:28:59 steveu Exp $ + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif + +#include "voipcodecs/telephony.h" +#include "voipcodecs/dc_restore.h" +#include "voipcodecs/lpc10.h" + +#include "lpc10_encdecs.h" + +static void lpc10_pack(lpc10_encode_state_t *s, uint8_t ibits[], lpc10_frame_t *t) +{ + static const int iblist[53] = + { + 13, 12, 11, 1, 2, 13, 12, 11, 1, 2, + 13, 10, 11, 2, 1, 10, 13, 12, 11, 10, + 2, 13, 12, 11, 10, 2, 1, 12, 7, 6, + 1, 10, 9, 8, 7, 4, 6, 9, 8, 7, + 5, 1, 9, 8, 4, 6, 1, 5, 9, 8, + 7, 5, 6 + }; + int32_t itab[13]; + int x; + int i; + + /* ibits is 54 bits of LPC data ordered as follows: */ + /* R1-0, R2-0, R3-0, P-0, A-0, */ + /* R1-1, R2-1, R3-1, P-1, A-1, */ + /* R1-2, R4-0, R3-2, A-2, P-2, R4-1, */ + /* R1-3, R2-2, R3-3, R4-2, A-3, */ + /* R1-4, R2-3, R3-4, R4-3, A-4, */ + /* P-3, R2-4, R7-0, R8-0, P-4, R4-4, */ + /* R5-0, R6-0, R7-1,R10-0, R8-1, */ + /* R5-1, R6-1, R7-2, R9-0, P-5, */ + /* R5-2, R6-2,R10-1, R8-2, P-6, R9-1, */ + /* R5-3, R6-3, R7-3, R9-2, R8-3, SYNC */ + + itab[0] = t->ipitch; + itab[1] = t->irms; + itab[2] = 0; + for (i = 0; i < LPC10_ORDER; i++) + itab[i + 3] = t->irc[LPC10_ORDER - 1 - i] & 0x7FFF; + /* Put 54 bits into the output buffer */ + x = 0; + for (i = 0; i < 53; i++) + { + x = (x << 1) | (itab[iblist[i] - 1] & 1); + if ((i & 7) == 7) + ibits[i >> 3] = (uint8_t) (x & 0xFF); + itab[iblist[i] - 1] >>= 1; + } + x = (x << 1) | (s->isync & 1); + s->isync ^= 1; + x <<= 2; + ibits[6] = (uint8_t) (x & 0xFF); +} +/*- End of function --------------------------------------------------------*/ + +/* Quantize LPC parameters for transmission */ +static int encode(lpc10_encode_state_t *s, + lpc10_frame_t *t, + int32_t *voice, + int32_t pitch, + float rms, + float *rc) +{ + static const int32_t enctab[16] = + { + 0, 7, 11, 12, 13, 10, 6, 1, 14, 9, 5, 2, 3, 4, 8, 15 + }; + static const int32_t entau[60] = + { + 19, 11, 27, 25, 29, 21, 23, 22, 30, 14, 15, 7, 39, 38, 46, + 42, 43, 41, 45, 37, 53, 49, 51, 50, 54, 52, 60, 56, 58, 26, + 90, 88, 92, 84, 86, 82, 83, 81, 85, 69, 77, 73, 75, 74, 78, + 70, 71, 67, 99, 97, 113, 112, 114, 98, 106, 104, 108, 100, + 101, 76 + }; + static const int32_t enadd[8] = + { + 1920, -768, 2432, 1280, 3584, 1536, 2816, -1152 + }; + static const float enscl[8] = + { + 0.0204f, 0.0167f, 0.0145f, 0.0147f, 0.0143f, 0.0135f, 0.0125f, 0.0112f + }; + static const int32_t enbits[8] = + { + 6, 5, 4, 4, 4, 4, 3, 3 + }; + static const int32_t entab6[64] = + { + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, + 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 13, 14, 15 + }; + static const int32_t rmst[64] = + { + 1024, 936, 856, 784, 718, 656, 600, 550, 502, + 460, 420, 384, 352, 328, 294, 270, 246, 226, + 206, 188, 172, 158, 144, 132, 120, 110, 102, + 92, 84, 78, 70, 64, 60, 54, 50, + 46, 42, 38, 34, 32, 30, 26, 24, + 22, 20, 18, 17, 16, 15, 14, 13, + 12, 11, 10, 9, 8, 7, 6, 5, 4, + 3, 2, 1, 0 + }; + + int32_t idel; + int32_t nbit; + int32_t i; + int32_t j; + int32_t i2; + int32_t i3; + int32_t mrk; + + /* Scale RMS and RC's to int32_ts */ + t->irms = (int32_t) rms; + for (i = 0; i < LPC10_ORDER; i++) + t->irc[i] = (int32_t) (rc[i]*32768.0f); + if (voice[0] != 0 && voice[1] != 0) + { + t->ipitch = entau[pitch - 1]; + } + else + { + if (s->error_correction) + { + t->ipitch = 0; + if (voice[0] != voice[1]) + t->ipitch = 127; + } + else + { + t->ipitch = (voice[0] << 1) + voice[1]; + } + } + /* Encode RMS by binary table search */ + j = 32; + idel = 16; + t->irms = min(t->irms, 1023); + while (idel > 0) + { + if (t->irms > rmst[j - 1]) + j -= idel; + if (t->irms < rmst[j - 1]) + j += idel; + idel /= 2; + } + if (t->irms > rmst[j - 1]) + --j; + t->irms = 31 - j/2; + /* Encode RC(1) and (2) as log-area-ratios */ + for (i = 0; i < 2; i++) + { + i2 = t->irc[i]; + mrk = 0; + if (i2 < 0) + { + i2 = -i2; + mrk = 1; + } + i2 = min(i2/512, 63); + i2 = entab6[i2]; + if (mrk != 0) + i2 = -i2; + t->irc[i] = i2; + } + /* Encode RC(3) - (10) linearly, remove bias then scale */ + for (i = 2; i < LPC10_ORDER; i++) + { + i2 = (int32_t) ((t->irc[i]/2 + enadd[LPC10_ORDER - 1 - i])*enscl[LPC10_ORDER - 1 - i]); + i2 = max(i2, -127); + i2 = min(i2, 127); + nbit = enbits[LPC10_ORDER - 1 - i]; + i3 = (i2 < 0); + i2 /= pow_ii(2, nbit); + if (i3) + i2--; + t->irc[i] = i2; + } + /* Protect the most significant bits of the most + important parameters during non-voiced frames. + RC(1) - RC(4) are protected using 20 parity bits + replacing RC(5) - RC(10). */ + if (s->error_correction) + { + if (t->ipitch == 0 || t->ipitch == 127) + { + t->irc[4] = enctab[(t->irc[0] & 0x1E) >> 1]; + t->irc[5] = enctab[(t->irc[1] & 0x1E) >> 1]; + t->irc[6] = enctab[(t->irc[2] & 0x1E) >> 1]; + t->irc[7] = enctab[(t->irms & 0x1E) >> 1]; + t->irc[8] = enctab[(t->irc[3] & 0x1E) >> 1] >> 1; + t->irc[9] = enctab[(t->irc[3] & 0x1E) >> 1] & 1; + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static void high_pass_100hz(lpc10_encode_state_t *s, float speech[], int start, int len) +{ + float si; + float err; + int i; + + /* 100 Hz high pass filter */ + for (i = start; i < len; i++) + { + si = speech[i]; + err = si + s->z11*1.859076f - s->z21*0.8648249f; + si = err - s->z11*2.0f + s->z21; + s->z21 = s->z11; + s->z11 = err; + err = si + s->z12*1.935715f - s->z22*0.9417004f; + si = err - s->z12*2.0f + s->z22; + s->z22 = s->z12; + s->z12 = err; + speech[i] = si*0.902428f; + } +} +/*- End of function --------------------------------------------------------*/ + +lpc10_encode_state_t *lpc10_encode_init(lpc10_encode_state_t *s, int error_correction) +{ + int i; + int j; + + if (s == NULL) + { + if ((s = (lpc10_encode_state_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + + s->error_correction = error_correction; + + /* State used only by function high_pass_100hz */ + s->z11 = 0.0f; + s->z21 = 0.0f; + s->z12 = 0.0f; + s->z22 = 0.0f; + + /* State used by function lpc10_analyse */ + for (i = 0; i < 540; i++) + { + s->inbuf[i] = 0.0f; + s->pebuf[i] = 0.0f; + } + for (i = 0; i < 696; i++) + s->lpbuf[i] = 0.0f; + for (i = 0; i < 312; i++) + s->ivbuf[i] = 0.0f; + s->bias = 0.0f; + s->osptr = 1; + for (i = 0; i < 3; i++) + s->obound[i] = 0; + s->vwin[2][0] = 307; + s->vwin[2][1] = 462; + s->awin[2][0] = 307; + s->awin[2][1] = 462; + for (i = 0; i < 4; i++) + { + s->voibuf[i][0] = 0; + s->voibuf[i][1] = 0; + } + for (i = 0; i < 3; i++) + s->rmsbuf[i] = 0.0f; + for (i = 0; i < 3; i++) + { + for (j = 0; j < 10; j++) + s->rcbuf[i][j] = 0.0f; + } + s->zpre = 0.0f; + + /* State used by function onset */ + s->n = 0.0f; + s->d__ = 1.0f; + for (i = 0; i < 16; i++) + s->l2buf[i] = 0.0f; + s->l2sum1 = 0.0f; + s->l2ptr1 = 1; + s->l2ptr2 = 9; + s->hyst = FALSE; + + /* State used by function lpc10_voicing */ + s->dither = 20.0f; + s->maxmin = 0.0f; + for (i = 0; i < 3; i++) + { + s->voice[i][0] = 0.0f; + s->voice[i][1] = 0.0f; + } + s->lbve = 3000; + s->fbve = 3000; + s->fbue = 187; + s->ofbue = 187; + s->sfbue = 187; + s->lbue = 93; + s->olbue = 93; + s->slbue = 93; + s->snr = (float) (s->fbve / s->fbue << 6); + + /* State used by function dynamic_pitch_tracking */ + for (i = 0; i < 60; i++) + s->s[i] = 0.0f; + for (i = 0; i < 2; i++) + { + for (j = 0; j < 60; j++) + s->p[i][j] = 0; + } + s->ipoint = 0; + s->alphax = 0.0f; + + /* State used by function lpc10_pack */ + s->isync = 0; + + return s; +} +/*- End of function --------------------------------------------------------*/ + +int lpc10_encode_release(lpc10_encode_state_t *s) +{ + free(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +int lpc10_encode(lpc10_encode_state_t *s, uint8_t code[], const int16_t amp[], int quant) +{ + int32_t voice[2]; + int32_t pitch; + float speech[LPC10_SAMPLES_PER_FRAME]; + float rc[LPC10_ORDER]; + float rms; + lpc10_frame_t frame; + int i; + int j; + + for (i = 0; i < quant; i++) + { + for (j = 0; j < LPC10_SAMPLES_PER_FRAME; j++) + speech[j] = (float) amp[i*LPC10_SAMPLES_PER_FRAME + j]/32768.0f; + high_pass_100hz(s, speech, 0, LPC10_SAMPLES_PER_FRAME); + lpc10_analyse(s, speech, voice, &pitch, &rms, rc); + encode(s, &frame, voice, pitch, rms, rc); + lpc10_pack(s, &code[7*i], &frame); + } + return quant*7; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/lpc10_placev.c b/libs/voipcodecs/src/lpc10_placev.c new file mode 100644 index 0000000000..e1d819ba38 --- /dev/null +++ b/libs/voipcodecs/src/lpc10_placev.c @@ -0,0 +1,335 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * lpc10_placev.c - LPC10 low bit rate speech codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This code is based on the U.S. Department of Defense reference + * implementation of the LPC-10 2400 bps Voice Coder. They do not + * exert copyright claims on their code, and it may be freely used. + * + * $Id: lpc10_placev.c,v 1.12 2007/01/03 14:15:35 steveu Exp $ + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif + +#include "voipcodecs/telephony.h" +#include "voipcodecs/dc_restore.h" +#include "voipcodecs/lpc10.h" + +#include "lpc10_encdecs.h" + +#define subsc(x,y) (((x) << 1) + (y)) + +void lpc10_placea(int32_t *ipitch, + int32_t voibuf[3][2], + int32_t *obound, + int32_t af, + int32_t vwin[3][2], + int32_t awin[3][2], + int32_t ewin[3][2], + int32_t lframe, + int32_t maxwin) +{ + int allv; + int winv; + int32_t i; + int32_t j; + int32_t k; + int32_t l; + int32_t hrange; + int ephase; + int32_t lrange; + + lrange = (af - 2)*lframe + 1; + hrange = af*lframe; + + /* Place the analysis window based on the voicing window placement, + onsets, tentative voicing decision, and pitch. */ + + /* Case 1: Sustained voiced speech + If the five most recent voicing decisions are + voiced, then the window is placed phase-synchronously with the + previous window, as close to the present voicing window if possible. + If onsets bound the voicing window, then preference is given to + a phase-synchronous placement which does not overlap these onsets. */ + + /* Case 2: Voiced transition + If at least one voicing decision in AF is voicied, and there are no + onsets, then the window is placed as in case 1. */ + + /* Case 3: Unvoiced speech or onsets + If both voicing decisions in AF are unvoiced, or there are onsets + then the window is placed coincident with the voicing window. */ + + /* Note: During phase-synchronous placement of windows, the length + is not altered from MAXWIN, since this would defeat the purpose + of phase-synchronous placement. */ + + /* Check for case 1 and case 2 */ + allv = voibuf[af - 2][1] == 1 + && + voibuf[af - 1][0] == 1 + && + voibuf[af - 1][1] == 1 + && + voibuf[af][0] == 1 + && + voibuf[af][1] == 1; + winv = voibuf[af][0] == 1 || voibuf[af][1] == 1; + if (allv || (winv && *obound == 0)) + { + /* APHASE: Phase synchronous window placement. */ + /* Get minimum lower index of the window. */ + i = (lrange + *ipitch - 1 - awin[af - 2][0]) / *ipitch; + i *= *ipitch; + i += awin[af - 2][0]; + /* l = the actual length of this frame's analysis window. */ + l = maxwin; + /* Calculate the location where a perfectly centered window would start. */ + k = (vwin[af - 1][0] + vwin[af - 1][1] + 1 - l)/2; + /* Choose the actual location to be the pitch multiple closest to this */ + awin[af - 1][0] = i + ((int) floorf((float) (k - i)/(float) *ipitch + 0.5f))*(*ipitch); + awin[af - 1][1] = awin[af - 1][0] + l - 1; + /* If there is an onset bounding the right of the voicing window and the + analysis window overlaps that, then move the analysis window backward + to avoid this onset. */ + if (*obound >= 2 && awin[af - 1][1] > vwin[af - 1][1]) + { + awin[af - 1][0] -= *ipitch; + awin[af - 1][1] -= *ipitch; + } + /* Similarly for the left of the voicing window. */ + if ((*obound == 1 || *obound == 3) && awin[af - 1][0] < vwin[af - 1][0]) + { + awin[af - 1][0] += *ipitch; + awin[af - 1][1] += *ipitch; + } + /* If this placement puts the analysis window above HRANGE, then + move it backward an integer number of pitch periods. */ + while (awin[af - 1][1] > hrange) + { + awin[af - 1][0] -= *ipitch; + awin[af - 1][1] -= *ipitch; + } + /* Similarly if the placement puts the analysis window below LRANGE. */ + while (awin[af - 1][0] < lrange) + { + awin[af - 1][0] += *ipitch; + awin[af - 1][1] += *ipitch; + } + /* Make energy window be phase-synchronous. */ + ephase = TRUE; + } + else + { + /* Case 3 */ + awin[af - 1][0] = vwin[af - 1][0]; + awin[af - 1][1] = vwin[af - 1][1]; + ephase = FALSE; + } + /* RMS is computed over an integer number of pitch periods in the analysis + window. When it is not placed phase-synchronously, it is placed as close + as possible to onsets. */ + j = (awin[af - 1][1] - awin[af - 1][0] + 1) / *ipitch * *ipitch; + if (j == 0 || !winv) + { + ewin[af - 1][0] = vwin[af - 1][0]; + ewin[af - 1][1] = vwin[af - 1][1]; + } + else if (!ephase && *obound == 2) + { + ewin[af - 1][0] = awin[af - 1][1] - j + 1; + ewin[af - 1][1] = awin[af - 1][1]; + } + else + { + ewin[af - 1][0] = awin[af - 1][0]; + ewin[af - 1][1] = awin[af - 1][0] + j - 1; + } +} +/*- End of function --------------------------------------------------------*/ + +void lpc10_placev(int32_t *osbuf, + int32_t *osptr, + int32_t oslen, + int32_t *obound, + int32_t vwin[3][2], + int32_t af, + int32_t lframe, + int32_t minwin, + int32_t maxwin, + int32_t dvwinl, + int32_t dvwinh) +{ + int32_t i1; + int32_t i2; + int crit; + int32_t q; + int32_t osptr1; + int32_t hrange; + int32_t lrange; + int i; + + /* Voicing window placement */ + + /* __________________ __________________ ______________ */ + /* | | | */ + /* | 1F | 2F | 3F ... */ + /* |__________________|__________________|______________ */ + + /* Previous | */ + /* Window | */ + /* ...________| */ + + /* | | */ + /* ------>| This window's placement range |<------ */ + /* | | */ + + /* There are three cases. Note these are different from those + given in the LPC-10e phase 1 report. */ + + /* 1. If there are no onsets in this range, then the voicing window + is centered in the pitch window. If such a placement is not within + the window's placement range, then the window is placed in the left-most + portion of the placement range. Its length is always MAXWIN. */ + + /* 2. If the first onset is in 2F and there is sufficient room to place + the window immediately before this onset, then the window is placed + there, and its length is set to the maximum possible under these + constraints. */ + + /* "Critical Region Exception": If there is another onset in 2F + such that a window can be placed between the two onsets, the + window is placed there (ie, as in case 3). */ + + /* 3. Otherwise, the window is placed immediately after the onset. The + window's length is the longest length that can fit in the range under these + constraints, except that the window may be shortened even further to avoid + overlapping other onsets in the placement range. In any case, the window's + length is at least MINWIN. */ + + /* Note that the values of MINWIN and LFRAME must be chosen such + that case 2 = false implies case 3 = true. This means that + MINWIN <= LFRAME/2. If this were not the case, then a fourth case + would have to be added for when the window cannot fit either before + or after the onset. */ + + /* Note also that onsets which weren't in 2F last time may be in 1F this + time, due to the filter delays in computing onsets. The result is that + occasionally a voicing window will overlap that onset. The only way + to circumvent this problem is to add more delay in processing input + speech. In the trade-off between delay and window-placement, window + placement lost. */ + + /* Compute the placement range */ + + /* Computing MAX */ + i1 = vwin[af - 2][1] + 1; + i2 = (af - 2)*lframe + 1; + lrange = max(i1, i2); + hrange = af*lframe; + /* Compute OSPTR1, so the following code only looks at relevant onsets. */ + for (osptr1 = *osptr - 1; osptr1 >= 1; osptr1--) + { + if (osbuf[osptr1 - 1] <= hrange) + break; + } + osptr1++; + /* Check for case 1 first (fast case) */ + if (osptr1 <= 1 || osbuf[osptr1 - 2] < lrange) + { + /* Compute max */ + i1 = vwin[af - 2][1] + 1; + vwin[af - 1][0] = max(i1, dvwinl); + vwin[af - 1][1] = vwin[af - 1][0] + maxwin - 1; + *obound = 0; + } + else + { + /* Search backward in OSBUF for first onset in range. */ + /* This code relies on the above check being performed first. */ + for (q = osptr1 - 1; q >= 1; q--) + { + if (osbuf[q - 1] < lrange) + break; + } + q++; + /* Check for case 2 (placement before onset): */ + /* Check for critical region exception: */ + crit = FALSE; + for (i = q + 1; i < osptr1; i++) + { + if (osbuf[i - 1] - osbuf[q - 1] >= minwin) + { + crit = TRUE; + break; + } + } + /* Compute max */ + i1 = (af - 1)*lframe; + i2 = lrange + minwin - 1; + if (!crit && osbuf[q - 1] > max(i1, i2)) + { + vwin[af - 1][1] = osbuf[q - 1] - 1; + /* Compute max */ + i2 = vwin[af - 1][1] - maxwin + 1; + vwin[af - 1][0] = max(lrange, i2); + *obound = 2; + } + else + { + /* Case 3 (placement after onset) */ + vwin[af - 1][0] = osbuf[q - 1]; + do + { + if (++q >= osptr1 + || + osbuf[q - 1] > vwin[af - 1][0] + maxwin) + { + /* Compute min */ + i1 = vwin[af - 1][0] + maxwin - 1; + vwin[af - 1][1] = min(i1, hrange); + *obound = 1; + return; + } + } + while (osbuf[q - 1] < vwin[af - 1][0] + minwin); + vwin[af - 1][1] = osbuf[q - 1] - 1; + *obound = 3; + } + } +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/lpc10_voicing.c b/libs/voipcodecs/src/lpc10_voicing.c new file mode 100644 index 0000000000..cd297c0cb1 --- /dev/null +++ b/libs/voipcodecs/src/lpc10_voicing.c @@ -0,0 +1,487 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * lpc10_voicing.c - LPC10 low bit rate speech codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This code is based on the U.S. Department of Defense reference + * implementation of the LPC-10 2400 bps Voice Coder. They do not + * exert copyright claims on their code, and it may be freely used. + * + * $Id: lpc10_voicing.c,v 1.7 2006/11/30 15:41:47 steveu Exp $ + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif + +#include "voipcodecs/telephony.h" +#include "voipcodecs/dc_restore.h" +#include "voipcodecs/lpc10.h" + +#include "lpc10_encdecs.h" + +static void vparms(int32_t vwin[], + float *inbuf, + float *lpbuf, + const int32_t buflim[], + int32_t half, + float *dither, + int32_t *mintau, + int32_t *zc, + int32_t *lbe, + int32_t *fbe, + float *qs, + float *rc1, + float *ar_b, + float *ar_f) +{ + int32_t inbuf_offset; + int32_t lpbuf_offset; + int32_t vlen; + int32_t stop; + int32_t i; + int32_t start; + float r1; + float r2; + float e_pre; + float ap_rms; + float e_0; + float oldsgn; + float lp_rms; + float e_b; + float e_f; + float r_b; + float r_f; + float e0ap; + + /* Calculate zero crossings (ZC) and several energy and correlation */ + /* measures on low band and full band speech. Each measure is taken */ + /* over either the first or the second half of the voicing window, */ + /* depending on the variable HALF. */ + lpbuf_offset = buflim[2]; + lpbuf -= lpbuf_offset; + inbuf_offset = buflim[0]; + inbuf -= inbuf_offset; + + lp_rms = 0.0f; + ap_rms = 0.0f; + e_pre = 0.0f; + e0ap = 0.0f; + *rc1 = 0.0f; + e_0 = 0.0f; + e_b = 0.0f; + e_f = 0.0f; + r_f = 0.0f; + r_b = 0.0f; + *zc = 0; + vlen = vwin[1] - vwin[0] + 1; + start = vwin[0] + half*vlen/2 + 1; + stop = start + vlen/2 - 1; + + /* I'll use the symbol HVL in the table below to represent the value */ + /* VLEN/2. Note that if VLEN is odd, then HVL should be rounded down, */ + /* i.e., HVL = (VLEN-1)/2. */ + + /* HALF START STOP */ + + /* 1 VWIN(1)+1 VWIN(1)+HVL */ + /* 2 VWIN(1)+HVL+1 VWIN(1)+2*HVL */ + oldsgn = r_sign(1.0f, inbuf[start - 1] - *dither); + for (i = start; i <= stop; i++) + { + lp_rms += fabsf(lpbuf[i]); + ap_rms += fabsf(inbuf[i]); + e_pre += fabsf(inbuf[i] - inbuf[i - 1]); + r1 = inbuf[i]; + e0ap += r1*r1; + *rc1 += inbuf[i]*inbuf[i - 1]; + r1 = lpbuf[i]; + e_0 += r1*r1; + r1 = lpbuf[i - *mintau]; + e_b += r1*r1; + r1 = lpbuf[i + *mintau]; + e_f += r1*r1; + r_f += lpbuf[i]*lpbuf[i + *mintau]; + r_b += lpbuf[i]*lpbuf[i - *mintau]; + r1 = inbuf[i] + *dither; + if (r_sign(1.0f, r1) != oldsgn) + { + ++(*zc); + oldsgn = -oldsgn; + } + *dither = -(*dither); + } + /* Normalized short-term autocovariance coefficient at unit sample delay */ + *rc1 /= max(e0ap, 1.0f); + /* Ratio of the energy of the first difference signal (6 dB/oct preemphasis)*/ + /* to the energy of the full band signal */ + /* Computing MAX */ + r1 = ap_rms*2.0f; + *qs = e_pre/max(r1, 1.0f); + /* aR_b is the product of the forward and reverse prediction gains, */ + /* looking backward in time (the causal case). */ + *ar_b = r_b/max(e_b, 1.0f)*(r_b/max(e_0, 1.0f)); + /* aR_f is the same as aR_b, but looking forward in time (non causal case).*/ + *ar_f = r_f/max(e_f, 1.0f)*(r_f/max(e_0, 1.0f)); + /* Normalize ZC, LBE, and FBE to old fixed window length of 180. */ + /* (The fraction 90/VLEN has a range of 0.58 to 1) */ + r2 = (float) (*zc << 1); + *zc = lrintf(r2*(90.0f/vlen)); + r1 = lp_rms/4*(90.0f/vlen); + *lbe = min(lrintf(r1), 32767); + r1 = ap_rms/4*(90.0f/vlen); + *fbe = min(lrintf(r1), 32767); +} +/*- End of function --------------------------------------------------------*/ + +/* Voicing detection makes voicing decisions for each half */ +/* frame of input speech. Tentative voicing decisions are made two frames*/ +/* in the future (2F) for each half frame. These decisions are carried */ +/* through one frame in the future (1F) to the present (P) frame where */ +/* they are examined and smoothed, resulting in the final voicing */ +/* decisions for each half frame. */ + +/* The voicing parameter (signal measurement) column vector (VALUE) */ +/* is based on a rectangular window of speech samples determined by the */ +/* window placement algorithm. The voicing parameter vector contains the*/ +/* AMDF windowed maximum-to-minimum ratio, the zero crossing rate, energy*/ +/* measures, reflection coefficients, and prediction gains. The voicing */ +/* window is placed to avoid contamination of the voicing parameter vector*/ +/* with speech onsets. */ + +/* The input signal is then classified as unvoiced (including */ +/* silence) or voiced. This decision is made by a linear discriminant */ +/* function consisting of a dot product of the voicing decision */ +/* coefficient (VDC) row vector with the measurement column vector */ +/* (VALUE). The VDC vector is 2-dimensional, each row vector is optimized*/ +/* for a particular signal-to-noise ratio (SNR). So, before the dot */ +/* product is performed, the SNR is estimated to select the appropriate */ +/* VDC vector. */ + +/* The smoothing algorithm is a modified median smoother. The */ +/* voicing discriminant function is used by the smoother to determine how*/ +/* strongly voiced or unvoiced a signal is. The smoothing is further */ +/* modified if a speech onset and a voicing decision transition occur */ +/* within one half frame. In this case, the voicing decision transition */ +/* is extended to the speech onset. For transmission purposes, there are*/ +/* constraints on the duration and transition of voicing decisions. The */ +/* smoother takes these constraints into account. */ + +/* Finally, the energy estimates are updated along with the dither */ +/* threshold used to calculate the zero crossing rate (ZC). */ + +void lpc10_voicing(lpc10_encode_state_t *s, + int32_t vwin[], + float *inbuf, + float *lpbuf, + const int32_t buflim[], + int32_t half, + float *minamd, + float *maxamd, + int32_t *mintau, + float ivrc[], + int32_t obound[]) +{ + static const float vdc[100] = + { + 0.0f, 1714.0f, -110.0f, 334.0f, -4096.0f, -654.0f, 3752.0f, 3769.0f, 0.0f, 1181.0f, + 0.0f, 874.0f, -97.0f, 300.0f, -4096.0f, -1021.0f, 2451.0f, 2527.0f, 0.0f, -500.0f, + 0.0f, 510.0f, -70.0f, 250.0f, -4096.0f, -1270.0f, 2194.0f, 2491.0f, 0.0f, -1500.0f, + 0.0f, 500.0f, -10.0f, 200.0f, -4096.0f, -1300.0f, 2.0e3f, 2.0e3f, 0.0f, -2.0e3f, + 0.0f, 500.0f, 0.0f, 0.0f, -4096.0f, -1300.0f, 2.0e3f, 2.0e3f, 0.0f, -2500.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f + }; + static const int nvdcl = 5; + static const float vdcl[10] = + { + 600.0f, 450.0f, 300.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f + }; + + int32_t inbuf_offset; + int32_t lpbuf_offset; + int32_t i1; + float r1; + float r2; + float ar_b; + float ar_f; + int32_t snrl; + int32_t i; + float value[9]; + int32_t zc; + int ot; + float qs; + int32_t vstate; + float rc1; + int32_t fbe; + int32_t lbe; + float snr2; + + inbuf_offset = 0; + lpbuf_offset = 0; + if (inbuf) + { + inbuf_offset = buflim[0]; + inbuf -= inbuf_offset; + } + if (lpbuf) + { + lpbuf_offset = buflim[2]; + lpbuf -= lpbuf_offset; + } + + /* Voicing Decision Parameter vector (* denotes zero coefficient): */ + + /* * MAXMIN */ + /* LBE/LBVE */ + /* ZC */ + /* RC1 */ + /* QS */ + /* IVRC2 */ + /* aR_B */ + /* aR_F */ + /* * LOG(LBE/LBVE) */ + /* Define 2-D voicing decision coefficient vector according to the voicing */ + /* parameter order above. Each row (VDC vector) is optimized for a specific */ + /* SNR. The last element of the vector is the constant. */ + /* E ZC RC1 Qs IVRC2 aRb aRf c */ + + /* The VOICE array contains the result of the linear discriminant function*/ + /* (analog values). The VOIBUF array contains the hard-limited binary */ + /* voicing decisions. The VOICE and VOIBUF arrays, according to FORTRAN */ + /* memory allocation, are addressed as: */ + + /* (half-frame number, future-frame number) */ + + /* | Past | Present | Future1 | Future2 | */ + /* | 1,0 | 2,0 | 1,1 | 2,1 | 1,2 | 2,2 | 1,3 | 2,3 | ---> time */ + + /* Update linear discriminant function history each frame: */ + if (half == 0) + { + s->voice[0][0] = s->voice[1][0]; + s->voice[0][1] = s->voice[1][1]; + s->voice[1][0] = s->voice[2][0]; + s->voice[1][1] = s->voice[2][1]; + s->maxmin = *maxamd / max(*minamd, 1.0f); + } + /* Calculate voicing parameters twice per frame */ + vparms(vwin, + &inbuf[inbuf_offset], + &lpbuf[lpbuf_offset], + buflim, + half, + &s->dither, + mintau, + &zc, + &lbe, + &fbe, + &qs, + &rc1, + &ar_b, + &ar_f); + /* Estimate signal-to-noise ratio to select the appropriate VDC vector. */ + /* The SNR is estimated as the running average of the ratio of the */ + /* running average full-band voiced energy to the running average */ + /* full-band unvoiced energy. SNR filter has gain of 63. */ + r1 = (s->snr + s->fbve/(float) max(s->fbue, 1))*63/64.0f; + s->snr = (float) lrintf(r1); + snr2 = s->snr*s->fbue/max(s->lbue, 1); + /* Quantize SNR to SNRL according to VDCL thresholds. */ + i1 = nvdcl - 1; + for (snrl = 0; snrl < i1; snrl++) + { + if (snr2 > vdcl[snrl]) + break; + } + /* (Note: SNRL = NVDCL here) */ + /* Linear discriminant voicing parameters: */ + value[0] = s->maxmin; + value[1] = (float) lbe/max(s->lbve, 1); + value[2] = (float) zc; + value[3] = rc1; + value[4] = qs; + value[5] = ivrc[1]; + value[6] = ar_b; + value[7] = ar_f; + /* Evaluation of linear discriminant function: */ + s->voice[2][half] = vdc[snrl*10 + 9]; + for (i = 0; i < 8; i++) + s->voice[2][half] += vdc[snrl*10 + i]*value[i]; + /* Classify as voiced if discriminant > 0, otherwise unvoiced */ + /* Voicing decision for current half-frame: 1 = Voiced; 0 = Unvoiced */ + s->voibuf[3][half] = (s->voice[2][half] > 0.0f) ? 1 : 0; + /* Skip voicing decision smoothing in first half-frame: */ + /* Give a value to VSTATE, so that trace statements below will print */ + /* a consistent value from one call to the next when HALF .EQ. 1. */ + /* The value of VSTATE is not used for any other purpose when this is */ + /* true. */ + vstate = -1; + if (half != 0) + { + /* Voicing decision smoothing rules (override of linear combination): */ + + /* Unvoiced half-frames: At least two in a row. */ + /* -------------------- */ + + /* Voiced half-frames: At least two in a row in one frame. */ + /* ------------------- Otherwise at least three in a row. */ + /* (Due to the way transition frames are encoded) */ + + /* In many cases, the discriminant function determines how to smooth. */ + /* In the following chart, the decisions marked with a * may be overridden. */ + + /* Voicing override of transitions at onsets: */ + /* If a V/UV or UV/V voicing decision transition occurs within one-half */ + /* frame of an onset bounding a voicing window, then the transition is */ + /* moved to occur at the onset. */ + + /* P 1F */ + /* ----- ----- */ + /* 0 0 0 0 */ + /* 0 0 0* 1 (If there is an onset there) */ + /* 0 0 1* 0* (Based on 2F and discriminant distance) */ + /* 0 0 1 1 */ + /* 0 1* 0 0 (Always) */ + /* 0 1* 0* 1 (Based on discriminant distance) */ + /* 0* 1 1 0* (Based on past, 2F, and discriminant distance) */ + /* 0 1* 1 1 (If there is an onset there) */ + /* 1 0* 0 0 (If there is an onset there) */ + /* 1 0 0 1 */ + /* 1 0* 1* 0 (Based on discriminant distance) */ + /* 1 0* 1 1 (Always) */ + /* 1 1 0 0 */ + /* 1 1 0* 1* (Based on 2F and discriminant distance) */ + /* 1 1 1* 0 (If there is an onset there) */ + /* 1 1 1 1 */ + + /* Determine if there is an onset transition between P and 1F. */ + /* OT (Onset Transition) is true if there is an onset between */ + /* P and 1F but not after 1F. */ + ot = ((obound[0] & 2) != 0 || obound[1] == 1) && (obound[2] & 1) == 0; + /* Multi-way dispatch on voicing decision history: */ + vstate = (s->voibuf[1][0] << 3) + (s->voibuf[1][1] << 2) + (s->voibuf[2][0] << 1) + s->voibuf[2][1]; + switch (vstate + 1) + { + case 2: + if (ot && s->voibuf[3][0] == 1) + s->voibuf[2][0] = 1; + break; + case 3: + if (s->voibuf[3][0] == 0 || s->voice[1][0] < -s->voice[1][1]) + s->voibuf[2][0] = 0; + else + s->voibuf[2][1] = 1; + break; + case 5: + s->voibuf[1][1] = 0; + break; + case 6: + if (s->voice[0][1] < -s->voice[1][0]) + s->voibuf[1][1] = 0; + else + s->voibuf[2][0] = 1; + break; + case 7: + if (s->voibuf[0][0] == 1 || s->voibuf[3][0] == 1 || s->voice[1][1] > s->voice[0][0]) + s->voibuf[2][1] = 1; + else + s->voibuf[1][0] = 1; + break; + case 8: + if (ot) + s->voibuf[1][1] = 0; + break; + case 9: + if (ot) + s->voibuf[1][1] = 1; + break; + case 11: + if (s->voice[1][9] < -s->voice[0][1]) + s->voibuf[2][0] = 0; + else + s->voibuf[1][1] = 1; + break; + case 12: + s->voibuf[1][1] = 1; + break; + case 14: + if (s->voibuf[3][0] == 0 && s->voice[1][1] < -s->voice[1][0]) + s->voibuf[2][1] = 0; + else + s->voibuf[2][0] = 1; + break; + case 15: + if (ot && s->voibuf[3][0] == 0) + s->voibuf[2][0] = 0; + break; + } + } + /* During unvoiced half-frames, update the low band and full band unvoiced*/ + /* energy estimates (LBUE and FBUE) and also the zero crossing */ + /* threshold (DITHER). (The input to the unvoiced energy filters is */ + /* restricted to be less than 10dB above the previous inputs of the */ + /* filters.) */ + /* During voiced half-frames, update the low-pass (LBVE) and all-pass */ + /* (FBVE) voiced energy estimates. */ + if (s->voibuf[3][half] == 0) + { + r1 = (s->sfbue*63 + (min(fbe, s->ofbue*3) << 3))/64.0f; + s->sfbue = lrintf(r1); + s->fbue = s->sfbue/8; + s->ofbue = fbe; + r1 = (s->slbue*63 + (min(lbe, s->olbue*3) << 3))/64.0f; + s->slbue = lrintf(r1); + s->lbue = s->slbue/8; + s->olbue = lbe; + } + else + { + s->lbve = lrintf((s->lbve*63 + lbe)/64.0f); + s->fbve = lrintf((s->fbve*63 + fbe)/64.0f); + } + /* Set dither threshold to yield proper zero crossing rates in the */ + /* presence of low frequency noise and low level signal input. */ + /* NOTE: The divisor is a function of REF, the expected energies. */ + /* Computing MIN */ + /* Computing MAX */ + r2 = sqrtf((float) (s->lbue*s->lbve))*64/3000; + r1 = max(r2, 1.0f); + s->dither = min(r1, 20.0f); + /* Voicing decisions are returned in VOIBUF. */ +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/msvc/gettimeofday.c b/libs/voipcodecs/src/msvc/gettimeofday.c new file mode 100644 index 0000000000..c59f19e0b8 --- /dev/null +++ b/libs/voipcodecs/src/msvc/gettimeofday.c @@ -0,0 +1,14 @@ +#ifdef _MSC_VER +#pragma warning(disable:4100) +#endif + +#include "windows.h" + +void gettimeofday(struct timeval *tv, void *tz) +{ + long int l = GetTickCount(); + + tv->tv_sec = l / 1000; + tv->tv_usec = (l % 1000) * 1000; + return; +} diff --git a/libs/voipcodecs/src/msvc/inttypes.h b/libs/voipcodecs/src/msvc/inttypes.h new file mode 100644 index 0000000000..5980bec935 --- /dev/null +++ b/libs/voipcodecs/src/msvc/inttypes.h @@ -0,0 +1,87 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * inttypes.h - a fudge for MSVC, which lacks this header + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Michael Jerris + * + * + * This file is released in the public domain. + * + */ + +#if !defined(_INTTYPES_H_) +#define _INTTYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +#if (_MSC_VER >= 1400) // VC8+ +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE +#endif +#ifndef _CRT_NONSTDC_NO_DEPRECATE +#define _CRT_NONSTDC_NO_DEPRECATE +#endif +#endif // VC8+ +#include +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; +#define inline __inline +#define __inline__ __inline +#define INT16_MAX 0x7fff +#define INT16_MIN (-INT16_MAX - 1) +#define _MMX_H_ + +/* disable the following warnings + * C4100: The formal parameter is not referenced in the body of the function. The unreferenced parameter is ignored. + * C4200: Non standard extension C zero sized array + * C4706: assignment within conditional expression + * C4244: conversion from 'type1' to 'type2', possible loss of data + * C4295: array is too small to include a terminating null character + * C4125: decimal digit terminates octal escape sequence + */ +#pragma warning(disable:4100 4200 4706 4295 4125) + +#pragma comment(lib, "ws2_32.lib") + +#define strncasecmp _strnicmp +#define strcasecmp _stricmp +#define snprintf _snprintf + +#if !defined(INFINITY) +#define INFINITY 0x7fffffff +#endif +#endif + +#define PACKAGE "voipcodecs" +#define VERSION "0.0.1andabit" + +#define INT32_MAX (2147483647) +#define INT32_MIN (-2147483647 - 1) + +#define PRId8 "d" +#define PRId16 "d" +#define PRId32 "ld" +#define PRId64 "lld" + +#define PRIu8 "u" +#define PRIu16 "u" +#define PRIu32 "lu" +#define PRIu64 "llu" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/voipcodecs/src/msvc/msvcproj.foot b/libs/voipcodecs/src/msvc/msvcproj.foot new file mode 100644 index 0000000000..e8b521ca54 --- /dev/null +++ b/libs/voipcodecs/src/msvc/msvcproj.foot @@ -0,0 +1,7 @@ + +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/libs/voipcodecs/src/msvc/msvcproj.head b/libs/voipcodecs/src/msvc/msvcproj.head new file mode 100644 index 0000000000..cabf08b497 --- /dev/null +++ b/libs/voipcodecs/src/msvc/msvcproj.head @@ -0,0 +1,92 @@ +# Microsoft Developer Studio Project File - Name="voipcodecs" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=voipcodecs - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "voipcodecs.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "voipcodecs.mak" CFG="voipcodecs - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "voipcodecs - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "voipcodecs - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "voipcodecs - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /Zi /O2 /I "." /I "..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /D "_WINDLL" /FR /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib ws2_32.lib winmm.lib /nologo /dll /map /debug /machine:I386 /out:"Release/libvoipcodecs.dll" + +!ELSEIF "$(CFG)" == "voipcodecs - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "." /I "..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /FR /FD /GZ /c +# SUBTRACT CPP /WX /YX +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib ws2_32.lib winmm.lib /nologo /dll /incremental:no /map /debug /machine:I386 /out:"Debug/libvoipcodecs.dll" /pdbtype:sept +# SUBTRACT LINK32 /nodefaultlib + +!ENDIF + +# Begin Target + +# Name "voipcodecs - Win32 Release" +# Name "voipcodecs - Win32 Debug" diff --git a/libs/voipcodecs/src/msvc/sys/time.h b/libs/voipcodecs/src/msvc/sys/time.h new file mode 100644 index 0000000000..bd3bcb2c7b --- /dev/null +++ b/libs/voipcodecs/src/msvc/sys/time.h @@ -0,0 +1 @@ +extern void gettimeofday(struct timeval *tv, void *tz); diff --git a/libs/voipcodecs/src/msvc/tgmath.h b/libs/voipcodecs/src/msvc/tgmath.h new file mode 100644 index 0000000000..a19c88153e --- /dev/null +++ b/libs/voipcodecs/src/msvc/tgmath.h @@ -0,0 +1,84 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * tgmath.h - a fudge for MSVC, which lacks this header + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Michael Jerris + * + * + * This file is released in the public domain. + * + */ + +#if !defined(_TGMATH_H_) +#define _TGMATH_H_ + +#include + +#if !defined(M_PI) +/* C99 systems may not define M_PI */ +#define M_PI 3.14159265358979323846264338327 +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +/* A kindofa rint() for VC++ (only kindofa, because rint should be type generic, + and this one is purely float to int */ +static inline long int lrintf(float a) +{ + long int i; + + __asm + { + fld a + fistp i + } + return i; +} + +static inline long int lrint(double a) +{ + long int i; + + __asm + { + fld a + fistp i + } + return i; +} + +static inline int rintf(float a) +{ + int i; + + __asm + { + fld a + fistp i + } + return i; +} + +static inline int rint(double a) +{ + int i; + + __asm + { + fld a + fistp i + } + return i; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/voipcodecs/src/msvc/unistd.h b/libs/voipcodecs/src/msvc/unistd.h new file mode 100644 index 0000000000..fc8cd06d7b --- /dev/null +++ b/libs/voipcodecs/src/msvc/unistd.h @@ -0,0 +1,31 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * inttypes.h - a fudge for MSVC, which lacks this header + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Michael Jerris + * + * + * This file is released in the public domain. + * + */ + +#if !defined(_INTTYPES_H_) +#define _INTTYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define open _open +#define write _write + +extern int gethostname (char *name, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/voipcodecs/src/msvc/vc8proj.foot b/libs/voipcodecs/src/msvc/vc8proj.foot new file mode 100644 index 0000000000..2b57fb4e9f --- /dev/null +++ b/libs/voipcodecs/src/msvc/vc8proj.foot @@ -0,0 +1,11 @@ + + + + + + + diff --git a/libs/voipcodecs/src/msvc/vc8proj.head b/libs/voipcodecs/src/msvc/vc8proj.head new file mode 100644 index 0000000000..1c12275b7f --- /dev/null +++ b/libs/voipcodecs/src/msvc/vc8proj.head @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/voipcodecs/src/msvc/voipcodecs.def b/libs/voipcodecs/src/msvc/voipcodecs.def new file mode 100644 index 0000000000..cb5076c2fa --- /dev/null +++ b/libs/voipcodecs/src/msvc/voipcodecs.def @@ -0,0 +1,304 @@ +EXPORTS +adsi_rx_init +adsi_rx +adsi_tx_init +adsi_send_alert_tone +adsi_put_message +adsi_next_field +adsi_add_field +async_tx_init +async_rx_init +awgn +bert_init +bert_get_bit +bert_put_bit +bert_set_report +bert_result +filter_create +filter_delete +filter_step +cfilter_create +cfilter_delete +cfilter_step +dds_phase_rate +dds_frequency +dds_scaling_dbm0 +dds_scaling_dbov +dds_lookup +dds_offset +dds +dds_mod +dds_complex +dds_complex_mod +dds_phase_ratef +dds_frequencyf +dds_scaling_dbm0f +dds_scaling_dbovf +ddsf +dds_modf +dds_complexf +dds_complex_modf +echo_can_create +echo_can_free +echo_can_flush +echo_can_adaption_mode +echo_can_update +fax_rx +fax_tx +fax_set_flush_handler +fax_init +fax_release +fsk_tx_init +fsk_tx_power +fsk_tx_set_get_bit +fsk_tx +fsk_rx_signal_power +fsk_rx_signal_cutoff +fsk_rx_init +fsk_rx +fsk_rx_set_put_bit +g722_encode_init +g722_encode_release +g722_encode +g722_decode_init +g722_decode_release +g722_decode +g726_init +g726_release +crc_itu32_calc +crc_itu32_append +crc_itu32_check +crc_itu16_calc +crc_itu16_append +crc_itu16_check +hdlc_rx_init +hdlc_rx_get_stats +hdlc_tx_init +hdlc_tx_frame +hdlc_tx_preamble +ima_adpcm_init +ima_adpcm_release +span_log_test +span_log +span_log_buf +span_log_init +span_log_set_protocol +span_set_message_handler +span_set_error_handler +modem_echo_can_create +modem_echo_can_free +modem_echo_can_flush +modem_echo_can_adaption_mode +modem_echo_can_update +noise +oki_adpcm_init +oki_adpcm_release +playout_put +playout_get +playout_get_unconditional +playout_current_length +playout_next_due +playout_new +playout_free +playout_restart +plc_rx +plc_fillin +plc_init +plc_release +power_meter_init +power_meter_damping +power_meter_update +power_meter_dbm0 +power_meter_dbov +power_meter_level_dbm0 +power_meter_level_dbov +queue_empty +queue_free_space +queue_contents +queue_flush +queue_view +queue_read +queue_write +queue_test_msg +queue_read_msg +queue_write_msg +queue_create +queue_delete +sig_tone_init +sig_tone_rx +sig_tone_tx +super_tone_rx_make_descriptor +super_tone_rx_add_tone +super_tone_rx_add_element +super_tone_rx_init +super_tone_rx_free +super_tone_rx_segment_callback +super_tone_rx +super_tone_tx_make_step +super_tone_tx_free +super_tone_tx_init +super_tone_tx +t30_init +t30_release +t30_restart +t30_create +t30_free +t30_frametype +t30_decode_dis_dtc_dcs +t30_completion_code_to_str +t30_set_header_info +t30_set_local_ident +t30_get_sub_address +t30_get_header_info +t30_get_local_ident +t30_get_far_ident +t30_get_transfer_statistics +t30_set_phase_b_handler +t30_set_phase_d_handler +t30_set_phase_e_handler +t30_set_document_handler +t30_set_rx_file +t30_set_tx_file +t30_local_interrupt_request +t30_send_complete +t30_hdlc_accept +t30_timer_update +t31_call_event +t31_at_rx +t31_rx +t31_tx +t31_init +t31_release +t35_decode +t38_indicator +t38_data_type +t38_field_type +t38_terminal_init +t38_gateway_init +t4_rx_create +t4_rx_init +t4_rx_start_page +t4_rx_end_page +t4_rx_delete +t4_rx_end +t4_rx_set_rx_encoding +t4_rx_set_sub_address +t4_rx_set_far_ident +t4_rx_set_vendor +t4_rx_set_model +t4_tx_create +t4_tx_init +t4_tx_start_page +t4_tx_restart_page +t4_tx_end_page +t4_tx_delete +t4_tx_end +t4_tx_set_tx_encoding +t4_tx_set_min_row_bits +t4_tx_set_local_ident +t4_tx_set_header_info +t4_get_transfer_statistics +t4_encoding_to_str +time_scale_init +time_scale_rate +time_scale +make_goertzel_descriptor +goertzel_init +goertzel_update +goertzel_result +dtmf_rx_init +dtmf_rx_set_realtime_callback +dtmf_rx_parms +dtmf_rx +make_tone_descriptor +make_tone_gen_descriptor +tone_gen_init +tone_gen +dtmf_tx_init +dtmf_tx +v17_rx_init +v17_rx_restart +v17_rx_release +v17_rx_set_put_bit +v17_rx +v17_rx_equalizer_state +v17_rx_carrier_frequency +v17_rx_symbol_timing_correction +v17_rx_signal_power +v17_rx_signal_cutoff +v17_rx_set_qam_report_handler +v17_tx_power +v17_tx_init +v17_tx_restart +v17_tx_release +v17_tx_set_get_bit +v17_tx +v22bis_rx_restart +v22bis_rx +v22bis_rx_equalizer_state +v22bis_rx_carrier_frequency +v22bis_rx_symbol_timing_correction +v22bis_rx_signal_power +v22bis_rx_set_qam_report_handler +v22bis_tx +v22bis_tx_power +v22bis_restart +v22bis_init +v22bis_set_get_bit +v22bis_set_put_bit +v27ter_rx_init +v27ter_rx_restart +v27ter_rx_release +v27ter_rx_set_put_bit +v27ter_rx +v27ter_rx_equalizer_state +v27ter_rx_carrier_frequency +v27ter_rx_symbol_timing_correction +v27ter_rx_signal_power +v27ter_rx_signal_cutoff +v27ter_rx_set_qam_report_handler +v27ter_tx_power +v27ter_tx_init +v27ter_tx_restart +v27ter_tx_release +v27ter_tx_set_get_bit +v27ter_tx +v29_rx_init +v29_rx_restart +v29_rx_release +v29_rx_set_put_bit +v29_rx +v29_rx_equalizer_state +v29_rx_carrier_frequency +v29_rx_symbol_timing_correction +v29_rx_signal_power +v29_rx_signal_cutoff +v29_rx_set_qam_report_handler +v29_tx_power +v29_tx_init +v29_tx_restart +v29_tx_release +v29_tx_set_get_bit +v29_tx +lapm_dump +lapm_receive +lapm_tx +lapm_tx_iframe +v42_set_status_callback +v42_rx_bit +v42_tx_bit +v42_init +v42_restart +v42_release +v42bis_compress +v42bis_compress_flush +v42bis_decompress +v42bis_decompress_flush +v42bis_init +v42bis_release +v8_init +v8_release +v8_tx +v8_rx +v8_log_supported_modulations + diff --git a/libs/voipcodecs/src/oki_adpcm.c b/libs/voipcodecs/src/oki_adpcm.c new file mode 100644 index 0000000000..1073048795 --- /dev/null +++ b/libs/voipcodecs/src/oki_adpcm.c @@ -0,0 +1,376 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * oki_adpcm.c - Conversion routines between linear 16 bit PCM data and + * OKI (Dialogic) ADPCM format. Supports with the 32kbps + * and 24kbps variants used by Dialogic. + * + * Written by Steve Underwood + * + * Copyright (C) 2001, 2004 Steve Underwood + * + * The actual OKI ADPCM encode and decode method is derived from freely + * available code, whose exact origins seem uncertain. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: oki_adpcm.c,v 1.22 2006/11/28 16:59:56 steveu Exp $ + */ + +/*! \file */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "voipcodecs/telephony.h" +#include "voipcodecs/oki_adpcm.h" + +/* Routines to convert 12 bit linear samples to the Oki ADPCM coding format, + widely used in CTI, because Dialogic use it. */ + +static const int16_t step_size[49] = +{ + 16, 17, 19, 21, 23, 25, 28, 31, + 34, 37, 41, 45, 50, 55, 60, 66, + 73, 80, 88, 97, 107, 118, 130, 143, + 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, + 724, 796, 876, 963, 1060, 1166, 1282, 1408, + 1552 +}; + +static const int16_t step_adjustment[8] = +{ + -1, -1, -1, -1, 2, 4, 6, 8 +}; + +/* Band limiting filter, to allow sample rate conversion to and + from 6k samples/second. */ +static const float cutoff_coeffs[] = +{ + -3.648392e-4f, + 5.062391e-4f, + 1.206247e-3f, + 1.804452e-3f, + 1.691750e-3f, + 4.083405e-4f, + -1.931085e-3f, + -4.452107e-3f, + -5.794821e-3f, + -4.778489e-3f, + -1.161266e-3f, + 3.928504e-3f, + 8.259786e-3f, + 9.500425e-3f, + 6.512800e-3f, + 2.227856e-4f, + -6.531275e-3f, + -1.026843e-2f, + -8.718062e-3f, + -2.280487e-3f, + 5.817733e-3f, + 1.096777e-2f, + 9.634404e-3f, + 1.569301e-3f, + -9.522632e-3f, + -1.748273e-2f, + -1.684408e-2f, + -6.100054e-3f, + 1.071206e-2f, + 2.525209e-2f, + 2.871779e-2f, + 1.664411e-2f, + -7.706268e-3f, + -3.331083e-2f, + -4.521249e-2f, + -3.085962e-2f, + 1.373653e-2f, + 8.089593e-2f, + 1.529060e-1f, + 2.080487e-1f, + 2.286834e-1f, + 2.080487e-1f, + 1.529060e-1f, + 8.089593e-2f, + 1.373653e-2f, + -3.085962e-2f, + -4.521249e-2f, + -3.331083e-2f, + -7.706268e-3f, + 1.664411e-2f, + 2.871779e-2f, + 2.525209e-2f, + 1.071206e-2f, + -6.100054e-3f, + -1.684408e-2f, + -1.748273e-2f, + -9.522632e-3f, + 1.569301e-3f, + 9.634404e-3f, + 1.096777e-2f, + 5.817733e-3f, + -2.280487e-3f, + -8.718062e-3f, + -1.026843e-2f, + -6.531275e-3f, + 2.227856e-4f, + 6.512800e-3f, + 9.500425e-3f, + 8.259786e-3f, + 3.928504e-3f, + -1.161266e-3f, + -4.778489e-3f, + -5.794821e-3f, + -4.452107e-3f, + -1.931085e-3f, + 4.083405e-4f, + 1.691750e-3f, + 1.804452e-3f, + 1.206247e-3f, + 5.062391e-4f, + -3.648392e-4f +}; + +static int16_t decode(oki_adpcm_state_t *s, uint8_t adpcm) +{ + int16_t e; + int16_t ss; + int16_t linear; + + /* Doing the next part as follows: + * + * x = adpcm & 0x07; + * e = (step_size[s->step_index]*(x + x + 1)) >> 3; + * + * Seems an obvious improvement on a modern machine, but remember + * the truncation errors do not come out the same. It would + * not, therefore, be an exact match for what this code is doing. + * + * Just what a Dialogic card does, I do not know! + */ + + ss = step_size[s->step_index]; + e = ss >> 3; + if (adpcm & 0x01) + e += (ss >> 2); + /*endif*/ + if (adpcm & 0x02) + e += (ss >> 1); + /*endif*/ + if (adpcm & 0x04) + e += ss; + /*endif*/ + if (adpcm & 0x08) + e = -e; + /*endif*/ + linear = s->last + e; + + /* Saturate the values to +/- 2^11 (supposed to be 12 bits) */ + if (linear > 2047) + linear = 2047; + else if (linear < -2048) + linear = -2048; + /*endif*/ + + s->last = linear; + s->step_index += step_adjustment[adpcm & 0x07]; + if (s->step_index < 0) + s->step_index = 0; + else if (s->step_index > 48) + s->step_index = 48; + /*endif*/ + /* Note: the result here is a 12 bit value */ + return linear; +} +/*- End of function --------------------------------------------------------*/ + +static uint8_t encode(oki_adpcm_state_t *s, int16_t linear) +{ + int16_t e; + int16_t ss; + uint8_t adpcm; + + ss = step_size[s->step_index]; + e = (linear >> 4) - s->last; + adpcm = (uint8_t) 0x00; + if (e < 0) + { + adpcm = (uint8_t) 0x08; + e = -e; + } + /*endif*/ + if (e >= ss) + { + adpcm |= (uint8_t) 0x04; + e -= ss; + } + /*endif*/ + if (e >= (ss >> 1)) + { + adpcm |= (uint8_t) 0x02; + e -= ss; + } + /*endif*/ + if (e >= (ss >> 2)) + adpcm |= (uint8_t) 0x01; + /*endif*/ + + /* Use the decoder to set the estimate of the last sample. */ + /* It also will adjust the step_index for us. */ + s->last = decode(s, adpcm); + return adpcm; +} +/*- End of function --------------------------------------------------------*/ + +oki_adpcm_state_t *oki_adpcm_init(oki_adpcm_state_t *s, int bit_rate) +{ + if (bit_rate != 32000 && bit_rate != 24000) + return NULL; + if (s == NULL) + { + if ((s = (oki_adpcm_state_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + memset(s, 0, sizeof(*s)); + s->bit_rate = bit_rate; + + return s; +} +/*- End of function --------------------------------------------------------*/ + +int oki_adpcm_release(oki_adpcm_state_t *s) +{ + free(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +int oki_adpcm_decode(oki_adpcm_state_t *s, + int16_t amp[], + const uint8_t oki_data[], + int oki_bytes) +{ + int i; + int x; + int l; + int n; + int samples; + float z; + + samples = 0; + if (s->bit_rate == 32000) + { + for (i = 0; i < oki_bytes; i++) + { + amp[samples++] = decode(s, (oki_data[i] >> 4) & 0xF) << 4; + amp[samples++] = decode(s, oki_data[i] & 0xF) << 4; + } + /*endwhile*/ + } + else + { + n = 0; + for (i = 0; i < oki_bytes; ) + { + /* 6k to 8k sample/second conversion */ + if (s->phase) + { + s->history[s->ptr++] = + decode(s, (n++ & 1) ? (oki_data[i++] & 0xF) : ((oki_data[i] >> 4) & 0xF)) << 4; + s->ptr &= (32 - 1); + } + /*endif*/ + z = 0.0f; + for (l = 80 - 3 + s->phase, x = s->ptr - 1; l >= 0; l -= 4, x--) + z += cutoff_coeffs[l]*s->history[x & (32 - 1)]; + amp[samples++] = (int16_t) (z*4.0f); + if (++s->phase > 3) + s->phase = 0; + /*endif*/ + } + /*endfor*/ + } + /*endif*/ + return samples; +} +/*- End of function --------------------------------------------------------*/ + +int oki_adpcm_encode(oki_adpcm_state_t *s, + uint8_t oki_data[], + const int16_t amp[], + int len) +{ + int x; + int l; + int n; + int bytes; + float z; + + bytes = 0; + if (s->bit_rate == 32000) + { + for (n = 0; n < len; n++) + { + s->oki_byte = (s->oki_byte << 4) | encode(s, amp[n]); + if ((s->mark++ & 1)) + oki_data[bytes++] = s->oki_byte; + /*endif*/ + } + /*endfor*/ + } + else + { + n = 0; + for (;;) + { + /* 8k to 6k sample/second conversion */ + if (s->phase > 2) + { + s->history[s->ptr++] = amp[n]; + s->ptr &= (32 - 1); + s->phase = 0; + if (++n >= len) + break; + /*endif*/ + } + /*endif*/ + s->history[s->ptr++] = amp[n]; + s->ptr &= (32 - 1); + z = 0.0f; + for (l = 80 - s->phase, x = s->ptr - 1; l >= 0; l -= 3, x--) + z += cutoff_coeffs[l]*s->history[x & (32 - 1)]; + /*endfor*/ + s->oki_byte = (s->oki_byte << 4) | encode(s, (int16_t) (z*3.0f)); + if ((s->mark++ & 1)) + oki_data[bytes++] = s->oki_byte; + /*endif*/ + s->phase++; + if (++n >= len) + break; + /*endif*/ + } + /*endfor*/ + } + /*endif*/ + return bytes; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/vector_int.c b/libs/voipcodecs/src/vector_int.c new file mode 100644 index 0000000000..e8ab8dce70 --- /dev/null +++ b/libs/voipcodecs/src/vector_int.c @@ -0,0 +1,347 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * vector_int.c - Integer vector arithmetic + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser Lesser GNU General Public License version 2.1.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: vector_int.c,v 1.6 2007/08/21 14:25:54 steveu Exp $ + */ + +/*! \file */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif +#include + +#include "voipcodecs/telephony.h" +#include "voipcodecs/vector_int.h" + +int32_t vec_dot_prodi16(const int16_t x[], const int16_t y[], int n) +{ + int32_t z; + +#if defined(__GNUC__) && defined(__i386__) + __asm__ __volatile__( + " emms;\n" + " pxor %%mm0,%%mm0;\n" + " leal -32(%%esi,%%eax,2),%%edx;\n" /* edx = top - 32 */ + + " cmpl %%edx,%%esi;\n" + " ja 1f;\n" + + /* Work in blocks of 16 int16_t's until we are near the end */ + " .p2align 2;\n" + "2:\n" + " movq (%%edi),%%mm1;\n" + " movq (%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq 8(%%edi),%%mm1;\n" + " movq 8(%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq 16(%%edi),%%mm1;\n" + " movq 16(%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq 24(%%edi),%%mm1;\n" + " movq 24(%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + + " addl $32,%%esi;\n" + " addl $32,%%edi;\n" + " cmpl %%edx,%%esi;\n" + " jbe 2b;\n" + + " .p2align 2;\n" + "1:\n" + " addl $24,%%edx;\n" /* now edx = top - 8 */ + " cmpl %%edx,%%esi;\n" + " ja 3f;\n" + + /* Work in blocks of 4 int16_t's until we are near the end */ + " .p2align 2;\n" + "4:\n" + " movq (%%edi),%%mm1;\n" + " movq (%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + + " addl $8,%%esi;\n" + " addl $8,%%edi;\n" + " cmpl %%edx,%%esi;" + " jbe 4b;\n" + + " .p2align 2;\n" + "3:\n" + " addl $4,%%edx;\n" /* now edx = top - 4 */ + " cmpl %%edx,%%esi;\n" + " ja 5f;\n" + + /* Work in a block of 2 int16_t's */ + " movd (%%edi),%%mm1;\n" + " movd (%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + + " addl $4,%%esi;\n" + " addl $4,%%edi;\n" + + " .p2align 2;\n" + "5:\n" + " addl $2,%%edx;\n" /* now edx = top - 2 */ + " cmpl %%edx,%%esi;\n" + " ja 6f;\n" + + /* Deal with the very last int16_t, when n is odd */ + " movswl (%%edi),%%eax;\n" + " andl $65535,%%eax;\n" + " movd %%eax,%%mm1;\n" + " movswl (%%esi),%%eax;\n" + " andl $65535,%%eax;\n" + " movd %%eax,%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + + " .p2align 2;\n" + "6:\n" + /* Merge the pieces of the answer */ + " movq %%mm0,%%mm1;\n" + " punpckhdq %%mm0,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + /* et voila, eax has the final result */ + " movd %%mm0,%%eax;\n" + + " emms;\n" + : "=a" (z) + : "S" (x), "D" (y), "a" (n) + : "cc" + ); +#else + int i; + + z = 0; + for (i = 0; i < n; i++) + z += (int32_t) x[i]*(int32_t) y[i]; +#endif + return z; +} +/*- End of function --------------------------------------------------------*/ + +int32_t vec_min_maxi16(const int16_t x[], int n, int16_t out[]) +{ +#if defined(__GNUC__) && defined(__i386__) + static const int32_t lower_bound = 0x80008000; + static const int32_t upper_bound = 0x7FFF7FFF; + int32_t max; + + __asm__ __volatile__( + " emms;\n" + " pushl %%edx;\n" + " leal -8(%%esi,%%eax,2),%%edx;\n" + + " cmpl %%edx,%%esi;\n" + " jbe 2f;\n" + " movd %[lower],%%mm0;\n" + " movd %[upper],%%mm1;\n" + " jmp 1f;\n" + + " .p2align 2;\n" + "2:\n" + " movq (%%esi),%%mm0;\n" /* mm0 will be max's */ + " movq %%mm0,%%mm1;\n" /* mm1 will be min's */ + " addl $8,%%esi;\n" + " cmpl %%edx,%%esi;\n" + " ja 4f;\n" + + " .p2align 2;\n" + "3:\n" + " movq (%%esi),%%mm2;\n" + + " movq %%mm2,%%mm3;\n" + " pcmpgtw %%mm0,%%mm3;\n" /* mm3 is bitmask for words where mm2 > mm0 */ + " movq %%mm3,%%mm4;\n" + " pand %%mm2,%%mm3;\n" /* mm3 is mm2 masked to new max's */ + " pandn %%mm0,%%mm4;\n" /* mm4 is mm0 masked to its max's */ + " por %%mm3,%%mm4;\n" + " movq %%mm4,%%mm0;\n" /* Now mm0 is updated max's */ + + " movq %%mm1,%%mm3;\n" + " pcmpgtw %%mm2,%%mm3;\n" /* mm3 is bitmask for words where mm2 < mm1 */ + " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new min's */ + " pandn %%mm1,%%mm3;\n" /* mm3 is mm1 masked to its min's */ + " por %%mm3,%%mm2;\n" + " movq %%mm2,%%mm1;\n" /* now mm1 is updated min's */ + + " addl $8,%%esi;\n" + " cmpl %%edx,%%esi;\n" + " jbe 3b;\n" + + " .p2align 2;\n" + "4:\n" + /* Merge down the 4-word max/mins to lower 2 words */ + " movq %%mm0,%%mm2;\n" + " psrlq $32,%%mm2;\n" + " movq %%mm2,%%mm3;\n" + " pcmpgtw %%mm0,%%mm3;\n" /* mm3 is bitmask for words where mm2 > mm0 */ + " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new max's */ + " pandn %%mm0,%%mm3;\n" /* mm3 is mm0 masked to its max's */ + " por %%mm3,%%mm2;\n" + " movq %%mm2,%%mm0;\n" /* now mm0 is updated max's */ + + " movq %%mm1,%%mm2;\n" + " psrlq $32,%%mm2;\n" + " movq %%mm1,%%mm3;\n" + " pcmpgtw %%mm2,%%mm3;\n" /* mm3 is bitmask for words where mm2 < mm1 */ + " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new min's */ + " pandn %%mm1,%%mm3;\n" /* mm3 is mm1 masked to its min's */ + " por %%mm3,%%mm2;\n" + " movq %%mm2,%%mm1;\n" /* now mm1 is updated min's */ + + " .p2align 2;\n" + "1:\n" + " addl $4,%%edx;\n" /* now dx = top-4 */ + " cmpl %%edx,%%esi;\n" + " ja 5f;\n" + /* Here, there are >= 2 words of input remaining */ + " movd (%%esi),%%mm2;\n" + + " movq %%mm2,%%mm3;\n" + " pcmpgtw %%mm0,%%mm3;\n" /* mm3 is bitmask for words where mm2 > mm0 */ + " movq %%mm3,%%mm4;\n" + " pand %%mm2,%%mm3;\n" /* mm3 is mm2 masked to new max's */ + " pandn %%mm0,%%mm4;\n" /* mm4 is mm0 masked to its max's */ + " por %%mm3,%%mm4;\n" + " movq %%mm4,%%mm0;\n" /* now mm0 is updated max's */ + + " movq %%mm1,%%mm3;\n" + " pcmpgtw %%mm2,%%mm3;\n" /* mm3 is bitmask for words where mm2 < mm1 */ + " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new min's */ + " pandn %%mm1,%%mm3;\n" /* mm3 is mm1 masked to its min's */ + " por %%mm3,%%mm2;\n" + " movq %%mm2,%%mm1;\n" /* now mm1 is updated min's */ + + " addl $4,%%esi;\n" + + " .p2align 2;\n" + "5:\n" + /* Merge down the 2-word max/mins to 1 word */ + " movq %%mm0,%%mm2;\n" + " psrlq $16,%%mm2;\n" + " movq %%mm2,%%mm3;\n" + " pcmpgtw %%mm0,%%mm3;\n" /* mm3 is bitmask for words where mm2 > mm0 */ + " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new max's */ + " pandn %%mm0,%%mm3;\n" /* mm3 is mm0 masked to its max's */ + " por %%mm3,%%mm2;\n" + " movd %%mm2,%%ecx;\n" /* cx is max so far */ + + " movq %%mm1,%%mm2;\n" + " psrlq $16,%%mm2;\n" + " movq %%mm1,%%mm3;\n" + " pcmpgtw %%mm2,%%mm3;\n" /* mm3 is bitmask for words where mm2 < mm1 */ + " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new min's */ + " pandn %%mm1,%%mm3;\n" /* mm3 is mm1 masked to its min's */ + " por %%mm3,%%mm2;\n" + " movd %%mm2,%%eax;\n" /* ax is min so far */ + + " addl $2,%%edx;\n" /* now dx = top-2 */ + " cmpl %%edx,%%esi;\n" + " ja 6f;\n" + + /* Here, there is one word of input left */ + " cmpw (%%esi),%%cx;\n" + " jge 9f;\n" + " movw (%%esi),%%cx;\n" + " .p2align 2;\n" + "9:\n" + " cmpw (%%esi),%%ax;\n" + " jle 6f;\n" + " movw (%%esi),%%ax;\n" + + " .p2align 2;\n" + "6:\n" + /* (finally!) cx is the max, ax the min */ + " movswl %%cx,%%ecx;\n" + " movswl %%ax,%%eax;\n" + + " popl %%edx;\n" /* ptr to output max,min vals */ + " andl %%edx,%%edx;\n" + " jz 7f;\n" + " movw %%cx,(%%edx);\n" /* max */ + " movw %%ax,2(%%edx);\n" /* min */ + " .p2align 2;\n" + "7:\n" + /* Now calculate max absolute value */ + " negl %%eax;\n" + " cmpl %%ecx,%%eax;\n" + " jge 8f;\n" + " movl %%ecx,%%eax;\n" + " .p2align 2;\n" + "8:\n" + " emms;\n" + : "=a" (max) + : "S" (x), "a" (n), "d" (out), [lower] "m" (lower_bound), [upper] "m" (upper_bound) + : "ecx" + ); + return max; +#else + int i; + int16_t min; + int16_t max; + int16_t temp; + int32_t z; + + max = INT16_MIN; + min = INT16_MAX; + for (i = 0; i < n; i++) + { + temp = x[i]; + if (temp > max) + max = temp; + /*endif*/ + if (temp < min) + min = temp; + /*endif*/ + } + /*endfor*/ + out[0] = max; + out[1] = min; + z = abs(min); + if (z > max) + return z; + return max; +#endif +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/voipcodecs.h.in b/libs/voipcodecs/src/voipcodecs.h.in new file mode 100644 index 0000000000..41c7c030fa --- /dev/null +++ b/libs/voipcodecs/src/voipcodecs.h.in @@ -0,0 +1,54 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * voipcodecs.h - The head guy amongst the headers + * + * Written by Steve Underwood + * + * Copyright (C) 2003 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ + +/*! \file */ + +#if !defined(_VOIPCODECS_H_) +#define _VOIPCODECS_H_ + +@VOIPCODECS_USE_FIXED_POINT@ + +#include +@INSERT_INTTYPES_HEADER@ +#include +#include +#include +@INSERT_MATH_HEADER@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/voipcodecs/bit_operations.h b/libs/voipcodecs/src/voipcodecs/bit_operations.h new file mode 100644 index 0000000000..9d5e928ca4 --- /dev/null +++ b/libs/voipcodecs/src/voipcodecs/bit_operations.h @@ -0,0 +1,262 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * bit_operations.h - Various bit level operations, such as bit reversal + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: bit_operations.h,v 1.19 2007/12/13 11:31:32 steveu Exp $ + */ + +/*! \file */ + +#if !defined(_SPANDSP_BIT_OPERATIONS_H_) +#define _SPANDSP_BIT_OPERATIONS_H_ + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/*! \brief Find the bit position of the highest set bit in a word + \param bits The word to be searched + \return The bit number of the highest set bit, or -1 if the word is zero. */ +static __inline__ int top_bit(unsigned int bits) +{ + int res; + +#if defined(__i386__) || defined(__x86_64__) + __asm__ (" xorl %[res],%[res];\n" + " decl %[res];\n" + " bsrl %[bits],%[res]\n" + : [res] "=&r" (res) + : [bits] "rm" (bits)); + return res; +#elif defined(__ppc__) || defined(__powerpc__) + __asm__ ("cntlzw %[res],%[bits];\n" + : [res] "=&r" (res) + : [bits] "r" (bits)); + return 31 - res; +#else + if (bits == 0) + return -1; + res = 0; + if (bits & 0xFFFF0000) + { + bits &= 0xFFFF0000; + res += 16; + } + if (bits & 0xFF00FF00) + { + bits &= 0xFF00FF00; + res += 8; + } + if (bits & 0xF0F0F0F0) + { + bits &= 0xF0F0F0F0; + res += 4; + } + if (bits & 0xCCCCCCCC) + { + bits &= 0xCCCCCCCC; + res += 2; + } + if (bits & 0xAAAAAAAA) + { + bits &= 0xAAAAAAAA; + res += 1; + } + return res; +#endif +} +/*- End of function --------------------------------------------------------*/ + +/*! \brief Find the bit position of the lowest set bit in a word + \param bits The word to be searched + \return The bit number of the lowest set bit, or -1 if the word is zero. */ +static __inline__ int bottom_bit(unsigned int bits) +{ + int res; + +#if defined(__i386__) || defined(__x86_64__) + __asm__ (" xorl %[res],%[res];\n" + " decl %[res];\n" + " bsfl %[bits],%[res]\n" + : [res] "=&r" (res) + : [bits] "rm" (bits)); + return res; +#else + if (bits == 0) + return -1; + res = 31; + if (bits & 0x0000FFFF) + { + bits &= 0x0000FFFF; + res -= 16; + } + if (bits & 0x00FF00FF) + { + bits &= 0x00FF00FF; + res -= 8; + } + if (bits & 0x0F0F0F0F) + { + bits &= 0x0F0F0F0F; + res -= 4; + } + if (bits & 0x33333333) + { + bits &= 0x33333333; + res -= 2; + } + if (bits & 0x55555555) + { + bits &= 0x55555555; + res -= 1; + } + return res; +#endif +} +/*- End of function --------------------------------------------------------*/ + +/*! \brief Bit reverse a byte. + \param data The byte to be reversed. + \return The bit reversed version of data. */ +static __inline__ uint8_t bit_reverse8(uint8_t x) +{ +#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__powerpc__) + /* If multiply is fast */ + return ((x*0x0802U & 0x22110U) | (x*0x8020U & 0x88440U))*0x10101U >> 16; +#else + /* If multiply is slow, but we have a barrel shifter */ + x = (x >> 4) | (x << 4); + x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2); + return ((x & 0xAA) >> 1) | ((x & 0x55) << 1); +#endif +} +/*- End of function --------------------------------------------------------*/ + +/*! \brief Bit reverse a 16 bit word. + \param data The word to be reversed. + \return The bit reversed version of data. */ +uint16_t bit_reverse16(uint16_t data); + +/*! \brief Bit reverse a 32 bit word. + \param data The word to be reversed. + \return The bit reversed version of data. */ +uint32_t bit_reverse32(uint32_t data); + +/*! \brief Bit reverse each of the four bytes in a 32 bit word. + \param data The word to be reversed. + \return The bit reversed version of data. */ +uint32_t bit_reverse_4bytes(uint32_t data); + +#if defined(__x86_64__) +/*! \brief Bit reverse each of the eight bytes in a 64 bit word. + \param data The word to be reversed. + \return The bit reversed version of data. */ +uint64_t bit_reverse_8bytes(uint64_t data); +#endif + +/*! \brief Bit reverse each bytes in a buffer. + \param to The buffer to place the reversed data in. + \param from The buffer containing the data to be reversed. + \param len The length of the data in the buffer. */ +void bit_reverse(uint8_t to[], const uint8_t from[], int len); + +/*! \brief Find the number of set bits in a 32 bit word. + \param x The word to be searched. + \return The number of set bits. */ +int one_bits32(uint32_t x); + +/*! \brief Create a mask as wide as the number in a 32 bit word. + \param x The word to be searched. + \return The mask. */ +uint32_t make_mask32(uint32_t x); + +/*! \brief Create a mask as wide as the number in a 16 bit word. + \param x The word to be searched. + \return The mask. */ +uint16_t make_mask16(uint16_t x); + +/*! \brief Find the least significant one in a word, and return a word + with just that bit set. + \param x The word to be searched. + \return The word with the single set bit. */ +static __inline__ uint32_t least_significant_one32(uint32_t x) +{ + return (x & (-(int32_t) x)); +} +/*- End of function --------------------------------------------------------*/ + +/*! \brief Find the most significant one in a word, and return a word + with just that bit set. + \param x The word to be searched. + \return The word with the single set bit. */ +static __inline__ uint32_t most_significant_one32(uint32_t x) +{ +#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__powerpc__) + return 1 << top_bit(x); +#else + x = make_mask32(x); + return (x ^ (x >> 1)); +#endif +} +/*- End of function --------------------------------------------------------*/ + +/*! \brief Find the parity of a byte. + \param x The byte to be checked. + \return 1 for odd, or 0 for even. */ +static __inline__ int parity8(uint8_t x) +{ + x = (x ^ (x >> 4)) & 0x0F; + return (0x6996 >> x) & 1; +} +/*- End of function --------------------------------------------------------*/ + +/*! \brief Find the parity of a 16 bit word. + \param x The word to be checked. + \return 1 for odd, or 0 for even. */ +static __inline__ int parity16(uint16_t x) +{ + x ^= (x >> 8); + x = (x ^ (x >> 4)) & 0x0F; + return (0x6996 >> x) & 1; +} +/*- End of function --------------------------------------------------------*/ + +/*! \brief Find the parity of a 32 bit word. + \param x The word to be checked. + \return 1 for odd, or 0 for even. */ +static __inline__ int parity32(uint32_t x) +{ + x ^= (x >> 16); + x ^= (x >> 8); + x = (x ^ (x >> 4)) & 0x0F; + return (0x6996 >> x) & 1; +} +/*- End of function --------------------------------------------------------*/ + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/voipcodecs/bitstream.h b/libs/voipcodecs/src/voipcodecs/bitstream.h new file mode 100644 index 0000000000..15131fdcce --- /dev/null +++ b/libs/voipcodecs/src/voipcodecs/bitstream.h @@ -0,0 +1,89 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * bitstream.h - Bitstream composition and decomposition routines. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: bitstream.h,v 1.8 2007/12/13 11:31:32 steveu Exp $ + */ + +/*! \file */ + +#if !defined(_SPANDSP_BITSTREAM_H_) +#define _SPANDSP_BITSTREAM_H_ + +/*! \page bitstream_page Bitstream composition and decomposition +\section bitstream_page_sec_1 What does it do? + +\section bitstream_page_sec_2 How does it work? +*/ + +/*! Bitstream handler state */ +typedef struct +{ + /*! The bit stream. */ + unsigned int bitstream; + /*! The residual bits in bitstream. */ + unsigned int residue; +} bitstream_state_t; + + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/*! \brief Put a chunk of bits into the output buffer. + \param s A pointer to the bitstream context. + \param c A pointer to the bitstream output buffer. + \param value The value to be pushed into the output buffer. + \param bits The number of bits of value to be pushed. 1 to 25 bit is valid. */ +void bitstream_put(bitstream_state_t *s, uint8_t **c, unsigned int value, int bits); + +void bitstream_put2(bitstream_state_t *s, uint8_t **c, unsigned int value, int bits); + +/*! \brief Get a chunk of bits from the input buffer. + \param s A pointer to the bitstream context. + \param c A pointer to the bitstream input buffer. + \param bits The number of bits of value to be grabbed. 1 to 25 bit is valid. + \return The value retrieved from the input buffer. */ +unsigned int bitstream_get(bitstream_state_t *s, const uint8_t **c, int bits); + +unsigned int bitstream_get2(bitstream_state_t *s, const uint8_t **c, int bits); + +/*! \brief Flush any residual bit to the output buffer. + \param s A pointer to the bitstream context. + \param c A pointer to the bitstream output buffer. */ +void bitstream_flush(bitstream_state_t *s, uint8_t **c); + +void bitstream_flush2(bitstream_state_t *s, uint8_t **c); + +/*! \brief Initialise a bitstream context. + \param s A pointer to the bitstream context. + \return A pointer to the bitstream context. */ +bitstream_state_t *bitstream_init(bitstream_state_t *s); + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/voipcodecs/dc_restore.h b/libs/voipcodecs/src/voipcodecs/dc_restore.h new file mode 100644 index 0000000000..64fee03456 --- /dev/null +++ b/libs/voipcodecs/src/voipcodecs/dc_restore.h @@ -0,0 +1,127 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * dc_restore.h - General telephony routines to restore the zero D.C. + * level to audio which has a D.C. bias. + * + * Written by Steve Underwood + * + * Copyright (C) 2001 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: dc_restore.h,v 1.18 2007/04/08 08:16:17 steveu Exp $ + */ + +/*! \file */ + +#if !defined(_SPANDSP_DC_RESTORE_H_) +#define _SPANDSP_DC_RESTORE_H_ + +/*! \page dc_restore_page Removing DC bias from a signal + +\section dc_restore_page_sec_1 What does it do? + +Telecoms signals often contain considerable DC, but DC upsets a lot of signal +processing functions. Placing a zero DC restorer at the front of the processing +chain can often simplify the downstream processing. + +\section dc_restore_page_sec_2 How does it work? + +The DC restorer uses a leaky integrator to provide a long-ish term estimate of +the DC bias in the signal. A 32 bit estimate is used for the 16 bit audio, so +the noise introduced by the estimation can be keep in the lower bits, and the 16 +bit DC value, which is subtracted from the signal, is fairly clean. The +following code fragment shows the algorithm used. dc_bias is a 32 bit integer, +while the sample and the resulting clean_sample are 16 bit integers. + + dc_bias += ((((int32_t) sample << 15) - dc_bias) >> 14); + clean_sample = sample - (dc_bias >> 15); +*/ + +/*! + Zero DC restoration descriptor. This defines the working state for a single + instance of DC content filter. +*/ +typedef struct +{ + int32_t state; +} dc_restore_state_t; + +#if defined(__cplusplus) +extern "C" +{ +#endif + +static __inline__ void dc_restore_init(dc_restore_state_t *dc) +{ + dc->state = 0; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int16_t dc_restore(dc_restore_state_t *dc, int16_t sample) +{ + dc->state += ((((int32_t) sample << 15) - dc->state) >> 14); + return (int16_t) (sample - (dc->state >> 15)); +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int16_t dc_restore_estimate(dc_restore_state_t *dc) +{ + return (int16_t) (dc->state >> 15); +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int16_t saturate(int32_t amp) +{ + int16_t amp16; + + /* Hopefully this is optimised for the common case - not clipping */ + amp16 = (int16_t) amp; + if (amp == amp16) + return amp16; + if (amp > INT16_MAX) + return INT16_MAX; + return INT16_MIN; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int16_t fsaturatef(float famp) +{ + if (famp > 32767.0) + return INT16_MAX; + if (famp < -32768.0) + return INT16_MIN; + return (int16_t) rintf(famp); +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int16_t fsaturate(double damp) +{ + if (damp > 32767.0) + return INT16_MAX; + if (damp < -32768.0) + return INT16_MIN; + return (int16_t) rint(damp); +} +/*- End of function --------------------------------------------------------*/ + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/voipcodecs/g711.h b/libs/voipcodecs/src/voipcodecs/g711.h new file mode 100644 index 0000000000..bf4b8e72b8 --- /dev/null +++ b/libs/voipcodecs/src/voipcodecs/g711.h @@ -0,0 +1,255 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * g711.h - In line A-law and u-law conversion routines + * + * Written by Steve Underwood + * + * Copyright (C) 2001 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: g711.h,v 1.8 2007/12/13 11:31:32 steveu Exp $ + */ + +/*! \file */ + +/*! \page g711_page A-law and mu-law handling +Lookup tables for A-law and u-law look attractive, until you consider the impact +on the CPU cache. If it causes a substantial area of your processor cache to get +hit too often, cache sloshing will severely slow things down. The main reason +these routines are slow in C, is the lack of direct access to the CPU's "find +the first 1" instruction. A little in-line assembler fixes that, and the +conversion routines can be faster than lookup tables, in most real world usage. +A "find the first 1" instruction is available on most modern CPUs, and is a +much underused feature. + +If an assembly language method of bit searching is not available, these routines +revert to a method that can be a little slow, so the cache thrashing might not +seem so bad :( + +Feel free to submit patches to add fast "find the first 1" support for your own +favourite processor. + +Look up tables are used for transcoding between A-law and u-law, since it is +difficult to achieve the precise transcoding procedure laid down in the G.711 +specification by other means. +*/ + +#if !defined(_SPANDSP_G711_H_) +#define _SPANDSP_G711_H_ + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* N.B. It is tempting to use look-up tables for A-law and u-law conversion. + * However, you should consider the cache footprint. + * + * A 64K byte table for linear to x-law and a 512 byte table for x-law to + * linear sound like peanuts these days, and shouldn't an array lookup be + * real fast? No! When the cache sloshes as badly as this one will, a tight + * calculation may be better. The messiest part is normally finding the + * segment, but a little inline assembly can fix that on an i386, x86_64 and + * many other modern processors. + */ + +/* + * Mu-law is basically as follows: + * + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz + * + * Each biased linear code has a leading 1 which identifies the segment + * number. The value of the segment number is equal to 7 minus the number + * of leading 0's. The quantization interval is directly available as the + * four bits wxyz. * The trailing bits (a - h) are ignored. + * + * Ordinarily the complement of the resulting code word is used for + * transmission, and so the code word is complemented before it is returned. + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ + +//#define ULAW_ZEROTRAP /* turn on the trap as per the MIL-STD */ +#define ULAW_BIAS 0x84 /* Bias for linear code. */ + +/*! \brief Encode a linear sample to u-law + \param linear The sample to encode. + \return The u-law value. +*/ +static __inline__ uint8_t linear_to_ulaw(int linear) +{ + uint8_t u_val; + int mask; + int seg; + + /* Get the sign and the magnitude of the value. */ + if (linear >= 0) + { + linear = ULAW_BIAS + linear; + mask = 0xFF; + } + else + { + linear = ULAW_BIAS - linear; + mask = 0x7F; + } + + seg = top_bit(linear | 0xFF) - 7; + + /* + * Combine the sign, segment, quantization bits, + * and complement the code word. + */ + if (seg >= 8) + u_val = (uint8_t) (0x7F ^ mask); + else + u_val = (uint8_t) (((seg << 4) | ((linear >> (seg + 3)) & 0xF)) ^ mask); +#ifdef ULAW_ZEROTRAP + /* Optional ITU trap */ + if (u_val == 0) + u_val = 0x02; +#endif + return u_val; +} +/*- End of function --------------------------------------------------------*/ + +/*! \brief Decode an u-law sample to a linear value. + \param ulaw The u-law sample to decode. + \return The linear value. +*/ +static __inline__ int16_t ulaw_to_linear(uint8_t ulaw) +{ + int t; + + /* Complement to obtain normal u-law value. */ + ulaw = ~ulaw; + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = (((ulaw & 0x0F) << 3) + ULAW_BIAS) << (((int) ulaw & 0x70) >> 4); + return (int16_t) ((ulaw & 0x80) ? (ULAW_BIAS - t) : (t - ULAW_BIAS)); +} +/*- End of function --------------------------------------------------------*/ + +/* + * A-law is basically as follows: + * + * Linear Input Code Compressed Code + * ----------------- --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ + +#define ALAW_AMI_MASK 0x55 + +/*! \brief Encode a linear sample to A-law + \param linear The sample to encode. + \return The A-law value. +*/ +static __inline__ uint8_t linear_to_alaw(int linear) +{ + int mask; + int seg; + + if (linear >= 0) + { + /* Sign (bit 7) bit = 1 */ + mask = ALAW_AMI_MASK | 0x80; + } + else + { + /* Sign (bit 7) bit = 0 */ + mask = ALAW_AMI_MASK; + linear = -linear - 1; + } + + /* Convert the scaled magnitude to segment number. */ + seg = top_bit(linear | 0xFF) - 7; + if (seg >= 8) + { + if (linear >= 0) + { + /* Out of range. Return maximum value. */ + return (uint8_t) (0x7F ^ mask); + } + /* We must be just a tiny step below zero */ + return (uint8_t) (0x00 ^ mask); + } + /* Combine the sign, segment, and quantization bits. */ + return (uint8_t) (((seg << 4) | ((linear >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask); +} +/*- End of function --------------------------------------------------------*/ + +/*! \brief Decode an A-law sample to a linear value. + \param alaw The A-law sample to decode. + \return The linear value. +*/ +static __inline__ int16_t alaw_to_linear(uint8_t alaw) +{ + int i; + int seg; + + alaw ^= ALAW_AMI_MASK; + i = ((alaw & 0x0F) << 4); + seg = (((int) alaw & 0x70) >> 4); + if (seg) + i = (i + 0x108) << (seg - 1); + else + i += 8; + return (int16_t) ((alaw & 0x80) ? i : -i); +} +/*- End of function --------------------------------------------------------*/ + +/*! \brief Transcode from A-law to u-law, using the procedure defined in G.711. + \param alaw The A-law sample to transcode. + \return The best matching u-law value. +*/ +uint8_t alaw_to_ulaw(uint8_t alaw); + +/*! \brief Transcode from u-law to A-law, using the procedure defined in G.711. + \param ulaw The u-law sample to transcode. + \return The best matching A-law value. +*/ +uint8_t ulaw_to_alaw(uint8_t ulaw); + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/voipcodecs/g722.h b/libs/voipcodecs/src/voipcodecs/g722.h new file mode 100644 index 0000000000..d96d15b21d --- /dev/null +++ b/libs/voipcodecs/src/voipcodecs/g722.h @@ -0,0 +1,180 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * g722.h - The ITU G.722 codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Based on a single channel G.722 codec which is: + * + ***** Copyright (c) CMU 1993 ***** + * Computer Science, Speech Group + * Chengxiang Lu and Alex Hauptmann + * + * $Id: g722.h,v 1.16 2007/04/08 08:16:17 steveu Exp $ + */ + + +/*! \file */ + +#if !defined(_SPANDSP_G722_H_) +#define _SPANDSP_G722_H_ + +/*! \page g722_page G.722 encoding and decoding +\section g722_page_sec_1 What does it do? +The G.722 module is a bit exact implementation of the ITU G.722 specification for all three +specified bit rates - 64000bps, 56000bps and 48000bps. It passes the ITU tests. + +To allow fast and flexible interworking with narrow band telephony, the encoder and decoder +support an option for the linear audio to be an 8k samples/second stream. In this mode the +codec is considerably faster, and still fully compatible with wideband terminals using G.722. + +\section g722_page_sec_2 How does it work? +???. +*/ + +enum +{ + G722_SAMPLE_RATE_8000 = 0x0001, + G722_PACKED = 0x0002 +}; + +typedef struct +{ + /*! TRUE if the operating in the special ITU test mode, with the band split filters + disabled. */ + int itu_test_mode; + /*! TRUE if the G.722 data is packed */ + int packed; + /*! TRUE if encode from 8k samples/second */ + int eight_k; + /*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */ + int bits_per_sample; + + /*! Signal history for the QMF */ + int x[24]; + + struct + { + int s; + int sp; + int sz; + int r[3]; + int a[3]; + int ap[3]; + int p[3]; + int d[7]; + int b[7]; + int bp[7]; + int sg[7]; + int nb; + int det; + } band[2]; + + unsigned int in_buffer; + int in_bits; + unsigned int out_buffer; + int out_bits; +} g722_encode_state_t; + +typedef struct +{ + /*! TRUE if the operating in the special ITU test mode, with the band split filters + disabled. */ + int itu_test_mode; + /*! TRUE if the G.722 data is packed */ + int packed; + /*! TRUE if decode to 8k samples/second */ + int eight_k; + /*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */ + int bits_per_sample; + + /*! Signal history for the QMF */ + int x[24]; + + struct + { + int s; + int sp; + int sz; + int r[3]; + int a[3]; + int ap[3]; + int p[3]; + int d[7]; + int b[7]; + int bp[7]; + int sg[7]; + int nb; + int det; + } band[2]; + + unsigned int in_buffer; + int in_bits; + unsigned int out_buffer; + int out_bits; +} g722_decode_state_t; + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/*! Initialise an G.722 encode context. + \param s The G.722 encode context. + \param rate The required bit rate for the G.722 data. + The valid rates are 64000, 56000 and 48000. + \param options + \return A pointer to the G.722 encode context, or NULL for error. */ +g722_encode_state_t *g722_encode_init(g722_encode_state_t *s, int rate, int options); + +int g722_encode_release(g722_encode_state_t *s); + +/*! Encode a buffer of linear PCM data to G.722 + \param s The G.722 context. + \param g722_data The G.722 data produced. + \param amp The audio sample buffer. + \param len The number of samples in the buffer. + \return The number of bytes of G.722 data produced. */ +int g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len); + +/*! Initialise an G.722 decode context. + \param s The G.722 decode context. + \param rate The bit rate of the G.722 data. + The valid rates are 64000, 56000 and 48000. + \param options + \return A pointer to the G.722 decode context, or NULL for error. */ +g722_decode_state_t *g722_decode_init(g722_decode_state_t *s, int rate, int options); + +int g722_decode_release(g722_decode_state_t *s); + +/*! Decode a buffer of G.722 data to linear PCM. + \param s The G.722 context. + \param amp The audio sample buffer. + \param g722_data + \param len + \return The number of samples returned. */ +int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/libs/voipcodecs/src/voipcodecs/g726.h b/libs/voipcodecs/src/voipcodecs/g726.h new file mode 100644 index 0000000000..df2e0b9480 --- /dev/null +++ b/libs/voipcodecs/src/voipcodecs/g726.h @@ -0,0 +1,195 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * g726.h - ITU G.726 codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Based on G.721/G.723 code which is: + * + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + * + * $Id: g726.h,v 1.18 2007/12/13 11:31:32 steveu Exp $ + */ + +/*! \file */ + +#if !defined(_SPANDSP_G726_H_) +#define _SPANDSP_G726_H_ + +/*! \page g726_page G.726 encoding and decoding +\section g726_page_sec_1 What does it do? + +The G.726 module is a bit exact implementation of the full ITU G.726 specification. +It supports: + - 16 kbps, 24kbps, 32kbps, and 40kbps operation. + - Tandem adjustment, for interworking with A-law and u-law. + - Annex A support, for use in environments not using A-law or u-law. + +It passes the ITU tests. + +\section g726_page_sec_2 How does it work? +???. +*/ + +enum +{ + G726_ENCODING_LINEAR = 0, /* Interworking with 16 bit signed linear */ + G726_ENCODING_ULAW, /* Interworking with u-law */ + G726_ENCODING_ALAW /* Interworking with A-law */ +}; + +enum +{ + G726_PACKING_NONE = 0, + G726_PACKING_LEFT = 1, + G726_PACKING_RIGHT = 2 +}; + +struct g726_state_s; + +typedef int16_t (*g726_decoder_func_t)(struct g726_state_s *s, uint8_t code); + +typedef uint8_t (*g726_encoder_func_t)(struct g726_state_s *s, int16_t amp); + +/*! + * The following is the definition of the state structure + * used by the G.726 encoder and decoder to preserve their internal + * state between successive calls. The meanings of the majority + * of the state structure fields are explained in detail in the + * CCITT Recommendation G.721. The field names are essentially indentical + * to variable names in the bit level description of the coding algorithm + * included in this Recommendation. + */ +typedef struct g726_state_s +{ + /*! The bit rate */ + int rate; + /*! The external coding, for tandem operation */ + int ext_coding; + /*! The number of bits per sample */ + unsigned int bits_per_sample; + /*! One of the G.726_PACKING_xxx options */ + int packing; + + /*! Locked or steady state step size multiplier. */ + int32_t yl; + /*! Unlocked or non-steady state step size multiplier. */ + int16_t yu; + /*! int16_t term energy estimate. */ + int16_t dms; + /*! Long term energy estimate. */ + int16_t dml; + /*! Linear weighting coefficient of 'yl' and 'yu'. */ + int16_t ap; + + /*! Coefficients of pole portion of prediction filter. */ + int16_t a[2]; + /*! Coefficients of zero portion of prediction filter. */ + int16_t b[6]; + /*! Signs of previous two samples of a partially reconstructed signal. */ + int16_t pk[2]; + /*! Previous 6 samples of the quantized difference signal represented in + an internal floating point format. */ + int16_t dq[6]; + /*! Previous 2 samples of the quantized difference signal represented in an + internal floating point format. */ + int16_t sr[2]; + /*! Delayed tone detect */ + int td; + + /*! \brief The bit stream processing context. */ + bitstream_state_t bs; + + /*! \brief The current encoder function. */ + g726_encoder_func_t enc_func; + /*! \brief The current decoder function. */ + g726_decoder_func_t dec_func; +} g726_state_t; + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/*! Initialise a G.726 encode or decode context. + \param s The G.726 context. + \param bit_rate The required bit rate for the ADPCM data. + The valid rates are 16000, 24000, 32000 and 40000. + \param ext_coding The coding used outside G.726. + \param packing One of the G.726_PACKING_xxx options. + \return A pointer to the G.726 context, or NULL for error. */ +g726_state_t *g726_init(g726_state_t *s, int bit_rate, int ext_coding, int packing); + +/*! Free a G.726 encode or decode context. + \param s The G.726 context. + \return 0 for OK. */ +int g726_release(g726_state_t *s); + +/*! Decode a buffer of G.726 ADPCM data to linear PCM, a-law or u-law. + \param s The G.726 context. + \param amp The audio sample buffer. + \param g726_data + \param g726_bytes + \return The number of samples returned. */ +int g726_decode(g726_state_t *s, + int16_t amp[], + const uint8_t g726_data[], + int g726_bytes); + +/*! Encode a buffer of linear PCM data to G.726 ADPCM. + \param s The G.726 context. + \param g726_data The G.726 data produced. + \param amp The audio sample buffer. + \param len The number of samples in the buffer. + \return The number of bytes of G.726 data produced. */ +int g726_encode(g726_state_t *s, + uint8_t g726_data[], + const int16_t amp[], + int len); + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/voipcodecs/gsm0610.h b/libs/voipcodecs/src/voipcodecs/gsm0610.h new file mode 100644 index 0000000000..282065adcc --- /dev/null +++ b/libs/voipcodecs/src/voipcodecs/gsm0610.h @@ -0,0 +1,175 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * gsm0610.h - GSM 06.10 full rate speech codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: gsm0610.h,v 1.13 2007/12/13 11:31:32 steveu Exp $ + */ + +#if !defined(_SPANDSP_GSM0610_H_) +#define _SPANDSP_GSM0610_H_ + +/*! \page gsm0610_page GSM 06.10 encoding and decoding +\section gsm0610_page_sec_1 What does it do? + +The GSM 06.10 module is an version of the widely used GSM FR codec software +available from http://kbs.cs.tu-berlin.de/~jutta/toast.html. This version +was produced since some versions of this codec are not bit exact, or not +very efficient on modern processors. This implementation can use MMX instructions +on Pentium class processors, or alternative methods on other processors. It +passes all the ETSI test vectors. That is, it is a tested bit exact implementation. + +This implementation supports encoded data in one of three packing formats: + - Unpacked, with the 76 parameters of a GSM 06.10 code frame each occupying a + separate byte. (note that none of the parameters exceed 8 bits). + - Packed the the 33 byte per frame, used for VoIP, where 4 bits per frame are wasted. + - Packed in WAV49 format, where 2 frames are packed into 65 bytes. + +\section gsm0610_page_sec_2 How does it work? +???. +*/ + +enum +{ + GSM0610_PACKING_NONE, + GSM0610_PACKING_WAV49, + GSM0610_PACKING_VOIP +}; + +/*! + GSM 06.10 FR codec unpacked frame. +*/ +typedef struct +{ + int16_t LARc[8]; + int16_t Nc[4]; + int16_t bc[4]; + int16_t Mc[4]; + int16_t xmaxc[4]; + int16_t xMc[4][13]; +} gsm0610_frame_t; + +/*! + GSM 06.10 FR codec state descriptor. This defines the state of + a single working instance of the GSM 06.10 FR encoder or decoder. +*/ +typedef struct +{ + /*! \brief One of the packing modes */ + int packing; + + int16_t dp0[280]; + + /*! Preprocessing */ + int16_t z1; + int32_t L_z2; + /*! Pre-emphasis */ + int16_t mp; + + /*! Short term delay filter */ + int16_t u[8]; + int16_t LARpp[2][8]; + int16_t j; + + /*! Long term synthesis */ + int16_t nrp; + /*! Short term synthesis */ + int16_t v[9]; + /*! Decoder postprocessing */ + int16_t msr; + + /*! Encoder data */ + int16_t e[50]; +} gsm0610_state_t; + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/*! Initialise a GSM 06.10 encode or decode context. + \param s The GSM 06.10 context + \param packing One of the GSM0610_PACKING_xxx options. + \return A pointer to the GSM 06.10 context, or NULL for error. */ +gsm0610_state_t *gsm0610_init(gsm0610_state_t *s, int packing); + +/*! Release a GSM 06.10 encode or decode context. + \param s The GSM 06.10 context + \return 0 for success, else -1. */ +int gsm0610_release(gsm0610_state_t *s); + +/*! Set the packing format for a GSM 06.10 encode or decode context. + \param s The GSM 06.10 context + \param packing One of the GSM0610_PACKING_xxx options. + \return 0 for success, else -1. */ +int gsm0610_set_packing(gsm0610_state_t *s, int packing); + +/*! Encode a buffer of linear PCM data to GSM 06.10. + \param s The GSM 06.10 context. + \param code The GSM 06.10 data produced. + \param amp The audio sample buffer. + \param quant The number of samples in the buffer. + \return The number of bytes of GSM 06.10 data produced. */ +int gsm0610_encode(gsm0610_state_t *s, uint8_t code[], const int16_t amp[], int quant); + +/*! Decode a buffer of GSM 06.10 data to linear PCM. + \param s The GSM 06.10 context. + \param amp The audio sample buffer. + \param code The GSM 06.10 data. + \param quant The number of frames of GSM 06.10 data to be decoded. + \return The number of samples returned. */ +int gsm0610_decode(gsm0610_state_t *s, int16_t amp[], const uint8_t code[], int quant); + +int gsm0610_pack_none(uint8_t c[], const gsm0610_frame_t *s); + +/*! Pack a pair of GSM 06.10 frames in the format used for wave files (wave type 49). + \param c The buffer for the packed data. This must be at least 65 bytes long. + \param s A pointer to the frames to be packed. + \return The number of bytes generated. */ +int gsm0610_pack_wav49(uint8_t c[], const gsm0610_frame_t *s); + +/*! Pack a GSM 06.10 frames in the format used for VoIP. + \param c The buffer for the packed data. This must be at least 33 bytes long. + \param s A pointer to the frame to be packed. + \return The number of bytes generated. */ +int gsm0610_pack_voip(uint8_t c[], const gsm0610_frame_t *s); + +int gsm0610_unpack_none(gsm0610_frame_t *s, const uint8_t c[]); + +/*! Unpack a pair of GSM 06.10 frames from the format used for wave files (wave type 49). + \param s A pointer to a buffer into which the frames will be packed. + \param c The buffer containing the data to be unpacked. This must be at least 65 bytes long. + \return The number of bytes absorbed. */ +int gsm0610_unpack_wav49(gsm0610_frame_t *s, const uint8_t c[]); + +/*! Unpack a GSM 06.10 frame from the format used for VoIP. + \param s A pointer to a buffer into which the frame will be packed. + \param c The buffer containing the data to be unpacked. This must be at least 33 bytes long. + \return The number of bytes absorbed. */ +int gsm0610_unpack_voip(gsm0610_frame_t *s, const uint8_t c[]); + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of include ---------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/voipcodecs/ima_adpcm.h b/libs/voipcodecs/src/voipcodecs/ima_adpcm.h new file mode 100644 index 0000000000..8a54cb48f6 --- /dev/null +++ b/libs/voipcodecs/src/voipcodecs/ima_adpcm.h @@ -0,0 +1,113 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * imaadpcm.c - Conversion routines between linear 16 bit PCM data and + * IMA/DVI/Intel ADPCM format. + * + * Written by Steve Underwood + * + * Copyright (C) 2004 Steve Underwood + * + * Based on a bit from here, a bit from there, eye of toad, + * ear of bat, etc - plus, of course, my own 2 cents. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: ima_adpcm.h,v 1.16 2007/12/13 11:31:32 steveu Exp $ + */ + +/*! \file */ + +#if !defined(_SPANDSP_IMA_ADPCM_H_) +#define _SPANDSP_IMA_ADPCM_H_ + +/*! \page ima_adpcm_page IMA/DVI/Intel ADPCM encoding and decoding +\section ima_adpcm_page_sec_1 What does it do? +IMA ADPCM offers a good balance of simplicity and quality at a rate of +32kbps. + +\section ima_adpcm_page_sec_2 How does it work? + +\section ima_adpcm_page_sec_3 How do I use it? +*/ + +enum +{ + IMA_ADPCM_DVI4 = 0, + IMA_ADPCM_VDVI = 1 +}; + +/*! + IMA (DVI/Intel) ADPCM conversion state descriptor. This defines the state of + a single working instance of the IMA ADPCM converter. This is used for + either linear to ADPCM or ADPCM to linear conversion. +*/ +typedef struct +{ + int variant; + /*! \brief The last state of the ADPCM algorithm. */ + int last; + /*! \brief Current index into the step size table. */ + int step_index; + /*! \brief The current IMA code byte in progress. */ + uint16_t ima_byte; + int bits; +} ima_adpcm_state_t; + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/*! Initialise an IMA ADPCM encode or decode context. + \param s The IMA ADPCM context + \param variant ??? + \return A pointer to the IMA ADPCM context, or NULL for error. */ +ima_adpcm_state_t *ima_adpcm_init(ima_adpcm_state_t *s, int variant); + +/*! Free an IMA ADPCM encode or decode context. + \param s The IMA ADPCM context. + \return 0 for OK. */ +int ima_adpcm_release(ima_adpcm_state_t *s); + +/*! Encode a buffer of linear PCM data to IMA ADPCM. + \param s The IMA ADPCM context. + \param ima_data The IMA ADPCM data produced. + \param amp The audio sample buffer. + \param len The number of samples in the buffer. + \return The number of bytes of IMA ADPCM data produced. */ +int ima_adpcm_encode(ima_adpcm_state_t *s, + uint8_t ima_data[], + const int16_t amp[], + int len); + +/*! Decode a buffer of IMA ADPCM data to linear PCM. + \param s The IMA ADPCM context. + \param amp The audio sample buffer. + \param ima_data + \param ima_bytes + \return The number of samples returned. */ +int ima_adpcm_decode(ima_adpcm_state_t *s, + int16_t amp[], + const uint8_t ima_data[], + int ima_bytes); + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/voipcodecs/lpc10.h b/libs/voipcodecs/src/voipcodecs/lpc10.h new file mode 100644 index 0000000000..192d63dcac --- /dev/null +++ b/libs/voipcodecs/src/voipcodecs/lpc10.h @@ -0,0 +1,213 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * lpc10.h - LPC10 low bit rate speech codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: lpc10.h,v 1.13 2007/04/08 08:16:18 steveu Exp $ + */ + +#if !defined(_SPANDSP_LPC10_H_) +#define _SPANDSP_LPC10_H_ + +/*! \page lpc10_page LPC10 encoding and decoding +\section lpc10_page_sec_1 What does it do? +The LPC10 module implements the US Department of Defense LPC10 +codec. This codec produces compressed data at 2400bps. At such +a low rate high fidelity cannot be expected. However, the speech +clarity is quite good, and this codec is unencumbered by patent +or other restrictions. + +\section lpc10_page_sec_2 How does it work? +???. +*/ + +#define LPC10_SAMPLES_PER_FRAME 180 +#define LPC10_BITS_IN_COMPRESSED_FRAME 54 + +/*! + LPC10 codec unpacked frame. +*/ +typedef struct +{ + int32_t ipitch; + int32_t irms; + int32_t irc[10]; +} lpc10_frame_t; + +/*! + LPC10 codec encoder state descriptor. This defines the state of + a single working instance of the LPC10 encoder. +*/ +typedef struct +{ + int error_correction; + + /* State used only by function high_pass_100hz */ + float z11; + float z21; + float z12; + float z22; + + /* State used by function lpc10_analyse */ + float inbuf[LPC10_SAMPLES_PER_FRAME*3]; + float pebuf[LPC10_SAMPLES_PER_FRAME*3]; + float lpbuf[696]; + float ivbuf[312]; + float bias; + int32_t osbuf[10]; /* No initial value necessary */ + int32_t osptr; /* Initial value 1 */ + int32_t obound[3]; + int32_t vwin[3][2]; /* Initial value vwin[2][0] = 307; vwin[2][1] = 462; */ + int32_t awin[3][2]; /* Initial value awin[2][0] = 307; awin[2][1] = 462; */ + int32_t voibuf[4][2]; + float rmsbuf[3]; + float rcbuf[3][10]; + float zpre; + + /* State used by function onset */ + float n; + float d__; /* Initial value 1.0f */ + float fpc; /* No initial value necessary */ + float l2buf[16]; + float l2sum1; + int32_t l2ptr1; /* Initial value 1 */ + int32_t l2ptr2; /* Initial value 9 */ + int32_t lasti; /* No initial value necessary */ + int hyst; /* Initial value FALSE */ + + /* State used by function lpc10_voicing */ + float dither; /* Initial value 20.0f */ + float snr; + float maxmin; + float voice[3][2]; /* Initial value is probably unnecessary */ + int32_t lbve; + int32_t lbue; + int32_t fbve; + int32_t fbue; + int32_t ofbue; + int32_t sfbue; + int32_t olbue; + int32_t slbue; + + /* State used by function dynamic_pitch_tracking */ + float s[60]; + int32_t p[2][60]; + int32_t ipoint; + float alphax; + + /* State used by function lpc10_pack */ + int32_t isync; +} lpc10_encode_state_t; + +/*! + LPC10 codec decoder state descriptor. This defines the state of + a single working instance of the LPC10 decoder. +*/ +typedef struct +{ + int error_correction; + + /* State used by function decode */ + int32_t iptold; /* Initial value 60 */ + int first; /* Initial value TRUE */ + int32_t ivp2h; + int32_t iovoic; + int32_t iavgp; /* Initial value 60 */ + int32_t erate; + int32_t drc[10][3]; + int32_t dpit[3]; + int32_t drms[3]; + + /* State used by function synths */ + float buf[LPC10_SAMPLES_PER_FRAME*2]; + int32_t buflen; /* Initial value LPC10_SAMPLES_PER_FRAME */ + + /* State used by function pitsyn */ + int32_t ivoico; /* No initial value necessary as long as first_pitsyn is initially TRUE_ */ + int32_t ipito; /* No initial value necessary as long as first_pitsyn is initially TRUE_ */ + float rmso; /* Initial value 1.0f */ + float rco[10]; /* No initial value necessary as long as first_pitsyn is initially TRUE_ */ + int32_t jsamp; /* Nno initial value necessary as long as first_pitsyn is initially TRUE_ */ + int first_pitsyn; /* Initial value TRUE */ + + /* State used by function bsynz */ + int32_t ipo; + float exc[166]; + float exc2[166]; + float lpi[3]; + float hpi[3]; + float rmso_bsynz; + + /* State used by function random */ + int32_t j; + int32_t k; + int16_t y[5]; + + /* State used by function deemp */ + float dei[2]; + float deo[3]; +} lpc10_decode_state_t; + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/*! Initialise an LPC10e encode context. + \param s The LPC10e context + \param error_correction ??? + \return A pointer to the LPC10e context, or NULL for error. */ +lpc10_encode_state_t *lpc10_encode_init(lpc10_encode_state_t *s, int error_correction); + +int lpc10_encode_release(lpc10_encode_state_t *s); + +/*! Encode a buffer of linear PCM data to LPC10e. + \param s The LPC10e context. + \param ima_data The LPC10e data produced. + \param amp The audio sample buffer. + \param len The number of samples in the buffer. + \return The number of bytes of LPC10e data produced. */ +int lpc10_encode(lpc10_encode_state_t *s, uint8_t code[], const int16_t amp[], int quant); + +/*! Initialise an LPC10e decode context. + \param s The LPC10e context + \param error_correction ??? + \return A pointer to the LPC10e context, or NULL for error. */ +lpc10_decode_state_t *lpc10_decode_init(lpc10_decode_state_t *st, int error_correction); + +int lpc10_decode_release(lpc10_decode_state_t *s); + +/*! Decode a buffer of LPC10e data to linear PCM. + \param s The LPC10e context. + \param amp The audio sample buffer. + \param code The LPC10e data. + \param quant The number of frames of LPC10e data to be decoded. + \return The number of samples returned. */ +int lpc10_decode(lpc10_decode_state_t *s, int16_t amp[], const uint8_t code[], int quant); + + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of include ---------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/voipcodecs/oki_adpcm.h b/libs/voipcodecs/src/voipcodecs/oki_adpcm.h new file mode 100644 index 0000000000..d050a995ee --- /dev/null +++ b/libs/voipcodecs/src/voipcodecs/oki_adpcm.h @@ -0,0 +1,119 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * oki_adpcm.h - Conversion routines between linear 16 bit PCM data and + * OKI (Dialogic) ADPCM format. + * + * Written by Steve Underwood + * + * Copyright (C) 2001 Steve Underwood + * + * Based on a bit from here, a bit from there, eye of toad, + * ear of bat, etc - plus, of course, my own 2 cents. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: oki_adpcm.h,v 1.17 2007/12/13 11:31:33 steveu Exp $ + */ + +/*! \file */ + +#if !defined(_SPANDSP_OKI_ADPCM_H_) +#define _SPANDSP_OKI_ADPCM_H_ + +/*! \page okiadpcm_page OKI (Dialogic) ADPCM encoding and decoding +\section okiadpcm_page_sec_1 What does it do? +OKI ADPCM is widely used in the CTI industry because it is the principal format +supported by Dialogic. As the market leader, they tend to define "common +practice". It offers a good balance of simplicity and quality at rates of +24kbps or 32kbps. 32kbps is obtained by ADPCM compressing 8k samples/second linear +PCM. 24kbps is obtained by resampling to 6k samples/second and using the same ADPCM +compression algorithm on the slower samples. + +The algorithms for this ADPCM codec can be found in "PC Telephony - The complete guide +to designing, building and programming systems using Dialogic and Related Hardware" +by Bob Edgar. pg 272-276. */ + +/*! + Oki (Dialogic) ADPCM conversion state descriptor. This defines the state of + a single working instance of the Oki ADPCM converter. This is used for + either linear to ADPCM or ADPCM to linear conversion. +*/ +typedef struct +{ + /*! \brief The bit rate - 24000 or 32000. */ + int bit_rate; + /*! \brief The last state of the ADPCM algorithm. */ + int16_t last; + /*! \brief Current index into the step size table. */ + int16_t step_index; + /*! \brief The compressed data byte in progress. */ + uint8_t oki_byte; + /*! \brief The signal history for the sample rate converter. */ + int16_t history[32]; + /*! \brief Pointer into the history buffer. */ + int ptr; + /*! \brief Odd/even sample counter. */ + int mark; + /*! \brief Phase accumulator for the sample rate converter. */ + int phase; +} oki_adpcm_state_t; + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/*! Initialise an Oki ADPCM encode or decode context. + \param s The Oki ADPCM context. + \param bit_rate The required bit rate for the ADPCM data. + The valid rates are 24000 and 32000. + \return A pointer to the Oki ADPCM context, or NULL for error. */ +oki_adpcm_state_t *oki_adpcm_init(oki_adpcm_state_t *s, int bit_rate); + +/*! Free an Oki ADPCM encode or decode context. + \param s The Oki ADPCM context. + \return 0 for OK. */ +int oki_adpcm_release(oki_adpcm_state_t *s); + +/*! Decode a buffer of Oki ADPCM data to linear PCM. + \param s The Oki ADPCM context. + \param amp The audio sample buffer. + \param oki_data + \param oki_bytes + \return The number of samples returned. */ +int oki_adpcm_decode(oki_adpcm_state_t *s, + int16_t amp[], + const uint8_t oki_data[], + int oki_bytes); + +/*! Encode a buffer of linear PCM data to Oki ADPCM. + \param s The Oki ADPCM context. + \param oki_data The Oki ADPCM data produced + \param amp The audio sample buffer. + \param len The number of samples in the buffer. + \return The number of bytes of Oki ADPCM data produced. */ +int oki_adpcm_encode(oki_adpcm_state_t *s, + uint8_t oki_data[], + const int16_t amp[], + int len); + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/voipcodecs/telephony.h b/libs/voipcodecs/src/voipcodecs/telephony.h new file mode 100644 index 0000000000..e9f079a27b --- /dev/null +++ b/libs/voipcodecs/src/voipcodecs/telephony.h @@ -0,0 +1,67 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * telephony.h - some very basic telephony definitions + * + * Written by Steve Underwood + * + * Copyright (C) 2003 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: telephony.h,v 1.10 2007/04/05 19:20:50 steveu Exp $ + */ + +#if !defined(_SPANDSP_TELEPHONY_H_) +#define _SPANDSP_TELEPHONY_H_ + +#define SAMPLE_RATE 8000 + +/* This is based on A-law, but u-law is only 0.03dB different */ +#define DBM0_MAX_POWER (3.14f + 3.02f) +#define DBM0_MAX_SINE_POWER (3.14f) +/* This is based on the ITU definition of dbOv in G.100.1 */ +#define DBOV_MAX_POWER (0.0f) +#define DBOV_MAX_SINE_POWER (-3.02f) + +/*! \brief A handler for pure receive. The buffer cannot be altered. */ +typedef int (span_rx_handler_t)(void *s, const int16_t amp[], int len); + +/*! \brief A handler for receive, where the buffer can be altered. */ +typedef int (span_mod_handler_t)(void *s, int16_t amp[], int len); + +/*! \brief A handler for transmit, where the buffer will be filled. */ +typedef int (span_tx_handler_t)(void *s, int16_t amp[], int max_len); + +#define ms_to_samples(t) (((t)*SAMPLE_RATE)/1000) + +#if !defined(FALSE) +#define FALSE 0 +#endif +#if !defined(TRUE) +#define TRUE (!FALSE) +#endif + +#if defined(__cplusplus) +/* C++ doesn't seem to have sane rounding functions/macros yet */ +#ifndef _MSC_VER +#define lrint(x) ((long int) (x)) +#define lrintf(x) ((long int) (x)) +#endif +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/voipcodecs/vector_int.h b/libs/voipcodecs/src/voipcodecs/vector_int.h new file mode 100644 index 0000000000..92591ef096 --- /dev/null +++ b/libs/voipcodecs/src/voipcodecs/vector_int.h @@ -0,0 +1,99 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * vector_int.h + * + * Written by Steve Underwood + * + * Copyright (C) 2003 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: vector_int.h,v 1.8 2007/12/13 11:31:33 steveu Exp $ + */ + +#if !defined(_SPANDSP_VECTOR_INT_H_) +#define _SPANDSP_VECTOR_INT_H_ + +#if defined(__cplusplus) +extern "C" +{ +#endif + +int32_t vec_dot_prodi16(const int16_t x[], const int16_t y[], int n); + +/*! \brief Find the minimum and maximum values in a vector. + \param x The vector to be searched. + \param n The number of elements in the vetor. + \param out A two element vector. The first will receive the + maximum. The second will receive the minimum. This parameter + may be set to NULL. + \return The absolute maximum value. Since the range of negative numbers + exceeds the range of positive one, the returned integer is longer + than the ones being searched. */ +int32_t vec_min_maxi16(const int16_t x[], int n, int16_t out[]); + +static __inline__ int vec_norm2i16(const int16_t *vec, int len) +{ + int i; + int sum; + + sum = 0; + for (i = 0; i < len; i++) + sum += vec[i]*vec[i]; + return sum; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void vec_sari16(int16_t *vec, int len, int shift) +{ + int i; + + for (i = 0; i < len; i++) + vec[i] >>= shift; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int vec_max_bitsi16(const int16_t *vec, int len) +{ + int i; + int max; + int v; + int b; + + max = 0; + for (i = 0; i < len; i++) + { + v = abs(vec[i]); + if (v > max) + max = v; + } + b = 0; + while (max != 0) + { + b++; + max >>= 1; + } + return b; +} +/*- End of function --------------------------------------------------------*/ + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/voipcodecs/version.h b/libs/voipcodecs/src/voipcodecs/version.h new file mode 100644 index 0000000000..9991ad2268 --- /dev/null +++ b/libs/voipcodecs/src/voipcodecs/version.h @@ -0,0 +1,37 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * version.h - A tag file, so the exact installed revision can be assertained. + * + * Written by Steve Underwood + * + * Copyright (C) 2007 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: version.h.in,v 1.2 2007/04/06 13:20:36 steveu Exp $ + */ + +#if !defined(_SPANDSP_VERSION_H_) +#define _SPANDSP_VERSION_H_ + +/* The date and time of the version are in UTC form. */ + +#define SPANDSP_RELEASE_DATE $SPANDSP_RELEASE_DATE +#define SPANDSP_RELEASE_TIME $SPANDSP_RELEASE_TIME + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/voipcodecs/version.h.in b/libs/voipcodecs/src/voipcodecs/version.h.in new file mode 100644 index 0000000000..9991ad2268 --- /dev/null +++ b/libs/voipcodecs/src/voipcodecs/version.h.in @@ -0,0 +1,37 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * version.h - A tag file, so the exact installed revision can be assertained. + * + * Written by Steve Underwood + * + * Copyright (C) 2007 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: version.h.in,v 1.2 2007/04/06 13:20:36 steveu Exp $ + */ + +#if !defined(_SPANDSP_VERSION_H_) +#define _SPANDSP_VERSION_H_ + +/* The date and time of the version are in UTC form. */ + +#define SPANDSP_RELEASE_DATE $SPANDSP_RELEASE_DATE +#define SPANDSP_RELEASE_TIME $SPANDSP_RELEASE_TIME + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/tests/Makefile.am b/libs/voipcodecs/tests/Makefile.am new file mode 100644 index 0000000000..0f9c2a3a1e --- /dev/null +++ b/libs/voipcodecs/tests/Makefile.am @@ -0,0 +1,60 @@ +## +## SpanDSP - a series of DSP components for telephony +## +## Makefile.am -- Process this file with automake to produce Makefile.in +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2, as +## published by the Free Software Foundation. +## +## 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., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## $Id: Makefile.am,v 1.94 2008/01/31 13:34:40 steveu Exp $ + +AM_CFLAGS = $(COMP_VENDOR_CFLAGS) + +LIBS += $(TESTLIBS) + +EXTRA_DIST = regression_tests.sh + +MAINTAINERCLEANFILES = Makefile.in + +INCLUDES = -I$(top_builddir)/src -DDATADIR="\"$(pkgdatadir)\"" + +LIBDIR = -L$(top_builddir)/src + +noinst_PROGRAMS = g711_tests \ + g722_tests \ + g726_tests \ + gsm0610_tests \ + ima_adpcm_tests \ + lpc10_tests \ + oki_adpcm_tests + +g711_tests_SOURCES = g711_tests.c +g711_tests_LDADD = $(LIBDIR) -lvoipcodecs -lspandsp + +g722_tests_SOURCES = g722_tests.c +g722_tests_LDADD = $(LIBDIR) -lvoipcodecs + +g726_tests_SOURCES = g726_tests.c +g726_tests_LDADD = $(LIBDIR) -lvoipcodecs + +gsm0610_tests_SOURCES = gsm0610_tests.c +gsm0610_tests_LDADD = $(LIBDIR) -lvoipcodecs + +ima_adpcm_tests_SOURCES = ima_adpcm_tests.c +ima_adpcm_tests_LDADD = $(LIBDIR) -lvoipcodecs + +lpc10_tests_SOURCES = lpc10_tests.c +lpc10_tests_LDADD = $(LIBDIR) -lvoipcodecs + +oki_adpcm_tests_SOURCES = oki_adpcm_tests.c +oki_adpcm_tests_LDADD = $(LIBDIR) -lvoipcodecs diff --git a/libs/voipcodecs/tests/g711_tests.c b/libs/voipcodecs/tests/g711_tests.c new file mode 100644 index 0000000000..d99f3201e2 --- /dev/null +++ b/libs/voipcodecs/tests/g711_tests.c @@ -0,0 +1,287 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * g711_tests.c + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: g711_tests.c,v 1.7 2007/11/10 11:14:58 steveu Exp $ + */ + +/*! \page g711_tests_page A-law and u-law conversion tests +\section g711_tests_page_sec_1 What does it do? + +\section g711_tests_page_sec_2 How is it used? +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "voipcodecs.h" +#include + +#define OUT_FILE_NAME "g711.wav" + +int16_t amp[65536]; + +const uint8_t alaw_1khz_sine[] = {0x34, 0x21, 0x21, 0x34, 0xB4, 0xA1, 0xA1, 0xB4}; +const uint8_t ulaw_1khz_sine[] = {0x1E, 0x0B, 0x0B, 0x1E, 0x9E, 0x8B, 0x8B, 0x9E}; + +int main(int argc, char *argv[]) +{ + AFfilehandle outhandle; + AFfilesetup filesetup; + power_meter_t power_meter; + int outframes; + int i; + int block; + int pre; + int post; + int post_post; + int alaw_failures; + int ulaw_failures; + float worst_alaw; + float worst_ulaw; + float tmp; + + if ((filesetup = afNewFileSetup()) == AF_NULL_FILESETUP) + { + fprintf(stderr, " Failed to create file setup\n"); + exit(2); + } + afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16); + afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE); + afInitFileFormat(filesetup, AF_FILE_WAVE); + afInitChannels(filesetup, AF_DEFAULT_TRACK, 1); + + if ((outhandle = afOpenFile(OUT_FILE_NAME, "w", filesetup)) == AF_NULL_FILEHANDLE) + { + fprintf(stderr, " Cannot create wave file '%s'\n", OUT_FILE_NAME); + exit(2); + } + + printf("Conversion accuracy tests.\n"); + alaw_failures = 0; + ulaw_failures = 0; + worst_alaw = 0.0; + worst_ulaw = 0.0; + for (block = 0; block < 1; block++) + { + for (i = 0; i < 65536; i++) + { + pre = i - 32768; + post = alaw_to_linear(linear_to_alaw(pre)); + if (abs(pre) > 140) + { + tmp = (float) abs(post - pre)/(float) abs(pre); + if (tmp > 0.10) + { + printf("A-law: Excessive error at %d (%d)\n", pre, post); + alaw_failures++; + } + if (tmp > worst_alaw) + worst_alaw = tmp; + } + else + { + /* Small values need different handling for sensible measurement */ + if (abs(post - pre) > 15) + { + printf("A-law: Excessive error at %d (%d)\n", pre, post); + alaw_failures++; + } + } + amp[i] = post; + } + outframes = afWriteFrames(outhandle, + AF_DEFAULT_TRACK, + amp, + 65536); + if (outframes != 65536) + { + fprintf(stderr, " Error writing wave file\n"); + exit(2); + } + for (i = 0; i < 65536; i++) + { + pre = i - 32768; + post = ulaw_to_linear(linear_to_ulaw(pre)); + if (abs(pre) > 40) + { + tmp = (float) abs(post - pre)/(float) abs(pre); + if (tmp > 0.10) + { + printf("u-law: Excessive error at %d (%d)\n", pre, post); + ulaw_failures++; + } + if (tmp > worst_ulaw) + worst_ulaw = tmp; + } + else + { + /* Small values need different handling for sensible measurement */ + if (abs(post - pre) > 4) + { + printf("u-law: Excessive error at %d (%d)\n", pre, post); + ulaw_failures++; + } + } + amp[i] = post; + } + outframes = afWriteFrames(outhandle, + AF_DEFAULT_TRACK, + amp, + 65536); + if (outframes != 65536) + { + fprintf(stderr, " Error writing wave file\n"); + exit(2); + } + } + printf("Worst A-law error (ignoring small values) %f%%\n", worst_alaw*100.0); + printf("Worst u-law error (ignoring small values) %f%%\n", worst_ulaw*100.0); + if (alaw_failures || ulaw_failures) + { + printf("%d A-law values with excessive error\n", alaw_failures); + printf("%d u-law values with excessive error\n", ulaw_failures); + printf("Tests failed\n"); + exit(2); + } + + printf("Cyclic conversion repeatability tests.\n"); + /* Find what happens to every possible linear value after a round trip. */ + for (i = 0; i < 65536; i++) + { + pre = i - 32768; + /* Make a round trip */ + post = alaw_to_linear(linear_to_alaw(pre)); + /* A second round trip should cause no further change */ + post_post = alaw_to_linear(linear_to_alaw(post)); + if (post_post != post) + { + printf("A-law second round trip mismatch - at %d, %d != %d\n", pre, post, post_post); + printf("Tests failed\n"); + exit(2); + } + /* Make a round trip */ + post = ulaw_to_linear(linear_to_ulaw(pre)); + /* A second round trip should cause no further change */ + post_post = ulaw_to_linear(linear_to_ulaw(post)); + if (post_post != post) + { + printf("u-law round trip mismatch - at %d, %d != %d\n", pre, post, post_post); + printf("Tests failed\n"); + exit(2); + } + } + + printf("Reference power level tests.\n"); + power_meter_init(&power_meter, 7); + + for (i = 0; i < 8000; i++) + { + amp[i] = ulaw_to_linear(ulaw_1khz_sine[i & 7]); + power_meter_update(&power_meter, amp[i]); + } + printf("Reference u-law 1kHz tone is %fdBm0\n", power_meter_current_dbm0(&power_meter)); + outframes = afWriteFrames(outhandle, + AF_DEFAULT_TRACK, + amp, + 8000); + if (outframes != 8000) + { + fprintf(stderr, " Error writing wave file\n"); + exit(2); + } + if (0.1f < fabs(power_meter_current_dbm0(&power_meter))) + { + printf("Test failed.\n"); + exit(2); + } + + for (i = 0; i < 8000; i++) + { + amp[i] = alaw_to_linear(alaw_1khz_sine[i & 7]); + power_meter_update(&power_meter, amp[i]); + } + printf("Reference A-law 1kHz tone is %fdBm0\n", power_meter_current_dbm0(&power_meter)); + outframes = afWriteFrames(outhandle, + AF_DEFAULT_TRACK, + amp, + 8000); + if (outframes != 8000) + { + fprintf(stderr, " Error writing wave file\n"); + exit(2); + } + if (0.1f < fabs(power_meter_current_dbm0(&power_meter))) + { + printf("Test failed.\n"); + exit(2); + } + + /* Check the transcoding functions. */ + printf("Testing transcoding A-law -> u-law -> A-law\n"); + for (i = 0; i < 256; i++) + { + if (alaw_to_ulaw(ulaw_to_alaw(i)) != i) + { + if (abs(alaw_to_ulaw(ulaw_to_alaw(i)) - i) > 1) + { + printf("u-law -> A-law -> u-law gave %d -> %d\n", i, alaw_to_ulaw(ulaw_to_alaw(i))); + printf("Test failed\n"); + exit(2); + } + } + } + + printf("Testing transcoding u-law -> A-law -> u-law\n"); + for (i = 0; i < 256; i++) + { + if (ulaw_to_alaw(alaw_to_ulaw(i)) != i) + { + if (abs(alaw_to_ulaw(ulaw_to_alaw(i)) - i) > 1) + { + printf("A-law -> u-law -> A-law gave %d -> %d\n", i, ulaw_to_alaw(alaw_to_ulaw(i))); + printf("Test failed\n"); + exit(2); + } + } + } + + if (afCloseFile(outhandle)) + { + fprintf(stderr, " Cannot close wave file '%s'\n", OUT_FILE_NAME); + exit(2); + } + afFreeFileSetup(filesetup); + + printf("Tests passed.\n"); + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/tests/g722_tests.c b/libs/voipcodecs/tests/g722_tests.c new file mode 100644 index 0000000000..bf281ffb84 --- /dev/null +++ b/libs/voipcodecs/tests/g722_tests.c @@ -0,0 +1,521 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * g722_tests.c - Test G.722 encode and decode. + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: g722_tests.c,v 1.19 2007/11/10 11:14:58 steveu Exp $ + */ + +/*! \file */ + +/*! \page g722_tests_page G.722 tests +\section g722_tests_page_sec_1 What does it do? +This modules implements two sets of tests: + - The tests defined in the G.722 specification, using the test data files supplied + with the specification. + - A generally audio quality test, consisting of compressing and decompressing a speeech + file for audible comparison. + +The speech file should be recorded at 16 bits/sample, 16000 samples/second, and named +"pre_g722.wav". + +The ITU tests use the codec in a special mode, in which the QMFs, which split and recombine the +sub-bands, are disabled. This means they do not test 100% of the codec. This is the reason for +including the additional listening test. + +\section g722_tests_page_sec_2 How is it used? +To perform the tests in the G.722 specification you need to obtain the test data files from the +specification. These are copyright material, and so cannot be distributed with this test software. + +The files, containing test vectors, which are supplied with the G.722 specification, should be +copied to itutests/g722. The ITU tests can then be run by executing g722_tests without +any parameters. + +To perform a general audio quality test, g722_tests should be run with a parameter specifying +the required bit rate for compression. The valid parameters are "-48", "-56", and "-64". +The file ../localtests/short_wb_voice.wav will be compressed to the specified bit rate, decompressed, +and the resulting audio stored in post_g722.wav. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "voipcodecs.h" + +#define G722_SAMPLE_RATE 16000 + +#define BLOCK_LEN 320 + +#define MAX_TEST_VECTOR_LEN 40000 + +#define TESTDATA_DIR "../itutests/g722/" + +#define EIGHTK_IN_FILE_NAME "../localtests/short_nb_voice.wav" +#define IN_FILE_NAME "../localtests/short_wb_voice.wav" +#define OUT_FILE_NAME "post_g722.wav" + +#if 0 +static const char *itu_test_files[] = +{ + TESTDATA_DIR "T1C1.XMT", /* 69973 bytes */ + TESTDATA_DIR "T1C2.XMT", /* 3605 bytes */ + TESTDATA_DIR "T1D3.COD", /* 69973 bytes */ + + TESTDATA_DIR "T2R1.COD", /* 69973 bytes */ + TESTDATA_DIR "T2R2.COD", /* 3605 bytes */ + + TESTDATA_DIR "T3L1.RC1", /* 69973 bytes */ + TESTDATA_DIR "T3L1.RC2", /* 69973 bytes */ + TESTDATA_DIR "T3L1.RC3", /* 69973 bytes */ + TESTDATA_DIR "T3H1.RC0", /* 69973 bytes */ + TESTDATA_DIR "T3L2.RC1", /* 3605 bytes */ + TESTDATA_DIR "T3L2.RC2", /* 3605 bytes */ + TESTDATA_DIR "T3L2.RC3", /* 3605 bytes */ + TESTDATA_DIR "T3H2.RC0", /* 3605 bytes */ + TESTDATA_DIR "T3L3.RC1", /* 69973 bytes */ + TESTDATA_DIR "T3L3.RC2", /* 69973 bytes */ + TESTDATA_DIR "T3L3.RC3", /* 69973 bytes */ + TESTDATA_DIR "T3H3.RC0" /* 69973 bytes */ +}; +#endif + +static const char *encode_test_files[] = +{ + TESTDATA_DIR "T1C1.XMT", TESTDATA_DIR "T2R1.COD", + TESTDATA_DIR "T1C2.XMT", TESTDATA_DIR "T2R2.COD", + NULL +}; + +static const char *decode_test_files[] = +{ + TESTDATA_DIR "T2R1.COD", + TESTDATA_DIR "T3L1.RC1", + TESTDATA_DIR "T3L1.RC2", + TESTDATA_DIR "T3L1.RC3", + TESTDATA_DIR "T3H1.RC0", + + TESTDATA_DIR "T2R2.COD", + TESTDATA_DIR "T3L2.RC1", + TESTDATA_DIR "T3L2.RC2", + TESTDATA_DIR "T3L2.RC3", + TESTDATA_DIR "T3H2.RC0", + + TESTDATA_DIR "T1D3.COD", + TESTDATA_DIR "T3L3.RC1", + TESTDATA_DIR "T3L3.RC2", + TESTDATA_DIR "T3L3.RC3", + TESTDATA_DIR "T3H3.RC0", + + NULL +}; + +int16_t itu_data[MAX_TEST_VECTOR_LEN]; +uint16_t itu_ref[MAX_TEST_VECTOR_LEN]; +uint16_t itu_ref_upper[MAX_TEST_VECTOR_LEN]; +uint8_t compressed[MAX_TEST_VECTOR_LEN]; +int16_t decompressed[MAX_TEST_VECTOR_LEN]; + +static int hex_get(char *s) +{ + int i; + int value; + int x; + + for (value = i = 0; i < 4; i++) + { + x = *s++ - 0x30; + if (x > 9) + x -= 0x07; + if (x > 15) + x -= 0x20; + if (x < 0 || x > 15) + return -1; + value <<= 4; + value |= x; + } + return value; +} +/*- End of function --------------------------------------------------------*/ + +static int get_vector(FILE *file, uint16_t vec[]) +{ + char buf[132 + 1]; + char *s; + int i; + int value; + + while (fgets(buf, 133, file)) + { + if (buf[0] == '/' && buf[1] == '*') + continue; + s = buf; + i = 0; + while ((value = hex_get(s)) >= 0) + { + vec[i++] = value; + s += 4; + } + return i; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int get_test_vector(const char *file, uint16_t buf[], int max_len) +{ + int octets; + int i; + FILE *infile; + + if ((infile = fopen(file, "r")) == NULL) + { + fprintf(stderr, " Failed to open '%s'\n", file); + exit(2); + } + octets = 0; + while ((i = get_vector(infile, buf + octets)) > 0) + octets += i; + fclose(infile); + return octets; +} +/*- End of function --------------------------------------------------------*/ + +int main(int argc, char *argv[]) +{ + g722_encode_state_t enc_state; + g722_decode_state_t dec_state; + int len; + int len_comp; + int len_comp_upper; + int len_data; + int len2; + int len3; + int i; + int j; + int k; + int file; + AFfilehandle inhandle; + AFfilehandle outhandle; + AFfilesetup filesetup; + int outframes; + int samples; + int mode; + int itutests; + int bit_rate; + int eight_k_in; + int eight_k_out; + float x; + int16_t indata[BLOCK_LEN]; + int16_t outdata[BLOCK_LEN]; + uint8_t adpcmdata[BLOCK_LEN]; + + i = 1; + bit_rate = 64000; + eight_k_in = FALSE; + eight_k_out = FALSE; + itutests = TRUE; + while (argc > i) + { + if (strcmp(argv[i], "-48") == 0) + { + bit_rate = 48000; + itutests = FALSE; + i++; + } + else if (strcmp(argv[i], "-56") == 0) + { + bit_rate = 56000; + itutests = FALSE; + i++; + } + else if (strcmp(argv[i], "-64") == 0) + { + bit_rate = 64000; + itutests = FALSE; + i++; + } + else if (strcmp(argv[i], "-8k8k") == 0) + { + eight_k_in = TRUE; + eight_k_out = TRUE; + i++; + } + else if (strcmp(argv[i], "-8k16k") == 0) + { + eight_k_in = TRUE; + eight_k_out = FALSE; + i++; + } + else if (strcmp(argv[i], "-16k8k") == 0) + { + eight_k_in = FALSE; + eight_k_out = TRUE; + i++; + } + else if (strcmp(argv[i], "-16k16k") == 0) + { + eight_k_in = FALSE; + eight_k_out = FALSE; + i++; + } + else + { + fprintf(stderr, "Unknown parameter %s specified.\n", argv[i]); + exit(2); + } + } + + if (itutests) + { + /* ITU G.722 encode tests, using configuration 1. The QMF is bypassed */ + for (file = 0; encode_test_files[file]; file += 2) + { + printf("Testing %s -> %s\n", encode_test_files[file], encode_test_files[file + 1]); + + /* Get the input data */ + len_data = get_test_vector(encode_test_files[file], (uint16_t *) itu_data, MAX_TEST_VECTOR_LEN); + + /* Get the reference output data */ + len_comp = get_test_vector(encode_test_files[file + 1], itu_ref, MAX_TEST_VECTOR_LEN); + + /* Process the input data */ + /* Skip the reset stuff at each end of the data */ + for (i = 0; i < len_data; i++) + { + if ((itu_data[i] & 1) == 0) + break; + } + for (j = i; j < len_data; j++) + { + if ((itu_data[j] & 1)) + break; + } + len = j - i; + g722_encode_init(&enc_state, 64000, 0); + enc_state.itu_test_mode = TRUE; + len2 = g722_encode(&enc_state, compressed, itu_data + i, len); + + /* Check the result against the ITU's reference output data */ + j = 0; + for (k = 0; k < len2; k++) + { + if ((compressed[k] & 0xFF) != ((itu_ref[k + i] >> 8) & 0xFF)) + { + printf(">>> %6d %4x %4x\n", k, compressed[k] & 0xFF, itu_ref[k + i] & 0xFFFF); + j++; + } + } + printf("%d bad samples, out of %d/%d samples\n", j, len, len_data); + if (j) + { + printf("Test failed\n"); + exit(2); + } + printf("Test passed\n"); + } + + /* ITU G.722 decode tests, using configuration 2. The QMF is bypassed */ + /* Run each of the tests for each of the modes - 48kbps, 56kbps and 64kbps. */ + for (mode = 1; mode <= 3; mode++) + { + for (file = 0; decode_test_files[file]; file += 5) + { + printf("Testing mode %d, %s -> %s + %s\n", + mode, + decode_test_files[file], + decode_test_files[file + mode], + decode_test_files[file + 4]); + + /* Get the input data */ + len_data = get_test_vector(decode_test_files[file], (uint16_t *) itu_data, MAX_TEST_VECTOR_LEN); + + /* Get the lower reference output data */ + len_comp = get_test_vector(decode_test_files[file + mode], itu_ref, MAX_TEST_VECTOR_LEN); + + /* Get the upper reference output data */ + len_comp_upper = get_test_vector(decode_test_files[file + 4], itu_ref_upper, MAX_TEST_VECTOR_LEN); + + /* Process the input data */ + /* Skip the reset stuff at each end of the data */ + for (i = 0; i < len_data; i++) + { + if ((itu_data[i] & 1) == 0) + break; + } + for (j = i; j < len_data; j++) + { + if ((itu_data[j] & 1)) + break; + } + len = j - i; + for (k = 0; k < len; k++) + compressed[k] = itu_data[k + i] >> ((mode == 3) ? 10 : (mode == 2) ? 9 : 8); + + g722_decode_init(&dec_state, (mode == 3) ? 48000 : (mode == 2) ? 56000 : 64000, 0); + dec_state.itu_test_mode = TRUE; + len2 = g722_decode(&dec_state, decompressed, compressed, len); + + /* Check the result against the ITU's reference output data */ + j = 0; + for (k = 0; k < len2; k += 2) + { + if ((decompressed[k] & 0xFFFF) != (itu_ref[(k >> 1) + i] & 0xFFFF) + || + (decompressed[k + 1] & 0xFFFF) != (itu_ref_upper[(k >> 1) + i] & 0xFFFF)) + { + printf(">>> %6d %4x %4x %4x %4x\n", k >> 1, decompressed[k] & 0xFFFF, decompressed[k + 1] & 0xFFFF, itu_ref[(k >> 1) + i] & 0xFFFF, itu_ref_upper[(k >> 1) + i] & 0xFFFF); + j++; + } + } + printf("%d bad samples, out of %d/%d samples\n", j, len, len_data); + if (j) + { + printf("Test failed\n"); + exit(2); + } + printf("Test passed\n"); + } + } + + printf("Tests passed.\n"); + } + else + { + if (eight_k_in) + { + if ((inhandle = afOpenFile(EIGHTK_IN_FILE_NAME, "r", NULL)) == AF_NULL_FILEHANDLE) + { + fprintf(stderr, " Cannot open wave file '%s'\n", EIGHTK_IN_FILE_NAME); + exit(2); + } + if ((x = afGetFrameSize(inhandle, AF_DEFAULT_TRACK, 1)) != 2.0) + { + printf(" Unexpected frame size in wave file '%s'\n", EIGHTK_IN_FILE_NAME); + exit(2); + } + if ((x = afGetRate(inhandle, AF_DEFAULT_TRACK)) != (float) SAMPLE_RATE) + { + printf(" Unexpected sample rate %f in wave file '%s'\n", x, EIGHTK_IN_FILE_NAME); + exit(2); + } + if ((x = afGetChannels(inhandle, AF_DEFAULT_TRACK)) != 1.0) + { + printf(" Unexpected number of channels in wave file '%s'\n", EIGHTK_IN_FILE_NAME); + exit(2); + } + } + else + { + if ((inhandle = afOpenFile(IN_FILE_NAME, "r", NULL)) == AF_NULL_FILEHANDLE) + { + fprintf(stderr, " Cannot open wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if ((x = afGetFrameSize(inhandle, AF_DEFAULT_TRACK, 1)) != 2.0) + { + printf(" Unexpected frame size in wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if ((x = afGetRate(inhandle, AF_DEFAULT_TRACK)) != (float) G722_SAMPLE_RATE) + { + printf(" Unexpected sample rate %f in wave file '%s'\n", x, IN_FILE_NAME); + exit(2); + } + if ((x = afGetChannels(inhandle, AF_DEFAULT_TRACK)) != 1.0) + { + printf(" Unexpected number of channels in wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + } + + if ((filesetup = afNewFileSetup()) == AF_NULL_FILESETUP) + { + fprintf(stderr, " Failed to create file setup\n"); + exit(2); + } + afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16); + if (eight_k_out) + afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE); + else + afInitRate(filesetup, AF_DEFAULT_TRACK, (float) G722_SAMPLE_RATE); + afInitFileFormat(filesetup, AF_FILE_WAVE); + afInitChannels(filesetup, AF_DEFAULT_TRACK, 1); + if ((outhandle = afOpenFile(OUT_FILE_NAME, "w", filesetup)) == AF_NULL_FILEHANDLE) + { + fprintf(stderr, " Cannot create wave file '%s'\n", OUT_FILE_NAME); + exit(2); + } + if (eight_k_in) + g722_encode_init(&enc_state, bit_rate, G722_PACKED | G722_SAMPLE_RATE_8000); + else + g722_encode_init(&enc_state, bit_rate, G722_PACKED); + if (eight_k_out) + g722_decode_init(&dec_state, bit_rate, G722_PACKED | G722_SAMPLE_RATE_8000); + else + g722_decode_init(&dec_state, bit_rate, G722_PACKED); + for (;;) + { + samples = afReadFrames(inhandle, + AF_DEFAULT_TRACK, + indata, + BLOCK_LEN); + if (samples <= 0) + break; + len2 = g722_encode(&enc_state, adpcmdata, indata, samples); + len3 = g722_decode(&dec_state, outdata, adpcmdata, len2); + outframes = afWriteFrames(outhandle, + AF_DEFAULT_TRACK, + outdata, + len3); + if (outframes != len3) + { + fprintf(stderr, " Error writing wave file\n"); + exit(2); + } + } + if (afCloseFile(inhandle)) + { + fprintf(stderr, " Cannot close wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if (afCloseFile(outhandle)) + { + fprintf(stderr, " Cannot close wave file '%s'\n", OUT_FILE_NAME); + exit(2); + } + afFreeFileSetup(filesetup); + + printf("'%s' transcoded to '%s' at %dbps.\n", IN_FILE_NAME, OUT_FILE_NAME, bit_rate); + } + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/tests/g726_tests.c b/libs/voipcodecs/tests/g726_tests.c new file mode 100644 index 0000000000..91fb64a798 --- /dev/null +++ b/libs/voipcodecs/tests/g726_tests.c @@ -0,0 +1,1334 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * g726_tests.c - Test G.726 encode and decode. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: g726_tests.c,v 1.17 2007/11/10 11:14:58 steveu Exp $ + */ + +/*! \file */ + +/*! \page g726_tests_page G.726 tests +\section g726_tests_page_sec_1 What does it do? +Two sets of tests are performed: + - The tests defined in the G.726 specification, using the test data files supplied with + the specification. + - A generally audio quality test, consisting of compressing and decompressing a speeech + file for audible comparison. + +The speech file should be recorded at 16 bits/sample, 8000 samples/second, and named +"pre_g726.wav". + +\section g726_tests_page_sec_2 How is it used? +To perform the tests in the G.726 specification you need to obtain the test data files from the +specification. These are copyright material, and so cannot be distributed with this test software. + +The files, containing test vectors, which are supplied with the G.726 specification, should be +copied to itutests/g726 so the files are arranged in the same directory heirarchy in which they +are supplied. That is, you should have file names like + + - itutests/g726/DISK1/INPUT/NRM.M + - itutests/g726/DISK1/INPUT/OVR.M + - itutests/g726/DISK2/INPUT/NRM.A + - itutests/g726/DISK2/INPUT/OVR.A + +in your source tree. The ITU tests can then be run by executing g726_tests without +any parameters. + +To perform a general audio quality test, g726_tests should be run with a parameter specifying +the required bit rate for compression. The valid parameters are "-16", "-24", "-32", and "-40". +The test file ../localtests/short_nb_voice.wav will be compressed to the specified bit rate, +decompressed, and the resulting audio stored in post_g726.wav. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "voipcodecs.h" + +#define BLOCK_LEN 320 +#define MAX_TEST_VECTOR_LEN 40000 + +#define IN_FILE_NAME "../localtests/short_nb_voice.wav" +#define OUT_FILE_NAME "post_g726.wav" + +#define TESTDATA_DIR "../itutests/g726/" + +int16_t outdata[MAX_TEST_VECTOR_LEN]; +uint8_t adpcmdata[MAX_TEST_VECTOR_LEN]; + +int16_t itudata[MAX_TEST_VECTOR_LEN]; +uint8_t itu_ref[MAX_TEST_VECTOR_LEN]; +uint8_t unpacked[MAX_TEST_VECTOR_LEN]; +uint8_t xlaw[MAX_TEST_VECTOR_LEN]; + +/* +Table 4 - V Reset and homing sequences for u-law + Normal I-input Overload +Algorithm Input Intermediate Output Input Output Input Intermediate Output + (PCM) (ADPCM) (PCM) (ADPCM) (PCM) (PCM) (ADPCM) (PCM) + +16F NRM.M RN16FM.I RN16FM.O I16 RI16FM.O OVR.M RV16FM.I RV16FM.O + HN16FM.I HN16FM.O HI16FM.O HV16FM.I HV16FM.O + +24F NRM.M RN24FM.I RN24FM.O I24 RI24FM.O OVR.M RV24FM.I RV24FM.O + HN24FM.I HN24FM.O HI24FM.O HV24FM.I HV24FM.O + +32F NRM.M RN32FM.I RN32FM.O I32 RI32FM.O OVR.M RV32FM.I RV32FM.O + HN32FM.I HN32FM.O HI32FM.O HV32FM.I HV32FM.O + +40F NRM.M RN40FM.I RN40FM.O I40 RI40FM.O OVR.M RV40FM.I RV40FM.O + HN40FM.I HN40FM.O HI40FM.O HV40FM.I HV40FM.O + + +Table 5 - V Reset and homing sequences for A-law + Normal I-input Overload +Algorithm Input Intermediate Output Input Output Input Intermediate Output + (PCM) (ADPCM) (PCM) (ADPCM) (PCM) (PCM) (ADPCM) (PCM) +16F NRM.A RN16FA.I RN16FA.O I16 RI16FA.O OVR.A RV16FA.I RV16FA.O + HN16FA.I HN16FA.O HI16FA.O HV16FA.I HV16FA.O + +24F NRM.A RN24FA.I RN24FA.O I24 RI24FA.O OVR.A RV24FA.I RV24FA.O + HN24FA.I HN24FA.O HI24FA.O HV24FA.I HV24FA.O + +32F NRM.A RN32FA.I RN32FA.O I32 RI32FA.O OVR.A RV32FA.I RV32FA.O + HN32FA.I HN32FA.O HI32FA.O HV32FA.I HV32FA.O + +40F NRM.A RN40FA.I RN40FA.O I40 RI40FA.O OVR.A RV40FA.I RV40FA.O + HN40FA.I HN40FA.O HI40FA.O HV40FA.I HV40FA.O + +Table 6 ¡V Reset and homing cross sequences for u-law -> A-law + Normal Overload +Algorithm Input Intermediate Output Input Intermediate Output + (PCM) (ADPCM) (PCM) (PCM) (ADPCM) (PCM) +16F NRM.M RN16FM.I RN16FC.O OVR.M RV16FM.I RV16FC.O + HN16FM.I HN16FC.O HV16FM.I HV16FC.O + +24F NRM.M RN24FM.I RN24FC.O OVR.M RV24FM.I RV24FC.O + HN24FM.I HN24FC.O HV24FM.I HV24FC.O + +32F NRM.M RN32FM.I RN32FC.O OVR.M RV32FM.I RV32FC.O + HN32FM.I HN32FC.O HV32FM.I HV32FC.O + +40F NRM.M RN40FM.I RN40FC.O OVR.M RV40FM.I RV40FC.O + HN40FM.I HN40FC.O HV40FM.I HV40FC.O + +Table 7 ¡V Reset and homing cross sequences for A-law -> u-law + Normal Overload +Algorithm Input Intermediate Output Input Intermediate Output + (PCM) (ADPCM) (PCM) (PCM) (ADPCM) (PCM) +16F NRM.A RN16FA.I RN16FX.O OVR.A RV16FA.I RV16FX.O + HN16FA.I HN16FX.O HV16FA.I HV16FX.O + +24F NRM.A RN24FA.I RN24FX.O OVR.A RV24FA.I RV24FX.O + HN24FA.I HN24FX.O HV24FA.I HV24FX.O + +32F NRM.A RN32FA.I RN32FX.O OVR.A RV32FA.I RV32FX.O + HN32FA.I HN32FX.O HV32FA.I HV32FX.O + +40F NRM.A RN40FA.I RN40FX.O OVR.A RV40FA.I RV40FX.O + HN40FA.I HN40FX.O HV40FA.I HV40FX.O +*/ + +#define G726_ENCODING_NONE 9999 + +typedef struct +{ + const char *conditioning_pcm_file; + const char *pcm_file; + const char *conditioning_adpcm_file; + const char *adpcm_file; + const char *output_file; + int rate; + int compression_law; + int decompression_law; +} test_set_t; + +static test_set_t itu_test_sets[] = +{ + /* u-law to u-law tests */ + { + "", + TESTDATA_DIR "DISK1/INPUT/NRM.M", + "", + TESTDATA_DIR "DISK1/RESET/16/RN16FM.I", + TESTDATA_DIR "DISK1/RESET/16/RN16FM.O", + 16000, + G726_ENCODING_ULAW, + G726_ENCODING_ULAW + }, + { + "", + "", + "", + TESTDATA_DIR "DISK1/INPUT/I16", + TESTDATA_DIR "DISK1/RESET/16/RI16FM.O", + 16000, + G726_ENCODING_NONE, + G726_ENCODING_ULAW + }, + { + "", + TESTDATA_DIR "DISK1/INPUT/OVR.M", + "", + TESTDATA_DIR "DISK1/RESET/16/RV16FM.I", + TESTDATA_DIR "DISK1/RESET/16/RV16FM.O", + 16000, + G726_ENCODING_ULAW, + G726_ENCODING_ULAW + }, + { + "", + TESTDATA_DIR "DISK1/INPUT/NRM.M", + "", + TESTDATA_DIR "DISK1/RESET/24/RN24FM.I", + TESTDATA_DIR "DISK1/RESET/24/RN24FM.O", + 24000, + G726_ENCODING_ULAW, + G726_ENCODING_ULAW + }, + { + "", + "", + "", + TESTDATA_DIR "DISK1/INPUT/I24", + TESTDATA_DIR "DISK1/RESET/24/RI24FM.O", + 24000, + G726_ENCODING_NONE, + G726_ENCODING_ULAW + }, + { + "", + TESTDATA_DIR "DISK1/INPUT/OVR.M", + "", + TESTDATA_DIR "DISK1/RESET/24/RV24FM.I", + TESTDATA_DIR "DISK1/RESET/24/RV24FM.O", + 24000, + G726_ENCODING_ULAW, + G726_ENCODING_ULAW + }, + { + "", + TESTDATA_DIR "DISK1/INPUT/NRM.M", + "", + TESTDATA_DIR "DISK1/RESET/32/RN32FM.I", + TESTDATA_DIR "DISK1/RESET/32/RN32FM.O", + 32000, + G726_ENCODING_ULAW, + G726_ENCODING_ULAW + }, + { + "", + "", + "", + TESTDATA_DIR "DISK1/INPUT/I32", + TESTDATA_DIR "DISK1/RESET/32/RI32FM.O", + 32000, + G726_ENCODING_NONE, + G726_ENCODING_ULAW + }, + { + "", + TESTDATA_DIR "DISK1/INPUT/OVR.M", + "", + TESTDATA_DIR "DISK1/RESET/32/RV32FM.I", + TESTDATA_DIR "DISK1/RESET/32/RV32FM.O", + 32000, + G726_ENCODING_ULAW, + G726_ENCODING_ULAW + }, + { + "", + TESTDATA_DIR "DISK1/INPUT/NRM.M", + "", + TESTDATA_DIR "DISK1/RESET/40/RN40FM.I", + TESTDATA_DIR "DISK1/RESET/40/RN40FM.O", + 40000, + G726_ENCODING_ULAW, + G726_ENCODING_ULAW + }, + { + "", + "", + "", + TESTDATA_DIR "DISK1/INPUT/I40", + TESTDATA_DIR "DISK1/RESET/40/RI40FM.O", + 40000, + G726_ENCODING_NONE, + G726_ENCODING_ULAW + }, + { + "", + TESTDATA_DIR "DISK1/INPUT/OVR.M", + "", + TESTDATA_DIR "DISK1/RESET/40/RV40FM.I", + TESTDATA_DIR "DISK1/RESET/40/RV40FM.O", + 40000, + G726_ENCODING_ULAW, + G726_ENCODING_ULAW + }, + /* A-law to A-law tests */ + { + "", + TESTDATA_DIR "DISK2/INPUT/NRM.A", + "", + TESTDATA_DIR "DISK2/RESET/16/RN16FA.I", + TESTDATA_DIR "DISK2/RESET/16/RN16FA.O", + 16000, + G726_ENCODING_ALAW, + G726_ENCODING_ALAW + }, + { + "", + "", + "", + TESTDATA_DIR "DISK2/INPUT/I16", + TESTDATA_DIR "DISK2/RESET/16/RI16FA.O", + 16000, + G726_ENCODING_NONE, + G726_ENCODING_ALAW + }, + { + "", + TESTDATA_DIR "DISK2/INPUT/OVR.A", + "", + TESTDATA_DIR "DISK2/RESET/16/RV16FA.I", + TESTDATA_DIR "DISK2/RESET/16/RV16FA.O", + 16000, + G726_ENCODING_ALAW, + G726_ENCODING_ALAW + }, + { + "", + TESTDATA_DIR "DISK2/INPUT/NRM.A", + "", + TESTDATA_DIR "DISK2/RESET/24/RN24FA.I", + TESTDATA_DIR "DISK2/RESET/24/RN24FA.O", + 24000, + G726_ENCODING_ALAW, + G726_ENCODING_ALAW + }, + { + "", + "", + "", + TESTDATA_DIR "DISK2/INPUT/I24", + TESTDATA_DIR "DISK2/RESET/24/RI24FA.O", + 24000, + G726_ENCODING_NONE, + G726_ENCODING_ALAW + }, + { + "", + TESTDATA_DIR "DISK2/INPUT/OVR.A", + "", + TESTDATA_DIR "DISK2/RESET/24/RV24FA.I", + TESTDATA_DIR "DISK2/RESET/24/RV24FA.O", + 24000, + G726_ENCODING_ALAW, + G726_ENCODING_ALAW + }, + { + "", + TESTDATA_DIR "DISK2/INPUT/NRM.A", + "", + TESTDATA_DIR "DISK2/RESET/32/RN32FA.I", + TESTDATA_DIR "DISK2/RESET/32/RN32FA.O", + 32000, + G726_ENCODING_ALAW, + G726_ENCODING_ALAW + }, + { + "", + "", + "", + TESTDATA_DIR "DISK2/INPUT/I32", + TESTDATA_DIR "DISK2/RESET/32/RI32FA.O", + 32000, + G726_ENCODING_NONE, + G726_ENCODING_ALAW + }, + { + "", + TESTDATA_DIR "DISK2/INPUT/OVR.A", + "", + TESTDATA_DIR "DISK2/RESET/32/RV32FA.I", + TESTDATA_DIR "DISK2/RESET/32/RV32FA.O", + 32000, + G726_ENCODING_ALAW, + G726_ENCODING_ALAW + }, + { + "", + TESTDATA_DIR "DISK2/INPUT/NRM.A", + "", + TESTDATA_DIR "DISK2/RESET/40/RN40FA.I", + TESTDATA_DIR "DISK2/RESET/40/RN40FA.O", + 40000, + G726_ENCODING_ALAW, + G726_ENCODING_ALAW + }, + { + "", + "", + "", + TESTDATA_DIR "DISK2/INPUT/I40", + TESTDATA_DIR "DISK2/RESET/40/RI40FA.O", + 40000, + G726_ENCODING_NONE, + G726_ENCODING_ALAW + }, + { + "", + TESTDATA_DIR "DISK2/INPUT/OVR.A", + "", + TESTDATA_DIR "DISK2/RESET/40/RV40FA.I", + TESTDATA_DIR "DISK2/RESET/40/RV40FA.O", + 40000, + G726_ENCODING_ALAW, + G726_ENCODING_ALAW + }, + /* u-law to A-law tests */ + { + "", + TESTDATA_DIR "DISK1/INPUT/NRM.M", + "", + TESTDATA_DIR "DISK1/RESET/16/RN16FM.I", + TESTDATA_DIR "DISK1/RESET/16/RN16FC.O", + 16000, + G726_ENCODING_ULAW, + G726_ENCODING_ALAW + }, + { + "", + TESTDATA_DIR "DISK1/INPUT/OVR.M", + "", + TESTDATA_DIR "DISK1/RESET/16/RV16FM.I", + TESTDATA_DIR "DISK1/RESET/16/RV16FC.O", + 16000, + G726_ENCODING_ULAW, + G726_ENCODING_ALAW + }, + { + "", + TESTDATA_DIR "DISK1/INPUT/NRM.M", + "", + TESTDATA_DIR "DISK1/RESET/24/RN24FM.I", + TESTDATA_DIR "DISK1/RESET/24/RN24FC.O", + 24000, + G726_ENCODING_ULAW, + G726_ENCODING_ALAW + }, + { + "", + TESTDATA_DIR "DISK1/INPUT/OVR.M", + "", + TESTDATA_DIR "DISK1/RESET/24/RV24FM.I", + TESTDATA_DIR "DISK1/RESET/24/RV24FC.O", + 24000, + G726_ENCODING_ULAW, + G726_ENCODING_ALAW + }, + { + "", + TESTDATA_DIR "DISK1/INPUT/NRM.M", + "", + TESTDATA_DIR "DISK1/RESET/32/RN32FM.I", + TESTDATA_DIR "DISK1/RESET/32/RN32FC.O", + 32000, + G726_ENCODING_ULAW, + G726_ENCODING_ALAW + }, + { + "", + TESTDATA_DIR "DISK1/INPUT/OVR.M", + "", + TESTDATA_DIR "DISK1/RESET/32/RV32FM.I", + TESTDATA_DIR "DISK1/RESET/32/RV32FC.O", + 32000, + G726_ENCODING_ULAW, + G726_ENCODING_ALAW + }, + { + "", + TESTDATA_DIR "DISK1/INPUT/NRM.M", + "", + TESTDATA_DIR "DISK1/RESET/40/RN40FM.I", + TESTDATA_DIR "DISK1/RESET/40/RN40FC.O", + 40000, + G726_ENCODING_ULAW, + G726_ENCODING_ALAW + }, + { + "", + TESTDATA_DIR "DISK1/INPUT/OVR.M", + "", + TESTDATA_DIR "DISK1/RESET/40/RV40FM.I", + TESTDATA_DIR "DISK1/RESET/40/RV40FC.O", + 40000, + G726_ENCODING_ULAW, + G726_ENCODING_ALAW + }, + /* A-law to u-law tests */ + { + "", + TESTDATA_DIR "DISK2/INPUT/NRM.A", + "", + TESTDATA_DIR "DISK2/RESET/16/RN16FA.I", + TESTDATA_DIR "DISK2/RESET/16/RN16FX.O", + 16000, + G726_ENCODING_ALAW, + G726_ENCODING_ULAW + }, + { + "", + TESTDATA_DIR "DISK2/INPUT/OVR.A", + "", + TESTDATA_DIR "DISK2/RESET/16/RV16FA.I", + TESTDATA_DIR "DISK2/RESET/16/RV16FX.O", + 16000, + G726_ENCODING_ALAW, + G726_ENCODING_ULAW + }, + { + "", + TESTDATA_DIR "DISK2/INPUT/NRM.A", + "", + TESTDATA_DIR "DISK2/RESET/24/RN24FA.I", + TESTDATA_DIR "DISK2/RESET/24/RN24FX.O", + 24000, + G726_ENCODING_ALAW, + G726_ENCODING_ULAW + }, + { + "", + TESTDATA_DIR "DISK2/INPUT/OVR.A", + "", + TESTDATA_DIR "DISK2/RESET/24/RV24FA.I", + TESTDATA_DIR "DISK2/RESET/24/RV24FX.O", + 24000, + G726_ENCODING_ALAW, + G726_ENCODING_ULAW + }, + { + "", + TESTDATA_DIR "DISK2/INPUT/NRM.A", + "", + TESTDATA_DIR "DISK2/RESET/32/RN32FA.I", + TESTDATA_DIR "DISK2/RESET/32/RN32FX.O", + 32000, + G726_ENCODING_ALAW, + G726_ENCODING_ULAW + }, + { + "", + TESTDATA_DIR "DISK2/INPUT/OVR.A", + "", + TESTDATA_DIR "DISK2/RESET/32/RV32FA.I", + TESTDATA_DIR "DISK2/RESET/32/RV32FX.O", + 32000, + G726_ENCODING_ALAW, + G726_ENCODING_ULAW + }, + { + "", + TESTDATA_DIR "DISK2/INPUT/NRM.A", + "", + TESTDATA_DIR "DISK2/RESET/40/RN40FA.I", + TESTDATA_DIR "DISK2/RESET/40/RN40FX.O", + 40000, + G726_ENCODING_ALAW, + G726_ENCODING_ULAW + }, + { + "", + TESTDATA_DIR "DISK2/INPUT/OVR.A", + "", + TESTDATA_DIR "DISK2/RESET/40/RV40FA.I", + TESTDATA_DIR "DISK2/RESET/40/RV40FX.O", + 40000, + G726_ENCODING_ALAW, + G726_ENCODING_ULAW + }, + /* u-law to u-law tests */ + { + TESTDATA_DIR "DISK1/PCM_INIT.M", + TESTDATA_DIR "DISK1/INPUT/NRM.M", + TESTDATA_DIR "DISK1/HOMING/16/I_INI_16.M", + TESTDATA_DIR "DISK1/HOMING/16/HN16FM.I", + TESTDATA_DIR "DISK1/HOMING/16/HN16FM.O", + 16000, + G726_ENCODING_ULAW, + G726_ENCODING_ULAW + }, + { + "", + "", + TESTDATA_DIR "DISK1/HOMING/16/I_INI_16.M", + TESTDATA_DIR "DISK1/INPUT/I16", + TESTDATA_DIR "DISK1/HOMING/16/HI16FM.O", + 16000, + G726_ENCODING_NONE, + G726_ENCODING_ULAW + }, + { + TESTDATA_DIR "DISK1/PCM_INIT.M", + TESTDATA_DIR "DISK1/INPUT/OVR.M", + TESTDATA_DIR "DISK1/HOMING/16/I_INI_16.M", + TESTDATA_DIR "DISK1/HOMING/16/HV16FM.I", + TESTDATA_DIR "DISK1/HOMING/16/HV16FM.O", + 16000, + G726_ENCODING_ULAW, + G726_ENCODING_ULAW + }, + { + TESTDATA_DIR "DISK1/PCM_INIT.M", + TESTDATA_DIR "DISK1/INPUT/NRM.M", + TESTDATA_DIR "DISK1/HOMING/24/I_INI_24.M", + TESTDATA_DIR "DISK1/HOMING/24/HN24FM.I", + TESTDATA_DIR "DISK1/HOMING/24/HN24FM.O", + 24000, + G726_ENCODING_ULAW, + G726_ENCODING_ULAW + }, + { + "", + "", + TESTDATA_DIR "DISK1/HOMING/24/I_INI_24.M", + TESTDATA_DIR "DISK1/INPUT/I24", + TESTDATA_DIR "DISK1/HOMING/24/HI24FM.O", + 24000, + G726_ENCODING_NONE, + G726_ENCODING_ULAW + }, + { + TESTDATA_DIR "DISK1/PCM_INIT.M", + TESTDATA_DIR "DISK1/INPUT/OVR.M", + TESTDATA_DIR "DISK1/HOMING/24/I_INI_24.M", + TESTDATA_DIR "DISK1/HOMING/24/HV24FM.I", + TESTDATA_DIR "DISK1/HOMING/24/HV24FM.O", + 24000, + G726_ENCODING_ULAW, + G726_ENCODING_ULAW + }, + { + TESTDATA_DIR "DISK1/PCM_INIT.M", + TESTDATA_DIR "DISK1/INPUT/NRM.M", + TESTDATA_DIR "DISK1/HOMING/32/I_INI_32.M", + TESTDATA_DIR "DISK1/HOMING/32/HN32FM.I", + TESTDATA_DIR "DISK1/HOMING/32/HN32FM.O", + 32000, + G726_ENCODING_ULAW, + G726_ENCODING_ULAW + }, + { + "", + "", + TESTDATA_DIR "DISK1/HOMING/32/I_INI_32.M", + TESTDATA_DIR "DISK1/INPUT/I32", + TESTDATA_DIR "DISK1/HOMING/32/HI32FM.O", + 32000, + G726_ENCODING_NONE, + G726_ENCODING_ULAW + }, + { + TESTDATA_DIR "DISK1/PCM_INIT.M", + TESTDATA_DIR "DISK1/INPUT/OVR.M", + TESTDATA_DIR "DISK1/HOMING/32/I_INI_32.M", + TESTDATA_DIR "DISK1/HOMING/32/HV32FM.I", + TESTDATA_DIR "DISK1/HOMING/32/HV32FM.O", + 32000, + G726_ENCODING_ULAW, + G726_ENCODING_ULAW + }, + { + TESTDATA_DIR "DISK1/PCM_INIT.M", + TESTDATA_DIR "DISK1/INPUT/NRM.M", + TESTDATA_DIR "DISK1/HOMING/40/I_INI_40.M", + TESTDATA_DIR "DISK1/HOMING/40/HN40FM.I", + TESTDATA_DIR "DISK1/HOMING/40/HN40FM.O", + 40000, + G726_ENCODING_ULAW, + G726_ENCODING_ULAW + }, + { + "", + "", + TESTDATA_DIR "DISK1/HOMING/40/I_INI_40.M", + TESTDATA_DIR "DISK1/INPUT/I40", + TESTDATA_DIR "DISK1/HOMING/40/HI40FM.O", + 40000, + G726_ENCODING_NONE, + G726_ENCODING_ULAW + }, + { + TESTDATA_DIR "DISK1/PCM_INIT.M", + TESTDATA_DIR "DISK1/INPUT/OVR.M", + TESTDATA_DIR "DISK1/HOMING/40/I_INI_40.M", + TESTDATA_DIR "DISK1/HOMING/40/HV40FM.I", + TESTDATA_DIR "DISK1/HOMING/40/HV40FM.O", + 40000, + G726_ENCODING_ULAW, + G726_ENCODING_ULAW + }, + /* A-law to A-law tests */ + { + TESTDATA_DIR "DISK2/PCM_INIT.A", + TESTDATA_DIR "DISK2/INPUT/NRM.A", + TESTDATA_DIR "DISK2/HOMING/16/I_INI_16.A", + TESTDATA_DIR "DISK2/HOMING/16/HN16FA.I", + TESTDATA_DIR "DISK2/HOMING/16/HN16FA.O", + 16000, + G726_ENCODING_ALAW, + G726_ENCODING_ALAW + }, + { + "", + "", + TESTDATA_DIR "DISK2/HOMING/16/I_INI_16.A", + TESTDATA_DIR "DISK2/INPUT/I16", + TESTDATA_DIR "DISK2/HOMING/16/HI16FA.O", + 16000, + G726_ENCODING_NONE, + G726_ENCODING_ALAW + }, + { + TESTDATA_DIR "DISK2/PCM_INIT.A", + TESTDATA_DIR "DISK2/INPUT/OVR.A", + TESTDATA_DIR "DISK2/HOMING/16/I_INI_16.A", + TESTDATA_DIR "DISK2/HOMING/16/HV16FA.I", + TESTDATA_DIR "DISK2/HOMING/16/HV16FA.O", + 16000, + G726_ENCODING_ALAW, + G726_ENCODING_ALAW + }, + { + TESTDATA_DIR "DISK2/PCM_INIT.A", + TESTDATA_DIR "DISK2/INPUT/NRM.A", + TESTDATA_DIR "DISK2/HOMING/24/I_INI_24.A", + TESTDATA_DIR "DISK2/HOMING/24/HN24FA.I", + TESTDATA_DIR "DISK2/HOMING/24/HN24FA.O", + 24000, + G726_ENCODING_ALAW, + G726_ENCODING_ALAW + }, + { + "", + "", + TESTDATA_DIR "DISK2/HOMING/24/I_INI_24.A", + TESTDATA_DIR "DISK2/INPUT/I24", + TESTDATA_DIR "DISK2/HOMING/24/HI24FA.O", + 24000, + G726_ENCODING_NONE, + G726_ENCODING_ALAW + }, + { + TESTDATA_DIR "DISK2/PCM_INIT.A", + TESTDATA_DIR "DISK2/INPUT/OVR.A", + TESTDATA_DIR "DISK2/HOMING/24/I_INI_24.A", + TESTDATA_DIR "DISK2/HOMING/24/HV24FA.I", + TESTDATA_DIR "DISK2/HOMING/24/HV24FA.O", + 24000, + G726_ENCODING_ALAW, + G726_ENCODING_ALAW + }, + { + TESTDATA_DIR "DISK2/PCM_INIT.A", + TESTDATA_DIR "DISK2/INPUT/NRM.A", + TESTDATA_DIR "DISK2/HOMING/32/I_INI_32.A", + TESTDATA_DIR "DISK2/HOMING/32/HN32FA.I", + TESTDATA_DIR "DISK2/HOMING/32/HN32FA.O", + 32000, + G726_ENCODING_ALAW, + G726_ENCODING_ALAW + }, + { + "", + "", + TESTDATA_DIR "DISK2/HOMING/32/I_INI_32.A", + TESTDATA_DIR "DISK2/INPUT/I32", + TESTDATA_DIR "DISK2/HOMING/32/HI32FA.O", + 32000, + G726_ENCODING_NONE, + G726_ENCODING_ALAW + }, + { + TESTDATA_DIR "DISK2/PCM_INIT.A", + TESTDATA_DIR "DISK2/INPUT/OVR.A", + TESTDATA_DIR "DISK2/HOMING/32/I_INI_32.A", + TESTDATA_DIR "DISK2/HOMING/32/HV32FA.I", + TESTDATA_DIR "DISK2/HOMING/32/HV32FA.O", + 32000, + G726_ENCODING_ALAW, + G726_ENCODING_ALAW + }, + { + TESTDATA_DIR "DISK2/PCM_INIT.A", + TESTDATA_DIR "DISK2/INPUT/NRM.A", + TESTDATA_DIR "DISK2/HOMING/40/I_INI_40.A", + TESTDATA_DIR "DISK2/HOMING/40/HN40FA.I", + TESTDATA_DIR "DISK2/HOMING/40/HN40FA.O", + 40000, + G726_ENCODING_ALAW, + G726_ENCODING_ALAW + }, + { + "", + "", + TESTDATA_DIR "DISK2/HOMING/40/I_INI_40.A", + TESTDATA_DIR "DISK2/INPUT/I40", + TESTDATA_DIR "DISK2/HOMING/40/HI40FA.O", + 40000, + G726_ENCODING_NONE, + G726_ENCODING_ALAW + }, + { + TESTDATA_DIR "DISK2/PCM_INIT.A", + TESTDATA_DIR "DISK2/INPUT/OVR.A", + TESTDATA_DIR "DISK2/HOMING/40/I_INI_40.A", + TESTDATA_DIR "DISK2/HOMING/40/HV40FA.I", + TESTDATA_DIR "DISK2/HOMING/40/HV40FA.O", + 40000, + G726_ENCODING_ALAW, + G726_ENCODING_ALAW + }, + /* u-law to A-law tests */ + { + TESTDATA_DIR "DISK1/PCM_INIT.M", + TESTDATA_DIR "DISK1/INPUT/NRM.M", + TESTDATA_DIR "DISK2/HOMING/16/I_INI_16.A", + TESTDATA_DIR "DISK1/HOMING/16/HN16FM.I", + TESTDATA_DIR "DISK1/HOMING/16/HN16FC.O", + 16000, + G726_ENCODING_ULAW, + G726_ENCODING_ALAW + }, + { + TESTDATA_DIR "DISK1/PCM_INIT.M", + TESTDATA_DIR "DISK1/INPUT/OVR.M", + TESTDATA_DIR "DISK2/HOMING/16/I_INI_16.A", + TESTDATA_DIR "DISK1/HOMING/16/HV16FM.I", + TESTDATA_DIR "DISK1/HOMING/16/HV16FC.O", + 16000, + G726_ENCODING_ULAW, + G726_ENCODING_ALAW + }, + { + TESTDATA_DIR "DISK1/PCM_INIT.M", + TESTDATA_DIR "DISK1/INPUT/NRM.M", + TESTDATA_DIR "DISK2/HOMING/24/I_INI_24.A", + TESTDATA_DIR "DISK1/HOMING/24/HN24FM.I", + TESTDATA_DIR "DISK1/HOMING/24/HN24FC.O", + 24000, + G726_ENCODING_ULAW, + G726_ENCODING_ALAW + }, + { + TESTDATA_DIR "DISK1/PCM_INIT.M", + TESTDATA_DIR "DISK1/INPUT/OVR.M", + TESTDATA_DIR "DISK2/HOMING/24/I_INI_24.A", + TESTDATA_DIR "DISK1/HOMING/24/HV24FM.I", + TESTDATA_DIR "DISK1/HOMING/24/HV24FC.O", + 24000, + G726_ENCODING_ULAW, + G726_ENCODING_ALAW + }, + { + TESTDATA_DIR "DISK1/PCM_INIT.M", + TESTDATA_DIR "DISK1/INPUT/NRM.M", + TESTDATA_DIR "DISK2/HOMING/32/I_INI_32.A", + TESTDATA_DIR "DISK1/HOMING/32/HN32FM.I", + TESTDATA_DIR "DISK1/HOMING/32/HN32FC.O", + 32000, + G726_ENCODING_ULAW, + G726_ENCODING_ALAW + }, + { + TESTDATA_DIR "DISK1/PCM_INIT.M", + TESTDATA_DIR "DISK1/INPUT/OVR.M", + TESTDATA_DIR "DISK2/HOMING/32/I_INI_32.A", + TESTDATA_DIR "DISK1/HOMING/32/HV32FM.I", + TESTDATA_DIR "DISK1/HOMING/32/HV32FC.O", + 32000, + G726_ENCODING_ULAW, + G726_ENCODING_ALAW + }, + { + TESTDATA_DIR "DISK1/PCM_INIT.M", + TESTDATA_DIR "DISK1/INPUT/NRM.M", + TESTDATA_DIR "DISK2/HOMING/40/I_INI_40.A", + TESTDATA_DIR "DISK1/HOMING/40/HN40FM.I", + TESTDATA_DIR "DISK1/HOMING/40/HN40FC.O", + 40000, + G726_ENCODING_ULAW, + G726_ENCODING_ALAW + }, + { + TESTDATA_DIR "DISK1/PCM_INIT.M", + TESTDATA_DIR "DISK1/INPUT/OVR.M", + TESTDATA_DIR "DISK2/HOMING/40/I_INI_40.A", + TESTDATA_DIR "DISK1/HOMING/40/HV40FM.I", + TESTDATA_DIR "DISK1/HOMING/40/HV40FC.O", + 40000, + G726_ENCODING_ULAW, + G726_ENCODING_ALAW + }, + /* A-law to u-law tests */ + { + TESTDATA_DIR "DISK2/PCM_INIT.A", + TESTDATA_DIR "DISK2/INPUT/NRM.A", + TESTDATA_DIR "DISK1/HOMING/16/I_INI_16.M", + TESTDATA_DIR "DISK2/HOMING/16/HN16FA.I", + TESTDATA_DIR "DISK2/HOMING/16/HN16FX.O", + 16000, + G726_ENCODING_ALAW, + G726_ENCODING_ULAW + }, + { + TESTDATA_DIR "DISK2/PCM_INIT.A", + TESTDATA_DIR "DISK2/INPUT/OVR.A", + TESTDATA_DIR "DISK1/HOMING/16/I_INI_16.M", + TESTDATA_DIR "DISK2/HOMING/16/HV16FA.I", + TESTDATA_DIR "DISK2/HOMING/16/HV16FX.O", + 16000, + G726_ENCODING_ALAW, + G726_ENCODING_ULAW + }, + { + TESTDATA_DIR "DISK2/PCM_INIT.A", + TESTDATA_DIR "DISK2/INPUT/NRM.A", + TESTDATA_DIR "DISK1/HOMING/24/I_INI_24.M", + TESTDATA_DIR "DISK2/HOMING/24/HN24FA.I", + TESTDATA_DIR "DISK2/HOMING/24/HN24FX.O", + 24000, + G726_ENCODING_ALAW, + G726_ENCODING_ULAW + }, + { + TESTDATA_DIR "DISK2/PCM_INIT.A", + TESTDATA_DIR "DISK2/INPUT/OVR.A", + TESTDATA_DIR "DISK1/HOMING/24/I_INI_24.M", + TESTDATA_DIR "DISK2/HOMING/24/HV24FA.I", + TESTDATA_DIR "DISK2/HOMING/24/HV24FX.O", + 24000, + G726_ENCODING_ALAW, + G726_ENCODING_ULAW + }, + { + TESTDATA_DIR "DISK2/PCM_INIT.A", + TESTDATA_DIR "DISK2/INPUT/NRM.A", + TESTDATA_DIR "DISK1/HOMING/32/I_INI_32.M", + TESTDATA_DIR "DISK2/HOMING/32/HN32FA.I", + TESTDATA_DIR "DISK2/HOMING/32/HN32FX.O", + 32000, + G726_ENCODING_ALAW, + G726_ENCODING_ULAW + }, + { + TESTDATA_DIR "DISK2/PCM_INIT.A", + TESTDATA_DIR "DISK2/INPUT/OVR.A", + TESTDATA_DIR "DISK1/HOMING/32/I_INI_32.M", + TESTDATA_DIR "DISK2/HOMING/32/HV32FA.I", + TESTDATA_DIR "DISK2/HOMING/32/HV32FX.O", + 32000, + G726_ENCODING_ALAW, + G726_ENCODING_ULAW + }, + { + TESTDATA_DIR "DISK2/PCM_INIT.A", + TESTDATA_DIR "DISK2/INPUT/NRM.A", + TESTDATA_DIR "DISK1/HOMING/40/I_INI_40.M", + TESTDATA_DIR "DISK2/HOMING/40/HN40FA.I", + TESTDATA_DIR "DISK2/HOMING/40/HN40FX.O", + 40000, + G726_ENCODING_ALAW, + G726_ENCODING_ULAW + }, + { + TESTDATA_DIR "DISK2/PCM_INIT.A", + TESTDATA_DIR "DISK2/INPUT/OVR.A", + TESTDATA_DIR "DISK1/HOMING/40/I_INI_40.M", + TESTDATA_DIR "DISK2/HOMING/40/HV40FA.I", + TESTDATA_DIR "DISK2/HOMING/40/HV40FX.O", + 40000, + G726_ENCODING_ALAW, + G726_ENCODING_ULAW + }, + { + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + 0 + } +}; + +static int hex_get(char *s) +{ + int i; + int value; + int x; + + for (value = i = 0; i < 2; i++) + { + x = *s++ - 0x30; + if (x > 9) + x -= 0x07; + if (x > 15) + x -= 0x20; + if (x < 0 || x > 15) + return -1; + value <<= 4; + value |= x; + } + return value; +} +/*- End of function --------------------------------------------------------*/ + +static int get_vector(FILE *file, uint8_t vec[]) +{ + char buf[132 + 1]; + char *s; + int i; + int value; + + while (fgets(buf, 133, file)) + { + s = buf; + i = 0; + while ((value = hex_get(s)) >= 0) + { + vec[i++] = value; + s += 2; + } + return i; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int get_test_vector(const char *file, uint8_t buf[], int max_len) +{ + int octets; + int i; + int sum; + FILE *infile; + + if ((infile = fopen(file, "r")) == NULL) + { + fprintf(stderr, " Failed to open '%s'\n", file); + exit(2); + } + octets = 0; + while ((i = get_vector(infile, buf + octets)) > 0) + octets += i; + fclose(infile); + /* The last octet is a sumcheck, so the real data octets are one less than + the total we have */ + octets--; + /* Test the checksum */ + for (sum = i = 0; i < octets; i++) + sum += buf[i]; + if (sum%255 != (int) buf[i]) + { + fprintf(stderr, " Sumcheck failed in '%s' - %x %x\n", file, sum%255, buf[i]); + exit(2); + } + return octets; +} +/*- End of function --------------------------------------------------------*/ + +int main(int argc, char *argv[]) +{ + g726_state_t enc_state; + g726_state_t dec_state; + int len2; + int len3; + int i; + int test; + int bits_per_code; + int itutests; + int bit_rate; + int bad_samples; + AFfilehandle inhandle; + AFfilehandle outhandle; + AFfilesetup filesetup; + int16_t amp[1024]; + int frames; + int outframes; + int conditioning_samples; + int samples; + int conditioning_adpcm; + int adpcm; + int packing; + float x; + + i = 1; + bit_rate = 32000; + itutests = TRUE; + packing = G726_PACKING_NONE; + while (argc > i) + { + if (strcmp(argv[i], "-16") == 0) + { + bit_rate = 16000; + itutests = FALSE; + i++; + } + else if (strcmp(argv[i], "-24") == 0) + { + bit_rate = 24000; + itutests = FALSE; + i++; + } + else if (strcmp(argv[i], "-32") == 0) + { + bit_rate = 32000; + itutests = FALSE; + i++; + } + else if (strcmp(argv[i], "-40") == 0) + { + bit_rate = 40000; + itutests = FALSE; + i++; + } + else if (strcmp(argv[i], "-l") == 0) + { + packing = G726_PACKING_LEFT; + i++; + } + else if (strcmp(argv[i], "-r") == 0) + { + packing = G726_PACKING_RIGHT; + i++; + } + else + { + fprintf(stderr, "Unknown parameter %s specified.\n", argv[i]); + exit(2); + } + } + + len2 = 0; + conditioning_samples = 0; + if (itutests) + { + for (test = 0; itu_test_sets[test].rate; test++) + { + printf("Test %2d: '%s' + '%s'\n" + " -> '%s' + '%s'\n" + " -> '%s' [%d, %d, %d]\n", + test, + itu_test_sets[test].conditioning_pcm_file, + itu_test_sets[test].pcm_file, + itu_test_sets[test].conditioning_adpcm_file, + itu_test_sets[test].adpcm_file, + itu_test_sets[test].output_file, + itu_test_sets[test].rate, + itu_test_sets[test].compression_law, + itu_test_sets[test].decompression_law); + switch (itu_test_sets[test].rate) + { + case 16000: + bits_per_code = 2; + break; + case 24000: + bits_per_code = 3; + break; + case 32000: + default: + bits_per_code = 4; + break; + case 40000: + bits_per_code = 5; + break; + } + if (itu_test_sets[test].compression_law != G726_ENCODING_NONE) + { + /* Test the encode side */ + g726_init(&enc_state, itu_test_sets[test].rate, itu_test_sets[test].compression_law, G726_PACKING_NONE); + if (itu_test_sets[test].conditioning_pcm_file[0]) + { + conditioning_samples = get_test_vector(itu_test_sets[test].conditioning_pcm_file, xlaw, MAX_TEST_VECTOR_LEN); + printf("Test %d: Homing %d samples at %dbps\n", test, conditioning_samples, itu_test_sets[test].rate); + } + else + { + conditioning_samples = 0; + } + samples = get_test_vector(itu_test_sets[test].pcm_file, xlaw + conditioning_samples, MAX_TEST_VECTOR_LEN); + memcpy(itudata, xlaw, samples + conditioning_samples); + printf("Test %d: Compressing %d samples at %dbps\n", test, samples, itu_test_sets[test].rate); + len2 = g726_encode(&enc_state, adpcmdata, itudata, conditioning_samples + samples); + } + /* Test the decode side */ + g726_init(&dec_state, itu_test_sets[test].rate, itu_test_sets[test].decompression_law, G726_PACKING_NONE); + if (itu_test_sets[test].conditioning_adpcm_file[0]) + { + conditioning_adpcm = get_test_vector(itu_test_sets[test].conditioning_adpcm_file, unpacked, MAX_TEST_VECTOR_LEN); + printf("Test %d: Homing %d octets at %dbps\n", test, conditioning_adpcm, itu_test_sets[test].rate); + } + else + { + conditioning_adpcm = 0; + } + adpcm = get_test_vector(itu_test_sets[test].adpcm_file, unpacked + conditioning_adpcm, MAX_TEST_VECTOR_LEN); + if (itu_test_sets[test].compression_law != G726_ENCODING_NONE) + { + /* Test our compressed version against the reference compressed version */ + printf("Test %d: Compressed data check - %d/%d octets\n", test, conditioning_adpcm + adpcm, len2); + if (conditioning_adpcm + adpcm == len2) + { + for (bad_samples = 0, i = conditioning_samples; i < len2; i++) + { + if (adpcmdata[i] != unpacked[i]) + { + bad_samples++; + printf("Test %d: Compressed mismatch %d %x %x\n", test, i, adpcmdata[i], unpacked[i]); + } + } + if (bad_samples > 0) + { + printf("Test failed\n"); + exit(2); + } + printf("Test passed\n"); + } + else + { + printf("Test %d: Length mismatch - ref = %d, processed = %d\n", test, conditioning_adpcm + adpcm, len2); + exit(2); + } + } + + len3 = g726_decode(&dec_state, outdata, unpacked, conditioning_adpcm + adpcm); + + /* Get the output reference data */ + samples = get_test_vector(itu_test_sets[test].output_file, xlaw, MAX_TEST_VECTOR_LEN); + memcpy(itu_ref, xlaw, samples); + /* Test our decompressed version against the reference decompressed version */ + printf("Test %d: Decompressed data check - %d/%d samples\n", test, samples, len3 - conditioning_adpcm); + if (samples == len3 - conditioning_adpcm) + { + for (bad_samples = 0, i = 0; i < len3; i++) + { + if (itu_ref[i] != ((uint8_t *) outdata)[i + conditioning_adpcm]) + { + bad_samples++; + printf("Test %d: Decompressed mismatch %d %x %x\n", test, i, itu_ref[i], ((uint8_t *) outdata)[i + conditioning_adpcm]); + } + } + if (bad_samples > 0) + { + printf("Test failed\n"); + exit(2); + } + printf("Test passed\n"); + } + else + { + printf("Test %d: Length mismatch - ref = %d, processed = %d\n", test, samples, len3 - conditioning_adpcm); + exit(2); + } + } + + printf("Tests passed.\n"); + } + else + { + if ((inhandle = afOpenFile(IN_FILE_NAME, "r", 0)) == AF_NULL_FILEHANDLE) + { + printf(" Cannot open wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if ((x = afGetFrameSize(inhandle, AF_DEFAULT_TRACK, 1)) != 2.0) + { + printf(" Unexpected frame size in wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if ((x = afGetRate(inhandle, AF_DEFAULT_TRACK)) != (float) SAMPLE_RATE) + { + printf(" Unexpected sample rate in wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if ((x = afGetChannels(inhandle, AF_DEFAULT_TRACK)) != 1.0) + { + printf(" Unexpected number of channels in wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if ((filesetup = afNewFileSetup()) == AF_NULL_FILESETUP) + { + fprintf(stderr, " Failed to create file setup\n"); + exit(2); + } + afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16); + afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE); + afInitFileFormat(filesetup, AF_FILE_WAVE); + afInitChannels(filesetup, AF_DEFAULT_TRACK, 1); + + outhandle = afOpenFile(OUT_FILE_NAME, "w", filesetup); + if (outhandle == AF_NULL_FILEHANDLE) + { + fprintf(stderr, " Cannot create wave file '%s'\n", OUT_FILE_NAME); + exit(2); + } + + printf("ADPCM packing is %d\n", packing); + g726_init(&enc_state, bit_rate, G726_ENCODING_LINEAR, packing); + g726_init(&dec_state, bit_rate, G726_ENCODING_LINEAR, packing); + + while ((frames = afReadFrames(inhandle, AF_DEFAULT_TRACK, amp, 159))) + { + adpcm = g726_encode(&enc_state, adpcmdata, amp, frames); + frames = g726_decode(&dec_state, amp, adpcmdata, adpcm); + outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, amp, frames); + } + if (afCloseFile(inhandle) != 0) + { + printf(" Cannot close wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if (afCloseFile(outhandle) != 0) + { + printf(" Cannot close wave file '%s'\n", OUT_FILE_NAME); + exit(2); + } + afFreeFileSetup(filesetup); + printf("'%s' transcoded to '%s' at %dbps.\n", IN_FILE_NAME, OUT_FILE_NAME, bit_rate); + } + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/tests/gsm0610_tests.c b/libs/voipcodecs/tests/gsm0610_tests.c new file mode 100644 index 0000000000..bf8f6afb64 --- /dev/null +++ b/libs/voipcodecs/tests/gsm0610_tests.c @@ -0,0 +1,649 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * gsm0610_tests.c - Test the GSM 06.10 FR codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: gsm0610_tests.c,v 1.8 2007/11/10 11:14:58 steveu Exp $ + */ + +/*! \file */ + +/*! \page gsm0610_tests_page GSM 06.10 full rate codec tests +\section gsm0610_tests_page_sec_1 What does it do? +Two sets of tests are performed: + - The tests defined in the GSM 06.10 specification, using the test data files supplied with + the specification. + - A generally audio quality test, consisting of compressing and decompressing a speeech + file for audible comparison. + +The speech file should be recorded at 16 bits/sample, 8000 samples/second, and named +"pre_gsm0610.wav". + +\section gsm0610_tests_page_sec_2 How is it used? +To perform the tests in the GSM 06.10 specification you need to obtain the test data files from the +specification. These are copyright material, and so cannot be distributed with this test software. +They can, however, be freely downloaded from the ETSI web site. + +The files, containing test vectors, which are supplied with the GSM 06.10 specification, should be +copied to etsitests/gsm0610/unpacked so the files are arranged in the following directories. + +./fr_A: + Seq01-A.cod Seq01-A.inp Seq01-A.out + Seq02-A.cod Seq02-A.inp Seq02-A.out + Seq03-A.cod Seq03-A.inp Seq03-A.out + Seq04-A.cod Seq04-A.inp Seq04-A.out + Seq05-A.out + +./fr_L: + Seq01.cod Seq01.inp Seq01.out + Seq02.cod Seq02.inp Seq02.out + Seq03.cod Seq03.inp Seq03.out + Seq04.cod Seq04.inp Seq04.out + Seq05.cod Seq05.out + +./fr_U: + Seq01-U.cod Seq01-U.inp Seq01-U.out + Seq02-U.cod Seq02-U.inp Seq02-U.out + Seq03-U.cod Seq03-U.inp Seq03-U.out + Seq04-U.cod Seq04-U.inp Seq04-U.out + Seq05-U.out + +./fr_homing_A: + Homing01_A.out + Seq01H_A.cod Seq01H_A.inp Seq01H_A.out + Seq02H_A.cod Seq02H_A.inp Seq02H_A.out + Seq03H_A.cod Seq03H_A.inp Seq03H_A.out + Seq04H_A.cod Seq04H_A.inp Seq04H_A.out + Seq05H_A.out + Seq06H_A.cod Seq06H_A.inp + +./fr_homing_L: + Homing01.cod Homing01.out + Seq01h.cod Seq01h.inp Seq01h.out + Seq02h.cod Seq02h.inp Seq02h.out + Seq03h.cod Seq03h.inp Seq03h.out + Seq04h.cod Seq04h.inp Seq04h.out + Seq05h.cod Seq05h.out + Seq06h.cod Seq06h.inp + +./fr_homing_U: + Homing01_U.out + Seq01H_U.cod Seq01H_U.inp Seq01H_U.out + Seq02H_U.cod Seq02H_U.inp Seq02H_U.out + Seq03H_U.cod Seq03H_U.inp Seq03H_U.out + Seq04H_U.cod Seq04H_U.inp Seq04H_U.out + Seq05H_U.out + Seq06H_U.cod Seq06H_U.inp + +./fr_sync_A: + Seqsync_A.inp + Sync000_A.cod --to-- Sync159_A.cod + +./fr_sync_L: + Bitsync.inp + Seqsync.inp + Sync000.cod --to-- Sync159.cod + +./fr_sync_U: + Seqsync_U.inp + Sync000_U.cod --to-- Sync159_U.cod + +This is different from the directory structure in which they are supplied. Also, the files names are a little +different. The supplied names are messy, and inconsistent across the sets. The names required by these tests +just clean up these inconsistencies. Note that you will need a Windows machine to unpack some of the supplied +files. + +To perform a general audio quality test, gsm0610_tests should be run. The file ../localtests/short_nb_voice.wav +will be compressed to GSM 06.10 data, decompressed, and the resulting audio stored in post_gsm0610.wav. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "voipcodecs.h" + +#define BLOCK_LEN 160 + +#define TEST_DIR "../etsitests/gsm0610/unpacked/fr_" + +#define IN_FILE_NAME "../localtests/short_nb_voice.wav" +#define OUT_FILE_NAME "post_gsm0610.wav" + +#define HIST_LEN 1000 + +uint8_t law_in_vector[1000000]; +int16_t in_vector[1000000]; +uint16_t code_vector_buf[1000000]; +uint8_t code_vector[1000000]; +uint8_t ref_code_vector[1000000]; +uint8_t decoder_code_vector[1000000]; +uint8_t law_out_vector[1000000]; +int16_t out_vector[1000000]; +int16_t ref_out_vector[1000000]; +uint8_t ref_law_out_vector[1000000]; +int vector_len; + +static int get_test_vector(int full, int disk, const char *name) +{ + char buf[500]; + int in; + int len; + int i; + + if (full) + { + sprintf(buf, "%s%c/%s.inp", TEST_DIR, 'L', name); + if ((in = open(buf, O_RDONLY)) < 0) + { + fprintf(stderr, "Cannot open %s\n", buf); + exit(2); + } + len = read(in, in_vector, 1000000); + close(in); + len /= sizeof(int16_t); + vector_len = len; + } + + sprintf(buf, "%s%c/%s.out", TEST_DIR, 'L', name); + if ((in = open(buf, O_RDONLY)) < 0) + { + fprintf(stderr, "Cannot open %s\n", buf); + exit(2); + } + len = read(in, ref_out_vector, 1000000); + close(in); + len /= sizeof(int16_t); + if (full) + { + if (len != vector_len) + { + fprintf(stderr, "Input and reference vector lengths do not match - %d %d\n", vector_len, len); + exit(2); + } + } + else + { + vector_len = len; + } + + sprintf(buf, "%s%c/%s.cod", TEST_DIR, 'L', name); + if ((in = open(buf, O_RDONLY)) < 0) + { + fprintf(stderr, "Cannot open %s\n", buf); + exit(2); + } + len = read(in, code_vector_buf, 1000000); + close(in); + len /= sizeof(int16_t); + for (i = 0; i < len; i++) + { + ref_code_vector[i] = code_vector_buf[i]; + decoder_code_vector[i] = code_vector_buf[i]; + } + if (len*BLOCK_LEN != vector_len*76) + { + fprintf(stderr, "Input and code vector lengths do not match - %d %d\n", vector_len, len); + exit(2); + } + + return len; +} +/*- End of function --------------------------------------------------------*/ + +static int get_law_test_vector(int full, int law, const char *name) +{ + char buf[500]; + int in; + int len; + int i; + int law_uc; + + law_uc = toupper(law); + + if (full) + { + sprintf(buf, "%s%c/%s-%c.inp", TEST_DIR, law_uc, name, law_uc); + if ((in = open(buf, O_RDONLY)) < 0) + { + fprintf(stderr, "Cannot open %s\n", buf); + exit(2); + } + len = read(in, law_in_vector, 1000000); + close(in); + vector_len = len; + + sprintf(buf, "%s%c/%s-%c.cod", TEST_DIR, law_uc, name, law_uc); + if ((in = open(buf, O_RDONLY)) < 0) + { + fprintf(stderr, "Cannot open %s\n", buf); + exit(2); + } + len = read(in, code_vector_buf, 1000000); + close(in); + len /= sizeof(int16_t); + for (i = 0; i < len; i++) + ref_code_vector[i] = code_vector_buf[i]; + if (len*BLOCK_LEN != vector_len*76) + { + fprintf(stderr, "Input and code vector lengths do not match - %d %d\n", vector_len, len); + exit(2); + } + } + + sprintf(buf, "%s%c/%s-%c.out", TEST_DIR, law_uc, name, law_uc); + if ((in = open(buf, O_RDONLY)) < 0) + { + fprintf(stderr, "Cannot open %s\n", buf); + exit(2); + } + len = read(in, ref_law_out_vector, 1000000); + close(in); + if (full) + { + if (len != vector_len) + { + fprintf(stderr, "Input and reference vector lengths do not match - %d %d\n", vector_len, len); + exit(2); + } + } + else + { + vector_len = len; + } + + sprintf(buf, "%s%c/%s.cod", TEST_DIR, 'L', name); + if ((in = open(buf, O_RDONLY)) < 0) + { + fprintf(stderr, "Cannot open %s\n", buf); + exit(2); + } + len = read(in, code_vector_buf, 1000000); + close(in); + len /= sizeof(int16_t); + for (i = 0; i < len; i++) + decoder_code_vector[i] = code_vector_buf[i]; + + return len; +} +/*- End of function --------------------------------------------------------*/ + +static int perform_linear_test(int full, int disk, const char *name) +{ + gsm0610_state_t *gsm0610_enc_state; + gsm0610_state_t *gsm0610_dec_state; + int i; + int xxx; + int mismatches; + + printf("Performing linear test '%s' from disk %d\n", name, disk); + + get_test_vector(full, disk, name); + + if (full) + { + if ((gsm0610_enc_state = gsm0610_init(NULL, GSM0610_PACKING_NONE)) == NULL) + { + fprintf(stderr, " Cannot create encoder\n"); + exit(2); + } + xxx = gsm0610_encode(gsm0610_enc_state, code_vector, in_vector, vector_len/BLOCK_LEN); + + printf("Check code vector of length %d\n", xxx); + for (i = 0, mismatches = 0; i < xxx; i++) + { + if (code_vector[i] != ref_code_vector[i]) + { + printf("%8d/%3d: %6d %6d\n", i/76, i%76, code_vector[i], ref_code_vector[i]); + mismatches++; + } + } + gsm0610_release(gsm0610_enc_state); + if (mismatches) + { + printf("Test failed: %d of %d samples mismatch\n", mismatches, xxx); + exit(2); + } + printf("Test passed\n"); + } + + if ((gsm0610_dec_state = gsm0610_init(NULL, GSM0610_PACKING_NONE)) == NULL) + { + fprintf(stderr, " Cannot create decoder\n"); + exit(2); + } + xxx = gsm0610_decode(gsm0610_dec_state, out_vector, decoder_code_vector, vector_len/BLOCK_LEN); + printf("Check output vector of length %d\n", vector_len); + for (i = 0, mismatches = 0; i < vector_len; i++) + { + if (out_vector[i] != ref_out_vector[i]) + { + printf("%8d: %6d %6d\n", i, out_vector[i], ref_out_vector[i]); + mismatches++; + } + } + if (mismatches) + { + printf("Test failed: %d of %d samples mismatch\n", mismatches, vector_len); + exit(2); + } + gsm0610_release(gsm0610_dec_state); + printf("Test passed\n"); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int perform_law_test(int full, int law, const char *name) +{ + gsm0610_state_t *gsm0610_enc_state; + gsm0610_state_t *gsm0610_dec_state; + int i; + int xxx; + int mismatches; + + if (law == 'a') + printf("Performing A-law test '%s'\n", name); + else + printf("Performing u-law test '%s'\n", name); + + get_law_test_vector(full, law, name); + + if (full) + { + if ((gsm0610_enc_state = gsm0610_init(NULL, GSM0610_PACKING_NONE)) == NULL) + { + fprintf(stderr, " Cannot create encoder\n"); + exit(2); + } + if (law == 'a') + { + for (i = 0; i < vector_len; i++) + in_vector[i] = alaw_to_linear(law_in_vector[i]); + } + else + { + for (i = 0; i < vector_len; i++) + in_vector[i] = ulaw_to_linear(law_in_vector[i]); + } + xxx = gsm0610_encode(gsm0610_enc_state, code_vector, in_vector, vector_len/BLOCK_LEN); + + printf("Check code vector of length %d\n", xxx); + for (i = 0, mismatches = 0; i < xxx; i++) + { + if (code_vector[i] != ref_code_vector[i]) + { + printf("%8d/%3d: %6d %6d %6d\n", i/76, i%76, code_vector[i], ref_code_vector[i], decoder_code_vector[i]); + mismatches++; + } + } + if (mismatches) + { + printf("Test failed: %d of %d samples mismatch\n", mismatches, xxx); + exit(2); + } + printf("Test passed\n"); + gsm0610_release(gsm0610_enc_state); + } + + if ((gsm0610_dec_state = gsm0610_init(NULL, GSM0610_PACKING_NONE)) == NULL) + { + fprintf(stderr, " Cannot create decoder\n"); + exit(2); + } + xxx = gsm0610_decode(gsm0610_dec_state, out_vector, decoder_code_vector, vector_len/BLOCK_LEN); + if (law == 'a') + { + for (i = 0; i < vector_len; i++) + law_out_vector[i] = linear_to_alaw(out_vector[i]); + } + else + { + for (i = 0; i < vector_len; i++) + law_out_vector[i] = linear_to_ulaw(out_vector[i]); + } + printf("Check output vector of length %d\n", vector_len); + for (i = 0, mismatches = 0; i < vector_len; i++) + { + if (law_out_vector[i] != ref_law_out_vector[i]) + { + printf("%8d: %6d %6d\n", i, law_out_vector[i], ref_law_out_vector[i]); + mismatches++; + } + } + if (mismatches) + { + printf("Test failed: %d of %d samples mismatch\n", mismatches, vector_len); + exit(2); + } + gsm0610_release(gsm0610_dec_state); + printf("Test passed\n"); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int repack_gsm0610_voip_to_wav49(uint8_t c[], const uint8_t d[]) +{ + gsm0610_frame_t frame[2]; + int n; + + n = gsm0610_unpack_voip(&frame[0], d); + gsm0610_unpack_voip(&frame[1], d + n); + n = gsm0610_pack_wav49(c, frame); + return n; +} +/*- End of function --------------------------------------------------------*/ + +static int repack_gsm0610_wav49_to_voip(uint8_t d[], const uint8_t c[]) +{ + gsm0610_frame_t frame[2]; + int n[2]; + + gsm0610_unpack_wav49(frame, c); + n[0] = gsm0610_pack_voip(d, &frame[0]); + n[1] = gsm0610_pack_voip(d + n[0], &frame[1]); + return n[0] + n[1]; +} +/*- End of function --------------------------------------------------------*/ + +static int perform_pack_unpack_test(void) +{ + uint8_t a[66]; + uint8_t b[66]; + uint8_t c[66]; + int i; + int j; + + printf("Performing packing/unpacking tests (not part of the ETSI conformance tests).\n"); + /* Try trans-packing a lot of random data looking for before/after mismatch. */ + for (j = 0; j < 1000; j++) + { + for (i = 0; i < 65; i++) + a[i] = rand(); + repack_gsm0610_wav49_to_voip(b, a); + repack_gsm0610_voip_to_wav49(c, b); + if (memcmp(a, c, 65)) + { + printf("Test failed: data mismatch\n"); + exit(2); + } + + for (i = 0; i < 66; i++) + a[i] = rand(); + /* Insert the magic code */ + a[0] = (a[0] & 0xF) | 0xD0; + a[33] = (a[33] & 0xF) | 0xD0; + repack_gsm0610_voip_to_wav49(b, a); + repack_gsm0610_wav49_to_voip(c, b); + //for (i = 0; i < 66; i++) + // printf("%2d: 0x%02X 0x%02X\n", i, a[i], c[i]); + if (memcmp(a, c, 66)) + { + printf("Test failed: data mismatch\n"); + exit(2); + } + } + printf("Test passed\n"); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +int main(int argc, char *argv[]) +{ + AFfilehandle inhandle; + AFfilehandle outhandle; + AFfilesetup filesetup; + int frames; + int outframes; + float x; + int16_t pre_amp[HIST_LEN]; + int16_t post_amp[HIST_LEN]; + uint8_t gsm0610_data[HIST_LEN]; + gsm0610_state_t *gsm0610_enc_state; + gsm0610_state_t *gsm0610_dec_state; + int etsitests; + int packing; + int i; + + etsitests = TRUE; + packing = GSM0610_PACKING_NONE; + for (i = 1; i < argc; i++) + { + if (strcmp(argv[i], "-l") == 0) + { + etsitests = FALSE; + continue; + } + if (strcmp(argv[i], "-p") == 0) + { + packing = atoi(argv[++i]); + continue; + } + fprintf(stderr, "Unknown parameter %s specified.\n", argv[i]); + exit(2); + } + + if (etsitests) + { + perform_linear_test(TRUE, 1, "Seq01"); + perform_linear_test(TRUE, 1, "Seq02"); + perform_linear_test(TRUE, 1, "Seq03"); + perform_linear_test(TRUE, 1, "Seq04"); + perform_linear_test(FALSE, 1, "Seq05"); + perform_law_test(TRUE, 'a', "Seq01"); + perform_law_test(TRUE, 'a', "Seq02"); + perform_law_test(TRUE, 'a', "Seq03"); + perform_law_test(TRUE, 'a', "Seq04"); + perform_law_test(FALSE, 'a', "Seq05"); + perform_law_test(TRUE, 'u', "Seq01"); + perform_law_test(TRUE, 'u', "Seq02"); + perform_law_test(TRUE, 'u', "Seq03"); + perform_law_test(TRUE, 'u', "Seq04"); + perform_law_test(FALSE, 'u', "Seq05"); + /* This is not actually an ETSI test */ + perform_pack_unpack_test(); + + printf("Tests passed.\n"); + } + else + { + if ((inhandle = afOpenFile(IN_FILE_NAME, "r", 0)) == AF_NULL_FILEHANDLE) + { + printf(" Cannot open wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if ((x = afGetFrameSize(inhandle, AF_DEFAULT_TRACK, 1)) != 2.0) + { + printf(" Unexpected frame size in wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if ((x = afGetRate(inhandle, AF_DEFAULT_TRACK)) != (float) SAMPLE_RATE) + { + printf(" Unexpected sample rate in wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if ((x = afGetChannels(inhandle, AF_DEFAULT_TRACK)) != 1.0) + { + printf(" Unexpected number of channels in wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if ((filesetup = afNewFileSetup()) == AF_NULL_FILESETUP) + { + fprintf(stderr, " Failed to create file setup\n"); + exit(2); + } + afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16); + afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE); + afInitFileFormat(filesetup, AF_FILE_WAVE); + afInitChannels(filesetup, AF_DEFAULT_TRACK, 1); + + outhandle = afOpenFile(OUT_FILE_NAME, "w", filesetup); + if (outhandle == AF_NULL_FILEHANDLE) + { + fprintf(stderr, " Cannot create wave file '%s'\n", OUT_FILE_NAME); + exit(2); + } + + if ((gsm0610_enc_state = gsm0610_init(NULL, packing)) == NULL) + { + fprintf(stderr, " Cannot create encoder\n"); + exit(2); + } + + if ((gsm0610_dec_state = gsm0610_init(NULL, packing)) == NULL) + { + fprintf(stderr, " Cannot create decoder\n"); + exit(2); + } + + while ((frames = afReadFrames(inhandle, AF_DEFAULT_TRACK, pre_amp, 2*BLOCK_LEN))) + { + gsm0610_encode(gsm0610_enc_state, gsm0610_data, pre_amp, (packing == GSM0610_PACKING_WAV49) ? 1 : 2); + gsm0610_decode(gsm0610_dec_state, post_amp, gsm0610_data, (packing == GSM0610_PACKING_WAV49) ? 1 : 2); + outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, post_amp, frames); + } + + if (afCloseFile(inhandle) != 0) + { + printf(" Cannot close wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if (afCloseFile(outhandle) != 0) + { + printf(" Cannot close wave file '%s'\n", OUT_FILE_NAME); + exit(2); + } + afFreeFileSetup(filesetup); + gsm0610_release(gsm0610_enc_state); + gsm0610_release(gsm0610_dec_state); + } + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/tests/ima_adpcm_tests.c b/libs/voipcodecs/tests/ima_adpcm_tests.c new file mode 100644 index 0000000000..ca40533c06 --- /dev/null +++ b/libs/voipcodecs/tests/ima_adpcm_tests.c @@ -0,0 +1,206 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * ima_adpcm_tests.c - Test the IMA/DVI/Intel ADPCM encode and decode + * software. + * + * Written by Steve Underwood + * + * Copyright (C) 2004 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ + +/*! \file */ + +/*! \page ima_adpcm_tests_page IMA ADPCM tests +\section ima_adpcm_tests_page_sec_1 What does it do? +To perform a general audio quality test, ima_adpcm_tests should be run. The test file +../localtests/short_nb_voice.wav will be compressed to the specified bit rate, +decompressed, and the resulting audio stored in post_ima_adpcm.wav. A simple SNR test +is automatically performed. Listening tests may be used for a more detailed evaluation +of the degradation in quality caused by the compression. + +\section ima_adpcm_tests_page_sec_2 How is it used? +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include "voipcodecs.h" + +#define IN_FILE_NAME "../localtests/short_nb_voice.wav" +#define OUT_FILE_NAME "post_ima_adpcm.wav" + +#define HIST_LEN 1000 + +int main(int argc, char *argv[]) +{ + int i; + AFfilehandle inhandle; + AFfilehandle outhandle; + AFfilesetup filesetup; + int frames; + int dec_frames; + int outframes; + int ima_bytes; + float x; + double pre_energy; + double post_energy; + double diff_energy; + int16_t pre_amp[HIST_LEN]; + int16_t post_amp[HIST_LEN]; + uint8_t ima_data[HIST_LEN]; + int16_t history[HIST_LEN]; + int hist_in; + int hist_out; + ima_adpcm_state_t *ima_enc_state; + ima_adpcm_state_t *ima_dec_state; + int xx; + int vbr; + const char *in_file_name; + + vbr = FALSE; + in_file_name = IN_FILE_NAME; + for (i = 1; i < argc; i++) + { + if (strcmp(argv[i], "-v") == 0) + { + vbr = TRUE; + continue; + } + if (strcmp(argv[i], "-i") == 0) + { + in_file_name = argv[++i]; + continue; + } + fprintf(stderr, "Unknown parameter %s specified.\n", argv[i]); + exit(2); + } + + if ((inhandle = afOpenFile(in_file_name, "r", 0)) == AF_NULL_FILEHANDLE) + { + printf(" Cannot open wave file '%s'\n", in_file_name); + exit(2); + } + if ((x = afGetFrameSize(inhandle, AF_DEFAULT_TRACK, 1)) != 2.0) + { + printf(" Unexpected frame size in wave file '%s'\n", in_file_name); + exit(2); + } + if ((x = afGetRate(inhandle, AF_DEFAULT_TRACK)) != (float) SAMPLE_RATE) + { + printf(" Unexpected sample rate in wave file '%s'\n", in_file_name); + exit(2); + } + if ((x = afGetChannels(inhandle, AF_DEFAULT_TRACK)) != 1.0) + { + printf(" Unexpected number of channels in wave file '%s'\n", in_file_name); + exit(2); + } + + if ((filesetup = afNewFileSetup()) == AF_NULL_FILESETUP) + { + fprintf(stderr, " Failed to create file setup\n"); + exit(2); + } + afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16); + afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE); + afInitFileFormat(filesetup, AF_FILE_WAVE); + afInitChannels(filesetup, AF_DEFAULT_TRACK, 1); + if ((outhandle = afOpenFile(OUT_FILE_NAME, "w", filesetup)) == AF_NULL_FILEHANDLE) + { + fprintf(stderr, " Cannot create wave file '%s'\n", OUT_FILE_NAME); + exit(2); + } + + if ((ima_enc_state = ima_adpcm_init(NULL, (vbr) ? IMA_ADPCM_VDVI : IMA_ADPCM_DVI4)) == NULL) + { + fprintf(stderr, " Cannot create encoder\n"); + exit(2); + } + + if ((ima_dec_state = ima_adpcm_init(NULL, (vbr) ? IMA_ADPCM_VDVI : IMA_ADPCM_DVI4)) == NULL) + { + fprintf(stderr, " Cannot create decoder\n"); + exit(2); + } + + hist_in = 0; + hist_out = 0; + pre_energy = 0.0; + post_energy = 0.0; + diff_energy = 0.0; + while ((frames = afReadFrames(inhandle, AF_DEFAULT_TRACK, pre_amp, 159))) + { + ima_bytes = ima_adpcm_encode(ima_enc_state, ima_data, pre_amp, frames); + dec_frames = ima_adpcm_decode(ima_dec_state, post_amp, ima_data, ima_bytes); + for (i = 0; i < frames; i++) + { + history[hist_in++] = pre_amp[i]; + if (hist_in >= HIST_LEN) + hist_in = 0; + pre_energy += (double) pre_amp[i] * (double) pre_amp[i]; + } + for (i = 0; i < dec_frames; i++) + { + post_energy += (double) post_amp[i] * (double) post_amp[i]; + xx = post_amp[i] - history[hist_out++]; + if (hist_out >= HIST_LEN) + hist_out = 0; + diff_energy += (double) xx * (double) xx; + } + outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, post_amp, dec_frames); + } + if (afCloseFile(inhandle) != 0) + { + printf(" Cannot close wave file '%s'\n", in_file_name); + exit(2); + } + if (afCloseFile(outhandle) != 0) + { + printf(" Cannot close wave file '%s'\n", OUT_FILE_NAME); + exit(2); + } + afFreeFileSetup(filesetup); + ima_adpcm_release(ima_enc_state); + ima_adpcm_release(ima_dec_state); + + printf("Output energy is %f%% of input energy.\n", 100.0*post_energy/pre_energy); + printf("Residual energy is %f%% of the total.\n", 100.0*diff_energy/post_energy); + if (fabs(1.0 - post_energy/pre_energy) > 0.05 + || + fabs(diff_energy/post_energy) > 0.03) + { + printf("Tests failed.\n"); + exit(2); + } + + printf("Tests passed.\n"); + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/tests/lpc10_tests.c b/libs/voipcodecs/tests/lpc10_tests.c new file mode 100644 index 0000000000..b7f5afa258 --- /dev/null +++ b/libs/voipcodecs/tests/lpc10_tests.c @@ -0,0 +1,307 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * lpc10_tests.c - Test the LPC10 low bit rate speech codec. + * + * Written by Steve Underwood + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: lpc10_tests.c,v 1.11 2007/11/10 11:14:58 steveu Exp $ + */ + +/*! \file */ + +/*! \page lpc10_tests_page LPC10 codec tests +\section lpc10_tests_page_sec_1 What does it do? + +\section lpc10_tests_page_sec_2 How is it used? +To perform a general audio quality test, lpc10 should be run. The file ../localtests/short_nb_voice.wav +will be compressed to LPC10 data, decompressed, and the resulting audio stored in post_lpc10.wav. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "voipcodecs.h" + +#define BLOCK_LEN 180 + +#define BLOCKS_PER_READ 1 + +#define IN_FILE_NAME "../localtests/dam9.wav" +#define REF_FILE_NAME "../localtests/dam9_lpc55.wav" +#define COMPRESS_FILE_NAME "lpc10_out.lpc10" +#define DECOMPRESS_FILE_NAME "lpc10_in.lpc10" +#define OUT_FILE_NAME "post_lpc10.wav" + +int main(int argc, char *argv[]) +{ + AFfilehandle inhandle; + AFfilehandle refhandle; + AFfilehandle outhandle; + AFfilesetup filesetup; + int frames; + int outframes; + float x; + double pre_energy; + double post_energy; + double ref_energy; + double diff_energy; + int16_t pre_amp[BLOCKS_PER_READ*BLOCK_LEN]; + int16_t post_amp[BLOCKS_PER_READ*BLOCK_LEN]; + int16_t ref_amp[BLOCKS_PER_READ*BLOCK_LEN]; + int16_t log_amp[BLOCKS_PER_READ*BLOCK_LEN*3]; + uint8_t lpc10_data[BLOCKS_PER_READ*7]; + double xx; + lpc10_encode_state_t *lpc10_enc_state; + lpc10_decode_state_t *lpc10_dec_state; + int i; + int block_no; + int log_error; + int compress; + int decompress; + const char *in_file_name; + int compress_file; + int decompress_file; + int len; + + compress = FALSE; + decompress = FALSE; + log_error = TRUE; + in_file_name = IN_FILE_NAME; + for (i = 1; i < argc; i++) + { + if (strcmp(argv[i], "-c") == 0) + { + compress = TRUE; + continue; + } + if (strcmp(argv[i], "-d") == 0) + { + decompress = TRUE; + continue; + } + if (strcmp(argv[i], "-i") == 0) + { + in_file_name = argv[++i]; + continue; + } + if (strcmp(argv[i], "-l") == 0) + { + log_error = FALSE; + continue; + } + } + + compress_file = -1; + decompress_file = -1; + inhandle = AF_NULL_FILEHANDLE; + refhandle = AF_NULL_FILEHANDLE; + outhandle = AF_NULL_FILEHANDLE; + if (!decompress) + { + if ((inhandle = afOpenFile(in_file_name, "r", 0)) == AF_NULL_FILEHANDLE) + { + printf(" Cannot open wave file '%s'\n", in_file_name); + exit(2); + } + if ((x = afGetFrameSize(inhandle, AF_DEFAULT_TRACK, 1)) != 2.0) + { + printf(" Unexpected frame size in wave file '%s'\n", in_file_name); + exit(2); + } + if ((x = afGetRate(inhandle, AF_DEFAULT_TRACK)) != (float) SAMPLE_RATE) + { + printf(" Unexpected sample rate in wave file '%s'\n", in_file_name); + exit(2); + } + if ((x = afGetChannels(inhandle, AF_DEFAULT_TRACK)) != 1.0) + { + printf(" Unexpected number of channels in wave file '%s'\n", in_file_name); + exit(2); + } + if ((filesetup = afNewFileSetup()) == AF_NULL_FILESETUP) + { + fprintf(stderr, " Failed to create file setup\n"); + exit(2); + } + + if ((refhandle = afOpenFile(REF_FILE_NAME, "r", 0)) == AF_NULL_FILEHANDLE) + { + printf(" Cannot open wave file '%s'\n", REF_FILE_NAME); + exit(2); + } + if ((x = afGetFrameSize(refhandle, AF_DEFAULT_TRACK, 1)) != 2.0) + { + printf(" Unexpected frame size in wave file '%s'\n", REF_FILE_NAME); + exit(2); + } + if ((x = afGetRate(refhandle, AF_DEFAULT_TRACK)) != (float) SAMPLE_RATE) + { + printf(" Unexpected sample rate in wave file '%s'\n", REF_FILE_NAME); + exit(2); + } + if ((x = afGetChannels(refhandle, AF_DEFAULT_TRACK)) != 1.0) + { + printf(" Unexpected number of channels in wave file '%s'\n", REF_FILE_NAME); + exit(2); + } + } + else + { + if ((decompress_file = open(DECOMPRESS_FILE_NAME, O_RDONLY)) < 0) + { + fprintf(stderr, " Cannot open decompressed data file '%s'\n", DECOMPRESS_FILE_NAME); + exit(2); + } + } + + if ((filesetup = afNewFileSetup()) == AF_NULL_FILESETUP) + { + fprintf(stderr, " Failed to create file setup\n"); + exit(2); + } + afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16); + afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE); + afInitFileFormat(filesetup, AF_FILE_WAVE); + afInitChannels(filesetup, AF_DEFAULT_TRACK, 1); + + if ((outhandle = afOpenFile(OUT_FILE_NAME, "w", filesetup)) == AF_NULL_FILEHANDLE) + { + fprintf(stderr, " Cannot create wave file '%s'\n", OUT_FILE_NAME); + exit(2); + } + + if ((lpc10_enc_state = lpc10_encode_init(NULL, TRUE)) == NULL) + { + fprintf(stderr, " Cannot create encoder\n"); + exit(2); + } + + if ((lpc10_dec_state = lpc10_decode_init(NULL, TRUE)) == NULL) + { + fprintf(stderr, " Cannot create decoder\n"); + exit(2); + } + + if (compress) + { + if ((compress_file = open(COMPRESS_FILE_NAME, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) + { + fprintf(stderr, " Cannot create compressed data file '%s'\n", COMPRESS_FILE_NAME); + exit(2); + } + } + + pre_energy = 0.0; + post_energy = 0.0; + ref_energy = 0.0; + diff_energy = 0.0; + + if (decompress) + { + while ((len = read(decompress_file, lpc10_data, BLOCKS_PER_READ*7)) > 0) + { + lpc10_decode(lpc10_dec_state, post_amp, lpc10_data, len/7); + outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, post_amp, BLOCK_LEN*len/7); + } + } + else + { + block_no = 0; + while ((frames = afReadFrames(inhandle, AF_DEFAULT_TRACK, pre_amp, BLOCKS_PER_READ*BLOCK_LEN)) == BLOCKS_PER_READ*BLOCK_LEN + && + (frames = afReadFrames(refhandle, AF_DEFAULT_TRACK, ref_amp, BLOCKS_PER_READ*BLOCK_LEN)) == BLOCKS_PER_READ*BLOCK_LEN) + { + lpc10_encode(lpc10_enc_state, lpc10_data, pre_amp, BLOCKS_PER_READ); + if (compress) + write(compress_file, lpc10_data, BLOCKS_PER_READ*7); + lpc10_decode(lpc10_dec_state, post_amp, lpc10_data, BLOCKS_PER_READ); + for (i = 0; i < BLOCK_LEN; i++) + { + pre_energy += (double) pre_amp[i]*(double) pre_amp[i]; + post_energy += (double) post_amp[i]*(double) post_amp[i]; + ref_energy += (double) ref_amp[i]*(double) ref_amp[i]; + /* The reference file has some odd clipping, so eliminate this from the + energy measurement. */ + if (ref_amp[i] == 32767 || ref_amp[i] == -32768) + xx = 0.0; + else + xx = post_amp[i] - ref_amp[i]; + diff_energy += (double) xx*(double) xx; + log_amp[i] = xx; + } + block_no++; + if (log_error) + outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, log_amp, frames); + else + outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, post_amp, frames); + } + if (afCloseFile(inhandle) != 0) + { + printf(" Cannot close wave file '%s'\n", in_file_name); + exit(2); + } + if (afCloseFile(refhandle) != 0) + { + printf(" Cannot close wave file '%s'\n", REF_FILE_NAME); + exit(2); + } + } + + if (afCloseFile(outhandle) != 0) + { + printf(" Cannot close wave file '%s'\n", OUT_FILE_NAME); + exit(2); + } + afFreeFileSetup(filesetup); + if (compress) + close(compress_file); + if (decompress) + close(decompress_file); + lpc10_encode_release(lpc10_enc_state); + lpc10_decode_release(lpc10_dec_state); + + if (!decompress) + { + printf("Output energy is %f%% of input energy.\n", 100.0*post_energy/pre_energy); + printf("Difference energy is %f%% of the total.\n", 100.0*diff_energy/ref_energy); + if (fabs(1.0 - post_energy/pre_energy) > 0.05 + || + fabs(diff_energy/post_energy) > 0.03) + { + printf("Tests failed.\n"); + exit(2); + } + printf("Tests passed.\n"); + } + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/tests/oki_adpcm_tests.c b/libs/voipcodecs/tests/oki_adpcm_tests.c new file mode 100644 index 0000000000..eb1cc3ecf4 --- /dev/null +++ b/libs/voipcodecs/tests/oki_adpcm_tests.c @@ -0,0 +1,239 @@ +/* + * VoIPcodecs - a series of DSP components for telephony + * + * oki_adpcm_tests.c - Test the Oki (Dialogic) ADPCM encode and decode + * software at 24kbps and 32kbps. + * + * Written by Steve Underwood + * + * Copyright (C) 2004 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: oki_adpcm_tests.c,v 1.24 2007/11/10 11:14:58 steveu Exp $ + */ + +/*! \file */ + +/*! \page oki_adpcm_tests_page OKI (Dialogic) ADPCM tests +\section oki_adpcm_tests_page_sec_1 What does it do? +To perform a general audio quality test, oki_adpcm_tests should be run. The test file +../localtests/short_nb_voice.wav will be compressed to the specified bit rate, +decompressed, and the resulting audio stored in post_oki_adpcm.wav. A simple SNR test +is automatically performed. Listening tests may be used for a more detailed evaluation +of the degradation in quality caused by the compression. Both 32k bps and 24k bps +compression may be tested. + +\section oki_adpcm_tests_page_sec_2 How is it used? +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include "voipcodecs.h" + +#define IN_FILE_NAME "../localtests/short_nb_voice.wav" +#define OUT_FILE_NAME "post_oki_adpcm.wav" + +#define HIST_LEN 1000 + +int main(int argc, char *argv[]) +{ + int i; + AFfilehandle inhandle; + AFfilehandle outhandle; + AFfilesetup filesetup; + int frames; + int dec_frames; + int outframes; + int oki_bytes; + int bit_rate; + float x; + double pre_energy; + double post_energy; + double diff_energy; + int16_t pre_amp[HIST_LEN]; + int16_t post_amp[HIST_LEN]; + uint8_t oki_data[HIST_LEN]; + int16_t history[HIST_LEN]; + int hist_in; + int hist_out; + oki_adpcm_state_t *oki_enc_state; + oki_adpcm_state_t *oki_dec_state; + int xx; + int total_pre_samples; + int total_compressed_bytes; + int total_post_samples; + const char *in_file_name; + + bit_rate = 32000; + in_file_name = IN_FILE_NAME; + for (i = 1; i < argc; i++) + { + if (strcmp(argv[i], "-2") == 0) + { + bit_rate = 24000; + continue; + } + if (strcmp(argv[i], "-i") == 0) + { + in_file_name = argv[++i]; + continue; + } + fprintf(stderr, "Unknown parameter %s specified.\n", argv[i]); + exit(2); + } + + if ((inhandle = afOpenFile(in_file_name, "r", 0)) == AF_NULL_FILEHANDLE) + { + printf(" Cannot open wave file '%s'\n", in_file_name); + exit(2); + } + if ((x = afGetFrameSize(inhandle, AF_DEFAULT_TRACK, 1)) != 2.0) + { + printf(" Unexpected frame size in wave file '%s'\n", in_file_name); + exit(2); + } + if ((x = afGetRate(inhandle, AF_DEFAULT_TRACK)) != (float) SAMPLE_RATE) + { + printf(" Unexpected sample rate in wave file '%s'\n", in_file_name); + exit(2); + } + if ((x = afGetChannels(inhandle, AF_DEFAULT_TRACK)) != 1.0) + { + printf(" Unexpected number of channels in wave file '%s'\n", in_file_name); + exit(2); + } + if ((filesetup = afNewFileSetup()) == AF_NULL_FILESETUP) + { + fprintf(stderr, " Failed to create file setup\n"); + exit(2); + } + afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16); + afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE); + afInitFileFormat(filesetup, AF_FILE_WAVE); + afInitChannels(filesetup, AF_DEFAULT_TRACK, 1); + + outhandle = afOpenFile(OUT_FILE_NAME, "w", filesetup); + if (outhandle == AF_NULL_FILEHANDLE) + { + fprintf(stderr, " Cannot create wave file '%s'\n", OUT_FILE_NAME); + exit(2); + } + + if ((oki_enc_state = oki_adpcm_init(NULL, bit_rate)) == NULL) + { + fprintf(stderr, " Cannot create encoder\n"); + exit(2); + } + + if ((oki_dec_state = oki_adpcm_init(NULL, bit_rate)) == NULL) + { + fprintf(stderr, " Cannot create decoder\n"); + exit(2); + } + + hist_in = 0; + if (bit_rate == 32000) + hist_out = 0; + else + hist_out = HIST_LEN - 27; + memset(history, 0, sizeof(history)); + pre_energy = 0.0; + post_energy = 0.0; + diff_energy = 0.0; + total_pre_samples = 0; + total_compressed_bytes = 0; + total_post_samples = 0; + while ((frames = afReadFrames(inhandle, AF_DEFAULT_TRACK, pre_amp, 159))) + { + total_pre_samples +=frames; + oki_bytes = oki_adpcm_encode(oki_enc_state, oki_data, pre_amp, frames); + total_compressed_bytes += oki_bytes; + dec_frames = oki_adpcm_decode(oki_dec_state, post_amp, oki_data, oki_bytes); + total_post_samples += dec_frames; + for (i = 0; i < frames; i++) + { + history[hist_in++] = pre_amp[i]; + if (hist_in >= HIST_LEN) + hist_in = 0; + pre_energy += (double) pre_amp[i] * (double) pre_amp[i]; + } + for (i = 0; i < dec_frames; i++) + { + post_energy += (double) post_amp[i] * (double) post_amp[i]; + xx = post_amp[i] - history[hist_out++]; + if (hist_out >= HIST_LEN) + hist_out = 0; + diff_energy += (double) xx * (double) xx; + //post_amp[i] = xx; + } + outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, post_amp, dec_frames); + } + if (afCloseFile(inhandle) != 0) + { + printf(" Cannot close wave file '%s'\n", in_file_name); + exit(2); + } + if (afCloseFile(outhandle) != 0) + { + printf(" Cannot close wave file '%s'\n", OUT_FILE_NAME); + exit(2); + } + afFreeFileSetup(filesetup); + oki_adpcm_release(oki_enc_state); + oki_adpcm_release(oki_dec_state); + + printf("Pre samples: %d\n", total_pre_samples); + printf("Compressed bytes: %d\n", total_compressed_bytes); + printf("Post samples: %d\n", total_post_samples); + + printf("Output energy is %f%% of input energy.\n", 100.0*post_energy/pre_energy); + printf("Residual energy is %f%% of the total.\n", 100.0*diff_energy/post_energy); + if (bit_rate == 32000) + { + if (fabs(1.0 - post_energy/pre_energy) > 0.05 + || + fabs(diff_energy/post_energy) > 0.03) + { + printf("Tests failed.\n"); + exit(2); + } + } + else + { + if (fabs(1.0 - post_energy/pre_energy) > 0.20 + || + fabs(diff_energy/post_energy) > 0.10) + { + printf("Tests failed.\n"); + exit(2); + } + } + + printf("Tests passed.\n"); + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/voipcodecs/tests/regression_tests.sh b/libs/voipcodecs/tests/regression_tests.sh new file mode 100755 index 0000000000..9d5817ac3d --- /dev/null +++ b/libs/voipcodecs/tests/regression_tests.sh @@ -0,0 +1,93 @@ +#!/bin/sh +# +# VoIPcodecs - a series of DSP components for telephony +# +# regression_tests.sh +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# $Id: regression_tests.sh,v 1.47 2007/12/22 12:37:22 steveu Exp $ +# + +STDOUT_DEST=xyzzy +STDERR_DEST=xyzzy2 + +echo Performing basic VoIP codecs regression tests +echo + +./g711_tests >$STDOUT_DEST 2>$STDERR_DEST +RETVAL=$? +if [ $RETVAL != 0 ] +then + echo g711_tests failed! + exit $RETVAL +fi +echo g711_tests completed OK + +./g722_tests >$STDOUT_DEST 2>$STDERR_DEST +RETVAL=$? +if [ $RETVAL != 0 ] +then + echo g722_tests failed! + exit $RETVAL +fi +echo g722_tests completed OK + +./g726_tests >$STDOUT_DEST 2>$STDERR_DEST +RETVAL=$? +if [ $RETVAL != 0 ] +then + echo g726_tests failed! + exit $RETVAL +fi +echo g726_tests completed OK + +./gsm0610_tests >$STDOUT_DEST 2>$STDERR_DEST +RETVAL=$? +if [ $RETVAL != 0 ] +then + echo gsm0610_tests failed! + exit $RETVAL +fi +echo gsm0610_tests completed OK + +./ima_adpcm_tests >$STDOUT_DEST 2>$STDERR_DEST +RETVAL=$? +if [ $RETVAL != 0 ] +then + echo ima_adpcm_tests failed! + exit $RETVAL +fi +echo ima_adpcm_tests completed OK + +./lpc10_tests >$STDOUT_DEST 2>$STDERR_DEST +RETVAL=$? +if [ $RETVAL != 0 ] +then + echo lpc10_tests failed! + exit $RETVAL +fi +echo lpc10_tests completed OK + +./oki_adpcm_tests >$STDOUT_DEST 2>$STDERR_DEST +RETVAL=$? +if [ $RETVAL != 0 ] +then + echo oki_adpcm_tests failed! + exit $RETVAL +fi +echo oki_adpcm_tests completed OK + +echo +echo All regression tests successfully completed diff --git a/libs/voipcodecs/voipcodecs.spec.in b/libs/voipcodecs/voipcodecs.spec.in new file mode 100644 index 0000000000..ac69fe9393 --- /dev/null +++ b/libs/voipcodecs/voipcodecs.spec.in @@ -0,0 +1,65 @@ +Summary: VoIPcodecs is a library of unencumbered codecs commonly used for VoIP +Name: @PACKAGE@ +Version: @VERSION@ +Release: 1 +License: GPL +Group: System Environment/Libraries +URL: http://www.soft-switch.org/voipcodecs +BuildRoot: %{_tmppath}/%{name}-%{version}-root +Source: http://www.soft-switch.org/downloads/voipcodecs/@PACKAGE@-@VERSION@.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +Docdir: %{_prefix}/doc + +BuildRequires: audiofile-devel +BuildRequires: doxygen + +%description +VoIPcodecs is a library of unencumbered codecs commonly used for VoIP. + +%package devel +Summary: VoIPcodecs development files +Group: Development/Libraries +Requires: voipcodecs = %{version} +PreReq: /sbin/install-info + +%description devel +VoIPcodecs development files. + +%prep +%setup -q + +%build +%configure --enable-doc --disable-static --disable-rpath +make + +%install +rm -rf %{buildroot} +make install DESTDIR=%{buildroot} +rm %{buildroot}%{_libdir}/libvoipcodecs.la + +%clean +rm -rf %{buildroot} + +%files +%defattr(-,root,root,-) +%doc ChangeLog AUTHORS COPYING NEWS README + +%{_libdir}/libvoipcodecs.so.* + +%{_datadir}/voipcodecs + +%files devel +%defattr(-,root,root,-) +%doc doc/api +%{_includedir}/voipcodecs.h +%{_includedir}/voipcodecs +%{_libdir}/libvoipcodecs.so + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%changelog +* Thu Feb 7 2008 Steve Underwood 0.0.1 +- First pass diff --git a/libs/voipcodecs/wrapper.xsl b/libs/voipcodecs/wrapper.xsl new file mode 100644 index 0000000000..89e314d781 --- /dev/null +++ b/libs/voipcodecs/wrapper.xsl @@ -0,0 +1,5 @@ + + + css.css + \ No newline at end of file