mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-07-04 19:31:56 +00:00
inital checkin of spandsp from http://www.soft-switch.org/downloads/snapshots/spandsp/spandsp-20080829.tar.gz
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@9425 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
@@ -0,0 +1 @@
|
||||
Steve Underwood <steveu@coppice.org>
|
||||
@@ -0,0 +1,853 @@
|
||||
The spandsp library is licenced under LGPL 2.1. The test suite, and some of
|
||||
the supporting code, are licenced under GPL 2. The full text of both licences
|
||||
may be found below.
|
||||
|
||||
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
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 and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, 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 library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete 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 distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
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 Library or any portion
|
||||
of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
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 Library, 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 Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you 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.
|
||||
|
||||
If distribution of 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 satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be 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.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library 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.
|
||||
|
||||
9. 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 Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
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 with
|
||||
this License.
|
||||
|
||||
11. 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 Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library 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 Library.
|
||||
|
||||
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.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library 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.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser 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 Library
|
||||
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 Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
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
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "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
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. 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 LIBRARY 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
|
||||
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. 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.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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.
|
||||
|
||||
<signature of Ty Coon>, 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.
|
||||
@@ -0,0 +1,47 @@
|
||||
07.08.29 - 0.0.4 - Steve Underwood <steveu@coppice.org>
|
||||
-
|
||||
|
||||
06.05.23 - 0.0.3 - Steve Underwood <steveu@coppice.org>
|
||||
- T.38 now implemented, though it needs further polishing.
|
||||
- G.726 and G.722 now implemented.
|
||||
|
||||
04.08.29 - 0.0.2 - Steve Underwood <steveu@coppice.org>
|
||||
- T.4 no longer uses libtiff for compresion and decompression on the line side
|
||||
(it is still used to handle the TIFF files). Spandsp no longer depends on
|
||||
accessing the "internals" of libtiff. New 1D and 2D compression and
|
||||
decompression code now handles the line side. This should be more robust than
|
||||
using libtiff, and handles the fudging of bad scan lines rather better.
|
||||
- T.30 line turn-around timing corrected.
|
||||
- T.30 DCS header contents corrected.
|
||||
- T.30 provision for V.17 added, as an option.
|
||||
- T.30 now has a statistics interface, for applications to find details about
|
||||
image transfers.
|
||||
- T.30 processing now correctly closes TIFF files are they have been sent.
|
||||
- FAX header line insertion is now supported for transmitted FAXes.
|
||||
- asynchronous serial processing now has a V.14 compatible rate adaption option.
|
||||
- V.8 modem negotiation module added.
|
||||
- OKI ADPCM now supports Dialogic compatible operation at 6k samples/second, as
|
||||
well as 8k samples/second, using its own sample rate converter.
|
||||
- message queuing added to ease things like T.31 handling
|
||||
- incomplete skeleton (still rather nasty, to be honest) T.31 processing.
|
||||
- incomplete skeleton of V.22bis added. There is probably quite a bit to do
|
||||
to get this complete and robust. It probably requires the T.31 processing
|
||||
be expanded to something more like V.250, so it doesn't just handle FAX.
|
||||
- Incomplete V.17 added (there could be an IBM patent related to the TCM part of
|
||||
V.17, but I think it has expired. Don't distribute binaries of spandsp built
|
||||
with V.17 enabled until this is resolved - and the modem is completed, of
|
||||
course :-) ). The current version transmits OK. It receives OK with the
|
||||
long training sequence, but the symbol and carrier syncing isn't good enough
|
||||
for robust receiving with the short training sequence.
|
||||
- A basic BER tester has been added.
|
||||
- The faster modems now have proper shutdown procedures, whether one is defined in
|
||||
the spec. or not.
|
||||
- The modems (except simple FSK) now have APIs to access performance information.
|
||||
- A common GUI (using FLTK) added for the modem tests.
|
||||
- A bit more documentation added.
|
||||
- Some API inconsistencies cleaned up.
|
||||
- The usual bundle of assorted buglet fixes and polishing.
|
||||
|
||||
04.04.29 - 0.0.1k - Steve Underwood <steveu@coppice.org>
|
||||
- The first version which gives solid faxing for a large number of people.
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
Intellectual Property Due Diligence
|
||||
-----------------------------------
|
||||
|
||||
Modems and voice coding are heavily patented areas. Implementing these without
|
||||
serious consideration of IP issues would be foolish. This document describes
|
||||
the basis on which the software has been implemented.
|
||||
|
||||
|
||||
A check of the intellectual property information at the ITU web site shows a
|
||||
number of patent claims against the current standards implemented by spandsp.
|
||||
It is important to realise, however, that some of these patents have long
|
||||
since expired (group III fax dates back to the 1970s). Also, many are
|
||||
related to recent additions to the FAX standard, such as colour FAX handling,
|
||||
which few people ever use.
|
||||
|
||||
The V.14 rate adaption standard seems free of patent encumberance.
|
||||
|
||||
One patent is listed as relevant to the V.17 standard. It is a patent from
|
||||
IBM, but the ITU database does not specify its nature. I believe it is
|
||||
related to the trellis coding used, and I think it has expired. I do not
|
||||
know for sure. The techniques used in the implementation should be free of
|
||||
patent encumberance. Most of the implementation is similar to the V.29
|
||||
modem. The key addition the trellis code processing. The trellis encoding
|
||||
is trivial. The decoding uses Viterbi techniques, which are quite old.
|
||||
|
||||
The V.21 standard dates from the 1950s. The V.23 standard is also very old.
|
||||
There is no possibility that any patents related to it are still in force.
|
||||
However, the implementation also needs to be free of patented techniques.
|
||||
The implementation only uses very mature numerical oscillator and quadrature
|
||||
correlation techniques, so there should be no patent issues.
|
||||
|
||||
Only one patent is listed as relevant to the V.29 standard. This dates from
|
||||
the 1970s, and must have expired. The modem has been implemented using only
|
||||
very mature techniques, none of which can be less than 20 years old. There
|
||||
seem no possibility, therefore, that any patents are still in force related
|
||||
to the techniques used.
|
||||
|
||||
Some aspect of the V.8 standard seems to have patents associated with it,
|
||||
according to the ITU patent database. I am unclear what these are. V.8 is a
|
||||
very simple standard. There seems to be nothing innovative about it.
|
||||
|
||||
Many patents are listed as relevant to the T.30 standard. However, they all
|
||||
appear to relate to newer features, such as colour FAX, added in recent years.
|
||||
The current implementation only covers the original features from the late
|
||||
1970s, where there appear to be patent issues.
|
||||
|
||||
The T.4 standard defines the image compression and decompression techniques
|
||||
used for group 3 FAXes. The spandsp implementation is based on code derived
|
||||
from freely available implementations of T.4. These have existed for a number
|
||||
of years without IP issues. The standard is old enough for any patents to have
|
||||
expired, anyway.
|
||||
|
||||
V.42bis compression uses the LZW algorithm. This is the same algorithm used in
|
||||
GIF files. Unisys patented this algorithm. However, the Unisys patent has now
|
||||
expired.
|
||||
@@ -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.
|
||||
@@ -0,0 +1,104 @@
|
||||
##
|
||||
## 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 Lesser 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 Lesser General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU Lesser 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.40 2008/07/15 14:28:20 steveu Exp $
|
||||
|
||||
AM_CFLAGS = $(COMP_VENDOR_CFLAGS)
|
||||
AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS)
|
||||
|
||||
noinst_SCRIPTS = spandsp.spec
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
EXTRA_DIST = autogen.sh \
|
||||
DueDiligence \
|
||||
README.testdata \
|
||||
spandsp.spec \
|
||||
wrapper.xsl \
|
||||
libspandsp.vcproj \
|
||||
unpack_g722_data.sh \
|
||||
unpack_g726_data.sh \
|
||||
unpack_gsm0610_data.sh \
|
||||
unpack_v56ter_data.sh \
|
||||
doc/doxygen.in \
|
||||
src/floating_fudge.h \
|
||||
src/spandsp/version.h.in \
|
||||
src/libspandsp.dsp \
|
||||
src/libspandsp.sln \
|
||||
src/msvc/gettimeofday.c \
|
||||
src/msvc/inttypes.h \
|
||||
src/msvc/tgmath.h \
|
||||
src/msvc/unistd.h \
|
||||
src/msvc/sys/time.h \
|
||||
src/msvc/spandsp.def \
|
||||
src/msvc/msvcproj.head \
|
||||
src/msvc/msvcproj.foot \
|
||||
src/msvc/vc8proj.head \
|
||||
src/msvc/vc8proj.foot \
|
||||
spandsp/global-tones.xml \
|
||||
spandsp/tones.dtd \
|
||||
spandsp/tsb85.xml \
|
||||
debian/changelog \
|
||||
debian/compat \
|
||||
debian/control \
|
||||
debian/copyright \
|
||||
debian/libspandsp5.install \
|
||||
debian/libspandsp-dev.install \
|
||||
debian/libspandsp-doc.install \
|
||||
debian/rules \
|
||||
debian/watch
|
||||
|
||||
if COND_DOC
|
||||
MAYBE_DOC=doc
|
||||
endif
|
||||
if COND_TESTS
|
||||
MAYBE_TESTS=spandsp-sim tests
|
||||
endif
|
||||
if COND_TESTDATA
|
||||
MAYBE_TESTDATA=test-data
|
||||
endif
|
||||
SUBDIRS = src $(MAYBE_DOC) $(MAYBE_TESTS) $(MAYBE_TESTDATA)
|
||||
|
||||
DIST_SUBDIRS = src doc spandsp-sim tests test-data
|
||||
|
||||
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: spandsp.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'/' \
|
||||
<spandsp.spec >spandsp.spec.new; \
|
||||
mv spandsp.spec.new spandsp.spec
|
||||
@@ -0,0 +1 @@
|
||||
No news is good news!
|
||||
@@ -0,0 +1,35 @@
|
||||
spandsp 0.0.4 - A DSP library for telephony
|
||||
-------------------------------------------
|
||||
|
||||
SpanDSP is a library of DSP functions for telephony, in the 8000 sample per
|
||||
second world of E1s, T1s, and higher order PCM channels. It contains low level
|
||||
functions, such as basic filters. It also contains higher level functions, such
|
||||
as cadenced supervisory tone detection, and a complete software FAX machine.
|
||||
The software has been designed to avoid intellectual property issues, using
|
||||
mature techniques where all relevant patents have expired. See the file
|
||||
DueDiligence for important information about these intellectual property issues.
|
||||
|
||||
The library is licenced under the LGPL 2.1 licence. The test suite, and some support
|
||||
programs are licenced under the GPL 2 licence. The full text of these licences can
|
||||
be found in the file COPYING.
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
spandsp depends on various other packages for various tasks. Most of these
|
||||
dependencies relate to building the test suite.
|
||||
|
||||
libtiff (and libtiff-devel on most Linux distributions) is required to
|
||||
build the spandsp library.
|
||||
|
||||
libaudiofile (and libaudiofile-devel) is required to build the test suite
|
||||
fftw (and fftw-devel) is required to build the test suite. Version 2 or 3 of
|
||||
FFTW may be used. Spandsp adapts to the differences between them.
|
||||
|
||||
fltk (and fltk-devel), Fl_Cartesian and Fl_Audio_Meter are required to build the
|
||||
test suite with GUI interfaces for some of the tests. The tests will build
|
||||
without these packages, but the GUI features will not be available.
|
||||
Fl_Cartesian and Fl_Audio_Meter can be downloaded from
|
||||
http://www.soft-switch.org/downloads.
|
||||
|
||||
Steve Underwood <steveu@coppice.org>
|
||||
@@ -0,0 +1,53 @@
|
||||
Setting up test data for the supplied suite of test programs.
|
||||
-------------------------------------------------------------
|
||||
|
||||
Some of the tests in the test suite for this package require test data files. These test
|
||||
data files fall into four categories:
|
||||
|
||||
- Some data files, such as those for some of the FAX tests, are generated by programs
|
||||
in the package.
|
||||
|
||||
- Some are freely distributable data files, from various sources. These are supplied
|
||||
with the package.
|
||||
|
||||
- Some are test data files from a standards body. These are the copyright material of
|
||||
the standards body, and so cannot be distributed with this package. However, most of
|
||||
these files can currently be downloaded at no charge from the standards body's web
|
||||
site. This file describes which files are needed, and how they may be processed to
|
||||
produce the right files in the right places for the tests.
|
||||
|
||||
- The two industry standard sources of test data for DTMF decoders are Bellcore/Telcordia
|
||||
and Mitel. Neither of these is either free, or supplied in a form directly usable
|
||||
with the test suite. These data sources are expected by several tests, and not just
|
||||
the DTMF decoder tests. Sad to say, you are on your own when trying to source data
|
||||
for these tests.
|
||||
|
||||
For the G.722 tests, obtain the file T-REC-G.722-198703-I!AppII!ZPF-E.zip from the ITU web site,
|
||||
and place it in this directory. Then run
|
||||
|
||||
./unpack_g722_data.sh
|
||||
|
||||
For the G.726 tests, obtain the file T-REC-G.726-199103-I!AppII!SOFT-ZST-E.zip from the ITU web
|
||||
site, and place it in this directory. Then run
|
||||
|
||||
./unpack_g726_data.sh
|
||||
|
||||
For the GSM 06.10 tests, obtain the file en_300961v080101p0.zip from the ETSI web site,
|
||||
and place it in this directory. If you are able to run .exe (i.e. MS DOS or Windows)
|
||||
files you can simply run
|
||||
|
||||
./unpack_gsm0610_data.sh
|
||||
|
||||
If you are unable to run .exe files on the machine you are using (e.e. you are not using Cygwin,
|
||||
Mingw, Wine, FreeDOS or something of that sort) you will need to find a machine which will. First,
|
||||
run
|
||||
|
||||
./unpack_gsm0610_data.sh --no-exe
|
||||
|
||||
This will leave 6 .EXE files in the etsitetss/gsm0610 directory. Take these to a machine which
|
||||
can run .EXE files, and execute all of them. This should result in a number of files which end
|
||||
with .COD, INP and .OUT. Copy these to the etsitests/gsm0610 directory, and run
|
||||
|
||||
./unpack_gsm0610_data.sh --no-exe-continue
|
||||
|
||||
The remainder of the extraction and repacking of files should then take place.
|
||||
Vendored
+7489
File diff suppressed because it is too large
Load Diff
Executable
+145
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env sh
|
||||
#
|
||||
# SpanDSP - a series of DSP components for telephony
|
||||
#
|
||||
# autogen script
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser 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 Lesser General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
#
|
||||
# $Id: autogen.sh,v 1.6 2008/03/30 18:33:24 steveu Exp $
|
||||
#
|
||||
|
||||
UNAME=`uname`
|
||||
|
||||
if [ "x$UNAME" = "xFreeBSD" ]; then
|
||||
echo ""
|
||||
echo ""
|
||||
echo "******************************************"
|
||||
echo "*** NOTICE ***"
|
||||
echo "******************************************"
|
||||
echo " "
|
||||
echo "FreeBSD is buggy. Please use this "
|
||||
echo "workaround if you want to bootstrap "
|
||||
echo "on FreeBSD. "
|
||||
echo " "
|
||||
echo "cd /usr/local/share/aclocal19 "
|
||||
echo "ln -s ../aclocal/libtool15.m4 . "
|
||||
echo "ln -s ../aclocal/ltdl15.m4 . "
|
||||
echo " "
|
||||
echo "******************************************"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
debug ()
|
||||
{
|
||||
# Outputs debug statments if DEBUG var is set
|
||||
if [ ! -z "$DEBUG" ]; then
|
||||
echo "DEBUG: $1"
|
||||
fi
|
||||
}
|
||||
|
||||
version_compare()
|
||||
{
|
||||
# Checks a command is found and the version is high enough
|
||||
PROGRAM=$1
|
||||
MAJOR=$2
|
||||
MINOR=$3
|
||||
MICRO=$4
|
||||
test -z "$MAJOR" && MAJOR=0
|
||||
test -z "$MINOR" && MINOR=0
|
||||
test -z "$MICRO" && MICRO=0
|
||||
|
||||
debug "Checking $PROGRAM >= $MAJOR.$MINOR.$MICRO"
|
||||
|
||||
WHICH_PATH=`whereis which | cut -f2 -d' '`
|
||||
COMMAND=`$WHICH_PATH $PROGRAM`
|
||||
if [ -z $COMMAND ]; then
|
||||
echo "$PROGRAM-$MAJOR.$MINOR.$MICRO is required and was not found."
|
||||
return 1
|
||||
else
|
||||
debug "Found $COMMAND"
|
||||
fi
|
||||
|
||||
INS_VER=`$COMMAND --version | head -1 | sed 's/[^0-9]*//' | cut -d' ' -f1`
|
||||
INS_MAJOR=`echo $INS_VER | cut -d. -f1 | sed s/[a-zA-Z\-].*//g`
|
||||
INS_MINOR=`echo $INS_VER | cut -d. -f2 | sed s/[a-zA-Z\-].*//g`
|
||||
INS_MICRO=`echo $INS_VER | cut -d. -f3 | sed s/[a-zA-Z\-].*//g`
|
||||
test -z "$INS_MAJOR" && INS_MAJOR=0
|
||||
test -z "$INS_MINOR" && INS_MINOR=0
|
||||
test -z "$INS_MICRO" && INS_MICRO=0
|
||||
debug "Installed version: $INS_VER"
|
||||
|
||||
if [ "$INS_MAJOR" -gt "$MAJOR" ]; then
|
||||
debug "MAJOR: $INS_MAJOR > $MAJOR"
|
||||
return 0
|
||||
elif [ "$INS_MAJOR" -eq "$MAJOR" ]; then
|
||||
debug "MAJOR: $INS_MAJOR = $MAJOR"
|
||||
if [ "$INS_MINOR" -gt "$MINOR" ]; then
|
||||
debug "MINOR: $INS_MINOR > $MINOR"
|
||||
return 0
|
||||
elif [ "$INS_MINOR" -eq "$MINOR" ]; then
|
||||
if [ "$INS_MICRO" -ge "$MICRO" ]; then
|
||||
debug "MICRO: $INS_MICRO >= $MICRO"
|
||||
return 0
|
||||
else
|
||||
debug "MICRO: $INS_MICRO < $MICRO"
|
||||
fi
|
||||
else
|
||||
debug "MINOR: $INS_MINOR < $MINOR"
|
||||
fi
|
||||
else
|
||||
debug "MAJOR: $INS_MAJOR < $MAJOR"
|
||||
fi
|
||||
|
||||
echo "You have the wrong version of $PROGRAM. The minimum required version is $MAJOR.$MINOR.$MICRO"
|
||||
echo " and the version installed is $INS_MAJOR.$INS_MINOR.$INS_MICRO ($COMMAND)."
|
||||
return 1
|
||||
}
|
||||
|
||||
# Check for required version and die if unhappy
|
||||
|
||||
if [ "x$UNAME" = "xFreeBSD" ]; then
|
||||
version_compare libtoolize 1 5 16 || exit 1
|
||||
version_compare automake19 1 9 5 || exit 1
|
||||
version_compare autoconf259 2 59 || exit 1
|
||||
ACLOCAL=aclocal19
|
||||
AUTOHEADER=autoheader259
|
||||
AUTOMAKE=automake19
|
||||
AUTOCONF=autoconf259
|
||||
else
|
||||
version_compare libtoolize 1 5 16 || exit 1
|
||||
version_compare automake 1 9 5 || exit 1
|
||||
version_compare autoconf 2 59 || exit 1
|
||||
ACLOCAL=aclocal
|
||||
AUTOHEADER=autoheader
|
||||
AUTOMAKE=automake
|
||||
AUTOCONF=autoconf
|
||||
fi
|
||||
|
||||
libtoolize --copy --force --ltdl
|
||||
#NetBSD seems to need this file writable
|
||||
chmod u+w libltdl/configure
|
||||
|
||||
$ACLOCAL
|
||||
$AUTOHEADER --force
|
||||
$AUTOMAKE --copy --add-missing
|
||||
$AUTOCONF --force
|
||||
|
||||
#chmod ug+x debian/rules
|
||||
|
||||
if [ "x$UNAME" = "xNetBSD" ]; then
|
||||
echo ""
|
||||
echo "Please remember to run gmake instead of make on NetBSD"
|
||||
echo ""
|
||||
fi
|
||||
@@ -0,0 +1,289 @@
|
||||
/* config-h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to 1 if you have the acosf() function. */
|
||||
#undef HAVE_ACOSF
|
||||
|
||||
/* Define to 1 if you have the asinf() function. */
|
||||
#undef HAVE_ASINF
|
||||
|
||||
/* Define to 1 if you have the atan2f() function. */
|
||||
#undef HAVE_ATAN2F
|
||||
|
||||
/* Define to 1 if you have the atanf() function. */
|
||||
#undef HAVE_ATANF
|
||||
|
||||
/* Define to 1 if you have the <audiofile.h> header file. */
|
||||
#undef HAVE_AUDIOFILE_H
|
||||
|
||||
/* Define to 1 if you have the ceilf() function. */
|
||||
#undef HAVE_CEILF
|
||||
|
||||
/* Define to 1 if you have the cosf() function. */
|
||||
#undef HAVE_COSF
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> 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 expf() function. */
|
||||
#undef HAVE_EXPF
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the <fftw3.h> header file. */
|
||||
#undef HAVE_FFTW3_H
|
||||
|
||||
/* Define to 1 if you have the <fftw.h> header file. */
|
||||
#undef HAVE_FFTW_H
|
||||
|
||||
/* Define to 1 if you have the <float.h> header file. */
|
||||
#undef HAVE_FLOAT_H
|
||||
|
||||
/* Define to 1 if you have the floorf() function. */
|
||||
#undef HAVE_FLOORF
|
||||
|
||||
/* Define to 1 if you have the <FL/Fl_Audio_Meter.H> header file. */
|
||||
#undef HAVE_FL_FL_AUDIO_METER_H
|
||||
|
||||
/* Define to 1 if you have the <FL/Fl_Cartesian.H> header file. */
|
||||
#undef HAVE_FL_FL_CARTESIAN_H
|
||||
|
||||
/* Define to 1 if you have the <FL/fl_draw.H> header file. */
|
||||
#undef HAVE_FL_FL_DRAW_H
|
||||
|
||||
/* Define to 1 if you have the <FL/Fl.H> header file. */
|
||||
#undef HAVE_FL_FL_H
|
||||
|
||||
/* Define to 1 if you have the <FL/Fl_Light_Button.H> header file. */
|
||||
#undef HAVE_FL_FL_LIGHT_BUTTON_H
|
||||
|
||||
/* Define to 1 if you have the <FL/Fl_Overlay_Window.H> 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 <inttypes.h> 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 <libxml/parser.h> header file. */
|
||||
#undef HAVE_LIBXML_PARSER_H
|
||||
|
||||
/* Define to 1 if you have the <libxml/xinclude.h> header file. */
|
||||
#undef HAVE_LIBXML_XINCLUDE_H
|
||||
|
||||
/* Define to 1 if you have the <libxml/xmlmemory.h> header file. */
|
||||
#undef HAVE_LIBXML_XMLMEMORY_H
|
||||
|
||||
/* Define if you have C99's llrint function. */
|
||||
#undef HAVE_LLRINT
|
||||
|
||||
/* Define if you have C99's llrintf function. */
|
||||
#undef HAVE_LLRINTF
|
||||
|
||||
/* Define to 1 if you have the log10f() function. */
|
||||
#undef HAVE_LOG10F
|
||||
|
||||
/* Define to 1 if you have the logf() function. */
|
||||
#undef HAVE_LOGF
|
||||
|
||||
/* 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 if you have C99's lrint function. */
|
||||
#undef HAVE_LRINT
|
||||
|
||||
/* Define if you have C99's lrintf function. */
|
||||
#undef HAVE_LRINTF
|
||||
|
||||
/* 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 <malloc.h> header file. */
|
||||
#undef HAVE_MALLOC_H
|
||||
|
||||
/* Define to 1 if you have the <math.h> 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 <memory.h> 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 powf() function. */
|
||||
#undef HAVE_POWF
|
||||
|
||||
/* Define to 1 if you have the <pthread.h> 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 sinf() function. */
|
||||
#undef HAVE_SINF
|
||||
|
||||
/* Define to 1 if you have the <socket.h> header file. */
|
||||
#undef HAVE_SOCKET_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> 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 <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> 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 <sys/fcntl.h> header file. */
|
||||
#undef HAVE_SYS_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
||||
#undef HAVE_SYS_IOCTL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/select.h> header file. */
|
||||
#undef HAVE_SYS_SELECT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#undef HAVE_SYS_SOCKET_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
|
||||
#undef HAVE_SYS_WAIT_H
|
||||
|
||||
/* Define to 1 if you have the tanf() function. */
|
||||
#undef HAVE_TANF
|
||||
|
||||
/* Define to 1 if you have the <tgmath.h> header file. */
|
||||
#undef HAVE_TGMATH_H
|
||||
|
||||
/* Define to 1 if you have the <tiffio.h> header file. */
|
||||
#undef HAVE_TIFFIO_H
|
||||
|
||||
/* Define to 1 if you have the <unicall.h> header file. */
|
||||
#undef HAVE_UNICALL_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> 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 <X11/X.h> 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
|
||||
|
||||
/* Do not expect a misaligned memory access to work correctly */
|
||||
#undef SPANDSP_MISALIGNED_ACCESS_FAILS
|
||||
|
||||
/* Enable fixed point processing, where possible, instead of floating point */
|
||||
#undef SPANDSP_USE_FIXED_POINT
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
|
||||
#undef TIME_WITH_SYS_TIME
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* 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
|
||||
@@ -0,0 +1,181 @@
|
||||
# @synopsis AX_C99_FLEXIBLE_ARRAY
|
||||
#
|
||||
# Does the compiler support the 1999 ISO C Standard "struct hack".
|
||||
# @version 1.1 Mar 15 2004
|
||||
# @author Erik de Castro Lopo <erikd AT mega-nerd DOT com>
|
||||
#
|
||||
# Permission to use, copy, modify, distribute, and sell this file for any
|
||||
# purpose is hereby granted without fee, provided that the above copyright
|
||||
# and this permission notice appear in all copies. No representations are
|
||||
# made about the suitability of this software for any purpose. It is
|
||||
# provided "as is" without express or implied warranty.
|
||||
|
||||
AC_DEFUN([AX_C99_FLEXIBLE_ARRAY],
|
||||
[AC_CACHE_CHECK(C99 struct flexible array support,
|
||||
ac_cv_c99_flexible_array,
|
||||
|
||||
# Initialize to unknown
|
||||
ac_cv_c99_flexible_array=no
|
||||
|
||||
AC_TRY_LINK([[
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
int k;
|
||||
char buffer [] ;
|
||||
} MY_STRUCT ;
|
||||
]],
|
||||
[ MY_STRUCT *p = calloc (1, sizeof (MY_STRUCT) + 42); ],
|
||||
ac_cv_c99_flexible_array=yes,
|
||||
ac_cv_c99_flexible_array=no
|
||||
))]
|
||||
) # AX_C99_FLEXIBLE_ARRAY
|
||||
|
||||
# @synopsis AX_C99_FUNC_LRINT
|
||||
#
|
||||
# Check whether C99's lrint function is available.
|
||||
# @version 1.3 Feb 12 2002
|
||||
# @author Erik de Castro Lopo <erikd AT mega-nerd DOT com>
|
||||
#
|
||||
# Permission to use, copy, modify, distribute, and sell this file for any
|
||||
# purpose is hereby granted without fee, provided that the above copyright
|
||||
# and this permission notice appear in all copies. No representations are
|
||||
# made about the suitability of this software for any purpose. It is
|
||||
# provided "as is" without express or implied warranty.
|
||||
#
|
||||
AC_DEFUN([AX_C99_FUNC_LRINT],
|
||||
[AC_CACHE_CHECK(for lrint,
|
||||
ac_cv_c99_lrint,
|
||||
[
|
||||
lrint_save_CFLAGS=$CFLAGS
|
||||
CFLAGS="-lm"
|
||||
AC_TRY_LINK([
|
||||
#define _ISOC9X_SOURCE 1
|
||||
#define _ISOC99_SOURCE 1
|
||||
#define __USE_ISOC99 1
|
||||
#define __USE_ISOC9X 1
|
||||
|
||||
#include <math.h>
|
||||
], if (!lrint(3.14159)) lrint(2.7183);, ac_cv_c99_lrint=yes, ac_cv_c99_lrint=no)
|
||||
|
||||
CFLAGS=$lrint_save_CFLAGS
|
||||
|
||||
])
|
||||
|
||||
if test "$ac_cv_c99_lrint" = yes; then
|
||||
AC_DEFINE(HAVE_LRINT, 1,
|
||||
[Define if you have C99's lrint function.])
|
||||
fi
|
||||
])# AX_C99_FUNC_LRINT
|
||||
|
||||
# @synopsis AX_C99_FUNC_LRINTF
|
||||
#
|
||||
# Check whether C99's lrintf function is available.
|
||||
# @version 1.3 Feb 12 2002
|
||||
# @author Erik de Castro Lopo <erikd AT mega-nerd DOT com>
|
||||
#
|
||||
# Permission to use, copy, modify, distribute, and sell this file for any
|
||||
# purpose is hereby granted without fee, provided that the above copyright
|
||||
# and this permission notice appear in all copies. No representations are
|
||||
# made about the suitability of this software for any purpose. It is
|
||||
# provided "as is" without express or implied warranty.
|
||||
#
|
||||
AC_DEFUN([AX_C99_FUNC_LRINTF],
|
||||
[AC_CACHE_CHECK(for lrintf,
|
||||
ac_cv_c99_lrintf,
|
||||
[
|
||||
lrintf_save_CFLAGS=$CFLAGS
|
||||
CFLAGS="-lm"
|
||||
AC_TRY_LINK([
|
||||
#define _ISOC9X_SOURCE 1
|
||||
#define _ISOC99_SOURCE 1
|
||||
#define __USE_ISOC99 1
|
||||
#define __USE_ISOC9X 1
|
||||
|
||||
#include <math.h>
|
||||
], if (!lrintf(3.14159)) lrintf(2.7183);, ac_cv_c99_lrintf=yes, ac_cv_c99_lrintf=no)
|
||||
|
||||
CFLAGS=$lrintf_save_CFLAGS
|
||||
|
||||
])
|
||||
|
||||
if test "$ac_cv_c99_lrintf" = yes; then
|
||||
AC_DEFINE(HAVE_LRINTF, 1,
|
||||
[Define if you have C99's lrintf function.])
|
||||
fi
|
||||
])# AX_C99_FUNC_LRINTF
|
||||
|
||||
# @synopsis AX_C99_FUNC_LLRINT
|
||||
#
|
||||
# Check whether C99's llrint function is available.
|
||||
# @version 1.1 Sep 30 2002
|
||||
# @author Erik de Castro Lopo <erikd AT mega-nerd DOT com>
|
||||
#
|
||||
# Permission to use, copy, modify, distribute, and sell this file for any
|
||||
# purpose is hereby granted without fee, provided that the above copyright
|
||||
# and this permission notice appear in all copies. No representations are
|
||||
# made about the suitability of this software for any purpose. It is
|
||||
# provided "as is" without express or implied warranty.
|
||||
#
|
||||
AC_DEFUN([AX_C99_FUNC_LLRINT],
|
||||
[AC_CACHE_CHECK(for llrint,
|
||||
ac_cv_c99_llrint,
|
||||
[
|
||||
llrint_save_CFLAGS=$CFLAGS
|
||||
CFLAGS="-lm"
|
||||
AC_TRY_LINK([
|
||||
#define ISOC9X_SOURCE 1
|
||||
#define _ISOC99_SOURCE 1
|
||||
#define __USE_ISOC99 1
|
||||
#define __USE_ISOC9X 1
|
||||
|
||||
#include <math.h>
|
||||
], long long int x ; x = llrint(3.14159) ;, ac_cv_c99_llrint=yes, ac_cv_c99_llrint=no)
|
||||
|
||||
CFLAGS=$llrint_save_CFLAGS
|
||||
|
||||
])
|
||||
|
||||
if test "$ac_cv_c99_llrint" = yes; then
|
||||
AC_DEFINE(HAVE_LLRINT, 1,
|
||||
[Define if you have C99's llrint function.])
|
||||
fi
|
||||
])# AX_C99_FUNC_LLRINT
|
||||
|
||||
|
||||
# @synopsis AX_C99_FUNC_LLRINTF
|
||||
#
|
||||
# Check whether C99's llrintf function is available.
|
||||
# @version 1.1 Sep 30 2002
|
||||
# @author Erik de Castro Lopo <erikd AT mega-nerd DOT com>
|
||||
#
|
||||
# Permission to use, copy, modify, distribute, and sell this file for any
|
||||
# purpose is hereby granted without fee, provided that the above copyright
|
||||
# and this permission notice appear in all copies. No representations are
|
||||
# made about the suitability of this software for any purpose. It is
|
||||
# provided "as is" without express or implied warranty.
|
||||
#
|
||||
AC_DEFUN([AX_C99_FUNC_LLRINTF],
|
||||
[AC_CACHE_CHECK(for llrintf,
|
||||
ac_cv_c99_llrintf,
|
||||
[
|
||||
llrintf_save_CFLAGS=$CFLAGS
|
||||
CFLAGS="-lm"
|
||||
AC_TRY_LINK([
|
||||
#define _ISOC9X_SOURCE 1
|
||||
#define _ISOC99_SOURCE 1
|
||||
#define __USE_ISOC99 1
|
||||
#define __USE_ISOC9X 1
|
||||
|
||||
#include <math.h>
|
||||
], long long int x ; x = llrintf(3.14159) ;, ac_cv_c99_llrintf=yes, ac_cv_c99_llrintf=no)
|
||||
|
||||
CFLAGS=$llrintf_save_CFLAGS
|
||||
|
||||
])
|
||||
|
||||
if test "$ac_cv_c99_llrintf" = yes; then
|
||||
AC_DEFINE(HAVE_LLRINTF, 1,
|
||||
[Define if you have C99's llrintf function.])
|
||||
fi
|
||||
])# AX_C99_FUNC_LLRINTF
|
||||
@@ -0,0 +1,27 @@
|
||||
# AX_CHECK_REAL_FILE(FILE, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Check for the existence of FILE, and make sure it is a real file or
|
||||
# directory, and not a symbolic link.
|
||||
#
|
||||
AC_DEFUN([AX_CHECK_REAL_FILE],
|
||||
[AC_DIAGNOSE([cross],
|
||||
[cannot check for file existence when cross compiling])dnl
|
||||
AS_VAR_PUSHDEF([ac_RealFile], [ac_cv_real_file_$1])dnl
|
||||
AC_CACHE_CHECK([for $1], ac_RealFile,
|
||||
[test "$cross_compiling" = yes &&
|
||||
AC_MSG_ERROR([cannot check for file existence when cross compiling])
|
||||
if test -r "$1"
|
||||
then
|
||||
if test -h "$1"
|
||||
then
|
||||
AS_VAR_SET(ac_RealFile, no)
|
||||
else
|
||||
AS_VAR_SET(ac_RealFile, yes)
|
||||
fi
|
||||
else
|
||||
AS_VAR_SET(ac_RealFile, no)
|
||||
fi])
|
||||
AS_IF([test AS_VAR_GET(ac_RealFile) = yes], [$2], [$3])[]dnl
|
||||
AS_VAR_POPDEF([ac_RealFile])dnl
|
||||
])# AX_CHECK_REAL_FILE
|
||||
@@ -0,0 +1,65 @@
|
||||
# ===========================================================================
|
||||
# http://autoconf-archive.cryp.to/ax_compiler_vendor.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_COMPILER_VENDOR
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Determine the vendor of the C/C++ compiler, e.g., gnu, intel, ibm, sun,
|
||||
# hp, borland, comeau, dec, cray, kai, lcc, metrowerks, sgi, microsoft,
|
||||
# watcom, etc. The vendor is returned in the cache variable
|
||||
# $ax_cv_c_compiler_vendor for C and $ax_cv_cxx_compiler_vendor for C++.
|
||||
#
|
||||
# LAST MODIFICATION
|
||||
#
|
||||
# 2008-04-12
|
||||
#
|
||||
# COPYLEFT
|
||||
#
|
||||
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
|
||||
# Copyright (c) 2008 Matteo Frigo
|
||||
#
|
||||
# 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Macro Archive. When you make and
|
||||
# distribute a modified version of the Autoconf Macro, you may extend this
|
||||
# special exception to the GPL to apply to your modified version as well.
|
||||
|
||||
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__ pathscale:__PATHCC__,__PATHSCALE__ 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
|
||||
])
|
||||
])
|
||||
@@ -0,0 +1,35 @@
|
||||
# AX_FIXED_POINT_MACHINE(MACHINE, [ACTION-IF-FIXED-POINT], [ACTION-IF-NOT-FIXED-POINT])
|
||||
# -------------------------------------------------------------------------------------
|
||||
#
|
||||
# Check if a specified machine type is a fixed point only machine. That is, if it lacks
|
||||
# fast floating point support.
|
||||
#
|
||||
# This is a simple lookup amongst machines known to the current autotools. 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.
|
||||
#
|
||||
AC_DEFUN([AX_FIXED_POINT_MACHINE],
|
||||
[AS_VAR_PUSHDEF([ac_FixedPoint], [ac_cv_fixed_point_machine_$1])dnl
|
||||
AC_CACHE_CHECK([if $1 is fixed point only], ac_FixedPoint,
|
||||
[case $1 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]-* )
|
||||
AS_VAR_SET(ac_FixedPoint, yes)
|
||||
;;
|
||||
*)
|
||||
AS_VAR_SET(ac_FixedPoint, no)
|
||||
;;
|
||||
esac])
|
||||
AS_IF([test AS_VAR_GET(ac_FixedPoint) = yes], [$2], [$3])[]dnl
|
||||
AS_VAR_POPDEF([ac_FixedPoint])dnl
|
||||
])# AX_FIXED_POINT_MACHINE
|
||||
@@ -0,0 +1,33 @@
|
||||
# AX_MISALIGNED_ACCESS_FAILS(MACHINE, [ACTION-IF-MISALIGNED-FAILS], [ACTION-IF-MISALIGNED-OK])
|
||||
# -------------------------------------------------------------------------------------
|
||||
#
|
||||
# Check if a specified machine type cannot handle misaligned data. That is, multi-byte data
|
||||
# types which are not properly aligned in memory fail. Many machines are happy to work with
|
||||
# misaligned data, but slowing down a bit. Other machines just won't tolerate such data.
|
||||
#
|
||||
# This is a simple lookup amongst machines known to the current autotools. So far we only deal
|
||||
# with the ARM and sparc.
|
||||
# A lookup is used, as many of the devices which cannot handled misaligned access are embedded
|
||||
# processors, for which the code normally be cross-compiled.
|
||||
#
|
||||
AC_DEFUN([AX_MISALIGNED_ACCESS_FAILS],
|
||||
[AS_VAR_PUSHDEF([ac_MisalignedAccessFails], [ac_cv_misaligned_access_fails_$1])dnl
|
||||
AC_CACHE_CHECK([if $1 fails on misaligned memory access], ac_MisalignedAccessFails,
|
||||
[case $1 in
|
||||
arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] \
|
||||
| bfin \
|
||||
| sparc \
|
||||
| xscale | xscalee[bl] \
|
||||
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
|
||||
| bfin-* \
|
||||
| sparc-* \
|
||||
| xscale-* | xscalee[bl]-* )
|
||||
AS_VAR_SET(ac_MisalignedAccessFails, yes)
|
||||
;;
|
||||
*)
|
||||
AS_VAR_SET(ac_MisalignedAccessFails, no)
|
||||
;;
|
||||
esac])
|
||||
AS_IF([test AS_VAR_GET(ac_MisalignedAccessFails) = yes], [$2], [$3])[]dnl
|
||||
AS_VAR_POPDEF([ac_MisalignedAccessFails])dnl
|
||||
])# MISALIGNED_ACCESS_FAILS
|
||||
@@ -0,0 +1,371 @@
|
||||
#
|
||||
# SpanDSP - 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 Lesser 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 Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser 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.56 2008/07/10 12:44:54 steveu Exp $
|
||||
|
||||
# @start 1
|
||||
|
||||
AC_INIT
|
||||
|
||||
m4_include(config/ax_compiler_vendor.m4)
|
||||
m4_include(config/ax_check_real_file.m4)
|
||||
m4_include(config/ax_fixed_point_machine.m4)
|
||||
m4_include(config/ax_misaligned_access_fails.m4)
|
||||
m4_include(config/ax_c99_features.m4)
|
||||
|
||||
SPANDSP_MAJOR_VERSION=0
|
||||
SPANDSP_MINOR_VERSION=0
|
||||
SPANDSP_MICRO_VERSION=5
|
||||
|
||||
SPANDSP_LT_CURRENT=1
|
||||
SPANDSP_LT_REVISION=0
|
||||
SPANDSP_LT_AGE=0
|
||||
|
||||
VERSION=$SPANDSP_MAJOR_VERSION.$SPANDSP_MINOR_VERSION.$SPANDSP_MICRO_VERSION
|
||||
PACKAGE=spandsp
|
||||
|
||||
AC_SUBST(SPANDSP_LT_CURRENT)
|
||||
AC_SUBST(SPANDSP_LT_REVISION)
|
||||
AC_SUBST(SPANDSP_LT_AGE)
|
||||
|
||||
AC_CONFIG_SRCDIR([src/tone_generate.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_FOR_BUILD=${CC_FOR_BUILD-gcc}
|
||||
CPPFLAGS_FOR_BUILD="\$(CPPFLAGS)"
|
||||
CC=${CC-${host_alias}-gcc}
|
||||
CFLAGS=${CFLAGS-"-g -O2"}
|
||||
CXX=${CXX-${host_alias}-c++}
|
||||
CXXFLAGS=${CXXFLAGS-"-g -O2"}
|
||||
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)"
|
||||
CPPFLAGS_FOR_BUILD="\$(CPPFLAGS)"
|
||||
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(test_data, [ --enable-test-data 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
|
||||
|
||||
AX_C99_FUNC_LRINT
|
||||
AX_C99_FUNC_LRINTF
|
||||
AX_C99_FUNC_LLRINT
|
||||
AX_C99_FUNC_LLRINTF
|
||||
|
||||
if test "x$ac_cv_c99_lrint" = "xno" ; then
|
||||
if test "x$ac_cv_c99_lrintf" = "xno" ; then
|
||||
AC_MSG_WARN([[*** Missing C99 standard functions lrint() and lrintf().]])
|
||||
AC_MSG_WARN([[*** This may cause benign compiler warnings on some systems (ie Solaris).]])
|
||||
fi
|
||||
fi
|
||||
|
||||
AX_C99_FLEXIBLE_ARRAY
|
||||
|
||||
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 <inttypes.h>"])
|
||||
AC_CHECK_HEADERS([stdint.h], [INSERT_STDINT_HEADER="#include <stdint.h>"])
|
||||
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 <tgmath.h>"])
|
||||
AC_CHECK_HEADERS([math.h], [INSERT_MATH_HEADER="#include <math.h>"])
|
||||
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([fftw3.h], , [AC_CHECK_HEADERS([fftw.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 <libxml/xmlmemory.h>], [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 <libxml/xmlmemory.h>], [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 <FL/Fl.H>
|
||||
]])
|
||||
AC_CHECK_HEADERS([FL/Fl_Audio_Meter.H], [], [], [],[[#include <FL/Fl.H>
|
||||
]])
|
||||
|
||||
AC_LANG([C])
|
||||
|
||||
if test "${build}" == "${host}"
|
||||
then
|
||||
case "${host}" in
|
||||
x86_64-*)
|
||||
AX_CHECK_REAL_FILE([${prefix}/lib64], libdir='$(exec_prefix)/lib64')
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
AC_CHECK_LIB([m], [cos])
|
||||
# Some platforms still seem to lack the basic single precision trig and power related function.
|
||||
AC_SEARCH_LIBS([sinf], [m], AC_DEFINE([HAVE_SINF], [1], [Define to 1 if you have the sinf() function.]))
|
||||
AC_SEARCH_LIBS([cosf], [m], AC_DEFINE([HAVE_COSF], [1], [Define to 1 if you have the cosf() function.]))
|
||||
AC_SEARCH_LIBS([tanf], [m], AC_DEFINE([HAVE_TANF], [1], [Define to 1 if you have the tanf() function.]))
|
||||
AC_SEARCH_LIBS([asinf], [m], AC_DEFINE([HAVE_ASINF], [1], [Define to 1 if you have the asinf() function.]))
|
||||
AC_SEARCH_LIBS([acosf], [m], AC_DEFINE([HAVE_ACOSF], [1], [Define to 1 if you have the acosf() function.]))
|
||||
AC_SEARCH_LIBS([atanf], [m], AC_DEFINE([HAVE_ATANF], [1], [Define to 1 if you have the atanf() function.]))
|
||||
AC_SEARCH_LIBS([atan2f], [m], AC_DEFINE([HAVE_ATAN2F], [1], [Define to 1 if you have the atan2f() function.]))
|
||||
AC_SEARCH_LIBS([ceilf], [m], AC_DEFINE([HAVE_CEILF], [1], [Define to 1 if you have the ceilf() function.]))
|
||||
AC_SEARCH_LIBS([floorf], [m], AC_DEFINE([HAVE_FLOORF], [1], [Define to 1 if you have the floorf() function.]))
|
||||
AC_SEARCH_LIBS([powf], [m], AC_DEFINE([HAVE_POWF], [1], [Define to 1 if you have the powf() function.]))
|
||||
AC_SEARCH_LIBS([expf], [m], AC_DEFINE([HAVE_EXPF], [1], [Define to 1 if you have the expf() function.]))
|
||||
AC_SEARCH_LIBS([logf], [m], AC_DEFINE([HAVE_LOGF], [1], [Define to 1 if you have the logf() function.]))
|
||||
AC_SEARCH_LIBS([log10f], [m], AC_DEFINE([HAVE_LOG10F], [1], [Define to 1 if you have the log10f() function.]))
|
||||
|
||||
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
|
||||
AX_CHECK_REAL_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([tiff], [TIFFOpen], , AC_MSG_ERROR("Can't build without libtiff (does your system require a libtiff-devel package?)"), -lm)
|
||||
|
||||
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([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)
|
||||
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_LANG([C++])
|
||||
AC_CHECK_LIB([fltk], [main], TESTLIBS="$TESTLIBS -lfltk -lsupc++",, $TESTLIBS)
|
||||
AC_CHECK_LIB([fltk_cartesian], [main], TESTLIBS="-lfltk_cartesian $TESTLIBS",, $TESTLIBS)
|
||||
AC_CHECK_LIB([fltk_audio_meter], [main], TESTLIBS="-lfltk_audio_meter $TESTLIBS",, $TESTLIBS)
|
||||
AC_LANG([C])
|
||||
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
|
||||
case $host_os in
|
||||
mingw* | cygwin*)
|
||||
COMP_VENDOR_LDFLAGS="-no-undefined"
|
||||
;;
|
||||
*)
|
||||
COMP_VENDOR_LDFLAGS=
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
sun)
|
||||
COMP_VENDOR_CFLAGS="-xc99=all -mt -xCC -errwarn=%all -xvpara"
|
||||
if test "$enable_sse" = "yes" ; then
|
||||
COMP_VENDOR_CFLAGS="-native -fast $COMP_VENDOR_CFLAGS"
|
||||
fi
|
||||
if test "$enable_mmx" = "yes" ; then
|
||||
COMP_VENDOR_CFLAGS="-native -fast $COMP_VENDOR_CFLAGS"
|
||||
fi
|
||||
COMP_VENDOR_LDFLAGS=
|
||||
;;
|
||||
*)
|
||||
COMP_VENDOR_CFLAGS="-std=c99 -Wall -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes"
|
||||
COMP_VENDOR_LDFLAGS=
|
||||
;;
|
||||
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_TESTDATA], [test "$enable_test_data" = 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([SPANDSP_USE_FIXED_POINT], [1], [Enable fixed point processing, where possible, instead of floating point])
|
||||
SPANDSP_USE_FIXED_POINT="#define SPANDSP_USE_FIXED_POINT 1"
|
||||
else
|
||||
AX_FIXED_POINT_MACHINE([$host],
|
||||
[AC_DEFINE([SPANDSP_USE_FIXED_POINT], [1], [Enable fixed point processing, where possible, instead of floating point])
|
||||
SPANDSP_USE_FIXED_POINT="#define SPANDSP_USE_FIXED_POINT 1"],
|
||||
[SPANDSP_USE_FIXED_POINT="#undef SPANDSP_USE_FIXED_POINT"])
|
||||
fi
|
||||
AX_MISALIGNED_ACCESS_FAILS([$host],
|
||||
[AC_DEFINE([SPANDSP_MISALIGNED_ACCESS_FAILS], [1], [Do not expect a misaligned memory access to work correctly])
|
||||
SPANDSP_MISALIGNED_ACCESS_FAILS="#define SPANDSP_MISALIGNED_ACCESS_FAILS 1"],
|
||||
[SPANDSP_MISALIGNED_ACCESS_FAILS="#undef SPANDSP_MISALIGNED_ACCESS_FAILS"])
|
||||
|
||||
AC_SUBST(CC_FOR_BUILD)
|
||||
AC_SUBST(CPPFLAGS_FOR_BUILD)
|
||||
AC_SUBST(COMP_VENDOR_CFLAGS)
|
||||
AC_SUBST(COMP_VENDOR_LDFLAGS)
|
||||
AC_SUBST(TESTLIBS)
|
||||
AC_SUBST(SPANDSP_USE_FIXED_POINT)
|
||||
AC_SUBST(SPANDSP_MISALIGNED_ACCESS_FAILS)
|
||||
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
|
||||
doc/doxygen
|
||||
src/Makefile
|
||||
src/spandsp.h
|
||||
spandsp-sim/Makefile
|
||||
test-data/Makefile
|
||||
test-data/etsi/Makefile
|
||||
test-data/etsi/fax/Makefile
|
||||
test-data/itu/Makefile
|
||||
test-data/itu/fax/Makefile
|
||||
test-data/local/Makefile
|
||||
tests/Makefile
|
||||
spandsp.spec])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
# @end 1
|
||||
@@ -0,0 +1,109 @@
|
||||
spandsp (0.0.5~pre2-1) unstable; urgency=low
|
||||
|
||||
[ Massimo Cetra ]
|
||||
* New upstream release.
|
||||
* Fixed upstream file name for get-orig-source.
|
||||
* Updates to 64bit archs support
|
||||
* Removal of obsoleted files
|
||||
|
||||
-- Massimo Cetra <devel@navynet.it> Mon, 5 May 2008 09:23:36 +0100
|
||||
|
||||
spandsp (0.0.4~pre3-1) unstable; urgency=low
|
||||
|
||||
[ Santiago Ruano Rincón ]
|
||||
* Added Conflicts: libspandsp2
|
||||
* Fixed URL in debian/rules
|
||||
|
||||
[ Tzafrir Cohen ]
|
||||
* New upstream release.
|
||||
* Fixed upstream file name for get-orig-source.
|
||||
* standards version updated to 3.7.2 .
|
||||
|
||||
-- Tzafrir Cohen <tzafrir.cohen@xorcom.com> Mon, 18 Jun 2007 09:53:06 +0300
|
||||
|
||||
spandsp (0.0.4~pre1-1) experimental; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Santiago Ruano Rincón <santiago@debian.org> Fri, 11 May 2007 15:24:41 -0500
|
||||
|
||||
spandsp (0.0.3pre27-2) experimental; urgency=low
|
||||
|
||||
* Conflict with libspandsp1 due to /usr/share/spandsp/global-tones.xml
|
||||
|
||||
-- Kilian Krause <kilian@debian.org> Thu, 4 Jan 2007 00:29:10 +0100
|
||||
|
||||
spandsp (0.0.3pre27-1) experimental; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
* Bump library name due to API incompatibility with 0.0.2 versions.
|
||||
|
||||
-- Kilian Krause <kilian@debian.org> Wed, 3 Jan 2007 21:31:17 +0100
|
||||
|
||||
spandsp (0.0.3pre26-1) experimental; urgency=low
|
||||
|
||||
* New upstream release
|
||||
- New version of spandsp available (Closes: #339293)
|
||||
- Remove src/spandsp/mmx.h is not GPL and has no license attached (Closes:
|
||||
#357813)
|
||||
* Lintian: outdated-autotools-helper-file - Build-Depends: autotools-dev
|
||||
* Add debian/watch
|
||||
|
||||
-- Mark Purcell <msp@debian.org> Sat, 9 Dec 2006 14:00:57 +0000
|
||||
|
||||
spandsp (0.0.2pre26-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
* Added get-orig-source target.
|
||||
* Removed unneeded and buggy nommx.dpatch (Closes: #376249, #377374)
|
||||
|
||||
-- Tzafrir Cohen <tzafrir.cohen@xorcom.com> Tue, 1 Aug 2006 06:27:47 +0100
|
||||
|
||||
spandsp (0.0.2pre25-1) unstable; urgency=low
|
||||
|
||||
* New upstream version.
|
||||
* debian/copyright: Source's URL in copyright file updated to the new author' site.
|
||||
* Added -doc package, with the API documentation.
|
||||
* Fixed package name to follow new upstream's version.
|
||||
|
||||
-- Kilian Krause <kilian@debian.org> Sat, 18 Feb 2006 22:10:21 +0100
|
||||
|
||||
spandsp (0.0.2pre17-1) unstable; urgency=low
|
||||
|
||||
* New upstream version.
|
||||
|
||||
-- Kilian Krause <kk@verfaction.de> Mon, 9 May 2005 21:56:53 +0200
|
||||
|
||||
spandsp (0.0.2pre10-3) unstable; urgency=low
|
||||
|
||||
* debian/control: fixed overrides. again. (Back to the old optional)
|
||||
|
||||
-- Kilian Krause <kk@verfaction.de> Mon, 21 Mar 2005 10:39:30 +0100
|
||||
|
||||
spandsp (0.0.2pre10-2) unstable; urgency=low
|
||||
|
||||
* debian/control: fixed overrides.
|
||||
* debian/patches/mmx.dpatch: Added compilation on non-i386 and non-amd64.
|
||||
|
||||
-- Kilian Krause <kk@verfaction.de> Sun, 20 Mar 2005 23:32:48 +0100
|
||||
|
||||
spandsp (0.0.2pre10-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
* Debian VoIP Team takes this package from Simon. Thanks!
|
||||
* debian/rules: fixed how config.[sub,guess] files are linked from
|
||||
autotools-dev and cleaned.
|
||||
|
||||
-- Kilian Krause <kk@verfaction.de> Sat, 22 Jan 2005 13:44:28 +0100
|
||||
|
||||
spandsp (0.0.2-2) unstable; urgency=low
|
||||
|
||||
* Corrected build dependencies.
|
||||
|
||||
-- Simon Richter <sjr@debian.org> Mon, 3 Jan 2005 13:33:33 +0100
|
||||
|
||||
spandsp (0.0.2-1) unstable; urgency=low
|
||||
|
||||
* Initial Release (Closes: #262032).
|
||||
|
||||
-- Simon Richter <sjr@debian.org> Sun, 2 Jan 2005 15:22:58 +0100
|
||||
@@ -0,0 +1 @@
|
||||
4
|
||||
@@ -0,0 +1,42 @@
|
||||
Source: spandsp
|
||||
Section: libs
|
||||
Priority: optional
|
||||
Maintainer: Debian VoIP Team <pkg-voip-maintainers@lists.alioth.debian.org>
|
||||
Uploaders: Jose Carlos Garcia Sogo <jsogo@debian.org>, Kilian Krause <kilian@debian.org>, Santiago Garcia Mantinan <manty@debian.org>, Mark Purcell <msp@debian.org>, Tzafrir Cohen <tzafrir.cohen@xorcom.com>, Santiago Ruano Rincón <santiago@debian.org>
|
||||
Build-Depends: debhelper (>= 4.0.0), libtiff4-dev, libjpeg62-dev, dpatch, doxygen, autotools-dev, xsltproc
|
||||
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: libspandsp5
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}
|
||||
Conflicts: libspandsp0, libspandsp1, libspandsp2
|
||||
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: libspandsp-dev
|
||||
Section: libdevel
|
||||
Architecture: any
|
||||
Depends: libspandsp5 (= ${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: libspandsp-doc
|
||||
Section: doc
|
||||
Architecture: all
|
||||
Description: Documentation for the spandsp signal processing library
|
||||
This package contains the online API in HTML for the libspandsp, 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.
|
||||
@@ -0,0 +1,25 @@
|
||||
This package was debianized by Simon Richter <sjr@debian.org> on
|
||||
Sun, 2 Jan 2005 15:22:58 +0100.
|
||||
|
||||
It was downloaded from http://soft-switch.org/downloads/spandsp/
|
||||
|
||||
Copyright: Steve Underwood <steveu@coppice.org>
|
||||
|
||||
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'.
|
||||
@@ -0,0 +1,4 @@
|
||||
debian/tmp/usr/include
|
||||
debian/tmp/usr/lib/libspandsp.so
|
||||
debian/tmp/usr/lib/libspandsp.la
|
||||
debian/tmp/usr/lib/libspandsp.a
|
||||
@@ -0,0 +1 @@
|
||||
doc/api/html usr/share/doc/libspandsp-doc/api/
|
||||
@@ -0,0 +1,2 @@
|
||||
debian/tmp/usr/lib*/libspandsp.so.1.*
|
||||
debian/tmp/usr/lib*/libspandsp.so.1
|
||||
Executable
+106
@@ -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 := spandsp_$(ORIGTARVER).orig.tar.gz
|
||||
FULLNAME := spandsp-$(UPVERSION)
|
||||
URL := http://soft-switch.org/downloads/spandsp/spandsp-$(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
|
||||
@@ -0,0 +1,7 @@
|
||||
# See uscan(1) for format
|
||||
|
||||
# Compulsory line, this is a version 3 file
|
||||
version=3
|
||||
|
||||
# <Webpage URL> <string match>
|
||||
http://soft-switch.org/downloads/spandsp/ spandsp-(.*)\.tgz debian svn-upgrade
|
||||
@@ -0,0 +1,39 @@
|
||||
##
|
||||
## 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 Lesser 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 Lesser General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU Lesser 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.11 2008/06/21 10:28:34 steveu Exp $
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
EXTRA_DIST = css.css \
|
||||
t38-gateway.dia \
|
||||
t38-terminal.dia \
|
||||
t38_manual.xml \
|
||||
wrapper.xsl \
|
||||
t38_manual/css.css
|
||||
|
||||
all: doxydocs t38_manual/index.html
|
||||
|
||||
doxydocs:
|
||||
doxygen doxygen
|
||||
|
||||
t38_manual/index.html: t38_manual.xml
|
||||
cd t38_manual ; xsltproc ../wrapper.xsl ../t38_manual.xml
|
||||
|
||||
clean:
|
||||
cd t38_manual ; rm *.html ; cd ../api ; rm -rf html
|
||||
@@ -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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,291 @@
|
||||
<?xml version="1.0" encoding="iso8859-1"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
|
||||
<!-- $Id: t38_manual.xml,v 1.5 2007/12/08 16:25:17 steveu Exp $ -->
|
||||
<book>
|
||||
<bookinfo>
|
||||
<date>2007-11-14</date>
|
||||
<title>T.38 protocol (FoIP) support</title>
|
||||
<subtitle>User manual</subtitle>
|
||||
<releaseinfo>documentation in progress</releaseinfo>
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Steve</firstname>
|
||||
<surname>Underwood</surname>
|
||||
</author>
|
||||
</authorgroup>
|
||||
<address>
|
||||
<email>steveu@coppice.org</email>
|
||||
</address>
|
||||
<copyright>
|
||||
<year>2007</year>
|
||||
<holder>Steve Underwood</holder>
|
||||
</copyright>
|
||||
<legalnotice>
|
||||
<para>
|
||||
This document can be freely redistributed according to the
|
||||
terms of the GNU General Public License.
|
||||
</para>
|
||||
</legalnotice>
|
||||
</bookinfo>
|
||||
|
||||
<toc></toc>
|
||||
|
||||
<chapter id="what-is-t38">
|
||||
<title>The T.38 real-time FAX over IP (FoIP) protocol</title>
|
||||
|
||||
<para>There are two ITU recommendations which address sending FAXes over IP networks. T.37 specifies a method of encapsulating FAX images in e-mails, and transporting them to the recipient (an e-mail box, or another FAX machine) in a store-and-forward manner. T.38 specifies a protocol for transmitting a FAX across an IP network in real time. This document discusses the implementation of the T.38, real time, FAX over IP (FoIP) protocol.</para>
|
||||
|
||||
<para>FAXing between two PSTN FAX machines provides the illusion of real-time communication, with confirmed delivery. This is, of course, no more than an illusion. The sender has no idea what is receiving the FAX. It might be a FAX mailbox, where the FAX might only be retrieved much later, or might never be retrieved at all. It might be a FAX machine which is out of paper, and is storing the FAX in memory. If nobody adds paper before the FAX machine is switched off, the FAX might never be printed. With increasing amounts of FAX spam, many people don't ever bother to collect FAXes from the FAX machine in their office. Still, with all these reasons why the real-time confirmed delivery nature of FAXing is an illusion, large numbers of people still insist on using direct FAXing.</para>
|
||||
|
||||
<para>The FAX protocols - in particular T.30 - were designed for the PSTN. The PSTN is very different from a packet network like the Internet. It offers very strict timing; latency is rock steady throughout a call; and latency is seldom very high. The lack of these features in packet networks tends to spoil the quality of voice over IP, compared to voice over the PSTN. However, it can totally destroy modem data, like that used for FAX. Jitter and packet loss can cause modem reception to fail, and excessive delays can cause timers designed for a low latency environment to expire. T.38 tries to mitigate these factors, and can greatly improve the reliability of FAXing across the internet. It can also send FAXes using less bandwidth than using VoIP protocols. There are limits to what can be achieved on a congested network, though, and T.38 can never offer the reliability of a store and forward protocol, like T.37. Sadly, the average office worker's love affair with real-time FAX ensures a bright future for the T.38 protocol, even though the T.37 protocol makes far more sense.</para>
|
||||
|
||||
<para>The T.38 protocol primarily operates between:
|
||||
<itemizedlist>
|
||||
<listitem><para>Internet-aware FAX terminals, which connect directly to an IP network.</para></listitem>
|
||||
<listitem><para>FAX gateways, which allow traditional PSTN FAX terminals to communicate via the Internet.</para></listitem>
|
||||
<listitem><para>A combination of these.</para></listitem>
|
||||
</itemizedlist>
|
||||
T.38 is the only standardised protocol which exists for real-time FoIP. Reliably transporting a FAX between PSTN FAX terminals, through an IP network, requires use of the T.38 protocol at FAX gateways. VoIP connections are not robust for modem use, including FAX modem use. Most use low bit rate codecs, which cannot convey the modem signals accurately. Even when high bit rate codecs, such as G.711, are used, VoIP connections suffer dropouts and timing adjustments, which modems cannot tolerate. In a LAN environment the dropout rate may be very low, but the timing adjustments which occur in VoIP connections still make modem operation unreliable. T.38 FAX gateways deal with the delays, timing jitter, and packet loss experienced in packet networks, and isolate the PSTN FAX terminals from these as far as possible. In addition, by sending FAXes as image data, rather than digitised audio, the required bandwidth of the IP network might be reduced. However, the redundant transmission needed to make T.38 work acceptably over an unreliable network tends to offset much of the potential bandwidth gain.</para>
|
||||
|
||||
<para>The original T.38 specification provides for operation up to 14,400bps, using a V.17 modem. The latest version of the T.38 specification adds features for FAXing at up to 33,600bps, using a V.34 modem. However, it appears most current T.38 implementations only support operation up to 14,400bps.</para>
|
||||
</chapter>
|
||||
|
||||
<chapter id="the-basics-of-a-t38-entity">
|
||||
<title>The basics of a T.38 entity</title>
|
||||
|
||||
<para>The T.38 protocol may be used to build an Internet-aware FAX terminal, for direct connection to the Internet. It may also be used to build gateways. A T.38 FAX gateway might be a gateway between the PSTN and the Internet. It might just be an a ATA box acting as a gateway between a directly connected traditional FAX machine and the Internet. The T.38 protocol merely defines what passes between two T.38 entities. Creating a robust entity, able to tolerate the widest possible variation in network delays, jitter and packet loss, requires considerably more than just implementing what is contained in the T.38 spec. Also, the protocol definition is somewhat loose, resulting is considerable variability in the way the protocol is implemented. Considerable flexibility is required in a T.38 entity's design, to tolerate these variations.</para>
|
||||
|
||||
<para>T.38 currently works over one of the following transports:
|
||||
<itemizedlist>
|
||||
<listitem><para>TCP, with TPKT message framing - the use of TPKT was originally specified in a vague way, and implementations without TPKT framing apparently exist.</para></listitem>
|
||||
<listitem><para>UDPTL - A UDP based protocol used nowhere else. This is the most common transport for T.38.</para></listitem>
|
||||
<listitem><para>RTP - Added quite late to the T.38 specification, and still not widely supported.</para></listitem>
|
||||
</itemizedlist>
|
||||
TCP is the ideal way to communicate between two entities on an IP network, which do not have real-time constraints. The entities can talk as fast as they and the medium between them permit, with full error control. Internet-aware FAX devices would, therefore, usually use TCP as the transport for T.38. Gateways have only limited control of the timing of the FAX data passing through them. They have to operate in real-time, at a rate outside their control. Gateways, therefore, usually use UDPTL. The RTP option was only added to the T.38 specification in 2004, and is not yet widely supported. Over time it may become the preferred replacement for UDPTL, since most entities handle more than just FAX, and need to implement RTP anyway.</para>
|
||||
|
||||
<para>A TCP stream is fully corrected by the TCP protocol itself. However, in the UDPTL or RTP modes of operation, T.38 is subject to possible packet loss. A high level of missing data would defeat the protocol, so some measure of FEC (forward error correction) must be used. The UDPTL specification defines two optional forms of FEC. Both consist of adding information from previous packets to new packets. In one form this repeated data is send as a direct copy of the original. In the other it is sent as parity information, which requires encoding and decoding. The specifications for RTP include definitions of suitable FEC and redundancy protocols (RFC2198 and RFC2733). The T.38 specification says these should be used for T.38 over RTP.</para>
|
||||
|
||||
<para>Interestingly, even the latest revision of the T.38 specification does not provide properly for security in FAX transmission. SRTP is a standard way to achieve secure multi-media communication, and can be applied to T.38 over RTP without any specific wording on the subject in the T.38 specification. UDPTL might be seen as obsolete in the long term, and not worthy of enhancements to encrypt the data. However, no secure option for T.38 over TCP is defined. TPKT could be sent over TLS/TCP. TLS also has message framing features which would allow IFP packets to be sent directly over a TLS protected connection. However, there is no specified way to do this.</para>
|
||||
|
||||
<para>Although redundant information in future packets is an important part of a solid T.38 implementation, it is not a complete solution to problem of lost packets. Sometimes the next packet occurs after a considerable delay (e.g. when allowing time for a fast modem to train). If a "start training" message is only received through the redundant information in a following packet, it usually arrives too late to be useful (at least for a gateway). Most T.38 implementations now follow a practice of sending several exact copies of key packets - generally the ones which start or end the stages of the T.30 protocol. Typically up to 4 identical copies of these packets are sent down the wire. The may be sent in a burst, as fast as possible, or they may be spaced in time by 10ms or 20ms. IP network congestion, and the resulting packet loss, can be very bursty. If all copies are sent together, they might all be lost. Even a small amount of spreading in time may significantly increase the likelihood of at least one copy reaching its destination. The price is some delay in delivery of the message, which might be problematic. Multiple copies of these packets add little to the overall volume of data transmitted, as only a small percentage of packets fall in this "key packet" category. Some T.38 implementations follow a less effective practice of sending multiple key packets, which have separate sequence numbers and are separately bundled with redundant information for transmission. They may also be spaced in time. Although this seems a less effective strategy, a T.38 entity must expect to receive packets streams of this kind, and tolerate them.</para>
|
||||
|
||||
<para>Between the high priority key packets, and the low priority packets for the image data (the loss of which might just cause a streak on an image, or be corrected by ECM FAXing), lies the V.21 HDLC control messages. Some T.38 implementations dynamically adjust the amount of redundant information in packets, so these control messages are repeated through several packets, but the large image data packets are repeated less, or not at all. Used with care, this dynamic redundancy strategy can nicely balance data volume and reliability.</para>
|
||||
|
||||
<para>A T.38 terminal has a lot more flexibility in how it can deal with problem data than a T.38 gateway. The terminal has no tight timing constraints governing how it behaves with regard to received data. It can wait a considerable period for delayed packets to arrive. The gateway is a man-in-the-middle, and must live with the timing constraints that imposes. This means a T.38 gateway has a rather more difficult design than a terminal.</para>
|
||||
</chapter>
|
||||
|
||||
<chapter id="the-core-elements-of-a-t38-implementation">
|
||||
<title>The core elements of a T.38 implementation</title>
|
||||
|
||||
<para>There are many differences between the behaviour of a T.38 terminal and a T.38 gateway. However, some functions are common to both types of T.38 entity, particular in the IP network interface.</para>
|
||||
|
||||
<sect1>
|
||||
<title>The T.38 Internet Fascimile Protocol (IFP) packetiser</title>
|
||||
|
||||
<para>The T.38 specification defines an ASN.1 schema for the messages which pass between T.38 entities. These messages are called IFP (Internet Fascimile Protocol) messages. Their format is independent of the transport used to carry them. However, there are currently two slightly different versions of the ASN.1 schema. This is due to a typo in the original version of the T.38 specification. The protocol negotiation which occurs just before T.38 communication resolves which version will be used. Although the typo was corrected several years ago, it is still very more common to find implementations which only support the original buggy version.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>The UDPTL, RTP, TPKT packetiser</title>
|
||||
|
||||
<para>A second level packetiser bundles the IFP packets for transmission. This functions in different ways, depending on the type of transport in use. For the unreliable transports (UDPTL and RTP) the packetiser adds forward error correction (FEC) information to the packets. This can greatly inprove the reliability of the T.38 protocol, at the expense of higher bandwidth. The amount of error correction information added to the packets is implementation dependant.</para>
|
||||
|
||||
<para>For UDPTL, two forms of FEC are defined. One simply repeats older T.38 packets as FEC information in the current UDPTL packet. The other generates parity packets over a series of T.38 packets, and includes that parity information in the current UDPTL packet. The type of FEC to be used is negotiated just before T.38 communication begins.</para>
|
||||
|
||||
<para>The RTP specifications (RFC3550, RFC3551, RFC2198, RFC2733) define common redundancy and FEC formats, to be used for any payload. Where T.38 packets are carried by RTP, the standard RTP FEC mechanisms are used.</para>
|
||||
|
||||
<para>TPKT (RFC1006, RFC2126) encapsulation works over a TCP transport. TCP provides full error correction, though retries may slow it considerably. TPKT encapsulation merely provides the ability to delineate the start and end of the IFP packets in the structureless TCP stream.</para>
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
||||
<chapter id="the-elements-of-a-t38-terminal">
|
||||
<title>The elements of a T.38 terminal</title>
|
||||
|
||||
<graphic fileref="t38-terminal.png"/>
|
||||
|
||||
</chapter>
|
||||
|
||||
<chapter id="the-elements-of-a-t38-gateway">
|
||||
<title>The elements of a T.38 gateway</title>
|
||||
|
||||
<graphic fileref="t38-gateway.png"/>
|
||||
|
||||
<sect1>
|
||||
<title>The HDLC decoder</title>
|
||||
<para>If the HDLC decoder in a T.38 gateway worked in whole frames, it would introduce unacceptable latency. Instead, the HDLC decoder must work progressively through the HDLC frames, outputing its results octet by octet. The T.38 message stream does not contain HDLC preamble, though it usually contains an indication that preamble is in progress. It does not contain the CRC octets, but simply an indication of whether the CRC is good or bad. The HDLC decoder provides an indication when preamble is being received, and checks the CRC octets at the end of frames to provide the good or bad indication. The decoder makes the frames available, octet by octet, to the T.38 engine for status tracking and possible modification. Tracking and modification imposes a few octets delay, but the goal is to keep this to the minimum possible. Whether the frames are modified or unmodified, good or bad they are always passed on, to maintain the appropriate timing flow for the T.30 protocol.</para>
|
||||
|
||||
<para>An interesting aspect of the timing flow of V.21 HDLC messages on the T.38 path relates to the size of the CRC. The usual practice for sending these frames is to send one octet in each message, with the messages spaced by the duration of one octet. They will normally be sent with the minimum possible delay. The CRC at the end of each frame is two octets long, and only an indication of good or bad is sent in the T.38 messages. It takes two octet times to know if the CRC is OK or not, typically causing the flow of T.38 messages to stutter by the duration of an octet. Since flow control within a frame is not possible when frames are replayed by a remote T.38 gateway, that gateway must allow for this inevitable stutter as it prepares to begin playout of the frame.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>T.30 message analysis and manipulation</title>
|
||||
<para>The T.30 message analyser in a T.38 gateway performs the following functions:
|
||||
<itemizedlist>
|
||||
<listitem><para>It passes NSS, NSF and NSC frames, but modifies their contents. A receiving FAX machine must be prevented from acting upon these messages in a manufacturer specific manner. The T.38 protocol is incapable of handling such manufacturer specific things. However, simply dropping these packets would upset the timing of the T.30 protocol. Instead, most T.38 implementations modify the country and manufacturer codes nesr the start of these messages, so the messages will be ignored by any receiver. They are typically set to 0x00, 0x55, 0xAA or 0xFF. Some implementations set them to the country and manufacturer code of the T.38 implementor. As long as they are set to something the receiver will not recognise, problems are avoided. To avoid removing useful information, the original country and manufacturer code bytes might be reinserted in a different part of the modified NSF message, provided space permits.</para></listitem>
|
||||
<listitem><para>It tracks the contents of the DCS messages. During flow control of non-ECM data, the minimum row length must be preserved, so the current minimum must be found from the DCS messages. Similarly, the current encoding must be known to apply non-ECM flow control correctly. ECM data must be flow controlled in a completely different way than non-ECM data, so ECM mode information must be found from the DCS messages.</para></listitem>
|
||||
<listitem><para>It may optionally modify the minimum row length in the DIS messages. Because flow control will be applied to non-ECM data, it can make sense to tell the sending FAX machine it has no need to impose a minimum row length, and let the emitting T.38 entity impose the minimum as part of its flow control operation.</para></listitem>
|
||||
<listitem><para>It passes on the stripped and modified HDLC frames, with the minimum possible delay. This implies that is must analyse and modify the messages octet by octet.</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>The HDLC rate adapting encoder</title>
|
||||
<para>The HDLC data rate adapting encoder accepts a T.30 message stream as input. The V.21 HDLC messages generally arriving byte by byte, in separate T.38 messages. ECM HDLC messages usually arrive in larger chunks, but they are still generally fragmented. The rate adapter dynamically buffers the T.30 data, generates preamble, and adjusts its length if the incoming message data is falling behind. It may insert additional flag octets between frames, as a flow control mechanism. However, the HDLC protocol is synchronous, so the adapter cannot perform any flow control within a frame. It must, therefore, buffer enough octets of a frame to provide reasonable jitter tolerance, before it emits the first octet of that frame. If the arriving messages fall too far behind mid-frame, there will be corruption of the outgoing stream. In the case of ECM image data frames, the frames are fast enough, that buffering whole frames is quite proactical within the T.30 timing constraints. This ensures mid-frame underflow can never occur.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>TCF (training confirmation) and non-ECM image data rate adaption</title>
|
||||
<para>Non-ECM image data rate adaption deals with exchanging TCF data, and non-ECM image data using T.4 1-D or 2-D compression. Non-ECM image data is typically padded with zero bits at the end of each pixel row. This is used to avoid rows arriving at the receiving FAX machine faster than the mechanical paper handling can process them. It is also used by sending FAX machines for flow control, when their paper handling falls behind. The minimum duration of a row is negotiated between the FAX machines, before image transfer commences.</para>
|
||||
|
||||
<para>TCF data is a continuous stream of zero bits. It may, optionally, be preceeded by a continuous block of one bits. So, when transferring TCF data between the T.38 entities, flow control is simply a matter of repeating the last received bit when the late arrival of TCF data packets causes underflow at an emitting gateway.</para>
|
||||
|
||||
<para>T.38 entities may negotiate to generate and check TCF data locally, and not exchange it. Generally, this is only used when TCP/TPKT is used as the transport for the T.38 messages. A TCF checker and a TCF generator are needed by a T.38 gateway supporting this option.</para>
|
||||
|
||||
<para>Some T.38 entities are capable of negotiating the removal of end of row padding bits in the data passing between the T.38 entities. This may reduce the amount of data significantly, for some types of image. If negotiated, most or all surplus zero bits are stripped from the image bit stream, at the sending T.38 entity. If a T.38 gateway is receiving such stripped data, it may need to reimpose a minimum row time, by inserting zeros, as part of its non-ECM rate adaption process. By checking the contents of the DCS messages, it can determine what this minimum should be.</para>
|
||||
|
||||
<para>Only two types of image compression are used for non-ECM transmission - T.4 1-D and 2-D. The end of line (EOL) marker for both these is 11 zero bits, followed by a one bit. In 2-D mode, an additional one or zero bit follows, which defines the mode of the next row. It turns out that the maximum number of valid consecutive zeros which could preceed the 11 zeros of an EOL is 3. In a valid image there are no longer runs of zeros than at an EOL, and the maximum there is 14. Therefore, if the padding stripper reduces all runs of zeros longer than 14 to just 14, it will strip most of the padding with very simple logic. Simple logic is a good thing in this case. It not only avoids the need to fully analyse the image data, it also minimises problems when there are bit errors in the image data stream.</para>
|
||||
|
||||
<para>For image data sent without error correction (T.4 1-D or 2-D) there may be underflow at the outgoing gateway, if image data packets arrive too late. To deal with slow mechanical paper handling in FAX machines, the T.30 specification includes an end of pixel row padding scheme for non-error corrected image data. The receiving machine may request a minimum row duration. The sending machine is required to impose that minimum, but can arbitrarily make it much longer to meet its own paper handling needs, sending padding bits as appropriate. This mechanism provides a robust basis for flow control in a T.38 gateway. If the outgoing gateway only starts sending a pixel row when it has the entire row in its buffer, it can safely idle, sending padding bits, at any row end it needs to. Only the 6 EOL markers, which terminate an image, must be protected from this kind of flow control. Those markers are defined as being consecutive, with no zero bit padding separating them.</para>
|
||||
|
||||
<para>When ECM is used (usually with T.6 image data) the image is packetised in HDLC frames. In this case rate adaption is handled in a similar manner to the V.21 HDLC packets.</para>
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
||||
<chapter id="testing-an-implementation-of-t38">
|
||||
<title>Testing an implementation of T.38</title>
|
||||
<para>The T.38 specification does not define any specific compliance tests which an implementation must pass. It is not supplied with any test vectors. Commetrex is a supplier of T.38 implementations, who have taken it upon themselves to define a set of tests, and create a lab for T.38 interoperability testing. This seems the closest thing to an industry standard for T.38 testing which exists at this time, and is much to their credit.</para>
|
||||
|
||||
<para>Commetrex have defined 16 tests which an implementation T.38 undergoes in their lab. These are described on the Commetrex web site as:
|
||||
|
||||
<table frame="all">
|
||||
<title>Commetrex T.38 tests</title>
|
||||
<tgroup cols="3" align="center" colsep="1" rowsep="1">
|
||||
<colspec colname="Test #" />
|
||||
<colspec colname="Direction" />
|
||||
<colspec colname="Transport" />
|
||||
<colspec colname="Image file" />
|
||||
<colspec colname="Error correction" />
|
||||
<colspec colname="Data rate mgt" />
|
||||
<colspec colname="Image encoding" />
|
||||
<colspec colname="Polling" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="centre">Test #</entry>
|
||||
<entry align="centre">Direction</entry>
|
||||
<entry align="centre">Transport</entry>
|
||||
<entry align="centre">Image file</entry>
|
||||
<entry align="centre">Error correction</entry>
|
||||
<entry align="centre">Data rate mgt</entry>
|
||||
<entry align="centre">Image encoding</entry>
|
||||
<entry align="centre">Polling</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>1</entry><entry>originate</entry><entry>UDP</entry><entry>ccitt2p.tif</entry><entry>redundancy 0</entry><entry>method 2</entry><entry>MR</entry><entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>2</entry><entry>originate</entry><entry>UDP</entry><entry>100page.tif</entry><entry>redundancy 0</entry><entry>method 2</entry><entry>MR</entry><entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>3</entry><entry>originate</entry><entry>TCP</entry><entry>ccitt2p.tif</entry><entry>redundancy 0</entry><entry>method 1</entry><entry>MR</entry><entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>4</entry><entry>originate</entry><entry>UDP</entry><entry>ccitt2p.tif</entry><entry>redundancy 3</entry><entry>method 2</entry><entry>MR</entry><entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>5</entry><entry>originate</entry><entry>TCP</entry><entry>ccitt2p.tif</entry><entry>FEC 2 from 3 span</entry><entry>method 2</entry><entry>MR</entry><entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>6</entry><entry>originate</entry><entry>UDP</entry><entry>dither1d.tif</entry><entry>redundancy 3</entry><entry>method 2</entry><entry>MR</entry><entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>7</entry><entry>originate</entry><entry>UDP</entry><entry>ccitt2p.tif</entry><entry>redundancy 3</entry><entry>method 2</entry><entry>ECM</entry><entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>8</entry><entry>originate & poll to rx</entry><entry>UDP</entry><entry>ccitt2p.tif</entry><entry>redundancy 3</entry><entry>method 2</entry><entry>MR</entry><entry>polled rx</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>9</entry><entry>answer</entry><entry>UDP</entry><entry>ccitt2p.tif</entry><entry>redundancy 0</entry><entry>method 2</entry><entry>MR</entry><entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>10</entry><entry>answer</entry><entry>UDP</entry><entry>100page.tif</entry><entry>redundancy 0</entry><entry>method 2</entry><entry>MR</entry><entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>11</entry><entry>answer</entry><entry>TCP</entry><entry>ccitt2p.tif</entry><entry>redundancy 0</entry><entry>method 1</entry><entry>MR</entry><entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>12</entry><entry>answer</entry><entry>UDP</entry><entry>ccitt2p.tif</entry><entry>redundancy 3</entry><entry>method 2</entry><entry>MR</entry><entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>13</entry><entry>answer</entry><entry>TCP</entry><entry>ccitt2p.tif</entry><entry>FEC 2 from 3 span</entry><entry>method 2</entry><entry>MR</entry><entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>14</entry><entry>answer</entry><entry>UDP</entry><entry>dither1d.tif</entry><entry>redundancy 3</entry><entry>method 2</entry><entry>MR</entry><entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>15</entry><entry>answer</entry><entry>UDP</entry><entry>ccitt2p.tif</entry><entry>redundancy 3</entry><entry>method 2</entry><entry>ECM</entry><entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>16</entry><entry>answer & polled to tx</entry><entry>UDP</entry><entry>ccitt2p.tif</entry><entry>redundancy 3</entry><entry>method 2</entry><entry>MR</entry><entry>polled tx</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
The file dither1d.tif is a whole page of dense checkerboard pattern, which does not compress, and produces a kind of torture test page. It is about 2M bytes. 100page.tif is exactly what it says - a file with 100 pages of FAX images. The content of the pages does not seem to be specified by Commetrex. The ITU T.30 test images, repeated sufficiently, seems a good basis for this test. ccitt2p.tif appears to be page 2 of the ITU test images. The tests are heavily biased towards non-ECM operation with MR coding. No other coding appears to be used, and only 2 tests use error corrected (ECM) FAXing.
|
||||
</para>
|
||||
|
||||
<para>Some of the Commetrex tests seem strange. Why is TCP transmission tested with FEC or redundancy? These things are only needed to overcome to lack of reliability in a UDP path.</para>
|
||||
</chapter>
|
||||
|
||||
<chapter id="living-with-real-world-t38-entities">
|
||||
<title>Living with real world T.38 entities.</title>
|
||||
<para> The T.38 specification leaves a number of grey areas, and many things can be implemented in several ways. It might, therefore, be expected that interoperability will not always run smoothly. Whilst some design decisions are reasonable subjects for discussion, it is quite common to find T.38 implementations doing things which are simply wrong.</para>
|
||||
|
||||
<sect1>
|
||||
<title>Non-ECM data ending immediately after the six EOLs denoting the end of a page causes corruption</title>
|
||||
<para>From the T.38 specification, a T.38 entity sending non-ECM image data should be able to end the image data, with <emphasis>t4-non-ecm-sig-end</emphasis>, at the last bit of the six consecutive EOLs which denote the end of a page. However, this offers poor compatibility with some implementations of T.38. They will drop their carrier signal prematurely, and the last few rows of the image will be corrupted at the receiver. This can happen regardless of whether the <emphasis>t4-non-ecm-sig-end</emphasis> is followed by a <emphasis>no-signal</emphasis> message, and regardless of the timing of that <emphasis>no-signal</emphasis> message. Padding with zero bytes for 40ms or more after the six EOLs seems to prevent this, and results in an image which exactly matches the one at the source.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Expect mixups between non-ECM and ECM image modes.</title>
|
||||
<para>The TCF data should always be sent as non-ECM image data, whether the images which follow it are sent as non-ECM or ECM data. However, some broken implementations of T.38 (e.g. Mediatrix) may send an <emphasis>hdlc-sig-end</emphasis> message to terminate the TCF data. To be as tolerant as possible, it is probably wise to accept <emphasis>hdlc-sig-end</emphasis> or <emphasis>t4-non-ecm-sig-end</emphasis>, regardless of which kind of data it is really terminating.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Expect some very poor timing decisions in various designs.</title>
|
||||
<para>The preamble for V.21 HDLC data is specified as being 1s ±15%. This should mean 850ms of preamble is within spec, and many modern FAX machines only send that much. A number of T.38 implementations choke on this. They require at least 1s between the <emphasis>v21-preamble</emphasis> message and the first HDLC data, for reliable operation. This is very poor design. Even if there is 1s between these events at the source, jitter on the network can make them arrive less than 1s apart. It appears the best a tolerant implementation can really do is impose a 1s minimum between sending these T.38 messages, and accept that things might still go wrong when there is some jitter.</para>
|
||||
|
||||
<para>There is similar intolerance with the timing of the start of training messages for the fast image data modems. Most implementations do not impose a minimum which is above that permitted by the T.30 specification. Some do, however, make no allowance for network jitter reducing the interval at the receiver. You should expect the far end to be using TEP, when sizing the required delay between the start of training, and the first data. Also, for ECM data, make sure the delay allows for the specified minimum 200ms of preamble.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Which kinds of error correction to use.</title>
|
||||
<para>T.38 defines two kinds of error correction for UDPTL streams. One inserts redundant copies of older IFP packets in each UDPTL packet. The other uses a more complex parity FEC scheme, based on XOR'ed data inserted in each UDPTL packet. Although each UDPTL packet identifies the type of error correction it contains, the original T.38 spec. did not offer any form of negotiation about the type to be used. The SIP and MGCP SDP for T.38 now includes preferred error correction type information, so some measure of negotiation is possible before the flow of UDPTL packets begins.</para>
|
||||
|
||||
<para>It appears all T.38 implementations are happy to receive packets with redundant secondary content. However, it seems not all implementations will actually recover anything when there are missing UDPTL packets. It appears not all T.38 implementations are happy to receive packets with parity FEC data. Unless the SDP data from the far end explicitly says they support the parity FEC scheme, it is better to send only redundant information. A good implementation should be prepared to accept either kind of data, even intermixed, regardless of anything in the SDP negotiation. In the real world, whatever you ask for in your SDP data, you will probably receive secondary IFP packet redundancy from the far end. It is the only thing most implementations support, and with real world packet loss it may perform just as well as the more complex parity FEC scheme.</para>
|
||||
|
||||
<para>When the first few UDPTL packets are sent, there will be no historical information to send as redundant secondary IFP packets, or parity FEC data. When using the redundant secondary packet scheme this is handled transparently. Each UDPTL packet says the number of redundant secondary IFP packets it contains. This can simply be set to zero for the first UDPTL packet, one for the second, up to the amount of redundancy which has been configured. All implementations seem to work in this way. When parity FEC is being used, the startup arrangement is less clear. While some implementations simply insert zeros for the non-existant packets before the start, others send a few packets with redundant secondary IFP packets, until they are able to insert the required amount of FEC data. Dealing with intermixed types of error correction makes a receiving implementation of UDPTL messier and slower, but is necessary for compatibility.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>What really ends the data?</title>
|
||||
<para>It should be correct to send some image data, and end with the image data signal end message. However, some T.38 implementations misbehave when this is all that is sent. Immediately following the signal end message with a <emphasis>no-signal</emphasis> indicator message seems to greatly improve compatibility with some T.38 implementations.</para>
|
||||
|
||||
<para>T.38 defines <emphasis>hdlc-fcs-OK</emphasis>, <emphasis>hdlc-fcs-OK-sig-end</emphasis>, <emphasis>hdlc-sig-end</emphasis>, and <emphasis>no-signal</emphasis> messages. Always end periods of HDLC transmission with either a <emphasis>hdlc-fcs-OK</emphasis>, <emphasis>hdlc-sig-end</emphasis>, <emphasis>no-signal</emphasis> sequence or a <emphasis>hdlc-fcs-OK-sig-end</emphasis>, <emphasis>no-signal</emphasis> sequence. Do not send <emphasis>hdlc-sig-end</emphasis> after <emphasis>hdlc-fcs-OK-sig-end</emphasis>. A number of T.38 implementations choke on this sequence, even though it looks fairly harmless.</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Normal use versus testing</title>
|
||||
<para>The design of some T.38 implementations precludes some reasonable tests from succeeding, due to design features which may have been implemented for sane reasons. This means each test failure needs to be investigated in detail, to see if it represents something genuinely bad in an implementation of T.38. For example, the 2M byte torture test page in the Commetrex test suite will not successfully pass through some T.38 implementations, because of a timeout they impose. For example, some ATAs based on Audiocodes silicon have been seen to stop any continuous period of modem transmission after about 90s. This appears to be a backstop timeout, to prevent troublesome implementations jamming the gateway. Legitimate pages just don't take that long, and the timeout is reasonable. However, the 2M byte test page takes up to 20 minutes to transmit, and will always fail on these boxes.</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
||||
</book>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version='1.0'>
|
||||
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/xhtml/chunk.xsl"/>
|
||||
<xsl:param name="html.stylesheet">css.css</xsl:param>
|
||||
</xsl:stylesheet>
|
||||
@@ -0,0 +1,793 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="libspandsp"
|
||||
ProjectGUID="{CF70F278-3364-4395-A2E1-23501C9B8AD2}"
|
||||
RootNamespace="libspandsp"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="src; src\spandsp; src\msvc"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
ModuleDefinitionFile="src/msvc/spandsp.def"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="src; src\spandsp; src\msvc"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
ModuleDefinitionFile="src/msvc/spandsp.def"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\src\adsi.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\async.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\at_interpreter.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\awgn.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\bell_r2_mf.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\bert.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\complex_filters.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\complex_vector_float.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\crc.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\dds_float.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\dds_int.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\dtmf.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\echo.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\fax.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\fsk.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\g722_decode.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\g722_encode.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\g726.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\msvc\gettimeofday.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\gsm0610_decode.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\gsm0610_encode.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\gsm0610_long_term.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\gsm0610_lpc.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\gsm0610_preprocess.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\gsm0610_rpe.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\gsm0610_short_term.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\hdlc.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\ima_adpcm.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\logging.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\lpc10_analyse.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\lpc10_decode.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\lpc10_encode.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\lpc10_placev.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\lpc10_voicing.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\modem_connect_tones.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\modem_echo.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\noise.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\oki_adpcm.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\playout.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\plc.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\power_meter.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\queue.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\schedule.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\sig_tone.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\super_tone_rx.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\super_tone_tx.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\t30_api.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\t30.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\t30_logging.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\t31.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\t35.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\t38_core.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\t38_gateway.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\t38_terminal.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\t4.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\testcpuid.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\time_scale.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\tone_detect.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\tone_generate.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\v17rx.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\v17tx.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\v22bis_rx.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\v22bis_tx.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\v27ter_rx.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\v27ter_tx.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\v29rx.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\v29tx.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\v42bis.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\v42.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\v8.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\vector_float.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\vector_int.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\adsi.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\arctan2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\async.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\at_interpreter.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\awgn.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\bell_r2_mf.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\bert.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\biquad.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\bit_operations.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\bitstream.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\complex_filters.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\complex.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\complex_vector_float.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\crc.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\dc_restore.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\dds.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\dtmf.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\echo.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\fax.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\faxfont.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\fir.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\fsk.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\g168models.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\g711.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\g722.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\g726.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\hdlc.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\ima_adpcm.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\msvc\inttypes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\logging.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\lpc10.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\modem_connect_tones.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\modem_echo.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\noise.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\oki_adpcm.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\playout.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\plc.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\power_meter.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\queue.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\schedule.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\sig_tone.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\silence_gen.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\super_tone_rx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\super_tone_tx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\t30_api.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\t30_fcf.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\t30.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\t30_logging.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\t31.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\t35.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\t38_core.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\t38_gateway.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\t38_terminal.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\t4.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\t4states.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\telephony.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\msvc\tgmath.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\msvc\sys\time.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\time_scale.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\timing.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\tone_detect.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\tone_generate.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\msvc\unistd.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\v17rx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\v17tx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\v22bis.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\v27ter_rx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\v27ter_tx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\v29rx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\v29tx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\v42bis.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\v42.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\v8.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\vector_float.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\vector_int.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\spandsp\version.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,103 @@
|
||||
##
|
||||
## 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.7 2008/05/03 13:05:04 steveu Exp $
|
||||
|
||||
AM_CFLAGS = $(COMP_VENDOR_CFLAGS)
|
||||
AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS)
|
||||
|
||||
LIBS += $(TESTLIBS)
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
INCLUDES = -I$(top_builddir) -I$(top_builddir)/src -DDATADIR="\"$(pkgdatadir)\""
|
||||
|
||||
noinst_PROGRAMS = make_line_models
|
||||
|
||||
lib_LTLIBRARIES = libspandsp-sim.la
|
||||
|
||||
libspandsp_sim_la_SOURCES = g1050.c \
|
||||
line_model.c \
|
||||
rfc2198_sim.c \
|
||||
test_utils.c
|
||||
|
||||
nodist_libspandsp_sim_la_SOURCES = line_models.c
|
||||
|
||||
libspandsp_sim_la_LDFLAGS = -version-info @SPANDSP_LT_CURRENT@:@SPANDSP_LT_REVISION@:@SPANDSP_LT_AGE@
|
||||
|
||||
nobase_include_HEADERS = spandsp/g1050.h \
|
||||
spandsp/line_model.h \
|
||||
spandsp/line_models.h \
|
||||
spandsp/rfc2198_sim.h \
|
||||
spandsp/test_utils.h \
|
||||
spandsp-sim.h
|
||||
|
||||
make_line_models_SOURCES = make_line_models.c
|
||||
make_line_models_LDADD = -L$(top_builddir)/src -lspandsp
|
||||
|
||||
# We need to run make_line_models, so it generates the line_models.h file
|
||||
# used by several of the test programs.
|
||||
|
||||
line_models.lo: make_line_models$(EXEEXT) line_models.c
|
||||
|
||||
line_models.$(OBJEXT): make_line_models$(EXEEXT) line_models.c
|
||||
|
||||
line_models.c: make_line_models$(EXEEXT)
|
||||
./make_line_models$(EXEEXT)
|
||||
|
||||
DSP = libspandsp-sim.dsp
|
||||
VCPROJ = libspandsp-sim.vcproj
|
||||
|
||||
WIN32SOURCES = $(libspandsp_sim_la_SOURCES) msvc/gettimeofday.c
|
||||
WIN32HEADERS = $(nobase_include_HEADERS) spandsp-sim.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 "<File RelativePath=\""$$file"\"></File>" $(VCPROJOUT); \
|
||||
done; \
|
||||
echo "</Filter><Filter Name=\"Header Files\">" $(VCPROJOUT); \
|
||||
for file in $(WIN32HEADERS); do \
|
||||
echo "<File RelativePath=\""$$file"\"></File>" $(VCPROJOUT); \
|
||||
done; \
|
||||
cat $(srcdir)/msvc/vc8proj.foot $(VCPROJOUT) )
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,566 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* line_model.c - Model a telephone line.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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: line_model.c,v 1.6 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <audiofile.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#define GEN_CONST
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#include "spandsp.h"
|
||||
#include "spandsp-sim.h"
|
||||
#include "spandsp/g168models.h"
|
||||
|
||||
#if !defined(NULL)
|
||||
#define NULL (void *) 0
|
||||
#endif
|
||||
|
||||
float null_line_model[] =
|
||||
{
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
};
|
||||
|
||||
static float *models[] =
|
||||
{
|
||||
null_line_model, /* 0 */
|
||||
proakis_line_model,
|
||||
ad_1_edd_1_model,
|
||||
ad_1_edd_2_model,
|
||||
ad_1_edd_3_model,
|
||||
ad_5_edd_1_model, /* 5 */
|
||||
ad_5_edd_2_model,
|
||||
ad_5_edd_3_model,
|
||||
ad_6_edd_1_model,
|
||||
ad_6_edd_2_model,
|
||||
ad_6_edd_3_model, /* 10 */
|
||||
ad_7_edd_1_model,
|
||||
ad_7_edd_2_model,
|
||||
ad_7_edd_3_model,
|
||||
ad_8_edd_1_model,
|
||||
ad_8_edd_2_model, /* 15 */
|
||||
ad_8_edd_3_model,
|
||||
ad_9_edd_1_model,
|
||||
ad_9_edd_2_model,
|
||||
ad_9_edd_3_model
|
||||
};
|
||||
|
||||
static float calc_near_line_filter(one_way_line_model_state_t *s, float v)
|
||||
{
|
||||
float sum;
|
||||
int j;
|
||||
int p;
|
||||
|
||||
/* Add the sample in the filter buffer */
|
||||
p = s->near_buf_ptr;
|
||||
s->near_buf[p] = v;
|
||||
if (++p == s->near_filter_len)
|
||||
p = 0;
|
||||
s->near_buf_ptr = p;
|
||||
|
||||
/* Apply the filter */
|
||||
sum = 0;
|
||||
for (j = 0; j < s->near_filter_len; j++)
|
||||
{
|
||||
sum += s->near_filter[j]*s->near_buf[p];
|
||||
if (++p >= s->near_filter_len)
|
||||
p = 0;
|
||||
}
|
||||
|
||||
/* Add noise */
|
||||
sum += awgn(&s->near_noise);
|
||||
|
||||
return sum;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static float calc_far_line_filter(one_way_line_model_state_t *s, float v)
|
||||
{
|
||||
float sum;
|
||||
int j;
|
||||
int p;
|
||||
|
||||
/* Add the sample in the filter buffer */
|
||||
p = s->far_buf_ptr;
|
||||
s->far_buf[p] = v;
|
||||
if (++p == s->far_filter_len)
|
||||
p = 0;
|
||||
s->far_buf_ptr = p;
|
||||
|
||||
/* Apply the filter */
|
||||
sum = 0;
|
||||
for (j = 0; j < s->far_filter_len; j++)
|
||||
{
|
||||
sum += s->far_filter[j]*s->far_buf[p];
|
||||
if (++p >= s->far_filter_len)
|
||||
p = 0;
|
||||
}
|
||||
|
||||
/* Add noise */
|
||||
sum += awgn(&s->far_noise);
|
||||
|
||||
return sum;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void one_way_line_model(one_way_line_model_state_t *s,
|
||||
int16_t output[],
|
||||
const int16_t input[],
|
||||
int samples)
|
||||
{
|
||||
int i;
|
||||
float in;
|
||||
float out;
|
||||
float out1;
|
||||
int16_t amp[1];
|
||||
|
||||
/* The path being modelled is:
|
||||
terminal
|
||||
| < hybrid
|
||||
|
|
||||
| < noise and filtering
|
||||
|
|
||||
| < hybrid
|
||||
CO
|
||||
|
|
||||
| < A-law distortion + bulk delay
|
||||
|
|
||||
CO
|
||||
| < hybrid
|
||||
|
|
||||
| < noise and filtering
|
||||
|
|
||||
| < hybrid
|
||||
terminal
|
||||
*/
|
||||
for (i = 0; i < samples; i++)
|
||||
{
|
||||
in = input[i];
|
||||
|
||||
/* Near end analogue section */
|
||||
|
||||
/* Line model filters & noise */
|
||||
out = calc_near_line_filter(s, in);
|
||||
|
||||
/* Long distance digital section */
|
||||
|
||||
amp[0] = out;
|
||||
codec_munge(s->munge, amp, 1);
|
||||
out = amp[0];
|
||||
/* Introduce the bulk delay of the long distance link. */
|
||||
out1 = s->bulk_delay_buf[s->bulk_delay_ptr];
|
||||
s->bulk_delay_buf[s->bulk_delay_ptr] = out;
|
||||
out = out1;
|
||||
if (++s->bulk_delay_ptr >= s->bulk_delay)
|
||||
s->bulk_delay_ptr = 0;
|
||||
|
||||
/* Far end analogue section */
|
||||
|
||||
/* Line model filters & noise */
|
||||
out = calc_far_line_filter(s, out);
|
||||
|
||||
if (s->mains_interference)
|
||||
{
|
||||
tone_gen(&s->mains_tone, amp, 1);
|
||||
out += amp[0];
|
||||
}
|
||||
output[i] = out + s->dc_offset;
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void one_way_line_model_set_dc(one_way_line_model_state_t *s, float dc)
|
||||
{
|
||||
s->dc_offset = dc;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void one_way_line_model_set_mains_pickup(one_way_line_model_state_t *s, int f, float level)
|
||||
{
|
||||
tone_gen_descriptor_t mains_tone_desc;
|
||||
|
||||
if (f)
|
||||
{
|
||||
make_tone_gen_descriptor(&mains_tone_desc, f, (int) (level - 10.0f), f*3, (int) level, 1, 0, 0, 0, TRUE);
|
||||
tone_gen_init(&s->mains_tone, &mains_tone_desc);
|
||||
}
|
||||
s->mains_interference = f;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void both_ways_line_model(both_ways_line_model_state_t *s,
|
||||
int16_t output1[],
|
||||
const int16_t input1[],
|
||||
int16_t output2[],
|
||||
const int16_t input2[],
|
||||
int samples)
|
||||
{
|
||||
int i;
|
||||
float in1;
|
||||
float in2;
|
||||
float out1;
|
||||
float out2;
|
||||
float tmp1;
|
||||
float tmp2;
|
||||
int16_t amp[1];
|
||||
|
||||
/* The path being modelled is:
|
||||
terminal
|
||||
| < hybrid echo
|
||||
|
|
||||
| < noise and filtering
|
||||
|
|
||||
| < hybrid echo
|
||||
CO
|
||||
|
|
||||
| < A-law distortion + bulk delay
|
||||
|
|
||||
CO
|
||||
| < hybrid echo
|
||||
|
|
||||
| < noise and filtering
|
||||
|
|
||||
| < hybrid echo
|
||||
terminal
|
||||
*/
|
||||
for (i = 0; i < samples; i++)
|
||||
{
|
||||
in1 = input1[i];
|
||||
in2 = input2[i];
|
||||
|
||||
/* Near end analogue sections */
|
||||
/* Echo from each terminal's CO hybrid */
|
||||
tmp1 = in1 + s->fout2*s->line1.near_co_hybrid_echo;
|
||||
tmp2 = in2 + s->fout1*s->line2.near_co_hybrid_echo;
|
||||
|
||||
/* Line model filters & noise */
|
||||
s->fout1 = calc_near_line_filter(&s->line1, tmp1);
|
||||
s->fout2 = calc_near_line_filter(&s->line2, tmp2);
|
||||
|
||||
/* Long distance digital section */
|
||||
|
||||
/* Introduce distortion due to A-law or u-law munging. */
|
||||
amp[0] = s->fout1;
|
||||
codec_munge(s->line1.munge, amp, 1);
|
||||
s->fout1 = amp[0];
|
||||
|
||||
amp[0] = s->fout2;
|
||||
codec_munge(s->line2.munge, amp, 1);
|
||||
s->fout2 = amp[0];
|
||||
|
||||
/* Introduce the bulk delay of the long distance digital link. */
|
||||
out1 = s->line1.bulk_delay_buf[s->line1.bulk_delay_ptr];
|
||||
s->line1.bulk_delay_buf[s->line1.bulk_delay_ptr] = s->fout1;
|
||||
s->fout1 = out1;
|
||||
if (++s->line1.bulk_delay_ptr >= s->line1.bulk_delay)
|
||||
s->line1.bulk_delay_ptr = 0;
|
||||
|
||||
out2 = s->line2.bulk_delay_buf[s->line2.bulk_delay_ptr];
|
||||
s->line2.bulk_delay_buf[s->line2.bulk_delay_ptr] = s->fout2;
|
||||
s->fout2 = out2;
|
||||
if (++s->line2.bulk_delay_ptr >= s->line2.bulk_delay)
|
||||
s->line2.bulk_delay_ptr = 0;
|
||||
|
||||
/* Far end analogue sections */
|
||||
|
||||
/* Echo from each terminal's own hybrid */
|
||||
out1 += in2*s->line1.far_cpe_hybrid_echo;
|
||||
out2 += in1*s->line2.far_cpe_hybrid_echo;
|
||||
|
||||
/* Line model filters & noise */
|
||||
out1 = calc_far_line_filter(&s->line1, out1);
|
||||
out2 = calc_far_line_filter(&s->line2, out2);
|
||||
|
||||
output1[i] = fsaturate(out1 + s->line1.dc_offset);
|
||||
output2[i] = fsaturate(out2 + s->line2.dc_offset);
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void both_ways_line_model_set_dc(both_ways_line_model_state_t *s, float dc1, float dc2)
|
||||
{
|
||||
s->line1.dc_offset = dc1;
|
||||
s->line2.dc_offset = dc2;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void both_ways_line_model_set_mains_pickup(both_ways_line_model_state_t *s, int f, float level1, float level2)
|
||||
{
|
||||
tone_gen_descriptor_t mains_tone_desc;
|
||||
|
||||
if (f)
|
||||
{
|
||||
make_tone_gen_descriptor(&mains_tone_desc, f, (int) (level1 - 10.0f), f*3, (int) level1, 1, 0, 0, 0, TRUE);
|
||||
tone_gen_init(&s->line1.mains_tone, &mains_tone_desc);
|
||||
make_tone_gen_descriptor(&mains_tone_desc, f, (int) (level2 - 10.0f), f*3, (int) level2, 1, 0, 0, 0, TRUE);
|
||||
tone_gen_init(&s->line2.mains_tone, &mains_tone_desc);
|
||||
}
|
||||
s->line1.mains_interference = f;
|
||||
s->line2.mains_interference = f;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
one_way_line_model_state_t *one_way_line_model_init(int model, float noise, int codec, int rbs_pattern)
|
||||
{
|
||||
one_way_line_model_state_t *s;
|
||||
|
||||
if ((s = (one_way_line_model_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
s->bulk_delay = 8;
|
||||
s->bulk_delay_ptr = 0;
|
||||
|
||||
s->munge = codec_munge_init(codec, rbs_pattern);
|
||||
|
||||
s->near_filter = models[model];
|
||||
s->near_filter_len = 129;
|
||||
|
||||
s->far_filter = models[model];
|
||||
s->far_filter_len = 129;
|
||||
|
||||
awgn_init_dbm0(&s->near_noise, 1234567, noise);
|
||||
awgn_init_dbm0(&s->far_noise, 1234567, noise);
|
||||
|
||||
s->dc_offset = 0.0f;
|
||||
s->mains_interference = 0;
|
||||
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int one_way_line_model_release(one_way_line_model_state_t *s)
|
||||
{
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
both_ways_line_model_state_t *both_ways_line_model_init(int model1,
|
||||
float noise1,
|
||||
int model2,
|
||||
float noise2,
|
||||
int codec,
|
||||
int rbs_pattern)
|
||||
{
|
||||
float echo_level;
|
||||
both_ways_line_model_state_t *s;
|
||||
|
||||
if ((s = (both_ways_line_model_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
s->line1.munge = codec_munge_init(codec, rbs_pattern);
|
||||
s->line2.munge = codec_munge_init(codec, rbs_pattern);
|
||||
|
||||
s->line1.bulk_delay = 8;
|
||||
s->line2.bulk_delay = 8;
|
||||
|
||||
s->line1.bulk_delay_ptr = 0;
|
||||
s->line2.bulk_delay_ptr = 0;
|
||||
|
||||
s->line1.near_filter = models[model1];
|
||||
s->line1.near_filter_len = 129;
|
||||
s->line2.near_filter = models[model2];
|
||||
s->line2.near_filter_len = 129;
|
||||
|
||||
s->line1.far_filter = models[model1];
|
||||
s->line1.far_filter_len = 129;
|
||||
s->line2.far_filter = models[model2];
|
||||
s->line2.far_filter_len = 129;
|
||||
|
||||
awgn_init_dbm0(&s->line1.near_noise, 1234567, noise1);
|
||||
awgn_init_dbm0(&s->line2.near_noise, 7654321, noise2);
|
||||
|
||||
awgn_init_dbm0(&s->line1.far_noise, 1234567, noise1);
|
||||
awgn_init_dbm0(&s->line2.far_noise, 7654321, noise2);
|
||||
|
||||
s->line1.dc_offset = 0.0f;
|
||||
s->line2.dc_offset = 0.0f;
|
||||
s->line1.mains_interference = 0;
|
||||
s->line2.mains_interference = 0;
|
||||
|
||||
/* Echos */
|
||||
echo_level = -15; /* in dB */
|
||||
s->line1.near_co_hybrid_echo = pow(10, echo_level/20.0);
|
||||
s->line2.near_co_hybrid_echo = pow(10, echo_level/20.0);
|
||||
s->line1.near_cpe_hybrid_echo = pow(10, echo_level/20.0);
|
||||
s->line2.near_cpe_hybrid_echo = pow(10, echo_level/20.0);
|
||||
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int both_ways_line_model_release(both_ways_line_model_state_t *s)
|
||||
{
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* rfc2198_sim.c - Simulate the behaviour of RFC2198 (or UDPTL) redundancy.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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: rfc2198_sim.c,v 1.6 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <audiofile.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#define GEN_CONST
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#include "spandsp.h"
|
||||
#include "spandsp/g1050.h"
|
||||
#include "spandsp/rfc2198_sim.h"
|
||||
|
||||
#define PACKET_LOSS_TIME -1
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE (!FALSE)
|
||||
|
||||
rfc2198_sim_state_t *rfc2198_sim_init(int model,
|
||||
int speed_pattern,
|
||||
int packet_size,
|
||||
int packet_rate,
|
||||
int redundancy_depth)
|
||||
{
|
||||
rfc2198_sim_state_t *s;
|
||||
|
||||
if ((s = (rfc2198_sim_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
s->g1050 = g1050_init(model, speed_pattern, packet_size, packet_rate);
|
||||
s->redundancy_depth = redundancy_depth;
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int rfc2198_sim_put(rfc2198_sim_state_t *s,
|
||||
const uint8_t buf[],
|
||||
int len,
|
||||
int seq_no,
|
||||
double departure_time)
|
||||
{
|
||||
uint8_t buf2[8192];
|
||||
uint8_t *p;
|
||||
uint16_t *q;
|
||||
int slot;
|
||||
int i;
|
||||
|
||||
/* Save the packet in the history buffer */
|
||||
memcpy(s->tx_pkt[s->next_pkt], buf, len);
|
||||
s->tx_pkt_len[s->next_pkt] = len;
|
||||
s->tx_pkt_seq_no[s->next_pkt] = seq_no;
|
||||
|
||||
/* Construct the redundant packet */
|
||||
p = buf2;
|
||||
slot = s->next_pkt;
|
||||
q = (uint16_t *) p;
|
||||
*q = s->redundancy_depth;
|
||||
p += sizeof(uint16_t);
|
||||
for (i = 0; i < s->redundancy_depth; i++)
|
||||
{
|
||||
q = (uint16_t *) p;
|
||||
*q = s->tx_pkt_len[slot];
|
||||
p += sizeof(uint16_t);
|
||||
memcpy(p, s->tx_pkt[slot], s->tx_pkt_len[slot]);
|
||||
p += s->tx_pkt_len[slot];
|
||||
slot = (slot - 1) & 0x1F;
|
||||
}
|
||||
s->next_pkt = (s->next_pkt + 1) & 0x1F;
|
||||
return g1050_put(s->g1050, buf2, p - buf2, seq_no, departure_time);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int rfc2198_sim_get(rfc2198_sim_state_t *s,
|
||||
uint8_t buf[],
|
||||
int max_len,
|
||||
double current_time,
|
||||
int *seq_no,
|
||||
double *departure_time,
|
||||
double *arrival_time)
|
||||
{
|
||||
int len;
|
||||
int lenx;
|
||||
int seq_nox;
|
||||
int i;
|
||||
uint8_t bufx[s->redundancy_depth*1024];
|
||||
uint8_t *p;
|
||||
uint16_t *q;
|
||||
int redundancy_depth;
|
||||
|
||||
if (s->rx_queued_pkts)
|
||||
{
|
||||
/* We have some stuff from the last g1050_get() still to deliver */
|
||||
s->rx_queued_pkts--;
|
||||
memcpy(buf, s->rx_pkt[s->rx_queued_pkts], s->rx_pkt_len[s->rx_queued_pkts]);
|
||||
*seq_no = s->rx_pkt_seq_no[s->rx_queued_pkts];
|
||||
return s->rx_pkt_len[s->rx_queued_pkts];
|
||||
}
|
||||
len = g1050_get(s->g1050, bufx, s->redundancy_depth*1024, current_time, &seq_nox, departure_time, arrival_time);
|
||||
if (len > 0)
|
||||
{
|
||||
p = bufx;
|
||||
q = (uint16_t *) p;
|
||||
redundancy_depth = *q;
|
||||
p += sizeof(uint16_t);
|
||||
i = 0;
|
||||
if (seq_nox > s->next_seq_no)
|
||||
{
|
||||
/* Some stuff is missing. Try to fill it in. */
|
||||
s->rx_queued_pkts = seq_nox - s->next_seq_no;
|
||||
if (s->rx_queued_pkts >= redundancy_depth)
|
||||
s->rx_queued_pkts = redundancy_depth - 1;
|
||||
for (i = 0; i < s->rx_queued_pkts; i++)
|
||||
{
|
||||
q = (uint16_t *) p;
|
||||
s->rx_pkt_len[i] = *q;
|
||||
p += sizeof(uint16_t);
|
||||
memcpy(s->rx_pkt[i], p, s->rx_pkt_len[i]);
|
||||
s->rx_pkt_seq_no[i] = seq_nox - i;
|
||||
p += s->rx_pkt_len[i];
|
||||
}
|
||||
}
|
||||
*seq_no = seq_nox - i;
|
||||
q = (uint16_t *) p;
|
||||
lenx = *q;
|
||||
p += sizeof(uint16_t);
|
||||
memcpy(buf, p, lenx);
|
||||
s->next_seq_no = seq_nox + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lenx = len;
|
||||
}
|
||||
return lenx;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* spandsp-sim.h - The head guy amongst the simulator headers
|
||||
*
|
||||
* Written by Steve Underwood <spandsp/steveu@coppice.org>
|
||||
*
|
||||
* 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: spandsp-sim.h,v 1.5 2008/04/26 13:39:16 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if !defined(_SPANDSP_SIM_H_)
|
||||
#define _SPANDSP_SIM_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <time.h>
|
||||
#include <tiffio.h>
|
||||
|
||||
#include <spandsp/g1050.h>
|
||||
#include <spandsp/rfc2198_sim.h>
|
||||
#include <spandsp/test_utils.h>
|
||||
#include <spandsp/line_model.h>
|
||||
#include <spandsp/line_models.h>
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* g1050.h - IP network modeling, as per G.1050/TIA-921.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: g1050.h,v 1.7 2008/04/17 18:03:23 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
/*! \page g1050_ip_network_model_page G.1050/TIA-921 IP network path model
|
||||
\section g1050_ip_network_model_page_sec_1 What does it do?
|
||||
The ITU G.1050 specification defines a model of an IP network, appropriate
|
||||
for the testing of how streaming media woud behave across the internet. The
|
||||
model is based on a path having 5 segments:
|
||||
- a local LAN (wired or wireless)
|
||||
- an access link to the internet
|
||||
- an internet of arbitrary complexity
|
||||
- an access link from the internet
|
||||
- a distant LAN (wired or wireless)
|
||||
The impairments typical of these segments at various service levels are modelled.
|
||||
8 standard service level behaviours are defined, covering lightly loaded to heavily
|
||||
congested levels. 133 standard sets of link speeds are defined, covering typical
|
||||
wired and wireless LAN, broadband access link, and backbone characteristics.
|
||||
|
||||
The G.1050 model is suitable for testing the behaviour of RTP, UDPTL and other streaming
|
||||
protocols for packet loss and jitter behaviour.
|
||||
*/
|
||||
|
||||
#if !defined(_G1050_H_)
|
||||
#define _G1050_H_
|
||||
|
||||
/* This is the time slice at which delays, packet loss, etc. are calculated. */
|
||||
#define G1050_TICKS_PER_SEC 1000
|
||||
|
||||
/* Search back 200 ms to preserve order of legitimately out of sequence packets. */
|
||||
#define SEARCHBACK_PERIOD 200
|
||||
|
||||
#define G1050_LOW_LOSS 0
|
||||
#define G1050_HIGH_LOSS 1
|
||||
|
||||
#define G1050_LAN_LINK 1
|
||||
#define G1050_ACCESS_LINK 2
|
||||
|
||||
/*! Segment constants, as defined in G.1050. */
|
||||
typedef struct
|
||||
{
|
||||
/*! Probability of changing from low to high and high to low loss states */
|
||||
double prob_loss_rate_change[2];
|
||||
/*! Probability of an impulse in the low and high loss states */
|
||||
double prob_impulse[2][2];
|
||||
|
||||
/*! Impulse height, based on MTU and bit rate */
|
||||
double impulse_height;
|
||||
/*! Impulse decay coefficient for the single pole IIR filter. */
|
||||
double impulse_coeff;
|
||||
|
||||
/*! Probability of packet loss due to occupancy. */
|
||||
double prob_packet_loss;
|
||||
/*! Probability of packet loss due to a multiple access collision. */
|
||||
double prob_packet_collision_loss;
|
||||
} g1050_segment_constants_t;
|
||||
|
||||
/*! End-to-end constants, as defined in G.1050. */
|
||||
typedef struct
|
||||
{
|
||||
g1050_segment_constants_t segment[4];
|
||||
} g1050_constants_t;
|
||||
|
||||
/*! The model definition for a LAN or access link segment */
|
||||
typedef struct
|
||||
{
|
||||
/*! Percentage occupancy of the media */
|
||||
double percentage_occupancy;
|
||||
/*! MTU of the media */
|
||||
int mtu;
|
||||
/*! Maximum jitter in the segment. */
|
||||
double max_jitter;
|
||||
} g1050_segment_model_t;
|
||||
|
||||
/*! The model definition for the core network (backbone) segment */
|
||||
typedef struct
|
||||
{
|
||||
/*! Basic delay of the backbone for regional paths */
|
||||
double base_regional_delay;
|
||||
/*! Basic delay of the backbone for intercontinental paths */
|
||||
double base_intercontinental_delay;
|
||||
/*! Percentage packet loss of the backbone */
|
||||
/*! Percentage packet loss of the backbone. */
|
||||
double percentage_packet_loss;
|
||||
/*! Maximum jitter in the backbone. */
|
||||
double max_jitter;
|
||||
/*! Interval between the backbone route flapping between two paths, in seconds. */
|
||||
double route_flap_interval;
|
||||
/*! The difference in backbone delay between the two routes we flap between, in seconds. */
|
||||
double route_flap_delay;
|
||||
/*! The interval between link failures. */
|
||||
double link_failure_interval;
|
||||
/*! The duration of link failures. */
|
||||
double link_failure_duration;
|
||||
/*! Probability of packet loss in the backbone. */
|
||||
double prob_packet_loss;
|
||||
/*! Probability of a packet going out of sequence in the backbone. */
|
||||
double prob_oos;
|
||||
} g1050_core_model_t;
|
||||
|
||||
/*! The model definition for a complete end-to-end path */
|
||||
typedef struct
|
||||
{
|
||||
/*! The likelyhood of occurance probabilities for the A, B and C scenarios defined in G.1050 */
|
||||
int loo[3];
|
||||
g1050_segment_model_t sidea_lan;
|
||||
g1050_segment_model_t sidea_access_link;
|
||||
g1050_core_model_t core;
|
||||
g1050_segment_model_t sideb_access_link;
|
||||
g1050_segment_model_t sideb_lan;
|
||||
} g1050_model_t;
|
||||
|
||||
/*! The speed model for a complete end-to-end path */
|
||||
typedef struct
|
||||
{
|
||||
int sidea_lan_bit_rate;
|
||||
int sidea_lan_multiple_access;
|
||||
int sidea_access_link_bit_rate_ab;
|
||||
int sidea_access_link_bit_rate_ba;
|
||||
int sidea_access_link_qos_enabled;
|
||||
int sideb_lan_bit_rate;
|
||||
int sideb_lan_multiple_access;
|
||||
int sideb_access_link_bit_rate_ab;
|
||||
int sideb_access_link_bit_rate_ba;
|
||||
int sideb_access_link_qos_enabled;
|
||||
double loo;
|
||||
} g1050_channel_speeds_t;
|
||||
|
||||
/*! The model state for a LAN or access link segment */
|
||||
typedef struct
|
||||
{
|
||||
/*! The type of link, G1050_LAN_LINK or G_1050_ACCESS_LINK */
|
||||
int link_type;
|
||||
/*! 1 if in the high loss state, or 0 if in the low loss state. */
|
||||
int high_loss;
|
||||
|
||||
/*! The probability of a loss rate change, for both loss rate states. */
|
||||
double prob_loss_rate_change[2];
|
||||
/*! The probability of a impulse occuring, for both loss rate states. */
|
||||
double prob_impulse[2];
|
||||
|
||||
/*! The maximum permitted height of impulses. */
|
||||
double impulse_height;
|
||||
/*! The impulse decay coefficient. */
|
||||
double impulse_coeff;
|
||||
|
||||
/*! The basic serial delay due to the link. */
|
||||
double serial_delay;
|
||||
/*! Peak jitter in the segment. */
|
||||
double max_jitter;
|
||||
/*! The probability of packet loss. */
|
||||
double prob_packet_loss;
|
||||
/*! The probability of packet loss due to collision. */
|
||||
double prob_packet_collision_loss;
|
||||
/*! The maximum addition delay due to congestion. */
|
||||
double congestion_delay;
|
||||
|
||||
/*! TRUE if QoS is enabled on the link. */
|
||||
int qos_enabled;
|
||||
/*! TRUE if the link is a multiple access type (e.g. an ethernet hub). */
|
||||
int multiple_access;
|
||||
|
||||
/*! The latest packet arrival time seen on the link. */
|
||||
double last_arrival_time;
|
||||
|
||||
/*! 3 seconds of predicted delays for the link */
|
||||
double delays[3*G1050_TICKS_PER_SEC];
|
||||
|
||||
/*! A count of packets lost on the link. */
|
||||
uint32_t lost_packets;
|
||||
/*! An extra debug count of packets lost on the link. */
|
||||
uint32_t lost_packets_2;
|
||||
} g1050_segment_state_t;
|
||||
|
||||
/*! The model state for the core network (backbone) segment */
|
||||
typedef struct
|
||||
{
|
||||
/* Router model. */
|
||||
int32_t route_flap_counter;
|
||||
int32_t route_flap_interval;
|
||||
double route_flap_delta;
|
||||
|
||||
/* Link failure model. */
|
||||
int32_t link_failure_counter;
|
||||
int32_t link_recovery_counter;
|
||||
|
||||
int32_t link_failure_interval_ticks;
|
||||
int32_t link_failure_duration_ticks;
|
||||
|
||||
/*! Basic backbone delay */
|
||||
double base_delay;
|
||||
/*! Peak jitter in the backbone delay */
|
||||
double max_jitter;
|
||||
/*! Probability of packet loss in the backbone, in percent */
|
||||
double prob_packet_loss;
|
||||
/*! Probability of a packet going out of sequence in the backbone. */
|
||||
double prob_oos;
|
||||
|
||||
/*! The latest packet arrival time seen on the link. */
|
||||
double last_arrival_time;
|
||||
double delay_delta;
|
||||
|
||||
/*! 3 seconds of predicted delays for the link */
|
||||
double delays[3*G1050_TICKS_PER_SEC];
|
||||
|
||||
/*! A count of packets lost on the link. */
|
||||
uint32_t lost_packets;
|
||||
/*! An extra debug count of packets lost on the link. */
|
||||
uint32_t lost_packets_2;
|
||||
} g1050_core_state_t;
|
||||
|
||||
/*! The definition of an element in the packet queue */
|
||||
typedef struct g1050_queue_element_s
|
||||
{
|
||||
struct g1050_queue_element_s *next;
|
||||
struct g1050_queue_element_s *prev;
|
||||
int seq_no;
|
||||
double departure_time;
|
||||
double arrival_time;
|
||||
int len;
|
||||
uint8_t pkt[0];
|
||||
} g1050_queue_element_t;
|
||||
|
||||
/*! The model definition for a complete end-to-end path */
|
||||
typedef struct
|
||||
{
|
||||
int packet_rate;
|
||||
int packet_size;
|
||||
float base_time;
|
||||
g1050_segment_state_t segment[4];
|
||||
g1050_core_state_t core;
|
||||
double arrival_times_1[3*G1050_TICKS_PER_SEC];
|
||||
double arrival_times_2[3*G1050_TICKS_PER_SEC];
|
||||
g1050_queue_element_t *first;
|
||||
g1050_queue_element_t *last;
|
||||
} g1050_state_t;
|
||||
|
||||
extern g1050_constants_t g1050_constants[1];
|
||||
extern g1050_channel_speeds_t g1050_speed_patterns[133];
|
||||
extern g1050_model_t g1050_standard_models[9];
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
g1050_state_t *g1050_init(int model,
|
||||
int speed_pattern,
|
||||
int packet_size,
|
||||
int packet_rate);
|
||||
|
||||
void g1050_dump_parms(int model, int speed_pattern);
|
||||
|
||||
int g1050_put(g1050_state_t *s,
|
||||
const uint8_t buf[],
|
||||
int len,
|
||||
int seq_no,
|
||||
double departure_time);
|
||||
|
||||
int g1050_get(g1050_state_t *s,
|
||||
uint8_t buf[],
|
||||
int max_len,
|
||||
double current_time,
|
||||
int *seq_no,
|
||||
double *departure_time,
|
||||
double *arrival_time);
|
||||
|
||||
void g1050_queue_dump(g1050_state_t *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* line_model.h - Model a telephone line.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: line_model.h,v 1.3 2008/04/17 18:03:23 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
/*! \page line_model_page Telephone line model
|
||||
\section line_model_page_sec_1 What does it do?
|
||||
The telephone line modelling module provides simple modelling of one way and two
|
||||
way telephone lines.
|
||||
|
||||
The path being modelled is:
|
||||
|
||||
- terminal
|
||||
- | < hybrid echo (2-way models)
|
||||
- |
|
||||
- | < noise and filtering
|
||||
- |
|
||||
- | < hybrid echo (2-way models)
|
||||
- CO
|
||||
- |
|
||||
- | < A-law distortion + bulk delay
|
||||
- |
|
||||
- CO
|
||||
- | < hybrid echo (2-way models)
|
||||
- |
|
||||
- | < noise and filtering
|
||||
- |
|
||||
- | < hybrid echo (2-way models)
|
||||
- terminal
|
||||
*/
|
||||
|
||||
#if !defined(_SPANDSP_LINE_MODEL_H_)
|
||||
#define _SPANDSP_LINE_MODEL_H_
|
||||
|
||||
#define LINE_FILTER_SIZE 129
|
||||
|
||||
/*!
|
||||
One way line model descriptor. This holds the complete state of
|
||||
a line model with transmission in only one direction.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
codec_munge_state_t *munge;
|
||||
|
||||
/*! The coefficients for the near end analogue section simulation filter */
|
||||
float *near_filter;
|
||||
/*! The number of coefficients for the near end analogue section simulation filter */
|
||||
int near_filter_len;
|
||||
/*! Last transmitted samples (ring buffer, used by the line filter) */
|
||||
float near_buf[LINE_FILTER_SIZE];
|
||||
/*! Pointer of the last transmitted sample in buf */
|
||||
int near_buf_ptr;
|
||||
/*! The noise source for local analogue section of the line */
|
||||
awgn_state_t near_noise;
|
||||
|
||||
/*! The bulk delay of the path, in samples */
|
||||
int bulk_delay;
|
||||
/*! A pointer to the current write position in the bulk delay store. */
|
||||
int bulk_delay_ptr;
|
||||
/*! The data store for simulating the bulk delay */
|
||||
int16_t bulk_delay_buf[8000];
|
||||
|
||||
/*! The coefficients for the far end analogue section simulation filter */
|
||||
float *far_filter;
|
||||
/*! The number of coefficients for the far end analogue section simulation filter */
|
||||
int far_filter_len;
|
||||
/*! Last transmitted samples (ring buffer, used by the line filter) */
|
||||
float far_buf[LINE_FILTER_SIZE];
|
||||
/*! Pointer of the last transmitted sample in buf */
|
||||
int far_buf_ptr;
|
||||
/*! The noise source for distant analogue section of the line */
|
||||
awgn_state_t far_noise;
|
||||
|
||||
/*! The scaling factor for the local CPE hybrid echo */
|
||||
float near_cpe_hybrid_echo;
|
||||
/*! The scaling factor for the local CO hybrid echo */
|
||||
float near_co_hybrid_echo;
|
||||
|
||||
/*! The scaling factor for the far CPE hybrid echo */
|
||||
float far_cpe_hybrid_echo;
|
||||
/*! The scaling factor for the far CO hybrid echo */
|
||||
float far_co_hybrid_echo;
|
||||
/*! DC offset impairment */
|
||||
float dc_offset;
|
||||
|
||||
/*! Mains pickup impairment */
|
||||
int mains_interference;
|
||||
tone_gen_state_t mains_tone;
|
||||
} one_way_line_model_state_t;
|
||||
|
||||
/*!
|
||||
Two way line model descriptor. This holds the complete state of
|
||||
a line model with transmission in both directions.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
one_way_line_model_state_t line1;
|
||||
one_way_line_model_state_t line2;
|
||||
float fout1;
|
||||
float fout2;
|
||||
} both_ways_line_model_state_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void both_ways_line_model(both_ways_line_model_state_t *s,
|
||||
int16_t output1[],
|
||||
const int16_t input1[],
|
||||
int16_t output2[],
|
||||
const int16_t input2[],
|
||||
int samples);
|
||||
|
||||
void both_ways_line_model_set_dc(both_ways_line_model_state_t *s, float dc1, float dc2);
|
||||
|
||||
void both_ways_line_model_set_mains_pickup(both_ways_line_model_state_t *s, int f, float level1, float level2);
|
||||
|
||||
both_ways_line_model_state_t *both_ways_line_model_init(int model1,
|
||||
float noise1,
|
||||
int model2,
|
||||
float noise2,
|
||||
int codec,
|
||||
int rbs_pattern);
|
||||
|
||||
int both_ways_line_model_release(both_ways_line_model_state_t *s);
|
||||
|
||||
void one_way_line_model(one_way_line_model_state_t *s,
|
||||
int16_t output[],
|
||||
const int16_t input[],
|
||||
int samples);
|
||||
|
||||
void one_way_line_model_set_dc(one_way_line_model_state_t *s, float dc);
|
||||
|
||||
void one_way_line_model_set_mains_pickup(one_way_line_model_state_t *s, int f, float level);
|
||||
|
||||
one_way_line_model_state_t *one_way_line_model_init(int model, float noise, int codec, int rbs_pattern);
|
||||
|
||||
int one_way_line_model_release(one_way_line_model_state_t *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* line_model.h - Model a telephone line.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: line_models.h,v 1.3 2008/04/17 18:03:23 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if !defined(_SPANDSP_LINE_MODELS_H_)
|
||||
#define _SPANDSP_LINE_MODELS_H_
|
||||
|
||||
extern float proakis_line_model[];
|
||||
extern float ad_1_edd_1_model[];
|
||||
extern float ad_1_edd_2_model[];
|
||||
extern float ad_1_edd_3_model[];
|
||||
extern float ad_5_edd_1_model[];
|
||||
extern float ad_5_edd_2_model[];
|
||||
extern float ad_5_edd_3_model[];
|
||||
extern float ad_6_edd_1_model[];
|
||||
extern float ad_6_edd_2_model[];
|
||||
extern float ad_6_edd_3_model[];
|
||||
extern float ad_7_edd_1_model[];
|
||||
extern float ad_7_edd_2_model[];
|
||||
extern float ad_7_edd_3_model[];
|
||||
extern float ad_8_edd_1_model[];
|
||||
extern float ad_8_edd_2_model[];
|
||||
extern float ad_8_edd_3_model[];
|
||||
extern float ad_9_edd_1_model[];
|
||||
extern float ad_9_edd_2_model[];
|
||||
extern float ad_9_edd_3_model[];
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* rfc2198_sim.h - Simulate the behaviour of RFC2198 (or UDPTL) redundancy.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: rfc2198_sim.h,v 1.3 2008/04/17 18:03:23 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
/*! \page rfc2198_model_page RFC2198 simulation
|
||||
\section rfc2198_model_page_sec_1 What does it do?
|
||||
*/
|
||||
|
||||
#if !defined(_RFC2198_SIM_H_)
|
||||
#define _RFC2198_SIM_H_
|
||||
|
||||
/*! The definition of an element in the packet queue */
|
||||
typedef struct rfc2198_sim_queue_element_s
|
||||
{
|
||||
struct rfc2198_sim_queue_element_s *next;
|
||||
struct rfc2198_sim_queue_element_s *prev;
|
||||
int seq_no;
|
||||
double departure_time;
|
||||
double arrival_time;
|
||||
int len;
|
||||
uint8_t pkt[0];
|
||||
} rfc2198_sim_queue_element_t;
|
||||
|
||||
/*! The model definition for a complete end-to-end path */
|
||||
typedef struct
|
||||
{
|
||||
int redundancy_depth;
|
||||
int next_seq_no;
|
||||
g1050_state_t *g1050;
|
||||
rfc2198_sim_queue_element_t *first;
|
||||
rfc2198_sim_queue_element_t *last;
|
||||
uint8_t tx_pkt[32][1024];
|
||||
int tx_pkt_len[32];
|
||||
int tx_pkt_seq_no[32];
|
||||
int next_pkt;
|
||||
uint8_t rx_pkt[32][1024];
|
||||
int rx_pkt_len[32];
|
||||
int rx_pkt_seq_no[32];
|
||||
int rx_queued_pkts;
|
||||
} rfc2198_sim_state_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
rfc2198_sim_state_t *rfc2198_sim_init(int model,
|
||||
int speed_pattern,
|
||||
int packet_size,
|
||||
int packet_rate,
|
||||
int redundancy_depth);
|
||||
|
||||
int rfc2198_sim_put(rfc2198_sim_state_t *s,
|
||||
const uint8_t buf[],
|
||||
int len,
|
||||
int seq_no,
|
||||
double departure_time);
|
||||
|
||||
int rfc2198_sim_get(rfc2198_sim_state_t *s,
|
||||
uint8_t buf[],
|
||||
int max_len,
|
||||
double current_time,
|
||||
int *seq_no,
|
||||
double *departure_time,
|
||||
double *arrival_time);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* test_utils.h - Utility routines for module tests.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: test_utils.h,v 1.5 2008/08/29 09:28:13 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if !defined(_TEST_UTILS_H_)
|
||||
#define _TEST_UTILS_H_
|
||||
|
||||
enum
|
||||
{
|
||||
MUNGE_CODEC_NONE = 0,
|
||||
MUNGE_CODEC_ALAW,
|
||||
MUNGE_CODEC_ULAW,
|
||||
MUNGE_CODEC_G726_40K,
|
||||
MUNGE_CODEC_G726_32K,
|
||||
MUNGE_CODEC_G726_24K,
|
||||
MUNGE_CODEC_G726_16K,
|
||||
};
|
||||
|
||||
typedef struct codec_munge_state_s codec_munge_state_t;
|
||||
|
||||
typedef struct complexify_state_s complexify_state_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
complexify_state_t *complexify_init(void);
|
||||
|
||||
void complexify_release(complexify_state_t *s);
|
||||
|
||||
complexf_t complexify(complexify_state_t *s, int16_t amp);
|
||||
|
||||
void fft(complex_t data[], int len);
|
||||
|
||||
void ifft(complex_t data[], int len);
|
||||
|
||||
codec_munge_state_t *codec_munge_init(int codec, int info);
|
||||
|
||||
void codec_munge_release(codec_munge_state_t *s);
|
||||
|
||||
void codec_munge(codec_munge_state_t *s, int16_t amp[], int len);
|
||||
|
||||
AFfilehandle afOpenFile_telephony_read(const char *name, int channels);
|
||||
|
||||
AFfilehandle afOpenFile_telephony_write(const char *name, int channels);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* test_utils.c - Utility routines for module tests.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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: test_utils.c,v 1.8 2008/08/29 09:28:13 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <audiofile.h>
|
||||
|
||||
#include "spandsp.h"
|
||||
#include "spandsp-sim.h"
|
||||
|
||||
#define MAX_FFT_LEN 8192
|
||||
|
||||
struct codec_munge_state_s
|
||||
{
|
||||
int munging_codec;
|
||||
g726_state_t g726_enc_state;
|
||||
g726_state_t g726_dec_state;
|
||||
int rbs_pattern;
|
||||
int sequence;
|
||||
};
|
||||
|
||||
struct complexify_state_s
|
||||
{
|
||||
float history[128];
|
||||
int ptr;
|
||||
};
|
||||
|
||||
static complex_t circle[MAX_FFT_LEN/2];
|
||||
static int circle_init = FALSE;
|
||||
static complex_t icircle[MAX_FFT_LEN/2];
|
||||
static int icircle_init = FALSE;
|
||||
|
||||
complexify_state_t *complexify_init(void)
|
||||
{
|
||||
complexify_state_t *s;
|
||||
int i;
|
||||
|
||||
if ((s = (complexify_state_t *) malloc(sizeof(*s))))
|
||||
{
|
||||
s->ptr = 0;
|
||||
for (i = 0; i < 128; i++)
|
||||
s->history[i] = 0.0f;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void complexify_release(complexify_state_t *s)
|
||||
{
|
||||
free(s);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
complexf_t complexify(complexify_state_t *s, int16_t amp)
|
||||
{
|
||||
#define HILBERT_GAIN 1.569546344
|
||||
static const float hilbert_coeffs[] =
|
||||
{
|
||||
+0.0012698413f, +0.0013489483f,
|
||||
+0.0015105196f, +0.0017620440f,
|
||||
+0.0021112899f, +0.0025663788f,
|
||||
+0.0031358856f, +0.0038289705f,
|
||||
+0.0046555545f, +0.0056265487f,
|
||||
+0.0067541562f, +0.0080522707f,
|
||||
+0.0095370033f, +0.0112273888f,
|
||||
+0.0131463382f, +0.0153219442f,
|
||||
+0.0177892941f, +0.0205930381f,
|
||||
+0.0237910974f, +0.0274601544f,
|
||||
+0.0317040029f, +0.0366666667f,
|
||||
+0.0425537942f, +0.0496691462f,
|
||||
+0.0584802574f, +0.0697446887f,
|
||||
+0.0847739823f, +0.1060495199f,
|
||||
+0.1388940865f, +0.1971551103f,
|
||||
+0.3316207267f, +0.9994281838f,
|
||||
};
|
||||
float famp;
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
complexf_t res;
|
||||
|
||||
s->history[s->ptr] = amp;
|
||||
i = s->ptr - 63;
|
||||
if (i < 0)
|
||||
i += 128;
|
||||
res.re = s->history[i];
|
||||
|
||||
famp = 0.0f;
|
||||
j = s->ptr - 126;
|
||||
if (j < 0)
|
||||
j += 128;
|
||||
for (i = 0, k = s->ptr; i < 32; i++)
|
||||
{
|
||||
famp += (s->history[k] - s->history[j])*hilbert_coeffs[i];
|
||||
j += 2;
|
||||
if (j >= 128)
|
||||
j -= 128;
|
||||
k -= 2;
|
||||
if (k < 0)
|
||||
k += 128;
|
||||
}
|
||||
res.im = famp/HILBERT_GAIN;
|
||||
|
||||
if (++s->ptr >= 128)
|
||||
s->ptr = 0;
|
||||
return res;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static __inline__ complex_t expj(double theta)
|
||||
{
|
||||
return complex_set(cos(theta), sin(theta));
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void fftx(complex_t data[], complex_t temp[], int n)
|
||||
{
|
||||
int i;
|
||||
int h;
|
||||
int p;
|
||||
int t;
|
||||
int i2;
|
||||
complex_t wkt;
|
||||
|
||||
if (n > 1)
|
||||
{
|
||||
h = n/2;
|
||||
for (i = 0; i < h; i++)
|
||||
{
|
||||
i2 = i*2;
|
||||
temp[i] = data[i2]; /* Even */
|
||||
temp[h + i] = data[i2 + 1]; /* Odd */
|
||||
}
|
||||
fftx(&temp[0], &data[0], h);
|
||||
fftx(&temp[h], &data[h], h);
|
||||
p = 0;
|
||||
t = MAX_FFT_LEN/n;
|
||||
for (i = 0; i < h; i++)
|
||||
{
|
||||
wkt = complex_mul(&circle[p], &temp[h + i]);
|
||||
data[i] = complex_add(&temp[i], &wkt);
|
||||
data[h + i] = complex_sub(&temp[i], &wkt);
|
||||
p += t;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void ifftx(complex_t data[], complex_t temp[], int n)
|
||||
{
|
||||
int i;
|
||||
int h;
|
||||
int p;
|
||||
int t;
|
||||
int i2;
|
||||
complex_t wkt;
|
||||
|
||||
if (n > 1)
|
||||
{
|
||||
h = n/2;
|
||||
for (i = 0; i < h; i++)
|
||||
{
|
||||
i2 = i*2;
|
||||
temp[i] = data[i2]; /* Even */
|
||||
temp[h + i] = data[i2 + 1]; /* Odd */
|
||||
}
|
||||
fftx(&temp[0], &data[0], h);
|
||||
fftx(&temp[h], &data[h], h);
|
||||
p = 0;
|
||||
t = MAX_FFT_LEN/n;
|
||||
for (i = 0; i < h; i++)
|
||||
{
|
||||
wkt = complex_mul(île[p], &temp[h + i]);
|
||||
data[i] = complex_add(&temp[i], &wkt);
|
||||
data[h + i] = complex_sub(&temp[i], &wkt);
|
||||
p += t;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void fft(complex_t data[], int len)
|
||||
{
|
||||
int i;
|
||||
double x;
|
||||
complex_t temp[MAX_FFT_LEN];
|
||||
|
||||
/* A very slow and clunky FFT, that's just fine for tests. */
|
||||
if (!circle_init)
|
||||
{
|
||||
for (i = 0; i < MAX_FFT_LEN/2; i++)
|
||||
{
|
||||
x = -(2.0*3.1415926535*i)/(double) MAX_FFT_LEN;
|
||||
circle[i] = expj(x);
|
||||
}
|
||||
circle_init = TRUE;
|
||||
}
|
||||
fftx(data, temp, len);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void ifft(complex_t data[], int len)
|
||||
{
|
||||
int i;
|
||||
double x;
|
||||
complex_t temp[MAX_FFT_LEN];
|
||||
|
||||
/* A very slow and clunky FFT, that's just fine for tests. */
|
||||
if (!icircle_init)
|
||||
{
|
||||
for (i = 0; i < MAX_FFT_LEN/2; i++)
|
||||
{
|
||||
x = (2.0*3.1415926535*i)/(double) MAX_FFT_LEN;
|
||||
icircle[i] = expj(x);
|
||||
}
|
||||
icircle_init = TRUE;
|
||||
}
|
||||
ifftx(data, temp, len);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
codec_munge_state_t *codec_munge_init(int codec, int info)
|
||||
{
|
||||
codec_munge_state_t *s;
|
||||
|
||||
if ((s = (codec_munge_state_t *) malloc(sizeof(*s))))
|
||||
{
|
||||
switch (codec)
|
||||
{
|
||||
case MUNGE_CODEC_G726_40K:
|
||||
g726_init(&s->g726_enc_state, 40000, G726_ENCODING_LINEAR, G726_PACKING_NONE);
|
||||
g726_init(&s->g726_dec_state, 40000, G726_ENCODING_LINEAR, G726_PACKING_NONE);
|
||||
s->munging_codec = MUNGE_CODEC_G726_32K;
|
||||
break;
|
||||
case MUNGE_CODEC_G726_32K:
|
||||
g726_init(&s->g726_enc_state, 32000, G726_ENCODING_LINEAR, G726_PACKING_NONE);
|
||||
g726_init(&s->g726_dec_state, 32000, G726_ENCODING_LINEAR, G726_PACKING_NONE);
|
||||
s->munging_codec = MUNGE_CODEC_G726_32K;
|
||||
break;
|
||||
case MUNGE_CODEC_G726_24K:
|
||||
g726_init(&s->g726_enc_state, 24000, G726_ENCODING_LINEAR, G726_PACKING_NONE);
|
||||
g726_init(&s->g726_dec_state, 24000, G726_ENCODING_LINEAR, G726_PACKING_NONE);
|
||||
s->munging_codec = MUNGE_CODEC_G726_32K;
|
||||
break;
|
||||
case MUNGE_CODEC_G726_16K:
|
||||
g726_init(&s->g726_enc_state, 16000, G726_ENCODING_LINEAR, G726_PACKING_NONE);
|
||||
g726_init(&s->g726_dec_state, 16000, G726_ENCODING_LINEAR, G726_PACKING_NONE);
|
||||
s->munging_codec = MUNGE_CODEC_G726_32K;
|
||||
break;
|
||||
default:
|
||||
s->munging_codec = codec;
|
||||
break;
|
||||
}
|
||||
s->sequence = 0;
|
||||
s->rbs_pattern = info;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void codec_munge_release(codec_munge_state_t *s)
|
||||
{
|
||||
free(s);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void codec_munge(codec_munge_state_t *s, int16_t amp[], int len)
|
||||
{
|
||||
uint8_t law;
|
||||
uint8_t adpcmdata[160];
|
||||
int i;
|
||||
int adpcm;
|
||||
int x;
|
||||
|
||||
switch (s->munging_codec)
|
||||
{
|
||||
case MUNGE_CODEC_NONE:
|
||||
/* Do nothing */
|
||||
break;
|
||||
case MUNGE_CODEC_ALAW:
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
law = linear_to_alaw(amp[i]);
|
||||
amp[i] = alaw_to_linear(law);
|
||||
}
|
||||
break;
|
||||
case MUNGE_CODEC_ULAW:
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
law = linear_to_ulaw(amp[i]);
|
||||
if (s->rbs_pattern & (1 << s->sequence))
|
||||
{
|
||||
/* Strip the bottom bit at the RBS rate */
|
||||
law &= 0xFE;
|
||||
}
|
||||
amp[i] = ulaw_to_linear(law);
|
||||
}
|
||||
break;
|
||||
case MUNGE_CODEC_G726_32K:
|
||||
/* This could actually be any of the G.726 rates */
|
||||
for (i = 0; i < len; i += x)
|
||||
{
|
||||
x = (len - i >= 160) ? 160 : (len - i);
|
||||
adpcm = g726_encode(&s->g726_enc_state, adpcmdata, amp + i, x);
|
||||
g726_decode(&s->g726_dec_state, amp + i, adpcmdata, adpcm);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
AFfilehandle afOpenFile_telephony_read(const char *name, int channels)
|
||||
{
|
||||
float x;
|
||||
AFfilehandle handle;
|
||||
|
||||
if ((handle = afOpenFile(name, "r", 0)) == AF_NULL_FILEHANDLE)
|
||||
{
|
||||
fprintf(stderr, " Cannot open wave file '%s'\n", name);
|
||||
exit(2);
|
||||
}
|
||||
if ((x = afGetFrameSize(handle, AF_DEFAULT_TRACK, 1)) != 2.0)
|
||||
{
|
||||
fprintf(stderr, " Unexpected frame size in wave file '%s'\n", name);
|
||||
exit(2);
|
||||
}
|
||||
if ((x = afGetRate(handle, AF_DEFAULT_TRACK)) != (float) SAMPLE_RATE)
|
||||
{
|
||||
printf(" Unexpected sample rate in wave file '%s'\n", name);
|
||||
exit(2);
|
||||
}
|
||||
if ((x = afGetChannels(handle, AF_DEFAULT_TRACK)) != (float) channels)
|
||||
{
|
||||
printf(" Unexpected number of channels in wave file '%s'\n", name);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
AFfilehandle afOpenFile_telephony_write(const char *name, int channels)
|
||||
{
|
||||
AFfilesetup setup;
|
||||
AFfilehandle handle;
|
||||
|
||||
if ((setup = afNewFileSetup()) == AF_NULL_FILESETUP)
|
||||
{
|
||||
fprintf(stderr, " %s: Failed to create file setup\n", name);
|
||||
exit(2);
|
||||
}
|
||||
afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
|
||||
afInitRate(setup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE);
|
||||
afInitFileFormat(setup, AF_FILE_WAVE);
|
||||
afInitChannels(setup, AF_DEFAULT_TRACK, channels);
|
||||
|
||||
if ((handle = afOpenFile(name, "w", setup)) == AF_NULL_FILEHANDLE)
|
||||
{
|
||||
fprintf(stderr, " Failed to open result file\n");
|
||||
exit(2);
|
||||
}
|
||||
afFreeFileSetup(setup);
|
||||
|
||||
return handle;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,83 @@
|
||||
Summary: A DSP library for telephony.
|
||||
Name: spandsp
|
||||
Version: 0.0.5
|
||||
Release: 1
|
||||
License: GPL
|
||||
Group: System Environment/Libraries
|
||||
URL: http://www.soft-switch.org/spandsp
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-root
|
||||
Source: http://www.soft-switch.org/downloads/spandsp/spandsp-0.0.5.tar.gz
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
|
||||
Docdir: %{_prefix}/doc
|
||||
|
||||
BuildRequires: libtiff-devel
|
||||
BuildRequires: audiofile-devel
|
||||
BuildRequires: doxygen
|
||||
|
||||
%description
|
||||
SpanDSP is a library of DSP functions for telephony, in the 8000
|
||||
sample per second world of E1s, T1s, and higher order PCM channels. It
|
||||
contains low level functions, such as basic filters. It also contains
|
||||
higher level functions, such as cadenced supervisory tone detection,
|
||||
and a complete software FAX machine. The software has been designed to
|
||||
avoid intellectual property issues, using mature techniques where all
|
||||
relevant patents have expired. See the file DueDiligence for important
|
||||
information about these intellectual property issues.
|
||||
|
||||
%package devel
|
||||
Summary: SpanDSP development files
|
||||
Group: Development/Libraries
|
||||
Requires: spandsp = %{version}
|
||||
Requires: libtiff-devel
|
||||
PreReq: /sbin/install-info
|
||||
|
||||
%description devel
|
||||
SpanDSP 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}/libspandsp.la
|
||||
|
||||
%clean
|
||||
rm -rf %{buildroot}
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%doc DueDiligence ChangeLog AUTHORS COPYING NEWS README
|
||||
|
||||
%{_libdir}/libspandsp.so.*
|
||||
|
||||
%{_datadir}/spandsp
|
||||
|
||||
%files devel
|
||||
%defattr(-,root,root,-)
|
||||
%doc doc/api
|
||||
%{_includedir}/spandsp.h
|
||||
%{_includedir}/spandsp
|
||||
%{_libdir}/libspandsp.so
|
||||
|
||||
%post -p /sbin/ldconfig
|
||||
|
||||
%postun -p /sbin/ldconfig
|
||||
|
||||
%changelog
|
||||
* Mon 23 Jun 2008 Steve Underwood <steveu@coppice.org> 0.0.5-1
|
||||
- Cleared out the dependency on libxml2
|
||||
|
||||
* Sun Dec 31 2006 Steve Underwood <steveu@coppice.org> 0.0.3-1
|
||||
- Preparing for 0.0.3 release
|
||||
|
||||
* Sat Oct 16 2004 Steve Underwood <steveu@coppice.org> 0.0.2-1
|
||||
- Preparing for 0.0.2 release
|
||||
|
||||
* Thu Apr 15 2004 Steve Underwood <steveu@coppice.org> 0.0.1-1
|
||||
- Initial version
|
||||
@@ -0,0 +1,83 @@
|
||||
Summary: A DSP library for telephony.
|
||||
Name: @PACKAGE@
|
||||
Version: @VERSION@
|
||||
Release: 1
|
||||
License: GPL
|
||||
Group: System Environment/Libraries
|
||||
URL: http://www.soft-switch.org/spandsp
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-root
|
||||
Source: http://www.soft-switch.org/downloads/spandsp/@PACKAGE@-@VERSION@.tar.gz
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
|
||||
Docdir: %{_prefix}/doc
|
||||
|
||||
BuildRequires: libtiff-devel
|
||||
BuildRequires: audiofile-devel
|
||||
BuildRequires: doxygen
|
||||
|
||||
%description
|
||||
SpanDSP is a library of DSP functions for telephony, in the 8000
|
||||
sample per second world of E1s, T1s, and higher order PCM channels. It
|
||||
contains low level functions, such as basic filters. It also contains
|
||||
higher level functions, such as cadenced supervisory tone detection,
|
||||
and a complete software FAX machine. The software has been designed to
|
||||
avoid intellectual property issues, using mature techniques where all
|
||||
relevant patents have expired. See the file DueDiligence for important
|
||||
information about these intellectual property issues.
|
||||
|
||||
%package devel
|
||||
Summary: SpanDSP development files
|
||||
Group: Development/Libraries
|
||||
Requires: spandsp = %{version}
|
||||
Requires: libtiff-devel
|
||||
PreReq: /sbin/install-info
|
||||
|
||||
%description devel
|
||||
SpanDSP 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}/libspandsp.la
|
||||
|
||||
%clean
|
||||
rm -rf %{buildroot}
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%doc DueDiligence ChangeLog AUTHORS COPYING NEWS README
|
||||
|
||||
%{_libdir}/libspandsp.so.*
|
||||
|
||||
%{_datadir}/spandsp
|
||||
|
||||
%files devel
|
||||
%defattr(-,root,root,-)
|
||||
%doc doc/api
|
||||
%{_includedir}/spandsp.h
|
||||
%{_includedir}/spandsp
|
||||
%{_libdir}/libspandsp.so
|
||||
|
||||
%post -p /sbin/ldconfig
|
||||
|
||||
%postun -p /sbin/ldconfig
|
||||
|
||||
%changelog
|
||||
* Mon 23 Jun 2008 Steve Underwood <steveu@coppice.org> 0.0.5-1
|
||||
- Cleared out the dependency on libxml2
|
||||
|
||||
* Sun Dec 31 2006 Steve Underwood <steveu@coppice.org> 0.0.3-1
|
||||
- Preparing for 0.0.3 release
|
||||
|
||||
* Sat Oct 16 2004 Steve Underwood <steveu@coppice.org> 0.0.2-1
|
||||
- Preparing for 0.0.2 release
|
||||
|
||||
* Thu Apr 15 2004 Steve Underwood <steveu@coppice.org> 0.0.1-1
|
||||
- Initial version
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,193 @@
|
||||
<!-- Global PSTN supervisory tones -->
|
||||
<!ELEMENT global-tones (tone-set)* >
|
||||
<!ELEMENT tone-set (dial-tone|ringback-tone|busy-tone|congestion-tone|number-unobtainable-tone|special-information-tone|call-waiting-tone|waiting-tone|payphone-recognition-tone|test-number-tone|end-of-three-party-service-tone|service-activated-tone|record-tone|facilities-tone|offering-tone|positive-indication-tone|negative-indication-tone|route-tone|pay-tone|confirmation-tone|intrusion-tone|intercept-tone|warning-tone|holding-tone|search-tone|acceptance-tone|executive-override-tone|function-acknowledge-tone|queue-tone|valid-tone-radio-paging|notify-tone|re-order-tone|preemption-tone|comfort-tone|connection-tone|refusal-tone|line-lockout-tone|permanent-signal-tone|identification-tone|reorder-tone|recall-dial-tone|special-ringback-tone|busy-verification-tone)* >
|
||||
|
||||
<!ATTLIST tone-set
|
||||
country CDATA #REQUIRED
|
||||
uncode CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT dial-tone (step)* >
|
||||
<!ATTLIST dial-tone
|
||||
domain CDATA #IMPLIED
|
||||
type CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT ringback-tone (step)* >
|
||||
<!ATTLIST ringback-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT busy-tone (step)* >
|
||||
<!ATTLIST busy-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT congestion-tone (step)* >
|
||||
<!ATTLIST congestion-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT number-unobtainable-tone (step)* >
|
||||
<!ATTLIST number-unobtainable-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT special-information-tone (step)* >
|
||||
<!ATTLIST special-information-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT call-waiting-tone (step)* >
|
||||
<!ATTLIST call-waiting-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT pay-tone (step)* >
|
||||
<!ATTLIST pay-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT payphone-recognition-tone (step)* >
|
||||
<!ATTLIST payphone-recognition-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT warning-tone (step)* >
|
||||
<!ATTLIST warning-tone
|
||||
type CDATA #IMPLIED
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT reorder-tone (step)* >
|
||||
<!ATTLIST reorder-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT recall-dial-tone (step)* >
|
||||
<!ATTLIST recall-dial-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT special-ringback-tone (step)* >
|
||||
<!ATTLIST special-ringback-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT busy-verification-tone (step)* >
|
||||
<!ATTLIST busy-verification-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT waiting-tone (step)* >
|
||||
<!ATTLIST waiting-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT test-number-tone (step)* >
|
||||
<!ATTLIST test-number-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT end-of-three-party-service-tone (step)* >
|
||||
<!ATTLIST end-of-three-party-service-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT service-activated-tone (step)* >
|
||||
<!ATTLIST service-activated-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT record-tone (step)* >
|
||||
<!ATTLIST record-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT facilities-tone (step)* >
|
||||
<!ATTLIST facilities-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT offering-tone (step)* >
|
||||
<!ATTLIST offering-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT positive-indication-tone (step)* >
|
||||
<!ATTLIST positive-indication-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT negative-indication-tone (step)* >
|
||||
<!ATTLIST negative-indication-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT route-tone (step)* >
|
||||
<!ATTLIST route-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT confirmation-tone (step)* >
|
||||
<!ATTLIST confirmation-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT intrusion-tone (step)* >
|
||||
<!ATTLIST intrusion-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT intercept-tone (step)* >
|
||||
<!ATTLIST intercept-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT holding-tone (step)* >
|
||||
<!ATTLIST holding-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT search-tone (step)* >
|
||||
<!ATTLIST search-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT acceptance-tone (step)* >
|
||||
<!ATTLIST acceptance-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT executive-override-tone (step)* >
|
||||
<!ATTLIST executive-override-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT function-acknowledge-tone (step)* >
|
||||
<!ATTLIST function-acknowledge-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT queue-tone (step)* >
|
||||
<!ATTLIST queue-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT valid-tone-radio-paging (step)* >
|
||||
<!ATTLIST valid-tone-radio-paging
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT notify-tone (step)* >
|
||||
<!ATTLIST notify-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT re-order-tone (step)* >
|
||||
<!ATTLIST re-order-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT preemption-tone (step)* >
|
||||
<!ATTLIST preemption-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT comfort-tone (step)* >
|
||||
<!ATTLIST comfort-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT connection-tone (step)* >
|
||||
<!ATTLIST connection-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT refusal-tone (step)* >
|
||||
<!ATTLIST refusal-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT line-lockout-tone (step)* >
|
||||
<!ATTLIST line-lockout-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT permanent-signal-tone (step)* >
|
||||
<!ATTLIST permanent-signal-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT identification-tone (step)* >
|
||||
<!ATTLIST identification-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT step (step|EMPTY)* >
|
||||
<!ATTLIST step
|
||||
cycles CDATA #IMPLIED
|
||||
freq CDATA #IMPLIED
|
||||
level CDATA #IMPLIED
|
||||
length CDATA #IMPLIED
|
||||
recorded-announcement CDATA #IMPLIED
|
||||
>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,379 @@
|
||||
##
|
||||
## 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 Lesser 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 Lesser General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU Lesser 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.100 2008/08/14 14:06:05 steveu Exp $
|
||||
|
||||
AM_CFLAGS = $(COMP_VENDOR_CFLAGS)
|
||||
AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS)
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
INCLUDES = -I$(top_builddir)
|
||||
|
||||
lib_LTLIBRARIES = libspandsp.la
|
||||
|
||||
libspandsp_la_SOURCES = adsi.c \
|
||||
async.c \
|
||||
at_interpreter.c \
|
||||
awgn.c \
|
||||
bell_r2_mf.c \
|
||||
bert.c \
|
||||
bit_operations.c \
|
||||
bitstream.c \
|
||||
complex_filters.c \
|
||||
complex_vector_float.c \
|
||||
crc.c \
|
||||
dds_float.c \
|
||||
dds_int.c \
|
||||
dtmf.c \
|
||||
echo.c \
|
||||
fax.c \
|
||||
fsk.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 \
|
||||
hdlc.c \
|
||||
ima_adpcm.c \
|
||||
logging.c \
|
||||
lpc10_analyse.c \
|
||||
lpc10_decode.c \
|
||||
lpc10_encode.c \
|
||||
lpc10_placev.c \
|
||||
lpc10_voicing.c \
|
||||
modem_echo.c \
|
||||
modem_connect_tones.c \
|
||||
noise.c \
|
||||
oki_adpcm.c \
|
||||
playout.c \
|
||||
plc.c \
|
||||
power_meter.c \
|
||||
queue.c \
|
||||
schedule.c \
|
||||
sig_tone.c \
|
||||
silence_gen.c \
|
||||
super_tone_rx.c \
|
||||
super_tone_tx.c \
|
||||
t4.c \
|
||||
t30.c \
|
||||
t30_api.c \
|
||||
t30_logging.c \
|
||||
t31.c \
|
||||
t35.c \
|
||||
t38_core.c \
|
||||
t38_gateway.c \
|
||||
t38_non_ecm_buffer.c \
|
||||
t38_terminal.c \
|
||||
testcpuid.c \
|
||||
time_scale.c \
|
||||
tone_detect.c \
|
||||
tone_generate.c \
|
||||
v17rx.c \
|
||||
v17tx.c \
|
||||
v22bis_rx.c \
|
||||
v22bis_tx.c \
|
||||
v27ter_rx.c \
|
||||
v27ter_tx.c \
|
||||
v29rx.c \
|
||||
v29tx.c \
|
||||
v42.c \
|
||||
v42bis.c \
|
||||
v8.c \
|
||||
vector_float.c \
|
||||
vector_int.c
|
||||
|
||||
libspandsp_la_LDFLAGS = -version-info @SPANDSP_LT_CURRENT@:@SPANDSP_LT_REVISION@:@SPANDSP_LT_AGE@
|
||||
|
||||
nobase_include_HEADERS = spandsp/adsi.h \
|
||||
spandsp/async.h \
|
||||
spandsp/arctan2.h \
|
||||
spandsp/at_interpreter.h \
|
||||
spandsp/awgn.h \
|
||||
spandsp/bell_r2_mf.h \
|
||||
spandsp/bert.h \
|
||||
spandsp/biquad.h \
|
||||
spandsp/bit_operations.h \
|
||||
spandsp/bitstream.h \
|
||||
spandsp/crc.h \
|
||||
spandsp/complex.h \
|
||||
spandsp/complex_filters.h \
|
||||
spandsp/complex_vector_float.h \
|
||||
spandsp/dc_restore.h \
|
||||
spandsp/dds.h \
|
||||
spandsp/dtmf.h \
|
||||
spandsp/echo.h \
|
||||
spandsp/fax.h \
|
||||
spandsp/fax_modems.h \
|
||||
spandsp/fir.h \
|
||||
spandsp/fsk.h \
|
||||
spandsp/g168models.h \
|
||||
spandsp/g711.h \
|
||||
spandsp/g722.h \
|
||||
spandsp/g726.h \
|
||||
spandsp/gsm0610.h \
|
||||
spandsp/hdlc.h \
|
||||
spandsp/ima_adpcm.h \
|
||||
spandsp/logging.h \
|
||||
spandsp/lpc10.h \
|
||||
spandsp/modem_echo.h \
|
||||
spandsp/modem_connect_tones.h \
|
||||
spandsp/noise.h \
|
||||
spandsp/oki_adpcm.h \
|
||||
spandsp/playout.h \
|
||||
spandsp/plc.h \
|
||||
spandsp/power_meter.h \
|
||||
spandsp/queue.h \
|
||||
spandsp/schedule.h \
|
||||
spandsp/sig_tone.h \
|
||||
spandsp/silence_gen.h \
|
||||
spandsp/super_tone_rx.h \
|
||||
spandsp/super_tone_tx.h \
|
||||
spandsp/t4.h \
|
||||
spandsp/t30.h \
|
||||
spandsp/t30_api.h \
|
||||
spandsp/t30_fcf.h \
|
||||
spandsp/t30_logging.h \
|
||||
spandsp/t31.h \
|
||||
spandsp/t35.h \
|
||||
spandsp/t38_core.h \
|
||||
spandsp/t38_gateway.h \
|
||||
spandsp/t38_non_ecm_buffer.h \
|
||||
spandsp/t38_terminal.h \
|
||||
spandsp/telephony.h \
|
||||
spandsp/time_scale.h \
|
||||
spandsp/timing.h \
|
||||
spandsp/tone_detect.h \
|
||||
spandsp/tone_generate.h \
|
||||
spandsp/v17rx.h \
|
||||
spandsp/v17tx.h \
|
||||
spandsp/v22bis.h \
|
||||
spandsp/v27ter_rx.h \
|
||||
spandsp/v27ter_tx.h \
|
||||
spandsp/v29rx.h \
|
||||
spandsp/v29tx.h \
|
||||
spandsp/v42.h \
|
||||
spandsp/v42bis.h \
|
||||
spandsp/v8.h \
|
||||
spandsp/vector_float.h \
|
||||
spandsp/vector_int.h \
|
||||
spandsp/version.h
|
||||
|
||||
nodist_include_HEADERS = spandsp.h
|
||||
|
||||
noinst_HEADERS = faxfont.h \
|
||||
filter_tools.h \
|
||||
gsm0610_local.h \
|
||||
lpc10_encdecs.h \
|
||||
t30_local.h \
|
||||
t4_states.h \
|
||||
v17rx_constellation_maps.h \
|
||||
v17tx_constellation_maps.h \
|
||||
v29tx_constellation_maps.h
|
||||
|
||||
noinst_PROGRAMS = make_at_dictionary \
|
||||
make_modem_filter
|
||||
|
||||
make_modem_filter_SOURCES = make_modem_filter.c \
|
||||
filter_tools.c
|
||||
|
||||
# We need to run make_at_dictionary, so it generates the
|
||||
# at_interpreter_dictionary.h file
|
||||
|
||||
at_interpreter.$(OBJEXT): at_interpreter_dictionary.h
|
||||
|
||||
at_interpreter.lo: at_interpreter_dictionary.h
|
||||
|
||||
at_interpreter_dictionary.h: make_at_dictionary$(EXEEXT)
|
||||
./make_at_dictionary$(EXEEXT) >at_interpreter_dictionary.h
|
||||
|
||||
v17rx.$(OBJEXT): v17rx_fixed_rrc.h v17rx_floating_rrc.h
|
||||
|
||||
v17rx.lo: v17rx_fixed_rrc.h v17rx_floating_rrc.h
|
||||
|
||||
v17rx_fixed_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.17 -i -r >v17rx_fixed_rrc.h
|
||||
|
||||
v17rx_floating_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.17 -r >v17rx_floating_rrc.h
|
||||
|
||||
v17tx.$(OBJEXT): v17tx_fixed_rrc.h v17tx_floating_rrc.h
|
||||
|
||||
v17tx.lo: v17tx_fixed_rrc.h v17tx_floating_rrc.h
|
||||
|
||||
v17tx_fixed_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.17 -i -t >v17tx_fixed_rrc.h
|
||||
|
||||
v17tx_floating_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.17 -t >v17tx_floating_rrc.h
|
||||
|
||||
v22bis_rx.$(OBJEXT): v22bis_rx_1200_fixed_rrc.h \
|
||||
v22bis_rx_2400_fixed_rrc.h \
|
||||
v22bis_rx_1200_floating_rrc.h \
|
||||
v22bis_rx_2400_floating_rrc.h
|
||||
|
||||
v22bis_rx.lo: v22bis_rx_1200_fixed_rrc.h \
|
||||
v22bis_rx_2400_fixed_rrc.h \
|
||||
v22bis_rx_1200_floating_rrc.h \
|
||||
v22bis_rx_2400_floating_rrc.h
|
||||
|
||||
v22bis_rx_1200_fixed_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.22bis1200 -i -r >v22bis_rx_1200_fixed_rrc.h
|
||||
|
||||
v22bis_rx_2400_fixed_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.22bis2400 -i -r >v22bis_rx_2400_fixed_rrc.h
|
||||
|
||||
v22bis_rx_1200_floating_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.22bis1200 -r >v22bis_rx_1200_floating_rrc.h
|
||||
|
||||
v22bis_rx_2400_floating_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.22bis2400 -r >v22bis_rx_2400_floating_rrc.h
|
||||
|
||||
v22bis_tx.$(OBJEXT): v22bis_tx_fixed_rrc.h v22bis_tx_floating_rrc.h
|
||||
|
||||
v22bis_tx.lo: v22bis_tx_fixed_rrc.h v22bis_tx_floating_rrc.h
|
||||
|
||||
v22bis_tx_fixed_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.22bis -i -t >v22bis_tx_fixed_rrc.h
|
||||
|
||||
v22bis_tx_floating_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.22bis -t >v22bis_tx_floating_rrc.h
|
||||
|
||||
v27ter_rx_.$(OBJEXT): v27ter_rx_2400_fixed_rrc.h \
|
||||
v27ter_rx_4800_fixed_rrc.h \
|
||||
v27ter_rx_2400_floating_rrc.h \
|
||||
v27ter_rx_4800_floating_rrc.h
|
||||
|
||||
v27ter_rx.lo: v27ter_rx_2400_fixed_rrc.h \
|
||||
v27ter_rx_4800_fixed_rrc.h \
|
||||
v27ter_rx_2400_floating_rrc.h \
|
||||
v27ter_rx_4800_floating_rrc.h
|
||||
|
||||
v27ter_rx_2400_fixed_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.27ter2400 -i -r >v27ter_rx_2400_fixed_rrc.h
|
||||
|
||||
v27ter_rx_4800_fixed_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.27ter4800 -i -r >v27ter_rx_4800_fixed_rrc.h
|
||||
|
||||
v27ter_rx_2400_floating_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.27ter2400 -r >v27ter_rx_2400_floating_rrc.h
|
||||
|
||||
v27ter_rx_4800_floating_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.27ter4800 -r >v27ter_rx_4800_floating_rrc.h
|
||||
|
||||
v27ter_tx_.$(OBJEXT): v27ter_tx_2400_fixed_rrc.h \
|
||||
v27ter_tx_4800_fixed_rrc.h \
|
||||
v27ter_tx_2400_floating_rrc.h \
|
||||
v27ter_tx_4800_floating_rrc.h
|
||||
|
||||
v27ter_tx.lo: v27ter_tx_2400_fixed_rrc.h \
|
||||
v27ter_tx_4800_fixed_rrc.h \
|
||||
v27ter_tx_2400_floating_rrc.h \
|
||||
v27ter_tx_4800_floating_rrc.h
|
||||
|
||||
v27ter_tx_2400_fixed_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.27ter2400 -i -t >v27ter_tx_2400_fixed_rrc.h
|
||||
|
||||
v27ter_tx_4800_fixed_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.27ter4800 -i -t >v27ter_tx_4800_fixed_rrc.h
|
||||
|
||||
v27ter_tx_2400_floating_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.27ter2400 -t >v27ter_tx_2400_floating_rrc.h
|
||||
|
||||
v27ter_tx_4800_floating_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.27ter4800 -t >v27ter_tx_4800_floating_rrc.h
|
||||
|
||||
v29rx.$(OBJEXT): v29rx_fixed_rrc.h v29rx_floating_rrc.h
|
||||
|
||||
v29rx.lo: v29rx_fixed_rrc.h v29rx_floating_rrc.h
|
||||
|
||||
v29rx_fixed_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.29 -i -r >v29rx_fixed_rrc.h
|
||||
|
||||
v29rx_floating_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.29 -r >v29rx_floating_rrc.h
|
||||
|
||||
v29tx.$(OBJEXT): v29tx_fixed_rrc.h v29tx_floating_rrc.h
|
||||
|
||||
v29tx.lo: v29tx_fixed_rrc.h v29tx_floating_rrc.h
|
||||
|
||||
v29tx_fixed_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.29 -i -t >v29tx_fixed_rrc.h
|
||||
|
||||
v29tx_floating_rrc.h: make_modem_filter$(EXEEXT)
|
||||
./make_modem_filter$(EXEEXT) -m V.29 -t >v29tx_floating_rrc.h
|
||||
|
||||
DSP = libspandsp.dsp
|
||||
VCPROJ = libspandsp.vcproj
|
||||
|
||||
WIN32SOURCES = $(libspandsp_la_SOURCES) msvc/gettimeofday.c
|
||||
WIN32HEADERS = $(nobase_include_HEADERS) spandsp.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 "<File RelativePath=\""$$file"\"></File>" $(VCPROJOUT); \
|
||||
done; \
|
||||
echo "</Filter><Filter Name=\"Header Files\">" $(VCPROJOUT); \
|
||||
for file in $(WIN32HEADERS); do \
|
||||
echo "<File RelativePath=\""$$file"\"></File>" $(VCPROJOUT); \
|
||||
done; \
|
||||
cat $(srcdir)/msvc/vc8proj.foot $(VCPROJOUT) )
|
||||
|
||||
spandsp/version.h:
|
||||
NOWDATE=`date --utc +"%Y%m%d"` ; \
|
||||
NOWTIME=`date --utc +"%H%M%S"` ; \
|
||||
sed 's/$$SPANDSP_RELEASE_DATE/'$$NOWDATE'/;s/$$SPANDSP_RELEASE_TIME/'$$NOWTIME'/' \
|
||||
<spandsp/version.h.in >spandsp/version.h
|
||||
|
||||
dist-hook:
|
||||
NOWDATE=`date --utc +"%Y%m%d"` ; \
|
||||
NOWTIME=`date --utc +"%H%M%S"` ; \
|
||||
sed 's/$$SPANDSP_RELEASE_DATE/'$$NOWDATE'/;s/$$SPANDSP_RELEASE_TIME/'$$NOWTIME'/' \
|
||||
<spandsp/version.h.in >spandsp/version.h
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* async.c - Asynchronous serial bit stream encoding and decoding
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 GNU Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: async.c,v 1.11 2008/05/13 13:17:21 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/async.h"
|
||||
|
||||
async_rx_state_t *async_rx_init(async_rx_state_t *s,
|
||||
int data_bits,
|
||||
int parity,
|
||||
int stop_bits,
|
||||
int use_v14,
|
||||
put_byte_func_t put_byte,
|
||||
void *user_data)
|
||||
{
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (async_rx_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
s->data_bits = data_bits;
|
||||
s->parity = parity;
|
||||
s->stop_bits = stop_bits;
|
||||
s->use_v14 = use_v14;
|
||||
|
||||
s->put_byte = put_byte;
|
||||
s->user_data = user_data;
|
||||
|
||||
s->byte_in_progress = 0;
|
||||
s->bitpos = 0;
|
||||
s->parity_bit = 0;
|
||||
|
||||
s->parity_errors = 0;
|
||||
s->framing_errors = 0;
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void async_rx_put_bit(void *user_data, int bit)
|
||||
{
|
||||
async_rx_state_t *s;
|
||||
|
||||
s = (async_rx_state_t *) user_data;
|
||||
if (bit < 0)
|
||||
{
|
||||
/* Special conditions */
|
||||
switch (bit)
|
||||
{
|
||||
case PUTBIT_CARRIER_UP:
|
||||
case PUTBIT_CARRIER_DOWN:
|
||||
case PUTBIT_TRAINING_IN_PROGRESS:
|
||||
case PUTBIT_TRAINING_SUCCEEDED:
|
||||
case PUTBIT_TRAINING_FAILED:
|
||||
case PUTBIT_END_OF_DATA:
|
||||
s->put_byte(s->user_data, bit);
|
||||
s->bitpos = 0;
|
||||
s->byte_in_progress = 0;
|
||||
break;
|
||||
default:
|
||||
//printf("Eh!\n");
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (s->bitpos == 0)
|
||||
{
|
||||
/* Search for the start bit */
|
||||
s->bitpos += (bit ^ 1);
|
||||
s->parity_bit = 0;
|
||||
s->byte_in_progress = 0;
|
||||
}
|
||||
else if (s->bitpos <= s->data_bits)
|
||||
{
|
||||
s->byte_in_progress = (s->byte_in_progress >> 1) | (bit << 7);
|
||||
s->parity_bit ^= bit;
|
||||
s->bitpos++;
|
||||
}
|
||||
else if (s->parity && s->bitpos == s->data_bits + 1)
|
||||
{
|
||||
if (s->parity == ASYNC_PARITY_ODD)
|
||||
s->parity_bit ^= 1;
|
||||
|
||||
if (s->parity_bit != bit)
|
||||
s->parity_errors++;
|
||||
s->bitpos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Stop bit */
|
||||
if (bit == 1)
|
||||
{
|
||||
/* Align the received value */
|
||||
if (s->data_bits < 8)
|
||||
s->byte_in_progress >>= (8 - s->data_bits);
|
||||
s->put_byte(s->user_data, s->byte_in_progress);
|
||||
s->bitpos = 0;
|
||||
}
|
||||
else if (s->use_v14)
|
||||
{
|
||||
/* This is actually the start bit for the next character, and
|
||||
the stop bit has been dropped from the stream. This is the
|
||||
rate adaption specified in V.14 */
|
||||
/* Align the received value */
|
||||
if (s->data_bits < 8)
|
||||
s->byte_in_progress >>= (8 - s->data_bits);
|
||||
s->put_byte(s->user_data, s->byte_in_progress);
|
||||
s->bitpos = 1;
|
||||
s->parity_bit = 0;
|
||||
s->byte_in_progress = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
s->framing_errors++;
|
||||
s->bitpos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
async_tx_state_t *async_tx_init(async_tx_state_t *s,
|
||||
int data_bits,
|
||||
int parity,
|
||||
int stop_bits,
|
||||
int use_v14,
|
||||
get_byte_func_t get_byte,
|
||||
void *user_data)
|
||||
{
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (async_tx_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
/* We have a use_v14 parameter for completeness, but right now V.14 only
|
||||
applies to the receive side. We are unlikely to have an application where
|
||||
flow control does not exist, so V.14 stuffing is not needed. */
|
||||
s->data_bits = data_bits;
|
||||
s->parity = parity;
|
||||
s->stop_bits = stop_bits;
|
||||
if (parity != ASYNC_PARITY_NONE)
|
||||
s->stop_bits++;
|
||||
|
||||
s->get_byte = get_byte;
|
||||
s->user_data = user_data;
|
||||
|
||||
s->byte_in_progress = 0;
|
||||
s->bitpos = 0;
|
||||
s->parity_bit = 0;
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int async_tx_get_bit(void *user_data)
|
||||
{
|
||||
async_tx_state_t *s;
|
||||
int bit;
|
||||
|
||||
s = (async_tx_state_t *) user_data;
|
||||
if (s->bitpos == 0)
|
||||
{
|
||||
if ((s->byte_in_progress = s->get_byte(s->user_data)) < 0)
|
||||
{
|
||||
/* No more data */
|
||||
bit = PUTBIT_END_OF_DATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Start bit */
|
||||
bit = 0;
|
||||
s->parity_bit = 0;
|
||||
s->bitpos++;
|
||||
}
|
||||
}
|
||||
else if (s->bitpos <= s->data_bits)
|
||||
{
|
||||
bit = s->byte_in_progress & 1;
|
||||
s->byte_in_progress >>= 1;
|
||||
s->parity_bit ^= bit;
|
||||
s->bitpos++;
|
||||
}
|
||||
else if (s->parity && s->bitpos == s->data_bits + 1)
|
||||
{
|
||||
if (s->parity == ASYNC_PARITY_ODD)
|
||||
s->parity_bit ^= 1;
|
||||
bit = s->parity_bit;
|
||||
s->bitpos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Stop bit(s) */
|
||||
bit = 1;
|
||||
if (++s->bitpos > s->data_bits + s->stop_bits)
|
||||
s->bitpos = 0;
|
||||
}
|
||||
return bit;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* awgn.c - An additive Gaussian white noise generator
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 GNU Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: awgn.c,v 1.16 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
/* This code is based on some demonstration code in a research
|
||||
paper somewhere. I can't track down where I got the original from,
|
||||
so that due recognition can be given. The original had no explicit
|
||||
copyright notice, and I hope nobody objects to its use here.
|
||||
|
||||
Having a reasonable Gaussian noise generator is pretty important for
|
||||
telephony testing (in fact, pretty much any DSP testing), and this
|
||||
one seems to have served me OK. Since the generation of Gaussian
|
||||
noise is only for test purposes, and not a core system component,
|
||||
I don't intend to worry excessively about copyright issues, unless
|
||||
someone worries me.
|
||||
|
||||
The non-core nature of this code also explains why it is unlikely
|
||||
to ever be optimised. */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/awgn.h"
|
||||
|
||||
/* Gaussian noise generator constants */
|
||||
#define M1 259200
|
||||
#define IA1 7141
|
||||
#define IC1 54773
|
||||
#define RM1 (1.0/M1)
|
||||
#define M2 134456
|
||||
#define IA2 8121
|
||||
#define IC2 28411
|
||||
#define RM2 (1.0/M2)
|
||||
#define M3 243000
|
||||
#define IA3 4561
|
||||
#define IC3 51349
|
||||
|
||||
static double ran1(awgn_state_t *s)
|
||||
{
|
||||
double temp;
|
||||
int j;
|
||||
|
||||
s->ix1 = (IA1*s->ix1 + IC1)%M1;
|
||||
s->ix2 = (IA2*s->ix2 + IC2)%M2;
|
||||
s->ix3 = (IA3*s->ix3 + IC3)%M3;
|
||||
j = 1 + ((97*s->ix3)/M3);
|
||||
if (j > 97 || j < 1)
|
||||
{
|
||||
/* Error */
|
||||
return -1;
|
||||
}
|
||||
temp = s->r[j];
|
||||
s->r[j] = (s->ix1 + s->ix2*RM2)*RM1;
|
||||
return temp;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
awgn_state_t *awgn_init_dbm0(awgn_state_t *s, int idum, float level)
|
||||
{
|
||||
return awgn_init_dbov(s, idum, level - DBM0_MAX_POWER);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
awgn_state_t *awgn_init_dbov(awgn_state_t *s, int idum, float level)
|
||||
{
|
||||
int j;
|
||||
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (awgn_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
if (idum < 0)
|
||||
idum = -idum;
|
||||
|
||||
s->rms = pow(10.0, level/20.0)*32768.0;
|
||||
|
||||
s->ix1 = (IC1 + idum)%M1;
|
||||
s->ix1 = (IA1*s->ix1 + IC1)%M1;
|
||||
s->ix2 = s->ix1%M2;
|
||||
s->ix1 = (IA1*s->ix1 + IC1)%M1;
|
||||
s->ix3 = s->ix1%M3;
|
||||
s->r[0] = 0.0;
|
||||
for (j = 1; j <= 97; j++)
|
||||
{
|
||||
s->ix1 = (IA1*s->ix1 + IC1)%M1;
|
||||
s->ix2 = (IA2*s->ix2 + IC2)%M2;
|
||||
s->r[j] = (s->ix1 + s->ix2*RM2)*RM1;
|
||||
}
|
||||
s->gset = 0.0;
|
||||
s->iset = 0;
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int16_t awgn(awgn_state_t *s)
|
||||
{
|
||||
double fac;
|
||||
double r;
|
||||
double v1;
|
||||
double v2;
|
||||
double amp;
|
||||
|
||||
if (s->iset == 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
v1 = 2.0*ran1(s) - 1.0;
|
||||
v2 = 2.0*ran1(s) - 1.0;
|
||||
r = v1*v1 + v2*v2;
|
||||
}
|
||||
while (r >= 1.0);
|
||||
fac = sqrt(-2.0*log(r)/r);
|
||||
s->gset = v1*fac;
|
||||
s->iset = 1;
|
||||
amp = v2*fac*s->rms;
|
||||
}
|
||||
else
|
||||
{
|
||||
s->iset = 0;
|
||||
amp = s->gset*s->rms;
|
||||
}
|
||||
return fsaturate(amp);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,833 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* bell_r2_mf.c - Bell MF and MFC/R2 tone generation and detection.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 GNU Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: bell_r2_mf.c,v 1.29 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/queue.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/complex.h"
|
||||
#include "spandsp/dds.h"
|
||||
#include "spandsp/tone_detect.h"
|
||||
#include "spandsp/tone_generate.h"
|
||||
#include "spandsp/super_tone_rx.h"
|
||||
#include "spandsp/dtmf.h"
|
||||
#include "spandsp/bell_r2_mf.h"
|
||||
|
||||
#if !defined(M_PI)
|
||||
/* C99 systems may not define M_PI */
|
||||
#define M_PI 3.14159265358979323846264338327
|
||||
#endif
|
||||
|
||||
#define ms_to_samples(t) (((t)*SAMPLE_RATE)/1000)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int f1; /* First freq */
|
||||
int f2; /* Second freq */
|
||||
int8_t level1; /* Level of the first freq (dB) */
|
||||
int8_t level2; /* Level of the second freq (dB) */
|
||||
uint8_t on_time; /* Tone on time (ms) */
|
||||
uint8_t off_time; /* Minimum post tone silence (ms) */
|
||||
} mf_digit_tones_t;
|
||||
|
||||
int bell_mf_gen_inited = FALSE;
|
||||
tone_gen_descriptor_t bell_mf_digit_tones[15];
|
||||
|
||||
int r2_mf_gen_inited = FALSE;
|
||||
tone_gen_descriptor_t r2_mf_fwd_digit_tones[15];
|
||||
tone_gen_descriptor_t r2_mf_back_digit_tones[15];
|
||||
|
||||
#if 0
|
||||
tone_gen_descriptor_t socotel_mf_digit_tones[18];
|
||||
#endif
|
||||
|
||||
/* Bell R1 tone generation specs.
|
||||
* Power: -7dBm +- 1dB
|
||||
* Frequency: within +-1.5%
|
||||
* Mismatch between the start time of a pair of tones: <=6ms.
|
||||
* Mismatch between the end time of a pair of tones: <=6ms.
|
||||
* Tone duration: 68+-7ms, except KP which is 100+-7ms.
|
||||
* Inter-tone gap: 68+-7ms.
|
||||
*/
|
||||
static const mf_digit_tones_t bell_mf_tones[] =
|
||||
{
|
||||
{ 700, 900, -7, -7, 68, 68},
|
||||
{ 700, 1100, -7, -7, 68, 68},
|
||||
{ 900, 1100, -7, -7, 68, 68},
|
||||
{ 700, 1300, -7, -7, 68, 68},
|
||||
{ 900, 1300, -7, -7, 68, 68},
|
||||
{1100, 1300, -7, -7, 68, 68},
|
||||
{ 700, 1500, -7, -7, 68, 68},
|
||||
{ 900, 1500, -7, -7, 68, 68},
|
||||
{1100, 1500, -7, -7, 68, 68},
|
||||
{1300, 1500, -7, -7, 68, 68},
|
||||
{ 700, 1700, -7, -7, 68, 68}, /* ST''' - use 'C' */
|
||||
{ 900, 1700, -7, -7, 68, 68}, /* ST' - use 'A' */
|
||||
{1100, 1700, -7, -7, 100, 68}, /* KP - use '*' */
|
||||
{1300, 1700, -7, -7, 68, 68}, /* ST'' - use 'B' */
|
||||
{1500, 1700, -7, -7, 68, 68}, /* ST - use '#' */
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
/* The order of the digits here must match the list above */
|
||||
static const char bell_mf_tone_codes[] = "1234567890CA*B#";
|
||||
|
||||
/* R2 tone generation specs.
|
||||
* Power: -11.5dBm +- 1dB
|
||||
* Frequency: within +-4Hz
|
||||
* Mismatch between the start time of a pair of tones: <=1ms.
|
||||
* Mismatch between the end time of a pair of tones: <=1ms.
|
||||
*/
|
||||
static const mf_digit_tones_t r2_mf_fwd_tones[] =
|
||||
{
|
||||
{1380, 1500, -11, -11, 1, 0},
|
||||
{1380, 1620, -11, -11, 1, 0},
|
||||
{1500, 1620, -11, -11, 1, 0},
|
||||
{1380, 1740, -11, -11, 1, 0},
|
||||
{1500, 1740, -11, -11, 1, 0},
|
||||
{1620, 1740, -11, -11, 1, 0},
|
||||
{1380, 1860, -11, -11, 1, 0},
|
||||
{1500, 1860, -11, -11, 1, 0},
|
||||
{1620, 1860, -11, -11, 1, 0},
|
||||
{1740, 1860, -11, -11, 1, 0},
|
||||
{1380, 1980, -11, -11, 1, 0},
|
||||
{1500, 1980, -11, -11, 1, 0},
|
||||
{1620, 1980, -11, -11, 1, 0},
|
||||
{1740, 1980, -11, -11, 1, 0},
|
||||
{1860, 1980, -11, -11, 1, 0},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static const mf_digit_tones_t r2_mf_back_tones[] =
|
||||
{
|
||||
{1140, 1020, -11, -11, 1, 0},
|
||||
{1140, 900, -11, -11, 1, 0},
|
||||
{1020, 900, -11, -11, 1, 0},
|
||||
{1140, 780, -11, -11, 1, 0},
|
||||
{1020, 780, -11, -11, 1, 0},
|
||||
{ 900, 780, -11, -11, 1, 0},
|
||||
{1140, 660, -11, -11, 1, 0},
|
||||
{1020, 660, -11, -11, 1, 0},
|
||||
{ 900, 660, -11, -11, 1, 0},
|
||||
{ 780, 660, -11, -11, 1, 0},
|
||||
{1140, 540, -11, -11, 1, 0},
|
||||
{1020, 540, -11, -11, 1, 0},
|
||||
{ 900, 540, -11, -11, 1, 0},
|
||||
{ 780, 540, -11, -11, 1, 0},
|
||||
{ 660, 540, -11, -11, 1, 0},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
/* The order of the digits here must match the lists above */
|
||||
static const char r2_mf_tone_codes[] = "1234567890BCDEF";
|
||||
|
||||
#if 0
|
||||
static const mf_digit_tones_t socotel_tones[] =
|
||||
{
|
||||
{ 700, 900, -11, -11, 1, 0},
|
||||
{ 700, 1100, -11, -11, 1, 0},
|
||||
{ 900, 1100, -11, -11, 1, 0},
|
||||
{ 700, 1300, -11, -11, 1, 0},
|
||||
{ 900, 1300, -11, -11, 1, 0},
|
||||
{1100, 1300, -11, -11, 1, 0},
|
||||
{ 700, 1500, -11, -11, 1, 0},
|
||||
{ 900, 1500, -11, -11, 1, 0},
|
||||
{1100, 1500, -11, -11, 1, 0},
|
||||
{1300, 1500, -11, -11, 1, 0},
|
||||
{1500, 1700, -11, -11, 1, 0},
|
||||
{ 700, 1700, -11, -11, 1, 0},
|
||||
{ 900, 1700, -11, -11, 1, 0},
|
||||
{1300, 1700, -11, -11, 1, 0},
|
||||
{1100, 1700, -11, -11, 1, 0},
|
||||
{1700, 0, -11, -11, 1, 0}, /* Use 'F' */
|
||||
{1900, 0, -11, -11, 1, 0}, /* Use 'G' */
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
/* The order of the digits here must match the list above */
|
||||
static char socotel_mf_tone_codes[] = "1234567890ABCDEFG";
|
||||
#endif
|
||||
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
#define BELL_MF_THRESHOLD 204089 /* -30.5dBm0 */
|
||||
#define BELL_MF_TWIST 3.981f /* 6dB */
|
||||
#define BELL_MF_RELATIVE_PEAK 12.589f /* 11dB */
|
||||
#define BELL_MF_SAMPLES_PER_BLOCK 120
|
||||
|
||||
#define R2_MF_THRESHOLD 62974 /* -36.5dBm0 */
|
||||
#define R2_MF_TWIST 5.012f /* 7dB */
|
||||
#define R2_MF_RELATIVE_PEAK 12.589f /* 11dB */
|
||||
#define R2_MF_SAMPLES_PER_BLOCK 133
|
||||
#else
|
||||
#define BELL_MF_THRESHOLD 3343803100.0f /* -30.5dBm0 [((120.0*32768.0/1.4142)*10^((-30.5 - DBM0_MAX_SINE_POWER)/20.0))^2 => 3343803100.0] */
|
||||
#define BELL_MF_TWIST 3.981f /* 6dB [10^(6/10) => 3.981] */
|
||||
#define BELL_MF_RELATIVE_PEAK 12.589f /* 11dB */
|
||||
#define BELL_MF_SAMPLES_PER_BLOCK 120
|
||||
|
||||
#define R2_MF_THRESHOLD 1031766650.0f /* -36.5dBm0 [((133.0*32768.0/1.4142)*10^((-36.5 - DBM0_MAX_SINE_POWER)/20.0))^2 => 1031766650.0] */
|
||||
#define R2_MF_TWIST 5.012f /* 7dB */
|
||||
#define R2_MF_RELATIVE_PEAK 12.589f /* 11dB */
|
||||
#define R2_MF_SAMPLES_PER_BLOCK 133
|
||||
#endif
|
||||
|
||||
static goertzel_descriptor_t bell_mf_detect_desc[6];
|
||||
|
||||
static goertzel_descriptor_t mf_fwd_detect_desc[6];
|
||||
static goertzel_descriptor_t mf_back_detect_desc[6];
|
||||
|
||||
static const int bell_mf_frequencies[] =
|
||||
{
|
||||
700, 900, 1100, 1300, 1500, 1700
|
||||
};
|
||||
|
||||
/* Use the follow characters for the Bell MF special signals:
|
||||
KP - use '*'
|
||||
ST - use '#'
|
||||
ST' - use 'A'
|
||||
ST'' - use 'B'
|
||||
ST''' - use 'C' */
|
||||
static const char bell_mf_positions[] = "1247C-358A--69*---0B----#";
|
||||
|
||||
static const int r2_mf_fwd_frequencies[] =
|
||||
{
|
||||
1380, 1500, 1620, 1740, 1860, 1980
|
||||
};
|
||||
|
||||
static const int r2_mf_back_frequencies[] =
|
||||
{
|
||||
1140, 1020, 900, 780, 660, 540
|
||||
};
|
||||
|
||||
/* Use codes '1' to 'F' for the R2 signals 1 to 15, except for signal 'A'.
|
||||
Use '0' for this, so the codes match the digits 0-9. */
|
||||
static const char r2_mf_positions[] = "1247B-358C--69D---0E----F";
|
||||
|
||||
static void bell_mf_gen_init(void)
|
||||
{
|
||||
int i;
|
||||
const mf_digit_tones_t *tones;
|
||||
|
||||
if (bell_mf_gen_inited)
|
||||
return;
|
||||
i = 0;
|
||||
tones = bell_mf_tones;
|
||||
while (tones->on_time)
|
||||
{
|
||||
/* Note: The duration of KP is longer than the other signals. */
|
||||
make_tone_gen_descriptor(&bell_mf_digit_tones[i++],
|
||||
tones->f1,
|
||||
tones->level1,
|
||||
tones->f2,
|
||||
tones->level2,
|
||||
tones->on_time,
|
||||
tones->off_time,
|
||||
0,
|
||||
0,
|
||||
FALSE);
|
||||
tones++;
|
||||
}
|
||||
bell_mf_gen_inited = TRUE;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int bell_mf_tx(bell_mf_tx_state_t *s, int16_t amp[], int max_samples)
|
||||
{
|
||||
int len;
|
||||
const char *cp;
|
||||
int digit;
|
||||
|
||||
len = 0;
|
||||
if (s->tones.current_section >= 0)
|
||||
{
|
||||
/* Deal with the fragment left over from last time */
|
||||
len = tone_gen(&(s->tones), amp, max_samples);
|
||||
}
|
||||
while (len < max_samples && (digit = queue_read_byte(&s->queue.queue)) >= 0)
|
||||
{
|
||||
/* Step to the next digit */
|
||||
if ((cp = strchr(bell_mf_tone_codes, digit)) == NULL)
|
||||
continue;
|
||||
tone_gen_init(&(s->tones), &bell_mf_digit_tones[cp - bell_mf_tone_codes]);
|
||||
len += tone_gen(&(s->tones), amp + len, max_samples - len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
size_t bell_mf_tx_put(bell_mf_tx_state_t *s, const char *digits, int len)
|
||||
{
|
||||
size_t space;
|
||||
|
||||
/* This returns the number of characters that would not fit in the buffer.
|
||||
The buffer will only be loaded if the whole string of digits will fit,
|
||||
in which case zero is returned. */
|
||||
if (len < 0)
|
||||
{
|
||||
if ((len = strlen(digits)) == 0)
|
||||
return 0;
|
||||
}
|
||||
if ((space = queue_free_space(&s->queue.queue)) < len)
|
||||
return len - space;
|
||||
if (queue_write(&s->queue.queue, (const uint8_t *) digits, len) >= 0)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
bell_mf_tx_state_t *bell_mf_tx_init(bell_mf_tx_state_t *s)
|
||||
{
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (bell_mf_tx_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
if (!bell_mf_gen_inited)
|
||||
bell_mf_gen_init();
|
||||
tone_gen_init(&(s->tones), &bell_mf_digit_tones[0]);
|
||||
s->current_sample = 0;
|
||||
queue_init(&s->queue.queue, MAX_BELL_MF_DIGITS, QUEUE_READ_ATOMIC | QUEUE_WRITE_ATOMIC);
|
||||
s->tones.current_section = -1;
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int bell_mf_tx_free(bell_mf_tx_state_t *s)
|
||||
{
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int r2_mf_tx(r2_mf_tx_state_t *s, int16_t amp[], int samples)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (s->digit == 0)
|
||||
{
|
||||
len = samples;
|
||||
memset(amp, 0, len*sizeof(int16_t));
|
||||
}
|
||||
else
|
||||
{
|
||||
len = tone_gen(&s->tone, amp, samples);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int r2_mf_tx_put(r2_mf_tx_state_t *s, char digit)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
if (digit && (cp = strchr(r2_mf_tone_codes, digit)))
|
||||
{
|
||||
if (s->fwd)
|
||||
tone_gen_init(&s->tone, &r2_mf_fwd_digit_tones[cp - r2_mf_tone_codes]);
|
||||
else
|
||||
tone_gen_init(&s->tone, &r2_mf_back_digit_tones[cp - r2_mf_tone_codes]);
|
||||
s->digit = digit;
|
||||
}
|
||||
else
|
||||
{
|
||||
s->digit = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
r2_mf_tx_state_t *r2_mf_tx_init(r2_mf_tx_state_t *s, int fwd)
|
||||
{
|
||||
int i;
|
||||
const mf_digit_tones_t *tones;
|
||||
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (r2_mf_tx_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
if (!r2_mf_gen_inited)
|
||||
{
|
||||
i = 0;
|
||||
tones = r2_mf_fwd_tones;
|
||||
while (tones->on_time)
|
||||
{
|
||||
make_tone_gen_descriptor(&r2_mf_fwd_digit_tones[i++],
|
||||
tones->f1,
|
||||
tones->level1,
|
||||
tones->f2,
|
||||
tones->level2,
|
||||
tones->on_time,
|
||||
tones->off_time,
|
||||
0,
|
||||
0,
|
||||
(tones->off_time == 0));
|
||||
tones++;
|
||||
}
|
||||
i = 0;
|
||||
tones = r2_mf_back_tones;
|
||||
while (tones->on_time)
|
||||
{
|
||||
make_tone_gen_descriptor(&r2_mf_back_digit_tones[i++],
|
||||
tones->f1,
|
||||
tones->level1,
|
||||
tones->f2,
|
||||
tones->level2,
|
||||
tones->on_time,
|
||||
tones->off_time,
|
||||
0,
|
||||
0,
|
||||
(tones->off_time == 0));
|
||||
tones++;
|
||||
}
|
||||
r2_mf_gen_inited = TRUE;
|
||||
}
|
||||
s->fwd = fwd;
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int r2_mf_tx_free(r2_mf_tx_state_t *s)
|
||||
{
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int bell_mf_rx(bell_mf_rx_state_t *s, const int16_t amp[], int samples)
|
||||
{
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
int32_t energy[6];
|
||||
int16_t xamp;
|
||||
#else
|
||||
float energy[6];
|
||||
float xamp;
|
||||
#endif
|
||||
int i;
|
||||
int j;
|
||||
int sample;
|
||||
int best;
|
||||
int second_best;
|
||||
int limit;
|
||||
uint8_t hit;
|
||||
|
||||
hit = 0;
|
||||
for (sample = 0; sample < samples; sample = limit)
|
||||
{
|
||||
if ((samples - sample) >= (BELL_MF_SAMPLES_PER_BLOCK - s->current_sample))
|
||||
limit = sample + (BELL_MF_SAMPLES_PER_BLOCK - s->current_sample);
|
||||
else
|
||||
limit = samples;
|
||||
for (j = sample; j < limit; j++)
|
||||
{
|
||||
xamp = goertzel_preadjust_amp(amp[j]);
|
||||
goertzel_samplex(&s->out[0], xamp);
|
||||
goertzel_samplex(&s->out[1], xamp);
|
||||
goertzel_samplex(&s->out[2], xamp);
|
||||
goertzel_samplex(&s->out[3], xamp);
|
||||
goertzel_samplex(&s->out[4], xamp);
|
||||
goertzel_samplex(&s->out[5], xamp);
|
||||
}
|
||||
s->current_sample += (limit - sample);
|
||||
if (s->current_sample < BELL_MF_SAMPLES_PER_BLOCK)
|
||||
continue;
|
||||
|
||||
/* We are at the end of an MF detection block */
|
||||
/* Find the two highest energies. The spec says to look for
|
||||
two tones and two tones only. Taking this literally -ie
|
||||
only two tones pass the minimum threshold - doesn't work
|
||||
well. The sinc function mess, due to rectangular windowing
|
||||
ensure that! Find the two highest energies and ensure they
|
||||
are considerably stronger than any of the others. */
|
||||
energy[0] = goertzel_result(&s->out[0]);
|
||||
energy[1] = goertzel_result(&s->out[1]);
|
||||
if (energy[0] > energy[1])
|
||||
{
|
||||
best = 0;
|
||||
second_best = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
best = 1;
|
||||
second_best = 0;
|
||||
}
|
||||
for (i = 2; i < 6; i++)
|
||||
{
|
||||
energy[i] = goertzel_result(&s->out[i]);
|
||||
if (energy[i] >= energy[best])
|
||||
{
|
||||
second_best = best;
|
||||
best = i;
|
||||
}
|
||||
else if (energy[i] >= energy[second_best])
|
||||
{
|
||||
second_best = i;
|
||||
}
|
||||
}
|
||||
/* Basic signal level and twist tests */
|
||||
hit = 0;
|
||||
if (energy[best] >= BELL_MF_THRESHOLD
|
||||
&&
|
||||
energy[second_best] >= BELL_MF_THRESHOLD
|
||||
&&
|
||||
energy[best] < energy[second_best]*BELL_MF_TWIST
|
||||
&&
|
||||
energy[best]*BELL_MF_TWIST > energy[second_best])
|
||||
{
|
||||
/* Relative peak test */
|
||||
hit = 'X';
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
if (i != best && i != second_best)
|
||||
{
|
||||
if (energy[i]*BELL_MF_RELATIVE_PEAK >= energy[second_best])
|
||||
{
|
||||
/* The best two are not clearly the best */
|
||||
hit = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hit)
|
||||
{
|
||||
/* Get the values into ascending order */
|
||||
if (second_best < best)
|
||||
{
|
||||
i = best;
|
||||
best = second_best;
|
||||
second_best = i;
|
||||
}
|
||||
best = best*5 + second_best - 1;
|
||||
hit = bell_mf_positions[best];
|
||||
/* Look for two successive similar results */
|
||||
/* The logic in the next test is:
|
||||
For KP we need 4 successive identical clean detects, with
|
||||
two blocks of something different preceeding it. For anything
|
||||
else we need two successive identical clean detects, with
|
||||
two blocks of something different preceeding it. */
|
||||
if (hit == s->hits[4]
|
||||
&&
|
||||
hit == s->hits[3]
|
||||
&&
|
||||
((hit != '*' && hit != s->hits[2] && hit != s->hits[1])
|
||||
||
|
||||
(hit == '*' && hit == s->hits[2] && hit != s->hits[1] && hit != s->hits[0])))
|
||||
{
|
||||
if (s->current_digits < MAX_BELL_MF_DIGITS)
|
||||
{
|
||||
s->digits[s->current_digits++] = (char) hit;
|
||||
s->digits[s->current_digits] = '\0';
|
||||
if (s->digits_callback)
|
||||
{
|
||||
s->digits_callback(s->digits_callback_data, s->digits, s->current_digits);
|
||||
s->current_digits = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s->lost_digits++;
|
||||
}
|
||||
}
|
||||
}
|
||||
s->hits[0] = s->hits[1];
|
||||
s->hits[1] = s->hits[2];
|
||||
s->hits[2] = s->hits[3];
|
||||
s->hits[3] = s->hits[4];
|
||||
s->hits[4] = hit;
|
||||
s->current_sample = 0;
|
||||
}
|
||||
if (s->current_digits && s->digits_callback)
|
||||
{
|
||||
s->digits_callback(s->digits_callback_data, s->digits, s->current_digits);
|
||||
s->digits[0] = '\0';
|
||||
s->current_digits = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
size_t bell_mf_rx_get(bell_mf_rx_state_t *s, char *buf, int max)
|
||||
{
|
||||
if (max > s->current_digits)
|
||||
max = s->current_digits;
|
||||
if (max > 0)
|
||||
{
|
||||
memcpy(buf, s->digits, max);
|
||||
memmove(s->digits, s->digits + max, s->current_digits - max);
|
||||
s->current_digits -= max;
|
||||
}
|
||||
buf[max] = '\0';
|
||||
return max;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
bell_mf_rx_state_t *bell_mf_rx_init(bell_mf_rx_state_t *s,
|
||||
digits_rx_callback_t callback,
|
||||
void *user_data)
|
||||
{
|
||||
int i;
|
||||
static int initialised = FALSE;
|
||||
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (bell_mf_rx_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
if (!initialised)
|
||||
{
|
||||
for (i = 0; i < 6; i++)
|
||||
make_goertzel_descriptor(&bell_mf_detect_desc[i], bell_mf_frequencies[i], BELL_MF_SAMPLES_PER_BLOCK);
|
||||
initialised = TRUE;
|
||||
}
|
||||
s->digits_callback = callback;
|
||||
s->digits_callback_data = user_data;
|
||||
|
||||
s->hits[0] =
|
||||
s->hits[1] =
|
||||
s->hits[2] =
|
||||
s->hits[3] =
|
||||
s->hits[4] = 0;
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
goertzel_init(&s->out[i], &bell_mf_detect_desc[i]);
|
||||
s->current_sample = 0;
|
||||
s->lost_digits = 0;
|
||||
s->current_digits = 0;
|
||||
s->digits[0] = '\0';
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int bell_mf_rx_free(bell_mf_rx_state_t *s)
|
||||
{
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int r2_mf_rx(r2_mf_rx_state_t *s, const int16_t amp[], int samples)
|
||||
{
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
int32_t energy[6];
|
||||
int16_t xamp;
|
||||
#else
|
||||
float energy[6];
|
||||
float xamp;
|
||||
#endif
|
||||
int i;
|
||||
int j;
|
||||
int sample;
|
||||
int best;
|
||||
int second_best;
|
||||
int hit;
|
||||
int hit_digit;
|
||||
int limit;
|
||||
|
||||
hit = 0;
|
||||
hit_digit = 0;
|
||||
for (sample = 0; sample < samples; sample = limit)
|
||||
{
|
||||
if ((samples - sample) >= (R2_MF_SAMPLES_PER_BLOCK - s->current_sample))
|
||||
limit = sample + (R2_MF_SAMPLES_PER_BLOCK - s->current_sample);
|
||||
else
|
||||
limit = samples;
|
||||
for (j = sample; j < limit; j++)
|
||||
{
|
||||
xamp = goertzel_preadjust_amp(amp[j]);
|
||||
goertzel_samplex(&s->out[0], xamp);
|
||||
goertzel_samplex(&s->out[1], xamp);
|
||||
goertzel_samplex(&s->out[2], xamp);
|
||||
goertzel_samplex(&s->out[3], xamp);
|
||||
goertzel_samplex(&s->out[4], xamp);
|
||||
goertzel_samplex(&s->out[5], xamp);
|
||||
}
|
||||
s->current_sample += (limit - sample);
|
||||
if (s->current_sample < R2_MF_SAMPLES_PER_BLOCK)
|
||||
continue;
|
||||
|
||||
/* We are at the end of an MF detection block */
|
||||
/* Find the two highest energies */
|
||||
energy[0] = goertzel_result(&s->out[0]);
|
||||
energy[1] = goertzel_result(&s->out[1]);
|
||||
if (energy[0] > energy[1])
|
||||
{
|
||||
best = 0;
|
||||
second_best = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
best = 1;
|
||||
second_best = 0;
|
||||
}
|
||||
|
||||
for (i = 2; i < 6; i++)
|
||||
{
|
||||
energy[i] = goertzel_result(&s->out[i]);
|
||||
if (energy[i] >= energy[best])
|
||||
{
|
||||
second_best = best;
|
||||
best = i;
|
||||
}
|
||||
else if (energy[i] >= energy[second_best])
|
||||
{
|
||||
second_best = i;
|
||||
}
|
||||
}
|
||||
/* Basic signal level and twist tests */
|
||||
hit = FALSE;
|
||||
if (energy[best] >= R2_MF_THRESHOLD
|
||||
&&
|
||||
energy[second_best] >= R2_MF_THRESHOLD
|
||||
&&
|
||||
energy[best] < energy[second_best]*R2_MF_TWIST
|
||||
&&
|
||||
energy[best]*R2_MF_TWIST > energy[second_best])
|
||||
{
|
||||
/* Relative peak test */
|
||||
hit = TRUE;
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
if (i != best && i != second_best)
|
||||
{
|
||||
if (energy[i]*R2_MF_RELATIVE_PEAK >= energy[second_best])
|
||||
{
|
||||
/* The best two are not clearly the best */
|
||||
hit = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hit)
|
||||
{
|
||||
/* Get the values into ascending order */
|
||||
if (second_best < best)
|
||||
{
|
||||
i = best;
|
||||
best = second_best;
|
||||
second_best = i;
|
||||
}
|
||||
best = best*5 + second_best - 1;
|
||||
hit_digit = r2_mf_positions[best];
|
||||
}
|
||||
else
|
||||
{
|
||||
hit_digit = 0;
|
||||
}
|
||||
if (s->current_digit != hit_digit && s->callback)
|
||||
{
|
||||
i = (hit_digit) ? -99 : -10;
|
||||
s->callback(s->callback_data, hit_digit, i, 0);
|
||||
}
|
||||
s->current_digit = hit_digit;
|
||||
s->current_sample = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int r2_mf_rx_get(r2_mf_rx_state_t *s)
|
||||
{
|
||||
return s->current_digit;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
r2_mf_rx_state_t *r2_mf_rx_init(r2_mf_rx_state_t *s,
|
||||
int fwd,
|
||||
tone_report_func_t callback,
|
||||
void *user_data)
|
||||
{
|
||||
int i;
|
||||
static int initialised = FALSE;
|
||||
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (r2_mf_rx_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
s->fwd = fwd;
|
||||
|
||||
if (!initialised)
|
||||
{
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
make_goertzel_descriptor(&mf_fwd_detect_desc[i], r2_mf_fwd_frequencies[i], R2_MF_SAMPLES_PER_BLOCK);
|
||||
make_goertzel_descriptor(&mf_back_detect_desc[i], r2_mf_back_frequencies[i], R2_MF_SAMPLES_PER_BLOCK);
|
||||
}
|
||||
initialised = TRUE;
|
||||
}
|
||||
if (fwd)
|
||||
{
|
||||
for (i = 0; i < 6; i++)
|
||||
goertzel_init(&s->out[i], &mf_fwd_detect_desc[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 6; i++)
|
||||
goertzel_init(&s->out[i], &mf_back_detect_desc[i]);
|
||||
}
|
||||
s->callback = callback;
|
||||
s->callback_data = user_data;
|
||||
s->current_digit = 0;
|
||||
s->current_sample = 0;
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int r2_mf_rx_free(r2_mf_rx_state_t *s)
|
||||
{
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,513 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* bert.c - Bit error rate tests.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: bert.c,v 1.27 2008/05/13 13:17:22 steveu Exp $
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/logging.h"
|
||||
#include "spandsp/async.h"
|
||||
#include "spandsp/bert.h"
|
||||
|
||||
static const char *qbf = "VoyeZ Le BricK GeanT QuE J'ExaminE PreS Du WharF 123 456 7890 + - * : = $ % ( )"
|
||||
"ThE QuicK BrowN FoX JumpS OveR ThE LazY DoG 123 456 7890 + - * : = $ % ( )";
|
||||
|
||||
const char *bert_event_to_str(int event)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case BERT_REPORT_SYNCED:
|
||||
return "synced";
|
||||
case BERT_REPORT_UNSYNCED:
|
||||
return "unsync'ed";
|
||||
case BERT_REPORT_REGULAR:
|
||||
return "regular";
|
||||
case BERT_REPORT_GT_10_2:
|
||||
return "error rate > 1 in 10^2";
|
||||
case BERT_REPORT_LT_10_2:
|
||||
return "error rate < 1 in 10^2";
|
||||
case BERT_REPORT_LT_10_3:
|
||||
return "error rate < 1 in 10^3";
|
||||
case BERT_REPORT_LT_10_4:
|
||||
return "error rate < 1 in 10^4";
|
||||
case BERT_REPORT_LT_10_5:
|
||||
return "error rate < 1 in 10^5";
|
||||
case BERT_REPORT_LT_10_6:
|
||||
return "error rate < 1 in 10^6";
|
||||
case BERT_REPORT_LT_10_7:
|
||||
return "error rate < 1 in 10^7";
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int bert_get_bit(bert_state_t *s)
|
||||
{
|
||||
int bit;
|
||||
|
||||
if (s->limit && s->tx_bits >= s->limit)
|
||||
return PUTBIT_END_OF_DATA;
|
||||
bit = 0;
|
||||
switch (s->pattern_class)
|
||||
{
|
||||
case 0:
|
||||
bit = s->tx_reg & 1;
|
||||
s->tx_reg = (s->tx_reg >> 1) | ((s->tx_reg & 1) << s->shift2);
|
||||
break;
|
||||
case 1:
|
||||
bit = s->tx_reg & 1;
|
||||
s->tx_reg = (s->tx_reg >> 1) | (((s->tx_reg ^ (s->tx_reg >> s->shift)) & 1) << s->shift2);
|
||||
if (s->max_zeros)
|
||||
{
|
||||
/* This generator suppresses runs >s->max_zeros */
|
||||
if (bit)
|
||||
{
|
||||
if (++s->tx_zeros > s->max_zeros)
|
||||
{
|
||||
s->tx_zeros = 0;
|
||||
bit ^= 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s->tx_zeros = 0;
|
||||
}
|
||||
}
|
||||
bit ^= s->invert;
|
||||
break;
|
||||
case 2:
|
||||
if (s->tx_step_bit == 0)
|
||||
{
|
||||
s->tx_step_bit = 7;
|
||||
s->tx_reg = qbf[s->tx_step++];
|
||||
if (s->tx_reg == 0)
|
||||
{
|
||||
s->tx_reg = 'V';
|
||||
s->tx_step = 1;
|
||||
}
|
||||
}
|
||||
bit = s->tx_reg & 1;
|
||||
s->tx_reg >>= 1;
|
||||
s->tx_step_bit--;
|
||||
break;
|
||||
}
|
||||
s->tx_bits++;
|
||||
return bit;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void assess_error_rate(bert_state_t *s)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
int sum;
|
||||
int test;
|
||||
|
||||
/* We assess the error rate in decadic steps. For each decade we assess the error over 10 times
|
||||
the number of bits, to smooth the result. This means we assess the 1 in 100 rate based on 1000 bits
|
||||
(i.e. we look for >=10 errors in 1000 bits). We make an assessment every 100 bits, using a sliding
|
||||
window over the last 1000 bits. We assess the 1 in 1000 rate over 10000 bits in a similar way, and
|
||||
so on for the lower error rates. */
|
||||
test = TRUE;
|
||||
for (i = 2; i <= 7; i++)
|
||||
{
|
||||
if (++s->decade_ptr[i] < 10)
|
||||
break;
|
||||
/* This decade has reached 10 snapshots, so we need to touch the next decade */
|
||||
s->decade_ptr[i] = 0;
|
||||
/* Sum the last 10 snapshots from this decade, to see if we overflow into the next decade */
|
||||
for (sum = 0, j = 0; j < 10; j++)
|
||||
sum += s->decade_bad[i][j];
|
||||
if (test && sum > 10)
|
||||
{
|
||||
/* We overflow into the next decade */
|
||||
test = FALSE;
|
||||
if (s->error_rate != i && s->reporter)
|
||||
s->reporter(s->user_data, BERT_REPORT_GT_10_2 + i - 2, &s->results);
|
||||
s->error_rate = i;
|
||||
}
|
||||
s->decade_bad[i][0] = 0;
|
||||
if (i < 7)
|
||||
s->decade_bad[i + 1][s->decade_ptr[i + 1]] = sum;
|
||||
}
|
||||
if (i > 7)
|
||||
{
|
||||
if (s->decade_ptr[i] >= 10)
|
||||
s->decade_ptr[i] = 0;
|
||||
if (test)
|
||||
{
|
||||
if (s->error_rate != i && s->reporter)
|
||||
s->reporter(s->user_data, BERT_REPORT_GT_10_2 + i - 2, &s->results);
|
||||
s->error_rate = i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s->decade_bad[i][s->decade_ptr[i]] = 0;
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void bert_put_bit(bert_state_t *s, int bit)
|
||||
{
|
||||
if (bit < 0)
|
||||
{
|
||||
/* Special conditions */
|
||||
switch (bit)
|
||||
{
|
||||
case PUTBIT_TRAINING_IN_PROGRESS:
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Training in progress\n");
|
||||
break;
|
||||
case PUTBIT_TRAINING_FAILED:
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed\n");
|
||||
break;
|
||||
case PUTBIT_TRAINING_SUCCEEDED:
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded\n");
|
||||
break;
|
||||
case PUTBIT_CARRIER_UP:
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Carrier up\n");
|
||||
break;
|
||||
case PUTBIT_CARRIER_DOWN:
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Carrier down\n");
|
||||
break;
|
||||
default:
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Eh!\n");
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
bit = (bit & 1) ^ s->invert;
|
||||
s->rx_bits++;
|
||||
switch (s->pattern_class)
|
||||
{
|
||||
case 0:
|
||||
if (s->resync)
|
||||
{
|
||||
s->rx_reg = (s->rx_reg >> 1) | (bit << s->shift2);
|
||||
s->ref_reg = (s->ref_reg >> 1) | ((s->ref_reg & 1) << s->shift2);
|
||||
if (s->rx_reg == s->ref_reg)
|
||||
{
|
||||
if (++s->resync > s->resync_time)
|
||||
{
|
||||
s->resync = 0;
|
||||
if (s->reporter)
|
||||
s->reporter(s->user_data, BERT_REPORT_SYNCED, &s->results);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s->resync = 2;
|
||||
s->ref_reg = s->master_reg;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s->results.total_bits++;
|
||||
if ((bit ^ s->ref_reg) & 1)
|
||||
s->results.bad_bits++;
|
||||
s->ref_reg = (s->ref_reg >> 1) | ((s->ref_reg & 1) << s->shift2);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (s->resync)
|
||||
{
|
||||
/* If we get a reasonable period for which we correctly predict the
|
||||
next bit, we must be in sync. */
|
||||
/* Don't worry about max. zeros tests when resyncing.
|
||||
It might just extend the resync time a little. Trying
|
||||
to include the test might affect robustness. */
|
||||
if (bit == (int) ((s->rx_reg >> s->shift) & 1))
|
||||
{
|
||||
if (++s->resync > s->resync_time)
|
||||
{
|
||||
s->resync = 0;
|
||||
if (s->reporter)
|
||||
s->reporter(s->user_data, BERT_REPORT_SYNCED, &s->results);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s->resync = 2;
|
||||
s->rx_reg ^= s->mask;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s->results.total_bits++;
|
||||
if (s->max_zeros)
|
||||
{
|
||||
/* This generator suppresses runs >s->max_zeros */
|
||||
if ((s->rx_reg & s->mask))
|
||||
{
|
||||
if (++s->rx_zeros > s->max_zeros)
|
||||
{
|
||||
s->rx_zeros = 0;
|
||||
bit ^= 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s->rx_zeros = 0;
|
||||
}
|
||||
}
|
||||
if (bit != (int) ((s->rx_reg >> s->shift) & 1))
|
||||
{
|
||||
s->results.bad_bits++;
|
||||
s->resync_bad_bits++;
|
||||
s->decade_bad[2][s->decade_ptr[2]]++;
|
||||
}
|
||||
if (--s->step <= 0)
|
||||
{
|
||||
/* Every hundred bits we need to do the error rate measurement */
|
||||
s->step = 100;
|
||||
assess_error_rate(s);
|
||||
}
|
||||
if (--s->resync_cnt <= 0)
|
||||
{
|
||||
/* Check if there were enough bad bits during this period to
|
||||
justify a resync. */
|
||||
if (s->resync_bad_bits >= (s->resync_len*s->resync_percent)/100)
|
||||
{
|
||||
s->resync = 1;
|
||||
s->results.resyncs++;
|
||||
if (s->reporter)
|
||||
s->reporter(s->user_data, BERT_REPORT_UNSYNCED, &s->results);
|
||||
}
|
||||
s->resync_cnt = s->resync_len;
|
||||
s->resync_bad_bits = 0;
|
||||
}
|
||||
}
|
||||
s->rx_reg = (s->rx_reg >> 1) | (((s->rx_reg ^ (s->rx_reg >> s->shift)) & 1) << s->shift2);
|
||||
break;
|
||||
case 2:
|
||||
s->rx_reg = (s->rx_reg >> 1) | (bit << 6);
|
||||
/* TODO: There is no mechanism for synching yet. This only works if things start in sync. */
|
||||
if (++s->rx_step_bit == 7)
|
||||
{
|
||||
s->rx_step_bit = 0;
|
||||
if ((int) s->rx_reg != qbf[s->rx_step])
|
||||
{
|
||||
/* We need to work out the number of actual bad bits here. We need to look at the
|
||||
error rate, and see it a resync is needed. etc. */
|
||||
s->results.bad_bits++;
|
||||
}
|
||||
if (qbf[++s->rx_step] == '\0')
|
||||
s->rx_step = 0;
|
||||
}
|
||||
s->results.total_bits++;
|
||||
break;
|
||||
}
|
||||
if (s->report_frequency > 0)
|
||||
{
|
||||
if (--s->report_countdown <= 0)
|
||||
{
|
||||
if (s->reporter)
|
||||
s->reporter(s->user_data, BERT_REPORT_REGULAR, &s->results);
|
||||
s->report_countdown = s->report_frequency;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int bert_result(bert_state_t *s, bert_results_t *results)
|
||||
{
|
||||
results->total_bits = s->results.total_bits;
|
||||
results->bad_bits = s->results.bad_bits;
|
||||
results->resyncs = s->results.resyncs;
|
||||
return sizeof(*results);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void bert_set_report(bert_state_t *s, int freq, bert_report_func_t reporter, void *user_data)
|
||||
{
|
||||
s->report_frequency = freq;
|
||||
s->reporter = reporter;
|
||||
s->user_data = user_data;
|
||||
|
||||
s->report_countdown = s->report_frequency;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
bert_state_t *bert_init(bert_state_t *s, int limit, int pattern, int resync_len, int resync_percent)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (bert_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
s->pattern = pattern;
|
||||
s->limit = limit;
|
||||
s->reporter = NULL;
|
||||
s->user_data = NULL;
|
||||
s->report_frequency = 0;
|
||||
|
||||
s->resync_time = 72;
|
||||
s->invert = 0;
|
||||
switch (s->pattern)
|
||||
{
|
||||
case BERT_PATTERN_ZEROS:
|
||||
s->tx_reg = 0;
|
||||
s->shift2 = 31;
|
||||
s->pattern_class = 0;
|
||||
break;
|
||||
case BERT_PATTERN_ONES:
|
||||
s->tx_reg = ~((uint32_t) 0);
|
||||
s->shift2 = 31;
|
||||
s->pattern_class = 0;
|
||||
break;
|
||||
case BERT_PATTERN_7_TO_1:
|
||||
s->tx_reg = 0xFEFEFEFE;
|
||||
s->shift2 = 31;
|
||||
s->pattern_class = 0;
|
||||
break;
|
||||
case BERT_PATTERN_3_TO_1:
|
||||
s->tx_reg = 0xEEEEEEEE;
|
||||
s->shift2 = 31;
|
||||
s->pattern_class = 0;
|
||||
break;
|
||||
case BERT_PATTERN_1_TO_1:
|
||||
s->tx_reg = 0xAAAAAAAA;
|
||||
s->shift2 = 31;
|
||||
s->pattern_class = 0;
|
||||
break;
|
||||
case BERT_PATTERN_1_TO_3:
|
||||
s->tx_reg = 0x11111111;
|
||||
s->shift2 = 31;
|
||||
s->pattern_class = 0;
|
||||
break;
|
||||
case BERT_PATTERN_1_TO_7:
|
||||
s->tx_reg = 0x01010101;
|
||||
s->shift2 = 31;
|
||||
s->pattern_class = 0;
|
||||
break;
|
||||
case BERT_PATTERN_QBF:
|
||||
s->tx_reg = 0;
|
||||
s->pattern_class = 2;
|
||||
break;
|
||||
case BERT_PATTERN_ITU_O151_23:
|
||||
s->pattern_class = 1;
|
||||
s->tx_reg = 0x7FFFFF;
|
||||
s->mask = 0x20;
|
||||
s->shift = 5;
|
||||
s->shift2 = 22;
|
||||
s->invert = 1;
|
||||
s->resync_time = 56;
|
||||
s->max_zeros = 0;
|
||||
break;
|
||||
case BERT_PATTERN_ITU_O151_20:
|
||||
s->pattern_class = 1;
|
||||
s->tx_reg = 0xFFFFF;
|
||||
s->mask = 0x8;
|
||||
s->shift = 3;
|
||||
s->shift2 = 19;
|
||||
s->invert = 1;
|
||||
s->resync_time = 50;
|
||||
s->max_zeros = 14;
|
||||
break;
|
||||
case BERT_PATTERN_ITU_O151_15:
|
||||
s->pattern_class = 1;
|
||||
s->tx_reg = 0x7FFF;
|
||||
s->mask = 0x2;
|
||||
s->shift = 1;
|
||||
s->shift2 = 14;
|
||||
s->invert = 1;
|
||||
s->resync_time = 40;
|
||||
s->max_zeros = 0;
|
||||
break;
|
||||
case BERT_PATTERN_ITU_O152_11:
|
||||
s->pattern_class = 1;
|
||||
s->tx_reg = 0x7FF;
|
||||
s->mask = 0x4;
|
||||
s->shift = 2;
|
||||
s->shift2 = 10;
|
||||
s->invert = 0;
|
||||
s->resync_time = 32;
|
||||
s->max_zeros = 0;
|
||||
break;
|
||||
case BERT_PATTERN_ITU_O153_9:
|
||||
s->pattern_class = 1;
|
||||
s->tx_reg = 0x1FF;
|
||||
s->mask = 0x10;
|
||||
s->shift = 4;
|
||||
s->shift2 = 8;
|
||||
s->invert = 0;
|
||||
s->resync_time = 28;
|
||||
s->max_zeros = 0;
|
||||
break;
|
||||
}
|
||||
s->tx_bits = 0;
|
||||
s->tx_step = 0;
|
||||
s->tx_step_bit = 0;
|
||||
s->tx_zeros = 0;
|
||||
|
||||
s->rx_reg = s->tx_reg;
|
||||
s->ref_reg = s->rx_reg;
|
||||
s->master_reg = s->ref_reg;
|
||||
s->rx_bits = 0;
|
||||
s->rx_step = 0;
|
||||
s->rx_step_bit = 0;
|
||||
|
||||
s->resync = 1;
|
||||
s->resync_cnt = resync_len;
|
||||
s->resync_bad_bits = 0;
|
||||
s->resync_len = resync_len;
|
||||
s->resync_percent = resync_percent;
|
||||
s->results.total_bits = 0;
|
||||
s->results.bad_bits = 0;
|
||||
s->results.resyncs = 0;
|
||||
|
||||
s->report_countdown = 0;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
for (j = 0; j < 10; j++)
|
||||
s->decade_bad[i][j] = 0;
|
||||
s->decade_ptr[i] = 0;
|
||||
}
|
||||
s->error_rate = 8;
|
||||
s->step = 100;
|
||||
|
||||
span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
|
||||
span_log_set_protocol(&s->logging, "BERT");
|
||||
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* bit_operations.c - Various bit level operations, such as bit reversal
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.c,v 1.15 2008/06/28 01:13:08 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <memory.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/bit_operations.h"
|
||||
|
||||
uint16_t bit_reverse16(uint16_t x)
|
||||
{
|
||||
x = (x >> 8) | (x << 8);
|
||||
x = ((x & 0xF0F0) >> 4) | ((x & 0x0F0F) << 4);
|
||||
x = ((x & 0xCCCC) >> 2) | ((x & 0x3333) << 2);
|
||||
return ((x & 0xAAAA) >> 1) | ((x & 0x5555) << 1);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
uint32_t bit_reverse32(uint32_t x)
|
||||
{
|
||||
x = (x >> 16) | (x << 16);
|
||||
x = ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8);
|
||||
x = ((x & 0xF0F0F0F0) >> 4) | ((x & 0x0F0F0F0F) << 4);
|
||||
x = ((x & 0xCCCCCCCC) >> 2) | ((x & 0x33333333) << 2);
|
||||
return ((x & 0xAAAAAAAA) >> 1) | ((x & 0x55555555) << 1);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
uint32_t bit_reverse_4bytes(uint32_t x)
|
||||
{
|
||||
x = ((x & 0xF0F0F0F0) >> 4) | ((x & 0x0F0F0F0F) << 4);
|
||||
x = ((x & 0xCCCCCCCC) >> 2) | ((x & 0x33333333) << 2);
|
||||
return ((x & 0xAAAAAAAA) >> 1) | ((x & 0x55555555) << 1);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
#if defined(__x86_64__)
|
||||
uint64_t bit_reverse_8bytes(uint64_t x)
|
||||
{
|
||||
x = ((x & 0xF0F0F0F0F0F0F0F0LLU) >> 4) | ((x & 0x0F0F0F0F0F0F0F0FLLU) << 4);
|
||||
x = ((x & 0xCCCCCCCCCCCCCCCCLLU) >> 2) | ((x & 0x3333333333333333LLU) << 2);
|
||||
return ((x & 0xAAAAAAAAAAAAAAAALLU) >> 1) | ((x & 0x5555555555555555LLU) << 1);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
#endif
|
||||
|
||||
void bit_reverse(uint8_t to[], const uint8_t from[], int len)
|
||||
{
|
||||
#if defined(SPANDSP_MISALIGNED_ACCESS_FAILS)
|
||||
int i;
|
||||
#else
|
||||
const uint8_t *y1;
|
||||
uint8_t *z1;
|
||||
const uint32_t *y4;
|
||||
uint32_t *z4;
|
||||
uint32_t x4;
|
||||
#if defined(__x86_64__)
|
||||
const uint64_t *y8;
|
||||
uint64_t *z8;
|
||||
uint64_t x8;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(SPANDSP_MISALIGNED_ACCESS_FAILS)
|
||||
/* This code works byte by byte, so it works on machines where misalignment
|
||||
is either desperately slow (its a bit slow on practically any machine, but
|
||||
some machines make it desparately slow) or fails. */
|
||||
for (i = 0; i < len; i++)
|
||||
to[i] = bit_reverse8(from[i]);
|
||||
#else
|
||||
/* This code is this is based on the woolly assumption that the start of the buffers
|
||||
is memory aligned. If it isn't, the routine will be less efficient on some machines,
|
||||
but might not work at all on others. */
|
||||
#if defined(__x86_64__)
|
||||
y8 = (const uint64_t *) from;
|
||||
z8 = (uint64_t *) to;
|
||||
while (len >= sizeof(uint64_t))
|
||||
{
|
||||
x8 = *y8++;
|
||||
x8 = ((x8 & 0xF0F0F0F0F0F0F0F0LLU) >> 4) | ((x8 & 0x0F0F0F0F0F0F0F0FLLU) << 4);
|
||||
x8 = ((x8 & 0xCCCCCCCCCCCCCCCCLLU) >> 2) | ((x8 & 0x3333333333333333LLU) << 2);
|
||||
*z8++ = ((x8 & 0xAAAAAAAAAAAAAAAALLU) >> 1) | ((x8 & 0x5555555555555555LLU) << 1);
|
||||
len -= sizeof(uint64_t);
|
||||
}
|
||||
y4 = (const uint32_t *) y8;
|
||||
z4 = (uint32_t *) z8;
|
||||
#else
|
||||
y4 = (const uint32_t *) from;
|
||||
z4 = (uint32_t *) to;
|
||||
#endif
|
||||
while (len >= sizeof(uint32_t))
|
||||
{
|
||||
x4 = *y4++;
|
||||
x4 = ((x4 & 0xF0F0F0F0) >> 4) | ((x4 & 0x0F0F0F0F) << 4);
|
||||
x4 = ((x4 & 0xCCCCCCCC) >> 2) | ((x4 & 0x33333333) << 2);
|
||||
*z4++ = ((x4 & 0xAAAAAAAA) >> 1) | ((x4 & 0x55555555) << 1);
|
||||
len -= sizeof(uint32_t);
|
||||
}
|
||||
y1 = (const uint8_t *) y4;
|
||||
z1 = (uint8_t *) z4;
|
||||
while (len-- > 0)
|
||||
*z1++ = bit_reverse8(*y1++);
|
||||
#endif
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int one_bits32(uint32_t x)
|
||||
{
|
||||
x = x - ((x >> 1) & 0x55555555);
|
||||
/* We now have 16 2-bit counts */
|
||||
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
|
||||
/* We now have 8 4-bit counts */
|
||||
x = (x + (x >> 4)) & 0x0F0F0F0F;
|
||||
/* We now have 4 8-bit counts */
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__powerpc__)
|
||||
/* If multiply is fast */
|
||||
return (x*0x01010101) >> 24;
|
||||
#else
|
||||
/* If multiply is slow */
|
||||
x += (x >> 8);
|
||||
x += (x >> 16);
|
||||
return (x & 0x0000003F);
|
||||
#endif
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
uint32_t make_mask32(uint32_t x)
|
||||
{
|
||||
x |= (x >> 1);
|
||||
x |= (x >> 2);
|
||||
x |= (x >> 4);
|
||||
x |= (x >> 8);
|
||||
x |= (x >> 16);
|
||||
return x;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
uint16_t make_mask16(uint16_t x)
|
||||
{
|
||||
x |= (x >> 1);
|
||||
x |= (x >> 2);
|
||||
x |= (x >> 4);
|
||||
x |= (x >> 8);
|
||||
return x;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* bitstream.c - Bitstream composition and decomposition routines.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.13 2008/05/13 13:17:22 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/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 ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* complex_filters.c
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 GNU Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: complex_filters.c,v 1.13 2008/05/13 13:17:22 steveu Exp $
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "spandsp/complex.h"
|
||||
#include "spandsp/complex_filters.h"
|
||||
|
||||
filter_t *filter_create(fspec_t *fs)
|
||||
{
|
||||
int i;
|
||||
filter_t *fi;
|
||||
|
||||
if ((fi = (filter_t *) malloc(sizeof(*fi) + sizeof(float)*(fs->np + 1))))
|
||||
{
|
||||
fi->fs = fs;
|
||||
fi->sum = 0.0;
|
||||
/* Moving average filters only */
|
||||
fi->ptr = 0;
|
||||
for (i = 0; i <= fi->fs->np; i++)
|
||||
fi->v[i] = 0.0;
|
||||
}
|
||||
return fi;
|
||||
}
|
||||
|
||||
void filter_delete(filter_t *fi)
|
||||
{
|
||||
if (fi)
|
||||
free(fi);
|
||||
}
|
||||
|
||||
float filter_step(filter_t *fi, float x)
|
||||
{
|
||||
return fi->fs->fsf(fi, x);
|
||||
}
|
||||
|
||||
cfilter_t *cfilter_create(fspec_t *fs)
|
||||
{
|
||||
cfilter_t *cfi;
|
||||
|
||||
if ((cfi = (cfilter_t *) malloc(sizeof(*cfi))))
|
||||
{
|
||||
if ((cfi->ref = filter_create(fs)) == NULL)
|
||||
{
|
||||
free(cfi);
|
||||
return NULL;
|
||||
}
|
||||
if ((cfi->imf = filter_create(fs)) == NULL)
|
||||
{
|
||||
free(cfi->ref);
|
||||
free(cfi);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return cfi;
|
||||
}
|
||||
|
||||
void cfilter_delete(cfilter_t *cfi)
|
||||
{
|
||||
if (cfi)
|
||||
{
|
||||
filter_delete(cfi->ref);
|
||||
filter_delete(cfi->imf);
|
||||
}
|
||||
}
|
||||
|
||||
complexf_t cfilter_step(cfilter_t *cfi, const complexf_t *z)
|
||||
{
|
||||
complexf_t cc;
|
||||
|
||||
cc.re = filter_step(cfi->ref, z->re);
|
||||
cc.im = filter_step(cfi->imf, z->im);
|
||||
return cc;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* vector_float.c - Floating vector arithmetic routines.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: complex_vector_float.c,v 1.8 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/logging.h"
|
||||
#include "spandsp/complex.h"
|
||||
#include "spandsp/vector_float.h"
|
||||
#include "spandsp/complex_vector_float.h"
|
||||
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* crc.c
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 GNU Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: crc.c,v 1.4 2008/05/13 13:17:22 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/crc.h"
|
||||
#include "spandsp/bit_operations.h"
|
||||
|
||||
static const uint32_t crc_itu32_table[] =
|
||||
{
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
|
||||
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
|
||||
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
|
||||
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
|
||||
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
|
||||
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
|
||||
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
|
||||
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
|
||||
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
|
||||
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
|
||||
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
|
||||
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
|
||||
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
|
||||
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
|
||||
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
|
||||
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
|
||||
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
|
||||
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
|
||||
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
|
||||
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
|
||||
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
|
||||
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
|
||||
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
||||
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
|
||||
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
|
||||
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
|
||||
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
|
||||
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
|
||||
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
|
||||
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
|
||||
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
|
||||
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
|
||||
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||
};
|
||||
|
||||
uint32_t crc_itu32_calc(const uint8_t *buf, int len, uint32_t crc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_itu32_table[(crc ^ buf[i]) & 0xFF];
|
||||
return crc;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int crc_itu32_append(uint8_t *buf, int len)
|
||||
{
|
||||
uint32_t crc;
|
||||
int new_len;
|
||||
int i;
|
||||
|
||||
crc = 0xFFFFFFFF;
|
||||
new_len = len + 4;
|
||||
for (i = 0; i < len; i++)
|
||||
crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_itu32_table[(crc ^ buf[i]) & 0xFF];
|
||||
crc ^= 0xFFFFFFFF;
|
||||
buf[i++] = (uint8_t) crc;
|
||||
buf[i++] = (uint8_t) (crc >> 8);
|
||||
buf[i++] = (uint8_t) (crc >> 16);
|
||||
buf[i++] = (uint8_t) (crc >> 24);
|
||||
return new_len;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int crc_itu32_check(const uint8_t *buf, int len)
|
||||
{
|
||||
uint32_t crc;
|
||||
int i;
|
||||
|
||||
crc = 0xFFFFFFFF;
|
||||
for (i = 0; i < len; i++)
|
||||
crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_itu32_table[(crc ^ buf[i]) & 0xFF];
|
||||
return (crc == 0xDEBB20E3);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static const uint16_t crc_itu16_table[] =
|
||||
{
|
||||
0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
|
||||
0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
|
||||
0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
|
||||
0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
|
||||
0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
|
||||
0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
|
||||
0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
|
||||
0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
|
||||
0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
|
||||
0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
|
||||
0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
|
||||
0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
|
||||
0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
|
||||
0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
|
||||
0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
|
||||
0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
|
||||
0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
|
||||
0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
|
||||
0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
|
||||
0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
|
||||
0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
|
||||
0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
|
||||
0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
|
||||
0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
|
||||
0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
|
||||
0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
|
||||
0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
|
||||
0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
|
||||
0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
|
||||
0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
|
||||
0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
|
||||
0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
|
||||
};
|
||||
|
||||
uint16_t crc_itu16_calc(const uint8_t *buf, int len, uint16_t crc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
crc = (crc >> 8) ^ crc_itu16_table[(crc ^ buf[i]) & 0xFF];
|
||||
return crc;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int crc_itu16_append(uint8_t *buf, int len)
|
||||
{
|
||||
uint16_t crc;
|
||||
int new_len;
|
||||
int i;
|
||||
|
||||
crc = 0xFFFF;
|
||||
new_len = len + 2;
|
||||
for (i = 0; i < len; i++)
|
||||
crc = (crc >> 8) ^ crc_itu16_table[(crc ^ buf[i]) & 0xFF];
|
||||
crc ^= 0xFFFF;
|
||||
buf[i++] = (uint8_t) crc;
|
||||
buf[i++] = (uint8_t) (crc >> 8);
|
||||
return new_len;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int crc_itu16_check(const uint8_t *buf, int len)
|
||||
{
|
||||
uint16_t crc;
|
||||
int i;
|
||||
|
||||
crc = 0xFFFF;
|
||||
for (i = 0; i < len; i++)
|
||||
crc = (crc >> 8) ^ crc_itu16_table[(crc ^ buf[i]) & 0xFF];
|
||||
return (crc & 0xFFFF) == 0xF0B8;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* dds.c
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 GNU Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: dds_int.c,v 1.9 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/complex.h"
|
||||
#include "spandsp/dds.h"
|
||||
|
||||
#if !defined(M_PI)
|
||||
# define M_PI 3.14159265358979323846 /* pi */
|
||||
#endif
|
||||
|
||||
/* In a A-law or u-law channel, a 128 step sine table is adequate to keep the spectral
|
||||
mess due to the DDS at a similar level to the spectral mess due to the A-law or u-law
|
||||
compression. */
|
||||
#define SLENK 7
|
||||
#define DDS_STEPS (1 << SLENK)
|
||||
#define DDS_SHIFT (32 - 2 - SLENK)
|
||||
|
||||
/* This is a simple set of direct digital synthesis (DDS) functions to generate sine
|
||||
waves. This version uses a 128 entry sin/cos table to cover one quadrant. */
|
||||
|
||||
static const int16_t sine_table[DDS_STEPS] =
|
||||
{
|
||||
201,
|
||||
603,
|
||||
1005,
|
||||
1407,
|
||||
1809,
|
||||
2210,
|
||||
2611,
|
||||
3012,
|
||||
3412,
|
||||
3812,
|
||||
4211,
|
||||
4609,
|
||||
5007,
|
||||
5404,
|
||||
5800,
|
||||
6195,
|
||||
6590,
|
||||
6983,
|
||||
7376,
|
||||
7767,
|
||||
8157,
|
||||
8546,
|
||||
8933,
|
||||
9319,
|
||||
9704,
|
||||
10088,
|
||||
10469,
|
||||
10850,
|
||||
11228,
|
||||
11605,
|
||||
11980,
|
||||
12354,
|
||||
12725,
|
||||
13095,
|
||||
13463,
|
||||
13828,
|
||||
14192,
|
||||
14553,
|
||||
14912,
|
||||
15269,
|
||||
15624,
|
||||
15976,
|
||||
16326,
|
||||
16673,
|
||||
17018,
|
||||
17361,
|
||||
17700,
|
||||
18037,
|
||||
18372,
|
||||
18703,
|
||||
19032,
|
||||
19358,
|
||||
19681,
|
||||
20001,
|
||||
20318,
|
||||
20632,
|
||||
20943,
|
||||
21251,
|
||||
21555,
|
||||
21856,
|
||||
22154,
|
||||
22449,
|
||||
22740,
|
||||
23028,
|
||||
23312,
|
||||
23593,
|
||||
23870,
|
||||
24144,
|
||||
24414,
|
||||
24680,
|
||||
24943,
|
||||
25202,
|
||||
25457,
|
||||
25708,
|
||||
25956,
|
||||
26199,
|
||||
26439,
|
||||
26674,
|
||||
26906,
|
||||
27133,
|
||||
27357,
|
||||
27576,
|
||||
27791,
|
||||
28002,
|
||||
28209,
|
||||
28411,
|
||||
28610,
|
||||
28803,
|
||||
28993,
|
||||
29178,
|
||||
29359,
|
||||
29535,
|
||||
29707,
|
||||
29875,
|
||||
30038,
|
||||
30196,
|
||||
30350,
|
||||
30499,
|
||||
30644,
|
||||
30784,
|
||||
30920,
|
||||
31050,
|
||||
31177,
|
||||
31298,
|
||||
31415,
|
||||
31527,
|
||||
31634,
|
||||
31737,
|
||||
31834,
|
||||
31927,
|
||||
32015,
|
||||
32099,
|
||||
32177,
|
||||
32251,
|
||||
32319,
|
||||
32383,
|
||||
32442,
|
||||
32496,
|
||||
32546,
|
||||
32590,
|
||||
32629,
|
||||
32664,
|
||||
32693,
|
||||
32718,
|
||||
32738,
|
||||
32753,
|
||||
32762,
|
||||
32767,
|
||||
};
|
||||
|
||||
int32_t dds_phase_rate(float frequency)
|
||||
{
|
||||
return (int32_t) (frequency*65536.0f*65536.0f/SAMPLE_RATE);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
float dds_frequency(int32_t phase_rate)
|
||||
{
|
||||
return (float) phase_rate*(float) SAMPLE_RATE/(65536.0f*65536.0f);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int dds_scaling_dbm0(float level)
|
||||
{
|
||||
return (int) (powf(10.0f, (level - DBM0_MAX_SINE_POWER)/20.0f)*32767.0f);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int dds_scaling_dbov(float level)
|
||||
{
|
||||
return (int) (powf(10.0f, (level - DBOV_MAX_SINE_POWER)/20.0f)*32767.0f);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int16_t dds_lookup(uint32_t phase)
|
||||
{
|
||||
uint32_t step;
|
||||
int16_t amp;
|
||||
|
||||
phase >>= DDS_SHIFT;
|
||||
step = phase & (DDS_STEPS - 1);
|
||||
if ((phase & DDS_STEPS))
|
||||
step = (DDS_STEPS - 1) - step;
|
||||
amp = sine_table[step];
|
||||
if ((phase & (2*DDS_STEPS)))
|
||||
amp = -amp;
|
||||
return amp;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int16_t dds_offset(uint32_t phase_acc, int32_t phase_offset)
|
||||
{
|
||||
return dds_lookup(phase_acc + phase_offset);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void dds_advance(uint32_t *phase_acc, int32_t phase_rate)
|
||||
{
|
||||
*phase_acc += phase_rate;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int16_t dds(uint32_t *phase_acc, int32_t phase_rate)
|
||||
{
|
||||
int16_t amp;
|
||||
|
||||
amp = dds_lookup(*phase_acc);
|
||||
*phase_acc += phase_rate;
|
||||
return amp;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int16_t dds_mod(uint32_t *phase_acc, int32_t phase_rate, int scale, int32_t phase)
|
||||
{
|
||||
int16_t amp;
|
||||
|
||||
amp = (int16_t) ((dds_lookup(*phase_acc + phase)*scale) >> 15);
|
||||
*phase_acc += phase_rate;
|
||||
return amp;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
complexi_t dds_lookup_complexi(uint32_t phase)
|
||||
{
|
||||
return complex_seti(dds_lookup(phase + (1 << 30)), dds_lookup(phase));
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
complexi_t dds_complexi(uint32_t *phase_acc, int32_t phase_rate)
|
||||
{
|
||||
complexi_t amp;
|
||||
|
||||
amp = complex_seti(dds_lookup(*phase_acc + (1 << 30)), dds_lookup(*phase_acc));
|
||||
*phase_acc += phase_rate;
|
||||
return amp;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
complexi_t dds_complexi_mod(uint32_t *phase_acc, int32_t phase_rate, int scale, int32_t phase)
|
||||
{
|
||||
complexi_t amp;
|
||||
|
||||
amp = complex_seti((dds_lookup(*phase_acc + phase + (1 << 30))*scale) >> 15,
|
||||
(dds_lookup(*phase_acc + phase)*scale) >> 15);
|
||||
*phase_acc += phase_rate;
|
||||
return amp;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,530 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* dtmf.c - DTMF generation and detection.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2001-2003, 2005, 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: dtmf.c,v 1.43 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file dtmf.h */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/queue.h"
|
||||
#include "spandsp/complex.h"
|
||||
#include "spandsp/dds.h"
|
||||
#include "spandsp/tone_detect.h"
|
||||
#include "spandsp/tone_generate.h"
|
||||
#include "spandsp/super_tone_rx.h"
|
||||
#include "spandsp/dtmf.h"
|
||||
|
||||
#define DEFAULT_DTMF_TX_LEVEL -10
|
||||
#define DEFAULT_DTMF_TX_ON_TIME 50
|
||||
#define DEFAULT_DTMF_TX_OFF_TIME 55
|
||||
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
#define DTMF_THRESHOLD 10438 /* -42dBm0 */
|
||||
#define DTMF_NORMAL_TWIST 6.309f /* 8dB */
|
||||
#define DTMF_REVERSE_TWIST 2.512f /* 4dB */
|
||||
#define DTMF_RELATIVE_PEAK_ROW 6.309f /* 8dB */
|
||||
#define DTMF_RELATIVE_PEAK_COL 6.309f /* 8dB */
|
||||
#define DTMF_TO_TOTAL_ENERGY 83.868f /* -0.85dB */
|
||||
#define DTMF_POWER_OFFSET 68.251f /* 10*log(256.0*256.0*DTMF_SAMPLES_PER_BLOCK) */
|
||||
#define DTMF_SAMPLES_PER_BLOCK 102
|
||||
#else
|
||||
#define DTMF_THRESHOLD 171032462.0f /* -42dBm0 [((DTMF_SAMPLES_PER_BLOCK*32768.0/1.4142)*10^((-42 - DBM0_MAX_SINE_POWER)/20.0))^2 => 171032462.0] */
|
||||
#define DTMF_NORMAL_TWIST 6.309f /* 8dB [10^(8/10) => 6.309] */
|
||||
#define DTMF_REVERSE_TWIST 2.512f /* 4dB */
|
||||
#define DTMF_RELATIVE_PEAK_ROW 6.309f /* 8dB */
|
||||
#define DTMF_RELATIVE_PEAK_COL 6.309f /* 8dB */
|
||||
#define DTMF_TO_TOTAL_ENERGY 83.868f /* -0.85dB [DTMF_SAMPLES_PER_BLOCK*10^(-0.85/10.0)] */
|
||||
#define DTMF_POWER_OFFSET 110.395f /* 10*log(32768.0*32768.0*DTMF_SAMPLES_PER_BLOCK) */
|
||||
#define DTMF_SAMPLES_PER_BLOCK 102
|
||||
#endif
|
||||
|
||||
static const float dtmf_row[] =
|
||||
{
|
||||
697.0f, 770.0f, 852.0f, 941.0f
|
||||
};
|
||||
static const float dtmf_col[] =
|
||||
{
|
||||
1209.0f, 1336.0f, 1477.0f, 1633.0f
|
||||
};
|
||||
|
||||
static const char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
|
||||
|
||||
static goertzel_descriptor_t dtmf_detect_row[4];
|
||||
static goertzel_descriptor_t dtmf_detect_col[4];
|
||||
|
||||
static int dtmf_tx_inited = FALSE;
|
||||
static tone_gen_descriptor_t dtmf_digit_tones[16];
|
||||
|
||||
int dtmf_rx(dtmf_rx_state_t *s, const int16_t amp[], int samples)
|
||||
{
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
int32_t row_energy[4];
|
||||
int32_t col_energy[4];
|
||||
int16_t xamp;
|
||||
float famp;
|
||||
#else
|
||||
float row_energy[4];
|
||||
float col_energy[4];
|
||||
float xamp;
|
||||
float famp;
|
||||
#endif
|
||||
float v1;
|
||||
int i;
|
||||
int j;
|
||||
int sample;
|
||||
int best_row;
|
||||
int best_col;
|
||||
int limit;
|
||||
uint8_t hit;
|
||||
|
||||
hit = 0;
|
||||
for (sample = 0; sample < samples; sample = limit)
|
||||
{
|
||||
/* The block length is optimised to meet the DTMF specs. */
|
||||
if ((samples - sample) >= (DTMF_SAMPLES_PER_BLOCK - s->current_sample))
|
||||
limit = sample + (DTMF_SAMPLES_PER_BLOCK - s->current_sample);
|
||||
else
|
||||
limit = samples;
|
||||
/* The following unrolled loop takes only 35% (rough estimate) of the
|
||||
time of a rolled loop on the machine on which it was developed */
|
||||
for (j = sample; j < limit; j++)
|
||||
{
|
||||
xamp = amp[j];
|
||||
if (s->filter_dialtone)
|
||||
{
|
||||
famp = xamp;
|
||||
/* Sharp notches applied at 350Hz and 440Hz - the two common dialtone frequencies.
|
||||
These are rather high Q, to achieve the required narrowness, without using lots of
|
||||
sections. */
|
||||
v1 = 0.98356f*famp + 1.8954426f*s->z350[0] - 0.9691396f*s->z350[1];
|
||||
famp = v1 - 1.9251480f*s->z350[0] + s->z350[1];
|
||||
s->z350[1] = s->z350[0];
|
||||
s->z350[0] = v1;
|
||||
|
||||
v1 = 0.98456f*famp + 1.8529543f*s->z440[0] - 0.9691396f*s->z440[1];
|
||||
famp = v1 - 1.8819938f*s->z440[0] + s->z440[1];
|
||||
s->z440[1] = s->z440[0];
|
||||
s->z440[0] = v1;
|
||||
xamp = famp;
|
||||
}
|
||||
xamp = goertzel_preadjust_amp(xamp);
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
s->energy += ((int32_t) xamp*xamp);
|
||||
#else
|
||||
s->energy += xamp*xamp;
|
||||
#endif
|
||||
goertzel_samplex(&s->row_out[0], xamp);
|
||||
goertzel_samplex(&s->col_out[0], xamp);
|
||||
goertzel_samplex(&s->row_out[1], xamp);
|
||||
goertzel_samplex(&s->col_out[1], xamp);
|
||||
goertzel_samplex(&s->row_out[2], xamp);
|
||||
goertzel_samplex(&s->col_out[2], xamp);
|
||||
goertzel_samplex(&s->row_out[3], xamp);
|
||||
goertzel_samplex(&s->col_out[3], xamp);
|
||||
}
|
||||
s->current_sample += (limit - sample);
|
||||
if (s->current_sample < DTMF_SAMPLES_PER_BLOCK)
|
||||
continue;
|
||||
|
||||
/* We are at the end of a DTMF detection block */
|
||||
/* Find the peak row and the peak column */
|
||||
row_energy[0] = goertzel_result(&s->row_out[0]);
|
||||
best_row = 0;
|
||||
col_energy[0] = goertzel_result(&s->col_out[0]);
|
||||
best_col = 0;
|
||||
for (i = 1; i < 4; i++)
|
||||
{
|
||||
row_energy[i] = goertzel_result(&s->row_out[i]);
|
||||
if (row_energy[i] > row_energy[best_row])
|
||||
best_row = i;
|
||||
col_energy[i] = goertzel_result(&s->col_out[i]);
|
||||
if (col_energy[i] > col_energy[best_col])
|
||||
best_col = i;
|
||||
}
|
||||
hit = 0;
|
||||
/* Basic signal level test and the twist test */
|
||||
if (row_energy[best_row] >= s->threshold
|
||||
&&
|
||||
col_energy[best_col] >= s->threshold
|
||||
&&
|
||||
col_energy[best_col] < row_energy[best_row]*s->reverse_twist
|
||||
&&
|
||||
col_energy[best_col]*s->normal_twist > row_energy[best_row])
|
||||
{
|
||||
/* Relative peak test ... */
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if ((i != best_col && col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col])
|
||||
||
|
||||
(i != best_row && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* ... and fraction of total energy test */
|
||||
if (i >= 4
|
||||
&&
|
||||
(row_energy[best_row] + col_energy[best_col]) > DTMF_TO_TOTAL_ENERGY*s->energy)
|
||||
{
|
||||
/* Got a hit */
|
||||
hit = dtmf_positions[(best_row << 2) + best_col];
|
||||
}
|
||||
}
|
||||
/* The logic in the next test should ensure the following for different successive hit patterns:
|
||||
-----ABB = start of digit B.
|
||||
----B-BB = start of digit B
|
||||
----A-BB = start of digit B
|
||||
BBBBBABB = still in digit B.
|
||||
BBBBBB-- = end of digit B
|
||||
BBBBBBC- = end of digit B
|
||||
BBBBACBB = B ends, then B starts again.
|
||||
BBBBBBCC = B ends, then C starts.
|
||||
BBBBBCDD = B ends, then D starts.
|
||||
This can work with:
|
||||
- Back to back differing digits. Back-to-back digits should
|
||||
not happen. The spec. says there should be a gap between digits.
|
||||
However, many real phones do not impose a gap, and rolling across
|
||||
the keypad can produce little or no gap.
|
||||
- It tolerates nasty phones that give a very wobbly start to a digit.
|
||||
- VoIP can give sample slips. The phase jumps that produces will cause
|
||||
the block it is in to give no detection. This logic will ride over a
|
||||
single missed block, and not falsely declare a second digit. If the
|
||||
hiccup happens in the wrong place on a minimum length digit, however
|
||||
we would still fail to detect that digit. Could anything be done to
|
||||
deal with that? Packet loss is clearly a no-go zone.
|
||||
Note this is only relevant to VoIP using A-law, u-law or similar.
|
||||
Low bit rate codecs scramble DTMF too much for it to be recognised,
|
||||
and often slip in units larger than a sample. */
|
||||
if (hit != s->in_digit)
|
||||
{
|
||||
if (s->last_hit != s->in_digit)
|
||||
{
|
||||
/* We have two successive indications that something has changed. */
|
||||
/* To declare digit on, the hits must agree. Otherwise we declare tone off. */
|
||||
hit = (hit && hit == s->last_hit) ? hit : 0;
|
||||
if (s->realtime_callback)
|
||||
{
|
||||
/* Avoid reporting multiple no digit conditions on flaky hits */
|
||||
if (s->in_digit || hit)
|
||||
{
|
||||
i = (s->in_digit && !hit) ? -99 : lrintf(log10f(s->energy)*10.0f - DTMF_POWER_OFFSET + DBM0_MAX_POWER);
|
||||
s->realtime_callback(s->realtime_callback_data, hit, i, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hit)
|
||||
{
|
||||
if (s->current_digits < MAX_DTMF_DIGITS)
|
||||
{
|
||||
s->digits[s->current_digits++] = (char) hit;
|
||||
s->digits[s->current_digits] = '\0';
|
||||
if (s->digits_callback)
|
||||
{
|
||||
s->digits_callback(s->digits_callback_data, s->digits, s->current_digits);
|
||||
s->current_digits = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s->lost_digits++;
|
||||
}
|
||||
}
|
||||
}
|
||||
s->in_digit = hit;
|
||||
}
|
||||
}
|
||||
s->last_hit = hit;
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
s->energy = 0;
|
||||
#else
|
||||
s->energy = 0.0f;
|
||||
#endif
|
||||
s->current_sample = 0;
|
||||
}
|
||||
if (s->current_digits && s->digits_callback)
|
||||
{
|
||||
s->digits_callback(s->digits_callback_data, s->digits, s->current_digits);
|
||||
s->digits[0] = '\0';
|
||||
s->current_digits = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int dtmf_rx_status(dtmf_rx_state_t *s)
|
||||
{
|
||||
if (s->in_digit)
|
||||
return s->in_digit;
|
||||
if (s->last_hit)
|
||||
return 'x';
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
size_t dtmf_rx_get(dtmf_rx_state_t *s, char *buf, int max)
|
||||
{
|
||||
if (max > s->current_digits)
|
||||
max = s->current_digits;
|
||||
if (max > 0)
|
||||
{
|
||||
memcpy(buf, s->digits, max);
|
||||
memmove(s->digits, s->digits + max, s->current_digits - max);
|
||||
s->current_digits -= max;
|
||||
}
|
||||
buf[max] = '\0';
|
||||
return max;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void dtmf_rx_set_realtime_callback(dtmf_rx_state_t *s,
|
||||
tone_report_func_t callback,
|
||||
void *user_data)
|
||||
{
|
||||
s->realtime_callback = callback;
|
||||
s->realtime_callback_data = user_data;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void dtmf_rx_parms(dtmf_rx_state_t *s,
|
||||
int filter_dialtone,
|
||||
int twist,
|
||||
int reverse_twist,
|
||||
int threshold)
|
||||
{
|
||||
float x;
|
||||
|
||||
if (filter_dialtone >= 0)
|
||||
{
|
||||
s->z350[0] = 0.0f;
|
||||
s->z350[1] = 0.0f;
|
||||
s->z440[0] = 0.0f;
|
||||
s->z440[1] = 0.0f;
|
||||
s->filter_dialtone = filter_dialtone;
|
||||
}
|
||||
if (twist >= 0)
|
||||
s->normal_twist = powf(10.0f, twist/10.0f);
|
||||
if (reverse_twist >= 0)
|
||||
s->reverse_twist = powf(10.0f, reverse_twist/10.0f);
|
||||
if (threshold > -99)
|
||||
{
|
||||
x = (DTMF_SAMPLES_PER_BLOCK*32768.0f/1.4142f)*powf(10.0f, (threshold - DBM0_MAX_SINE_POWER)/20.0f);
|
||||
s->threshold = x*x;
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
dtmf_rx_state_t *dtmf_rx_init(dtmf_rx_state_t *s,
|
||||
digits_rx_callback_t callback,
|
||||
void *user_data)
|
||||
{
|
||||
int i;
|
||||
static int initialised = FALSE;
|
||||
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (dtmf_rx_state_t *) malloc(sizeof (*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
s->digits_callback = callback;
|
||||
s->digits_callback_data = user_data;
|
||||
s->realtime_callback = NULL;
|
||||
s->realtime_callback_data = NULL;
|
||||
s->filter_dialtone = FALSE;
|
||||
s->normal_twist = DTMF_NORMAL_TWIST;
|
||||
s->reverse_twist = DTMF_REVERSE_TWIST;
|
||||
s->threshold = DTMF_THRESHOLD;
|
||||
|
||||
s->in_digit = 0;
|
||||
s->last_hit = 0;
|
||||
|
||||
if (!initialised)
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
make_goertzel_descriptor(&dtmf_detect_row[i], dtmf_row[i], DTMF_SAMPLES_PER_BLOCK);
|
||||
make_goertzel_descriptor(&dtmf_detect_col[i], dtmf_col[i], DTMF_SAMPLES_PER_BLOCK);
|
||||
}
|
||||
initialised = TRUE;
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
goertzel_init(&s->row_out[i], &dtmf_detect_row[i]);
|
||||
goertzel_init(&s->col_out[i], &dtmf_detect_col[i]);
|
||||
}
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
s->energy = 0;
|
||||
#else
|
||||
s->energy = 0.0f;
|
||||
#endif
|
||||
s->current_sample = 0;
|
||||
s->lost_digits = 0;
|
||||
s->current_digits = 0;
|
||||
s->digits[0] = '\0';
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int dtmf_rx_free(dtmf_rx_state_t *s)
|
||||
{
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void dtmf_tx_initialise(void)
|
||||
{
|
||||
int row;
|
||||
int col;
|
||||
|
||||
if (dtmf_tx_inited)
|
||||
return;
|
||||
for (row = 0; row < 4; row++)
|
||||
{
|
||||
for (col = 0; col < 4; col++)
|
||||
{
|
||||
make_tone_gen_descriptor(&dtmf_digit_tones[row*4 + col],
|
||||
(int) dtmf_row[row],
|
||||
DEFAULT_DTMF_TX_LEVEL,
|
||||
(int) dtmf_col[col],
|
||||
DEFAULT_DTMF_TX_LEVEL,
|
||||
DEFAULT_DTMF_TX_ON_TIME,
|
||||
DEFAULT_DTMF_TX_OFF_TIME,
|
||||
0,
|
||||
0,
|
||||
FALSE);
|
||||
}
|
||||
}
|
||||
dtmf_tx_inited = TRUE;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int dtmf_tx(dtmf_tx_state_t *s, int16_t amp[], int max_samples)
|
||||
{
|
||||
int len;
|
||||
const char *cp;
|
||||
int digit;
|
||||
|
||||
len = 0;
|
||||
if (s->tones.current_section >= 0)
|
||||
{
|
||||
/* Deal with the fragment left over from last time */
|
||||
len = tone_gen(&(s->tones), amp, max_samples);
|
||||
}
|
||||
while (len < max_samples && (digit = queue_read_byte(&s->queue.queue)) >= 0)
|
||||
{
|
||||
/* Step to the next digit */
|
||||
if (digit == 0)
|
||||
continue;
|
||||
if ((cp = strchr(dtmf_positions, digit)) == NULL)
|
||||
continue;
|
||||
tone_gen_init(&(s->tones), &dtmf_digit_tones[cp - dtmf_positions]);
|
||||
s->tones.tone[0].gain = s->low_level;
|
||||
s->tones.tone[1].gain = s->high_level;
|
||||
s->tones.duration[0] = s->on_time;
|
||||
s->tones.duration[1] = s->off_time;
|
||||
len += tone_gen(&(s->tones), amp + len, max_samples - len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
size_t dtmf_tx_put(dtmf_tx_state_t *s, const char *digits, int len)
|
||||
{
|
||||
size_t space;
|
||||
|
||||
/* This returns the number of characters that would not fit in the buffer.
|
||||
The buffer will only be loaded if the whole string of digits will fit,
|
||||
in which case zero is returned. */
|
||||
if (len < 0)
|
||||
{
|
||||
if ((len = strlen(digits)) == 0)
|
||||
return 0;
|
||||
}
|
||||
if ((space = queue_free_space(&s->queue.queue)) < len)
|
||||
return len - space;
|
||||
if (queue_write(&s->queue.queue, (const uint8_t *) digits, len) >= 0)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void dtmf_tx_set_level(dtmf_tx_state_t *s, int level, int twist)
|
||||
{
|
||||
s->low_level = dds_scaling_dbm0f((float) level);
|
||||
s->high_level = dds_scaling_dbm0f((float) (level + twist));
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void dtmf_tx_set_timing(dtmf_tx_state_t *s, int on_time, int off_time)
|
||||
{
|
||||
s->on_time = ((on_time >= 0) ? on_time : DEFAULT_DTMF_TX_ON_TIME)*SAMPLE_RATE/1000;
|
||||
s->off_time = ((off_time >= 0) ? off_time : DEFAULT_DTMF_TX_OFF_TIME)*SAMPLE_RATE/1000;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
dtmf_tx_state_t *dtmf_tx_init(dtmf_tx_state_t *s)
|
||||
{
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (dtmf_tx_state_t *) malloc(sizeof (*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
if (!dtmf_tx_inited)
|
||||
dtmf_tx_initialise();
|
||||
tone_gen_init(&(s->tones), &dtmf_digit_tones[0]);
|
||||
dtmf_tx_set_level(s, DEFAULT_DTMF_TX_LEVEL, 0);
|
||||
dtmf_tx_set_timing(s, -1, -1);
|
||||
queue_init(&s->queue.queue, MAX_DTMF_DIGITS, QUEUE_READ_ATOMIC | QUEUE_WRITE_ATOMIC);
|
||||
s->tones.current_section = -1;
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int dtmf_tx_free(dtmf_tx_state_t *s)
|
||||
{
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,612 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* echo.c - An echo cancellor, suitable for electrical and acoustic
|
||||
* cancellation. This code does not currently comply with
|
||||
* any relevant standards (e.g. G.164/5/7/8). One day....
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2001, 2003 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 GNU Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: echo.c,v 1.27 2008/08/29 09:28:13 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
/* TODO:
|
||||
Finish the echo suppressor option, however nasty suppression may be.
|
||||
Add an option to reintroduce side tone at -24dB under appropriate conditions.
|
||||
Improve double talk detector (iterative!)
|
||||
*/
|
||||
|
||||
/* We need to differentiate between transmitted energy which will train the echo
|
||||
canceller well (voice, white noise, and other broadband sources) and energy
|
||||
which will train it badly (supervisory tones, DTMF, whistles, and other
|
||||
narrowband sources). There are many ways this might be done. This canceller uses
|
||||
a method based on the autocorrelation qualities of the transmitted signal. A rather
|
||||
peaky autocorrelation function is a clear sign of a narrowband signal. We only need
|
||||
perform the autocorrelation at well spaced intervals, so the compute load is not too
|
||||
great. Multiple successive autocorrelation functions with a similar peaky shape are a
|
||||
clear indication of a stationary narrowband signal. Using TKEO, it should be possible to
|
||||
greatly reduce the compute requirement for narrowband detection. */
|
||||
|
||||
/* The FIR taps must be adapted as 32 bit values, to get the necessary finesse
|
||||
in the adaption process. However, they are applied as 16 bit values (bits 30-15
|
||||
of the 32 bit values) in the FIR. For the working 16 bit values, we need 4 sets.
|
||||
|
||||
3 of the 16 bit sets are used on a rotating basis. Normally the canceller steps
|
||||
round these 3 sets at regular intervals. Any time we detect double talk, we can go
|
||||
back to the set from two steps ago with reasonable assurance it is a well adapted
|
||||
set. We cannot just go back one step, as we may have rotated the sets just before
|
||||
double talk or tone was detected, and that set may already be somewhat corrupted.
|
||||
|
||||
When narrowband energy is detected we need to continue adapting to it, to echo
|
||||
cancel it. However, the adaption will almost certainly be going astray. Broadband
|
||||
(or even complex sequences of narrowband) energy will normally lead to a well
|
||||
trained cancellor, with taps matching the impulse response of the channel.
|
||||
For stationary narrowband energy, there is usually has an infinite number of
|
||||
alternative tap sets which will cancel it well. A previously well trained set of
|
||||
taps will tend to drift amongst the alternatives. When broadband energy resumes, the
|
||||
taps may be a total mismatch for the signal, and could even amplify rather than
|
||||
attenuate the echo. The solution is to use a fourth set of 16 bit taps. When we first
|
||||
detect the narrowband energy we save the oldest of the group of three sets, but do
|
||||
not change back to an older set. We let the canceller cancel, and it adaption drift
|
||||
while the narrowband energy is present. When we detect the narrowband energy has ceased,
|
||||
we switch to using the fourth set of taps which was saved.
|
||||
|
||||
When we revert to an older set of taps, we must replace both the 16 bit and 32 bit
|
||||
working tap sets. The saved 16 bit values are good enough to also be used as a replacement
|
||||
for the 32 bit values. We loose the fractions, but they should soon settle down in a
|
||||
reasonable way. */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/logging.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/bit_operations.h"
|
||||
#include "spandsp/echo.h"
|
||||
|
||||
#if !defined(NULL)
|
||||
#define NULL (void *) 0
|
||||
#endif
|
||||
#if !defined(FALSE)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#if !defined(TRUE)
|
||||
#define TRUE (!FALSE)
|
||||
#endif
|
||||
|
||||
#define NONUPDATE_DWELL_TIME 600 /* 600 samples, or 75ms */
|
||||
|
||||
#define MIN_TX_POWER_FOR_ADAPTION 64*64
|
||||
#define MIN_RX_POWER_FOR_ADAPTION 64*64
|
||||
|
||||
static int narrowband_detect(echo_can_state_t *ec)
|
||||
{
|
||||
int k;
|
||||
int i;
|
||||
float temp;
|
||||
float scale;
|
||||
float sf[128];
|
||||
float f_acf[128];
|
||||
int32_t acf[28];
|
||||
int score;
|
||||
int len = 32;
|
||||
int alen = 9;
|
||||
|
||||
k = ec->curr_pos;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
sf[i] = ec->fir_state.history[k++];
|
||||
if (k >= 256)
|
||||
k = 0;
|
||||
}
|
||||
for (k = 0; k < alen; k++)
|
||||
{
|
||||
temp = 0;
|
||||
for (i = k; i < len; i++)
|
||||
temp += sf[i]*sf[i - k];
|
||||
f_acf[k] = temp;
|
||||
}
|
||||
scale = 0x1FFFFFFF/f_acf[0];
|
||||
for (k = 0; k < alen; k++)
|
||||
acf[k] = (int32_t) (f_acf[k]*scale);
|
||||
score = 0;
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
if (ec->last_acf[i] >= 0 && acf[i] >= 0)
|
||||
{
|
||||
if ((ec->last_acf[i] >> 1) < acf[i] && acf[i] < (ec->last_acf[i] << 1))
|
||||
score++;
|
||||
}
|
||||
else if (ec->last_acf[i] < 0 && acf[i] < 0)
|
||||
{
|
||||
if ((ec->last_acf[i] >> 1) > acf[i] && acf[i] > (ec->last_acf[i] << 1))
|
||||
score++;
|
||||
}
|
||||
}
|
||||
memcpy(ec->last_acf, acf, alen*sizeof(ec->last_acf[0]));
|
||||
return score;
|
||||
}
|
||||
|
||||
static __inline__ void lms_adapt(echo_can_state_t *ec, int factor)
|
||||
{
|
||||
int i;
|
||||
|
||||
#if 0
|
||||
mmx_t *mmx_taps;
|
||||
mmx_t *mmx_coeffs;
|
||||
mmx_t *mmx_hist;
|
||||
mmx_t mmx;
|
||||
|
||||
mmx.w[0] =
|
||||
mmx.w[1] =
|
||||
mmx.w[2] =
|
||||
mmx.w[3] = factor;
|
||||
mmx_hist = (mmx_t *) &fir->history[fir->curr_pos];
|
||||
mmx_taps = (mmx_t *) &fir->taps;
|
||||
mmx_coeffs = (mmx_t *) fir->coeffs;
|
||||
i = fir->taps;
|
||||
movq_m2r(mmx, mm0);
|
||||
while (i > 0)
|
||||
{
|
||||
movq_m2r(mmx_hist[0], mm1);
|
||||
movq_m2r(mmx_taps[0], mm0);
|
||||
movq_m2r(mmx_taps[1], mm1);
|
||||
movq_r2r(mm1, mm2);
|
||||
pmulhw(mm0, mm1);
|
||||
pmullw(mm0, mm2);
|
||||
|
||||
pmaddwd_r2r(mm1, mm0);
|
||||
pmaddwd_r2r(mm3, mm2);
|
||||
paddd_r2r(mm0, mm4);
|
||||
paddd_r2r(mm2, mm4);
|
||||
movq_r2m(mm0, mmx_taps[0]);
|
||||
movq_r2m(mm1, mmx_taps[0]);
|
||||
movq_r2m(mm2, mmx_coeffs[0]);
|
||||
mmx_taps += 2;
|
||||
mmx_coeffs += 1;
|
||||
mmx_hist += 1;
|
||||
i -= 4;
|
||||
)
|
||||
emms();
|
||||
#elif 0
|
||||
/* Update the FIR taps */
|
||||
for (i = ec->taps - 1; i >= 0; i--)
|
||||
{
|
||||
/* Leak to avoid the coefficients drifting beyond the ability of the
|
||||
adaption process to bring them back under control. */
|
||||
ec->fir_taps32[i] -= (ec->fir_taps32[i] >> 23);
|
||||
ec->fir_taps32[i] += (ec->fir_state.history[i + ec->curr_pos]*factor);
|
||||
ec->latest_correction = (ec->fir_state.history[i + ec->curr_pos]*factor);
|
||||
ec->fir_taps16[ec->tap_set][i] = ec->fir_taps32[i] >> 15;
|
||||
}
|
||||
#else
|
||||
int offset1;
|
||||
int offset2;
|
||||
|
||||
/* Update the FIR taps */
|
||||
offset2 = ec->curr_pos;
|
||||
offset1 = ec->taps - offset2;
|
||||
for (i = ec->taps - 1; i >= offset1; i--)
|
||||
{
|
||||
ec->fir_taps32[i] += (ec->fir_state.history[i - offset1]*factor);
|
||||
ec->fir_taps16[ec->tap_set][i] = (int16_t) (ec->fir_taps32[i] >> 15);
|
||||
}
|
||||
for ( ; i >= 0; i--)
|
||||
{
|
||||
ec->fir_taps32[i] += (ec->fir_state.history[i + offset2]*factor);
|
||||
ec->fir_taps16[ec->tap_set][i] = (int16_t) (ec->fir_taps32[i] >> 15);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
echo_can_state_t *echo_can_create(int len, int adaption_mode)
|
||||
{
|
||||
echo_can_state_t *ec;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
if ((ec = (echo_can_state_t *) malloc(sizeof(*ec))) == NULL)
|
||||
return NULL;
|
||||
memset(ec, 0, sizeof(*ec));
|
||||
ec->taps = len;
|
||||
ec->curr_pos = ec->taps - 1;
|
||||
ec->tap_mask = ec->taps - 1;
|
||||
if ((ec->fir_taps32 = (int32_t *) malloc(ec->taps*sizeof(int32_t))) == NULL)
|
||||
{
|
||||
free(ec);
|
||||
return NULL;
|
||||
}
|
||||
memset(ec->fir_taps32, 0, ec->taps*sizeof(int32_t));
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if ((ec->fir_taps16[i] = (int16_t *) malloc(ec->taps*sizeof(int16_t))) == NULL)
|
||||
{
|
||||
for (j = 0; j < i; j++)
|
||||
free(ec->fir_taps16[j]);
|
||||
free(ec->fir_taps32);
|
||||
free(ec);
|
||||
return NULL;
|
||||
}
|
||||
memset(ec->fir_taps16[i], 0, ec->taps*sizeof(int16_t));
|
||||
}
|
||||
fir16_create(&ec->fir_state,
|
||||
ec->fir_taps16[0],
|
||||
ec->taps);
|
||||
ec->rx_power_threshold = 10000000;
|
||||
ec->geigel_max = 0;
|
||||
ec->geigel_lag = 0;
|
||||
ec->dtd_onset = FALSE;
|
||||
ec->tap_set = 0;
|
||||
ec->tap_rotate_counter = 1600;
|
||||
ec->cng_level = 1000;
|
||||
echo_can_adaption_mode(ec, adaption_mode);
|
||||
return ec;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void echo_can_free(echo_can_state_t *ec)
|
||||
{
|
||||
int i;
|
||||
|
||||
fir16_free(&ec->fir_state);
|
||||
free(ec->fir_taps32);
|
||||
for (i = 0; i < 4; i++)
|
||||
free(ec->fir_taps16[i]);
|
||||
free(ec);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void echo_can_adaption_mode(echo_can_state_t *ec, int adaption_mode)
|
||||
{
|
||||
ec->adaption_mode = adaption_mode;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void echo_can_flush(echo_can_state_t *ec)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
ec->tx_power[i] = 0;
|
||||
for (i = 0; i < 3; i++)
|
||||
ec->rx_power[i] = 0;
|
||||
ec->clean_rx_power = 0;
|
||||
ec->nonupdate_dwell = 0;
|
||||
|
||||
fir16_flush(&ec->fir_state);
|
||||
ec->fir_state.curr_pos = ec->taps - 1;
|
||||
memset(ec->fir_taps32, 0, ec->taps*sizeof(int32_t));
|
||||
for (i = 0; i < 4; i++)
|
||||
memset(ec->fir_taps16[i], 0, ec->taps*sizeof(int16_t));
|
||||
|
||||
ec->curr_pos = ec->taps - 1;
|
||||
|
||||
ec->supp_test1 = 0;
|
||||
ec->supp_test2 = 0;
|
||||
ec->supp1 = 0;
|
||||
ec->supp2 = 0;
|
||||
ec->vad = 0;
|
||||
ec->cng_level = 1000;
|
||||
ec->cng_filter = 0;
|
||||
|
||||
ec->geigel_max = 0;
|
||||
ec->geigel_lag = 0;
|
||||
ec->dtd_onset = FALSE;
|
||||
ec->tap_set = 0;
|
||||
ec->tap_rotate_counter = 1600;
|
||||
|
||||
ec->latest_correction = 0;
|
||||
|
||||
memset(ec->last_acf, 0, sizeof(ec->last_acf));
|
||||
ec->narrowband_count = 0;
|
||||
ec->narrowband_score = 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int sample_no = 0;
|
||||
|
||||
void echo_can_snapshot(echo_can_state_t *ec)
|
||||
{
|
||||
memcpy(ec->snapshot, ec->fir_taps16[0], ec->taps*sizeof(int16_t));
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static __inline__ int16_t echo_can_hpf(int32_t coeff[2], int16_t amp)
|
||||
{
|
||||
int32_t z;
|
||||
|
||||
/*
|
||||
Filter DC, 3dB point is 160Hz (I think), note 32 bit precision required
|
||||
otherwise values do not track down to 0. Zero at DC, Pole at (1-Beta)
|
||||
only real axis. Some chip sets (like Si labs) don't need
|
||||
this, but something like a $10 X100P card does. Any DC really slows
|
||||
down convergence.
|
||||
|
||||
Note: removes some low frequency from the signal, this reduces
|
||||
the speech quality when listening to samples through headphones
|
||||
but may not be obvious through a telephone handset.
|
||||
|
||||
Note that the 3dB frequency in radians is approx Beta, e.g. for
|
||||
Beta = 2^(-3) = 0.125, 3dB freq is 0.125 rads = 159Hz.
|
||||
|
||||
This is one of the classic DC removal filters, adjusted to provide sufficient
|
||||
bass rolloff to meet the above requirement to protect hybrids from things that
|
||||
upset them. The difference between successive samples produces a lousy HPF, and
|
||||
then a suitably placed pole flattens things out. The final result is a nicely
|
||||
rolled off bass end. The filtering is implemented with extended fractional
|
||||
precision, which noise shapes things, giving very clean DC removal.
|
||||
|
||||
Make sure the gain of the HPF is 1.0. The first can still saturate a little under
|
||||
impulse conditions, and it might roll to 32768 and need clipping on sustained peak
|
||||
level signals. However, the scale of such clipping is small, and the error due to
|
||||
any saturation should not markedly affect the downstream processing. */
|
||||
z = amp << 15;
|
||||
z -= (z >> 4);
|
||||
coeff[0] += z - (coeff[0] >> 3) - coeff[1];
|
||||
coeff[1] = z;
|
||||
z = coeff[0] >> 15;
|
||||
|
||||
return saturate(z);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int16_t echo_can_update(echo_can_state_t *ec, int16_t tx, int16_t rx)
|
||||
{
|
||||
int32_t echo_value;
|
||||
int clean_rx;
|
||||
int nsuppr;
|
||||
int score;
|
||||
int i;
|
||||
|
||||
sample_no++;
|
||||
if (ec->adaption_mode & ECHO_CAN_USE_RX_HPF)
|
||||
rx = echo_can_hpf(ec->rx_hpf, rx);
|
||||
|
||||
ec->latest_correction = 0;
|
||||
/* Evaluate the echo - i.e. apply the FIR filter */
|
||||
/* Assume the gain of the FIR does not exceed unity. Exceeding unity
|
||||
would seem like a rather poor thing for an echo cancellor to do :)
|
||||
This means we can compute the result with a total disregard for
|
||||
overflows. 16bits x 16bits -> 31bits, so no overflow can occur in
|
||||
any multiply. While accumulating we may overflow and underflow the
|
||||
32 bit scale often. However, if the gain does not exceed unity,
|
||||
everything should work itself out, and the final result will be
|
||||
OK, without any saturation logic. */
|
||||
/* Overflow is very much possible here, and we do nothing about it because
|
||||
of the compute costs */
|
||||
/* 16 bit coeffs for the LMS give lousy results (maths good, actual sound
|
||||
bad!), but 32 bit coeffs require some shifting. On balance 32 bit seems
|
||||
best */
|
||||
echo_value = fir16(&ec->fir_state, tx);
|
||||
|
||||
/* And the answer is..... */
|
||||
clean_rx = rx - echo_value;
|
||||
printf("echo is %" PRId32 "\n", echo_value);
|
||||
/* That was the easy part. Now we need to adapt! */
|
||||
if (ec->nonupdate_dwell > 0)
|
||||
ec->nonupdate_dwell--;
|
||||
|
||||
/* Calculate short term power levels using very simple single pole IIRs */
|
||||
/* TODO: Is the nasty modulus approach the fastest, or would a real
|
||||
tx*tx power calculation actually be faster? Using the squares
|
||||
makes the numbers grow a lot! */
|
||||
ec->tx_power[3] += ((abs(tx) - ec->tx_power[3]) >> 5);
|
||||
ec->tx_power[2] += ((tx*tx - ec->tx_power[2]) >> 8);
|
||||
ec->tx_power[1] += ((tx*tx - ec->tx_power[1]) >> 5);
|
||||
ec->tx_power[0] += ((tx*tx - ec->tx_power[0]) >> 3);
|
||||
ec->rx_power[1] += ((rx*rx - ec->rx_power[1]) >> 6);
|
||||
ec->rx_power[0] += ((rx*rx - ec->rx_power[0]) >> 3);
|
||||
ec->clean_rx_power += ((clean_rx*clean_rx - ec->clean_rx_power) >> 6);
|
||||
|
||||
score = 0;
|
||||
/* If there is very little being transmitted, any attempt to train is
|
||||
futile. We would either be training on the far end's noise or signal,
|
||||
the channel's own noise, or our noise. Either way, this is hardly good
|
||||
training, so don't do it (avoid trouble). */
|
||||
if (ec->tx_power[0] > MIN_TX_POWER_FOR_ADAPTION)
|
||||
{
|
||||
/* If the received power is very low, either we are sending very little or
|
||||
we are already well adapted. There is little point in trying to improve
|
||||
the adaption under these circumstances, so don't do it (reduce the
|
||||
compute load). */
|
||||
if (ec->tx_power[1] > ec->rx_power[0])
|
||||
{
|
||||
/* There is no (or little) far-end speech. */
|
||||
if (ec->nonupdate_dwell == 0)
|
||||
{
|
||||
if (++ec->narrowband_count >= 160)
|
||||
{
|
||||
ec->narrowband_count = 0;
|
||||
score = narrowband_detect(ec);
|
||||
printf("Do the narrowband test %d at %d\n", score, ec->curr_pos);
|
||||
if (score > 6)
|
||||
{
|
||||
if (ec->narrowband_score == 0)
|
||||
memcpy(ec->fir_taps16[3], ec->fir_taps16[(ec->tap_set + 1)%3], ec->taps*sizeof(int16_t));
|
||||
ec->narrowband_score += score;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ec->narrowband_score > 200)
|
||||
{
|
||||
printf("Revert to %d at %d\n", (ec->tap_set + 1)%3, sample_no);
|
||||
memcpy(ec->fir_taps16[ec->tap_set], ec->fir_taps16[3], ec->taps*sizeof(int16_t));
|
||||
memcpy(ec->fir_taps16[(ec->tap_set - 1)%3], ec->fir_taps16[3], ec->taps*sizeof(int16_t));
|
||||
for (i = 0; i < ec->taps; i++)
|
||||
ec->fir_taps32[i] = ec->fir_taps16[3][i] << 15;
|
||||
ec->tap_rotate_counter = 1600;
|
||||
}
|
||||
ec->narrowband_score = 0;
|
||||
}
|
||||
}
|
||||
ec->dtd_onset = FALSE;
|
||||
if (--ec->tap_rotate_counter <= 0)
|
||||
{
|
||||
printf("Rotate to %d at %d\n", ec->tap_set, sample_no);
|
||||
ec->tap_rotate_counter = 1600;
|
||||
ec->tap_set++;
|
||||
if (ec->tap_set > 2)
|
||||
ec->tap_set = 0;
|
||||
ec->fir_state.coeffs = ec->fir_taps16[ec->tap_set];
|
||||
}
|
||||
/* ... and we are not in the dwell time from previous speech. */
|
||||
if ((ec->adaption_mode & ECHO_CAN_USE_ADAPTION) && ec->narrowband_score == 0)
|
||||
{
|
||||
//nsuppr = saturate((clean_rx << 16)/ec->tx_power[1]);
|
||||
//nsuppr = clean_rx/ec->tx_power[1];
|
||||
/* If a sudden surge in signal level (e.g. the onset of a tone
|
||||
burst) cause an abnormally high instantaneous to average
|
||||
signal power ratio, we could kick the adaption badly in the
|
||||
wrong direction. This is because the tx_power takes too long
|
||||
to react and rise. We need to stop too rapid adaption to the
|
||||
new signal. We normalise to a value derived from the
|
||||
instantaneous signal if it exceeds the peak by too much. */
|
||||
nsuppr = clean_rx;
|
||||
/* Divide isn't very quick, but the "where is the top bit" and shift
|
||||
instructions are single cycle. */
|
||||
if (tx > 4*ec->tx_power[3])
|
||||
i = top_bit(tx) - 8;
|
||||
else
|
||||
i = top_bit(ec->tx_power[3]) - 8;
|
||||
if (i > 0)
|
||||
nsuppr >>= i;
|
||||
lms_adapt(ec, nsuppr);
|
||||
}
|
||||
}
|
||||
//printf("%10d %10d %10d %10d %10d\n", rx, clean_rx, nsuppr, ec->tx_power[1], ec->rx_power[1]);
|
||||
//printf("%.4f\n", (float) ec->rx_power[1]/(float) ec->clean_rx_power);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ec->dtd_onset)
|
||||
{
|
||||
printf("Revert to %d at %d\n", (ec->tap_set + 1)%3, sample_no);
|
||||
memcpy(ec->fir_taps16[ec->tap_set], ec->fir_taps16[(ec->tap_set + 1)%3], ec->taps*sizeof(int16_t));
|
||||
memcpy(ec->fir_taps16[(ec->tap_set - 1)%3], ec->fir_taps16[(ec->tap_set + 1)%3], ec->taps*sizeof(int16_t));
|
||||
for (i = 0; i < ec->taps; i++)
|
||||
ec->fir_taps32[i] = ec->fir_taps16[(ec->tap_set + 1)%3][i] << 15;
|
||||
ec->tap_rotate_counter = 1600;
|
||||
ec->dtd_onset = TRUE;
|
||||
}
|
||||
ec->nonupdate_dwell = NONUPDATE_DWELL_TIME;
|
||||
}
|
||||
}
|
||||
|
||||
if (ec->rx_power[1])
|
||||
ec->vad = (8000*ec->clean_rx_power)/ec->rx_power[1];
|
||||
else
|
||||
ec->vad = 0;
|
||||
if (ec->rx_power[1] > 2048*2048 && ec->clean_rx_power > 4*ec->rx_power[1])
|
||||
{
|
||||
/* The EC seems to be making things worse, instead of better. Zap it! */
|
||||
memset(ec->fir_taps32, 0, ec->taps*sizeof(int32_t));
|
||||
for (i = 0; i < 4; i++)
|
||||
memset(ec->fir_taps16[i], 0, ec->taps*sizeof(int16_t));
|
||||
}
|
||||
|
||||
#if defined(XYZZY)
|
||||
if ((ec->adaption_mode & ECHO_CAN_USE_SUPPRESSOR))
|
||||
{
|
||||
ec->supp_test1 += (ec->fir_state.history[ec->curr_pos] - ec->fir_state.history[(ec->curr_pos - 7) & ec->tap_mask]);
|
||||
ec->supp_test2 += (ec->fir_state.history[(ec->curr_pos - 24) & ec->tap_mask] - ec->fir_state.history[(ec->curr_pos - 31) & ec->tap_mask]);
|
||||
if (ec->supp_test1 > 42 && ec->supp_test2 > 42)
|
||||
supp_change = 25;
|
||||
else
|
||||
supp_change = 50;
|
||||
supp = supp_change + k1*ec->supp1 + k2*ec->supp2;
|
||||
ec->supp2 = ec->supp1;
|
||||
ec->supp1 = supp;
|
||||
clean_rx *= (1 - supp);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((ec->adaption_mode & ECHO_CAN_USE_NLP))
|
||||
{
|
||||
/* Non-linear processor - a fancy way to say "zap small signals, to avoid
|
||||
residual echo due to (uLaw/ALaw) non-linearity in the channel.". */
|
||||
if (ec->rx_power[1] < 30000000)
|
||||
{
|
||||
if (!ec->cng)
|
||||
{
|
||||
ec->cng_level = ec->clean_rx_power;
|
||||
ec->cng = TRUE;
|
||||
}
|
||||
if ((ec->adaption_mode & ECHO_CAN_USE_CNG))
|
||||
{
|
||||
/* Very elementary comfort noise generation */
|
||||
/* Just random numbers rolled off very vaguely Hoth-like */
|
||||
ec->cng_rndnum = 1664525U*ec->cng_rndnum + 1013904223U;
|
||||
ec->cng_filter = ((ec->cng_rndnum & 0xFFFF) - 32768 + 5*ec->cng_filter) >> 3;
|
||||
clean_rx = (ec->cng_filter*ec->cng_level) >> 17;
|
||||
/* TODO: A better CNG, with more accurate (tracking) spectral shaping! */
|
||||
}
|
||||
else
|
||||
{
|
||||
clean_rx = 0;
|
||||
}
|
||||
//clean_rx = -16000;
|
||||
}
|
||||
else
|
||||
{
|
||||
ec->cng = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ec->cng = FALSE;
|
||||
}
|
||||
|
||||
printf("Narrowband score %4d %5d at %d\n", ec->narrowband_score, score, sample_no);
|
||||
/* Roll around the rolling buffer */
|
||||
if (ec->curr_pos <= 0)
|
||||
ec->curr_pos = ec->taps;
|
||||
ec->curr_pos--;
|
||||
return (int16_t) clean_rx;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int16_t echo_can_hpf_tx(echo_can_state_t *ec, int16_t tx)
|
||||
{
|
||||
if (ec->adaption_mode & ECHO_CAN_USE_TX_HPF)
|
||||
tx = echo_can_hpf(ec->tx_hpf, tx);
|
||||
return tx;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,590 @@
|
||||
//#define LOG_FAX_AUDIO
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* fax.c - Analogue line ITU T.30 FAX transfer processing
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2003, 2005, 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: fax.c,v 1.79 2008/08/13 00:11:30 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#if defined(LOG_FAX_AUDIO)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <tiffio.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/logging.h"
|
||||
#include "spandsp/queue.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/power_meter.h"
|
||||
#include "spandsp/complex.h"
|
||||
#include "spandsp/tone_detect.h"
|
||||
#include "spandsp/tone_generate.h"
|
||||
#include "spandsp/async.h"
|
||||
#include "spandsp/hdlc.h"
|
||||
#include "spandsp/silence_gen.h"
|
||||
#include "spandsp/fsk.h"
|
||||
#include "spandsp/v29rx.h"
|
||||
#include "spandsp/v29tx.h"
|
||||
#include "spandsp/v27ter_rx.h"
|
||||
#include "spandsp/v27ter_tx.h"
|
||||
#include "spandsp/v17rx.h"
|
||||
#include "spandsp/v17tx.h"
|
||||
#include "spandsp/super_tone_rx.h"
|
||||
#include "spandsp/modem_connect_tones.h"
|
||||
#include "spandsp/t4.h"
|
||||
|
||||
#include "spandsp/t30_fcf.h"
|
||||
#include "spandsp/t35.h"
|
||||
#include "spandsp/t30.h"
|
||||
#include "spandsp/t30_api.h"
|
||||
#include "spandsp/t30_logging.h"
|
||||
|
||||
#include "spandsp/fax_modems.h"
|
||||
#include "spandsp/fax.h"
|
||||
|
||||
#define HDLC_FRAMING_OK_THRESHOLD 5
|
||||
|
||||
static void fax_send_hdlc(void *user_data, const uint8_t *msg, int len)
|
||||
{
|
||||
fax_state_t *s;
|
||||
|
||||
s = (fax_state_t *) user_data;
|
||||
|
||||
hdlc_tx_frame(&s->modems.hdlc_tx, msg, len);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void tone_detected(void *user_data, int on, int level, int delay)
|
||||
{
|
||||
t30_state_t *s;
|
||||
|
||||
s = (t30_state_t *) user_data;
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "FAX tone declared %s (%ddBm0)\n", (on) ? "on" : "off", level);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void hdlc_underflow_handler(void *user_data)
|
||||
{
|
||||
t30_state_t *s;
|
||||
|
||||
s = (t30_state_t *) user_data;
|
||||
t30_front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int v17_v21_rx(void *user_data, const int16_t amp[], int len)
|
||||
{
|
||||
fax_state_t *t;
|
||||
fax_modems_state_t *s;
|
||||
|
||||
t = (fax_state_t *) user_data;
|
||||
s = &t->modems;
|
||||
v17_rx(&s->v17_rx, amp, len);
|
||||
if (t->t30.rx_trained)
|
||||
{
|
||||
/* The fast modem has trained, so we no longer need to run the slow
|
||||
one in parallel. */
|
||||
span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.17 + V.21 to V.17 (%.2fdBm0)\n", v17_rx_signal_power(&s->v17_rx));
|
||||
s->rx_handler = (span_rx_handler_t *) &v17_rx;
|
||||
s->rx_user_data = &s->v17_rx;
|
||||
}
|
||||
else
|
||||
{
|
||||
fsk_rx(&s->v21_rx, amp, len);
|
||||
if (t->t30.rx_frame_received)
|
||||
{
|
||||
/* We have received something, and the fast modem has not trained. We must
|
||||
be receiving valid V.21 */
|
||||
span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.17 + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
|
||||
s->rx_handler = (span_rx_handler_t *) &fsk_rx;
|
||||
s->rx_user_data = &s->v21_rx;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int v27ter_v21_rx(void *user_data, const int16_t amp[], int len)
|
||||
{
|
||||
fax_state_t *t;
|
||||
fax_modems_state_t *s;
|
||||
|
||||
t = (fax_state_t *) user_data;
|
||||
s = &t->modems;
|
||||
v27ter_rx(&s->v27ter_rx, amp, len);
|
||||
if (t->t30.rx_trained)
|
||||
{
|
||||
/* The fast modem has trained, so we no longer need to run the slow
|
||||
one in parallel. */
|
||||
span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.27ter + V.21 to V.27ter (%.2fdBm0)\n", v27ter_rx_signal_power(&s->v27ter_rx));
|
||||
s->rx_handler = (span_rx_handler_t *) &v27ter_rx;
|
||||
s->rx_user_data = &s->v27ter_rx;
|
||||
}
|
||||
else
|
||||
{
|
||||
fsk_rx(&s->v21_rx, amp, len);
|
||||
if (t->t30.rx_frame_received)
|
||||
{
|
||||
/* We have received something, and the fast modem has not trained. We must
|
||||
be receiving valid V.21 */
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.27ter + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
|
||||
s->rx_handler = (span_rx_handler_t *) &fsk_rx;
|
||||
s->rx_user_data = &s->v21_rx;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int v29_v21_rx(void *user_data, const int16_t amp[], int len)
|
||||
{
|
||||
fax_state_t *t;
|
||||
fax_modems_state_t *s;
|
||||
|
||||
t = (fax_state_t *) user_data;
|
||||
s = &t->modems;
|
||||
v29_rx(&s->v29_rx, amp, len);
|
||||
if (t->t30.rx_trained)
|
||||
{
|
||||
/* The fast modem has trained, so we no longer need to run the slow
|
||||
one in parallel. */
|
||||
span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.29 + V.21 to V.29 (%.2fdBm0)\n", v29_rx_signal_power(&s->v29_rx));
|
||||
s->rx_handler = (span_rx_handler_t *) &v29_rx;
|
||||
s->rx_user_data = &s->v29_rx;
|
||||
}
|
||||
else
|
||||
{
|
||||
fsk_rx(&s->v21_rx, amp, len);
|
||||
if (t->t30.rx_frame_received)
|
||||
{
|
||||
/* We have received something, and the fast modem has not trained. We must
|
||||
be receiving valid V.21 */
|
||||
span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.29 + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
|
||||
s->rx_handler = (span_rx_handler_t *) &fsk_rx;
|
||||
s->rx_user_data = &s->v21_rx;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void fax_fax_modems_init(fax_modems_state_t *s, int use_tep, void *user_data)
|
||||
{
|
||||
s->use_tep = use_tep;
|
||||
|
||||
hdlc_rx_init(&s->hdlc_rx, FALSE, FALSE, HDLC_FRAMING_OK_THRESHOLD, t30_hdlc_accept, user_data);
|
||||
hdlc_tx_init(&s->hdlc_tx, FALSE, 2, FALSE, hdlc_underflow_handler, user_data);
|
||||
fsk_rx_init(&s->v21_rx, &preset_fsk_specs[FSK_V21CH2], TRUE, (put_bit_func_t) hdlc_rx_put_bit, &s->hdlc_rx);
|
||||
fsk_rx_signal_cutoff(&s->v21_rx, -45.5);
|
||||
fsk_tx_init(&s->v21_tx, &preset_fsk_specs[FSK_V21CH2], (get_bit_func_t) hdlc_tx_get_bit, &s->hdlc_tx);
|
||||
v17_rx_init(&s->v17_rx, 14400, t30_non_ecm_put_bit, user_data);
|
||||
v17_tx_init(&s->v17_tx, 14400, s->use_tep, t30_non_ecm_get_bit, user_data);
|
||||
v29_rx_init(&s->v29_rx, 9600, t30_non_ecm_put_bit, user_data);
|
||||
v29_rx_signal_cutoff(&s->v29_rx, -45.5);
|
||||
v29_tx_init(&s->v29_tx, 9600, s->use_tep, t30_non_ecm_get_bit, user_data);
|
||||
v27ter_rx_init(&s->v27ter_rx, 4800, t30_non_ecm_put_bit, user_data);
|
||||
v27ter_tx_init(&s->v27ter_tx, 4800, s->use_tep, t30_non_ecm_get_bit, user_data);
|
||||
silence_gen_init(&s->silence_gen, 0);
|
||||
modem_connect_tones_tx_init(&s->connect_tx, MODEM_CONNECT_TONES_FAX_CNG);
|
||||
modem_connect_tones_rx_init(&s->connect_rx,
|
||||
MODEM_CONNECT_TONES_FAX_CNG,
|
||||
tone_detected,
|
||||
user_data);
|
||||
dc_restore_init(&s->dc_restore);
|
||||
|
||||
s->rx_signal_present = FALSE;
|
||||
s->rx_handler = (span_rx_handler_t *) &span_dummy_rx;
|
||||
s->rx_user_data = NULL;
|
||||
s->tx_handler = (span_tx_handler_t *) &silence_gen;
|
||||
s->tx_user_data = &s->silence_gen;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int fax_rx(fax_state_t *s, int16_t *amp, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
#if defined(LOG_FAX_AUDIO)
|
||||
if (s->modems.audio_rx_log >= 0)
|
||||
write(s->modems.audio_rx_log, amp, len*sizeof(int16_t));
|
||||
#endif
|
||||
for (i = 0; i < len; i++)
|
||||
amp[i] = dc_restore(&s->modems.dc_restore, amp[i]);
|
||||
s->modems.rx_handler(s->modems.rx_user_data, amp, len);
|
||||
t30_timer_update(&s->t30, len);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int set_next_tx_type(fax_state_t *s)
|
||||
{
|
||||
fax_modems_state_t *t;
|
||||
|
||||
t = &s->modems;
|
||||
if (t->next_tx_handler)
|
||||
{
|
||||
t->tx_handler = t->next_tx_handler;
|
||||
t->tx_user_data = t->next_tx_user_data;
|
||||
t->next_tx_handler = NULL;
|
||||
return 0;
|
||||
}
|
||||
/* If there is nothing else to change to, so use zero length silence */
|
||||
silence_gen_alter(&t->silence_gen, 0);
|
||||
t->tx_handler = (span_tx_handler_t *) &silence_gen;
|
||||
t->tx_user_data = &t->silence_gen;
|
||||
t->next_tx_handler = NULL;
|
||||
t->transmit = FALSE;
|
||||
return -1;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int fax_tx(fax_state_t *s, int16_t *amp, int max_len)
|
||||
{
|
||||
int len;
|
||||
#if defined(LOG_FAX_AUDIO)
|
||||
int required_len;
|
||||
|
||||
required_len = max_len;
|
||||
#endif
|
||||
len = 0;
|
||||
if (s->modems.transmit)
|
||||
{
|
||||
while ((len += s->modems.tx_handler(s->modems.tx_user_data, amp + len, max_len - len)) < max_len)
|
||||
{
|
||||
/* Allow for a change of tx handler within a block */
|
||||
if (set_next_tx_type(s) && s->modems.current_tx_type != T30_MODEM_NONE && s->modems.current_tx_type != T30_MODEM_DONE)
|
||||
t30_front_end_status(&s->t30, T30_FRONT_END_SEND_STEP_COMPLETE);
|
||||
if (!s->modems.transmit)
|
||||
{
|
||||
if (s->modems.transmit_on_idle)
|
||||
{
|
||||
/* Pad to the requested length with silence */
|
||||
memset(amp + len, 0, (max_len - len)*sizeof(int16_t));
|
||||
len = max_len;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s->modems.transmit_on_idle)
|
||||
{
|
||||
/* Pad to the requested length with silence */
|
||||
memset(amp, 0, max_len*sizeof(int16_t));
|
||||
len = max_len;
|
||||
}
|
||||
}
|
||||
#if defined(LOG_FAX_AUDIO)
|
||||
if (s->modems.audio_tx_log >= 0)
|
||||
{
|
||||
if (len < required_len)
|
||||
memset(amp + len, 0, (required_len - len)*sizeof(int16_t));
|
||||
write(s->modems.audio_tx_log, amp, required_len*sizeof(int16_t));
|
||||
}
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void fax_set_rx_type(void *user_data, int type, int bit_rate, int short_train, int use_hdlc)
|
||||
{
|
||||
fax_state_t *s;
|
||||
put_bit_func_t put_bit_func;
|
||||
void *put_bit_user_data;
|
||||
fax_modems_state_t *t;
|
||||
|
||||
s = (fax_state_t *) user_data;
|
||||
t = &s->modems;
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Set rx type %d\n", type);
|
||||
if (t->current_rx_type == type)
|
||||
return;
|
||||
t->current_rx_type = type;
|
||||
t->rx_bit_rate = bit_rate;
|
||||
if (use_hdlc)
|
||||
{
|
||||
put_bit_func = (put_bit_func_t) hdlc_rx_put_bit;
|
||||
put_bit_user_data = (void *) &t->hdlc_rx;
|
||||
hdlc_rx_init(&t->hdlc_rx, FALSE, FALSE, HDLC_FRAMING_OK_THRESHOLD, t30_hdlc_accept, &s->t30);
|
||||
}
|
||||
else
|
||||
{
|
||||
put_bit_func = t30_non_ecm_put_bit;
|
||||
put_bit_user_data = (void *) &s->t30;
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
case T30_MODEM_V21:
|
||||
fsk_rx_init(&t->v21_rx, &preset_fsk_specs[FSK_V21CH2], TRUE, (put_bit_func_t) hdlc_rx_put_bit, put_bit_user_data);
|
||||
fsk_rx_signal_cutoff(&t->v21_rx, -45.5);
|
||||
t->rx_handler = (span_rx_handler_t *) &fsk_rx;
|
||||
t->rx_user_data = &t->v21_rx;
|
||||
break;
|
||||
case T30_MODEM_V27TER:
|
||||
v27ter_rx_restart(&t->v27ter_rx, bit_rate, FALSE);
|
||||
v27ter_rx_set_put_bit(&t->v27ter_rx, put_bit_func, put_bit_user_data);
|
||||
t->rx_handler = (span_rx_handler_t *) &v27ter_v21_rx;
|
||||
t->rx_user_data = s;
|
||||
break;
|
||||
case T30_MODEM_V29:
|
||||
v29_rx_restart(&t->v29_rx, bit_rate, FALSE);
|
||||
v29_rx_set_put_bit(&t->v29_rx, put_bit_func, put_bit_user_data);
|
||||
t->rx_handler = (span_rx_handler_t *) &v29_v21_rx;
|
||||
t->rx_user_data = s;
|
||||
break;
|
||||
case T30_MODEM_V17:
|
||||
v17_rx_restart(&t->v17_rx, bit_rate, short_train);
|
||||
v17_rx_set_put_bit(&t->v17_rx, put_bit_func, put_bit_user_data);
|
||||
t->rx_handler = (span_rx_handler_t *) &v17_v21_rx;
|
||||
t->rx_user_data = s;
|
||||
break;
|
||||
case T30_MODEM_DONE:
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "FAX exchange complete\n");
|
||||
default:
|
||||
t->rx_handler = (span_rx_handler_t *) &span_dummy_rx;
|
||||
t->rx_user_data = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void fax_set_tx_type(void *user_data, int type, int bit_rate, int short_train, int use_hdlc)
|
||||
{
|
||||
fax_state_t *s;
|
||||
get_bit_func_t get_bit_func;
|
||||
void *get_bit_user_data;
|
||||
fax_modems_state_t *t;
|
||||
int tone;
|
||||
|
||||
s = (fax_state_t *) user_data;
|
||||
t = &s->modems;
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Set tx type %d\n", type);
|
||||
if (t->current_tx_type == type)
|
||||
return;
|
||||
if (use_hdlc)
|
||||
{
|
||||
get_bit_func = (get_bit_func_t) hdlc_tx_get_bit;
|
||||
get_bit_user_data = (void *) &t->hdlc_tx;
|
||||
}
|
||||
else
|
||||
{
|
||||
get_bit_func = t30_non_ecm_get_bit;
|
||||
get_bit_user_data = (void *) &s->t30;
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
case T30_MODEM_PAUSE:
|
||||
silence_gen_alter(&t->silence_gen, ms_to_samples(short_train));
|
||||
t->tx_handler = (span_tx_handler_t *) &silence_gen;
|
||||
t->tx_user_data = &t->silence_gen;
|
||||
t->next_tx_handler = NULL;
|
||||
t->transmit = TRUE;
|
||||
break;
|
||||
case T30_MODEM_CED:
|
||||
case T30_MODEM_CNG:
|
||||
if (type == T30_MODEM_CED)
|
||||
tone = MODEM_CONNECT_TONES_FAX_CED;
|
||||
else
|
||||
tone = MODEM_CONNECT_TONES_FAX_CNG;
|
||||
modem_connect_tones_tx_init(&t->connect_tx, tone);
|
||||
t->tx_handler = (span_tx_handler_t *) &modem_connect_tones_tx;
|
||||
t->tx_user_data = &t->connect_tx;
|
||||
t->next_tx_handler = NULL;
|
||||
t->transmit = TRUE;
|
||||
break;
|
||||
case T30_MODEM_V21:
|
||||
fsk_tx_init(&t->v21_tx, &preset_fsk_specs[FSK_V21CH2], get_bit_func, get_bit_user_data);
|
||||
/* The spec says 1s +-15% of preamble. So, the minimum is 32 octets. */
|
||||
hdlc_tx_flags(&t->hdlc_tx, 32);
|
||||
/* Pause before switching from phase C, as per T.30 5.3.2.2. If we omit this, the receiver
|
||||
might not see the carrier fall between the high speed and low speed sections. In practice,
|
||||
a 75ms gap before any V.21 transmission is harmless, adds little to the overall length of
|
||||
a call, and ensures the receiving end is ready. */
|
||||
silence_gen_alter(&t->silence_gen, ms_to_samples(75));
|
||||
t->tx_handler = (span_tx_handler_t *) &silence_gen;
|
||||
t->tx_user_data = &t->silence_gen;
|
||||
t->next_tx_handler = (span_tx_handler_t *) &fsk_tx;
|
||||
t->next_tx_user_data = &t->v21_tx;
|
||||
t->transmit = TRUE;
|
||||
break;
|
||||
case T30_MODEM_V27TER:
|
||||
silence_gen_alter(&t->silence_gen, ms_to_samples(75));
|
||||
/* For any fast modem, set 200ms of preamble flags */
|
||||
hdlc_tx_flags(&t->hdlc_tx, bit_rate/(8*5));
|
||||
v27ter_tx_restart(&t->v27ter_tx, bit_rate, t->use_tep);
|
||||
v27ter_tx_set_get_bit(&t->v27ter_tx, get_bit_func, get_bit_user_data);
|
||||
t->tx_handler = (span_tx_handler_t *) &silence_gen;
|
||||
t->tx_user_data = &t->silence_gen;
|
||||
t->next_tx_handler = (span_tx_handler_t *) &v27ter_tx;
|
||||
t->next_tx_user_data = &t->v27ter_tx;
|
||||
t->transmit = TRUE;
|
||||
break;
|
||||
case T30_MODEM_V29:
|
||||
silence_gen_alter(&t->silence_gen, ms_to_samples(75));
|
||||
/* For any fast modem, set 200ms of preamble flags */
|
||||
hdlc_tx_flags(&t->hdlc_tx, bit_rate/(8*5));
|
||||
v29_tx_restart(&t->v29_tx, bit_rate, t->use_tep);
|
||||
v29_tx_set_get_bit(&t->v29_tx, get_bit_func, get_bit_user_data);
|
||||
t->tx_handler = (span_tx_handler_t *) &silence_gen;
|
||||
t->tx_user_data = &t->silence_gen;
|
||||
t->next_tx_handler = (span_tx_handler_t *) &v29_tx;
|
||||
t->next_tx_user_data = &t->v29_tx;
|
||||
t->transmit = TRUE;
|
||||
break;
|
||||
case T30_MODEM_V17:
|
||||
silence_gen_alter(&t->silence_gen, ms_to_samples(75));
|
||||
/* For any fast modem, set 200ms of preamble flags */
|
||||
hdlc_tx_flags(&t->hdlc_tx, bit_rate/(8*5));
|
||||
v17_tx_restart(&t->v17_tx, bit_rate, t->use_tep, short_train);
|
||||
v17_tx_set_get_bit(&t->v17_tx, get_bit_func, get_bit_user_data);
|
||||
t->tx_handler = (span_tx_handler_t *) &silence_gen;
|
||||
t->tx_user_data = &t->silence_gen;
|
||||
t->next_tx_handler = (span_tx_handler_t *) &v17_tx;
|
||||
t->next_tx_user_data = &t->v17_tx;
|
||||
t->transmit = TRUE;
|
||||
break;
|
||||
case T30_MODEM_DONE:
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "FAX exchange complete\n");
|
||||
/* Fall through */
|
||||
default:
|
||||
silence_gen_alter(&t->silence_gen, 0);
|
||||
t->tx_handler = (span_tx_handler_t *) &silence_gen;
|
||||
t->tx_user_data = &t->silence_gen;
|
||||
t->next_tx_handler = NULL;
|
||||
t->transmit = FALSE;
|
||||
break;
|
||||
}
|
||||
t->tx_bit_rate = bit_rate;
|
||||
t->current_tx_type = type;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void fax_set_transmit_on_idle(fax_state_t *s, int transmit_on_idle)
|
||||
{
|
||||
s->modems.transmit_on_idle = transmit_on_idle;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void fax_set_tep_mode(fax_state_t *s, int use_tep)
|
||||
{
|
||||
s->modems.use_tep = use_tep;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
t30_state_t *fax_get_t30_state(fax_state_t *s)
|
||||
{
|
||||
return &s->t30;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
fax_state_t *fax_init(fax_state_t *s, int calling_party)
|
||||
{
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (fax_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
|
||||
span_log_set_protocol(&s->logging, "FAX");
|
||||
fax_fax_modems_init(&s->modems, FALSE, &s->t30);
|
||||
t30_init(&s->t30,
|
||||
calling_party,
|
||||
fax_set_rx_type,
|
||||
(void *) s,
|
||||
fax_set_tx_type,
|
||||
(void *) s,
|
||||
fax_send_hdlc,
|
||||
(void *) s);
|
||||
t30_set_supported_modems(&s->t30, T30_SUPPORT_V27TER | T30_SUPPORT_V29);
|
||||
t30_restart(&s->t30);
|
||||
#if defined(LOG_FAX_AUDIO)
|
||||
{
|
||||
char buf[100 + 1];
|
||||
struct tm *tm;
|
||||
time_t now;
|
||||
|
||||
time(&now);
|
||||
tm = localtime(&now);
|
||||
sprintf(buf,
|
||||
"/tmp/fax-rx-audio-%p-%02d%02d%02d%02d%02d%02d",
|
||||
s,
|
||||
tm->tm_year%100,
|
||||
tm->tm_mon + 1,
|
||||
tm->tm_mday,
|
||||
tm->tm_hour,
|
||||
tm->tm_min,
|
||||
tm->tm_sec);
|
||||
s->modems.audio_rx_log = open(buf, O_CREAT | O_TRUNC | O_WRONLY, 0666);
|
||||
sprintf(buf,
|
||||
"/tmp/fax-tx-audio-%p-%02d%02d%02d%02d%02d%02d",
|
||||
s,
|
||||
tm->tm_year%100,
|
||||
tm->tm_mon + 1,
|
||||
tm->tm_mday,
|
||||
tm->tm_hour,
|
||||
tm->tm_min,
|
||||
tm->tm_sec);
|
||||
s->modems.audio_tx_log = open(buf, O_CREAT | O_TRUNC | O_WRONLY, 0666);
|
||||
}
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int fax_release(fax_state_t *s)
|
||||
{
|
||||
t30_release(&s->t30);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int fax_free(fax_state_t *s)
|
||||
{
|
||||
t30_release(&s->t30);
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* filter_tools.c - A collection of routines used for filter design.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2008 Steve Underwood
|
||||
*
|
||||
* This includes some elements based on the mkfilter package by
|
||||
* A.J. Fisher, University of York <fisher@minster.york.ac.uk>, November 1996
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: filter_tools.c,v 1.8 2008/08/29 09:28:13 steveu Exp $
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/complex.h"
|
||||
#include "filter_tools.h"
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE (!FALSE)
|
||||
|
||||
#define MAXPZ 8192
|
||||
#define SEQ_LEN 8192
|
||||
#define MAX_FFT_LEN SEQ_LEN
|
||||
|
||||
static complex_t circle[MAX_FFT_LEN/2];
|
||||
|
||||
static __inline__ complex_t expj(double theta)
|
||||
{
|
||||
return complex_set(cos(theta), sin(theta));
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static __inline__ double fix(double x)
|
||||
{
|
||||
/* Nearest integer */
|
||||
return (x >= 0.0) ? floor(0.5 + x) : -floor(0.5 - x);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void fftx(complex_t data[], complex_t temp[], int n)
|
||||
{
|
||||
int i;
|
||||
int h;
|
||||
int p;
|
||||
int t;
|
||||
int i2;
|
||||
complex_t wkt;
|
||||
|
||||
if (n > 1)
|
||||
{
|
||||
h = n/2;
|
||||
for (i = 0; i < h; i++)
|
||||
{
|
||||
i2 = i*2;
|
||||
temp[i] = data[i2]; /* Even */
|
||||
temp[h + i] = data[i2 + 1]; /* Odd */
|
||||
}
|
||||
fftx(&temp[0], &data[0], h);
|
||||
fftx(&temp[h], &data[h], h);
|
||||
p = 0;
|
||||
t = MAX_FFT_LEN/n;
|
||||
for (i = 0; i < h; i++)
|
||||
{
|
||||
wkt = complex_mul(&circle[p], &temp[h + i]);
|
||||
data[i] = complex_add(&temp[i], &wkt);
|
||||
data[h + i] = complex_sub(&temp[i], &wkt);
|
||||
p += t;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void ifft(complex_t data[], int len)
|
||||
{
|
||||
int i;
|
||||
double x;
|
||||
complex_t temp[MAX_FFT_LEN];
|
||||
|
||||
/* A very slow and clunky FFT, that's just fine for filter design. */
|
||||
for (i = 0; i < MAX_FFT_LEN/2; i++)
|
||||
{
|
||||
x = (2.0*3.1415926535*i)/(double) MAX_FFT_LEN;
|
||||
circle[i] = expj(x);
|
||||
}
|
||||
fftx(data, temp, len);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void compute_raised_cosine_filter(double coeffs[],
|
||||
int len,
|
||||
int root,
|
||||
int sinc_compensate,
|
||||
double alpha,
|
||||
double beta)
|
||||
{
|
||||
double f;
|
||||
double x;
|
||||
double f1;
|
||||
double f2;
|
||||
double tau;
|
||||
complex_t vec[SEQ_LEN];
|
||||
int i;
|
||||
int j;
|
||||
int h;
|
||||
|
||||
f1 = (1.0 - beta)*alpha;
|
||||
f2 = (1.0 + beta)*alpha;
|
||||
tau = 0.5/alpha;
|
||||
/* (Root) raised cosine */
|
||||
for (i = 0; i <= SEQ_LEN/2; i++)
|
||||
{
|
||||
f = (double) i/(double) SEQ_LEN;
|
||||
if (f <= f1)
|
||||
vec[i] = complex_set(1.0, 0.0);
|
||||
else if (f <= f2)
|
||||
vec[i] = complex_set(0.5*(1.0 + cos((3.1415926535*tau/beta) * (f - f1))), 0.0);
|
||||
else
|
||||
vec[i] = complex_set(0.0, 0.0);
|
||||
}
|
||||
if (root)
|
||||
{
|
||||
for (i = 0; i <= SEQ_LEN/2; i++)
|
||||
vec[i].re = sqrt(vec[i].re);
|
||||
}
|
||||
if (sinc_compensate)
|
||||
{
|
||||
for (i = 1; i <= SEQ_LEN/2; i++)
|
||||
{
|
||||
x = 3.1415926535*(double) i/(double) SEQ_LEN;
|
||||
vec[i].re *= (x/sin(x));
|
||||
}
|
||||
}
|
||||
for (i = 0; i <= SEQ_LEN/2; i++)
|
||||
vec[i].re *= tau;
|
||||
for (i = 1; i < SEQ_LEN/2; i++)
|
||||
vec[SEQ_LEN - i] = vec[i];
|
||||
ifft(vec, SEQ_LEN);
|
||||
h = (len - 1)/2;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
j = (SEQ_LEN - h + i)%SEQ_LEN;
|
||||
coeffs[i] = vec[j].re/(double) SEQ_LEN;
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void compute_hilbert_transform(double coeffs[], int len)
|
||||
{
|
||||
double x;
|
||||
int i;
|
||||
int h;
|
||||
|
||||
h = (len - 1)/2;
|
||||
coeffs[h] = 0.0;
|
||||
for (i = 1; i <= h; i++)
|
||||
{
|
||||
if ((i & 1))
|
||||
{
|
||||
x = 1.0/(double) i;
|
||||
coeffs[h + i] = -x;
|
||||
coeffs[h - i] = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void apply_hamming_window(double coeffs[], int len)
|
||||
{
|
||||
double w;
|
||||
int i;
|
||||
int h;
|
||||
|
||||
h = (len - 1)/2;
|
||||
for (i = 1; i <= h; i++)
|
||||
{
|
||||
w = 0.53836 - 0.46164*cos(2.0*3.1415926535*(double) (h + i)/(double) (len - 1.0));
|
||||
coeffs[h + i] *= w;
|
||||
coeffs[h - i] *= w;
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void truncate_coeffs(double coeffs[], int len, int bits, int hilbert)
|
||||
{
|
||||
double x;
|
||||
double fac;
|
||||
double max;
|
||||
double scale;
|
||||
int h;
|
||||
int i;
|
||||
|
||||
fac = pow(2.0, (double) (bits - 1.0));
|
||||
h = (len - 1)/2;
|
||||
max = (hilbert) ? coeffs[h - 1] : coeffs[h]; /* Max coeff */
|
||||
scale = (fac - 1.0)/(fac*max);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
x = coeffs[i]*scale; /* Scale coeffs so max is (fac - 1.0)/fac */
|
||||
coeffs[i] = fix(x*fac)/fac; /* Truncate */
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* filter_tools.h - A collection of routines used for filter design.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2008 Steve Underwood
|
||||
*
|
||||
* Based on:
|
||||
* mkshape -- design raised cosine FIR filter
|
||||
* A.J. Fisher, University of York <fisher@minster.york.ac.uk>, November 1996
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: filter_tools.h,v 1.3 2008/04/17 14:26:56 steveu Exp $
|
||||
*/
|
||||
|
||||
#if !defined(_FILTER_TOOLS_H_)
|
||||
#define _FILTER_TOOLS_H_
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void ifft(complex_t data[], int len);
|
||||
void apply_hamming_window(double coeffs[], int len);
|
||||
void truncate_coeffs(double coeffs[], int len, int bits, int hilbert);
|
||||
|
||||
void compute_raised_cosine_filter(double coeffs[],
|
||||
int len,
|
||||
int root,
|
||||
int sinc_compensate,
|
||||
double alpha,
|
||||
double beta);
|
||||
|
||||
void compute_hilbert_transform(double coeffs[], int len);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,483 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* floating_fudge.h - A bunch of shims, to use double maths
|
||||
* functions on platforms which lack the
|
||||
* float versions with an 'f' at the end,
|
||||
* and to deal with the vaguaries of lrint().
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2008 Steve Underwood
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: floating_fudge.h,v 1.5 2008/08/03 03:44:00 steveu Exp $
|
||||
*/
|
||||
|
||||
#if !defined(_FLOATING_FUDGE_H_)
|
||||
#define _FLOATING_FUDGE_H_
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_SINF)
|
||||
static __inline__ float sinf(float x)
|
||||
{
|
||||
return (float) sin((double) x);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_COSF)
|
||||
static __inline__ float cosf(float x)
|
||||
{
|
||||
return (float) cos((double) x);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_TANF)
|
||||
static __inline__ float tanf(float x)
|
||||
{
|
||||
return (float) tan((double) x);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_ASINF)
|
||||
static __inline__ float asinf(float x)
|
||||
{
|
||||
return (float) asin((double) x);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_ACOSF)
|
||||
static __inline__ float acosf(float x)
|
||||
{
|
||||
return (float) acos((double) x);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_ATANF)
|
||||
static __inline__ float atanf(float x)
|
||||
{
|
||||
return (float) atan((double) x);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_ATAN2F)
|
||||
static __inline__ float atan2f(float y, float x)
|
||||
{
|
||||
return (float) atan2((double) y, (double) x);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_CEILF)
|
||||
static __inline__ float ceilf(float x)
|
||||
{
|
||||
return (float) ceil((double) x);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_FLOORF)
|
||||
static __inline__ float floorf(float x)
|
||||
{
|
||||
return (float) floor((double) x);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_POWF)
|
||||
static __inline__ float powf(float x, float y)
|
||||
{
|
||||
return (float) pow((double) x, (double) y);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_EXPF)
|
||||
static __inline__ float expf(float x)
|
||||
{
|
||||
return (float) expf((double) x);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_LOGF)
|
||||
static __inline__ float logf(float x)
|
||||
{
|
||||
return (float) logf((double) x);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_LOG10F)
|
||||
static __inline__ float log10f(float x)
|
||||
{
|
||||
return (float) log10((double) x);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The following code, to handle issues with lrint() and lrintf() on various
|
||||
* platforms, is adapted from similar code in libsndfile, which is:
|
||||
*
|
||||
* Copyright (C) 2001-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* On Intel Pentium processors (especially PIII and probably P4), converting
|
||||
* from float to int is very slow. To meet the C specs, the code produced by
|
||||
* most C compilers targeting Pentium needs to change the FPU rounding mode
|
||||
* before the float to int conversion is performed.
|
||||
*
|
||||
* Changing the FPU rounding mode causes the FPU pipeline to be flushed. It
|
||||
* is this flushing of the pipeline which is so slow.
|
||||
*
|
||||
* Fortunately the ISO C99 specification defines the functions lrint, lrintf,
|
||||
* llrint and llrintf which fix this problem as a side effect.
|
||||
*
|
||||
* On Unix-like systems, the configure process should have detected the
|
||||
* presence of these functions. If they weren't found we have to replace them
|
||||
* here with a standard C cast.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The C99 prototypes for these functions are as follows:
|
||||
*
|
||||
* int rintf(float x);
|
||||
* int rint(double x);
|
||||
* long int lrintf(float x);
|
||||
* long int lrint(double x);
|
||||
* long long int llrintf(float x);
|
||||
* long long int llrint(double x);
|
||||
*
|
||||
* The presence of the required functions are detected during the configure
|
||||
* process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in
|
||||
* the config file.
|
||||
*/
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
/*
|
||||
* CYGWIN has lrint and lrintf functions, but they are slow and buggy:
|
||||
* http://sourceware.org/ml/cygwin/2005-06/msg00153.html
|
||||
* http://sourceware.org/ml/cygwin/2005-09/msg00047.html
|
||||
* The latest version of cygwin seems to have made no effort to fix this.
|
||||
* These replacement functions (pulled from the Public Domain MinGW
|
||||
* math.h header) replace the native versions.
|
||||
*/
|
||||
static __inline__ long int lrint(double x)
|
||||
{
|
||||
long int retval;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"fistpl %0"
|
||||
: "=m" (retval)
|
||||
: "t" (x)
|
||||
: "st"
|
||||
);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static __inline__ long int lrintf(float x)
|
||||
{
|
||||
long int retval;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"fistpl %0"
|
||||
: "=m" (retval)
|
||||
: "t" (x)
|
||||
: "st"
|
||||
);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static __inline__ long int lfastrint(double x)
|
||||
{
|
||||
long int retval;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"fistpl %0"
|
||||
: "=m" (retval)
|
||||
: "t" (x)
|
||||
: "st"
|
||||
);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static __inline__ long int lfastrintf(float x)
|
||||
{
|
||||
long int retval;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"fistpl %0"
|
||||
: "=m" (retval)
|
||||
: "t" (x)
|
||||
: "st"
|
||||
);
|
||||
return retval;
|
||||
}
|
||||
#elif defined(HAVE_LRINT) && defined(HAVE_LRINTF)
|
||||
|
||||
#if defined(__i386__)
|
||||
/* These routines are guaranteed fast on an i386 machine. Using the built in
|
||||
lrint() and lrintf() should be similar, but they may not always be enabled.
|
||||
Sometimes, especially with "-O0", you might get slow calls to routines. */
|
||||
static __inline__ long int lfastrint(double x)
|
||||
{
|
||||
long int retval;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"fistpl %0"
|
||||
: "=m" (retval)
|
||||
: "t" (x)
|
||||
: "st"
|
||||
);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static __inline__ long int lfastrintf(float x)
|
||||
{
|
||||
long int retval;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"fistpl %0"
|
||||
: "=m" (retval)
|
||||
: "t" (x)
|
||||
: "st"
|
||||
);
|
||||
return retval;
|
||||
}
|
||||
#elif defined(__x86_64__)
|
||||
/* On an x86_64 machine, the fastest thing seems to be a pure assignment from a
|
||||
double or float to an int. It looks like the design on the x86_64 took account
|
||||
of the default behaviour specified for C. */
|
||||
static __inline__ long int lfastrint(double x)
|
||||
{
|
||||
return (long int) (x);
|
||||
}
|
||||
|
||||
static __inline__ long int lfastrintf(float x)
|
||||
{
|
||||
return (long int) (x);
|
||||
}
|
||||
#elif defined(__ppc__) || defined(__powerpc__)
|
||||
static __inline__ long int lfastrint(register double x)
|
||||
{
|
||||
int res[2];
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"fctiw %1, %1\n\t"
|
||||
"stfd %1, %0"
|
||||
: "=m" (res) /* Output */
|
||||
: "f" (x) /* Input */
|
||||
: "memory"
|
||||
);
|
||||
|
||||
return res[1];
|
||||
}
|
||||
|
||||
static __inline__ long int lfastrintf(register float x)
|
||||
{
|
||||
int res[2];
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"fctiw %1, %1\n\t"
|
||||
"stfd %1, %0"
|
||||
: "=m" (res) /* Output */
|
||||
: "f" (x) /* Input */
|
||||
: "memory"
|
||||
);
|
||||
|
||||
return res[1];
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(WIN32) || defined(_WIN32)
|
||||
/*
|
||||
* Win32 doesn't seem to have the lrint() and lrintf() functions.
|
||||
* Therefore implement inline versions of these functions here.
|
||||
*/
|
||||
__inline long int lrint(double x)
|
||||
{
|
||||
long int i;
|
||||
|
||||
_asm
|
||||
{
|
||||
fld x
|
||||
fistp i
|
||||
};
|
||||
return i;
|
||||
}
|
||||
|
||||
__inline long int lrintf(float x)
|
||||
{
|
||||
long int i;
|
||||
|
||||
_asm
|
||||
{
|
||||
fld x
|
||||
fistp i
|
||||
};
|
||||
return i;
|
||||
}
|
||||
|
||||
__inline long int lfastrint(double x)
|
||||
{
|
||||
long int i;
|
||||
|
||||
_asm
|
||||
{
|
||||
fld x
|
||||
fistp i
|
||||
};
|
||||
return i;
|
||||
}
|
||||
|
||||
__inline long int lfastrintf(float x)
|
||||
{
|
||||
long int i;
|
||||
|
||||
_asm
|
||||
{
|
||||
fld x
|
||||
fistp i
|
||||
};
|
||||
return i;
|
||||
}
|
||||
#elif defined(WIN64) || defined(_WIN64)
|
||||
/*
|
||||
* Win64 machines will do best with a simple assignment.
|
||||
*/
|
||||
__inline long int lfastrint(double x)
|
||||
{
|
||||
return (long int) (x);
|
||||
}
|
||||
|
||||
__inline long int lfastrintf(float x)
|
||||
{
|
||||
return (long int) (x);
|
||||
}
|
||||
#elif defined(__MWERKS__) && defined(macintosh)
|
||||
/* This MacOS 9 solution was provided by Stephane Letz */
|
||||
|
||||
long int __inline__ lfastrint(register double x)
|
||||
{
|
||||
long int res[2];
|
||||
|
||||
asm
|
||||
{
|
||||
fctiw x, x
|
||||
stfd x, res
|
||||
}
|
||||
return res[1];
|
||||
}
|
||||
|
||||
long int __inline__ lfastrintf(register float x)
|
||||
{
|
||||
long int res[2];
|
||||
|
||||
asm
|
||||
{
|
||||
fctiw x, x
|
||||
stfd x, res
|
||||
}
|
||||
return res[1];
|
||||
}
|
||||
|
||||
#elif defined(__MACH__) && defined(__APPLE__) && (defined(__ppc__) || defined(__powerpc__))
|
||||
/* For Apple Mac OS/X - do recent versions still need this? */
|
||||
|
||||
static __inline__ long int lfastrint(register double x)
|
||||
{
|
||||
int res[2];
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"fctiw %1, %1\n\t"
|
||||
"stfd %1, %0"
|
||||
: "=m" (res) /* Output */
|
||||
: "f" (x) /* Input */
|
||||
: "memory"
|
||||
);
|
||||
|
||||
return res[1];
|
||||
}
|
||||
|
||||
static __inline__ long int lfastrintf(register float x)
|
||||
{
|
||||
int res[2];
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"fctiw %1, %1\n\t"
|
||||
"stfd %1, %0"
|
||||
: "=m" (res) /* Output */
|
||||
: "f" (x) /* Input */
|
||||
: "memory"
|
||||
);
|
||||
|
||||
return res[1];
|
||||
}
|
||||
#else
|
||||
/* There is nothing else to do, but use a simple casting operation, instead of a real
|
||||
rint() type function. Since we are only trying to use rint() to speed up conversions,
|
||||
the accuracy issues related to changing the rounding scheme are of little concern
|
||||
to us. */
|
||||
|
||||
#if !defined(__sgi)
|
||||
#warning "No usable lrint() and lrintf() functions available."
|
||||
#warning "Replacing these functions with a simple C cast."
|
||||
#endif
|
||||
|
||||
static __inline__ long int lfastrint(double x)
|
||||
{
|
||||
return (long int) (x);
|
||||
}
|
||||
|
||||
static __inline__ long int lfastrintf(float x)
|
||||
{
|
||||
return (long int) (x);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* fsk.c - FSK modem transmit and receive parts
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 GNU Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: fsk.c,v 1.44 2008/07/16 17:01:49 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/complex.h"
|
||||
#include "spandsp/dds.h"
|
||||
#include "spandsp/power_meter.h"
|
||||
#include "spandsp/async.h"
|
||||
#include "spandsp/fsk.h"
|
||||
|
||||
const fsk_spec_t preset_fsk_specs[] =
|
||||
{
|
||||
{
|
||||
"V21 ch 1",
|
||||
1080 + 100,
|
||||
1080 - 100,
|
||||
-14,
|
||||
-30,
|
||||
300*100
|
||||
},
|
||||
{
|
||||
"V21 ch 2",
|
||||
1750 + 100,
|
||||
1750 - 100,
|
||||
-14,
|
||||
-30,
|
||||
300*100
|
||||
},
|
||||
{
|
||||
"V23 ch 1",
|
||||
2100,
|
||||
1300,
|
||||
-14,
|
||||
-30,
|
||||
1200*100
|
||||
},
|
||||
{
|
||||
"V23 ch 2",
|
||||
450,
|
||||
390,
|
||||
-14,
|
||||
-30,
|
||||
75*100
|
||||
},
|
||||
{
|
||||
"Bell103 ch 1",
|
||||
2125 - 100,
|
||||
2125 + 100,
|
||||
-14,
|
||||
-30,
|
||||
300*100
|
||||
},
|
||||
{
|
||||
"Bell103 ch 2",
|
||||
1170 - 100,
|
||||
1170 + 100,
|
||||
-14,
|
||||
-30,
|
||||
300*100
|
||||
},
|
||||
{
|
||||
"Bell202",
|
||||
2200,
|
||||
1200,
|
||||
-14,
|
||||
-30,
|
||||
1200*100
|
||||
},
|
||||
{
|
||||
"Weitbrecht", /* Used for TDD (Telecoms Device for the Deaf) */
|
||||
1800,
|
||||
1400,
|
||||
-14,
|
||||
-30,
|
||||
4545
|
||||
}
|
||||
};
|
||||
|
||||
fsk_tx_state_t *fsk_tx_init(fsk_tx_state_t *s,
|
||||
const fsk_spec_t *spec,
|
||||
get_bit_func_t get_bit,
|
||||
void *user_data)
|
||||
{
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (fsk_tx_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->baud_rate = spec->baud_rate;
|
||||
s->get_bit = get_bit;
|
||||
s->get_bit_user_data = user_data;
|
||||
|
||||
s->phase_rates[0] = dds_phase_rate((float) spec->freq_zero);
|
||||
s->phase_rates[1] = dds_phase_rate((float) spec->freq_one);
|
||||
s->scaling = dds_scaling_dbm0((float) spec->tx_level);
|
||||
/* Initialise fractional sample baud generation. */
|
||||
s->phase_acc = 0;
|
||||
s->baud_inc = s->baud_rate;
|
||||
s->baud_frac = 0;
|
||||
s->current_phase_rate = s->phase_rates[1];
|
||||
|
||||
s->shutdown = FALSE;
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int fsk_tx(fsk_tx_state_t *s, int16_t *amp, int len)
|
||||
{
|
||||
int sample;
|
||||
int bit;
|
||||
|
||||
if (s->shutdown)
|
||||
return 0;
|
||||
/* Make the transitions between 0 and 1 phase coherent, but instantaneous
|
||||
jumps. There is currently no interpolation for bauds that end mid-sample.
|
||||
Mainstream users will not care. Some specialist users might have a problem
|
||||
with them, if they care about accurate transition timing. */
|
||||
for (sample = 0; sample < len; sample++)
|
||||
{
|
||||
if ((s->baud_frac += s->baud_inc) >= SAMPLE_RATE*100)
|
||||
{
|
||||
s->baud_frac -= SAMPLE_RATE*100;
|
||||
if ((bit = s->get_bit(s->get_bit_user_data)) == PUTBIT_END_OF_DATA)
|
||||
{
|
||||
if (s->status_handler)
|
||||
s->status_handler(s->status_user_data, MODEM_TX_STATUS_DATA_EXHAUSTED);
|
||||
if (s->status_handler)
|
||||
s->status_handler(s->status_user_data, MODEM_TX_STATUS_SHUTDOWN_COMPLETE);
|
||||
s->shutdown = TRUE;
|
||||
break;
|
||||
}
|
||||
s->current_phase_rate = s->phase_rates[bit & 1];
|
||||
}
|
||||
amp[sample] = dds_mod(&(s->phase_acc), s->current_phase_rate, s->scaling, 0);
|
||||
}
|
||||
return sample;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void fsk_tx_power(fsk_tx_state_t *s, float power)
|
||||
{
|
||||
s->scaling = dds_scaling_dbm0(power);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void fsk_tx_set_get_bit(fsk_tx_state_t *s, get_bit_func_t get_bit, void *user_data)
|
||||
{
|
||||
s->get_bit = get_bit;
|
||||
s->get_bit_user_data = user_data;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void fsk_tx_set_modem_status_handler(fsk_tx_state_t *s, modem_tx_status_func_t handler, void *user_data)
|
||||
{
|
||||
s->status_handler = handler;
|
||||
s->status_user_data = user_data;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void fsk_rx_signal_cutoff(fsk_rx_state_t *s, float cutoff)
|
||||
{
|
||||
/* The 6.04 allows for the gain of the DC blocker */
|
||||
s->carrier_on_power = (int32_t) (power_meter_level_dbm0(cutoff + 2.5f - 6.04f));
|
||||
s->carrier_off_power = (int32_t) (power_meter_level_dbm0(cutoff - 2.5f - 6.04f));
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
float fsk_rx_signal_power(fsk_rx_state_t *s)
|
||||
{
|
||||
return power_meter_current_dbm0(&s->power);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void fsk_rx_set_put_bit(fsk_rx_state_t *s, put_bit_func_t put_bit, void *user_data)
|
||||
{
|
||||
s->put_bit = put_bit;
|
||||
s->put_bit_user_data = user_data;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void fsk_rx_set_modem_status_handler(fsk_rx_state_t *s, modem_tx_status_func_t handler, void *user_data)
|
||||
{
|
||||
s->status_handler = handler;
|
||||
s->status_user_data = user_data;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
fsk_rx_state_t *fsk_rx_init(fsk_rx_state_t *s,
|
||||
const fsk_spec_t *spec,
|
||||
int sync_mode,
|
||||
put_bit_func_t put_bit,
|
||||
void *user_data)
|
||||
{
|
||||
int chop;
|
||||
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (fsk_rx_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->baud_rate = spec->baud_rate;
|
||||
s->sync_mode = sync_mode;
|
||||
fsk_rx_signal_cutoff(s, (float) spec->min_level);
|
||||
s->put_bit = put_bit;
|
||||
s->put_bit_user_data = user_data;
|
||||
|
||||
/* Detect by correlating against the tones we want, over a period
|
||||
of one baud. The correlation must be quadrature. */
|
||||
|
||||
/* First we need the quadrature tone generators to correlate
|
||||
against. */
|
||||
s->phase_rate[0] = dds_phase_rate((float) spec->freq_zero);
|
||||
s->phase_rate[1] = dds_phase_rate((float) spec->freq_one);
|
||||
s->phase_acc[0] = 0;
|
||||
s->phase_acc[1] = 0;
|
||||
s->last_sample = 0;
|
||||
|
||||
/* The correlation should be over one baud. */
|
||||
s->correlation_span = SAMPLE_RATE*100/spec->baud_rate;
|
||||
/* But limit it for very slow baud rates, so we do not overflow our
|
||||
buffer. */
|
||||
if (s->correlation_span > FSK_MAX_WINDOW_LEN)
|
||||
s->correlation_span = FSK_MAX_WINDOW_LEN;
|
||||
|
||||
/* We need to scale, to avoid overflow in the correlation. */
|
||||
s->scaling_shift = 0;
|
||||
chop = s->correlation_span;
|
||||
while (chop != 0)
|
||||
{
|
||||
s->scaling_shift++;
|
||||
chop >>= 1;
|
||||
}
|
||||
|
||||
/* Initialise the baud/bit rate tracking. */
|
||||
s->baud_inc = s->baud_rate;
|
||||
s->baud_pll = 0;
|
||||
|
||||
/* Initialise a power detector, so sense when a signal is present. */
|
||||
power_meter_init(&(s->power), 4);
|
||||
s->signal_present = 0;
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void report_status_change(fsk_rx_state_t *s, int status)
|
||||
{
|
||||
if (s->status_handler)
|
||||
s->status_handler(s->status_user_data, status);
|
||||
else if (s->put_bit)
|
||||
s->put_bit(s->put_bit_user_data, status);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len)
|
||||
{
|
||||
int buf_ptr;
|
||||
int baudstate;
|
||||
int i;
|
||||
int j;
|
||||
int16_t x;
|
||||
int32_t dot;
|
||||
int32_t sum[2];
|
||||
int32_t power;
|
||||
complexi_t ph;
|
||||
|
||||
buf_ptr = s->buf_ptr;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
/* If there isn't much signal, don't demodulate - it will only produce
|
||||
useless junk results. */
|
||||
/* There should be no DC in the signal, but sometimes there is.
|
||||
We need to measure the power with the DC blocked, but not using
|
||||
a slow to respond DC blocker. Use the most elementary HPF. */
|
||||
x = amp[i] >> 1;
|
||||
power = power_meter_update(&(s->power), x - s->last_sample);
|
||||
s->last_sample = x;
|
||||
if (s->signal_present)
|
||||
{
|
||||
/* Look for power below turn-off threshold to turn the carrier off */
|
||||
if (power < s->carrier_off_power)
|
||||
{
|
||||
if (--s->signal_present <= 0)
|
||||
{
|
||||
/* Count down a short delay, to ensure we push the last
|
||||
few bits through the filters before stopping. */
|
||||
report_status_change(s, PUTBIT_CARRIER_DOWN);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Look for power exceeding turn-on threshold to turn the carrier on */
|
||||
if (power < s->carrier_on_power)
|
||||
continue;
|
||||
s->signal_present = 1;
|
||||
report_status_change(s, PUTBIT_CARRIER_UP);
|
||||
}
|
||||
/* Non-coherent FSK demodulation by correlation with the target tones
|
||||
over a one baud interval. The slow V.xx specs. are too open ended
|
||||
to allow anything fancier to be used. The dot products are calculated
|
||||
using a sliding window approach, so the compute load is not that great. */
|
||||
/* The *totally* asynchronous character to character behaviour of these
|
||||
modems, when carrying async. data, seems to force a sample by sample
|
||||
approach. */
|
||||
for (j = 0; j < 2; j++)
|
||||
{
|
||||
s->dot[j].re -= s->window[j][buf_ptr].re;
|
||||
s->dot[j].im -= s->window[j][buf_ptr].im;
|
||||
|
||||
ph = dds_complexi(&(s->phase_acc[j]), s->phase_rate[j]);
|
||||
s->window[j][buf_ptr].re = (ph.re*amp[i]) >> s->scaling_shift;
|
||||
s->window[j][buf_ptr].im = (ph.im*amp[i]) >> s->scaling_shift;
|
||||
|
||||
s->dot[j].re += s->window[j][buf_ptr].re;
|
||||
s->dot[j].im += s->window[j][buf_ptr].im;
|
||||
|
||||
dot = s->dot[j].re >> 15;
|
||||
sum[j] = dot*dot;
|
||||
dot = s->dot[j].im >> 15;
|
||||
sum[j] += dot*dot;
|
||||
}
|
||||
baudstate = (sum[0] < sum[1]);
|
||||
|
||||
if (s->lastbit != baudstate)
|
||||
{
|
||||
s->lastbit = baudstate;
|
||||
if (s->sync_mode)
|
||||
{
|
||||
/* For synchronous use (e.g. HDLC channels in FAX modems), nudge
|
||||
the baud phase gently, trying to keep it centred on the bauds. */
|
||||
if (s->baud_pll < (SAMPLE_RATE*50))
|
||||
s->baud_pll += (s->baud_inc >> 3);
|
||||
else
|
||||
s->baud_pll -= (s->baud_inc >> 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* For async. operation, believe transitions completely, and
|
||||
sample appropriately. This allows instant start on the first
|
||||
transition. */
|
||||
/* We must now be about half way to a sampling point. We do not do
|
||||
any fractional sample estimation of the transitions, so this is
|
||||
the most accurate baud alignment we can do. */
|
||||
s->baud_pll = SAMPLE_RATE*50;
|
||||
}
|
||||
|
||||
}
|
||||
if ((s->baud_pll += s->baud_inc) >= (SAMPLE_RATE*100))
|
||||
{
|
||||
/* We should be in the middle of a baud now, so report the current
|
||||
state as the next bit */
|
||||
s->baud_pll -= (SAMPLE_RATE*100);
|
||||
s->put_bit(s->put_bit_user_data, baudstate);
|
||||
}
|
||||
if (++buf_ptr >= s->correlation_span)
|
||||
buf_ptr = 0;
|
||||
}
|
||||
s->buf_ptr = buf_ptr;
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* g711.c - A-law and u-law transcoding routines
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.11 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/bit_operations.h"
|
||||
#include "spandsp/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 --------------------------------------------------------*/
|
||||
|
||||
int g711_decode(g711_state_t *s,
|
||||
int16_t amp[],
|
||||
const uint8_t g711_data[],
|
||||
int g711_bytes)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (s->mode == G711_ALAW)
|
||||
{
|
||||
for (i = 0; i < g711_bytes; i++)
|
||||
amp[i] = alaw_to_linear(g711_data[i]);
|
||||
/*endfor*/
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < g711_bytes; i++)
|
||||
amp[i] = ulaw_to_linear(g711_data[i]);
|
||||
/*endfor*/
|
||||
}
|
||||
/*endif*/
|
||||
return g711_bytes;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int g711_encode(g711_state_t *s,
|
||||
uint8_t g711_data[],
|
||||
const int16_t amp[],
|
||||
int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (s->mode == G711_ALAW)
|
||||
{
|
||||
for (i = 0; i < len; i++)
|
||||
g711_data[i] = linear_to_alaw(amp[i]);
|
||||
/*endfor*/
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < len; i++)
|
||||
g711_data[i] = linear_to_ulaw(amp[i]);
|
||||
/*endfor*/
|
||||
}
|
||||
/*endif*/
|
||||
return len;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int g711_transcode(g711_state_t *s,
|
||||
uint8_t g711_out[],
|
||||
const uint8_t g711_in[],
|
||||
int g711_bytes)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (s->mode == G711_ALAW)
|
||||
{
|
||||
for (i = 0; i < g711_bytes; i++)
|
||||
g711_out[i] = alaw_to_ulaw_table[g711_in[i]];
|
||||
/*endfor*/
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < g711_bytes; i++)
|
||||
g711_out[i] = ulaw_to_alaw_table[g711_in[i]];
|
||||
/*endfor*/
|
||||
}
|
||||
/*endif*/
|
||||
return g711_bytes;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
g711_state_t *g711_init(g711_state_t *s, int mode)
|
||||
{
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (g711_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
s->mode = mode;
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int g711_release(g711_state_t *s)
|
||||
{
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* g722_decode.c - The ITU G.722 codec, decode part.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.24 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <memory.h>
|
||||
#include <stdlib.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/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 ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* g722_encode.c - The ITU G.722 codec, encode part.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.22 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <memory.h>
|
||||
#include <stdlib.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/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 ------------------------------------------------------------*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* gsm0610_decode.c - GSM 06.10 full rate speech codec.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.21 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/bitstream.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/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 len)
|
||||
{
|
||||
gsm0610_frame_t frame[2];
|
||||
int bytes;
|
||||
int samples;
|
||||
int i;
|
||||
|
||||
samples = 0;
|
||||
for (i = 0; i < len; i += bytes)
|
||||
{
|
||||
switch (s->packing)
|
||||
{
|
||||
default:
|
||||
case GSM0610_PACKING_NONE:
|
||||
if ((bytes = gsm0610_unpack_none(frame, &code[i])) < 0)
|
||||
return 0;
|
||||
decode_a_frame(s, &[samples], frame);
|
||||
samples += GSM0610_FRAME_LEN;
|
||||
break;
|
||||
case GSM0610_PACKING_WAV49:
|
||||
if ((bytes = gsm0610_unpack_wav49(frame, &code[i])) < 0)
|
||||
return 0;
|
||||
decode_a_frame(s, &[samples], frame);
|
||||
samples += GSM0610_FRAME_LEN;
|
||||
decode_a_frame(s, &[samples], frame + 1);
|
||||
samples += GSM0610_FRAME_LEN;
|
||||
break;
|
||||
case GSM0610_PACKING_VOIP:
|
||||
if ((bytes = gsm0610_unpack_voip(frame, &code[i])) < 0)
|
||||
return 0;
|
||||
decode_a_frame(s, &[samples], frame);
|
||||
samples += GSM0610_FRAME_LEN;
|
||||
break;
|
||||
}
|
||||
/*endswitch*/
|
||||
}
|
||||
/*endfor*/
|
||||
return samples;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* gsm0610_encode.c - GSM 06.10 full rate speech codec.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.25 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/bitstream.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/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)
|
||||
{
|
||||
if ((s = (gsm0610_state_t *) malloc(sizeof (*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];
|
||||
}
|
||||
/*endfor*/
|
||||
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++ = (uint8_t) (sr >> 4);
|
||||
sr = (sr >> 5) | (s->LARc[2] << 11);
|
||||
*c++ = (uint8_t) (sr >> 7);
|
||||
sr = (sr >> 5) | (s->LARc[3] << 11);
|
||||
sr = (sr >> 4) | (s->LARc[4] << 12);
|
||||
*c++ = (uint8_t) (sr >> 6);
|
||||
sr = (sr >> 4) | (s->LARc[5] << 12);
|
||||
sr = (sr >> 3) | (s->LARc[6] << 13);
|
||||
*c++ = (uint8_t) (sr >> 7);
|
||||
sr = (sr >> 3) | (s->LARc[7] << 13);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
sr = (sr >> 7) | (s->Nc[i] << 9);
|
||||
*c++ = (uint8_t) (sr >> 5);
|
||||
sr = (sr >> 2) | (s->bc[i] << 14);
|
||||
sr = (sr >> 2) | (s->Mc[i] << 14);
|
||||
sr = (sr >> 6) | (s->xmaxc[i] << 10);
|
||||
*c++ = (uint8_t) (sr >> 3);
|
||||
sr = (sr >> 3) | (s->xMc[i][0] << 13);
|
||||
*c++ = (uint8_t) (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++ = (uint8_t) (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++ = (uint8_t) (sr >> 6);
|
||||
sr = (sr >> 3) | (s->xMc[i][7] << 13);
|
||||
sr = (sr >> 3) | (s->xMc[i][8] << 13);
|
||||
*c++ = (uint8_t) (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++ = (uint8_t) (sr >> 7);
|
||||
sr = (sr >> 3) | (s->xMc[i][12] << 13);
|
||||
}
|
||||
/*endfor*/
|
||||
|
||||
s++;
|
||||
sr = (sr >> 6) | (s->LARc[0] << 10);
|
||||
*c++ = (uint8_t) (sr >> 6);
|
||||
sr = (sr >> 6) | (s->LARc[1] << 10);
|
||||
*c++ = (uint8_t) (sr >> 8);
|
||||
sr = (sr >> 5) | (s->LARc[2] << 11);
|
||||
sr = (sr >> 5) | (s->LARc[3] << 11);
|
||||
*c++ = (uint8_t) (sr >> 6);
|
||||
sr = (sr >> 4) | (s->LARc[4] << 12);
|
||||
sr = (sr >> 4) | (s->LARc[5] << 12);
|
||||
*c++ = (uint8_t) (sr >> 6);
|
||||
sr = (sr >> 3) | (s->LARc[6] << 13);
|
||||
sr = (sr >> 3) | (s->LARc[7] << 13);
|
||||
*c++ = (uint8_t) (sr >> 8);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
sr = (sr >> 7) | (s->Nc[i] << 9);
|
||||
sr = (sr >> 2) | (s->bc[i] << 14);
|
||||
*c++ = (uint8_t) (sr >> 7);
|
||||
sr = (sr >> 2) | (s->Mc[i] << 14);
|
||||
sr = (sr >> 6) | (s->xmaxc[i] << 10);
|
||||
*c++ = (uint8_t) (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++ = (uint8_t) (sr >> 6);
|
||||
sr = (sr >> 3) | (s->xMc[i][3] << 13);
|
||||
sr = (sr >> 3) | (s->xMc[i][4] << 13);
|
||||
*c++ = (uint8_t) (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++ = (uint8_t) (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++ = (uint8_t) (sr >> 6);
|
||||
sr = (sr >> 3) | (s->xMc[i][11] << 13);
|
||||
sr = (sr >> 3) | (s->xMc[i][12] << 13);
|
||||
*c++ = (uint8_t) (sr >> 8);
|
||||
}
|
||||
/*endfor*/
|
||||
return 65;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int gsm0610_pack_voip(uint8_t c[33], const gsm0610_frame_t *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
*c++ = (uint8_t) (((GSM0610_MAGIC & 0xF) << 4)
|
||||
| ((s->LARc[0] >> 2) & 0xF));
|
||||
*c++ = (uint8_t) (((s->LARc[0] & 0x3) << 6)
|
||||
| (s->LARc[1] & 0x3F));
|
||||
*c++ = (uint8_t) (((s->LARc[2] & 0x1F) << 3)
|
||||
| ((s->LARc[3] >> 2) & 0x7));
|
||||
*c++ = (uint8_t) (((s->LARc[3] & 0x3) << 6)
|
||||
| ((s->LARc[4] & 0xF) << 2)
|
||||
| ((s->LARc[5] >> 2) & 0x3));
|
||||
*c++ = (uint8_t) (((s->LARc[5] & 0x3) << 6)
|
||||
| ((s->LARc[6] & 0x7) << 3)
|
||||
| (s->LARc[7] & 0x7));
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
*c++ = (uint8_t) (((s->Nc[i] & 0x7F) << 1)
|
||||
| ((s->bc[i] >> 1) & 0x1));
|
||||
*c++ = (uint8_t) (((s->bc[i] & 0x1) << 7)
|
||||
| ((s->Mc[i] & 0x3) << 5)
|
||||
| ((s->xmaxc[i] >> 1) & 0x1F));
|
||||
*c++ = (uint8_t) (((s->xmaxc[i] & 0x1) << 7)
|
||||
| ((s->xMc[i][0] & 0x7) << 4)
|
||||
| ((s->xMc[i][1] & 0x7) << 1)
|
||||
| ((s->xMc[i][2] >> 2) & 0x1));
|
||||
*c++ = (uint8_t) (((s->xMc[i][2] & 0x3) << 6)
|
||||
| ((s->xMc[i][3] & 0x7) << 3)
|
||||
| (s->xMc[i][4] & 0x7));
|
||||
*c++ = (uint8_t) (((s->xMc[i][5] & 0x7) << 5)
|
||||
| ((s->xMc[i][6] & 0x7) << 2)
|
||||
| ((s->xMc[i][7] >> 1) & 0x3));
|
||||
*c++ = (uint8_t) (((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++ = (uint8_t) (((s->xMc[i][10] & 0x3) << 6)
|
||||
| ((s->xMc[i][11] & 0x7) << 3)
|
||||
| (s->xMc[i][12] & 0x7));
|
||||
}
|
||||
/*endfor*/
|
||||
return 33;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int gsm0610_encode(gsm0610_state_t *s, uint8_t code[], const int16_t amp[], int len)
|
||||
{
|
||||
gsm0610_frame_t frame[2];
|
||||
int bytes;
|
||||
int i;
|
||||
|
||||
bytes = 0;
|
||||
for (i = 0; i < len; i += GSM0610_FRAME_LEN)
|
||||
{
|
||||
encode_a_frame(s, frame, &[i]);
|
||||
switch (s->packing)
|
||||
{
|
||||
case GSM0610_PACKING_WAV49:
|
||||
i += GSM0610_FRAME_LEN;
|
||||
encode_a_frame(s, frame + 1, &[i]);
|
||||
bytes += gsm0610_pack_wav49(&code[bytes], frame);
|
||||
break;
|
||||
case GSM0610_PACKING_VOIP:
|
||||
bytes += gsm0610_pack_voip(&code[bytes], frame);
|
||||
break;
|
||||
default:
|
||||
bytes += gsm0610_pack_none(&code[bytes], frame);
|
||||
break;
|
||||
}
|
||||
/*endswitch*/
|
||||
}
|
||||
/*endfor*/
|
||||
return bytes;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -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 <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.10 2008/04/17 14:26:56 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 (int16_t) (-(a < 0));
|
||||
/*endif*/
|
||||
if (n <= -16)
|
||||
return 0;
|
||||
/*endif*/
|
||||
if (n < 0)
|
||||
return (int16_t) (a << -n);
|
||||
/*endif*/
|
||||
return (int16_t) (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 (int16_t) (-(a < 0));
|
||||
/*endif*/
|
||||
if (n < 0)
|
||||
return gsm_asr(a, -n);
|
||||
/*endif*/
|
||||
return (int16_t) (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 ---------------------------------------------------------*/
|
||||
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* gsm0610_long_term.c - GSM 06.10 full rate speech codec.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.16 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/bitstream.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/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)
|
||||
{
|
||||
#if 0
|
||||
assert(d);
|
||||
assert(dp);
|
||||
assert(e);
|
||||
assert(dpp);
|
||||
assert(Nc);
|
||||
assert(bc);
|
||||
#endif
|
||||
|
||||
*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 ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,534 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* gsm0610_lpc.c - GSM 06.10 full rate speech codec.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.20 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/bitstream.h"
|
||||
#include "spandsp/bit_operations.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/vector_int.h"
|
||||
#include "spandsp/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 ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* gsm0610_preprocess.c - GSM 06.10 full rate speech codec.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.13 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/bitstream.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/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 ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,541 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* gsm0610_rpe.c - GSM 06.10 full rate speech codec.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.21 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/bitstream.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/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 union
|
||||
{
|
||||
int16_t gsm_H[12];
|
||||
uint64_t x[3];
|
||||
} gsm_H =
|
||||
{
|
||||
{
|
||||
-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" (gsm_H.x[0]), [gsm_H8] "X" (gsm_H.x[1]), [gsm_H16] "X" (gsm_H.x[2])
|
||||
: "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]).
|
||||
*/
|
||||
#if 0
|
||||
assert(mant >= 0 && mant <= 7);
|
||||
#endif
|
||||
|
||||
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 ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* gsm0610_short_term.c - GSM 06.10 full rate speech codec.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.15 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/bitstream.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/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 ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,571 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* hdlc.c
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 GNU Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: hdlc.c,v 1.60 2008/05/13 13:17:22 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/async.h"
|
||||
#include "spandsp/crc.h"
|
||||
#include "spandsp/bit_operations.h"
|
||||
#include "spandsp/hdlc.h"
|
||||
|
||||
static void rx_special_condition(hdlc_rx_state_t *s, int condition)
|
||||
{
|
||||
/* Special conditions */
|
||||
switch (condition)
|
||||
{
|
||||
case PUTBIT_CARRIER_UP:
|
||||
case PUTBIT_TRAINING_SUCCEEDED:
|
||||
/* Reset the HDLC receiver. */
|
||||
s->raw_bit_stream = 0;
|
||||
s->len = 0;
|
||||
s->num_bits = 0;
|
||||
s->flags_seen = 0;
|
||||
s->framing_ok_announced = FALSE;
|
||||
/* Fall through */
|
||||
case PUTBIT_TRAINING_IN_PROGRESS:
|
||||
case PUTBIT_TRAINING_FAILED:
|
||||
case PUTBIT_CARRIER_DOWN:
|
||||
case PUTBIT_END_OF_DATA:
|
||||
s->frame_handler(s->user_data, NULL, condition, TRUE);
|
||||
break;
|
||||
default:
|
||||
//printf("Eh!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static __inline__ void octet_set_and_count(hdlc_rx_state_t *s)
|
||||
{
|
||||
if (s->octet_count_report_interval == 0)
|
||||
return;
|
||||
|
||||
/* If we are not in octet counting mode, we start it.
|
||||
If we are in octet counting mode, we update it. */
|
||||
if (s->octet_counting_mode)
|
||||
{
|
||||
if (--s->octet_count <= 0)
|
||||
{
|
||||
s->octet_count = s->octet_count_report_interval;
|
||||
s->frame_handler(s->user_data, NULL, PUTBIT_OCTET_REPORT, TRUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s->octet_counting_mode = TRUE;
|
||||
s->octet_count = s->octet_count_report_interval;
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static __inline__ void octet_count(hdlc_rx_state_t *s)
|
||||
{
|
||||
if (s->octet_count_report_interval == 0)
|
||||
return;
|
||||
|
||||
/* If we are not in octet counting mode, we start it.
|
||||
If we are in octet counting mode, we update it. */
|
||||
if (s->octet_counting_mode)
|
||||
{
|
||||
if (--s->octet_count <= 0)
|
||||
{
|
||||
s->octet_count = s->octet_count_report_interval;
|
||||
s->frame_handler(s->user_data, NULL, PUTBIT_OCTET_REPORT, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void rx_flag_or_abort(hdlc_rx_state_t *s)
|
||||
{
|
||||
if ((s->raw_bit_stream & 0x8000))
|
||||
{
|
||||
/* Hit HDLC abort */
|
||||
s->rx_aborts++;
|
||||
s->frame_handler(s->user_data, NULL, PUTBIT_ABORT, TRUE);
|
||||
/* If we have not yet seen enough flags, restart the count. If we
|
||||
are beyond that point, just back off one step, so we need to see
|
||||
another flag before proceeding to collect frame octets. */
|
||||
if (s->flags_seen < s->framing_ok_threshold)
|
||||
s->flags_seen = 0;
|
||||
else
|
||||
s->flags_seen = s->framing_ok_threshold - 1;
|
||||
/* An abort starts octet counting */
|
||||
octet_set_and_count(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Hit HDLC flag */
|
||||
/* A flag clears octet counting */
|
||||
s->octet_counting_mode = FALSE;
|
||||
if (s->flags_seen >= s->framing_ok_threshold)
|
||||
{
|
||||
/* We may have a frame, or we may have back to back flags */
|
||||
if (s->len)
|
||||
{
|
||||
if (s->num_bits == 7 && s->len >= s->crc_bytes && s->len <= s->max_frame_len)
|
||||
{
|
||||
if ((s->crc_bytes == 2 && crc_itu16_check(s->buffer, s->len))
|
||||
||
|
||||
(s->crc_bytes != 2 && crc_itu32_check(s->buffer, s->len)))
|
||||
{
|
||||
s->rx_frames++;
|
||||
s->rx_bytes += s->len - s->crc_bytes;
|
||||
s->len -= s->crc_bytes;
|
||||
s->frame_handler(s->user_data, s->buffer, s->len, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
s->rx_crc_errors++;
|
||||
if (s->report_bad_frames)
|
||||
{
|
||||
s->len -= s->crc_bytes;
|
||||
s->frame_handler(s->user_data, s->buffer, s->len, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Frame too short or too long, or the flag is misaligned with its octets. */
|
||||
if (s->report_bad_frames)
|
||||
{
|
||||
/* Don't let the length go below zero, or it will be confused
|
||||
with one of the special conditions. */
|
||||
if (s->len >= s->crc_bytes)
|
||||
s->len -= s->crc_bytes;
|
||||
else
|
||||
s->len = 0;
|
||||
s->frame_handler(s->user_data, s->buffer, s->len, FALSE);
|
||||
}
|
||||
s->rx_length_errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check the flags are back-to-back when testing for valid preamble. This
|
||||
greatly reduces the chances of false preamble detection, and anything
|
||||
which doesn't send them back-to-back is badly broken. */
|
||||
if (s->num_bits != 7)
|
||||
s->flags_seen = 0;
|
||||
if (++s->flags_seen >= s->framing_ok_threshold && !s->framing_ok_announced)
|
||||
{
|
||||
s->frame_handler(s->user_data, NULL, PUTBIT_FRAMING_OK, TRUE);
|
||||
s->framing_ok_announced = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
s->len = 0;
|
||||
s->num_bits = 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static __inline__ void hdlc_rx_put_bit_core(hdlc_rx_state_t *s)
|
||||
{
|
||||
if ((s->raw_bit_stream & 0x3F00) == 0x3E00)
|
||||
{
|
||||
/* Its time to either skip a bit, for stuffing, or process a
|
||||
flag or abort */
|
||||
if ((s->raw_bit_stream & 0x4000))
|
||||
rx_flag_or_abort(s);
|
||||
return;
|
||||
}
|
||||
s->num_bits++;
|
||||
if (s->flags_seen < s->framing_ok_threshold)
|
||||
{
|
||||
if ((s->num_bits & 0x7) == 0)
|
||||
octet_count(s);
|
||||
return;
|
||||
}
|
||||
s->byte_in_progress = (s->byte_in_progress | (s->raw_bit_stream & 0x100)) >> 1;
|
||||
if (s->num_bits == 8)
|
||||
{
|
||||
/* Ensure we do not accept an overlength frame, and especially that
|
||||
we do not overflow our buffer */
|
||||
if (s->len < s->max_frame_len)
|
||||
{
|
||||
s->buffer[s->len++] = (uint8_t) s->byte_in_progress;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is too long. Abandon the frame, and wait for the next
|
||||
flag octet. */
|
||||
s->len = sizeof(s->buffer) + 1;
|
||||
s->flags_seen = s->framing_ok_threshold - 1;
|
||||
octet_set_and_count(s);
|
||||
}
|
||||
s->num_bits = 0;
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void hdlc_rx_put_bit(hdlc_rx_state_t *s, int new_bit)
|
||||
{
|
||||
if (new_bit < 0)
|
||||
{
|
||||
rx_special_condition(s, new_bit);
|
||||
return;
|
||||
}
|
||||
s->raw_bit_stream = (s->raw_bit_stream << 1) | ((new_bit << 8) & 0x100);
|
||||
hdlc_rx_put_bit_core(s);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void hdlc_rx_put_byte(hdlc_rx_state_t *s, int new_byte)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (new_byte < 0)
|
||||
{
|
||||
rx_special_condition(s, new_byte);
|
||||
return;
|
||||
}
|
||||
s->raw_bit_stream |= new_byte;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
s->raw_bit_stream <<= 1;
|
||||
hdlc_rx_put_bit_core(s);
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void hdlc_rx_put(hdlc_rx_state_t *s, const uint8_t buf[], int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
hdlc_rx_put_byte(s, buf[i]);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void hdlc_rx_set_max_frame_len(hdlc_rx_state_t *s, size_t max_len)
|
||||
{
|
||||
max_len += s->crc_bytes;
|
||||
s->max_frame_len = (max_len <= sizeof(s->buffer)) ? max_len : sizeof(s->buffer);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void hdlc_rx_set_octet_counting_report_interval(hdlc_rx_state_t *s, int interval)
|
||||
{
|
||||
s->octet_count_report_interval = interval;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
hdlc_rx_state_t *hdlc_rx_init(hdlc_rx_state_t *s,
|
||||
int crc32,
|
||||
int report_bad_frames,
|
||||
int framing_ok_threshold,
|
||||
hdlc_frame_handler_t handler,
|
||||
void *user_data)
|
||||
{
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (hdlc_rx_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->frame_handler = handler;
|
||||
s->user_data = user_data;
|
||||
s->crc_bytes = (crc32) ? 4 : 2;
|
||||
s->report_bad_frames = report_bad_frames;
|
||||
s->framing_ok_threshold = (framing_ok_threshold < 1) ? 1 : framing_ok_threshold;
|
||||
s->max_frame_len = sizeof(s->buffer);
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int hdlc_rx_get_stats(hdlc_rx_state_t *s,
|
||||
hdlc_rx_stats_t *t)
|
||||
{
|
||||
t->bytes = s->rx_bytes;
|
||||
t->good_frames = s->rx_frames;
|
||||
t->crc_errors = s->rx_crc_errors;
|
||||
t->length_errors = s->rx_length_errors;
|
||||
t->aborts = s->rx_aborts;
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int hdlc_tx_frame(hdlc_tx_state_t *s, const uint8_t *frame, size_t len)
|
||||
{
|
||||
if (len <= 0)
|
||||
{
|
||||
s->tx_end = TRUE;
|
||||
return 0;
|
||||
}
|
||||
if (s->len + len > s->max_frame_len)
|
||||
return -1;
|
||||
if (s->progressive)
|
||||
{
|
||||
/* Only lock out if we are in the CRC section. */
|
||||
if (s->pos >= HDLC_MAXFRAME_LEN)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Lock out if there is anything in the buffer. */
|
||||
if (s->len)
|
||||
return -1;
|
||||
}
|
||||
memcpy(s->buffer + s->len, frame, len);
|
||||
if (s->crc_bytes == 2)
|
||||
s->crc = crc_itu16_calc(frame, len, (uint16_t) s->crc);
|
||||
else
|
||||
s->crc = crc_itu32_calc(frame, len, s->crc);
|
||||
if (s->progressive)
|
||||
s->len += len;
|
||||
else
|
||||
s->len = len;
|
||||
s->tx_end = FALSE;
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int hdlc_tx_flags(hdlc_tx_state_t *s, int len)
|
||||
{
|
||||
/* Some HDLC applications require the ability to force a period of HDLC
|
||||
flag words. */
|
||||
if (s->pos)
|
||||
return -1;
|
||||
if (len < 0)
|
||||
s->flag_octets += -len;
|
||||
else
|
||||
s->flag_octets = len;
|
||||
s->report_flag_underflow = TRUE;
|
||||
s->tx_end = FALSE;
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int hdlc_tx_abort(hdlc_tx_state_t *s)
|
||||
{
|
||||
/* TODO: This is a really crude way of just fudging an abort out for simple
|
||||
test purposes. */
|
||||
s->flag_octets++;
|
||||
s->abort_octets++;
|
||||
return -1;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int hdlc_tx_corrupt_frame(hdlc_tx_state_t *s)
|
||||
{
|
||||
if (s->len <= 0)
|
||||
return -1;
|
||||
s->crc ^= 0xFFFF;
|
||||
s->buffer[HDLC_MAXFRAME_LEN] ^= 0xFF;
|
||||
s->buffer[HDLC_MAXFRAME_LEN + 1] ^= 0xFF;
|
||||
s->buffer[HDLC_MAXFRAME_LEN + 2] ^= 0xFF;
|
||||
s->buffer[HDLC_MAXFRAME_LEN + 3] ^= 0xFF;
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int hdlc_tx_get_byte(hdlc_tx_state_t *s)
|
||||
{
|
||||
int i;
|
||||
int byte_in_progress;
|
||||
int txbyte;
|
||||
|
||||
if (s->flag_octets > 0)
|
||||
{
|
||||
/* We are in a timed flag section (preamble, inter frame gap, etc.) */
|
||||
if (--s->flag_octets <= 0 && s->report_flag_underflow)
|
||||
{
|
||||
s->report_flag_underflow = FALSE;
|
||||
if (s->len == 0)
|
||||
{
|
||||
/* The timed flags have finished, there is nothing else queued to go,
|
||||
and we have been told to report this underflow. */
|
||||
if (s->underflow_handler)
|
||||
s->underflow_handler(s->user_data);
|
||||
}
|
||||
}
|
||||
if (s->abort_octets)
|
||||
{
|
||||
s->abort_octets = 0;
|
||||
return 0x7F;
|
||||
}
|
||||
return s->idle_octet;
|
||||
}
|
||||
if (s->len)
|
||||
{
|
||||
if (s->num_bits >= 8)
|
||||
{
|
||||
s->num_bits -= 8;
|
||||
return (s->octets_in_progress >> s->num_bits) & 0xFF;
|
||||
}
|
||||
if (s->pos >= s->len)
|
||||
{
|
||||
if (s->pos == s->len)
|
||||
{
|
||||
s->crc ^= 0xFFFFFFFF;
|
||||
s->buffer[HDLC_MAXFRAME_LEN] = (uint8_t) s->crc;
|
||||
s->buffer[HDLC_MAXFRAME_LEN + 1] = (uint8_t) (s->crc >> 8);
|
||||
if (s->crc_bytes == 4)
|
||||
{
|
||||
s->buffer[HDLC_MAXFRAME_LEN + 2] = (uint8_t) (s->crc >> 16);
|
||||
s->buffer[HDLC_MAXFRAME_LEN + 3] = (uint8_t) (s->crc >> 24);
|
||||
}
|
||||
s->pos = HDLC_MAXFRAME_LEN;
|
||||
}
|
||||
else if (s->pos == HDLC_MAXFRAME_LEN + s->crc_bytes)
|
||||
{
|
||||
/* Finish off the current byte with some flag bits. If we are at the
|
||||
start of a byte we need a at least one whole byte of flag to ensure
|
||||
we cannot end up with back to back frames, and no flag octet at all */
|
||||
txbyte = (uint8_t) ((s->octets_in_progress << (8 - s->num_bits)) | (0x7E >> s->num_bits));
|
||||
/* Create a rotated octet of flag for idling... */
|
||||
s->idle_octet = (0x7E7E >> s->num_bits) & 0xFF;
|
||||
/* ...and the partial flag octet needed to start off the next message. */
|
||||
s->octets_in_progress = s->idle_octet >> (8 - s->num_bits);
|
||||
s->flag_octets = s->inter_frame_flags - 1;
|
||||
s->len = 0;
|
||||
s->pos = 0;
|
||||
if (s->crc_bytes == 2)
|
||||
s->crc = 0xFFFF;
|
||||
else
|
||||
s->crc = 0xFFFFFFFF;
|
||||
/* Report the underflow now. If there are timed flags still in progress, loading the
|
||||
next frame right now will be harmless. */
|
||||
s->report_flag_underflow = FALSE;
|
||||
if (s->underflow_handler)
|
||||
s->underflow_handler(s->user_data);
|
||||
/* Make sure we finish off with at least one flag octet, if the underflow report did not result
|
||||
in a new frame being sent. */
|
||||
if (s->len == 0 && s->flag_octets < 2)
|
||||
s->flag_octets = 2;
|
||||
return txbyte;
|
||||
}
|
||||
}
|
||||
byte_in_progress = s->buffer[s->pos++];
|
||||
i = bottom_bit(byte_in_progress | 0x100);
|
||||
s->octets_in_progress <<= i;
|
||||
byte_in_progress >>= i;
|
||||
for ( ; i < 8; i++)
|
||||
{
|
||||
s->octets_in_progress = (s->octets_in_progress << 1) | (byte_in_progress & 0x01);
|
||||
byte_in_progress >>= 1;
|
||||
if ((s->octets_in_progress & 0x1F) == 0x1F)
|
||||
{
|
||||
/* There are 5 ones - stuff */
|
||||
s->octets_in_progress <<= 1;
|
||||
s->num_bits++;
|
||||
}
|
||||
}
|
||||
/* An input byte will generate between 8 and 10 output bits */
|
||||
return (s->octets_in_progress >> s->num_bits) & 0xFF;
|
||||
}
|
||||
/* Untimed idling on flags */
|
||||
if (s->tx_end)
|
||||
{
|
||||
s->tx_end = FALSE;
|
||||
return PUTBIT_END_OF_DATA;
|
||||
}
|
||||
return s->idle_octet;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int hdlc_tx_get_bit(hdlc_tx_state_t *s)
|
||||
{
|
||||
int txbit;
|
||||
|
||||
if (s->bits == 0)
|
||||
{
|
||||
if ((s->byte = hdlc_tx_get_byte(s)) < 0)
|
||||
return s->byte;
|
||||
s->bits = 8;
|
||||
}
|
||||
s->bits--;
|
||||
txbit = (s->byte >> s->bits) & 0x01;
|
||||
return txbit;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int hdlc_tx_get(hdlc_tx_state_t *s, uint8_t buf[], size_t max_len)
|
||||
{
|
||||
int i;
|
||||
int x;
|
||||
|
||||
for (i = 0; i < max_len; i++)
|
||||
{
|
||||
if ((x = hdlc_tx_get_byte(s)) == PUTBIT_END_OF_DATA)
|
||||
return i;
|
||||
buf[i] = x;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void hdlc_tx_set_max_frame_len(hdlc_tx_state_t *s, size_t max_len)
|
||||
{
|
||||
s->max_frame_len = (max_len <= HDLC_MAXFRAME_LEN) ? max_len : HDLC_MAXFRAME_LEN;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
hdlc_tx_state_t *hdlc_tx_init(hdlc_tx_state_t *s,
|
||||
int crc32,
|
||||
int inter_frame_flags,
|
||||
int progressive,
|
||||
hdlc_underflow_handler_t handler,
|
||||
void *user_data)
|
||||
{
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (hdlc_tx_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->idle_octet = 0x7E;
|
||||
s->underflow_handler = handler;
|
||||
s->user_data = user_data;
|
||||
s->inter_frame_flags = (inter_frame_flags < 1) ? 1 : inter_frame_flags;
|
||||
if (crc32)
|
||||
{
|
||||
s->crc_bytes = 4;
|
||||
s->crc = 0xFFFFFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
s->crc_bytes = 2;
|
||||
s->crc = 0xFFFF;
|
||||
}
|
||||
s->progressive = progressive;
|
||||
s->max_frame_len = HDLC_MAXFRAME_LEN;
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,497 @@
|
||||
/*
|
||||
* SpanDSP - 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 <steveu@coppice.org>
|
||||
*
|
||||
* 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 GNU Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.28 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/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 compress, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
DVI4 uses an adaptive delta pulse code modulation (ADPCM) encoding
|
||||
scheme that was specified by the Interactive Multimedia Association
|
||||
(IMA) as the "IMA ADPCM wave type". However, the encoding defined
|
||||
here as DVI4 differs in three respects from the IMA specification:
|
||||
|
||||
o The RTP DVI4 header contains the predicted value rather than the
|
||||
first sample value contained the IMA ADPCM block header.
|
||||
|
||||
o IMA ADPCM blocks contain an odd number of samples, since the first
|
||||
sample of a block is contained just in the header (uncompressed),
|
||||
followed by an even number of compressed samples. DVI4 has an
|
||||
even number of compressed samples only, using the `predict' word
|
||||
from the header to decode the first sample.
|
||||
|
||||
o For DVI4, the 4-bit samples are packed with the first sample in
|
||||
the four most significant bits and the second sample in the four
|
||||
least significant bits. In the IMA ADPCM codec, the samples are
|
||||
packed in the opposite order.
|
||||
|
||||
Each packet contains a single DVI block. This profile only defines
|
||||
the 4-bit-per-sample version, while IMA also specified a 3-bit-per-
|
||||
sample encoding.
|
||||
|
||||
The "header" word for each channel has the following structure:
|
||||
|
||||
int16 predict; // predicted value of first sample
|
||||
// from the previous block (L16 format)
|
||||
u_int8 index; // current index into stepsize table
|
||||
u_int8 reserved; // set to zero by sender, ignored by receiver
|
||||
|
||||
Each octet following the header contains two 4-bit samples, thus the
|
||||
number of samples per packet MUST be even because there is no means
|
||||
to indicate a partially filled last octet.
|
||||
*/
|
||||
|
||||
#define STEP_MAX 88
|
||||
|
||||
/* Intel ADPCM step variation table */
|
||||
static const int step_size[STEP_MAX + 1] =
|
||||
{
|
||||
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 > STEP_MAX)
|
||||
s->step_index = STEP_MAX;
|
||||
/*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 > STEP_MAX)
|
||||
s->step_index = STEP_MAX;
|
||||
/*endif*/
|
||||
return (uint8_t) adpcm;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
ima_adpcm_state_t *ima_adpcm_init(ima_adpcm_state_t *s, int variant, int chunk_size)
|
||||
{
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (ima_adpcm_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
/*endif*/
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->variant = variant;
|
||||
s->chunk_size = chunk_size;
|
||||
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;
|
||||
switch (s->variant)
|
||||
{
|
||||
case IMA_ADPCM_IMA4:
|
||||
i = 0;
|
||||
if (s->chunk_size == 0)
|
||||
{
|
||||
amp[samples++] = (ima_data[1] << 8) | ima_data[0];
|
||||
s->step_index = ima_data[2];
|
||||
s->last = amp[0];
|
||||
i = 4;
|
||||
}
|
||||
/*endif*/
|
||||
for ( ; i < ima_bytes; i++)
|
||||
{
|
||||
amp[samples++] = decode(s, ima_data[i] & 0xF);
|
||||
amp[samples++] = decode(s, (ima_data[i] >> 4) & 0xF);
|
||||
}
|
||||
/*endfor*/
|
||||
break;
|
||||
case IMA_ADPCM_DVI4:
|
||||
i = 0;
|
||||
if (s->chunk_size == 0)
|
||||
{
|
||||
s->last = (int16_t) ((ima_data[0] << 8) | ima_data[1]);
|
||||
s->step_index = ima_data[2];
|
||||
i = 4;
|
||||
}
|
||||
/*endif*/
|
||||
for ( ; i < ima_bytes; i++)
|
||||
{
|
||||
amp[samples++] = decode(s, (ima_data[i] >> 4) & 0xF);
|
||||
amp[samples++] = decode(s, ima_data[i] & 0xF);
|
||||
}
|
||||
/*endfor*/
|
||||
break;
|
||||
case IMA_ADPCM_VDVI:
|
||||
i = 0;
|
||||
if (s->chunk_size == 0)
|
||||
{
|
||||
s->last = (int16_t) ((ima_data[0] << 8) | ima_data[1]);
|
||||
s->step_index = ima_data[2];
|
||||
i = 4;
|
||||
}
|
||||
/*endif*/
|
||||
code = 0;
|
||||
s->bits = 0;
|
||||
for (;;)
|
||||
{
|
||||
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;
|
||||
}
|
||||
/*endwhile*/
|
||||
break;
|
||||
}
|
||||
/*endswitch*/
|
||||
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;
|
||||
switch (s->variant)
|
||||
{
|
||||
case IMA_ADPCM_IMA4:
|
||||
i = 0;
|
||||
if (s->chunk_size == 0)
|
||||
{
|
||||
ima_data[bytes++] = (uint8_t) amp[0];
|
||||
ima_data[bytes++] = (uint8_t) (amp[0] >> 8);
|
||||
ima_data[bytes++] = (uint8_t) s->step_index;
|
||||
ima_data[bytes++] = 0;
|
||||
s->last = amp[0];
|
||||
s->bits = 0;
|
||||
i = 1;
|
||||
}
|
||||
/*endif*/
|
||||
for ( ; 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*/
|
||||
break;
|
||||
case IMA_ADPCM_DVI4:
|
||||
if (s->chunk_size == 0)
|
||||
{
|
||||
ima_data[bytes++] = (uint8_t) (s->last >> 8);
|
||||
ima_data[bytes++] = (uint8_t) s->last;
|
||||
ima_data[bytes++] = (uint8_t) s->step_index;
|
||||
ima_data[bytes++] = 0;
|
||||
}
|
||||
/*endif*/
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
s->ima_byte = (uint8_t) ((s->ima_byte << 4) | encode(s, amp[i]));
|
||||
if ((s->bits++ & 1))
|
||||
ima_data[bytes++] = (uint8_t) s->ima_byte;
|
||||
/*endif*/
|
||||
}
|
||||
/*endfor*/
|
||||
break;
|
||||
case IMA_ADPCM_VDVI:
|
||||
if (s->chunk_size == 0)
|
||||
{
|
||||
ima_data[bytes++] = (uint8_t) (s->last >> 8);
|
||||
ima_data[bytes++] = (uint8_t) s->last;
|
||||
ima_data[bytes++] = (uint8_t) s->step_index;
|
||||
ima_data[bytes++] = 0;
|
||||
}
|
||||
/*endif*/
|
||||
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*/
|
||||
break;
|
||||
}
|
||||
/*endswitch*/
|
||||
return bytes;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,707 @@
|
||||
# Microsoft Developer Studio Project File - Name="spandsp" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||
|
||||
CFG=spandsp - 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 "spandsp.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 "spandsp.mak" CFG="spandsp - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "spandsp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "spandsp - 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)" == "spandsp - 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/libspandsp.dll"
|
||||
|
||||
!ELSEIF "$(CFG)" == "spandsp - 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/libspandsp.dll" /pdbtype:sept
|
||||
# SUBTRACT LINK32 /nodefaultlib
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "spandsp - Win32 Release"
|
||||
# Name "spandsp - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\adsi.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\async.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\at_interpreter.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\awgn.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\bell_r2_mf.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\bert.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\bit_operations.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\bitstream.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\complex_filters.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\complex_vector_float.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\crc.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\dds_float.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\dds_int.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\dtmf.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\echo.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\fax.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\fsk.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=.\hdlc.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ima_adpcm.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\logging.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=.\modem_echo.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\modem_connect_tones.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\noise.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\oki_adpcm.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\playout.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\plc.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\power_meter.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\queue.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\schedule.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\sig_tone.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\silence_gen.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\super_tone_rx.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\super_tone_tx.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\t4.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\t30.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\t30_api.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\t30_logging.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\t31.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\t35.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\t38_core.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\t38_gateway.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\t38_non_ecm_buffer.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\t38_terminal.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\testcpuid.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\time_scale.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\tone_detect.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\tone_generate.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\v17rx.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\v17tx.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\v22bis_rx.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\v22bis_tx.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\v27ter_rx.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\v27ter_tx.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\v29rx.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\v29tx.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\v42.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\v42bis.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\v8.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\vector_float.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\vector_int.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\msvc/gettimeofday.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/adsi.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/async.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/arctan2.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/at_interpreter.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/awgn.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/bell_r2_mf.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/bert.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/biquad.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/bit_operations.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/bitstream.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/crc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/complex.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/complex_filters.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/complex_vector_float.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/dc_restore.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/dds.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/dtmf.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/echo.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/fax.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/fax_modems.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/fir.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/fsk.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/g168models.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/g711.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/g722.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/g726.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/gsm0610.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/hdlc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/ima_adpcm.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/logging.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/lpc10.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/modem_echo.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/modem_connect_tones.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/noise.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/oki_adpcm.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/playout.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/plc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/power_meter.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/queue.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/schedule.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/sig_tone.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/silence_gen.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/super_tone_rx.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/super_tone_tx.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/t4.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/t30.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/t30_api.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/t30_fcf.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/t30_logging.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/t31.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/t35.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/t38_core.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/t38_gateway.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/t38_non_ecm_buffer.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/t38_terminal.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/telephony.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/time_scale.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/timing.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/tone_detect.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/tone_generate.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/v17rx.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/v17tx.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/v22bis.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/v27ter_rx.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/v27ter_tx.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/v29rx.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/v29tx.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/v42.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/v42bis.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/v8.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/vector_float.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/vector_int.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp/version.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\spandsp.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
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual Studio 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspandsp", "libspandsp.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
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* logging.c - error and debug logging.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: logging.c,v 1.26 2008/05/13 13:17:22 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/logging.h"
|
||||
|
||||
static void default_message_handler(int level, const char *text);
|
||||
|
||||
static message_handler_func_t __span_message = *default_message_handler;
|
||||
static error_handler_func_t __span_error = NULL;
|
||||
|
||||
/* Note that this list *must* match the enum definition in logging.h */
|
||||
static const char *severities[] =
|
||||
{
|
||||
"NONE",
|
||||
"ERROR",
|
||||
"WARNING",
|
||||
"PROTOCOL_ERROR",
|
||||
"PROTOCOL_WARNING",
|
||||
"FLOW",
|
||||
"FLOW 2",
|
||||
"FLOW 3",
|
||||
"DEBUG 1",
|
||||
"DEBUG 2",
|
||||
"DEBUG 3"
|
||||
};
|
||||
|
||||
static void default_message_handler(int level, const char *text)
|
||||
{
|
||||
fprintf(stderr, "%s", text);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int span_log_test(logging_state_t *s, int level)
|
||||
{
|
||||
if (s && (s->level & SPAN_LOG_SEVERITY_MASK) >= (level & SPAN_LOG_SEVERITY_MASK))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int span_log(logging_state_t *s, int level, const char *format, ...)
|
||||
{
|
||||
char msg[1024 + 1];
|
||||
va_list arg_ptr;
|
||||
int len;
|
||||
struct tm *tim;
|
||||
struct timeval nowx;
|
||||
time_t now;
|
||||
|
||||
if (span_log_test(s, level))
|
||||
{
|
||||
va_start(arg_ptr, format);
|
||||
len = 0;
|
||||
if ((level & SPAN_LOG_SUPPRESS_LABELLING) == 0)
|
||||
{
|
||||
if ((s->level & SPAN_LOG_SHOW_DATE))
|
||||
{
|
||||
gettimeofday(&nowx, NULL);
|
||||
now = nowx.tv_sec;
|
||||
tim = gmtime(&now);
|
||||
len += snprintf(msg + len,
|
||||
1024 - len,
|
||||
"%04d/%02d/%02d %02d:%02d:%02d.%03d ",
|
||||
tim->tm_year + 1900,
|
||||
tim->tm_mon + 1,
|
||||
tim->tm_mday,
|
||||
tim->tm_hour,
|
||||
tim->tm_min,
|
||||
tim->tm_sec,
|
||||
(int) nowx.tv_usec/1000);
|
||||
}
|
||||
/*endif*/
|
||||
if ((s->level & SPAN_LOG_SHOW_SAMPLE_TIME))
|
||||
{
|
||||
now = s->elapsed_samples/s->samples_per_second;
|
||||
tim = gmtime(&now);
|
||||
len += snprintf(msg + len,
|
||||
1024 - len,
|
||||
"%02d:%02d:%02d.%03d ",
|
||||
tim->tm_hour,
|
||||
tim->tm_min,
|
||||
tim->tm_sec,
|
||||
(int) (s->elapsed_samples%s->samples_per_second)*1000/s->samples_per_second);
|
||||
}
|
||||
/*endif*/
|
||||
if ((s->level & SPAN_LOG_SHOW_SEVERITY) && (level & SPAN_LOG_SEVERITY_MASK) <= SPAN_LOG_DEBUG_3)
|
||||
len += snprintf(msg + len, 1024 - len, "%s ", severities[level & SPAN_LOG_SEVERITY_MASK]);
|
||||
/*endif*/
|
||||
if ((s->level & SPAN_LOG_SHOW_PROTOCOL) && s->protocol)
|
||||
len += snprintf(msg + len, 1024 - len, "%s ", s->protocol);
|
||||
/*endif*/
|
||||
if ((s->level & SPAN_LOG_SHOW_TAG) && s->tag)
|
||||
len += snprintf(msg + len, 1024 - len, "%s ", s->tag);
|
||||
/*endif*/
|
||||
}
|
||||
/*endif*/
|
||||
len += vsnprintf(msg + len, 1024 - len, format, arg_ptr);
|
||||
if (s->span_error && level == SPAN_LOG_ERROR)
|
||||
s->span_error(msg);
|
||||
else if (__span_error && level == SPAN_LOG_ERROR)
|
||||
__span_error(msg);
|
||||
else if (s->span_message)
|
||||
s->span_message(level, msg);
|
||||
else if (__span_message)
|
||||
__span_message(level, msg);
|
||||
/*endif*/
|
||||
va_end(arg_ptr);
|
||||
return 1;
|
||||
}
|
||||
/*endif*/
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int span_log_buf(logging_state_t *s, int level, const char *tag, const uint8_t *buf, int len)
|
||||
{
|
||||
char msg[1024];
|
||||
int i;
|
||||
int msg_len;
|
||||
|
||||
if (span_log_test(s, level))
|
||||
{
|
||||
msg_len = 0;
|
||||
if (tag)
|
||||
msg_len += snprintf(msg + msg_len, 1024 - msg_len, "%s", tag);
|
||||
for (i = 0; i < len && msg_len < 800; i++)
|
||||
msg_len += snprintf(msg + msg_len, 1024 - msg_len, " %02x", buf[i]);
|
||||
msg_len += snprintf(msg + msg_len, 1024 - msg_len, "\n");
|
||||
return span_log(s, level, msg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int span_log_init(logging_state_t *s, int level, const char *tag)
|
||||
{
|
||||
s->span_error = __span_error;
|
||||
s->span_message = __span_message;
|
||||
s->level = level;
|
||||
s->tag = tag;
|
||||
s->protocol = NULL;
|
||||
s->samples_per_second = SAMPLE_RATE;
|
||||
s->elapsed_samples = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int span_log_set_level(logging_state_t *s, int level)
|
||||
{
|
||||
s->level = level;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int span_log_set_tag(logging_state_t *s, const char *tag)
|
||||
{
|
||||
s->tag = tag;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int span_log_set_protocol(logging_state_t *s, const char *protocol)
|
||||
{
|
||||
s->protocol = protocol;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int span_log_set_sample_rate(logging_state_t *s, int samples_per_second)
|
||||
{
|
||||
s->samples_per_second = samples_per_second;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int span_log_bump_samples(logging_state_t *s, int samples)
|
||||
{
|
||||
s->elapsed_samples += samples;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void span_log_set_message_handler(logging_state_t *s, message_handler_func_t func)
|
||||
{
|
||||
s->span_message = func;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void span_log_set_error_handler(logging_state_t *s, error_handler_func_t func)
|
||||
{
|
||||
s->span_error = func;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void span_set_message_handler(message_handler_func_t func)
|
||||
{
|
||||
__span_message = func;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void span_set_error_handler(error_handler_func_t func)
|
||||
{
|
||||
__span_error = func;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,713 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* lpc10_analyse.c - LPC10 low bit rate speech codec.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.19 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <memory.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/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 ------------------------------------------------------------*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.11 2008/04/17 14:26:56 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 ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* lpc10_encode.c - LPC10 low bit rate speech codec.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.23 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <memory.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/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 len)
|
||||
{
|
||||
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;
|
||||
|
||||
len /= LPC10_SAMPLES_PER_FRAME;
|
||||
for (i = 0; i < len; 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 len*7;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* lpc10_placev.c - LPC10 low bit rate speech codec.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.17 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <memory.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/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 ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* lpc10_voicing.c - LPC10 low bit rate speech codec.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.14 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <memory.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/dc_restore.h"
|
||||
#include "spandsp/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;
|
||||
|
||||
#if (_MSC_VER >= 1400)
|
||||
__analysis_assume(half >= 0 && half < 2);
|
||||
#endif
|
||||
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 ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,632 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* make_at_dictionary.c - Generate a trie based dictionary for the AT
|
||||
* commands supported by the AT interpreter.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: make_at_dictionary.c,v 1.1 2008/07/01 03:27:51 steveu Exp $
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
const char *wordlist[] =
|
||||
{
|
||||
" ", /* Dummy to absorb spaces in commands */
|
||||
"&C", /* V.250 6.2.8 - Circuit 109 (received line signal detector), behaviour */
|
||||
"&D", /* V.250 6.2.9 - Circuit 108 (data terminal ready) behaviour */
|
||||
"&F", /* V.250 6.1.2 - Set to factory-defined configuration */
|
||||
"+A8A", /* V.251 6.3 - V.8 calling tone indication */
|
||||
"+A8C", /* V.251 6.2 - V.8 answer signal indication */
|
||||
"+A8E", /* V.251 5.1 - V.8 and V.8bis operation controls */
|
||||
"+A8I", /* V.251 6.1 - V.8 CI signal indication */
|
||||
"+A8J", /* V.251 6.4 - V.8 negotiation complete */
|
||||
"+A8M", /* V.251 5.2 - Send V.8 menu signals */
|
||||
"+A8R", /* V.251 6.6 - V.8bis signal and message reporting */
|
||||
"+A8T", /* V.251 5.3 - Send V.8bis signal and/or message(s) */
|
||||
"+ASTO", /* V.250 6.3.15 - Store telephone number */
|
||||
"+CAAP", /* 3GPP TS 27.007 7.25 - Automatic answer for eMLPP Service */
|
||||
"+CACM", /* 3GPP TS 27.007 8.25 - Accumulated call meter */
|
||||
"+CACSP", /* 3GPP TS 27.007 11.1.7 - Voice Group or Voice Broadcast Call State Attribute Presentation */
|
||||
"+CAD", /* IS-99 5.6.3 - Query analogue or digital service */
|
||||
"+CAEMLPP", /* 3GPP TS 27.007 7.22 - eMLPP Priority Registration and Interrogation */
|
||||
"+CAHLD", /* 3GPP TS 27.007 11.1.3 - Leave an ongoing Voice Group or Voice Broadcast Call */
|
||||
"+CAJOIN", /* 3GPP TS 27.007 11.1.1 - Accept an incoming Voice Group or Voice Broadcast Call */
|
||||
"+CALA", /* 3GPP TS 27.007 8.16 - Alarm */
|
||||
"+CALCC", /* 3GPP TS 27.007 11.1.6 - List current Voice Group and Voice Broadcast Calls */
|
||||
"+CALD", /* 3GPP TS 27.007 8.38 - Delete alar m */
|
||||
"+CALM", /* 3GPP TS 27.007 8.20 - Alert sound mode */
|
||||
"+CAMM", /* 3GPP TS 27.007 8.26 - Accumulated call meter maximum */
|
||||
"+CANCHEV", /* 3GPP TS 27.007 11.1.8 - NCH Support Indication */
|
||||
"+CAOC", /* 3GPP TS 27.007 7.16 - Advice of Charge */
|
||||
"+CAPD", /* 3GPP TS 27.007 8.39 - Postpone or dismiss an alarm */
|
||||
"+CAPTT", /* 3GPP TS 27.007 11.1.4 - Talker Access for Voice Group Call */
|
||||
"+CAREJ", /* 3GPP TS 27.007 11.1.2 - Reject an incoming Voice Group or Voice Broadcast Call */
|
||||
"+CAULEV", /* 3GPP TS 27.007 11.1.5 - Voice Group Call Uplink Status Presentation */
|
||||
"+CBC", /* 3GPP TS 27.007 8.4 - Battery charge */
|
||||
"+CBCS", /* 3GPP TS 27.007 11.3.2 - VBS subscriptions and GId status */
|
||||
"+CBIP", /* IS-99 5.6 - Base station IP address */
|
||||
"+CBST", /* 3GPP TS 27.007 6.7 - Select bearer service type */
|
||||
"+CCFC", /* 3GPP TS 27.007 7.11 - Call forwarding number and conditions */
|
||||
"+CCLK", /* 3GPP TS 27.007 8.15 - Clock */
|
||||
"+CCS", /* IS-135 4.1.22 - Compression status */
|
||||
"+CCUG", /* 3GPP TS 27.007 7.10 - Closed user group */
|
||||
"+CCWA", /* 3GPP TS 27.007 7.12 - Call waiting */
|
||||
"+CCWE", /* 3GPP TS 27.007 8.28 - Call Meter maximum event */
|
||||
"+CDIP", /* 3GPP TS 27.007 7.9 - Called line identification presentation */
|
||||
"+CDIS", /* 3GPP TS 27.007 8.8 - Display control */
|
||||
"+CDV", /* IS-99 5.6 - Dial command for voice call */
|
||||
"+CEER", /* 3GPP TS 27.007 6.10 - Extended error report */
|
||||
"+CESP", /* GSM07.05 3.2.4 - Enter SMS block mode protocol */
|
||||
"+CFCS", /* 3GPP TS 27.007 7.24 - Fast call setup conditions */
|
||||
"+CFG", /* IS-99 5.6 - Configuration string */
|
||||
"+CFUN", /* 3GPP TS 27.007 8.2 - Set phone functionality */
|
||||
"+CGACT", /* 3GPP TS 27.007 10.1.10 - PDP context activate or deactivate */
|
||||
"+CGANS", /* 3GPP TS 27.007 10.1.16 - Manual response to a network request for PDP context activation */
|
||||
"+CGATT", /* 3GPP TS 27.007 10.1.9 - PS attach or detach */
|
||||
"+CGAUTO", /* 3GPP TS 27.007 10.1.15 - Automatic response to a network request for PDP context activation */
|
||||
"+CGCAP", /* IS-99 5.6 - Request complete capabilities list */
|
||||
"+CGCLASS", /* 3GPP TS 27.007 10.1.17 - GPRS mobile station class (GPRS only) */
|
||||
"+CGCLOSP", /* 3GPP TS 27.007 10.1.13 - Configure local octet stream PAD parameters (Obsolete) */
|
||||
"+CGCLPAD", /* 3GPP TS 27.007 10.1.12 - Configure local triple-X PAD parameters (GPRS only) (Obsolete) */
|
||||
"+CGCMOD", /* 3GPP TS 27.007 10.1.11 - PDP Context Modify */
|
||||
"+CGCS", /* 3GPP TS 27.007 11.3.1 - VGCS subscriptions and GId status */
|
||||
"+CGDATA", /* 3GPP TS 27.007 10.1.12 - Enter data state */
|
||||
"+CGDCONT", /* 3GPP TS 27.007 10.1.1 - Define PDP Context */
|
||||
"+CGDSCONT",/* 3GPP TS 27.007 10.1.2 - Define Secondary PDP Context */
|
||||
"+CGEQMIN", /* 3GPP TS 27.007 10.1.7 - 3G Quality of Service Profile (Minimum acceptable) */
|
||||
"+CGEQNEG", /* 3GPP TS 27.007 10.1.8 - 3G Quality of Service Profile (Negotiated) */
|
||||
"+CGEQREQ", /* 3GPP TS 27.007 10.1.6 - 3G Quality of Service Profile (Requested) */
|
||||
"+CGEREP", /* 3GPP TS 27.007 10.1.18 - Packet Domain event reporting */
|
||||
"+CGMI", /* 3GPP TS 27.007 5.1 - Request manufacturer identification */
|
||||
"+CGMM", /* 3GPP TS 27.007 5.2 - Request model identification */
|
||||
"+CGMR", /* 3GPP TS 27.007 5.3 - Request revision identification */
|
||||
"+CGOI", /* IS-99 5.6 - Request global object identification */
|
||||
"+CGPADDR", /* 3GPP TS 27.007 10.1.14 - Show PDP address */
|
||||
"+CGQMIN", /* 3GPP TS 27.007 10.1.5 - Quality of Service Profile (Minimum acceptable) */
|
||||
"+CGQREQ", /* 3GPP TS 27.007 10.1.4 - Quality of Service Profile (Requested) */
|
||||
"+CGREG", /* 3GPP TS 27.007 10.1.19 - GPRS network registration status */
|
||||
"+CGSMS", /* 3GPP TS 27.007 10.1.20 - Select service for MO SMS messages */
|
||||
"+CGSN", /* 3GPP TS 27.007 5.4 - Request product serial number identification */
|
||||
"+CGTFT", /* 3GPP TS 27.007 10.1.3 - Traffic Flow Template */
|
||||
"+CHLD", /* 3GPP TS 27.007 7.13 - Call related supplementary services */
|
||||
"+CHSA", /* 3GPP TS 27.007 6.18 - HSCSD non-transparent asymmetry configuration */
|
||||
"+CHSC", /* 3GPP TS 27.007 6.15 - HSCSD current call parameters */
|
||||
"+CHSD", /* 3GPP TS 27.007 6.12 - HSCSD device parameters */
|
||||
"+CHSN", /* 3GPP TS 27.007 6.14 - HSCSD non-transparent call configuration */
|
||||
"+CHSR", /* 3GPP TS 27.007 6.16 - HSCSD parameters report */
|
||||
"+CHST", /* 3GPP TS 27.007 6.13 - HSCSD transparent call configuration */
|
||||
"+CHSU", /* 3GPP TS 27.007 6.17 - HSCSD automatic user initiated upgrading */
|
||||
"+CHUP", /* 3GPP TS 27.007 6.5 - Hangup call */
|
||||
"+CHV", /* IS-99 5.6 - Hang-up voice */
|
||||
"+CIMI", /* 3GPP TS 27.007 5.6 - Request international mobile subscriber identity */
|
||||
"+CIND", /* 3GPP TS 27.007 8.9 - Indicator control */
|
||||
"+CIT", /* IS-99 5.6 - Command state inactivity timer */
|
||||
"+CKPD", /* 3GPP TS 27.007 8.7 - Keypad control */
|
||||
"+CLAC", /* 3GPP TS 27.007 8.37 - List all available AT commands */
|
||||
"+CLAE", /* 3GPP TS 27.007 8.31 - Language Event */
|
||||
"+CLAN", /* 3GPP TS 27.007 8.30 - Set Language */
|
||||
"+CLCC", /* 3GPP TS 27.007 7.18 - List current calls */
|
||||
"+CLCK", /* 3GPP TS 27.007 7.4 - Facility lock */
|
||||
"+CLIP", /* 3GPP TS 27.007 7.6 - Calling line identification presentation */
|
||||
"+CLIR", /* 3GPP TS 27.007 7.7 - Calling line identification restriction */
|
||||
"+CLVL", /* 3GPP TS 27.007 8.23 - Loudspeaker volume level */
|
||||
"+CMAR", /* 3GPP TS 27.007 8.36 - Master reset */
|
||||
"+CMEC", /* 3GPP TS 27.007 8.6 - Mobile termination control mode */
|
||||
"+CMEE", /* GSM07.07 9.1 - Report mobile equipment error */
|
||||
"+CMER", /* 3GPP TS 27.007 8.10 - Mobile termination event reporting */
|
||||
"+CMGC", /* GSM07.05 3.5.5/4.5 - Send command */
|
||||
"+CMGD", /* GSM07.05 3.5.4 - Delete message */
|
||||
"+CMGF", /* GSM07.05 3.2.3 - Message Format */
|
||||
"+CMGL", /* GSM07.05 3.4.2/4.1 - List messages */
|
||||
"+CMGR", /* GSM07.05 3.4.3/4.2 - Read message */
|
||||
"+CMGS", /* GSM07.05 3.5.1/4.3 - Send message */
|
||||
"+CMGW", /* GSM07.05 3.5.3/4.4 - Write message to memory */
|
||||
"+CMIP", /* IS-99 5.6 - Mobile station IP address */
|
||||
"+CMM", /* IS-135 4.1.23 - Menu map */
|
||||
"+CMMS", /* GSM07.05 3.5.6 - More messages to send */
|
||||
"+CMOD", /* 3GPP TS 27.007 6.4 - Call mode */
|
||||
"+CMSS", /* GSM07.05 3.5.2/4.7 - Send message from storage */
|
||||
"+CMUT", /* 3GPP TS 27.007 8.24 - Mute control */
|
||||
"+CMUX", /* 3GPP TS 27.007 5.7 - Multiplexing mode */
|
||||
"+CNMA", /* GSM07.05 3.4.4/4.6 - New message acknowledgement to terminal adapter */
|
||||
"+CNMI", /* GSM07.05 3.4.1 - New message indications to terminal equipment */
|
||||
"+CNUM", /* 3GPP TS 27.007 7.1 - Subscriber number */
|
||||
"+COLP", /* 3GPP TS 27.007 7.8 - Connected line identification presentation */
|
||||
"+COPN", /* 3GPP TS 27.007 7.21 - Read operator names */
|
||||
"+COPS", /* 3GPP TS 27.007 7.3 - PLMN selection */
|
||||
"+COS", /* IS-135 4.1.24 - Originating service */
|
||||
"+COTDI", /* 3GPP TS 27.007 11.1.9 - Originator to Dispatcher Information */
|
||||
"+CPAS", /* 3GPP TS 27.007 8.1 - Phone activity status */
|
||||
"+CPBF", /* 3GPP TS 27.007 8.13 - Find phonebook entries */
|
||||
"+CPBR", /* 3GPP TS 27.007 8.12 - Read phonebook entries */
|
||||
"+CPBS", /* 3GPP TS 27.007 8.11 - Select phonebook memory storage */
|
||||
"+CPBW", /* 3GPP TS 27.007 8.14 - Write phonebook entry */
|
||||
"+CPIN", /* 3GPP TS 27.007 8.3 - Enter PIN */
|
||||
"+CPLS", /* 3GPP TS 27.007 7.20 - Selection of preferred PLMN list */
|
||||
"+CPMS", /* GSM07.05 3.2.2 - Preferred message storage */
|
||||
"+CPOL", /* 3GPP TS 27.007 7.19 - Preferred PLMN list */
|
||||
"+CPPS", /* 3GPP TS 27.007 7.23 - eMLPP subscriptions */
|
||||
"+CPROT", /* 3GPP TS 27.007 8.42 - Enter protocol mode */
|
||||
"+CPUC", /* 3GPP TS 27.007 8.27 - Price per unit and currency table */
|
||||
"+CPWC", /* 3GPP TS 27.007 8.29 - Power class */
|
||||
"+CPWD", /* 3GPP TS 27.007 7.5 - Change password */
|
||||
"+CQD", /* IS-135 4.1.25 - Query disconnect timer */
|
||||
"+CR", /* 3GPP TS 27.007 6.9 - Service reporting control */
|
||||
"+CRC", /* 3GPP TS 27.007 6.11 - Cellular result codes */
|
||||
"+CREG", /* 3GPP TS 27.007 7.2 - Network registration */
|
||||
"+CRES", /* GSM07.05 3.3.6 - Restore Settings */
|
||||
"+CRLP", /* 3GPP TS 27.007 6.8 - Radio link protocol */
|
||||
"+CRM", /* IS-99 5.6 - Set rm interface protocol */
|
||||
"+CRMC", /* 3GPP TS 27.007 8.34 - Ring Melody Control */
|
||||
"+CRMP", /* 3GPP TS 27.007 8.35 - Ring Melody Playback */
|
||||
"+CRSL", /* 3GPP TS 27.007 8.21 - Ringer sound level */
|
||||
"+CRSM", /* 3GPP TS 27.007 8.18 - Restricted SIM access */
|
||||
"+CSAS", /* GSM07.05 3.3.5 - Save settings */
|
||||
"+CSCA", /* GSM07.05 3.3.1 - Service centre address */
|
||||
"+CSCB", /* GSM07.05 3.3.4 - Select cell broadcast message types */
|
||||
"+CSCC", /* 3GPP TS 27.007 8.19 - Secure control command */
|
||||
"+CSCS", /* 3GPP TS 27.007 5.5 - Select TE character set */
|
||||
"+CSDF", /* 3GPP TS 27.007 6.22 - Settings date format */
|
||||
"+CSDH", /* GSM07.05 3.3.3 - Show text mode parameters */
|
||||
"+CSGT", /* 3GPP TS 27.007 8.32 - Set Greeting Text */
|
||||
"+CSIL", /* 3GPP TS 27.007 6.23 - Silence Command */
|
||||
"+CSIM", /* 3GPP TS 27.007 8.17 - Generic SIM access */
|
||||
"+CSMP", /* GSM07.05 3.3.2 - Set text mode parameters */
|
||||
"+CSMS", /* GSM07.05 3.2.1 - Select Message Service */
|
||||
"+CSNS", /* 3GPP TS 27.007 6.19 - Single numbering scheme */
|
||||
"+CSQ", /* 3GPP TS 27.007 8.5 - Signal quality */
|
||||
"+CSS", /* IS-135 4.1.28 - Serving system identification */
|
||||
"+CSSN", /* 3GPP TS 27.007 7.17 - Supplementary service notifications */
|
||||
"+CSTA", /* 3GPP TS 27.007 6.1 - Select type of address */
|
||||
"+CSTF", /* 3GPP TS 27.007 6.24 - Settings time format */
|
||||
"+CSVM", /* 3GPP TS 27.007 8.33 - Set Voice Mail Number */
|
||||
"+CTA", /* IS-135 4.1.29 - MT-Terminated async. Data calls */
|
||||
"+CTF", /* IS-135 4.1.30 - MT-Terminated FAX calls */
|
||||
"+CTFR", /* 3GPP TS 27.007 7.14 - Call deflection */
|
||||
"+CTZR", /* 3GPP TS 27.007 8.41 - Time Zone Reporting */
|
||||
"+CTZU", /* 3GPP TS 27.007 8.40 - Automatic Time Zone Update */
|
||||
"+CUSD", /* 3GPP TS 27.007 7.15 - Unstructured supplementary service data */
|
||||
"+CUUS1", /* 3GPP TS 27.007 7.26 - User to User Signalling Service 1 */
|
||||
"+CV120", /* 3GPP TS 27.007 6.21 - V.120 rate adaption protocol */
|
||||
"+CVHU", /* 3GPP TS 27.007 6.20 - Voice Hangup Control */
|
||||
"+CVIB", /* 3GPP TS 27.007 8.22 - Vibrator mode */
|
||||
"+CXT", /* IS-99 5.6 - Cellular extension */
|
||||
"+DR", /* V.250 6.6.2 - Data compression reporting */
|
||||
"+DS", /* V.250 6.6.1 - Data compression */
|
||||
"+DS44", /* V.250 6.6.2 - V.44 data compression */
|
||||
"+EB", /* V.250 6.5.2 - Break handling in error control operation */
|
||||
"+EFCS", /* V.250 6.5.4 - 32-bit frame check sequence */
|
||||
"+EFRAM", /* V.250 6.5.8 - Frame length */
|
||||
"+ER", /* V.250 6.5.5 - Error control reporting */
|
||||
"+ES", /* V.250 6.5.1 - Error control selection */
|
||||
"+ESR", /* V.250 6.5.3 - Selective repeat */
|
||||
"+ETBM", /* V.250 6.5.6 - Call termination buffer management */
|
||||
"+EWIND", /* V.250 6.5.7 - Window size */
|
||||
"+FAA", /* T.32 8.5.2.5 - Adaptive Answer parameter */
|
||||
"+FAP", /* T.32 8.5.1.12 - Addressing and polling capabilities parameter */
|
||||
"+FAR", /* T.31 8.5.1 - Adaptive reception control */
|
||||
"+FBO", /* T.32 8.5.3.4 - Phase C data bit order */
|
||||
"+FBS", /* T.32 8.5.3.2 - Buffer Size, read only parameter */
|
||||
"+FBU", /* T.32 8.5.1.10 - HDLC Frame Reporting parameter */
|
||||
"+FCC", /* T.32 8.5.1.1 - DCE capabilities parameters */
|
||||
"+FCL", /* T.31 8.5.2 - Carrier loss timeout */
|
||||
"+FCLASS", /* T.31 8.2 - Capabilities identification and control */
|
||||
"+FCQ", /* T.32 8.5.2.3 - Copy quality checking parameter */
|
||||
"+FCR", /* T.32 8.5.1.9 - Capability to receive parameter */
|
||||
"+FCS", /* T.32 8.5.1.3 - Current Session Results parameters */
|
||||
"+FCT", /* T.32 8.5.2.6 - DTE phase C timeout parameter */
|
||||
"+FDD", /* T.31 8.5.3 - Double escape character replacement */
|
||||
"+FDR", /* T.32 8.3.4 - Data reception command */
|
||||
"+FDT", /* T.32 8.3.3 - Data transmission command */
|
||||
"+FEA", /* T.32 8.5.3.5 - Phase C received EOL alignment parameter */
|
||||
"+FFC", /* T.32 8.5.3.6 - Format conversion parameter */
|
||||
"+FFD", /* T.32 8.5.1.14 - File diagnostic message parameter */
|
||||
"+FHS", /* T.32 8.5.2.7 - Call termination status parameter */
|
||||
"+FIE", /* T.32 8.5.2.1 - Procedure interrupt enable parameter */
|
||||
"+FIP", /* T.32 8.3.6 - Initialize facsimile parameters */
|
||||
"+FIS", /* T.32 8.5.1.2 - Current session parameters */
|
||||
"+FIT", /* T.31 8.5.4 - DTE inactivity timeout */
|
||||
"+FKS", /* T.32 8.3.5 - Session termination command */
|
||||
"+FLI", /* T.32 8.5.1.5 - Local ID string parameter, TSI or CSI */
|
||||
"+FLO", /* T.31 says to implement something similar to +IFC */
|
||||
"+FLP", /* T.32 8.5.1.7 - Indicate document to poll parameter */
|
||||
"+FMI", /* T.31 says to duplicate +GMI */
|
||||
"+FMM", /* T.31 says to duplicate +GMM */
|
||||
"+FMR", /* T.31 says to duplicate +GMR */
|
||||
"+FMS", /* T.32 8.5.2.9 - Minimum phase C speed parameter */
|
||||
"+FND", /* T.32 8.5.2.10 - Non-Standard Message Data Indication parameter */
|
||||
"+FNR", /* T.32 8.5.1.11 - Negotiation message reporting control parameters */
|
||||
"+FNS", /* T.32 8.5.1.6 - Non-Standard Frame FIF parameter */
|
||||
"+FPA", /* T.32 8.5.1.13 - Selective polling address parameter */
|
||||
"+FPI", /* T.32 8.5.1.5 - Local Polling ID String parameter */
|
||||
"+FPP", /* T.32 8.5.3 - Facsimile packet protocol */
|
||||
"+FPR", /* T.31 says to implement something similar to +IPR */
|
||||
"+FPS", /* T.32 8.5.2.2 - Page Status parameter */
|
||||
"+FPW", /* T.32 8.5.1.13 - PassWord parameter (Sending or Polling) */
|
||||
"+FRH", /* T.31 8.3.6 - HDLC receive */
|
||||
"+FRM", /* T.31 8.3.4 - Facsimile receive */
|
||||
"+FRQ", /* T.32 8.5.2.4 - Receive Quality Thresholds parameters */
|
||||
"+FRS", /* T.31 8.3.2 - Receive silence */
|
||||
"+FRY", /* T.32 8.5.2.8 - ECM Retry Value parameter */
|
||||
"+FSA", /* T.32 8.5.1.13 - Subaddress parameter */
|
||||
"+FSP", /* T.32 8.5.1.8 - Request to poll parameter */
|
||||
"+FTH", /* T.31 8.3.5 - HDLC transmit */
|
||||
"+FTM", /* T.31 8.3.3 - Facsimile transmit */
|
||||
"+FTS", /* T.31 8.3.1 - Transmit silence */
|
||||
"+GCAP", /* V.250 6.1.9 - Request complete capabilities list */
|
||||
"+GCI", /* V.250 6.1.10 - Country of installation, */
|
||||
"+GMI", /* V.250 6.1.4 - Request manufacturer identification */
|
||||
"+GMM", /* V.250 6.1.5 - Request model identification */
|
||||
"+GMR", /* V.250 6.1.6 - Request revision identification */
|
||||
"+GOI", /* V.250 6.1.8 - Request global object identification */
|
||||
"+GSN", /* V.250 6.1.7 - Request product serial number identification */
|
||||
"+IBC", /* TIA-617 8.3 - Control of in-band control */
|
||||
"+IBM", /* TIA-617 8.4 - In-Band MARK idle reporting control */
|
||||
"+ICF", /* V.250 6.2.11 - DTE-DCE character framing */
|
||||
"+ICLOK", /* V.250 6.2.14 - Select sync transmit clock source */
|
||||
"+IDSR", /* V.250 6.2.16 - Select data set ready option */
|
||||
"+IFC", /* V.250 6.2.12 - DTE-DCE local flow control */
|
||||
"+ILRR", /* V.250 6.2.13 - DTE-DCE local rate reporting */
|
||||
"+ILSD", /* V.250 6.2.15 - Select long space disconnect option */
|
||||
"+IPR", /* V.250 6.2.10 - Fixed DTE rate */
|
||||
"+IRTS", /* V.250 6.2.17 - Select synchronous mode RTS option */
|
||||
"+MA", /* V.250 6.4.2 - Modulation automode control */
|
||||
"+MR", /* V.250 6.4.3 - Modulation reporting control */
|
||||
"+MS", /* V.250 6.4.1 - Modulation selection */
|
||||
"+MSC", /* V.250 6.4.8 - Seamless rate change enable */
|
||||
"+MV18AM", /* V.250 6.4.6 - V.18 answering message editing */
|
||||
"+MV18P", /* V.250 6.4.7 - Order of probes */
|
||||
"+MV18R", /* V.250 6.4.5 - V.18 reporting control */
|
||||
"+MV18S", /* V.250 6.4.4 - V.18 selection */
|
||||
"+PCW", /* V.250 6.8.1 - Call waiting enable (V.92 DCE) */
|
||||
"+PIG", /* V.250 6.8.5 - PCM upstream ignore */
|
||||
"+PMH", /* V.250 6.8.2 - Modem on hold enable */
|
||||
"+PMHF", /* V.250 6.8.6 - V.92 Modem on hold hook flash */
|
||||
"+PMHR", /* V.250 6.8.4 - Initiate modem on hold */
|
||||
"+PMHT", /* V.250 6.8.3 - Modem on hold timer */
|
||||
"+PQC", /* V.250 6.8.7 - V.92 Phase 1 and Phase 2 Control */
|
||||
"+PSS", /* V.250 6.8.8 - V.92 Use Short Sequence */
|
||||
"+SAC", /* V.252 3.4 - Audio transmit configuration */
|
||||
"+SAM", /* V.252 3.5 - Audio receive mode */
|
||||
"+SAR", /* V.252 5.3 - Audio receive channel indication */
|
||||
"+SARR", /* V.252 3.9 - Audio indication reporting */
|
||||
"+SAT", /* V.252 5.4 - Audio transmit channel indication */
|
||||
"+SCRR", /* V.252 3.11 - Capabilities indication reporting */
|
||||
"+SDC", /* V.252 3.3 - Data configuration */
|
||||
"+SDI", /* V.252 5.2 - Data channel identification */
|
||||
"+SDR", /* V.252 3.8 - Data indication reporting */
|
||||
"+SRSC", /* V.252 5.1.2 - Remote terminal simultaneous capability indication */
|
||||
"+STC", /* V.252 3.1 - Terminal configuration */
|
||||
"+STH", /* V.252 3.2 - Close logical channel */
|
||||
"+SVC", /* V.252 3.6 - Video transmit configuration */
|
||||
"+SVM", /* V.252 3.7 - Video receive mode */
|
||||
"+SVR", /* V.252 5.5 - Video receive channel indication */
|
||||
"+SVRR", /* V.252 3.10 - Video indication reporting */
|
||||
"+SVT", /* V.252 5.6 - Video transmit channel indication */
|
||||
"+TADR", /* V.250 6.7.2.9 - Local V.54 address */
|
||||
"+TAL", /* V.250 6.7.2.15 - Local analogue loop */
|
||||
"+TALS", /* V.250 6.7.2.6 - Analogue loop status */
|
||||
"+TDLS", /* V.250 6.7.2.7 - Local digital loop status */
|
||||
"+TE140", /* V.250 6.7.2.1 - Enable ckt 140 */
|
||||
"+TE141", /* V.250 6.7.2.2 - Enable ckt 141 */
|
||||
"+TEPAL", /* V.250 6.7.2.5 - Enable front panel analogue loop */
|
||||
"+TEPDL", /* V.250 6.7.2.4 - Enable front panel RDL */
|
||||
"+TERDL", /* V.250 6.7.2.3 - Enable RDL from remote */
|
||||
"+TLDL", /* V.250 6.7.2.13 - Local digital loop */
|
||||
"+TMO", /* V.250 6.9 - V.59 command */
|
||||
"+TMODE", /* V.250 6.7.2.10 - Set V.54 mode */
|
||||
"+TNUM", /* V.250 6.7.2.12 - Errored bit and block counts */
|
||||
"+TRDL", /* V.250 6.7.2.14 - Request remote digital loop */
|
||||
"+TRDLS", /* V.250 6.7.2.8 - Remote digital loop status */
|
||||
"+TRES", /* V.250 6.7.2.17 - Self test result */
|
||||
"+TSELF", /* V.250 6.7.2.16 - Self test */
|
||||
"+TTER", /* V.250 6.7.2.11 - Test error rate */
|
||||
"+VAC", /* V.252 4.1 - Set audio code */
|
||||
"+VACR", /* V.252 6.1 - Audio code report */
|
||||
"+VBT", /* 3GPP TS 27.007 C.2.2 - Buffer threshold setting */
|
||||
"+VCID", /* V.253 9.2.3 - Caller ID service */
|
||||
"+VCIDR", /* V.252 6.2 - Caller ID report */
|
||||
"+VDID", /* V.253 9.2.4 - DID service */
|
||||
"+VDIDR", /* V.252 6.2 - DID report */
|
||||
"+VDR", /* V.253 10.3.1 - Distinctive ring (ring cadence reporting) */
|
||||
"+VDT", /* V.253 10.3.2 - Control tone cadence reporting */
|
||||
"+VDX", /* V.253 10.5.6 - Speakerphone duplex mode */
|
||||
"+VEM", /* V.253 10.5.7 - Deliver event reports */
|
||||
"+VGM", /* V.253 10.5.2 - Microphone gain */
|
||||
"+VGR", /* V.253 10.2.1 - Receive gain selection */
|
||||
"+VGS", /* V.253 10.5.3 - Speaker gain */
|
||||
"+VGT", /* V.253 10.2.2 - Volume selection */
|
||||
"+VHC", /* V.252 4.12 - Telephony port hook control */
|
||||
"+VIP", /* V.253 10.1.1 - Initialize voice parameters */
|
||||
"+VIT", /* V.253 10.2.3 - DTE/DCE inactivity timer */
|
||||
"+VLS", /* V.253 10.2.4 - Analogue source/destination selection */
|
||||
"+VNH", /* V.253 9.2.5 - Automatic hangup control */
|
||||
"+VPH", /* V.252 4.11 - Phone hookswitch status */
|
||||
"+VPP", /* V.253 10.4.2 - Voice packet protocol */
|
||||
"+VPR", /* IS-101 10.4.3 - Select DTE/DCE interface rate */
|
||||
"+VRA", /* V.253 10.2.5 - Ringing tone goes away timer */
|
||||
"+VRID", /* Extension - Find the originating and destination numbers */
|
||||
"+VRL", /* V.253 10.1.2 - Ring local phone */
|
||||
"+VRN", /* V.253 10.2.6 - Ringing tone never appeared timer */
|
||||
"+VRX", /* V.253 10.1.3 - Voice receive state */
|
||||
"+VSD", /* V.253 10.2.7 - Silence detection (QUIET and SILENCE) */
|
||||
"+VSID", /* Extension - Set the originating number */
|
||||
"+VSM", /* V.253 10.2.8 - Compression method selection */
|
||||
"+VSP", /* V.253 10.5.1 - Voice speakerphone state */
|
||||
"+VTA", /* V.253 10.5.4 - Train acoustic echo-canceller */
|
||||
"+VTD", /* V.253 10.2.9 - Beep tone duration timer */
|
||||
"+VTER", /* V.252 6.4 - Simple telephony event report */
|
||||
"+VTH", /* V.253 10.5.5 - Train line echo-canceller */
|
||||
"+VTR", /* V.253 10.1.4 - Voice duplex state */
|
||||
"+VTS", /* V.253 10.1.5 - DTMF and tone generation in voice */
|
||||
"+VTX", /* V.253 10.1.6 - Transmit data state */
|
||||
"+VXT", /* IS-101 10.1.5 - Translate voice data */
|
||||
"+W", /* TIA-678 5.2.4.1 - Compliance indication */
|
||||
"+WBAG", /* TIA-678 C.5.6 Bias modem audio gain */
|
||||
"+WCDA", /* TIA-678 B.3.2.5 Display data link address */
|
||||
"+WCHG", /* TIA-678 B.3.2.4 Display battery charging status */
|
||||
"+WCID", /* TIA-678 B.3.2.1 Display system ID (operator) */
|
||||
"+WCLK", /* TIA-678 B.3.2.3 Lock/unlock DCE */
|
||||
"+WCPN", /* TIA-678 B.3.2.2 Set personal identification number */
|
||||
"+WCXF", /* TIA-678 B.3.2.6 Display supported annex B commands */
|
||||
"+WDAC", /* TIA-678 C.5.1 Data over analogue cellular command query */
|
||||
"+WDIR", /* TIA-678 C.5.8 Phone number directory selection */
|
||||
"+WECR", /* TIA-678 C.5.3 Enable cellular result codes */
|
||||
"+WFON", /* TIA-678 C.5.5 Phone specification */
|
||||
"+WKPD", /* TIA-678 C.5.7 Keypad emulation */
|
||||
"+WPBA", /* TIA-678 C.5.9 Phone battery query */
|
||||
"+WPTH", /* TIA-678 C.5.10 Call path */
|
||||
"+WRLK", /* TIA-678 C.5.4 Roam lockout */
|
||||
"+WS45", /* TIA-678 5.2.4.2 DTE-side stack selection */
|
||||
"+WS46", /* 3GPP TS 27.007 5.9 - PCCA STD-101 [17] select wireless network */
|
||||
"+WS50", /* TIA-678 B.3.1.1 Normalized signal strength */
|
||||
"+WS51", /* TIA-678 B.3.1.2 Carrier detect signal threshold */
|
||||
"+WS52", /* TIA-678 B.3.1.3 Normalized battery level */
|
||||
"+WS53", /* TIA-678 B.3.1.4 Normalized channel quality */
|
||||
"+WS54", /* TIA-678 B.3.1.5 Carrier detect channel quality threshold */
|
||||
"+WS57", /* TIA-678 B.3.1.7 Antenna preference */
|
||||
"+WS58", /* TIA-678 B.3.1.8 Idle time-out value */
|
||||
"+WSTL", /* TIA-678 C.5.2 Call session time limit */
|
||||
";", /* Dummy to absorb semi-colon delimiters in commands */
|
||||
"A", /* V.250 6.3.5 - Answer */
|
||||
"D", /* V.250 6.3.1 - Dial */
|
||||
"E", /* V.250 6.2.4 - Command echo */
|
||||
"H", /* V.250 6.3.6 - Hook control */
|
||||
"I", /* V.250 6.1.3 - Request identification information */
|
||||
"L", /* V.250 6.3.13 - Monitor speaker loudness */
|
||||
"M", /* V.250 6.3.14 - Monitor speaker mode */
|
||||
"O", /* V.250 6.3.7 - Return to online data state */
|
||||
"P", /* V.250 6.3.3 - Select pulse dialling (command) */
|
||||
"Q", /* V.250 6.2.5 - Result code suppression */
|
||||
"S0", /* V.250 6.3.8 - Automatic answer */
|
||||
"S10", /* V.250 6.3.12 - Automatic disconnect delay */
|
||||
"S3", /* V.250 6.2.1 - Command line termination character */
|
||||
"S4", /* V.250 6.2.2 - Response formatting character */
|
||||
"S5", /* V.250 6.2.3 - Command line editing character */
|
||||
"S6", /* V.250 6.3.9 - Pause before blind dialling */
|
||||
"S7", /* V.250 6.3.10 - Connection completion timeout */
|
||||
"S8", /* V.250 6.3.11 - Comma dial modifier time */
|
||||
"T", /* V.250 6.3.2 - Select tone dialling (command) */
|
||||
"V", /* V.250 6.2.6 - DCE response format */
|
||||
"X", /* V.250 6.2.7 - Result code selection and call progress monitoring control */
|
||||
"Z", /* V.250 6.1.1 - Reset to default configuration */
|
||||
NULL
|
||||
};
|
||||
|
||||
int packed_ptr = 0;
|
||||
|
||||
short int packed_trie[30000];
|
||||
|
||||
#define ALPHABET_SIZE 128
|
||||
|
||||
typedef struct trie_node_s
|
||||
{
|
||||
int first;
|
||||
int last;
|
||||
int node_no;
|
||||
int entry;
|
||||
/* Array of pointers to children */
|
||||
struct trie_node_s *child_list[ALPHABET_SIZE];
|
||||
} trie_node_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int entries;
|
||||
/* The root of the trie */
|
||||
trie_node_t *root;
|
||||
} trie_t;
|
||||
|
||||
static trie_node_t *trie_node_create(void)
|
||||
{
|
||||
trie_node_t *s;
|
||||
|
||||
if ((s = (trie_node_t *) malloc(sizeof(*s))))
|
||||
{
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->first = ALPHABET_SIZE - 1;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static trie_t *trie_create(void)
|
||||
{
|
||||
trie_t *s;
|
||||
|
||||
if ((s = (trie_t *) malloc(sizeof(*s))))
|
||||
{
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->root = trie_node_create();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void trie_recursive_add_node_numbers(trie_node_t *t)
|
||||
{
|
||||
int index;
|
||||
|
||||
if (t)
|
||||
{
|
||||
if (t->first <= t->last)
|
||||
{
|
||||
t->node_no = packed_ptr + 1;
|
||||
packed_ptr += (t->last - t->first + 1 + 3);
|
||||
for (index = 0; index < ALPHABET_SIZE; index++)
|
||||
trie_recursive_add_node_numbers(t->child_list[index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
t->node_no = packed_ptr + 1;
|
||||
packed_ptr += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void trie_recursive_build_packed_trie(trie_node_t *t)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (t)
|
||||
{
|
||||
if (t->first <= t->last)
|
||||
{
|
||||
packed_trie[packed_ptr++] = t->first;
|
||||
packed_trie[packed_ptr++] = t->last;
|
||||
packed_trie[packed_ptr++] = t->entry;
|
||||
for (i = t->first; i <= t->last; i++)
|
||||
packed_trie[packed_ptr++] = (t->child_list[i]) ? t->child_list[i]->node_no : 0;
|
||||
for (i = t->first; i <= t->last; i++)
|
||||
trie_recursive_build_packed_trie(t->child_list[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
packed_trie[packed_ptr++] = 1;
|
||||
packed_trie[packed_ptr++] = 0;
|
||||
packed_trie[packed_ptr++] = t->entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void trie_add(trie_t *s, const char *u, size_t len)
|
||||
{
|
||||
int i;
|
||||
int index;
|
||||
trie_node_t *t;
|
||||
|
||||
s->entries++;
|
||||
/* Loop over the length of the string to add and traverse the trie... */
|
||||
for (t = s->root, i = 0; i < len; i++)
|
||||
{
|
||||
/* The character in u we are processing... */
|
||||
index = (unsigned char) u[i];
|
||||
|
||||
/* Is there a child node for this character? */
|
||||
if (t->child_list[index] == NULL)
|
||||
{
|
||||
t->child_list[index] = trie_node_create();
|
||||
if (index < t->first)
|
||||
t->first = index;
|
||||
if (index > t->last)
|
||||
t->last = index;
|
||||
}
|
||||
|
||||
/* Move to the new node... and loop */
|
||||
t = t->child_list[index];
|
||||
}
|
||||
t->entry = s->entries;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void dump_trie(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("\nstatic const at_cmd_service_t at_commands[] =\n{\n");
|
||||
for (i = 0; wordlist[i]; i++)
|
||||
{
|
||||
switch (wordlist[i][0])
|
||||
{
|
||||
case ' ':
|
||||
case ';':
|
||||
printf(" at_cmd_dummy,\n");
|
||||
break;
|
||||
case '+':
|
||||
printf(" at_cmd_plus_%s,\n", wordlist[i] + 1);
|
||||
break;
|
||||
case '&':
|
||||
printf(" at_cmd_amp_%s,\n", wordlist[i] + 1);
|
||||
break;
|
||||
default:
|
||||
printf(" at_cmd_%s,\n", wordlist[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("};\n");
|
||||
|
||||
printf("\nstatic const uint16_t command_trie[] =\n{");
|
||||
for (i = 0; i < packed_ptr; i++)
|
||||
{
|
||||
if ((i & 7) == 0)
|
||||
printf("\n ");
|
||||
printf("0x%04X, ", packed_trie[i]);
|
||||
}
|
||||
printf("\n};\n");
|
||||
printf("\n#define COMMAND_TRIE_LEN %d\n", packed_ptr);
|
||||
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
trie_t *s;
|
||||
int i;
|
||||
|
||||
s = trie_create();
|
||||
|
||||
for (i = 0; wordlist[i]; i++)
|
||||
trie_add(s, wordlist[i], strlen(wordlist[i]));
|
||||
printf("// The trie contains %d entries\n", i);
|
||||
|
||||
packed_ptr = 0;
|
||||
trie_recursive_add_node_numbers(s->root);
|
||||
packed_ptr = 0;
|
||||
trie_recursive_build_packed_trie(s->root);
|
||||
|
||||
dump_trie();
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* make_modem_filter.c - Create coefficient sets for pulse shaping
|
||||
* various modem rx and tx signals.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2008 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: make_modem_filter.c,v 1.11 2008/07/02 14:48:25 steveu Exp $
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "floating_fudge.h"
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/complex.h"
|
||||
#include "filter_tools.h"
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE (!FALSE)
|
||||
|
||||
//#define SAMPLE_RATE 8000.0
|
||||
#define MAX_COEFFS_PER_FILTER 128
|
||||
#define MAX_COEFF_SETS 384
|
||||
|
||||
static void make_tx_filter(int coeff_sets,
|
||||
int coeffs_per_filter,
|
||||
double carrier,
|
||||
double baud_rate,
|
||||
double excess_bandwidth,
|
||||
int fixed_point,
|
||||
const char *tag)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
int x;
|
||||
int total_coeffs;
|
||||
double alpha;
|
||||
double beta;
|
||||
double gain;
|
||||
double scaling;
|
||||
double peak;
|
||||
double coeffs[MAX_COEFF_SETS*MAX_COEFFS_PER_FILTER + 1];
|
||||
|
||||
total_coeffs = coeff_sets*coeffs_per_filter + 1;
|
||||
alpha = baud_rate/(2.0*(double) (coeff_sets*baud_rate));
|
||||
beta = excess_bandwidth;
|
||||
|
||||
compute_raised_cosine_filter(coeffs, total_coeffs, TRUE, FALSE, alpha, beta);
|
||||
|
||||
/* Find the DC gain of the filter, and adjust the filter to unity gain. */
|
||||
gain = 0.0;
|
||||
for (i = coeff_sets/2; i < total_coeffs; i += coeff_sets)
|
||||
gain += coeffs[i];
|
||||
/* Normalise the gain to 1.0 */
|
||||
for (i = 0; i < total_coeffs; i++)
|
||||
coeffs[i] /= gain;
|
||||
gain = 1.0;
|
||||
|
||||
if (fixed_point)
|
||||
{
|
||||
peak = -1.0;
|
||||
for (i = 0; i < total_coeffs; i++)
|
||||
{
|
||||
if (fabs(coeffs[i]) > peak)
|
||||
peak = fabs(coeffs[i]);
|
||||
}
|
||||
scaling = 32767.0;
|
||||
if (peak >= 1.0)
|
||||
{
|
||||
scaling /= peak;
|
||||
gain = 1.0/peak;
|
||||
}
|
||||
for (i = 0; i < total_coeffs; i++)
|
||||
coeffs[i] *= scaling;
|
||||
}
|
||||
|
||||
/* Churn out the data as a C source code header file, which can be directly included by the
|
||||
modem code. */
|
||||
printf("#define TX_PULSESHAPER%s_GAIN %ff\n", tag, gain);
|
||||
printf("#define TX_PULSESHAPER%s_COEFF_SETS %d\n", tag, coeff_sets);
|
||||
printf("static const %s tx_pulseshaper%s[TX_PULSESHAPER%s_COEFF_SETS][%d] =\n",
|
||||
(fixed_point) ? "int16_t" : "float",
|
||||
tag,
|
||||
tag,
|
||||
coeffs_per_filter);
|
||||
printf("{\n");
|
||||
for (j = 0; j < coeff_sets; j++)
|
||||
{
|
||||
x = j;
|
||||
printf(" {\n");
|
||||
if (fixed_point)
|
||||
printf(" %8d, /* Filter %d */\n", (int) coeffs[x], j);
|
||||
else
|
||||
printf(" %15.10ff, /* Filter %d */\n", coeffs[x], j);
|
||||
for (i = 1; i < coeffs_per_filter - 1; i++)
|
||||
{
|
||||
x = i*coeff_sets + j;
|
||||
if (fixed_point)
|
||||
printf(" %8d,\n", (int) coeffs[x]);
|
||||
else
|
||||
printf(" %15.10ff,\n", coeffs[x]);
|
||||
}
|
||||
x = i*coeff_sets + j;
|
||||
if (fixed_point)
|
||||
printf(" %8d\n", (int) coeffs[x]);
|
||||
else
|
||||
printf(" %15.10ff\n", coeffs[x]);
|
||||
if (j < coeff_sets - 1)
|
||||
printf(" },\n");
|
||||
else
|
||||
printf(" }\n");
|
||||
}
|
||||
printf("};\n");
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void make_rx_filter(int coeff_sets,
|
||||
int coeffs_per_filter,
|
||||
double carrier,
|
||||
double baud_rate,
|
||||
double excess_bandwidth,
|
||||
int fixed_point,
|
||||
const char *tag)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
int m;
|
||||
int x;
|
||||
int total_coeffs;
|
||||
double alpha;
|
||||
double beta;
|
||||
double gain;
|
||||
double peak;
|
||||
double coeffs[MAX_COEFF_SETS*MAX_COEFFS_PER_FILTER + 1];
|
||||
complex_t co[MAX_COEFFS_PER_FILTER];
|
||||
|
||||
total_coeffs = coeff_sets*coeffs_per_filter + 1;
|
||||
alpha = baud_rate/(2.0*(double) (coeff_sets*SAMPLE_RATE));
|
||||
beta = excess_bandwidth;
|
||||
carrier *= 2.0*3.1415926535/SAMPLE_RATE;
|
||||
|
||||
compute_raised_cosine_filter(coeffs, total_coeffs, TRUE, FALSE, alpha, beta);
|
||||
|
||||
/* Find the DC gain of the filter, and adjust the filter to unity gain. */
|
||||
gain = 0.0;
|
||||
for (i = coeff_sets/2; i < total_coeffs; i += coeff_sets)
|
||||
gain += coeffs[i];
|
||||
/* Normalise the gain to 1.0 */
|
||||
for (i = 0; i < total_coeffs; i++)
|
||||
coeffs[i] /= gain;
|
||||
gain = 1.0;
|
||||
|
||||
if (fixed_point)
|
||||
{
|
||||
peak = -1.0;
|
||||
for (i = 0; i < total_coeffs; i++)
|
||||
{
|
||||
if (fabs(coeffs[i]) > peak)
|
||||
peak = fabs(coeffs[i]);
|
||||
}
|
||||
gain = 32767.0;
|
||||
if (peak >= 1.0)
|
||||
gain /= peak;
|
||||
for (i = 0; i < total_coeffs; i++)
|
||||
coeffs[i] *= gain;
|
||||
}
|
||||
|
||||
/* Churn out the data as a C source code header file, which can be directly included by the
|
||||
modem code. */
|
||||
printf("#define RX_PULSESHAPER%s_GAIN %ff\n", tag, gain);
|
||||
printf("#define RX_PULSESHAPER%s_COEFF_SETS %d\n", tag, coeff_sets);
|
||||
printf("static const %s rx_pulseshaper%s[RX_PULSESHAPER%s_COEFF_SETS][%d] =\n",
|
||||
(fixed_point) ? "complexi16_t" : "complexf_t",
|
||||
tag,
|
||||
tag,
|
||||
coeffs_per_filter);
|
||||
printf("{\n");
|
||||
for (j = 0; j < coeff_sets; j++)
|
||||
{
|
||||
/* Complex modulate the filter, to make it a complex pulse shaping bandpass filter
|
||||
centred at the nominal carrier frequency. Use the same phase for all the coefficient
|
||||
sets. This means the modem can step the carrier in whole samples, and not worry about
|
||||
the fractional sample shift caused by selecting amongst the various coefficient sets. */
|
||||
for (i = 0; i < coeffs_per_filter; i++)
|
||||
{
|
||||
m = i - (coeffs_per_filter >> 1);
|
||||
x = i*coeff_sets + j;
|
||||
co[i].re = coeffs[x]*cos(carrier*m);
|
||||
co[i].im = coeffs[x]*sin(carrier*m);
|
||||
}
|
||||
printf(" {\n");
|
||||
if (fixed_point)
|
||||
printf(" {%8d, %8d}, /* Filter %d */\n", (int) co[i].re, (int) co[i].im, j);
|
||||
else
|
||||
printf(" {%15.10ff, %15.10ff}, /* Filter %d */\n", co[0].re, co[0].im, j);
|
||||
for (i = 1; i < coeffs_per_filter - 1; i++)
|
||||
{
|
||||
if (fixed_point)
|
||||
printf(" {%8d, %8d},\n", (int) co[i].re, (int) co[i].im);
|
||||
else
|
||||
printf(" {%15.10ff, %15.10ff},\n", co[i].re, co[i].im);
|
||||
}
|
||||
if (fixed_point)
|
||||
printf(" {%8d, %8d}\n", (int) co[i].re, (int) co[i].im);
|
||||
else
|
||||
printf(" {%15.10ff, %15.10ff}\n", co[i].re, co[i].im);
|
||||
if (j < coeff_sets - 1)
|
||||
printf(" },\n");
|
||||
else
|
||||
printf(" }\n");
|
||||
}
|
||||
printf("};\n");
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: make_modem_rx_filter -m <V.17 | V.22bis | V.22bis1200 | V.22bis2400 | V.27ter2400 | V.27ter4800 | V.29> [-i] [-r] [-t]\n");
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rx_coeff_sets;
|
||||
int rx_coeffs_per_filter;
|
||||
int tx_coeff_sets;
|
||||
int tx_coeffs_per_filter;
|
||||
int opt;
|
||||
int transmit_modem;
|
||||
int fixed_point;
|
||||
double carrier;
|
||||
double baud_rate;
|
||||
double rx_excess_bandwidth;
|
||||
double tx_excess_bandwidth;
|
||||
const char *tag;
|
||||
const char *modem;
|
||||
|
||||
fixed_point = FALSE;
|
||||
transmit_modem = FALSE;
|
||||
modem = "";
|
||||
while ((opt = getopt(argc, argv, "im:rt")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'i':
|
||||
fixed_point = TRUE;
|
||||
break;
|
||||
case 'm':
|
||||
modem = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
transmit_modem = FALSE;
|
||||
break;
|
||||
case 't':
|
||||
transmit_modem = TRUE;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
exit(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (strcmp(modem, "V.17") == 0)
|
||||
{
|
||||
rx_coeff_sets = 192;
|
||||
rx_coeffs_per_filter = 27;
|
||||
rx_excess_bandwidth = 0.5;
|
||||
tx_coeff_sets = 10;
|
||||
tx_coeffs_per_filter = 9;
|
||||
tx_excess_bandwidth = 0.25;
|
||||
carrier = 1800.0;
|
||||
baud_rate = 2400.0;
|
||||
tag = "";
|
||||
}
|
||||
else if (strcmp(modem, "V.22bis") == 0)
|
||||
{
|
||||
/* This is only intended to apply to transmit. */
|
||||
rx_coeff_sets = 12;
|
||||
rx_coeffs_per_filter = 37;
|
||||
rx_excess_bandwidth = 0.75;
|
||||
tx_coeff_sets = 40;
|
||||
tx_coeffs_per_filter = 9;
|
||||
tx_excess_bandwidth = 0.75;
|
||||
carrier = 1200.0;
|
||||
baud_rate = 600.0;
|
||||
tag = "";
|
||||
}
|
||||
else if (strcmp(modem, "V.22bis1200") == 0)
|
||||
{
|
||||
/* This is only intended to apply to receive. */
|
||||
rx_coeff_sets = 12;
|
||||
rx_coeffs_per_filter = 37;
|
||||
rx_excess_bandwidth = 0.75;
|
||||
tx_coeff_sets = 40;
|
||||
tx_coeffs_per_filter = 9;
|
||||
tx_excess_bandwidth = 0.75;
|
||||
carrier = 1200.0;
|
||||
baud_rate = 600.0;
|
||||
tag = "_1200";
|
||||
}
|
||||
else if (strcmp(modem, "V.22bis2400") == 0)
|
||||
{
|
||||
/* This is only intended to apply to receive. */
|
||||
rx_coeff_sets = 12;
|
||||
rx_coeffs_per_filter = 37;
|
||||
rx_excess_bandwidth = 0.75;
|
||||
tx_coeff_sets = 40;
|
||||
tx_coeffs_per_filter = 9;
|
||||
tx_excess_bandwidth = 0.75;
|
||||
carrier = 2400.0;
|
||||
baud_rate = 600.0;
|
||||
tag = "_2400";
|
||||
}
|
||||
else if (strcmp(modem, "V.27ter4800") == 0)
|
||||
{
|
||||
rx_coeff_sets = 8;
|
||||
rx_coeffs_per_filter = 27;
|
||||
rx_excess_bandwidth = 0.5;
|
||||
tx_coeff_sets = 5;
|
||||
tx_coeffs_per_filter = 9;
|
||||
tx_excess_bandwidth = 0.5;
|
||||
carrier = 1800.0;
|
||||
baud_rate = 1600.0;
|
||||
tag = "_4800";
|
||||
}
|
||||
else if (strcmp(modem, "V.27ter2400") == 0)
|
||||
{
|
||||
rx_coeff_sets = 12;
|
||||
rx_coeffs_per_filter = 27;
|
||||
rx_excess_bandwidth = 0.5;
|
||||
tx_coeff_sets = 20;
|
||||
tx_coeffs_per_filter = 9;
|
||||
tx_excess_bandwidth = 0.5;
|
||||
carrier = 1800.0;
|
||||
baud_rate = 1200.0;
|
||||
tag = "_2400";
|
||||
}
|
||||
else if (strcmp(modem, "V.29") == 0)
|
||||
{
|
||||
rx_coeff_sets = 48;
|
||||
rx_coeffs_per_filter = 27;
|
||||
rx_excess_bandwidth = 0.5;
|
||||
tx_coeff_sets = 10;
|
||||
tx_coeffs_per_filter = 9;
|
||||
tx_excess_bandwidth = 0.25;
|
||||
carrier = 1700.0;
|
||||
baud_rate = 2400.0;
|
||||
tag = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
usage();
|
||||
exit(2);
|
||||
}
|
||||
if (transmit_modem)
|
||||
{
|
||||
make_tx_filter(tx_coeff_sets,
|
||||
tx_coeffs_per_filter,
|
||||
carrier,
|
||||
baud_rate,
|
||||
tx_excess_bandwidth,
|
||||
fixed_point,
|
||||
tag);
|
||||
}
|
||||
else
|
||||
{
|
||||
make_rx_filter(rx_coeff_sets,
|
||||
rx_coeffs_per_filter,
|
||||
carrier,
|
||||
baud_rate,
|
||||
rx_excess_bandwidth,
|
||||
fixed_point,
|
||||
tag);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user