first commit
This commit is contained in:
Vendored
+504
@@ -0,0 +1,504 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, 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 Street, 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!
|
||||
Vendored
+81
@@ -0,0 +1,81 @@
|
||||
#
|
||||
# Makefile for SPECBLEACH
|
||||
# This one creates libspecbleach.a intended for static linking
|
||||
#
|
||||
|
||||
FFTWINCLUDE=`pkg-config --cflags fftw3f`
|
||||
|
||||
CFLAGS?= -pthread -O3 -D_GNU_SOURCE -Wno-parentheses $(FFTWINCLUDE)
|
||||
|
||||
COMPILE=$(CC) $(CFLAGS) -Iinclude -Isrc -Isrc/shared
|
||||
|
||||
SOURCES= \
|
||||
src/processors/specbleach_adenoiser.c \
|
||||
src/processors/specbleach_denoiser.c \
|
||||
src/processors/adaptivedenoiser/adaptive_denoiser.c \
|
||||
src/shared/gain_estimation/gain_estimators.c \
|
||||
src/shared/noise_estimation/adaptive_noise_estimator.c \
|
||||
src/shared/pre_estimation/absolute_hearing_thresholds.c \
|
||||
src/shared/pre_estimation/critical_bands.c \
|
||||
src/shared/pre_estimation/masking_estimator.c \
|
||||
src/shared/pre_estimation/noise_scaling_criterias.c \
|
||||
src/shared/pre_estimation/spectral_smoother.c \
|
||||
src/shared/pre_estimation/transient_detector.c \
|
||||
src/shared/post_estimation/noise_floor_manager.c \
|
||||
src/shared/post_estimation/postfilter.c \
|
||||
src/shared/post_estimation/spectral_whitening.c \
|
||||
src/shared/utils/denoise_mixer.c \
|
||||
src/shared/utils/general_utils.c \
|
||||
src/shared/utils/spectral_features.c \
|
||||
src/shared/utils/spectral_utils.c \
|
||||
src/shared/stft/stft_processor.c \
|
||||
src/shared/stft/fft_transform.c \
|
||||
src/shared/stft/stft_buffer.c \
|
||||
src/shared/stft/stft_windows.c
|
||||
|
||||
HEADERS= \
|
||||
|
||||
OBJS= \
|
||||
src/processors/specbleach_adenoiser.o \
|
||||
src/processors/specbleach_denoiser.o \
|
||||
src/processors/adaptivedenoiser/adaptive_denoiser.o \
|
||||
src/shared/gain_estimation/gain_estimators.o \
|
||||
src/shared/pre_estimation/absolute_hearing_thresholds.o \
|
||||
src/shared/pre_estimation/critical_bands.o \
|
||||
src/shared/pre_estimation/masking_estimator.o \
|
||||
src/shared/noise_estimation/adaptive_noise_estimator.o \
|
||||
src/shared/pre_estimation/noise_scaling_criterias.o \
|
||||
src/shared/pre_estimation/spectral_smoother.o \
|
||||
src/shared/pre_estimation/transient_detector.o \
|
||||
src/shared/post_estimation/noise_floor_manager.o \
|
||||
src/shared/post_estimation/postfilter.o \
|
||||
src/shared/post_estimation/spectral_whitening.o \
|
||||
src/shared/utils/denoise_mixer.o \
|
||||
src/shared/utils/general_utils.o \
|
||||
src/shared/utils/spectral_features.o \
|
||||
src/shared/utils/spectral_utils.o \
|
||||
src/shared/stft/stft_processor.o \
|
||||
src/shared/stft/fft_transform.o \
|
||||
src/shared/stft/stft_buffer.o \
|
||||
src/shared/stft/stft_windows.o
|
||||
|
||||
|
||||
libspecbleach.a: $(OBJS)
|
||||
ar rv libspecbleach.a $(OBJS)
|
||||
ranlib libspecbleach.a
|
||||
|
||||
.c.o:
|
||||
$(COMPILE) -c -o $@ $<
|
||||
|
||||
|
||||
clean:
|
||||
-rm -f libspecbleach.a $(OBJS)
|
||||
|
||||
#############################################################################
|
||||
#
|
||||
# What follows is automatically generated by the "makedepend" program
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
# DO NOT DELETE
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
libspecbleach
|
||||
=============
|
||||
|
||||
The material put here into piHPSDR comes from
|
||||
|
||||
https://github.com/lucianodato/libspecbleach
|
||||
|
||||
and reflects commit 52660fa1dbe41991cf420b9d60648f7563b9717e.
|
||||
|
||||
A Makefile has been provided that just compiles the files needed
|
||||
in piHPSDR and produce a library that can be linked statically.
|
||||
|
||||
This means, compared to the original repository, only the files
|
||||
|
||||
libspecbleach/Makefile
|
||||
libspecbleach/README.DL1YCF (this file)
|
||||
|
||||
have been added and lots of files (e.g. tests, examples,
|
||||
meson build files, etc.) have been omitted.
|
||||
Vendored
+135
@@ -0,0 +1,135 @@
|
||||
# libspecbleach
|
||||
|
||||
[](https://github.com/lucianodato/libspecbleach/actions/workflows/build.yml)
|
||||
[](https://codecov.io/gh/lucianodato/libspecbleach)
|
||||
[](https://www.gnu.org/licenses/lgpl-2.1)
|
||||
|
||||
C library for audio noise reduction and other spectral effects
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Background](#background)
|
||||
- [De-noise Algorithms](#de-noise-algorithms)
|
||||
- [Build](#build)
|
||||
- [Installation](#installation)
|
||||
- [Usage Examples](#usage-examples)
|
||||
- [Development](#development)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
|
||||
## Background
|
||||
|
||||
This library is based on the algorithms that were used in [noise-repellent](https://github.com/lucianodato/noise-repellent). These were extracted into a standalone library to remove the lv2 dependency. It was designed to be extensible and modular. It uses the concept of a spectral processor which itself uses a short time Fourier transform (STFT) to process the audio. There are two initial processors in place, one which uses the adaptive part of noise repellent and one that uses the manual capturing profile based denoising. The library could be extended with more spectral processors using any STFT-based algorithm such as de-crackle, de-click and other audio restoration algorithms.
|
||||
|
||||
## De-noise Algorithms
|
||||
|
||||
There are several techniques implemented in the library that are being used in the denoisers, such as masking thresholds estimation, onset detectors, etc. All these are being used in conjunction to improve the very basic spectral subtraction algorithm. Most of the papers used are listed in the wiki of the project. Also a block diagram is provided to explain the reduction architecture.
|
||||
|
||||
## Build
|
||||
|
||||
If you wish to compile yourself and install the library you will need:
|
||||
- A C compiling toolchain (GCC or Clang)
|
||||
- [Meson](https://mesonbuild.com/) build system (0.60.0 or newer)
|
||||
- [Ninja](https://ninja-build.org/) build tool
|
||||
- [FFTW3](http://www.fftw.org/) library (float version)
|
||||
- [libsndfile](https://github.com/libsndfile/libsndfile) (optional, for examples)
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
git clone https://github.com/lucianodato/libspecbleach.git
|
||||
cd libspecbleach
|
||||
meson setup build --buildtype=release
|
||||
meson compile -C build
|
||||
sudo meson install -C build
|
||||
```
|
||||
|
||||
## Build Options
|
||||
|
||||
You can configure the build using `-Doption=value`:
|
||||
|
||||
- `enable_examples`: Build example applications (default: `false`). Requires `libsndfile`.
|
||||
- `enable_tests`: Build unit and integration tests (default: `false`). Requires `libsndfile`.
|
||||
- `static_deps`: Link internal dependencies (like FFTW3) statically (default: `false`). Useful for creating self-contained libraries.
|
||||
- `custom_warning_level`: 0-3 (default: `2`). Controls compiler warning verbosity.
|
||||
- `treat_warnings_as_errors`: Treat compiler warnings as errors (default: `false`).
|
||||
- `enable_sanitizers`: Enable sanitizers in debug builds (default: `false`).
|
||||
- `sanitize_address`: Enable AddressSanitizer (default: `false`).
|
||||
- `sanitize_undefined`: Enable UndefinedBehaviorSanitizer (default: `false`).
|
||||
|
||||
Example for a static build with examples:
|
||||
```bash
|
||||
meson setup build -Dstatic_deps=true -Denable_examples=true
|
||||
meson compile -C build
|
||||
```
|
||||
|
||||
|
||||
## Usage Examples
|
||||
|
||||
Simple console apps examples are provided to demonstrate how to use the library. It needs libsndfile to compile successfully. You can build them with:
|
||||
|
||||
```bash
|
||||
meson setup build --buildtype=release -Denable_examples=true
|
||||
meson compile -C build
|
||||
```
|
||||
|
||||
### Adaptive noise reduction
|
||||
|
||||
```bash
|
||||
./build/example/adenoiser_demo <input file name> <output file name>
|
||||
```
|
||||
|
||||
### Manual noise reduction
|
||||
|
||||
```bash
|
||||
./build/example/denoiser_demo <input file name> <output file name>
|
||||
```
|
||||
|
||||
It will recognize any libsndfile supported format.
|
||||
|
||||
## Development
|
||||
|
||||
### Building for Development
|
||||
|
||||
For development builds with debugging symbols:
|
||||
|
||||
```bash
|
||||
meson setup build --buildtype=debug
|
||||
meson compile -C build
|
||||
```
|
||||
|
||||
### Code Formatting
|
||||
|
||||
The project uses `clang-format` for code formatting. To format the code:
|
||||
|
||||
```bash
|
||||
meson compile format -C build
|
||||
```
|
||||
|
||||
### Running Tests
|
||||
|
||||
If tests are enabled:
|
||||
|
||||
```bash
|
||||
meson setup build -Denable_tests=true
|
||||
meson test -C build
|
||||
```
|
||||
|
||||
### Coverage
|
||||
|
||||
To generate coverage reports locally, you will need `gcovr` or `lcov` installed.
|
||||
|
||||
```bash
|
||||
meson setup build --buildtype=debug -Db_coverage=true
|
||||
meson compile -C build
|
||||
meson test -C build
|
||||
ninja -C build coverage-html
|
||||
```
|
||||
|
||||
The report will be available in `build/meson-logs/coveragereport/index.html`.
|
||||
|
||||
## License
|
||||
|
||||
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.
|
||||
|
||||
See [LICENSE](LICENSE) for more details.
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef SPECBLEACH_ADENOISER_H_INCLUDED
|
||||
#define SPECBLEACH_ADENOISER_H_INCLUDED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void* SpectralBleachHandle;
|
||||
|
||||
typedef struct SpectralBleachAdaptiveParameters {
|
||||
/* Enables outputting the residue of the reduction processing. It's either
|
||||
* true or false */
|
||||
bool residual_listen;
|
||||
|
||||
/* Sets the amount of dBs that the noise will be attenuated. It goes from 0 dB
|
||||
* to 40 dB. This controls both the gain attenuation strength and the residual
|
||||
* noise mixing level for optimal noise reduction. */
|
||||
float reduction_amount;
|
||||
|
||||
/* Percentage of smoothing to apply. Averages the reduction calculation frame
|
||||
* per frame so the rate of change is less resulting in less musical noise but
|
||||
* if too strong it can blur transient and reduce high frequencies. It goes
|
||||
* from 0 to 100 percent */
|
||||
float smoothing_factor;
|
||||
|
||||
/* Percentage of whitening that is going to be applied to the residue of the
|
||||
* reduction. It modifies the noise floor to be more like white noise. This
|
||||
* can help hide musical noise when the noise is colored. It goes from 0 to
|
||||
* 100 percent */
|
||||
float whitening_factor;
|
||||
|
||||
/* Type of algorithm used to scale noise in order to apply over or under
|
||||
* subtraction in different parts of the spectrum while calculating the
|
||||
* reduction. 0 is a-posteriori snr scaling using the complete spectrum, 1 is
|
||||
* a-posteriori using critical bands, 2 is using masking thresholds and 3 is
|
||||
* disabled.
|
||||
*/
|
||||
int noise_scaling_type;
|
||||
|
||||
/* Strength in which the reduction will be applied. It uses the masking
|
||||
* thresholds of the signal to determine where in the spectrum the reduction
|
||||
* needs to be stronger. This parameter scales how much in each of the
|
||||
* frequencies the reduction is going to be applied. It can be a positive dB
|
||||
* value in between 0 dB and 12 dB */
|
||||
float noise_rescale;
|
||||
|
||||
/* Sets the SNR threshold in dB in which the post-filter will start to blur
|
||||
* musical noise. It can be a positive or negative dB value in between -10 dB
|
||||
* and 10 dB */
|
||||
float post_filter_threshold;
|
||||
|
||||
/* Method used for adaptive noise estimation in the adaptive denoiser.
|
||||
* 0: LOUIZOU_METHOD uses minimum statistics (default)
|
||||
* 1: SPP_MMSE_METHOD uses Speech Presence Probability with MMSE estimation
|
||||
* for lower complexity and unbiased noise tracking. */
|
||||
int noise_estimation_method;
|
||||
} SpectralBleachAdaptiveParameters;
|
||||
|
||||
/**
|
||||
* Returns a handle to an instance of the library for the adaptive based
|
||||
* noise reduction. Sample rate could be anything from 4000hz to 192khz.
|
||||
* Recommended frame size range is between 20ms and 100ms
|
||||
*/
|
||||
SpectralBleachHandle specbleach_adaptive_initialize(uint32_t sample_rate,
|
||||
float frame_size);
|
||||
|
||||
/**
|
||||
* Free instance associated to the handle passed
|
||||
*/
|
||||
void specbleach_adaptive_free(SpectralBleachHandle instance);
|
||||
/**
|
||||
* Loads the parameters for the reduction.
|
||||
* This has to be called before processing
|
||||
*/
|
||||
bool specbleach_adaptive_load_parameters(
|
||||
SpectralBleachHandle instance, SpectralBleachAdaptiveParameters parameters);
|
||||
/**
|
||||
* Returns the latency in samples associated with the library instance
|
||||
*/
|
||||
uint32_t specbleach_adaptive_get_latency(SpectralBleachHandle instance);
|
||||
/**
|
||||
* Process buffer of a number of samples
|
||||
*/
|
||||
bool specbleach_adaptive_process(SpectralBleachHandle instance,
|
||||
uint32_t number_of_samples, const float* input,
|
||||
float* output);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef SPECBLEACH_DENOISER_H_INCLUDED
|
||||
#define SPECBLEACH_DENOISER_H_INCLUDED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void* SpectralBleachHandle;
|
||||
|
||||
typedef struct SpectralBleachDenoiserParameters {
|
||||
/* Sets the processor in listening mode to capture the noise profile.
|
||||
* 0 is disabled, 1 will learn all profile types simultaneously. */
|
||||
int learn_noise;
|
||||
|
||||
/* Sets the noise reduction mode to use when learning is disabled.
|
||||
* 1 will use the average profile, 2 will use the median profile
|
||||
* and 3 will use the max profile. */
|
||||
int noise_reduction_mode;
|
||||
|
||||
/* Enables outputting the residue of the reduction processing. It's either
|
||||
* true or false */
|
||||
bool residual_listen;
|
||||
|
||||
/* Sets the amount of dBs that the noise will be attenuated. It goes from 0 dB
|
||||
* to 40 dB. This controls both the gain attenuation strength and the residual
|
||||
* noise mixing level for optimal noise reduction. */
|
||||
float reduction_amount;
|
||||
|
||||
/* Percentage of smoothing to apply. Averages the reduction calculation frame
|
||||
* per frame so the rate of change is less resulting in less musical noise but
|
||||
* if too strong it can blur transient and reduce high frequencies. It goes
|
||||
* from 0 to 100 percent */
|
||||
float smoothing_factor;
|
||||
|
||||
/* Percentage of whitening that is going to be applied to the residue of the
|
||||
* reduction. It modifies the noise floor to be more like white noise. This
|
||||
* can help hide musical noise when the noise is colored. It goes from 0 to
|
||||
* 100 percent */
|
||||
float whitening_factor;
|
||||
|
||||
/* Type of algorithm used to scale noise in order to apply over or under
|
||||
* subtraction in different parts of the spectrum while calculating the
|
||||
* reduction. 0 is a-posteriori snr scaling using the complete spectrum, 1 is
|
||||
* a-posteriori using critical bands, 2 is using masking thresholds and 3 is
|
||||
* disabled.
|
||||
*/
|
||||
int noise_scaling_type;
|
||||
|
||||
/* Strength in which the reduction will be applied. It uses the masking
|
||||
* thresholds of the signal to determine where in the spectrum the reduction
|
||||
* needs to be stronger. This parameter scales how much in each of the
|
||||
* frequencies the reduction is going to be applied. It can be a positive dB
|
||||
* value in between 0 dB and 12 dB */
|
||||
float noise_rescale;
|
||||
|
||||
/* Sets the SNR threshold in dB in which the post-filter will start to blur
|
||||
* musical noise. It can be a positive or negative dB value in between -10 dB
|
||||
* and 10 dB */
|
||||
float post_filter_threshold;
|
||||
} SpectralBleachDenoiserParameters;
|
||||
|
||||
/**
|
||||
* Returns a handle to an instance of the library for the spectral based
|
||||
* noise reduction. Sample rate could be anything from 4000hz to 192khz.
|
||||
* Recommended frame size range is between 20ms and 100ms
|
||||
*/
|
||||
SpectralBleachHandle specbleach_initialize(uint32_t sample_rate,
|
||||
float frame_size);
|
||||
/**
|
||||
* Free instance associated to the handle passed
|
||||
*/
|
||||
void specbleach_free(SpectralBleachHandle instance);
|
||||
/**
|
||||
* Loads the parameters for the reduction.
|
||||
* This has to be called before processing
|
||||
*/
|
||||
bool specbleach_load_parameters(SpectralBleachHandle instance,
|
||||
SpectralBleachDenoiserParameters parameters);
|
||||
/**
|
||||
* Process buffer of a number of samples
|
||||
*/
|
||||
bool specbleach_process(SpectralBleachHandle instance,
|
||||
uint32_t number_of_samples, const float* input,
|
||||
float* output);
|
||||
/**
|
||||
* Returns the latency in samples associated with the library instance
|
||||
*/
|
||||
uint32_t specbleach_get_latency(SpectralBleachHandle instance);
|
||||
/**
|
||||
* Returns the size of the noise profile spectrum
|
||||
*/
|
||||
uint32_t specbleach_get_noise_profile_size(SpectralBleachHandle instance);
|
||||
/**
|
||||
* Returns a pointer to the noise profile calculated inside the instance
|
||||
*/
|
||||
float* specbleach_get_noise_profile(SpectralBleachHandle instance);
|
||||
/**
|
||||
* Allows to load a custom noise profile
|
||||
*/
|
||||
bool specbleach_load_noise_profile(SpectralBleachHandle instance,
|
||||
const float* restored_profile,
|
||||
uint32_t profile_size,
|
||||
uint32_t profile_blocks);
|
||||
/**
|
||||
* Allows to load a custom noise profile for a specific mode
|
||||
*/
|
||||
bool specbleach_load_noise_profile_for_mode(SpectralBleachHandle instance,
|
||||
const float* restored_profile,
|
||||
uint32_t profile_size,
|
||||
uint32_t profile_blocks, int mode);
|
||||
/**
|
||||
* Resets the internal noise profile of the library instance
|
||||
*/
|
||||
bool specbleach_reset_noise_profile(SpectralBleachHandle instance);
|
||||
/**
|
||||
* Returns if the instance has a noise profile calculated internally
|
||||
*/
|
||||
bool specbleach_noise_profile_available(SpectralBleachHandle instance);
|
||||
/**
|
||||
* Returns the number of blocks used for the noise profile calculation
|
||||
*/
|
||||
uint32_t specbleach_get_noise_profile_blocks_averaged(
|
||||
SpectralBleachHandle instance);
|
||||
|
||||
/**
|
||||
* Returns the number of blocks used for the noise profile calculation for a
|
||||
* specific mode
|
||||
*/
|
||||
uint32_t specbleach_get_noise_profile_blocks_averaged_for_mode(
|
||||
SpectralBleachHandle instance, int mode);
|
||||
|
||||
/**
|
||||
* Returns a pointer to the noise profile for a specific mode
|
||||
*/
|
||||
float* specbleach_get_noise_profile_for_mode(SpectralBleachHandle instance,
|
||||
int mode);
|
||||
|
||||
/**
|
||||
* Returns if the instance has a noise profile calculated for a specific mode
|
||||
*/
|
||||
bool specbleach_noise_profile_available_for_mode(SpectralBleachHandle instance,
|
||||
int mode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
BIN
Binary file not shown.
+354
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "adaptive_denoiser.h"
|
||||
#include "shared/configurations.h"
|
||||
#include "shared/gain_estimation/gain_estimators.h"
|
||||
#include "shared/noise_estimation/adaptive_noise_estimator.h"
|
||||
#include "shared/post_estimation/noise_floor_manager.h"
|
||||
#include "shared/post_estimation/postfilter.h"
|
||||
#include "shared/pre_estimation/critical_bands.h"
|
||||
#include "shared/pre_estimation/noise_scaling_criterias.h"
|
||||
#include "shared/pre_estimation/spectral_smoother.h"
|
||||
#include "shared/utils/denoise_mixer.h"
|
||||
#include "shared/utils/spectral_features.h"
|
||||
#include "shared/utils/spectral_utils.h"
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct SpectralAdaptiveDenoiser {
|
||||
uint32_t fft_size;
|
||||
uint32_t real_spectrum_size;
|
||||
uint32_t sample_rate;
|
||||
uint32_t hop;
|
||||
float default_oversubtraction;
|
||||
float default_undersubtraction;
|
||||
|
||||
AdaptiveDenoiserParameters parameters;
|
||||
|
||||
float* alpha;
|
||||
float* beta;
|
||||
float* gain_spectrum;
|
||||
float* residual_spectrum;
|
||||
float* denoised_spectrum;
|
||||
float* noise_profile;
|
||||
|
||||
SpectrumType spectrum_type;
|
||||
CriticalBandType band_type;
|
||||
GainEstimationType gain_estimation_type;
|
||||
TimeSmoothingType time_smoothing_type;
|
||||
|
||||
DenoiseMixer* mixer;
|
||||
NoiseScalingCriterias* noise_scaling_criteria;
|
||||
SpectralSmoother* spectrum_smoothing;
|
||||
PostFilter* postfiltering;
|
||||
AdaptiveNoiseEstimator* adaptive_estimator;
|
||||
SpectralFeatures* spectral_features;
|
||||
NoiseFloorManager* noise_floor_manager;
|
||||
bool postfiltering_enabled;
|
||||
bool whitening_enabled;
|
||||
} SpectralAdaptiveDenoiser;
|
||||
|
||||
SpectralProcessorHandle spectral_adaptive_denoiser_initialize(
|
||||
const uint32_t sample_rate, const uint32_t fft_size,
|
||||
const uint32_t overlap_factor) {
|
||||
|
||||
if (sample_rate == 0 || fft_size == 0 || overlap_factor == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SpectralAdaptiveDenoiser* self =
|
||||
(SpectralAdaptiveDenoiser*)calloc(1U, sizeof(SpectralAdaptiveDenoiser));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->fft_size = fft_size;
|
||||
self->real_spectrum_size = (self->fft_size / 2U) + 1U;
|
||||
self->sample_rate = sample_rate;
|
||||
self->hop = self->fft_size / overlap_factor;
|
||||
self->default_oversubtraction = DEFAULT_OVERSUBTRACTION;
|
||||
self->default_undersubtraction = DEFAULT_UNDERSUBTRACTION;
|
||||
self->spectrum_type = SPECTRAL_TYPE_SPEECH;
|
||||
self->band_type = CRITICAL_BANDS_TYPE_SPEECH;
|
||||
self->gain_estimation_type = GAIN_ESTIMATION_TYPE_SPEECH;
|
||||
self->time_smoothing_type = TIME_SMOOTHING_TYPE_SPEECH;
|
||||
self->postfiltering_enabled = POSTFILTER_ENABLED_SPEECH;
|
||||
self->whitening_enabled = WHITENING_ENABLED_SPEECH;
|
||||
|
||||
self->gain_spectrum = (float*)calloc(self->fft_size, sizeof(float));
|
||||
if (!self->gain_spectrum) {
|
||||
spectral_adaptive_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
(void)initialize_spectrum_with_value(self->gain_spectrum, self->fft_size,
|
||||
1.F);
|
||||
|
||||
self->alpha = (float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
if (!self->alpha) {
|
||||
spectral_adaptive_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
(void)initialize_spectrum_with_value(self->alpha, self->real_spectrum_size,
|
||||
1.F);
|
||||
|
||||
self->beta = (float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
if (!self->beta) {
|
||||
spectral_adaptive_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->noise_profile = (float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
if (!self->noise_profile) {
|
||||
spectral_adaptive_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->adaptive_estimator = louizou_estimator_initialize(
|
||||
self->real_spectrum_size, sample_rate, fft_size);
|
||||
if (!self->adaptive_estimator) {
|
||||
spectral_adaptive_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->residual_spectrum = (float*)calloc((self->fft_size), sizeof(float));
|
||||
if (!self->residual_spectrum) {
|
||||
spectral_adaptive_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->denoised_spectrum = (float*)calloc((self->fft_size), sizeof(float));
|
||||
if (!self->denoised_spectrum) {
|
||||
spectral_adaptive_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (self->postfiltering_enabled) {
|
||||
self->postfiltering = postfilter_initialize(self->fft_size);
|
||||
if (!self->postfiltering) {
|
||||
spectral_adaptive_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
self->spectrum_smoothing =
|
||||
spectral_smoothing_initialize(self->fft_size, self->time_smoothing_type);
|
||||
if (!self->spectrum_smoothing) {
|
||||
spectral_adaptive_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->noise_scaling_criteria = noise_scaling_criterias_initialize(
|
||||
self->fft_size, self->band_type, self->sample_rate, self->spectrum_type);
|
||||
if (!self->noise_scaling_criteria) {
|
||||
spectral_adaptive_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->spectral_features =
|
||||
spectral_features_initialize(self->real_spectrum_size);
|
||||
if (!self->spectral_features) {
|
||||
spectral_adaptive_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->mixer =
|
||||
denoise_mixer_initialize(self->fft_size, self->sample_rate, self->hop);
|
||||
if (!self->mixer) {
|
||||
spectral_adaptive_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->noise_floor_manager = noise_floor_manager_initialize(
|
||||
self->fft_size, self->sample_rate, self->hop);
|
||||
if (!self->noise_floor_manager) {
|
||||
spectral_adaptive_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void spectral_adaptive_denoiser_free(SpectralProcessorHandle instance) {
|
||||
SpectralAdaptiveDenoiser* self = (SpectralAdaptiveDenoiser*)instance;
|
||||
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->adaptive_estimator) {
|
||||
if (self->parameters.noise_estimation_method == SPP_MMSE_METHOD) {
|
||||
spp_mmse_estimator_free(self->adaptive_estimator);
|
||||
} else {
|
||||
louizou_estimator_free(self->adaptive_estimator);
|
||||
}
|
||||
}
|
||||
if (self->spectral_features) {
|
||||
spectral_features_free(self->spectral_features);
|
||||
}
|
||||
if (self->noise_scaling_criteria) {
|
||||
noise_scaling_criterias_free(self->noise_scaling_criteria);
|
||||
}
|
||||
if (self->spectrum_smoothing) {
|
||||
spectral_smoothing_free(self->spectrum_smoothing);
|
||||
}
|
||||
if (self->postfiltering) {
|
||||
postfilter_free(self->postfiltering);
|
||||
}
|
||||
if (self->mixer) {
|
||||
denoise_mixer_free(self->mixer);
|
||||
}
|
||||
if (self->residual_spectrum) {
|
||||
free(self->residual_spectrum);
|
||||
}
|
||||
|
||||
if (self->noise_floor_manager) {
|
||||
noise_floor_manager_free(self->noise_floor_manager);
|
||||
}
|
||||
if (self->denoised_spectrum) {
|
||||
free(self->denoised_spectrum);
|
||||
}
|
||||
if (self->noise_profile) {
|
||||
free(self->noise_profile);
|
||||
}
|
||||
if (self->gain_spectrum) {
|
||||
free(self->gain_spectrum);
|
||||
}
|
||||
if (self->alpha) {
|
||||
free(self->alpha);
|
||||
}
|
||||
if (self->beta) {
|
||||
free(self->beta);
|
||||
}
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
bool load_adaptive_reduction_parameters(SpectralProcessorHandle instance,
|
||||
AdaptiveDenoiserParameters parameters) {
|
||||
if (!instance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SpectralAdaptiveDenoiser* self = (SpectralAdaptiveDenoiser*)instance;
|
||||
|
||||
// Check if noise estimation method has changed
|
||||
bool method_changed = (self->parameters.noise_estimation_method !=
|
||||
parameters.noise_estimation_method);
|
||||
|
||||
self->parameters = parameters;
|
||||
|
||||
// If method changed, reinitialize the adaptive estimator
|
||||
if (method_changed && self->adaptive_estimator) {
|
||||
louizou_estimator_free(self->adaptive_estimator);
|
||||
self->adaptive_estimator = NULL;
|
||||
|
||||
// Initialize the appropriate estimator based on the method
|
||||
if (self->parameters.noise_estimation_method == SPP_MMSE_METHOD) {
|
||||
self->adaptive_estimator = spp_mmse_estimator_initialize(
|
||||
self->real_spectrum_size, self->sample_rate, self->fft_size);
|
||||
} else {
|
||||
// Default to Louizou method
|
||||
self->adaptive_estimator = louizou_estimator_initialize(
|
||||
self->real_spectrum_size, self->sample_rate, self->fft_size);
|
||||
}
|
||||
|
||||
if (!self->adaptive_estimator) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool spectral_adaptive_denoiser_run(SpectralProcessorHandle instance,
|
||||
float* fft_spectrum) {
|
||||
if (!fft_spectrum || !instance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SpectralAdaptiveDenoiser* self = (SpectralAdaptiveDenoiser*)instance;
|
||||
|
||||
float* reference_spectrum =
|
||||
get_spectral_feature(self->spectral_features, fft_spectrum,
|
||||
self->fft_size, self->spectrum_type);
|
||||
|
||||
// Estimate noise using the selected method
|
||||
if (self->parameters.noise_estimation_method == SPP_MMSE_METHOD) {
|
||||
spp_mmse_estimator_run(self->adaptive_estimator, reference_spectrum,
|
||||
self->noise_profile);
|
||||
} else {
|
||||
// Default to Louizou method
|
||||
louizou_estimator_run(self->adaptive_estimator, reference_spectrum,
|
||||
self->noise_profile);
|
||||
}
|
||||
|
||||
float whitening_factor =
|
||||
self->whitening_enabled ? self->parameters.whitening_factor : 0.0f;
|
||||
|
||||
// Scale estimated noise profile for oversubtraction
|
||||
NoiseScalingParameters oversubtraction_parameters = (NoiseScalingParameters){
|
||||
.oversubtraction =
|
||||
self->default_oversubtraction + self->parameters.noise_rescale,
|
||||
.undersubtraction = self->parameters.reduction_amount,
|
||||
.scaling_type = self->parameters.noise_scaling_type,
|
||||
};
|
||||
apply_noise_scaling_criteria(self->noise_scaling_criteria, reference_spectrum,
|
||||
self->noise_profile, self->alpha, self->beta,
|
||||
oversubtraction_parameters);
|
||||
|
||||
TimeSmoothingParameters spectral_smoothing_parameters =
|
||||
(TimeSmoothingParameters){
|
||||
.smoothing = self->parameters.smoothing_factor,
|
||||
};
|
||||
spectral_smoothing_run(self->spectrum_smoothing,
|
||||
spectral_smoothing_parameters, reference_spectrum);
|
||||
|
||||
estimate_gains(self->real_spectrum_size, self->fft_size, reference_spectrum,
|
||||
self->noise_profile, self->gain_spectrum, self->alpha,
|
||||
self->beta, self->gain_estimation_type);
|
||||
|
||||
noise_floor_manager_apply(
|
||||
self->noise_floor_manager, self->real_spectrum_size, self->fft_size,
|
||||
self->gain_spectrum, self->noise_profile,
|
||||
self->parameters.reduction_amount, whitening_factor);
|
||||
|
||||
if (self->postfiltering_enabled) {
|
||||
PostFiltersParameters post_filter_parameters = (PostFiltersParameters){
|
||||
.snr_threshold = self->parameters.post_filter_threshold,
|
||||
.gain_floor = self->parameters.reduction_amount,
|
||||
};
|
||||
postfilter_apply(self->postfiltering, fft_spectrum, self->gain_spectrum,
|
||||
post_filter_parameters);
|
||||
}
|
||||
|
||||
DenoiseMixerParameters mixer_parameters = (DenoiseMixerParameters){
|
||||
.noise_level = self->parameters.reduction_amount,
|
||||
.residual_listen = self->parameters.residual_listen,
|
||||
.whitening_amount = whitening_factor,
|
||||
};
|
||||
|
||||
denoise_mixer_run(self->mixer, fft_spectrum, self->gain_spectrum,
|
||||
mixer_parameters);
|
||||
|
||||
return true;
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef SPECTRAL_ADAPTIVE_DENOISER_H
|
||||
#define SPECTRAL_ADAPTIVE_DENOISER_H
|
||||
|
||||
#include "shared/spectral_processor.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "shared/noise_estimation/adaptive_noise_estimator.h"
|
||||
|
||||
typedef struct AdaptiveDenoiserParameters {
|
||||
float reduction_amount;
|
||||
int noise_scaling_type;
|
||||
float noise_rescale;
|
||||
float smoothing_factor;
|
||||
float whitening_factor;
|
||||
float post_filter_threshold;
|
||||
bool residual_listen;
|
||||
|
||||
/* Method used for adaptive noise estimation.
|
||||
* LOUIZOU_METHOD uses minimum statistics (default), SPP_MMSE_METHOD uses
|
||||
* Speech Presence Probability with MMSE estimation for lower complexity
|
||||
* and unbiased noise tracking. */
|
||||
AdaptiveNoiseEstimationMethod noise_estimation_method;
|
||||
} AdaptiveDenoiserParameters;
|
||||
|
||||
SpectralProcessorHandle spectral_adaptive_denoiser_initialize(
|
||||
uint32_t sample_rate, uint32_t fft_size, uint32_t overlap_factor);
|
||||
void spectral_adaptive_denoiser_free(SpectralProcessorHandle instance);
|
||||
bool load_adaptive_reduction_parameters(SpectralProcessorHandle instance,
|
||||
AdaptiveDenoiserParameters parameters);
|
||||
bool spectral_adaptive_denoiser_run(SpectralProcessorHandle instance,
|
||||
float* fft_spectrum);
|
||||
|
||||
#endif
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "spectral_denoiser.h"
|
||||
#include "shared/configurations.h"
|
||||
#include "shared/gain_estimation/gain_estimators.h"
|
||||
#include "shared/noise_estimation/noise_estimator.h"
|
||||
#include "shared/post_estimation/noise_floor_manager.h"
|
||||
#include "shared/post_estimation/postfilter.h"
|
||||
#include "shared/pre_estimation/critical_bands.h"
|
||||
#include "shared/pre_estimation/noise_scaling_criterias.h"
|
||||
#include "shared/pre_estimation/spectral_smoother.h"
|
||||
#include "shared/utils/denoise_mixer.h"
|
||||
#include "shared/utils/spectral_features.h"
|
||||
#include "shared/utils/spectral_utils.h"
|
||||
#include <float.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct SbSpectralDenoiser {
|
||||
uint32_t fft_size;
|
||||
uint32_t real_spectrum_size;
|
||||
uint32_t sample_rate;
|
||||
uint32_t hop;
|
||||
float default_oversubtraction;
|
||||
float default_undersubtraction;
|
||||
|
||||
float* gain_spectrum;
|
||||
float* alpha;
|
||||
float* beta;
|
||||
float* noise_spectrum;
|
||||
|
||||
SpectrumType spectrum_type;
|
||||
CriticalBandType band_type;
|
||||
DenoiserParameters denoise_parameters;
|
||||
GainEstimationType gain_estimation_type;
|
||||
TimeSmoothingType time_smoothing_type;
|
||||
NoiseEstimatorType noise_estimator_type;
|
||||
|
||||
NoiseEstimator* noise_estimator;
|
||||
PostFilter* postfiltering;
|
||||
NoiseProfile* noise_profile;
|
||||
SpectralFeatures* spectral_features;
|
||||
DenoiseMixer* mixer;
|
||||
NoiseScalingCriterias* noise_scaling_criteria;
|
||||
SpectralSmoother* spectrum_smoothing;
|
||||
NoiseFloorManager* noise_floor_manager;
|
||||
bool postfiltering_enabled;
|
||||
bool whitening_enabled;
|
||||
} SbSpectralDenoiser;
|
||||
|
||||
SpectralProcessorHandle spectral_denoiser_initialize(
|
||||
const uint32_t sample_rate, const uint32_t fft_size,
|
||||
const uint32_t overlap_factor, NoiseProfile* noise_profile) {
|
||||
|
||||
if (!noise_profile || sample_rate == 0 || fft_size == 0 ||
|
||||
overlap_factor == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SbSpectralDenoiser* self =
|
||||
(SbSpectralDenoiser*)calloc(1U, sizeof(SbSpectralDenoiser));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->fft_size = fft_size;
|
||||
self->real_spectrum_size = (self->fft_size / 2U) + 1U;
|
||||
self->hop = self->fft_size / overlap_factor;
|
||||
self->sample_rate = sample_rate;
|
||||
self->spectrum_type = SPECTRAL_TYPE_GENERAL;
|
||||
self->band_type = CRITICAL_BANDS_TYPE;
|
||||
self->default_oversubtraction = DEFAULT_OVERSUBTRACTION;
|
||||
self->default_undersubtraction = DEFAULT_UNDERSUBTRACTION;
|
||||
self->gain_estimation_type = GAIN_ESTIMATION_TYPE;
|
||||
self->time_smoothing_type = TIME_SMOOTHING_TYPE;
|
||||
self->postfiltering_enabled = POSTFILTER_ENABLED_GENERAL;
|
||||
self->whitening_enabled = WHITENING_ENABLED_GENERAL;
|
||||
|
||||
self->gain_spectrum = (float*)calloc(self->fft_size, sizeof(float));
|
||||
if (!self->gain_spectrum) {
|
||||
spectral_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
(void)initialize_spectrum_with_value(self->gain_spectrum, self->fft_size,
|
||||
1.F);
|
||||
|
||||
self->alpha = (float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
if (!self->alpha) {
|
||||
spectral_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
(void)initialize_spectrum_with_value(self->alpha, self->real_spectrum_size,
|
||||
1.F);
|
||||
|
||||
self->beta = (float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
if (!self->beta) {
|
||||
spectral_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->noise_profile = noise_profile;
|
||||
self->noise_spectrum =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
if (!self->noise_spectrum) {
|
||||
spectral_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->noise_estimator =
|
||||
noise_estimation_initialize(self->fft_size, noise_profile);
|
||||
if (!self->noise_estimator) {
|
||||
spectral_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->spectral_features =
|
||||
spectral_features_initialize(self->real_spectrum_size);
|
||||
if (!self->spectral_features) {
|
||||
spectral_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (self->postfiltering_enabled) {
|
||||
self->postfiltering = postfilter_initialize(self->fft_size);
|
||||
if (!self->postfiltering) {
|
||||
spectral_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
self->spectrum_smoothing =
|
||||
spectral_smoothing_initialize(self->fft_size, self->time_smoothing_type);
|
||||
if (!self->spectrum_smoothing) {
|
||||
spectral_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->noise_scaling_criteria = noise_scaling_criterias_initialize(
|
||||
self->fft_size, self->band_type, self->sample_rate, self->spectrum_type);
|
||||
if (!self->noise_scaling_criteria) {
|
||||
spectral_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->mixer =
|
||||
denoise_mixer_initialize(self->fft_size, self->sample_rate, self->hop);
|
||||
if (!self->mixer) {
|
||||
spectral_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->noise_floor_manager = noise_floor_manager_initialize(
|
||||
self->fft_size, self->sample_rate, self->hop);
|
||||
if (!self->noise_floor_manager) {
|
||||
spectral_denoiser_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void spectral_denoiser_free(SpectralProcessorHandle instance) {
|
||||
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
|
||||
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't free noise profile used as reference here
|
||||
|
||||
if (self->noise_estimator) {
|
||||
noise_estimation_free(self->noise_estimator);
|
||||
}
|
||||
if (self->spectral_features) {
|
||||
spectral_features_free(self->spectral_features);
|
||||
}
|
||||
if (self->spectrum_smoothing) {
|
||||
spectral_smoothing_free(self->spectrum_smoothing);
|
||||
}
|
||||
if (self->noise_scaling_criteria) {
|
||||
noise_scaling_criterias_free(self->noise_scaling_criteria);
|
||||
}
|
||||
if (self->postfiltering) {
|
||||
postfilter_free(self->postfiltering);
|
||||
}
|
||||
if (self->mixer) {
|
||||
denoise_mixer_free(self->mixer);
|
||||
}
|
||||
if (self->gain_spectrum) {
|
||||
free(self->gain_spectrum);
|
||||
}
|
||||
|
||||
if (self->noise_floor_manager) {
|
||||
noise_floor_manager_free(self->noise_floor_manager);
|
||||
}
|
||||
if (self->alpha) {
|
||||
free(self->alpha);
|
||||
}
|
||||
if (self->beta) {
|
||||
free(self->beta);
|
||||
}
|
||||
if (self->noise_spectrum) {
|
||||
free(self->noise_spectrum);
|
||||
}
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
bool load_reduction_parameters(SpectralProcessorHandle instance,
|
||||
DenoiserParameters parameters) {
|
||||
if (!instance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
|
||||
self->denoise_parameters = parameters;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool spectral_denoiser_run(SpectralProcessorHandle instance,
|
||||
float* fft_spectrum) {
|
||||
if (!fft_spectrum || !instance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
|
||||
|
||||
float* reference_spectrum =
|
||||
get_spectral_feature(self->spectral_features, fft_spectrum,
|
||||
self->fft_size, self->spectrum_type);
|
||||
|
||||
if (self->denoise_parameters.learn_noise > 0) {
|
||||
// Learn all modes simultaneously
|
||||
for (int mode = ROLLING_MEAN; mode <= MAX; mode++) {
|
||||
noise_estimation_run(self->noise_estimator, (NoiseEstimatorType)mode,
|
||||
reference_spectrum);
|
||||
}
|
||||
} else if (is_noise_estimation_available(
|
||||
self->noise_profile,
|
||||
self->denoise_parameters.noise_reduction_mode)) {
|
||||
memcpy(self->noise_spectrum,
|
||||
get_noise_profile(self->noise_profile,
|
||||
self->denoise_parameters.noise_reduction_mode),
|
||||
self->real_spectrum_size * sizeof(float));
|
||||
|
||||
NoiseScalingParameters oversubtraction_parameters =
|
||||
(NoiseScalingParameters){
|
||||
.oversubtraction = (self->default_oversubtraction +
|
||||
self->denoise_parameters.noise_rescale),
|
||||
.undersubtraction = self->denoise_parameters.reduction_amount,
|
||||
.scaling_type = self->denoise_parameters.noise_scaling_type,
|
||||
};
|
||||
|
||||
float whitening_factor = self->whitening_enabled
|
||||
? self->denoise_parameters.whitening_factor
|
||||
: 0.0f;
|
||||
|
||||
apply_noise_scaling_criteria(
|
||||
self->noise_scaling_criteria, reference_spectrum, self->noise_spectrum,
|
||||
self->alpha, self->beta, oversubtraction_parameters);
|
||||
|
||||
TimeSmoothingParameters spectral_smoothing_parameters =
|
||||
(TimeSmoothingParameters){
|
||||
.smoothing = self->denoise_parameters.smoothing_factor,
|
||||
};
|
||||
spectral_smoothing_run(self->spectrum_smoothing,
|
||||
spectral_smoothing_parameters, reference_spectrum);
|
||||
|
||||
estimate_gains(self->real_spectrum_size, self->fft_size, reference_spectrum,
|
||||
self->noise_spectrum, self->gain_spectrum, self->alpha,
|
||||
self->beta, self->gain_estimation_type);
|
||||
|
||||
noise_floor_manager_apply(
|
||||
self->noise_floor_manager, self->real_spectrum_size, self->fft_size,
|
||||
self->gain_spectrum, self->noise_spectrum,
|
||||
self->denoise_parameters.reduction_amount, whitening_factor);
|
||||
|
||||
if (self->postfiltering_enabled) {
|
||||
PostFiltersParameters post_filter_parameters = (PostFiltersParameters){
|
||||
.snr_threshold = self->denoise_parameters.post_filter_threshold,
|
||||
.gain_floor = self->denoise_parameters.reduction_amount,
|
||||
};
|
||||
postfilter_apply(self->postfiltering, fft_spectrum, self->gain_spectrum,
|
||||
post_filter_parameters);
|
||||
}
|
||||
|
||||
DenoiseMixerParameters mixer_parameters = (DenoiseMixerParameters){
|
||||
.noise_level = self->denoise_parameters.reduction_amount,
|
||||
.residual_listen = self->denoise_parameters.residual_listen,
|
||||
.whitening_amount = whitening_factor,
|
||||
};
|
||||
|
||||
denoise_mixer_run(self->mixer, fft_spectrum, self->gain_spectrum,
|
||||
mixer_parameters);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef SPECTRAL_DENOISER_H
|
||||
#define SPECTRAL_DENOISER_H
|
||||
|
||||
#include "shared/noise_estimation/noise_profile.h"
|
||||
#include "shared/spectral_processor.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct DenoiserParameters {
|
||||
float reduction_amount;
|
||||
int noise_scaling_type;
|
||||
float noise_rescale;
|
||||
bool residual_listen;
|
||||
int learn_noise;
|
||||
int noise_reduction_mode;
|
||||
float smoothing_factor;
|
||||
float whitening_factor;
|
||||
float post_filter_threshold;
|
||||
} DenoiserParameters;
|
||||
|
||||
SpectralProcessorHandle spectral_denoiser_initialize(
|
||||
uint32_t sample_rate, uint32_t fft_size, uint32_t overlap_factor,
|
||||
NoiseProfile* noise_profile);
|
||||
void spectral_denoiser_free(SpectralProcessorHandle instance);
|
||||
bool load_reduction_parameters(SpectralProcessorHandle instance,
|
||||
DenoiserParameters parameters);
|
||||
bool spectral_denoiser_run(SpectralProcessorHandle instance,
|
||||
float* fft_spectrum);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
processors_sources = files(
|
||||
'denoiser/spectral_denoiser.c',
|
||||
'adaptivedenoiser/adaptive_denoiser.c',
|
||||
'specbleach_adenoiser.c',
|
||||
'specbleach_denoiser.c',
|
||||
)
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "specbleach_adenoiser.h"
|
||||
#include "adaptivedenoiser/adaptive_denoiser.h"
|
||||
#include "shared/configurations.h"
|
||||
#include "shared/stft/stft_processor.h"
|
||||
#include "shared/utils/general_utils.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct SbAdaptiveDenoiser {
|
||||
uint32_t sample_rate;
|
||||
AdaptiveDenoiserParameters denoise_parameters;
|
||||
|
||||
SpectralProcessorHandle adaptive_spectral_denoiser;
|
||||
StftProcessor* stft_processor;
|
||||
} SbAdaptiveDenoiser;
|
||||
|
||||
SpectralBleachHandle specbleach_adaptive_initialize(const uint32_t sample_rate,
|
||||
float frame_size) {
|
||||
SbAdaptiveDenoiser* self =
|
||||
(SbAdaptiveDenoiser*)calloc(1U, sizeof(SbAdaptiveDenoiser));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->sample_rate = sample_rate;
|
||||
|
||||
self->stft_processor = stft_processor_initialize(
|
||||
sample_rate, frame_size, OVERLAP_FACTOR_SPEECH,
|
||||
PADDING_CONFIGURATION_SPEECH, ZEROPADDING_AMOUNT_SPEECH,
|
||||
INPUT_WINDOW_TYPE_SPEECH, OUTPUT_WINDOW_TYPE_SPEECH);
|
||||
|
||||
if (!self->stft_processor) {
|
||||
specbleach_adaptive_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const uint32_t fft_size = get_stft_fft_size(self->stft_processor);
|
||||
|
||||
self->adaptive_spectral_denoiser = spectral_adaptive_denoiser_initialize(
|
||||
self->sample_rate, fft_size, OVERLAP_FACTOR_SPEECH);
|
||||
|
||||
if (!self->adaptive_spectral_denoiser) {
|
||||
specbleach_adaptive_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void specbleach_adaptive_free(SpectralBleachHandle instance) {
|
||||
SbAdaptiveDenoiser* self = (SbAdaptiveDenoiser*)instance;
|
||||
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->adaptive_spectral_denoiser) {
|
||||
spectral_adaptive_denoiser_free(self->adaptive_spectral_denoiser);
|
||||
}
|
||||
if (self->stft_processor) {
|
||||
stft_processor_free(self->stft_processor);
|
||||
}
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
uint32_t specbleach_adaptive_get_latency(SpectralBleachHandle instance) {
|
||||
SbAdaptiveDenoiser* self = (SbAdaptiveDenoiser*)instance;
|
||||
|
||||
return get_stft_latency(self->stft_processor);
|
||||
}
|
||||
|
||||
bool specbleach_adaptive_process(SpectralBleachHandle instance,
|
||||
const uint32_t number_of_samples,
|
||||
const float* input, float* output) {
|
||||
if (!instance || number_of_samples == 0 || !input || !output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SbAdaptiveDenoiser* self = (SbAdaptiveDenoiser*)instance;
|
||||
|
||||
stft_processor_run(self->stft_processor, number_of_samples, input, output,
|
||||
&spectral_adaptive_denoiser_run,
|
||||
self->adaptive_spectral_denoiser);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool specbleach_adaptive_load_parameters(
|
||||
SpectralBleachHandle instance,
|
||||
SpectralBleachAdaptiveParameters parameters) {
|
||||
if (!instance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SbAdaptiveDenoiser* self = (SbAdaptiveDenoiser*)instance;
|
||||
|
||||
// clang-format off
|
||||
self->denoise_parameters = (AdaptiveDenoiserParameters){
|
||||
.residual_listen = parameters.residual_listen,
|
||||
.reduction_amount =
|
||||
from_db_to_coefficient(parameters.reduction_amount * -1.F),
|
||||
.noise_rescale = from_db_to_coefficient(parameters.noise_rescale),
|
||||
.noise_scaling_type = parameters.noise_scaling_type,
|
||||
.smoothing_factor = remap_percentage_log_like_unity(parameters.smoothing_factor / 100.F),
|
||||
.whitening_factor = parameters.whitening_factor / 100.F,
|
||||
.post_filter_threshold = from_db_to_coefficient(parameters.post_filter_threshold),
|
||||
.noise_estimation_method = parameters.noise_estimation_method,
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
load_adaptive_reduction_parameters(self->adaptive_spectral_denoiser,
|
||||
self->denoise_parameters);
|
||||
|
||||
return true;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "specbleach_denoiser.h"
|
||||
#include "denoiser/spectral_denoiser.h"
|
||||
#include "shared/configurations.h"
|
||||
#include "shared/noise_estimation/noise_profile.h"
|
||||
#include "shared/stft/stft_processor.h"
|
||||
#include "shared/utils/general_utils.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct SbSpectralDenoiser {
|
||||
uint32_t sample_rate;
|
||||
DenoiserParameters denoise_parameters;
|
||||
|
||||
NoiseProfile* noise_profile;
|
||||
SpectralProcessorHandle spectral_denoiser;
|
||||
StftProcessor* stft_processor;
|
||||
} SbSpectralDenoiser;
|
||||
|
||||
SpectralBleachHandle specbleach_initialize(const uint32_t sample_rate,
|
||||
float frame_size) {
|
||||
if (sample_rate < 4000 || sample_rate > 192000 || frame_size <= 0.0f) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SbSpectralDenoiser* self =
|
||||
(SbSpectralDenoiser*)calloc(1U, sizeof(SbSpectralDenoiser));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->sample_rate = sample_rate;
|
||||
|
||||
self->stft_processor = stft_processor_initialize(
|
||||
sample_rate, frame_size, OVERLAP_FACTOR_GENERAL,
|
||||
PADDING_CONFIGURATION_GENERAL, ZEROPADDING_AMOUNT_GENERAL,
|
||||
INPUT_WINDOW_TYPE_GENERAL, OUTPUT_WINDOW_TYPE_GENERAL);
|
||||
|
||||
if (!self->stft_processor) {
|
||||
specbleach_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const uint32_t fft_size = get_stft_fft_size(self->stft_processor);
|
||||
const uint32_t real_spectrum_size =
|
||||
get_stft_real_spectrum_size(self->stft_processor);
|
||||
|
||||
self->noise_profile = noise_profile_initialize(real_spectrum_size);
|
||||
|
||||
if (!self->noise_profile) {
|
||||
specbleach_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->spectral_denoiser = spectral_denoiser_initialize(
|
||||
self->sample_rate, fft_size, OVERLAP_FACTOR_GENERAL, self->noise_profile);
|
||||
|
||||
if (!self->spectral_denoiser) {
|
||||
specbleach_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void specbleach_free(SpectralBleachHandle instance) {
|
||||
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
|
||||
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->noise_profile) {
|
||||
noise_profile_free(self->noise_profile);
|
||||
}
|
||||
if (self->spectral_denoiser) {
|
||||
spectral_denoiser_free(self->spectral_denoiser);
|
||||
}
|
||||
if (self->stft_processor) {
|
||||
stft_processor_free(self->stft_processor);
|
||||
}
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
uint32_t specbleach_get_latency(SpectralBleachHandle instance) {
|
||||
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
|
||||
|
||||
if (!self || !self->stft_processor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return get_stft_latency(self->stft_processor);
|
||||
}
|
||||
|
||||
bool specbleach_process(SpectralBleachHandle instance,
|
||||
const uint32_t number_of_samples, const float* input,
|
||||
float* output) {
|
||||
if (!instance || number_of_samples == 0 || !input || !output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
|
||||
|
||||
stft_processor_run(self->stft_processor, number_of_samples, input, output,
|
||||
&spectral_denoiser_run, self->spectral_denoiser);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t specbleach_get_noise_profile_size(SpectralBleachHandle instance) {
|
||||
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
|
||||
|
||||
if (!self || !self->noise_profile) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return get_noise_profile_size(self->noise_profile);
|
||||
}
|
||||
|
||||
uint32_t specbleach_get_noise_profile_blocks_averaged(
|
||||
SpectralBleachHandle instance) {
|
||||
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
|
||||
|
||||
if (!self || !self->noise_profile) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return get_noise_profile_blocks_averaged(
|
||||
self->noise_profile, self->denoise_parameters.noise_reduction_mode);
|
||||
}
|
||||
|
||||
float* specbleach_get_noise_profile(SpectralBleachHandle instance) {
|
||||
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
|
||||
|
||||
if (!self || !self->noise_profile) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return get_noise_profile(self->noise_profile,
|
||||
self->denoise_parameters.noise_reduction_mode);
|
||||
}
|
||||
|
||||
bool specbleach_load_noise_profile(SpectralBleachHandle instance,
|
||||
const float* restored_profile,
|
||||
const uint32_t profile_size,
|
||||
const uint32_t averaged_blocks) {
|
||||
if (!instance || !restored_profile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
|
||||
|
||||
if (profile_size != get_noise_profile_size(self->noise_profile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
set_noise_profile(self->noise_profile,
|
||||
self->denoise_parameters.noise_reduction_mode,
|
||||
restored_profile, profile_size, averaged_blocks);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool specbleach_load_noise_profile_for_mode(SpectralBleachHandle instance,
|
||||
const float* restored_profile,
|
||||
const uint32_t profile_size,
|
||||
const uint32_t averaged_blocks,
|
||||
const int mode) {
|
||||
if (!instance || !restored_profile || mode < 1 || mode > 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
|
||||
|
||||
if (profile_size != get_noise_profile_size(self->noise_profile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
set_noise_profile(self->noise_profile, mode, restored_profile, profile_size,
|
||||
averaged_blocks);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool specbleach_reset_noise_profile(SpectralBleachHandle instance) {
|
||||
if (!instance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
|
||||
|
||||
reset_noise_profile(self->noise_profile);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool specbleach_noise_profile_available(SpectralBleachHandle instance) {
|
||||
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
|
||||
|
||||
return is_noise_estimation_available(
|
||||
self->noise_profile, self->denoise_parameters.noise_reduction_mode);
|
||||
}
|
||||
|
||||
uint32_t specbleach_get_noise_profile_blocks_averaged_for_mode(
|
||||
SpectralBleachHandle instance, int mode) {
|
||||
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
|
||||
if (!self || mode < 1 || mode > 3) {
|
||||
return 0;
|
||||
}
|
||||
return get_noise_profile_blocks_averaged(self->noise_profile, mode);
|
||||
}
|
||||
|
||||
float* specbleach_get_noise_profile_for_mode(SpectralBleachHandle instance,
|
||||
int mode) {
|
||||
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
|
||||
if (!self || mode < 1 || mode > 3) {
|
||||
return NULL;
|
||||
}
|
||||
return get_noise_profile(self->noise_profile, mode);
|
||||
}
|
||||
|
||||
bool specbleach_noise_profile_available_for_mode(SpectralBleachHandle instance,
|
||||
int mode) {
|
||||
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
|
||||
if (!self || mode < 1 || mode > 3) {
|
||||
return false;
|
||||
}
|
||||
return is_noise_estimation_available(self->noise_profile, mode);
|
||||
}
|
||||
|
||||
bool specbleach_load_parameters(SpectralBleachHandle instance,
|
||||
SpectralBleachDenoiserParameters parameters) {
|
||||
if (!instance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
|
||||
|
||||
// clang-format off
|
||||
self->denoise_parameters = (DenoiserParameters){
|
||||
.learn_noise = parameters.learn_noise,
|
||||
.noise_reduction_mode = parameters.noise_reduction_mode,
|
||||
.residual_listen = parameters.residual_listen,
|
||||
.noise_scaling_type = parameters.noise_scaling_type,
|
||||
.reduction_amount =
|
||||
from_db_to_coefficient(parameters.reduction_amount * -1.F),
|
||||
.noise_rescale = from_db_to_coefficient(parameters.noise_rescale),
|
||||
.smoothing_factor = remap_percentage_log_like_unity(parameters.smoothing_factor / 100.F),
|
||||
.whitening_factor = parameters.whitening_factor / 100.F,
|
||||
.post_filter_threshold = from_db_to_coefficient(parameters.post_filter_threshold),
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
load_reduction_parameters(self->spectral_denoiser, self->denoise_parameters);
|
||||
|
||||
return true;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef MODULES_CONFIGURATIONS_H
|
||||
#define MODULES_CONFIGURATIONS_H
|
||||
|
||||
#include "utils/spectral_utils.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Compile-time assertions for configuration validity
|
||||
_Static_assert(HANN_WINDOW >= 0 && HANN_WINDOW <= 3,
|
||||
"HANN_WINDOW must be between 0 and 3");
|
||||
_Static_assert(HAMMING_WINDOW >= 0 && HAMMING_WINDOW <= 3,
|
||||
"HAMMING_WINDOW must be between 0 and 3");
|
||||
_Static_assert(BLACKMAN_WINDOW >= 0 && BLACKMAN_WINDOW <= 3,
|
||||
"BLACKMAN_WINDOW must be between 0 and 3");
|
||||
_Static_assert(VORBIS_WINDOW >= 0 && VORBIS_WINDOW <= 3,
|
||||
"VORBIS_WINDOW must be between 0 and 3");
|
||||
|
||||
// Additional C17 compile-time validations
|
||||
_Static_assert(sizeof(uint32_t) == 4, "uint32_t must be exactly 32 bits");
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI (3.14159265358979323846)
|
||||
#endif
|
||||
|
||||
#ifndef M_PIf
|
||||
#define M_PIf (3.14159265358979323846F)
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* ------------------- Shared Modules configurations ------------------- */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
// Absolute hearing thresholds
|
||||
#define REFERENCE_SINE_WAVE_FREQ (1000.F)
|
||||
#define REFERENCE_LEVEL (90.F)
|
||||
#define SINE_AMPLITUDE (1.F)
|
||||
|
||||
// Spectral Whitening
|
||||
#define WHITENING_DECAY_RATE (1000.F)
|
||||
#define WHITENING_FLOOR (0.01F)
|
||||
|
||||
// Masking Thresholds
|
||||
#define BIAS false
|
||||
#define HIGH_FREQ_BIAS 20.F
|
||||
#if BIAS
|
||||
// clang-format off
|
||||
#define relative_thresholds \
|
||||
(float[25]){-16.F, -17.F, -18.F, -19.F, -20.F, -21.F, -22.F, -23.F, -24.F, \
|
||||
-25.F, -25.F, -25.F, -25.F, -25.F, -25.F, -24.F, -23.F, -22.F, \
|
||||
-19.F, -18.F, -18.F, -18.F, -18.F, -18.F, -18.F}
|
||||
// clang-format on
|
||||
#endif
|
||||
|
||||
// Postfilter SNR Threshold
|
||||
#define POSTFILTER_SCALE (10.0F)
|
||||
#define PRESERVE_MINIMUN_GAIN (true)
|
||||
#define POSTFILTER_MIN_GAIN_DB (-15.0F)
|
||||
|
||||
// Gain Estimators
|
||||
#define GSS_EXPONENT \
|
||||
2.0F // 2 Power Subtraction / 1 Magnitude Subtraxtion / 0.5 Spectral
|
||||
// Subtraction
|
||||
|
||||
// Oversubtraction criteria
|
||||
#define ALPHA_MAX (6.F)
|
||||
#define ALPHA_MIN (1.F)
|
||||
#define BETA_MAX (0.01F)
|
||||
#define BETA_MIN (0.F)
|
||||
#define DEFAULT_OVERSUBTRACTION (ALPHA_MIN)
|
||||
#define DEFAULT_UNDERSUBTRACTION (BETA_MAX)
|
||||
#define LOWER_SNR (0.F)
|
||||
#define HIGHER_SNR (20.F)
|
||||
|
||||
// Adaptive Estimator
|
||||
#define N_SMOOTH (0.7F)
|
||||
#define BETA_AT (0.8F)
|
||||
#define GAMMA (0.998F)
|
||||
#define ALPHA_P (0.2F)
|
||||
#define ALPHA_D (0.85F)
|
||||
|
||||
#define CROSSOVER_POINT1 (1000.F)
|
||||
#define CROSSOVER_POINT2 (3000.F)
|
||||
#define BAND_1_LEVEL (2.F)
|
||||
#define BAND_2_LEVEL (2.F)
|
||||
#define BAND_3_LEVEL (5.F)
|
||||
|
||||
// SPP-MMSE Estimator Constants
|
||||
#define SPP_PRIOR_H1 (0.5F) // P(H1) - Speech present prior
|
||||
#define SPP_PRIOR_H0 (0.5F) // P(H0) - Speech absent prior
|
||||
#define SPP_FIXED_XI_H1 (31.62F) // Fixed a priori SNR (15 dB in linear)
|
||||
#define SPP_ALPHA_POW (0.8F) // Power spectrum smoothing factor
|
||||
#define SPP_SMOOTH_SPP (0.9F) // SPP smoothing for stagnation control
|
||||
#define SPP_CURRENT_SPP (0.1F) // Current SPP weighting for stagnation control
|
||||
#define SPP_STAGNATION_CAP (0.99F) // Maximum SPP value to prevent locking
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
/* ------------------- Denoiser configurations ------------------- */
|
||||
/* --------------------------------------------------------------- */
|
||||
|
||||
// STFT configurations - Frame size in milliseconds
|
||||
#define OVERLAP_FACTOR_GENERAL 4
|
||||
#define INPUT_WINDOW_TYPE_GENERAL HANN_WINDOW
|
||||
#define OUTPUT_WINDOW_TYPE_GENERAL HANN_WINDOW
|
||||
|
||||
// Fft configuration
|
||||
#define PADDING_CONFIGURATION_GENERAL NO_PADDING
|
||||
#define ZEROPADDING_AMOUNT_GENERAL 50 // Even Number
|
||||
|
||||
// Spectral Type
|
||||
#define SPECTRAL_TYPE_GENERAL POWER_SPECTRUM
|
||||
|
||||
// Transient protection
|
||||
#define UPPER_LIMIT (5.F)
|
||||
#define DEFAULT_TRANSIENT_THRESHOLD (2.F)
|
||||
|
||||
// Masking
|
||||
#define CRITICAL_BANDS_TYPE OPUS_SCALE
|
||||
|
||||
// Noise Estimator
|
||||
#define MIN_NUMBER_OF_WINDOWS_NOISE_AVERAGED 5
|
||||
#define NUMBER_OF_MEDIAN_SPECTRUM 5
|
||||
|
||||
// Noise Scaling strategy
|
||||
#define NOISE_SCALING_TYPE_GENERAL MASKING_THRESHOLDS
|
||||
#define GAIN_ESTIMATION_TYPE WIENER
|
||||
|
||||
// Time Smoothing
|
||||
#define TIME_SMOOTHING_TYPE FIXED
|
||||
|
||||
// Postfilter
|
||||
#define POSTFILTER_ENABLED_GENERAL true
|
||||
|
||||
// Whitening
|
||||
#define WHITENING_ENABLED_GENERAL true
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* ------------------- Adaptive Denoiser configurations ------------------- */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
// STFT configurations - Frame size in milliseconds
|
||||
#define OVERLAP_FACTOR_SPEECH 2
|
||||
#define INPUT_WINDOW_TYPE_SPEECH VORBIS_WINDOW
|
||||
#define OUTPUT_WINDOW_TYPE_SPEECH VORBIS_WINDOW
|
||||
|
||||
// Fft configurations
|
||||
#define PADDING_CONFIGURATION_SPEECH NO_PADDING
|
||||
#define ZEROPADDING_AMOUNT_SPEECH 50 // Even Number
|
||||
|
||||
// Spectral Type
|
||||
#define SPECTRAL_TYPE_SPEECH POWER_SPECTRUM
|
||||
|
||||
// Masking
|
||||
#define CRITICAL_BANDS_TYPE_SPEECH OPUS_SCALE
|
||||
|
||||
// Noise Scaling strategy
|
||||
#define NOISE_SCALING_TYPE_SPEECH MASKING_THRESHOLDS
|
||||
#define GAIN_ESTIMATION_TYPE_SPEECH WIENER
|
||||
|
||||
// Time Smoothing
|
||||
#define TIME_SMOOTHING_TYPE_SPEECH FIXED
|
||||
|
||||
// Postfilter
|
||||
#define POSTFILTER_ENABLED_SPEECH true
|
||||
|
||||
// Whitening
|
||||
#define WHITENING_ENABLED_SPEECH true
|
||||
|
||||
#endif // ifndef
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "gain_estimators.h"
|
||||
#include "../configurations.h"
|
||||
#include "../utils/general_utils.h"
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stddef.h>
|
||||
|
||||
static void wiener_subtraction(const uint32_t real_spectrum_size,
|
||||
const uint32_t fft_size, const float* spectrum,
|
||||
const float* noise_spectrum,
|
||||
float* gain_spectrum) {
|
||||
for (uint32_t k = 0U; k < real_spectrum_size; k++) {
|
||||
if (noise_spectrum[k] > FLT_MIN) {
|
||||
if (spectrum[k] > noise_spectrum[k]) {
|
||||
gain_spectrum[k] = (spectrum[k] - (noise_spectrum[k])) / spectrum[k];
|
||||
} else {
|
||||
gain_spectrum[k] = 0.F;
|
||||
}
|
||||
} else {
|
||||
gain_spectrum[k] = 1.F;
|
||||
}
|
||||
|
||||
if (k > 0U && k < (fft_size - k)) {
|
||||
gain_spectrum[fft_size - k] = gain_spectrum[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void spectral_gating(const uint32_t real_spectrum_size,
|
||||
const uint32_t fft_size, const float* spectrum,
|
||||
const float* noise_spectrum, float* gain_spectrum) {
|
||||
for (uint32_t k = 0U; k < real_spectrum_size; k++) {
|
||||
if (noise_spectrum[k] > FLT_MIN) {
|
||||
if (spectrum[k] >= noise_spectrum[k]) {
|
||||
gain_spectrum[k] = 1.F;
|
||||
} else {
|
||||
gain_spectrum[k] = 0.F;
|
||||
}
|
||||
} else {
|
||||
gain_spectrum[k] = 1.F;
|
||||
}
|
||||
|
||||
if (k > 0U && k < (fft_size - k)) {
|
||||
gain_spectrum[fft_size - k] = gain_spectrum[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void generalized_spectral_subtraction(
|
||||
const uint32_t real_spectrum_size, const uint32_t fft_size,
|
||||
const float* spectrum, const float* noise_spectrum, float* gain_spectrum,
|
||||
const float* alpha, const float* beta) {
|
||||
for (uint32_t k = 0U; k < real_spectrum_size; k++) {
|
||||
if (spectrum[k] > FLT_MIN) {
|
||||
if (powf((noise_spectrum[k] / spectrum[k]), GSS_EXPONENT) <
|
||||
(1.F / (alpha[k] + beta[k]))) {
|
||||
gain_spectrum[k] =
|
||||
fmaxf(powf(1.F - (alpha[k] * powf((noise_spectrum[k] / spectrum[k]),
|
||||
GSS_EXPONENT)),
|
||||
1.F / GSS_EXPONENT),
|
||||
0.F);
|
||||
} else {
|
||||
gain_spectrum[k] = fmaxf(
|
||||
powf(
|
||||
beta[k] * powf((noise_spectrum[k] / spectrum[k]), GSS_EXPONENT),
|
||||
1.F / GSS_EXPONENT),
|
||||
0.F);
|
||||
}
|
||||
} else {
|
||||
gain_spectrum[k] = 1.F;
|
||||
}
|
||||
|
||||
if (k > 0U && k < (fft_size - k)) {
|
||||
gain_spectrum[fft_size - k] = gain_spectrum[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void scale_noise_profile(uint32_t real_spectrum_size,
|
||||
float* noise_spectrum, const float* alpha) {
|
||||
for (uint32_t k = 0U; k < real_spectrum_size; k++) {
|
||||
noise_spectrum[k] *= alpha[k];
|
||||
}
|
||||
}
|
||||
|
||||
void estimate_gains(uint32_t real_spectrum_size, uint32_t fft_size,
|
||||
const float* spectrum, float* noise_spectrum,
|
||||
float* gain_spectrum, const float* alpha, const float* beta,
|
||||
GainEstimationType type) {
|
||||
switch (type) {
|
||||
case GATES:
|
||||
scale_noise_profile(real_spectrum_size, noise_spectrum, alpha);
|
||||
spectral_gating(real_spectrum_size, fft_size, spectrum, noise_spectrum,
|
||||
gain_spectrum);
|
||||
break;
|
||||
case WIENER:
|
||||
scale_noise_profile(real_spectrum_size, noise_spectrum, alpha);
|
||||
wiener_subtraction(real_spectrum_size, fft_size, spectrum, noise_spectrum,
|
||||
gain_spectrum);
|
||||
break;
|
||||
case GENERALIZED_SPECTRALSUBTRACION:
|
||||
generalized_spectral_subtraction(real_spectrum_size, fft_size, spectrum,
|
||||
noise_spectrum, gain_spectrum, alpha,
|
||||
beta);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef GAIN_ESTIMATORS_H
|
||||
#define GAIN_ESTIMATORS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum GainEstimationType {
|
||||
WIENER = 0,
|
||||
GATES = 1,
|
||||
GENERALIZED_SPECTRALSUBTRACION = 2,
|
||||
} GainEstimationType;
|
||||
|
||||
void estimate_gains(uint32_t real_spectrum_size, uint32_t fft_size,
|
||||
const float* spectrum, float* noise_spectrum,
|
||||
float* gain_spectrum, const float* alpha, const float* beta,
|
||||
GainEstimationType type);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
shared_sources += files(
|
||||
'gain_estimators.c',
|
||||
)
|
||||
@@ -0,0 +1,7 @@
|
||||
shared_sources = []
|
||||
subdir('gain_estimation')
|
||||
subdir('noise_estimation')
|
||||
subdir('post_estimation')
|
||||
subdir('pre_estimation')
|
||||
subdir('stft')
|
||||
subdir('utils')
|
||||
+401
@@ -0,0 +1,401 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "adaptive_noise_estimator.h"
|
||||
#include "../configurations.h"
|
||||
#include "../utils/general_utils.h"
|
||||
#include "../utils/spectral_utils.h"
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct FrameSpectrum {
|
||||
float* smoothed_spectrum;
|
||||
float* local_minimum_spectrum;
|
||||
float* speech_present_probability_spectrum;
|
||||
} FrameSpectrum;
|
||||
|
||||
static FrameSpectrum* frame_spectrum_initialize(uint32_t frame_size);
|
||||
static void frame_spectrum_free(FrameSpectrum* self);
|
||||
static void compute_auto_thresholds(AdaptiveNoiseEstimator* self,
|
||||
uint32_t sample_rate,
|
||||
uint32_t noise_spectrum_size,
|
||||
uint32_t fft_size);
|
||||
static void update_frame_spectums(AdaptiveNoiseEstimator* self,
|
||||
const float* noise_spectrum);
|
||||
|
||||
// SPP-MMSE helper functions
|
||||
static float compute_spp_probability(float observation_power,
|
||||
float previous_noise_psd);
|
||||
static float compute_mmse_noise_estimate(float spp_h1, float spp_h0,
|
||||
float observation_power,
|
||||
float previous_noise_psd);
|
||||
|
||||
struct AdaptiveNoiseEstimator {
|
||||
uint32_t noise_spectrum_size;
|
||||
float noisy_speech_ratio;
|
||||
|
||||
FrameSpectrum* current;
|
||||
FrameSpectrum* previous;
|
||||
|
||||
float* minimum_detection_thresholds;
|
||||
float* previous_noise_spectrum;
|
||||
float* time_frequency_smoothing_constant;
|
||||
uint32_t* speech_presence_detection;
|
||||
bool is_first_frame;
|
||||
|
||||
// SPP-MMSE specific fields (optional, used when SPP method is selected)
|
||||
float* spp_previous_noise_psd; // Previous noise PSD estimate
|
||||
float* spp_smoothed_spp; // Smoothed SPP for stagnation control
|
||||
};
|
||||
|
||||
// SPP-MMSE helper function implementations
|
||||
static float compute_spp_probability(float observation_power,
|
||||
float previous_noise_psd) {
|
||||
// Avoid division by zero and ensure numerical stability
|
||||
if (previous_noise_psd < 1e-12F) {
|
||||
previous_noise_psd = 1e-12F;
|
||||
}
|
||||
|
||||
// Compute the exponent: -(|y|^2 / σ_N²(l-1)) * (ξ_H1 / (1 + ξ_H1))
|
||||
float ratio = observation_power / previous_noise_psd;
|
||||
float exponent = -ratio * (SPP_FIXED_XI_H1 / (1.F + SPP_FIXED_XI_H1));
|
||||
|
||||
// Compute exp(exponent) with numerical stability check
|
||||
float exp_term = expf(exponent);
|
||||
if (!isfinite(exp_term)) {
|
||||
exp_term = (exponent > 0.F) ? FLT_MAX : 0.F;
|
||||
}
|
||||
|
||||
// Compute the ratio: P(H0)/P(H1) * (1 + ξ_H1) * exp(...)
|
||||
// Since P(H0) = P(H1) = 0.5, P(H0)/P(H1) = 1
|
||||
float denominator_ratio = (1.F + SPP_FIXED_XI_H1) * exp_term;
|
||||
|
||||
// Compute SPP: 1 / (1 + denominator_ratio)
|
||||
float spp = 1.F / (1.F + denominator_ratio);
|
||||
|
||||
// Ensure SPP is in valid range [0, 1]
|
||||
spp = fmaxf(0.F, fminf(1.F, spp));
|
||||
|
||||
return spp;
|
||||
}
|
||||
|
||||
static float compute_mmse_noise_estimate(float spp_h1, float spp_h0,
|
||||
float observation_power,
|
||||
float previous_noise_psd) {
|
||||
// MMSE estimate: E{|N|²|y} = P(H0|y) * |y|² + P(H1|y) * σ_N²(l-1)
|
||||
return (spp_h0 * observation_power) + (spp_h1 * previous_noise_psd);
|
||||
}
|
||||
|
||||
AdaptiveNoiseEstimator* louizou_estimator_initialize(
|
||||
const uint32_t noise_spectrum_size, const uint32_t sample_rate,
|
||||
const uint32_t fft_size) {
|
||||
AdaptiveNoiseEstimator* self =
|
||||
(AdaptiveNoiseEstimator*)calloc(1U, sizeof(AdaptiveNoiseEstimator));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->noise_spectrum_size = noise_spectrum_size;
|
||||
|
||||
self->minimum_detection_thresholds =
|
||||
(float*)calloc(self->noise_spectrum_size, sizeof(float));
|
||||
self->time_frequency_smoothing_constant =
|
||||
(float*)calloc(self->noise_spectrum_size, sizeof(float));
|
||||
self->speech_presence_detection =
|
||||
(uint32_t*)calloc(self->noise_spectrum_size, sizeof(uint32_t));
|
||||
self->previous_noise_spectrum =
|
||||
(float*)calloc(self->noise_spectrum_size, sizeof(float));
|
||||
self->spp_previous_noise_psd =
|
||||
(float*)calloc(self->noise_spectrum_size, sizeof(float));
|
||||
self->spp_smoothed_spp =
|
||||
(float*)calloc(self->noise_spectrum_size, sizeof(float));
|
||||
|
||||
if (!self->minimum_detection_thresholds ||
|
||||
!self->time_frequency_smoothing_constant ||
|
||||
!self->speech_presence_detection || !self->previous_noise_spectrum ||
|
||||
!self->spp_previous_noise_psd || !self->spp_smoothed_spp) {
|
||||
louizou_estimator_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
compute_auto_thresholds(self, sample_rate, noise_spectrum_size, fft_size);
|
||||
self->current = frame_spectrum_initialize(noise_spectrum_size);
|
||||
self->previous = frame_spectrum_initialize(noise_spectrum_size);
|
||||
|
||||
if (!self->current || !self->previous) {
|
||||
louizou_estimator_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->noisy_speech_ratio = 0.F;
|
||||
self->is_first_frame = true;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
AdaptiveNoiseEstimator* spp_mmse_estimator_initialize(
|
||||
const uint32_t noise_spectrum_size, const uint32_t sample_rate,
|
||||
const uint32_t fft_size) {
|
||||
AdaptiveNoiseEstimator* self =
|
||||
(AdaptiveNoiseEstimator*)calloc(1U, sizeof(AdaptiveNoiseEstimator));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->noise_spectrum_size = noise_spectrum_size;
|
||||
|
||||
self->minimum_detection_thresholds =
|
||||
(float*)calloc(self->noise_spectrum_size, sizeof(float));
|
||||
self->time_frequency_smoothing_constant =
|
||||
(float*)calloc(self->noise_spectrum_size, sizeof(float));
|
||||
self->speech_presence_detection =
|
||||
(uint32_t*)calloc(self->noise_spectrum_size, sizeof(uint32_t));
|
||||
self->previous_noise_spectrum =
|
||||
(float*)calloc(self->noise_spectrum_size, sizeof(float));
|
||||
self->spp_previous_noise_psd =
|
||||
(float*)calloc(self->noise_spectrum_size, sizeof(float));
|
||||
self->spp_smoothed_spp =
|
||||
(float*)calloc(self->noise_spectrum_size, sizeof(float));
|
||||
|
||||
if (!self->minimum_detection_thresholds ||
|
||||
!self->time_frequency_smoothing_constant ||
|
||||
!self->speech_presence_detection || !self->previous_noise_spectrum ||
|
||||
!self->spp_previous_noise_psd || !self->spp_smoothed_spp) {
|
||||
spp_mmse_estimator_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
compute_auto_thresholds(self, sample_rate, noise_spectrum_size, fft_size);
|
||||
self->current = frame_spectrum_initialize(noise_spectrum_size);
|
||||
self->previous = frame_spectrum_initialize(noise_spectrum_size);
|
||||
|
||||
if (!self->current || !self->previous) {
|
||||
spp_mmse_estimator_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->noisy_speech_ratio = 0.F;
|
||||
self->is_first_frame = true;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void spp_mmse_estimator_free(AdaptiveNoiseEstimator* self) {
|
||||
louizou_estimator_free(self); // Reuse the same cleanup logic
|
||||
}
|
||||
|
||||
void louizou_estimator_free(AdaptiveNoiseEstimator* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
free(self->minimum_detection_thresholds);
|
||||
free(self->time_frequency_smoothing_constant);
|
||||
free(self->speech_presence_detection);
|
||||
free(self->previous_noise_spectrum);
|
||||
free(self->spp_previous_noise_psd);
|
||||
free(self->spp_smoothed_spp);
|
||||
|
||||
frame_spectrum_free(self->current);
|
||||
frame_spectrum_free(self->previous);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
bool louizou_estimator_run(AdaptiveNoiseEstimator* self, const float* spectrum,
|
||||
float* noise_spectrum) {
|
||||
if (!self || !spectrum || !noise_spectrum) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self->is_first_frame) {
|
||||
for (uint32_t k = 0U; k < self->noise_spectrum_size; k++) {
|
||||
self->current->smoothed_spectrum[k] = spectrum[k];
|
||||
self->current->local_minimum_spectrum[k] = spectrum[k];
|
||||
noise_spectrum[k] = spectrum[k];
|
||||
}
|
||||
self->is_first_frame = false;
|
||||
} else {
|
||||
for (uint32_t k = 0U; k < self->noise_spectrum_size; k++) {
|
||||
self->current->smoothed_spectrum[k] =
|
||||
(N_SMOOTH * self->previous->smoothed_spectrum[k]) +
|
||||
((1.F - N_SMOOTH) * spectrum[k]);
|
||||
|
||||
if (self->previous->local_minimum_spectrum[k] <
|
||||
self->current->smoothed_spectrum[k]) {
|
||||
self->current->local_minimum_spectrum[k] =
|
||||
(GAMMA * self->previous->local_minimum_spectrum[k]) +
|
||||
(((1.F - GAMMA) / (1.F - BETA_AT)) *
|
||||
(self->current->smoothed_spectrum[k] -
|
||||
(BETA_AT * self->previous->smoothed_spectrum[k])));
|
||||
} else {
|
||||
self->current->local_minimum_spectrum[k] =
|
||||
self->current->smoothed_spectrum[k];
|
||||
}
|
||||
|
||||
self->noisy_speech_ratio = sanitize_denormal(
|
||||
self->current->smoothed_spectrum[k] /
|
||||
(self->current->local_minimum_spectrum[k] + 1e-12F));
|
||||
|
||||
if (self->noisy_speech_ratio > self->minimum_detection_thresholds[k]) {
|
||||
self->speech_presence_detection[k] = 1U;
|
||||
} else {
|
||||
self->speech_presence_detection[k] = 0U;
|
||||
}
|
||||
|
||||
self->current->speech_present_probability_spectrum[k] =
|
||||
(ALPHA_P * self->previous->speech_present_probability_spectrum[k]) +
|
||||
((1.F - ALPHA_P) * (float)self->speech_presence_detection[k]);
|
||||
|
||||
self->time_frequency_smoothing_constant[k] =
|
||||
ALPHA_D + ((1.F - ALPHA_D) *
|
||||
self->current->speech_present_probability_spectrum[k]);
|
||||
|
||||
noise_spectrum[k] =
|
||||
(self->time_frequency_smoothing_constant[k] *
|
||||
self->previous_noise_spectrum[k]) +
|
||||
((1.F - self->time_frequency_smoothing_constant[k]) * spectrum[k]);
|
||||
}
|
||||
}
|
||||
|
||||
update_frame_spectums(self, noise_spectrum);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool spp_mmse_estimator_run(AdaptiveNoiseEstimator* self, const float* spectrum,
|
||||
float* noise_spectrum) {
|
||||
if (!self || !spectrum || !noise_spectrum) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self->is_first_frame) {
|
||||
// Initialize with first frame (assume noise-only)
|
||||
for (uint32_t k = 0U; k < self->noise_spectrum_size; k++) {
|
||||
self->spp_previous_noise_psd[k] = spectrum[k];
|
||||
self->spp_smoothed_spp[k] = 0.F; // Initialize smoothed SPP to 0
|
||||
noise_spectrum[k] = spectrum[k];
|
||||
}
|
||||
self->is_first_frame = false;
|
||||
} else {
|
||||
for (uint32_t k = 0U; k < self->noise_spectrum_size; k++) {
|
||||
// Step 1: Compute A Posteriori Speech Presence Probability
|
||||
float spp_h1 =
|
||||
compute_spp_probability(spectrum[k], self->spp_previous_noise_psd[k]);
|
||||
|
||||
// Step 2: Apply stagnation control
|
||||
// If smoothed SPP > 0.99, cap current SPP at 0.99 to allow noise update
|
||||
if (self->spp_smoothed_spp[k] > SPP_STAGNATION_CAP) {
|
||||
spp_h1 = fminf(spp_h1, SPP_STAGNATION_CAP);
|
||||
}
|
||||
float spp_h0 = 1.F - spp_h1;
|
||||
|
||||
// Step 3: Compute MMSE noise periodogram estimate
|
||||
float mmse_noise_estimate = compute_mmse_noise_estimate(
|
||||
spp_h1, spp_h0, spectrum[k], self->spp_previous_noise_psd[k]);
|
||||
|
||||
// Step 4: Temporal smoothing
|
||||
// σ_N²(l) = α_pow * σ_N²(l-1) + (1 - α_pow) * E{|N|²|y}
|
||||
noise_spectrum[k] = (SPP_ALPHA_POW * self->spp_previous_noise_psd[k]) +
|
||||
((1.F - SPP_ALPHA_POW) * mmse_noise_estimate);
|
||||
|
||||
// Step 5: Update smoothed SPP for next frame's stagnation control
|
||||
// P̄(l) = 0.9 * P̄(l-1) + 0.1 * P(H1|y)
|
||||
self->spp_smoothed_spp[k] = (SPP_SMOOTH_SPP * self->spp_smoothed_spp[k]) +
|
||||
(SPP_CURRENT_SPP * spp_h1);
|
||||
|
||||
// Step 6: Store current noise estimate for next frame
|
||||
self->spp_previous_noise_psd[k] = noise_spectrum[k];
|
||||
}
|
||||
}
|
||||
|
||||
// Update frame spectrums (reuse existing infrastructure for compatibility)
|
||||
update_frame_spectums(self, noise_spectrum);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void update_frame_spectums(AdaptiveNoiseEstimator* self,
|
||||
const float* noise_spectrum) {
|
||||
memcpy(self->previous_noise_spectrum, noise_spectrum,
|
||||
sizeof(float) * self->noise_spectrum_size);
|
||||
memcpy(self->previous->local_minimum_spectrum,
|
||||
self->current->local_minimum_spectrum,
|
||||
sizeof(float) * self->noise_spectrum_size);
|
||||
memcpy(self->previous->smoothed_spectrum, self->current->smoothed_spectrum,
|
||||
sizeof(float) * self->noise_spectrum_size);
|
||||
memcpy(self->previous->speech_present_probability_spectrum,
|
||||
self->current->speech_present_probability_spectrum,
|
||||
sizeof(float) * self->noise_spectrum_size);
|
||||
}
|
||||
|
||||
static FrameSpectrum* frame_spectrum_initialize(const uint32_t frame_size) {
|
||||
FrameSpectrum* self = (FrameSpectrum*)calloc(1U, sizeof(FrameSpectrum));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->smoothed_spectrum = (float*)calloc(frame_size, sizeof(float));
|
||||
self->local_minimum_spectrum = (float*)calloc(frame_size, sizeof(float));
|
||||
self->speech_present_probability_spectrum =
|
||||
(float*)calloc(frame_size, sizeof(float));
|
||||
|
||||
if (!self->smoothed_spectrum || !self->local_minimum_spectrum ||
|
||||
!self->speech_present_probability_spectrum) {
|
||||
frame_spectrum_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(void)initialize_spectrum_with_value(self->local_minimum_spectrum, frame_size,
|
||||
FLT_MIN);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static void frame_spectrum_free(FrameSpectrum* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
free(self->smoothed_spectrum);
|
||||
free(self->local_minimum_spectrum);
|
||||
free(self->speech_present_probability_spectrum);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
static void compute_auto_thresholds(AdaptiveNoiseEstimator* self,
|
||||
const uint32_t sample_rate,
|
||||
const uint32_t noise_spectrum_size,
|
||||
const uint32_t fft_size) {
|
||||
uint32_t lf = freq_to_fft_bin(CROSSOVER_POINT1, sample_rate, fft_size);
|
||||
uint32_t mf = freq_to_fft_bin(CROSSOVER_POINT2, sample_rate, fft_size);
|
||||
for (uint32_t k = 0U; k < noise_spectrum_size; k++) {
|
||||
if (k <= lf) {
|
||||
self->minimum_detection_thresholds[k] = BAND_1_LEVEL;
|
||||
}
|
||||
if (k > lf && k < mf) {
|
||||
self->minimum_detection_thresholds[k] = BAND_2_LEVEL;
|
||||
}
|
||||
if (k >= mf) {
|
||||
self->minimum_detection_thresholds[k] = BAND_3_LEVEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef ADAPTIVE_NOISE_ESTIMATOR_H
|
||||
#define ADAPTIVE_NOISE_ESTIMATOR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum AdaptiveNoiseEstimationMethod {
|
||||
LOUIZOU_METHOD = 0, // Original minimum statistics method (default)
|
||||
SPP_MMSE_METHOD = 1, // Speech Presence Probability - MMSE method
|
||||
} AdaptiveNoiseEstimationMethod;
|
||||
|
||||
typedef struct AdaptiveNoiseEstimator AdaptiveNoiseEstimator;
|
||||
|
||||
AdaptiveNoiseEstimator* louizou_estimator_initialize(
|
||||
uint32_t noise_spectrum_size, uint32_t sample_rate, uint32_t fft_size);
|
||||
void louizou_estimator_free(AdaptiveNoiseEstimator* self);
|
||||
bool louizou_estimator_run(AdaptiveNoiseEstimator* self, const float* spectrum,
|
||||
float* noise_spectrum);
|
||||
|
||||
// SPP-MMSE based adaptive noise estimator (Real-Time Unbiased MMSE Noise PSD
|
||||
// Tracking)
|
||||
AdaptiveNoiseEstimator* spp_mmse_estimator_initialize(
|
||||
uint32_t noise_spectrum_size, uint32_t sample_rate, uint32_t fft_size);
|
||||
void spp_mmse_estimator_free(AdaptiveNoiseEstimator* self);
|
||||
bool spp_mmse_estimator_run(AdaptiveNoiseEstimator* self, const float* spectrum,
|
||||
float* noise_spectrum);
|
||||
|
||||
#endif
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
shared_sources += files(
|
||||
'adaptive_noise_estimator.c',
|
||||
'noise_estimator.c',
|
||||
'noise_profile.c',
|
||||
)
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "noise_estimator.h"
|
||||
#include "../configurations.h"
|
||||
#include "../utils/spectral_trailing_buffer.h"
|
||||
#include "../utils/spectral_utils.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct NoiseEstimator {
|
||||
uint32_t fft_size;
|
||||
uint32_t real_spectrum_size;
|
||||
SpectralTrailingBuffer* median_buffer;
|
||||
|
||||
NoiseProfile* noise_profile;
|
||||
};
|
||||
|
||||
NoiseEstimator* noise_estimation_initialize(const uint32_t fft_size,
|
||||
NoiseProfile* noise_profile) {
|
||||
NoiseEstimator* self = (NoiseEstimator*)calloc(1U, sizeof(NoiseEstimator));
|
||||
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->fft_size = fft_size;
|
||||
self->real_spectrum_size = (self->fft_size / 2U) + 1U;
|
||||
|
||||
self->noise_profile = noise_profile;
|
||||
self->median_buffer = spectral_trailing_buffer_initialize(
|
||||
self->real_spectrum_size, NUMBER_OF_MEDIAN_SPECTRUM);
|
||||
|
||||
if (!self->median_buffer) {
|
||||
noise_estimation_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void noise_estimation_free(NoiseEstimator* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't free noise profile used as reference here
|
||||
|
||||
spectral_trailing_buffer_free(self->median_buffer);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
bool noise_estimation_run(NoiseEstimator* self,
|
||||
const NoiseEstimatorType noise_estimator_type,
|
||||
float* signal_spectrum) {
|
||||
if (!self || !signal_spectrum) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float* noise_profile =
|
||||
get_noise_profile(self->noise_profile, noise_estimator_type);
|
||||
|
||||
switch (noise_estimator_type) {
|
||||
case ROLLING_MEAN:
|
||||
get_rolling_mean_spectrum(noise_profile, signal_spectrum,
|
||||
get_noise_profile_blocks_averaged(
|
||||
self->noise_profile, noise_estimator_type),
|
||||
self->real_spectrum_size);
|
||||
increment_blocks_averaged(self->noise_profile, noise_estimator_type);
|
||||
break;
|
||||
case MEDIAN:
|
||||
spectral_trailing_buffer_push_back(self->median_buffer, signal_spectrum);
|
||||
bool is_valid_median = get_rolling_median_spectrum(
|
||||
noise_profile, get_trailing_spectral_buffer(self->median_buffer),
|
||||
get_spectrum_buffer_size(self->median_buffer),
|
||||
get_spectrum_size(self->median_buffer));
|
||||
if (is_valid_median) {
|
||||
set_noise_profile_available(self->noise_profile, noise_estimator_type);
|
||||
}
|
||||
break;
|
||||
case MAX:
|
||||
(void)max_spectrum(noise_profile, signal_spectrum,
|
||||
self->real_spectrum_size);
|
||||
set_noise_profile_available(self->noise_profile, noise_estimator_type);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef NOISE_ESTIMATOR_H
|
||||
#define NOISE_ESTIMATOR_H
|
||||
|
||||
#include "noise_profile.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct NoiseEstimator NoiseEstimator;
|
||||
|
||||
typedef enum NoiseEstimatorType {
|
||||
OFF = 0,
|
||||
ROLLING_MEAN = 1,
|
||||
MEDIAN = 2,
|
||||
MAX = 3,
|
||||
} NoiseEstimatorType;
|
||||
|
||||
NoiseEstimator* noise_estimation_initialize(uint32_t fft_size,
|
||||
NoiseProfile* noise_profile);
|
||||
void noise_estimation_free(NoiseEstimator* self);
|
||||
bool noise_estimation_run(NoiseEstimator* self,
|
||||
NoiseEstimatorType noise_estimator_type,
|
||||
float* signal_spectrum);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "noise_profile.h"
|
||||
#include "../configurations.h"
|
||||
#include "../utils/spectral_utils.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct NoiseProfile {
|
||||
uint32_t noise_profile_size;
|
||||
uint32_t noise_profile_blocks_averaged[NOISE_PROFILE_MODES];
|
||||
float* noise_profiles[NOISE_PROFILE_MODES];
|
||||
bool noise_spectrum_available[NOISE_PROFILE_MODES];
|
||||
};
|
||||
|
||||
NoiseProfile* noise_profile_initialize(const uint32_t size) {
|
||||
NoiseProfile* self = (NoiseProfile*)calloc(1U, sizeof(NoiseProfile));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
self->noise_profile_size = size;
|
||||
|
||||
for (int i = 0; i < NOISE_PROFILE_MODES; i++) {
|
||||
self->noise_profile_blocks_averaged[i] = 0U;
|
||||
self->noise_spectrum_available[i] = false;
|
||||
self->noise_profiles[i] = (float*)calloc(size, sizeof(float));
|
||||
if (!self->noise_profiles[i]) {
|
||||
noise_profile_free(self);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void noise_profile_free(NoiseProfile* self) {
|
||||
if (self) {
|
||||
for (int i = 0; i < NOISE_PROFILE_MODES; i++) {
|
||||
if (self->noise_profiles[i]) {
|
||||
free(self->noise_profiles[i]);
|
||||
}
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_noise_estimation_available(NoiseProfile* self, int mode) {
|
||||
if (mode < 1 || mode > 3) {
|
||||
return false;
|
||||
}
|
||||
return self->noise_spectrum_available[mode - 1];
|
||||
}
|
||||
|
||||
float* get_noise_profile(NoiseProfile* self, int mode) {
|
||||
if (mode < 1 || mode > 3) {
|
||||
return NULL;
|
||||
}
|
||||
return self->noise_profiles[mode - 1];
|
||||
}
|
||||
|
||||
uint32_t get_noise_profile_size(NoiseProfile* self) {
|
||||
return self->noise_profile_size;
|
||||
}
|
||||
|
||||
uint32_t get_noise_profile_blocks_averaged(NoiseProfile* self, int mode) {
|
||||
if (mode < 1 || mode > 3) {
|
||||
return 0;
|
||||
}
|
||||
return self->noise_profile_blocks_averaged[mode - 1];
|
||||
}
|
||||
void set_noise_profile_available(NoiseProfile* self, int mode) {
|
||||
if (mode >= 1 && mode <= 3) {
|
||||
self->noise_spectrum_available[mode - 1] = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool set_noise_profile(NoiseProfile* self, int mode, const float* noise_profile,
|
||||
const uint32_t noise_profile_size,
|
||||
const uint32_t noise_profile_blocks_averaged) {
|
||||
if (!self || mode < 1 || mode > 3 || !noise_profile ||
|
||||
noise_profile_size != self->noise_profile_size) {
|
||||
return false;
|
||||
}
|
||||
int index = mode - 1;
|
||||
memcpy(self->noise_profiles[index], noise_profile,
|
||||
noise_profile_size * sizeof(float));
|
||||
|
||||
self->noise_profile_blocks_averaged[index] = noise_profile_blocks_averaged;
|
||||
self->noise_spectrum_available[index] = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool increment_blocks_averaged(NoiseProfile* self, int mode) {
|
||||
if (!self || mode < 1 || mode > 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = mode - 1;
|
||||
self->noise_profile_blocks_averaged[index]++;
|
||||
|
||||
if (self->noise_profile_blocks_averaged[index] >
|
||||
MIN_NUMBER_OF_WINDOWS_NOISE_AVERAGED &&
|
||||
!self->noise_spectrum_available[index]) {
|
||||
self->noise_spectrum_available[index] = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool reset_noise_profile(NoiseProfile* self) {
|
||||
if (!self) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NOISE_PROFILE_MODES; i++) {
|
||||
(void)initialize_spectrum_with_value(self->noise_profiles[i],
|
||||
self->noise_profile_size, 0.F);
|
||||
self->noise_profile_blocks_averaged[i] = 0U;
|
||||
self->noise_spectrum_available[i] = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef NOISE_PROFILE_H
|
||||
#define NOISE_PROFILE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct NoiseProfile NoiseProfile;
|
||||
|
||||
#define NOISE_PROFILE_MODES \
|
||||
3 // ROLLING_MEAN, MEDIAN, MAX (no OFF storage needed)
|
||||
|
||||
NoiseProfile* noise_profile_initialize(uint32_t size);
|
||||
void noise_profile_free(NoiseProfile* self);
|
||||
float* get_noise_profile(NoiseProfile* self, int mode);
|
||||
uint32_t get_noise_profile_size(NoiseProfile* self);
|
||||
uint32_t get_noise_profile_blocks_averaged(NoiseProfile* self, int mode);
|
||||
bool increment_blocks_averaged(NoiseProfile* self, int mode);
|
||||
bool set_noise_profile(NoiseProfile* self, int mode, const float* noise_profile,
|
||||
uint32_t noise_profile_size, uint32_t averaged_blocks);
|
||||
void set_noise_profile_available(NoiseProfile* self, int mode);
|
||||
bool reset_noise_profile(NoiseProfile* self);
|
||||
bool is_noise_estimation_available(NoiseProfile* self, int mode);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
shared_sources += files(
|
||||
'noise_floor_manager.c',
|
||||
'spectral_whitening.c',
|
||||
'postfilter.c',
|
||||
)
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "noise_floor_manager.h"
|
||||
#include "spectral_whitening.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct NoiseFloorManager {
|
||||
SpectralWhitening* whitening;
|
||||
float* whitening_weights;
|
||||
uint32_t real_spectrum_size;
|
||||
};
|
||||
|
||||
NoiseFloorManager* noise_floor_manager_initialize(const uint32_t fft_size,
|
||||
const uint32_t sample_rate,
|
||||
const uint32_t hop) {
|
||||
NoiseFloorManager* self =
|
||||
(NoiseFloorManager*)calloc(1U, sizeof(NoiseFloorManager));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->real_spectrum_size = (fft_size / 2U) + 1U;
|
||||
|
||||
self->whitening = spectral_whitening_initialize(fft_size);
|
||||
if (!self->whitening) {
|
||||
free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->whitening_weights =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
if (!self->whitening_weights) {
|
||||
spectral_whitening_free(self->whitening);
|
||||
free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void noise_floor_manager_free(NoiseFloorManager* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
if (self->whitening) {
|
||||
spectral_whitening_free(self->whitening);
|
||||
}
|
||||
if (self->whitening_weights) {
|
||||
free(self->whitening_weights);
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
|
||||
void noise_floor_manager_apply(NoiseFloorManager* self,
|
||||
uint32_t real_spectrum_size, uint32_t fft_size,
|
||||
float* gain_spectrum, const float* noise_profile,
|
||||
float reduction_amount, float whitening_factor) {
|
||||
if (!self || !gain_spectrum || !noise_profile) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Calculate whitening weights (including tapering)
|
||||
spectral_whitening_get_weights(self->whitening, whitening_factor,
|
||||
noise_profile, self->whitening_weights);
|
||||
|
||||
// 2. Apply biasing + frequency-dependent floor
|
||||
for (uint32_t k = 0U; k < real_spectrum_size; k++) {
|
||||
float floor = reduction_amount * self->whitening_weights[k];
|
||||
if (floor > 1.0f) {
|
||||
floor = 1.0f;
|
||||
}
|
||||
|
||||
float range = 1.0f - floor;
|
||||
gain_spectrum[k] = floor + (range * gain_spectrum[k]);
|
||||
}
|
||||
|
||||
// 3. Symmetric copy
|
||||
for (uint32_t k = 1U; k < fft_size - k; k++) {
|
||||
gain_spectrum[fft_size - k] = gain_spectrum[k];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef NO_FLOOR_MANAGER_H
|
||||
#define NO_FLOOR_MANAGER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct NoiseFloorManager NoiseFloorManager;
|
||||
|
||||
NoiseFloorManager* noise_floor_manager_initialize(uint32_t fft_size,
|
||||
uint32_t sample_rate,
|
||||
uint32_t hop);
|
||||
|
||||
void noise_floor_manager_free(NoiseFloorManager* self);
|
||||
|
||||
void noise_floor_manager_apply(NoiseFloorManager* self,
|
||||
uint32_t real_spectrum_size, uint32_t fft_size,
|
||||
float* gain_spectrum, const float* noise_profile,
|
||||
float reduction_amount, float whitening_factor);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "postfilter.h"
|
||||
#include "../configurations.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct PostFilter {
|
||||
float* intermediate_gains;
|
||||
|
||||
uint32_t fft_size;
|
||||
uint32_t real_spectrum_size;
|
||||
bool preserve_minimum;
|
||||
float default_postfilter_scale;
|
||||
float min_gain_coefficient;
|
||||
};
|
||||
|
||||
PostFilter* postfilter_initialize(const uint32_t fft_size) {
|
||||
PostFilter* self = (PostFilter*)calloc(1U, sizeof(PostFilter));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->fft_size = fft_size;
|
||||
self->real_spectrum_size = (self->fft_size / 2U) + 1U;
|
||||
self->preserve_minimum = (bool)PRESERVE_MINIMUN_GAIN;
|
||||
self->default_postfilter_scale = POSTFILTER_SCALE;
|
||||
self->min_gain_coefficient = powf(10.F, (float)POSTFILTER_MIN_GAIN_DB / 20.F);
|
||||
|
||||
self->intermediate_gains =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
if (!self->intermediate_gains) {
|
||||
free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void postfilter_free(PostFilter* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
free(self->intermediate_gains);
|
||||
free(self);
|
||||
}
|
||||
|
||||
static uint32_t get_adaptive_window_size(const PostFilter* self,
|
||||
const float* spectrum,
|
||||
const float snr_threshold,
|
||||
const float* gain_spectrum) {
|
||||
float clean_energy = 0.F;
|
||||
float noisy_energy = 0.F;
|
||||
|
||||
for (uint32_t k = 0U; k < self->real_spectrum_size; k++) {
|
||||
const float noisy = spectrum[k];
|
||||
const float clean = noisy * gain_spectrum[k];
|
||||
clean_energy += clean * clean;
|
||||
noisy_energy += noisy * noisy;
|
||||
}
|
||||
|
||||
if (noisy_energy <= 1e-12F) {
|
||||
return 1U;
|
||||
}
|
||||
|
||||
const float zeta = clean_energy / noisy_energy;
|
||||
const float zeta_t = (zeta >= snr_threshold) ? 1.F : zeta;
|
||||
|
||||
if (zeta_t >= 1.F) {
|
||||
return 1U;
|
||||
}
|
||||
|
||||
const float n = (2.F * roundf(self->default_postfilter_scale *
|
||||
(1.F - (zeta_t / snr_threshold)))) +
|
||||
1.F;
|
||||
|
||||
return (uint32_t)n;
|
||||
}
|
||||
|
||||
static void moving_average(const float* in, float* out, uint32_t size,
|
||||
uint32_t n) {
|
||||
if (n <= 1U || n > size) {
|
||||
memcpy(out, in, size * sizeof(float));
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t half = n / 2U;
|
||||
double current_sum = 0.0;
|
||||
|
||||
// Initial window sum (boundary handling: use clamping for start)
|
||||
for (int i = -(int)half; i <= (int)half; i++) {
|
||||
int idx = i;
|
||||
if (idx < 0) {
|
||||
idx = 0;
|
||||
}
|
||||
if (idx >= (int)size) {
|
||||
idx = (int)size - 1;
|
||||
}
|
||||
current_sum += (double)in[idx];
|
||||
}
|
||||
|
||||
for (uint32_t i = 0U; i < size; i++) {
|
||||
out[i] = (float)(current_sum / (double)n);
|
||||
|
||||
if (i + 1U < size) {
|
||||
// Move window: subtract oldest, add newest
|
||||
int old_idx = (int)i - (int)half;
|
||||
int new_idx = (int)i + (int)half + 1;
|
||||
|
||||
if (old_idx < 0) {
|
||||
old_idx = 0;
|
||||
}
|
||||
if (new_idx >= (int)size) {
|
||||
new_idx = (int)size - 1;
|
||||
}
|
||||
|
||||
current_sum -= (double)in[old_idx];
|
||||
current_sum += (double)in[new_idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool postfilter_apply(PostFilter* self, const float* spectrum,
|
||||
float* gain_spectrum,
|
||||
const PostFiltersParameters parameters) {
|
||||
if (!self || !spectrum || !gain_spectrum) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t n = get_adaptive_window_size(
|
||||
self, spectrum, parameters.snr_threshold, gain_spectrum);
|
||||
|
||||
if (n > 1U) {
|
||||
moving_average(gain_spectrum, self->intermediate_gains,
|
||||
self->real_spectrum_size, n);
|
||||
|
||||
if (self->preserve_minimum) {
|
||||
for (uint32_t k = 0U; k < self->real_spectrum_size; k++) {
|
||||
gain_spectrum[k] = fminf(gain_spectrum[k], self->intermediate_gains[k]);
|
||||
}
|
||||
} else {
|
||||
memcpy(gain_spectrum, self->intermediate_gains,
|
||||
self->real_spectrum_size * sizeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
// Apply gain floor
|
||||
for (uint32_t k = 0U; k < self->real_spectrum_size; k++) {
|
||||
if (gain_spectrum[k] < parameters.gain_floor) {
|
||||
gain_spectrum[k] = parameters.gain_floor;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef POSTFILTER_H
|
||||
#define POSTFILTER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct PostFilter PostFilter;
|
||||
|
||||
typedef struct PostFiltersParameters {
|
||||
float snr_threshold;
|
||||
float gain_floor;
|
||||
} PostFiltersParameters;
|
||||
|
||||
PostFilter* postfilter_initialize(uint32_t fft_size);
|
||||
void postfilter_free(PostFilter* self);
|
||||
bool postfilter_apply(PostFilter* self, const float* spectrum,
|
||||
float* gain_spectrum, PostFiltersParameters parameters);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "spectral_whitening.h"
|
||||
#include "../configurations.h"
|
||||
#include "../utils/spectral_utils.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct SpectralWhitening {
|
||||
float* tapering_window;
|
||||
uint32_t fft_size;
|
||||
uint32_t real_spectrum_size;
|
||||
};
|
||||
|
||||
SpectralWhitening* spectral_whitening_initialize(const uint32_t fft_size) {
|
||||
SpectralWhitening* self =
|
||||
(SpectralWhitening*)calloc(1U, sizeof(SpectralWhitening));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->fft_size = fft_size;
|
||||
self->real_spectrum_size = (self->fft_size / 2U) + 1U;
|
||||
|
||||
self->tapering_window =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
if (!self->tapering_window) {
|
||||
free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Pre-calculate Right half of Hamming window for HF tapering
|
||||
uint32_t n_samples = (self->real_spectrum_size * 2U) - 1U;
|
||||
for (uint32_t k = 0U; k < self->real_spectrum_size; k++) {
|
||||
uint32_t n = (k + self->real_spectrum_size) - 1U;
|
||||
self->tapering_window[k] =
|
||||
0.54f - (0.46f * cosf((2.0f * (float)M_PI * (float)n) /
|
||||
(float)(n_samples - 1U)));
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void spectral_whitening_free(SpectralWhitening* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
if (self->tapering_window) {
|
||||
free(self->tapering_window);
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
|
||||
void spectral_whitening_get_weights(SpectralWhitening* self,
|
||||
float whitening_factor,
|
||||
const float* noise_profile,
|
||||
float* weights_out) {
|
||||
if (!self || !weights_out || !noise_profile) {
|
||||
return;
|
||||
}
|
||||
|
||||
float noise_peak = 1e-12f;
|
||||
for (uint32_t k = 0U; k < self->real_spectrum_size; k++) {
|
||||
if (noise_profile[k] > noise_peak) {
|
||||
noise_peak = noise_profile[k];
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t k = 0U; k < self->real_spectrum_size; k++) {
|
||||
float weight = 1.0f;
|
||||
if (whitening_factor > 0.0f && noise_profile[k] > 1e-12f) {
|
||||
// Power-law valley filling
|
||||
weight = powf(noise_peak / noise_profile[k], whitening_factor);
|
||||
}
|
||||
// Weights include tapering
|
||||
weights_out[k] = weight * self->tapering_window[k];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef SPECTRAL_WHITENER_H
|
||||
#define SPECTRAL_WHITENER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct SpectralWhitening SpectralWhitening;
|
||||
|
||||
SpectralWhitening* spectral_whitening_initialize(uint32_t fft_size);
|
||||
|
||||
void spectral_whitening_free(SpectralWhitening* self);
|
||||
|
||||
void spectral_whitening_get_weights(SpectralWhitening* self,
|
||||
float whitening_factor,
|
||||
const float* noise_profile,
|
||||
float* weights_out);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
+165
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "absolute_hearing_thresholds.h"
|
||||
#include "../configurations.h"
|
||||
#include "../stft/fft_transform.h"
|
||||
#include "../utils/spectral_utils.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static void generate_sinewave(AbsoluteHearingThresholds* self);
|
||||
static void compute_spl_reference_spectrum(AbsoluteHearingThresholds* self);
|
||||
static void compute_absolute_thresholds(AbsoluteHearingThresholds* self);
|
||||
|
||||
struct AbsoluteHearingThresholds {
|
||||
float* sinewave;
|
||||
float* window;
|
||||
float* spl_reference_values;
|
||||
float* absolute_thresholds;
|
||||
|
||||
SpectralFeatures* spectral_features;
|
||||
FftTransform* fft_transform;
|
||||
|
||||
SpectrumType spectrum_type;
|
||||
uint32_t fft_size;
|
||||
uint32_t real_spectrum_size;
|
||||
uint32_t sample_rate;
|
||||
float sine_wave_amplitude;
|
||||
float sine_wave_frequency;
|
||||
float reference_level;
|
||||
};
|
||||
|
||||
AbsoluteHearingThresholds* absolute_hearing_thresholds_initialize(
|
||||
const uint32_t sample_rate, const uint32_t fft_size,
|
||||
SpectrumType spectrum_type) {
|
||||
AbsoluteHearingThresholds* self =
|
||||
(AbsoluteHearingThresholds*)calloc(1U, sizeof(AbsoluteHearingThresholds));
|
||||
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->fft_size = fft_size;
|
||||
self->real_spectrum_size = (self->fft_size / 2U) + 1U;
|
||||
self->sample_rate = sample_rate;
|
||||
self->spectrum_type = spectrum_type;
|
||||
self->sine_wave_amplitude = SINE_AMPLITUDE;
|
||||
self->sine_wave_frequency = REFERENCE_SINE_WAVE_FREQ;
|
||||
self->reference_level = REFERENCE_LEVEL;
|
||||
|
||||
self->fft_transform = fft_transform_initialize_bins(self->fft_size);
|
||||
|
||||
self->spl_reference_values =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
|
||||
self->absolute_thresholds =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
|
||||
self->sinewave = (float*)calloc(self->fft_size, sizeof(float));
|
||||
self->window = (float*)calloc(self->fft_size, sizeof(float));
|
||||
|
||||
self->spectral_features =
|
||||
spectral_features_initialize(self->real_spectrum_size);
|
||||
|
||||
if (!self->fft_transform || !self->spl_reference_values ||
|
||||
!self->absolute_thresholds || !self->sinewave || !self->window ||
|
||||
!self->spectral_features) {
|
||||
absolute_hearing_thresholds_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
generate_sinewave(self);
|
||||
(void)get_fft_window(self->window, self->fft_size, VORBIS_WINDOW);
|
||||
compute_spl_reference_spectrum(self);
|
||||
compute_absolute_thresholds(self);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void absolute_hearing_thresholds_free(AbsoluteHearingThresholds* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
fft_transform_free(self->fft_transform);
|
||||
spectral_features_free(self->spectral_features);
|
||||
|
||||
free(self->sinewave);
|
||||
free(self->window);
|
||||
free(self->spl_reference_values);
|
||||
free(self->absolute_thresholds);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
static void generate_sinewave(AbsoluteHearingThresholds* self) {
|
||||
for (uint32_t k = 0U; k < self->fft_size; k++) {
|
||||
self->sinewave[k] =
|
||||
self->sine_wave_amplitude *
|
||||
sinf((2.F * M_PIf * (float)k * self->sine_wave_frequency) /
|
||||
(float)self->sample_rate);
|
||||
}
|
||||
}
|
||||
|
||||
static void compute_spl_reference_spectrum(AbsoluteHearingThresholds* self) {
|
||||
for (uint32_t k = 0U; k < self->fft_size; k++) {
|
||||
get_fft_input_buffer(self->fft_transform)[k] =
|
||||
self->sinewave[k] * self->window[k];
|
||||
}
|
||||
|
||||
compute_forward_fft(self->fft_transform);
|
||||
|
||||
float* reference_spectrum = get_spectral_feature(
|
||||
self->spectral_features, get_fft_output_buffer(self->fft_transform),
|
||||
self->fft_size, self->spectrum_type);
|
||||
|
||||
for (uint32_t k = 0U; k < self->real_spectrum_size; k++) {
|
||||
self->spl_reference_values[k] =
|
||||
self->reference_level - (10.F * log10f(reference_spectrum[k] + 1e-12F));
|
||||
}
|
||||
}
|
||||
|
||||
bool apply_thresholds_as_floor(AbsoluteHearingThresholds* self,
|
||||
float* spectrum) {
|
||||
if (!self || !spectrum) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t k = 0U; k < self->real_spectrum_size; k++) {
|
||||
const float spl_level =
|
||||
(10.F * log10f(spectrum[k] + 1e-12F)) + self->spl_reference_values[k];
|
||||
spectrum[k] =
|
||||
powf(10.F, fmaxf(spl_level, self->absolute_thresholds[k]) / 10.F);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void compute_absolute_thresholds(AbsoluteHearingThresholds* self) {
|
||||
for (uint32_t k = 0U; k < self->real_spectrum_size; k++) {
|
||||
const float frequency =
|
||||
fmaxf(fft_bin_to_freq(k, self->sample_rate, self->fft_size), 20.F);
|
||||
self->absolute_thresholds[k] =
|
||||
(3.64F * powf((frequency / 1000.F), -0.8F)) -
|
||||
(6.5F * expf(-0.6F * powf(((frequency / 1000.F) - 3.3F), 2.F))) +
|
||||
(powf(10.F, -3.F) * powf((frequency / 1000.F), 4.F));
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef ABSOLUTE_HEARING_THRESHOLDS_H
|
||||
#define ABSOLUTE_HEARING_THRESHOLDS_H
|
||||
|
||||
#include "../utils/spectral_features.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct AbsoluteHearingThresholds AbsoluteHearingThresholds;
|
||||
|
||||
AbsoluteHearingThresholds* absolute_hearing_thresholds_initialize(
|
||||
uint32_t sample_rate, uint32_t fft_size, SpectrumType spectrum_type);
|
||||
void absolute_hearing_thresholds_free(AbsoluteHearingThresholds* self);
|
||||
bool apply_thresholds_as_floor(AbsoluteHearingThresholds* self,
|
||||
float* spectrum);
|
||||
|
||||
#endif
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "critical_bands.h"
|
||||
#include "../utils/spectral_utils.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static const float bark_bands[24] = {
|
||||
100.F, 200.F, 300.F, 400.F, 510.F, 630.F, 770.F, 920.F,
|
||||
1080.F, 1270.F, 1480.F, 1720.F, 2000.F, 2320.F, 2700.F, 3150.F,
|
||||
3700.F, 4400.F, 5300.F, 6400.F, 7700.F, 9500.F, 12000.F, 15500.F};
|
||||
static const float opus_bands[20] = {200.F, 400.F, 600.F, 800.F, 1000.F,
|
||||
1200.F, 1400.F, 1600.F, 2000.F, 2400.F,
|
||||
2800.F, 3200.F, 4000.F, 4800.F, 5600.F,
|
||||
6800.F, 8000.F, 9600.F, 12000.F, 15600.F};
|
||||
static const float mel_bands[33] = {
|
||||
250.F, 500.F, 750.F, 1000.F, 1250.F, 1500.F, 1750.F, 2000.F,
|
||||
2250.F, 2500.F, 2750.F, 3000.F, 3250.F, 3500.F, 3750.F, 4000.F,
|
||||
4250.F, 4500.F, 4750.F, 5000.F, 5250.F, 5500.F, 5750.F, 6000.F,
|
||||
6250.F, 6500.F, 6750.F, 7000.F, 7250.F, 7500.F, 7750.F, 8000.F};
|
||||
static const float octave_bands[10] = {31.5F, 63.F, 125.F, 250.F, 500.F,
|
||||
1000.F, 2000.F, 4000.F, 8000.F, 16000.F};
|
||||
|
||||
void set_number_of_bands(CriticalBands* self);
|
||||
static void compute_mapping_spectrum(CriticalBands* self);
|
||||
static void compute_band_indexes(CriticalBands* self);
|
||||
static uint32_t get_last_valid_band_for_samplerate(CriticalBands* self,
|
||||
uint32_t number_of_bands);
|
||||
|
||||
struct CriticalBands {
|
||||
uint32_t* band_delimiter_bins;
|
||||
uint32_t* number_bins_per_band;
|
||||
float* current_critical_bands;
|
||||
|
||||
uint32_t fft_size;
|
||||
uint32_t real_spectrum_size;
|
||||
uint32_t sample_rate;
|
||||
uint32_t number_bands;
|
||||
CriticalBandType type;
|
||||
CriticalBandIndexes band_indexes;
|
||||
};
|
||||
|
||||
CriticalBands* critical_bands_initialize(const uint32_t sample_rate,
|
||||
const uint32_t fft_size,
|
||||
const CriticalBandType type) {
|
||||
|
||||
CriticalBands* self = (CriticalBands*)calloc(1U, sizeof(CriticalBands));
|
||||
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->fft_size = fft_size;
|
||||
self->real_spectrum_size = (fft_size / 2U) + 1U;
|
||||
self->sample_rate = sample_rate;
|
||||
self->type = type;
|
||||
|
||||
compute_mapping_spectrum(self);
|
||||
|
||||
self->band_delimiter_bins =
|
||||
(uint32_t*)calloc(self->number_bands, sizeof(uint32_t));
|
||||
self->number_bins_per_band =
|
||||
(uint32_t*)calloc(self->number_bands, sizeof(uint32_t));
|
||||
|
||||
if (!self->band_delimiter_bins || !self->number_bins_per_band) {
|
||||
critical_bands_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
compute_band_indexes(self);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void critical_bands_free(CriticalBands* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
free(self->band_delimiter_bins);
|
||||
free(self->number_bins_per_band);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
static void compute_band_indexes(CriticalBands* self) {
|
||||
for (uint32_t k = 0U; k < self->number_bands; k++) {
|
||||
|
||||
const uint32_t bin_index =
|
||||
freq_to_fft_bin(self->current_critical_bands[k], self->sample_rate,
|
||||
self->real_spectrum_size);
|
||||
|
||||
if (k == 0) {
|
||||
self->number_bins_per_band[k] = bin_index; // Don't include DC bin
|
||||
self->band_delimiter_bins[k] = bin_index;
|
||||
} else if (k == self->number_bands - 1U) {
|
||||
self->band_delimiter_bins[k] = self->real_spectrum_size;
|
||||
self->number_bins_per_band[k] =
|
||||
self->band_delimiter_bins[k] - self->band_delimiter_bins[k - 1];
|
||||
} else {
|
||||
self->number_bins_per_band[k] =
|
||||
bin_index - self->band_delimiter_bins[k - 1];
|
||||
self->band_delimiter_bins[k] = bin_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void compute_mapping_spectrum(CriticalBands* self) {
|
||||
switch (self->type) {
|
||||
case BARK_SCALE: {
|
||||
self->current_critical_bands = (float*)bark_bands;
|
||||
uint32_t number_of_bark_bands = sizeof(bark_bands) / sizeof(float);
|
||||
self->number_bands =
|
||||
get_last_valid_band_for_samplerate(self, number_of_bark_bands);
|
||||
break;
|
||||
}
|
||||
case MEL_SCALE: {
|
||||
self->current_critical_bands = (float*)mel_bands;
|
||||
uint32_t number_of_mel_bands = sizeof(mel_bands) / sizeof(float);
|
||||
self->number_bands =
|
||||
get_last_valid_band_for_samplerate(self, number_of_mel_bands);
|
||||
break;
|
||||
}
|
||||
case OPUS_SCALE: {
|
||||
self->current_critical_bands = (float*)opus_bands;
|
||||
uint32_t number_of_opus_bands = sizeof(opus_bands) / sizeof(float);
|
||||
self->number_bands =
|
||||
get_last_valid_band_for_samplerate(self, number_of_opus_bands);
|
||||
break;
|
||||
}
|
||||
case OCTAVE_SCALE: {
|
||||
self->current_critical_bands = (float*)octave_bands;
|
||||
uint32_t number_of_octave_bands = sizeof(opus_bands) / sizeof(float);
|
||||
self->number_bands =
|
||||
get_last_valid_band_for_samplerate(self, number_of_octave_bands);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t get_last_valid_band_for_samplerate(CriticalBands* self,
|
||||
uint32_t number_of_bands) {
|
||||
float nyquist_frequency = (float)self->sample_rate / 2.F;
|
||||
uint32_t last_valid_band = 0U;
|
||||
|
||||
for (uint32_t i = 0; i < number_of_bands; i++) {
|
||||
if (self->current_critical_bands[i] < nyquist_frequency) {
|
||||
last_valid_band = i;
|
||||
}
|
||||
}
|
||||
|
||||
return last_valid_band;
|
||||
}
|
||||
bool compute_critical_bands_spectrum(CriticalBands* self, const float* spectrum,
|
||||
float* critical_bands) {
|
||||
if (!self || !spectrum || !critical_bands) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(critical_bands, 0, self->number_bands * sizeof(float));
|
||||
|
||||
for (uint32_t j = 0U; j < self->number_bands; j++) {
|
||||
self->band_indexes = get_band_indexes(self, j);
|
||||
|
||||
for (uint32_t k = self->band_indexes.start_position;
|
||||
k < self->band_indexes.end_position; k++) {
|
||||
critical_bands[j] += spectrum[k];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CriticalBandIndexes get_band_indexes(CriticalBands* self,
|
||||
const uint32_t band_number) {
|
||||
return (CriticalBandIndexes){
|
||||
.start_position = self->band_delimiter_bins[band_number] -
|
||||
self->number_bins_per_band[band_number],
|
||||
.end_position = self->band_delimiter_bins[band_number],
|
||||
};
|
||||
}
|
||||
|
||||
uint32_t get_number_of_critical_bands(CriticalBands* self) {
|
||||
return self->number_bands;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef CRITICAL_BANDS_H
|
||||
#define CRITICAL_BANDS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct CriticalBands CriticalBands;
|
||||
|
||||
typedef enum CriticalBandType {
|
||||
BARK_SCALE = 0,
|
||||
MEL_SCALE = 1,
|
||||
OPUS_SCALE = 2,
|
||||
OCTAVE_SCALE = 3,
|
||||
} CriticalBandType;
|
||||
|
||||
typedef struct CriticalBandIndexes {
|
||||
uint32_t start_position;
|
||||
uint32_t end_position;
|
||||
} CriticalBandIndexes;
|
||||
|
||||
CriticalBands* critical_bands_initialize(uint32_t sample_rate,
|
||||
uint32_t fft_size,
|
||||
CriticalBandType type);
|
||||
void critical_bands_free(CriticalBands* self);
|
||||
bool compute_critical_bands_spectrum(CriticalBands* self, const float* spectrum,
|
||||
float* critical_bands);
|
||||
CriticalBandIndexes get_band_indexes(CriticalBands* self, uint32_t band_number);
|
||||
uint32_t get_number_of_critical_bands(CriticalBands* self);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "masking_estimator.h"
|
||||
#include "../configurations.h"
|
||||
#include "../utils/spectral_utils.h"
|
||||
#include "absolute_hearing_thresholds.h"
|
||||
#include "critical_bands.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static void compute_spectral_spreading_function(MaskingEstimator* self);
|
||||
static float compute_tonality_factor(MaskingEstimator* self,
|
||||
const float* spectrum, uint32_t band);
|
||||
|
||||
struct MaskingEstimator {
|
||||
|
||||
uint32_t fft_size;
|
||||
uint32_t real_spectrum_size;
|
||||
uint32_t sample_rate;
|
||||
uint32_t number_critical_bands;
|
||||
|
||||
AbsoluteHearingThresholds* reference_spectrum;
|
||||
CriticalBands* critical_bands;
|
||||
CriticalBandIndexes band_indexes;
|
||||
|
||||
float* spectral_spreading_function;
|
||||
float* unity_gain_critical_bands_spectrum;
|
||||
float* spreaded_unity_gain_critical_bands_spectrum;
|
||||
float* threshold_j;
|
||||
float* masking_offset;
|
||||
float* spreaded_spectrum;
|
||||
float* critical_bands_reference_spectrum;
|
||||
};
|
||||
|
||||
MaskingEstimator* masking_estimation_initialize(const uint32_t fft_size,
|
||||
const uint32_t sample_rate,
|
||||
SpectrumType spectrum_type) {
|
||||
|
||||
MaskingEstimator* self =
|
||||
(MaskingEstimator*)calloc(1U, sizeof(MaskingEstimator));
|
||||
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->fft_size = fft_size;
|
||||
self->real_spectrum_size = (self->fft_size / 2U) + 1U;
|
||||
self->sample_rate = sample_rate;
|
||||
|
||||
self->critical_bands = critical_bands_initialize(
|
||||
self->sample_rate, self->fft_size, CRITICAL_BANDS_TYPE);
|
||||
if (!self->critical_bands) {
|
||||
masking_estimation_free(self);
|
||||
return NULL;
|
||||
}
|
||||
self->number_critical_bands =
|
||||
get_number_of_critical_bands(self->critical_bands);
|
||||
|
||||
self->spectral_spreading_function =
|
||||
(float*)calloc(((size_t)self->number_critical_bands *
|
||||
(size_t)self->number_critical_bands),
|
||||
sizeof(float));
|
||||
self->unity_gain_critical_bands_spectrum =
|
||||
(float*)calloc(self->number_critical_bands, sizeof(float));
|
||||
self->spreaded_unity_gain_critical_bands_spectrum =
|
||||
(float*)calloc(self->number_critical_bands, sizeof(float));
|
||||
self->threshold_j =
|
||||
(float*)calloc(self->number_critical_bands, sizeof(float));
|
||||
self->masking_offset =
|
||||
(float*)calloc(self->number_critical_bands, sizeof(float));
|
||||
self->spreaded_spectrum =
|
||||
(float*)calloc(self->number_critical_bands, sizeof(float));
|
||||
self->critical_bands_reference_spectrum =
|
||||
(float*)calloc(self->number_critical_bands, sizeof(float));
|
||||
|
||||
self->reference_spectrum = absolute_hearing_thresholds_initialize(
|
||||
self->sample_rate, self->fft_size, spectrum_type);
|
||||
|
||||
if (!self->spectral_spreading_function ||
|
||||
!self->unity_gain_critical_bands_spectrum ||
|
||||
!self->spreaded_unity_gain_critical_bands_spectrum ||
|
||||
!self->threshold_j || !self->masking_offset || !self->spreaded_spectrum ||
|
||||
!self->critical_bands_reference_spectrum || !self->reference_spectrum) {
|
||||
masking_estimation_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
compute_spectral_spreading_function(self);
|
||||
(void)initialize_spectrum_with_value(self->unity_gain_critical_bands_spectrum,
|
||||
self->number_critical_bands, 1.F);
|
||||
(void)direct_matrix_to_vector_spectral_convolution(
|
||||
self->spectral_spreading_function,
|
||||
self->unity_gain_critical_bands_spectrum,
|
||||
self->spreaded_unity_gain_critical_bands_spectrum,
|
||||
self->number_critical_bands);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void masking_estimation_free(MaskingEstimator* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
absolute_hearing_thresholds_free(self->reference_spectrum);
|
||||
critical_bands_free(self->critical_bands);
|
||||
|
||||
free(self->spectral_spreading_function);
|
||||
free(self->unity_gain_critical_bands_spectrum);
|
||||
free(self->spreaded_unity_gain_critical_bands_spectrum);
|
||||
free(self->threshold_j);
|
||||
free(self->masking_offset);
|
||||
free(self->spreaded_spectrum);
|
||||
free(self->critical_bands_reference_spectrum);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
bool compute_masking_thresholds(MaskingEstimator* self, const float* spectrum,
|
||||
float* masking_thresholds) {
|
||||
if (!self || !spectrum || !masking_thresholds) {
|
||||
return false;
|
||||
}
|
||||
|
||||
compute_critical_bands_spectrum(self->critical_bands, spectrum,
|
||||
self->critical_bands_reference_spectrum);
|
||||
|
||||
(void)direct_matrix_to_vector_spectral_convolution(
|
||||
self->spectral_spreading_function,
|
||||
self->critical_bands_reference_spectrum, self->spreaded_spectrum,
|
||||
self->number_critical_bands);
|
||||
|
||||
for (uint32_t j = 0U; j < self->number_critical_bands; j++) {
|
||||
|
||||
const float tonality_factor = compute_tonality_factor(self, spectrum, j);
|
||||
|
||||
self->masking_offset[j] = (tonality_factor * (14.5F + (float)(j + 1))) +
|
||||
(5.5F * (1.F - tonality_factor));
|
||||
|
||||
#if BIAS
|
||||
self->masking_offset[j] = relative_thresholds[j];
|
||||
|
||||
if (j > 15) {
|
||||
self->masking_offset[j] += HIGH_FREQ_BIAS;
|
||||
}
|
||||
#endif
|
||||
|
||||
self->threshold_j[j] = powf(
|
||||
10.F, (log10f(self->spreaded_spectrum[j] + 1e-12F) -
|
||||
(self->masking_offset[j] / 10.F) -
|
||||
log10f(self->spreaded_unity_gain_critical_bands_spectrum[j] +
|
||||
1e-12F)));
|
||||
|
||||
self->band_indexes = get_band_indexes(self->critical_bands, j);
|
||||
|
||||
for (uint32_t k = self->band_indexes.start_position;
|
||||
k < self->band_indexes.end_position; k++) {
|
||||
masking_thresholds[k] = self->threshold_j[j];
|
||||
}
|
||||
}
|
||||
|
||||
apply_thresholds_as_floor(self->reference_spectrum, masking_thresholds);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void compute_spectral_spreading_function(MaskingEstimator* self) {
|
||||
for (uint32_t i = 0U; i < self->number_critical_bands; i++) {
|
||||
for (uint32_t j = 0U; j < self->number_critical_bands; j++) {
|
||||
const uint32_t y = (i + 1) - (j + 1);
|
||||
|
||||
self->spectral_spreading_function[(i * self->number_critical_bands) + j] =
|
||||
15.81F + (7.5F * ((float)y + 0.474F)) -
|
||||
(17.5F * sqrtf(1.F + (((float)y + 0.474F) * ((float)y + 0.474F))));
|
||||
|
||||
self->spectral_spreading_function[(i * self->number_critical_bands) + j] =
|
||||
powf(10.F, self->spectral_spreading_function
|
||||
[(i * self->number_critical_bands) + j] /
|
||||
10.F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static float compute_tonality_factor(MaskingEstimator* self,
|
||||
const float* spectrum, uint32_t band) {
|
||||
float sum_bins = 0.F;
|
||||
float sum_log_bins = 0.F;
|
||||
|
||||
self->band_indexes = get_band_indexes(self->critical_bands, band);
|
||||
|
||||
for (uint32_t k = self->band_indexes.start_position;
|
||||
k < self->band_indexes.end_position; k++) {
|
||||
const float val = fmaxf(spectrum[k], 1e-12F);
|
||||
sum_bins += val;
|
||||
sum_log_bins += log10f(val);
|
||||
}
|
||||
|
||||
float bins_in_band = (float)self->band_indexes.end_position -
|
||||
(float)self->band_indexes.start_position;
|
||||
|
||||
const float sfm =
|
||||
(10.F * (sum_log_bins / bins_in_band)) - log10f(sum_bins / bins_in_band);
|
||||
|
||||
const float tonality_factor = fminf(sfm / -60.F, 1.F);
|
||||
|
||||
return tonality_factor;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef MASKING_ESTIMATOR_H
|
||||
#define MASKING_ESTIMATOR_H
|
||||
|
||||
#include "../utils/spectral_features.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct MaskingEstimator MaskingEstimator;
|
||||
|
||||
MaskingEstimator* masking_estimation_initialize(uint32_t fft_size,
|
||||
uint32_t sample_rate,
|
||||
SpectrumType spectrum_type);
|
||||
void masking_estimation_free(MaskingEstimator* self);
|
||||
bool compute_masking_thresholds(MaskingEstimator* self, const float* spectrum,
|
||||
float* masking_thresholds);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,8 @@
|
||||
shared_sources += files(
|
||||
'absolute_hearing_thresholds.c',
|
||||
'masking_estimator.c',
|
||||
'critical_bands.c',
|
||||
'noise_scaling_criterias.c',
|
||||
'transient_detector.c',
|
||||
'spectral_smoother.c',
|
||||
)
|
||||
+277
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "noise_scaling_criterias.h"
|
||||
#include "../configurations.h"
|
||||
#include "../utils/spectral_utils.h"
|
||||
#include "critical_bands.h"
|
||||
#include "masking_estimator.h"
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void a_posteriori_snr_critical_bands(NoiseScalingCriterias* self,
|
||||
const float* spectrum,
|
||||
const float* noise_spectrum,
|
||||
float* alpha,
|
||||
NoiseScalingParameters parameters);
|
||||
static void a_posteriori_snr(NoiseScalingCriterias* self, const float* spectrum,
|
||||
const float* noise_spectrum, float* alpha,
|
||||
NoiseScalingParameters parameters);
|
||||
static void masking_thresholds(NoiseScalingCriterias* self,
|
||||
const float* spectrum,
|
||||
const float* noise_spectrum, float* alpha,
|
||||
float* beta, NoiseScalingParameters parameters);
|
||||
|
||||
struct NoiseScalingCriterias {
|
||||
NoiseScalingType noise_scaling_type;
|
||||
uint32_t fft_size;
|
||||
uint32_t real_spectrum_size;
|
||||
uint32_t sample_rate;
|
||||
SpectrumType spectrum_type;
|
||||
uint32_t number_critical_bands;
|
||||
float lower_snr;
|
||||
float higher_snr;
|
||||
float alpha_minimun;
|
||||
float beta_minimun;
|
||||
CriticalBandIndexes band_indexes;
|
||||
CriticalBandType critical_band_type;
|
||||
|
||||
float* masking_thresholds;
|
||||
float* clean_signal_estimation;
|
||||
float* critical_bands_noise_profile;
|
||||
float* critical_bands_reference_spectrum;
|
||||
|
||||
MaskingEstimator* masking_estimation;
|
||||
CriticalBands* critical_bands;
|
||||
};
|
||||
|
||||
NoiseScalingCriterias* noise_scaling_criterias_initialize(
|
||||
const uint32_t fft_size, const CriticalBandType critical_band_type,
|
||||
const uint32_t sample_rate, SpectrumType spectrum_type) {
|
||||
|
||||
NoiseScalingCriterias* self =
|
||||
(NoiseScalingCriterias*)calloc(1U, sizeof(NoiseScalingCriterias));
|
||||
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->fft_size = fft_size;
|
||||
self->real_spectrum_size = (self->fft_size / 2U) + 1U;
|
||||
self->critical_band_type = critical_band_type;
|
||||
self->sample_rate = sample_rate;
|
||||
self->spectrum_type = spectrum_type;
|
||||
self->lower_snr = LOWER_SNR;
|
||||
self->higher_snr = HIGHER_SNR;
|
||||
self->alpha_minimun = ALPHA_MIN;
|
||||
self->beta_minimun = BETA_MIN;
|
||||
|
||||
self->critical_bands = critical_bands_initialize(
|
||||
self->sample_rate, self->fft_size, self->critical_band_type);
|
||||
self->masking_estimation = masking_estimation_initialize(
|
||||
self->fft_size, self->sample_rate, self->spectrum_type);
|
||||
|
||||
if (!self->critical_bands || !self->masking_estimation) {
|
||||
noise_scaling_criterias_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->number_critical_bands =
|
||||
get_number_of_critical_bands(self->critical_bands);
|
||||
|
||||
self->critical_bands_noise_profile =
|
||||
(float*)calloc(self->number_critical_bands, sizeof(float));
|
||||
self->critical_bands_reference_spectrum =
|
||||
(float*)calloc(self->number_critical_bands, sizeof(float));
|
||||
|
||||
self->masking_thresholds =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
self->clean_signal_estimation =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
|
||||
if (!self->critical_bands_noise_profile ||
|
||||
!self->critical_bands_reference_spectrum || !self->masking_thresholds ||
|
||||
!self->clean_signal_estimation) {
|
||||
noise_scaling_criterias_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void noise_scaling_criterias_free(NoiseScalingCriterias* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
critical_bands_free(self->critical_bands);
|
||||
masking_estimation_free(self->masking_estimation);
|
||||
|
||||
free(self->clean_signal_estimation);
|
||||
free(self->masking_thresholds);
|
||||
free(self->critical_bands_noise_profile);
|
||||
free(self->critical_bands_reference_spectrum);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
bool apply_noise_scaling_criteria(NoiseScalingCriterias* self,
|
||||
const float* spectrum,
|
||||
const float* noise_spectrum, float* alpha,
|
||||
float* beta,
|
||||
NoiseScalingParameters parameters) {
|
||||
if (!spectrum || !noise_spectrum) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ((NoiseScalingType)parameters.scaling_type) {
|
||||
case A_POSTERIORI_SNR:
|
||||
a_posteriori_snr(self, spectrum, noise_spectrum, alpha, parameters);
|
||||
break;
|
||||
case A_POSTERIORI_SNR_CRITICAL_BANDS:
|
||||
a_posteriori_snr_critical_bands(self, spectrum, noise_spectrum, alpha,
|
||||
parameters);
|
||||
break;
|
||||
case MASKING_THRESHOLDS:
|
||||
masking_thresholds(self, spectrum, noise_spectrum, alpha, beta,
|
||||
parameters);
|
||||
break;
|
||||
|
||||
case NO_SCALING:
|
||||
for (uint32_t k = 0U; k < self->real_spectrum_size; k++) {
|
||||
alpha[k] = self->alpha_minimun;
|
||||
beta[k] = self->beta_minimun;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void a_posteriori_snr_critical_bands(NoiseScalingCriterias* self,
|
||||
const float* spectrum,
|
||||
const float* noise_spectrum,
|
||||
float* alpha,
|
||||
NoiseScalingParameters parameters) {
|
||||
|
||||
compute_critical_bands_spectrum(self->critical_bands, noise_spectrum,
|
||||
self->critical_bands_noise_profile);
|
||||
compute_critical_bands_spectrum(self->critical_bands, spectrum,
|
||||
self->critical_bands_reference_spectrum);
|
||||
|
||||
float oversustraction_factor = 1.F;
|
||||
|
||||
for (uint32_t j = 0U; j < self->number_critical_bands; j++) {
|
||||
|
||||
self->band_indexes = get_band_indexes(self->critical_bands, j);
|
||||
|
||||
const float snr_db =
|
||||
10.F * log10f(self->critical_bands_reference_spectrum[j] /
|
||||
self->critical_bands_noise_profile[j]);
|
||||
|
||||
if (snr_db >= self->lower_snr && snr_db <= self->higher_snr) {
|
||||
oversustraction_factor = (-0.05F * (snr_db)) + parameters.oversubtraction;
|
||||
} else if (snr_db < 0.F) {
|
||||
oversustraction_factor = parameters.oversubtraction;
|
||||
} else if (snr_db > 20.F) {
|
||||
oversustraction_factor = 1.F;
|
||||
}
|
||||
|
||||
for (uint32_t k = self->band_indexes.start_position;
|
||||
k < self->band_indexes.end_position; k++) {
|
||||
alpha[k] = oversustraction_factor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void a_posteriori_snr(NoiseScalingCriterias* self, const float* spectrum,
|
||||
const float* noise_spectrum, float* alpha,
|
||||
NoiseScalingParameters parameters) {
|
||||
float noisy_spectrum_sum = 0.F;
|
||||
float noise_spectrum_sum = 0.F;
|
||||
|
||||
for (uint32_t k = 0U; k < self->real_spectrum_size; k++) {
|
||||
noisy_spectrum_sum += spectrum[k];
|
||||
noise_spectrum_sum += noise_spectrum[k];
|
||||
}
|
||||
|
||||
const float snr_db = 10.F * log10f(noisy_spectrum_sum / noise_spectrum_sum);
|
||||
|
||||
float oversustraction_factor;
|
||||
if (snr_db >= self->lower_snr && snr_db <= self->higher_snr) {
|
||||
oversustraction_factor = (-0.05F * (snr_db)) + parameters.oversubtraction;
|
||||
} else if (snr_db < 0.F) {
|
||||
oversustraction_factor = parameters.oversubtraction;
|
||||
} else {
|
||||
oversustraction_factor = 1.F;
|
||||
}
|
||||
|
||||
for (uint32_t k = 0U; k < self->real_spectrum_size; k++) {
|
||||
alpha[k] = oversustraction_factor;
|
||||
}
|
||||
}
|
||||
|
||||
static void masking_thresholds(NoiseScalingCriterias* self,
|
||||
const float* spectrum,
|
||||
const float* noise_spectrum, float* alpha,
|
||||
float* beta, NoiseScalingParameters parameters) {
|
||||
|
||||
for (uint32_t k = 0U; k < self->real_spectrum_size; k++) {
|
||||
self->clean_signal_estimation[k] =
|
||||
fmaxf(spectrum[k] - noise_spectrum[k], 0.F);
|
||||
}
|
||||
|
||||
compute_masking_thresholds(self->masking_estimation,
|
||||
self->clean_signal_estimation,
|
||||
self->masking_thresholds);
|
||||
|
||||
float max_masked_value =
|
||||
10.F * log10f(max_spectral_value(self->masking_thresholds,
|
||||
self->real_spectrum_size) +
|
||||
1e-12F);
|
||||
float min_masked_value =
|
||||
10.F * log10f(min_spectral_value(self->masking_thresholds,
|
||||
self->real_spectrum_size) +
|
||||
1e-12F);
|
||||
|
||||
for (uint32_t k = 0U; k < self->real_spectrum_size; k++) {
|
||||
const float current_masked_value =
|
||||
10.F * log10f(self->masking_thresholds[k] + 1e-12F);
|
||||
|
||||
if (current_masked_value >= max_masked_value) {
|
||||
alpha[k] = self->alpha_minimun;
|
||||
beta[k] = self->beta_minimun;
|
||||
} else if (current_masked_value <= min_masked_value) {
|
||||
alpha[k] = parameters.oversubtraction;
|
||||
beta[k] = parameters.undersubtraction;
|
||||
} else {
|
||||
const float normalized_value = (current_masked_value - min_masked_value) /
|
||||
(max_masked_value - min_masked_value);
|
||||
|
||||
alpha[k] = ((1.F - normalized_value) * parameters.oversubtraction) +
|
||||
(normalized_value * self->alpha_minimun);
|
||||
beta[k] = ((1.F - normalized_value) * parameters.undersubtraction) +
|
||||
(normalized_value * self->beta_minimun);
|
||||
}
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef NOISE_SCALING_CRITERIAS_H
|
||||
#define NOISE_SCALING_CRITERIAS_H
|
||||
|
||||
#include "../utils/spectral_features.h"
|
||||
#include "critical_bands.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum NoiseScalingType {
|
||||
A_POSTERIORI_SNR = 0,
|
||||
A_POSTERIORI_SNR_CRITICAL_BANDS = 1,
|
||||
MASKING_THRESHOLDS = 2,
|
||||
NO_SCALING = 3,
|
||||
} NoiseScalingType;
|
||||
|
||||
typedef struct NoiseScalingParameters {
|
||||
float undersubtraction;
|
||||
float oversubtraction;
|
||||
int scaling_type;
|
||||
} NoiseScalingParameters;
|
||||
|
||||
typedef struct NoiseScalingCriterias NoiseScalingCriterias;
|
||||
|
||||
NoiseScalingCriterias* noise_scaling_criterias_initialize(
|
||||
uint32_t fft_size, CriticalBandType critical_band_type,
|
||||
uint32_t sample_rate, SpectrumType spectrum_type);
|
||||
void noise_scaling_criterias_free(NoiseScalingCriterias* self);
|
||||
bool apply_noise_scaling_criteria(NoiseScalingCriterias* self,
|
||||
const float* spectrum,
|
||||
const float* noise_spectrum, float* alpha,
|
||||
float* beta,
|
||||
NoiseScalingParameters parameters);
|
||||
|
||||
#endif
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "spectral_smoother.h"
|
||||
#include "transient_detector.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static void spectrum_time_smoothing(SpectralSmoother* self, float smoothing);
|
||||
static void spectrum_transient_aware_time_smoothing(SpectralSmoother* self,
|
||||
float smoothing,
|
||||
float* spectrum);
|
||||
|
||||
struct SpectralSmoother {
|
||||
uint32_t fft_size;
|
||||
uint32_t real_spectrum_size;
|
||||
float adaptive_coefficient;
|
||||
float previous_adaptive_coefficient;
|
||||
TimeSmoothingType type;
|
||||
|
||||
float* noise_spectrum;
|
||||
float* smoothed_spectrum;
|
||||
float* smoothed_spectrum_previous;
|
||||
|
||||
TransientDetector* transient_detection;
|
||||
};
|
||||
|
||||
SpectralSmoother* spectral_smoothing_initialize(const uint32_t fft_size,
|
||||
TimeSmoothingType type) {
|
||||
SpectralSmoother* self =
|
||||
(SpectralSmoother*)calloc(1U, sizeof(SpectralSmoother));
|
||||
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->fft_size = fft_size;
|
||||
self->real_spectrum_size = (self->fft_size / 2U) + 1U;
|
||||
self->type = type;
|
||||
self->previous_adaptive_coefficient = 0.F;
|
||||
self->adaptive_coefficient = 0.F;
|
||||
|
||||
self->noise_spectrum =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
self->smoothed_spectrum =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
self->smoothed_spectrum_previous =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
|
||||
self->transient_detection = transient_detector_initialize(self->fft_size);
|
||||
|
||||
if (!self->noise_spectrum || !self->smoothed_spectrum ||
|
||||
!self->smoothed_spectrum_previous || !self->transient_detection) {
|
||||
spectral_smoothing_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void spectral_smoothing_free(SpectralSmoother* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
transient_detector_free(self->transient_detection);
|
||||
|
||||
free(self->noise_spectrum);
|
||||
free(self->smoothed_spectrum);
|
||||
free(self->smoothed_spectrum_previous);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
bool spectral_smoothing_run(SpectralSmoother* self,
|
||||
TimeSmoothingParameters parameters,
|
||||
float* signal_spectrum) {
|
||||
if (!self || !signal_spectrum) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(self->smoothed_spectrum, signal_spectrum,
|
||||
sizeof(float) * self->real_spectrum_size);
|
||||
|
||||
switch (self->type) {
|
||||
case FIXED:
|
||||
spectrum_time_smoothing(self, parameters.smoothing);
|
||||
break;
|
||||
case TRANSIENT_AWARE:
|
||||
spectrum_transient_aware_time_smoothing(self, parameters.smoothing,
|
||||
signal_spectrum);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(self->smoothed_spectrum_previous, self->smoothed_spectrum,
|
||||
sizeof(float) * self->real_spectrum_size);
|
||||
memcpy(signal_spectrum, self->smoothed_spectrum,
|
||||
sizeof(float) * self->real_spectrum_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void spectrum_transient_aware_time_smoothing(SpectralSmoother* self,
|
||||
const float smoothing,
|
||||
float* spectrum) {
|
||||
|
||||
if (!transient_detector_run(self->transient_detection, spectrum)) {
|
||||
for (uint32_t k = 0U; k < self->real_spectrum_size; k++) {
|
||||
if (self->smoothed_spectrum[k] > self->smoothed_spectrum_previous[k]) {
|
||||
self->smoothed_spectrum[k] =
|
||||
(smoothing * self->smoothed_spectrum_previous[k]) +
|
||||
((1.F - smoothing) * self->smoothed_spectrum[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void spectrum_time_smoothing(SpectralSmoother* self,
|
||||
const float smoothing) {
|
||||
for (uint32_t k = 0U; k < self->real_spectrum_size; k++) {
|
||||
if (self->smoothed_spectrum[k] > self->smoothed_spectrum_previous[k]) {
|
||||
self->smoothed_spectrum[k] =
|
||||
(smoothing * self->smoothed_spectrum_previous[k]) +
|
||||
((1.F - smoothing) * self->smoothed_spectrum[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef SPECTRAL_SMOOTHER_H
|
||||
#define SPECTRAL_SMOOTHER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum TimeSmoothingType {
|
||||
NO_SMOOTHING = 0,
|
||||
FIXED = 1,
|
||||
TRANSIENT_AWARE = 2,
|
||||
} TimeSmoothingType;
|
||||
|
||||
typedef struct TimeSmoothingParameters {
|
||||
float smoothing;
|
||||
} TimeSmoothingParameters;
|
||||
|
||||
typedef struct SpectralSmoother SpectralSmoother;
|
||||
|
||||
SpectralSmoother* spectral_smoothing_initialize(uint32_t fft_size,
|
||||
TimeSmoothingType type);
|
||||
void spectral_smoothing_free(SpectralSmoother* self);
|
||||
bool spectral_smoothing_run(SpectralSmoother* self,
|
||||
TimeSmoothingParameters parameters,
|
||||
float* signal_spectrum);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "transient_detector.h"
|
||||
#include "../configurations.h"
|
||||
#include "../utils/spectral_utils.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct TransientDetector {
|
||||
uint32_t fft_size;
|
||||
uint32_t real_spectrum_size;
|
||||
float rolling_mean;
|
||||
bool transient_present;
|
||||
uint32_t window_count;
|
||||
|
||||
float* previous_spectrum;
|
||||
};
|
||||
|
||||
TransientDetector* transient_detector_initialize(const uint32_t fft_size) {
|
||||
TransientDetector* self =
|
||||
(TransientDetector*)calloc(1U, sizeof(TransientDetector));
|
||||
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->fft_size = fft_size;
|
||||
self->real_spectrum_size = (self->fft_size / 2U) + 1U;
|
||||
|
||||
self->previous_spectrum =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
|
||||
if (!self->previous_spectrum) {
|
||||
transient_detector_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->window_count = 0U;
|
||||
self->rolling_mean = 0.F;
|
||||
self->transient_present = false;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void transient_detector_free(TransientDetector* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
free(self->previous_spectrum);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
bool transient_detector_run(TransientDetector* self, const float* spectrum) {
|
||||
const float reduction_function = spectral_flux(
|
||||
spectrum, self->previous_spectrum, self->real_spectrum_size);
|
||||
|
||||
self->window_count += 1U;
|
||||
|
||||
if (self->window_count > 1U) {
|
||||
self->rolling_mean +=
|
||||
((reduction_function - self->rolling_mean) / (float)self->window_count);
|
||||
} else {
|
||||
self->rolling_mean = reduction_function;
|
||||
}
|
||||
|
||||
const float adapted_threshold =
|
||||
((UPPER_LIMIT - DEFAULT_TRANSIENT_THRESHOLD) * self->rolling_mean) +
|
||||
1e-6F;
|
||||
|
||||
memcpy(self->previous_spectrum, spectrum,
|
||||
sizeof(float) * self->real_spectrum_size);
|
||||
|
||||
if (reduction_function > adapted_threshold) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef TRANSIENT_DETECTOR_H
|
||||
#define TRANSIENT_DETECTOR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct TransientDetector TransientDetector;
|
||||
|
||||
TransientDetector* transient_detector_initialize(uint32_t fft_size);
|
||||
void transient_detector_free(TransientDetector* self);
|
||||
bool transient_detector_run(TransientDetector* self, const float* spectrum);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef SPECTRAL_PROCESSOR_H
|
||||
#define SPECTRAL_PROCESSOR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
// Generic Spectral Processing function over an FFT spectrum. Receives any
|
||||
// spectral processing module handle (void *) and the FFT of a audio block.
|
||||
// This is to inject any spectral processor and processing function into the
|
||||
// STFT transform at runtime
|
||||
typedef void* SpectralProcessorHandle;
|
||||
|
||||
// Processing function which deals with the fft spectrum by mutating the array
|
||||
// with any DSP that operates with the FFT spectrum (1d FFTW spectrum)
|
||||
typedef bool (*spectral_processing)(SpectralProcessorHandle spectral_processor,
|
||||
float* fft_spectrum);
|
||||
#endif
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "fft_transform.h"
|
||||
#include "../utils/general_utils.h"
|
||||
|
||||
#include <fftw3.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static uint32_t calculate_fft_size(FftTransform* self);
|
||||
static bool allocate_fftw(FftTransform* self);
|
||||
|
||||
struct FftTransform {
|
||||
fftwf_plan forward;
|
||||
fftwf_plan backward;
|
||||
|
||||
uint32_t fft_size;
|
||||
uint32_t frame_size;
|
||||
uint32_t zeropadding_amount;
|
||||
uint32_t copy_position;
|
||||
ZeroPaddingType padding_type;
|
||||
uint32_t padding_amount;
|
||||
float* input_fft_buffer;
|
||||
float* output_fft_buffer;
|
||||
};
|
||||
|
||||
FftTransform* fft_transform_initialize(const uint32_t frame_size,
|
||||
const ZeroPaddingType padding_type,
|
||||
const uint32_t zeropadding_amount) {
|
||||
FftTransform* self = (FftTransform*)calloc(1U, sizeof(FftTransform));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->padding_type = padding_type;
|
||||
self->zeropadding_amount = zeropadding_amount;
|
||||
self->frame_size = frame_size;
|
||||
|
||||
self->fft_size = calculate_fft_size(self);
|
||||
|
||||
self->copy_position = (self->fft_size / 2U) - (self->frame_size / 2U);
|
||||
|
||||
if (!allocate_fftw(self)) {
|
||||
fft_transform_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
FftTransform* fft_transform_initialize_bins(const uint32_t fft_size) {
|
||||
FftTransform* self = (FftTransform*)calloc(1U, sizeof(FftTransform));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->fft_size = fft_size;
|
||||
self->frame_size = self->fft_size;
|
||||
|
||||
if (!allocate_fftw(self)) {
|
||||
fft_transform_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static bool allocate_fftw(FftTransform* self) {
|
||||
self->input_fft_buffer = (float*)fftwf_malloc(self->fft_size * sizeof(float));
|
||||
self->output_fft_buffer =
|
||||
(float*)fftwf_malloc(self->fft_size * sizeof(float));
|
||||
|
||||
if (!self->input_fft_buffer || !self->output_fft_buffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(self->input_fft_buffer, 0, self->fft_size * sizeof(float));
|
||||
memset(self->output_fft_buffer, 0, self->fft_size * sizeof(float));
|
||||
|
||||
self->forward =
|
||||
fftwf_plan_r2r_1d((int)self->fft_size, self->input_fft_buffer,
|
||||
self->output_fft_buffer, FFTW_R2HC, FFTW_ESTIMATE);
|
||||
self->backward =
|
||||
fftwf_plan_r2r_1d((int)self->fft_size, self->output_fft_buffer,
|
||||
self->input_fft_buffer, FFTW_HC2R, FFTW_ESTIMATE);
|
||||
|
||||
return self->forward && self->backward;
|
||||
}
|
||||
|
||||
static uint32_t calculate_fft_size(FftTransform* self) {
|
||||
switch (self->padding_type) {
|
||||
case NO_PADDING: {
|
||||
self->padding_amount = 0;
|
||||
return get_next_divisible_two((int)self->frame_size);
|
||||
}
|
||||
case NEXT_POWER_OF_TWO: {
|
||||
uint32_t next_power_of_two = get_next_power_two((int)self->frame_size);
|
||||
self->padding_amount = next_power_of_two - self->frame_size;
|
||||
return next_power_of_two;
|
||||
}
|
||||
case FIXED_AMOUNT: {
|
||||
self->padding_amount = self->zeropadding_amount;
|
||||
return get_next_divisible_two(
|
||||
(int)(self->frame_size + self->padding_amount));
|
||||
}
|
||||
default:
|
||||
return get_next_divisible_two((int)self->frame_size);
|
||||
}
|
||||
}
|
||||
|
||||
void fft_transform_free(FftTransform* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->input_fft_buffer) {
|
||||
fftwf_free(self->input_fft_buffer);
|
||||
}
|
||||
if (self->output_fft_buffer) {
|
||||
fftwf_free(self->output_fft_buffer);
|
||||
}
|
||||
|
||||
// FFTW plans can be NULL if initialization failed
|
||||
if (self->forward) {
|
||||
fftwf_destroy_plan(self->forward);
|
||||
}
|
||||
if (self->backward) {
|
||||
fftwf_destroy_plan(self->backward);
|
||||
}
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
uint32_t get_fft_size(FftTransform* self) {
|
||||
if (!self) {
|
||||
return 0;
|
||||
}
|
||||
return self->fft_size;
|
||||
}
|
||||
uint32_t get_fft_real_spectrum_size(FftTransform* self) {
|
||||
if (!self) {
|
||||
return 0;
|
||||
}
|
||||
return (self->fft_size / 2U) + 1U;
|
||||
}
|
||||
|
||||
bool fft_load_input_samples(FftTransform* self, const float* input) {
|
||||
if (!self || !input) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure buffer bounds are safe
|
||||
if (self->frame_size + self->copy_position > self->fft_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy centered values only
|
||||
for (uint32_t i = self->copy_position;
|
||||
i < (self->frame_size + self->copy_position); i++) {
|
||||
self->input_fft_buffer[i] = input[i - self->copy_position];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fft_get_output_samples(FftTransform* self, float* output) {
|
||||
if (!self || !output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure buffer bounds are safe
|
||||
if (self->frame_size + self->copy_position > self->fft_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy centered values only
|
||||
for (uint32_t i = self->copy_position;
|
||||
i < (self->frame_size + self->copy_position); i++) {
|
||||
output[i - self->copy_position] = self->input_fft_buffer[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool compute_forward_fft(FftTransform* self) {
|
||||
if (!self) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fftwf_execute(self->forward);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool compute_backward_fft(FftTransform* self) {
|
||||
if (!self) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fftwf_execute(self->backward);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float* get_fft_input_buffer(FftTransform* self) {
|
||||
return self->input_fft_buffer;
|
||||
}
|
||||
|
||||
float* get_fft_output_buffer(FftTransform* self) {
|
||||
return self->output_fft_buffer;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef FFT_TRANSFORM_H
|
||||
#define FFT_TRANSFORM_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// C17 enum validation
|
||||
enum ZeroPaddingType {
|
||||
NEXT_POWER_OF_TWO = 0,
|
||||
FIXED_AMOUNT = 1,
|
||||
NO_PADDING = 2,
|
||||
};
|
||||
|
||||
// Compile-time validation of enum values
|
||||
_Static_assert(NEXT_POWER_OF_TWO == 0, "NEXT_POWER_OF_TWO must be 0");
|
||||
_Static_assert(FIXED_AMOUNT == 1, "FIXED_AMOUNT must be 1");
|
||||
_Static_assert(NO_PADDING == 2, "NO_PADDING must be 2");
|
||||
|
||||
typedef enum ZeroPaddingType ZeroPaddingType;
|
||||
|
||||
typedef struct FftTransform FftTransform;
|
||||
|
||||
FftTransform* fft_transform_initialize(uint32_t frame_size,
|
||||
ZeroPaddingType padding_type,
|
||||
uint32_t zeropadding_amount);
|
||||
FftTransform* fft_transform_initialize_bins(uint32_t fft_size);
|
||||
void fft_transform_free(FftTransform* self);
|
||||
bool fft_load_input_samples(FftTransform* self, const float* input);
|
||||
bool fft_get_output_samples(FftTransform* self, float* output);
|
||||
uint32_t get_fft_size(FftTransform* self);
|
||||
uint32_t get_fft_real_spectrum_size(FftTransform* self);
|
||||
bool compute_forward_fft(FftTransform* self);
|
||||
bool compute_backward_fft(FftTransform* self);
|
||||
float* get_fft_input_buffer(FftTransform* self);
|
||||
float* get_fft_output_buffer(FftTransform* self);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,6 @@
|
||||
shared_sources += files(
|
||||
'fft_transform.c',
|
||||
'stft_windows.c',
|
||||
'stft_buffer.c',
|
||||
'stft_processor.c',
|
||||
)
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "stft_buffer.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct StftBuffer {
|
||||
uint32_t read_position;
|
||||
uint32_t start_position;
|
||||
uint32_t stft_frame_size;
|
||||
uint32_t block_step;
|
||||
|
||||
float* in_fifo;
|
||||
float* out_fifo;
|
||||
};
|
||||
|
||||
StftBuffer* stft_buffer_initialize(const uint32_t stft_frame_size,
|
||||
const uint32_t start_position,
|
||||
const uint32_t block_step) {
|
||||
StftBuffer* self = (StftBuffer*)calloc(1U, sizeof(StftBuffer));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->stft_frame_size = stft_frame_size;
|
||||
self->start_position = start_position;
|
||||
self->block_step = block_step;
|
||||
self->read_position = self->start_position;
|
||||
self->in_fifo = (float*)calloc(self->stft_frame_size, sizeof(float));
|
||||
self->out_fifo = (float*)calloc(self->stft_frame_size, sizeof(float));
|
||||
|
||||
if (!self->in_fifo || !self->out_fifo) {
|
||||
stft_buffer_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void stft_buffer_free(StftBuffer* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
free(self->in_fifo);
|
||||
free(self->out_fifo);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
bool is_buffer_full(StftBuffer* self) {
|
||||
if (self->read_position == self->stft_frame_size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
float stft_buffer_fill(StftBuffer* self, const float input_sample) {
|
||||
float sample_value = 0.F;
|
||||
|
||||
self->in_fifo[self->read_position] = input_sample;
|
||||
sample_value = self->out_fifo[self->read_position - self->start_position];
|
||||
if (self->read_position < self->stft_frame_size) {
|
||||
self->read_position++; // Advance
|
||||
}
|
||||
|
||||
return sample_value;
|
||||
}
|
||||
|
||||
bool stft_buffer_advance_block(StftBuffer* self,
|
||||
const float* reconstructed_signal) {
|
||||
if (!reconstructed_signal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self->read_position = self->start_position; // Reset read
|
||||
|
||||
memmove(self->in_fifo, &self->in_fifo[self->block_step],
|
||||
sizeof(float) * self->start_position);
|
||||
|
||||
memcpy(self->out_fifo, reconstructed_signal,
|
||||
sizeof(float) * self->block_step);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float* get_full_buffer_block(StftBuffer* self) {
|
||||
return self->in_fifo;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef STFT_BUFFER_H
|
||||
#define STFT_BUFFER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct StftBuffer StftBuffer;
|
||||
StftBuffer* stft_buffer_initialize(uint32_t stft_frame_size,
|
||||
uint32_t start_position,
|
||||
uint32_t block_step);
|
||||
void stft_buffer_free(StftBuffer* self);
|
||||
bool is_buffer_full(StftBuffer* self);
|
||||
float stft_buffer_fill(StftBuffer* self, float input_sample);
|
||||
bool stft_buffer_advance_block(StftBuffer* self,
|
||||
const float* reconstructed_signal);
|
||||
float* get_full_buffer_block(StftBuffer* self);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "stft_processor.h"
|
||||
#include "stft_buffer.h"
|
||||
#include "stft_windows.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct StftProcessor {
|
||||
uint32_t input_latency;
|
||||
uint32_t hop;
|
||||
uint32_t overlap_factor;
|
||||
uint32_t fft_size;
|
||||
uint32_t frame_size;
|
||||
float* output_accumulator;
|
||||
float* tmp_buffer;
|
||||
|
||||
FftTransform* fft_transform;
|
||||
StftBuffer* stft_buffer;
|
||||
StftWindows* stft_windows;
|
||||
};
|
||||
|
||||
StftProcessor* stft_processor_initialize(const uint32_t sample_rate,
|
||||
const float stft_frame_size,
|
||||
const uint32_t overlap_factor,
|
||||
ZeroPaddingType padding_type,
|
||||
const uint32_t zeropadding_amount,
|
||||
WindowTypes input_window,
|
||||
WindowTypes output_window) {
|
||||
if (sample_rate == 0 || stft_frame_size <= 0.0f || overlap_factor == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
StftProcessor* self = (StftProcessor*)calloc(1U, sizeof(StftProcessor));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->frame_size =
|
||||
(uint32_t)((stft_frame_size / 1000.F) * (float)sample_rate);
|
||||
self->fft_transform = fft_transform_initialize(self->frame_size, padding_type,
|
||||
zeropadding_amount);
|
||||
if (!self->fft_transform) {
|
||||
stft_processor_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->fft_size = get_fft_size(self->fft_transform);
|
||||
self->overlap_factor = overlap_factor;
|
||||
self->hop = self->frame_size / self->overlap_factor;
|
||||
self->input_latency = self->frame_size;
|
||||
|
||||
self->output_accumulator =
|
||||
(float*)calloc(self->frame_size * 2L, sizeof(float));
|
||||
if (!self->output_accumulator) {
|
||||
stft_processor_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->tmp_buffer = (float*)calloc(self->frame_size, sizeof(float));
|
||||
if (!self->tmp_buffer) {
|
||||
stft_processor_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->stft_buffer = stft_buffer_initialize(
|
||||
self->frame_size, self->input_latency - self->hop, self->hop);
|
||||
if (!self->stft_buffer) {
|
||||
stft_processor_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->stft_windows = stft_window_initialize(
|
||||
self->fft_size, self->overlap_factor, input_window, output_window);
|
||||
if (!self->stft_windows) {
|
||||
stft_processor_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void stft_processor_free(StftProcessor* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->stft_buffer) {
|
||||
stft_buffer_free(self->stft_buffer);
|
||||
}
|
||||
if (self->stft_windows) {
|
||||
stft_window_free(self->stft_windows);
|
||||
}
|
||||
if (self->fft_transform) {
|
||||
fft_transform_free(self->fft_transform);
|
||||
}
|
||||
|
||||
if (self->output_accumulator) {
|
||||
free(self->output_accumulator);
|
||||
}
|
||||
if (self->tmp_buffer) {
|
||||
free(self->tmp_buffer);
|
||||
}
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
bool stft_processor_run(StftProcessor* self, const uint32_t number_of_samples,
|
||||
const float* input, float* output,
|
||||
spectral_processing spectral_processing,
|
||||
SpectralProcessorHandle spectral_processor) {
|
||||
if (!self || !input || !output || number_of_samples == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t k = 0U; k < number_of_samples; k++) {
|
||||
// Start filling buffer sample per sample
|
||||
output[k] = stft_buffer_fill(self->stft_buffer, input[k]);
|
||||
|
||||
if (is_buffer_full(self->stft_buffer)) {
|
||||
fft_load_input_samples(self->fft_transform,
|
||||
get_full_buffer_block(self->stft_buffer));
|
||||
|
||||
// STFT Analysis
|
||||
stft_window_apply(self->stft_windows,
|
||||
get_fft_input_buffer(self->fft_transform),
|
||||
INPUT_WINDOW);
|
||||
|
||||
compute_forward_fft(self->fft_transform);
|
||||
|
||||
// Apply processing
|
||||
spectral_processing(spectral_processor,
|
||||
get_fft_output_buffer(self->fft_transform));
|
||||
|
||||
// STFT Synthesis
|
||||
compute_backward_fft(self->fft_transform);
|
||||
|
||||
stft_window_apply(self->stft_windows,
|
||||
get_fft_input_buffer(self->fft_transform),
|
||||
OUTPUT_WINDOW);
|
||||
|
||||
fft_get_output_samples(self->fft_transform, self->tmp_buffer);
|
||||
|
||||
// STFT Overlap Add
|
||||
for (uint32_t j = 0U; j < self->frame_size; j++) {
|
||||
self->output_accumulator[j] += self->tmp_buffer[j];
|
||||
}
|
||||
|
||||
stft_buffer_advance_block(self->stft_buffer, self->output_accumulator);
|
||||
|
||||
memmove(self->output_accumulator, &self->output_accumulator[self->hop],
|
||||
self->frame_size * sizeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t get_stft_latency(StftProcessor* self) {
|
||||
if (!self) {
|
||||
return 0;
|
||||
}
|
||||
return self->input_latency;
|
||||
}
|
||||
|
||||
uint32_t get_stft_fft_size(StftProcessor* self) {
|
||||
if (!self) {
|
||||
return 0;
|
||||
}
|
||||
return self->fft_size;
|
||||
}
|
||||
|
||||
uint32_t get_stft_real_spectrum_size(StftProcessor* self) {
|
||||
if (!self) {
|
||||
return 0;
|
||||
}
|
||||
return get_fft_real_spectrum_size(self->fft_transform);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef STFT_PROCESSOR_H
|
||||
#define STFT_PROCESSOR_H
|
||||
|
||||
#include "../spectral_processor.h"
|
||||
#include "../utils/spectral_utils.h"
|
||||
#include "fft_transform.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct StftProcessor StftProcessor;
|
||||
|
||||
StftProcessor* stft_processor_initialize(
|
||||
uint32_t sample_rate, float stft_frame_size, uint32_t overlap_factor,
|
||||
ZeroPaddingType padding_type, uint32_t zeropadding_amount,
|
||||
WindowTypes input_window, WindowTypes output_window);
|
||||
void stft_processor_free(StftProcessor* self);
|
||||
uint32_t get_stft_latency(StftProcessor* self);
|
||||
uint32_t get_stft_fft_size(StftProcessor* self);
|
||||
uint32_t get_stft_real_spectrum_size(StftProcessor* self);
|
||||
|
||||
// Receives an input and output buffer with a a number_of_samples and does the
|
||||
// STFT transform applying any spectral_processing. It works similar to qsort,
|
||||
// because it receives a function pointer of any spectral processing that needs
|
||||
// to be applied in between the analysis and the synthesis
|
||||
bool stft_processor_run(StftProcessor* self, uint32_t number_of_samples,
|
||||
const float* input, float* output,
|
||||
spectral_processing spectral_processing,
|
||||
SpectralProcessorHandle spectral_processor);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "stft_windows.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static float get_windows_scale_factor(StftWindows* self,
|
||||
uint32_t overlap_factor);
|
||||
|
||||
struct StftWindows {
|
||||
float* input_window;
|
||||
float* output_window;
|
||||
|
||||
uint32_t stft_frame_size;
|
||||
float scale_factor;
|
||||
};
|
||||
|
||||
StftWindows* stft_window_initialize(const uint32_t stft_frame_size,
|
||||
const uint32_t overlap_factor,
|
||||
const WindowTypes input_window,
|
||||
const WindowTypes output_window) {
|
||||
StftWindows* self = (StftWindows*)calloc(1U, sizeof(StftWindows));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->stft_frame_size = stft_frame_size;
|
||||
|
||||
self->input_window = (float*)calloc(self->stft_frame_size, sizeof(float));
|
||||
self->output_window = (float*)calloc(self->stft_frame_size, sizeof(float));
|
||||
|
||||
if (!self->input_window || !self->output_window) {
|
||||
stft_window_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(void)get_fft_window(self->input_window, self->stft_frame_size, input_window);
|
||||
(void)get_fft_window(self->output_window, self->stft_frame_size,
|
||||
output_window);
|
||||
|
||||
self->scale_factor = get_windows_scale_factor(self, overlap_factor);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void stft_window_free(StftWindows* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
free(self->input_window);
|
||||
free(self->output_window);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
static float get_windows_scale_factor(StftWindows* self,
|
||||
const uint32_t overlap_factor) {
|
||||
if (overlap_factor < 2) {
|
||||
return 0.F;
|
||||
}
|
||||
float sum = 0.F;
|
||||
for (uint32_t i = 0U; i < self->stft_frame_size; i++) {
|
||||
sum += self->input_window[i] * self->output_window[i];
|
||||
}
|
||||
|
||||
return sum * (float)overlap_factor;
|
||||
}
|
||||
|
||||
bool stft_window_apply(StftWindows* self, float* frame,
|
||||
const WindowPlace place) {
|
||||
if (!self || !frame) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0U; i < self->stft_frame_size; i++) {
|
||||
switch (place) {
|
||||
case INPUT_WINDOW:
|
||||
frame[i] *= self->input_window[i];
|
||||
break;
|
||||
case OUTPUT_WINDOW:
|
||||
frame[i] *= self->output_window[i] / self->scale_factor;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef STFT_WINDOW_H
|
||||
#define STFT_WINDOW_H
|
||||
|
||||
#include "../utils/spectral_utils.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct StftWindows StftWindows;
|
||||
|
||||
typedef enum WindowPlace { INPUT_WINDOW = 1, OUTPUT_WINDOW = 2 } WindowPlace;
|
||||
|
||||
StftWindows* stft_window_initialize(uint32_t stft_frame_size,
|
||||
uint32_t overlap_factor,
|
||||
WindowTypes input_window,
|
||||
WindowTypes output_window);
|
||||
void stft_window_free(StftWindows* self);
|
||||
bool stft_window_apply(StftWindows* self, float* frame, WindowPlace place);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "denoise_mixer.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct DenoiseMixer {
|
||||
float* residual_spectrum;
|
||||
float* denoised_spectrum;
|
||||
|
||||
uint32_t fft_size;
|
||||
uint32_t real_spectrum_size;
|
||||
uint32_t sample_rate;
|
||||
uint32_t hop;
|
||||
};
|
||||
|
||||
DenoiseMixer* denoise_mixer_initialize(uint32_t fft_size, uint32_t sample_rate,
|
||||
uint32_t hop) {
|
||||
DenoiseMixer* self = (DenoiseMixer*)calloc(1U, sizeof(DenoiseMixer));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->fft_size = fft_size;
|
||||
self->real_spectrum_size = (self->fft_size / 2U) + 1U;
|
||||
self->sample_rate = sample_rate;
|
||||
self->hop = hop;
|
||||
|
||||
self->residual_spectrum = (float*)calloc((self->fft_size), sizeof(float));
|
||||
self->denoised_spectrum = (float*)calloc((self->fft_size), sizeof(float));
|
||||
|
||||
if (!self->residual_spectrum || !self->denoised_spectrum) {
|
||||
denoise_mixer_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void denoise_mixer_free(DenoiseMixer* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
free(self->residual_spectrum);
|
||||
free(self->denoised_spectrum);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
bool denoise_mixer_run(DenoiseMixer* self, float* fft_spectrum,
|
||||
const float* gain_spectrum,
|
||||
DenoiseMixerParameters parameters) {
|
||||
|
||||
if (!fft_spectrum || !gain_spectrum) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get denoised spectrum - Apply to both real and complex parts
|
||||
for (uint32_t k = 0U; k < self->fft_size; k++) {
|
||||
self->denoised_spectrum[k] = fft_spectrum[k] * gain_spectrum[k];
|
||||
}
|
||||
|
||||
// Get residual spectrum - Apply to both real and complex parts
|
||||
for (uint32_t k = 0U; k < self->fft_size; k++) {
|
||||
self->residual_spectrum[k] = fft_spectrum[k] - self->denoised_spectrum[k];
|
||||
}
|
||||
|
||||
// Mix denoised and residual - Now a simple toggle
|
||||
if (parameters.residual_listen) {
|
||||
for (uint32_t k = 0U; k < self->fft_size; k++) {
|
||||
fft_spectrum[k] = self->residual_spectrum[k];
|
||||
}
|
||||
} else {
|
||||
for (uint32_t k = 0U; k < self->fft_size; k++) {
|
||||
fft_spectrum[k] = self->denoised_spectrum[k];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef DENOISE_MIXER_H
|
||||
#define DENOISE_MIXER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct DenoiseMixerParameters {
|
||||
float noise_level;
|
||||
bool residual_listen;
|
||||
float whitening_amount;
|
||||
} DenoiseMixerParameters;
|
||||
|
||||
typedef struct DenoiseMixer DenoiseMixer;
|
||||
|
||||
DenoiseMixer* denoise_mixer_initialize(uint32_t fft_size, uint32_t sample_rate,
|
||||
uint32_t hop);
|
||||
void denoise_mixer_free(DenoiseMixer* self);
|
||||
bool denoise_mixer_run(DenoiseMixer* self, float* fft_spectrum,
|
||||
const float* gain_spectrum,
|
||||
DenoiseMixerParameters parameters);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "general_utils.h"
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
float sanitize_denormal(float value) {
|
||||
if (!isnormal(value)) {
|
||||
value = 0.F;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
float from_db_to_coefficient(const float value_db) {
|
||||
return expf(value_db / 20.F * logf(10.F));
|
||||
}
|
||||
|
||||
float remap_percentage_log_like_unity(const float value) {
|
||||
return 1.F - expf(-3.F * (value));
|
||||
}
|
||||
|
||||
int get_next_divisible_two(int number) {
|
||||
int q = number / 2;
|
||||
int n1 = 2 * q;
|
||||
int n2 = (number * 2) > 0 ? (2 * (q + 1)) : (2 * (q - 1));
|
||||
if (abs(number - n1) < abs(number - n2)) {
|
||||
return n1;
|
||||
}
|
||||
|
||||
return n2;
|
||||
}
|
||||
|
||||
int get_next_power_two(int number) {
|
||||
return (int)roundf(powf(2.F, ceilf(log2f((float)number))));
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef GENERAL_UTILS_H
|
||||
#define GENERAL_UTILS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Compile-time validation
|
||||
_Static_assert(sizeof(float) >= 4, "float must be at least 32 bits");
|
||||
_Static_assert(sizeof(double) >= 8, "double must be at least 64 bits");
|
||||
|
||||
__attribute__((warn_unused_result)) float sanitize_denormal(float value);
|
||||
__attribute__((warn_unused_result)) float from_db_to_coefficient(
|
||||
float value_db);
|
||||
__attribute__((warn_unused_result)) float remap_percentage_log_like_unity(
|
||||
float value);
|
||||
__attribute__((warn_unused_result)) int get_next_divisible_two(int number);
|
||||
__attribute__((warn_unused_result)) int get_next_power_two(int number);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
shared_sources += files(
|
||||
'general_utils.c',
|
||||
'denoise_mixer.c',
|
||||
'spectral_features.c',
|
||||
'spectral_utils.c',
|
||||
'spectral_trailing_buffer.c',
|
||||
)
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "spectral_features.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct SpectralFeatures {
|
||||
float* power_spectrum;
|
||||
float* phase_spectrum;
|
||||
float* magnitude_spectrum;
|
||||
|
||||
uint32_t real_spectrum_size;
|
||||
};
|
||||
|
||||
SpectralFeatures* spectral_features_initialize(
|
||||
const uint32_t real_spectrum_size) {
|
||||
SpectralFeatures* self =
|
||||
(SpectralFeatures*)calloc(1U, sizeof(SpectralFeatures));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->real_spectrum_size = real_spectrum_size;
|
||||
|
||||
self->power_spectrum =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
self->phase_spectrum =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
self->magnitude_spectrum =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
|
||||
if (!self->power_spectrum || !self->phase_spectrum ||
|
||||
!self->magnitude_spectrum) {
|
||||
spectral_features_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void spectral_features_free(SpectralFeatures* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
free(self->power_spectrum);
|
||||
free(self->phase_spectrum);
|
||||
free(self->magnitude_spectrum);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
float* get_power_spectrum(SpectralFeatures* self) {
|
||||
return self->power_spectrum;
|
||||
}
|
||||
float* get_magnitude_spectrum(SpectralFeatures* self) {
|
||||
return self->magnitude_spectrum;
|
||||
}
|
||||
float* get_phase_spectrum(SpectralFeatures* self) {
|
||||
return self->phase_spectrum;
|
||||
}
|
||||
|
||||
static bool compute_power_spectrum(SpectralFeatures* self,
|
||||
const float* fft_spectrum,
|
||||
const uint32_t fft_spectrum_size) {
|
||||
if (!self || !fft_spectrum || !fft_spectrum_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t n = fft_spectrum_size;
|
||||
const uint32_t n2 = n / 2U;
|
||||
const bool is_even = (n % 2U == 0);
|
||||
|
||||
// DC bin
|
||||
self->power_spectrum[0] = fft_spectrum[0] * fft_spectrum[0];
|
||||
|
||||
// Complex bins
|
||||
for (uint32_t k = 1U; k < n2; k++) {
|
||||
float real = fft_spectrum[k];
|
||||
float imag = fft_spectrum[n - k];
|
||||
self->power_spectrum[k] = (real * real) + (imag * imag);
|
||||
}
|
||||
|
||||
// Nyquist bin
|
||||
if (is_even) {
|
||||
self->power_spectrum[n2] = fft_spectrum[n2] * fft_spectrum[n2];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool compute_magnitude_spectrum(SpectralFeatures* self,
|
||||
const float* fft_spectrum,
|
||||
const uint32_t fft_spectrum_size) {
|
||||
if (!self || !fft_spectrum || !fft_spectrum_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t n = fft_spectrum_size;
|
||||
const uint32_t n2 = n / 2U;
|
||||
const bool is_even = (n % 2U == 0);
|
||||
|
||||
// DC bin
|
||||
self->magnitude_spectrum[0] = fabsf(fft_spectrum[0]);
|
||||
|
||||
// Complex bins
|
||||
for (uint32_t k = 1U; k < n2; k++) {
|
||||
self->magnitude_spectrum[k] = hypotf(fft_spectrum[k], fft_spectrum[n - k]);
|
||||
}
|
||||
|
||||
// Nyquist bin
|
||||
if (is_even) {
|
||||
self->magnitude_spectrum[n2] = fabsf(fft_spectrum[n2]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool compute_phase_spectrum(SpectralFeatures* self,
|
||||
const float* fft_spectrum,
|
||||
const uint32_t fft_spectrum_size) {
|
||||
if (!self || !fft_spectrum || !fft_spectrum_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t n = fft_spectrum_size;
|
||||
const uint32_t n2 = n / 2U;
|
||||
const bool is_even = (n % 2U == 0);
|
||||
|
||||
// DC bin - purely real
|
||||
self->phase_spectrum[0] = atan2f(0.F, fft_spectrum[0]);
|
||||
|
||||
// Complex bins
|
||||
for (uint32_t k = 1U; k < n2; k++) {
|
||||
float real = fft_spectrum[k];
|
||||
float imag = fft_spectrum[n - k];
|
||||
self->phase_spectrum[k] = atan2f(imag, real);
|
||||
}
|
||||
|
||||
// Nyquist bin - purely real
|
||||
if (is_even) {
|
||||
self->phase_spectrum[n2] = atan2f(0.F, fft_spectrum[n2]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float* get_spectral_feature(SpectralFeatures* self, const float* fft_spectrum,
|
||||
uint32_t fft_spectrum_size, SpectrumType type) {
|
||||
if (!self || !fft_spectrum || fft_spectrum_size == 0U) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case POWER_SPECTRUM:
|
||||
compute_power_spectrum(self, fft_spectrum, fft_spectrum_size);
|
||||
return get_power_spectrum(self);
|
||||
break;
|
||||
case MAGNITUDE_SPECTRUM:
|
||||
compute_magnitude_spectrum(self, fft_spectrum, fft_spectrum_size);
|
||||
return get_magnitude_spectrum(self);
|
||||
break;
|
||||
case PHASE_SPECTRUM:
|
||||
compute_phase_spectrum(self, fft_spectrum, fft_spectrum_size);
|
||||
return get_phase_spectrum(self);
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef SPECTRAL_FEATURES_H
|
||||
#define SPECTRAL_FEATURES_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct SpectralFeatures SpectralFeatures;
|
||||
|
||||
typedef enum SpectrumType {
|
||||
POWER_SPECTRUM = 0,
|
||||
MAGNITUDE_SPECTRUM = 1,
|
||||
PHASE_SPECTRUM = 2,
|
||||
} SpectrumType;
|
||||
|
||||
SpectralFeatures* spectral_features_initialize(uint32_t real_spectrum_size);
|
||||
void spectral_features_free(SpectralFeatures* self);
|
||||
float* get_spectral_feature(SpectralFeatures* self, const float* fft_spectrum,
|
||||
uint32_t fft_spectrum_size, SpectrumType type);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "spectral_trailing_buffer.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct SpectralTrailingBuffer {
|
||||
uint32_t real_spectrum_size;
|
||||
uint32_t buffer_size;
|
||||
|
||||
float* buffer;
|
||||
};
|
||||
|
||||
SpectralTrailingBuffer* spectral_trailing_buffer_initialize(
|
||||
const uint32_t real_spectrum_size, const uint32_t buffer_size) {
|
||||
SpectralTrailingBuffer* self =
|
||||
(SpectralTrailingBuffer*)calloc(1U, sizeof(SpectralTrailingBuffer));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->real_spectrum_size = real_spectrum_size;
|
||||
self->buffer_size = buffer_size;
|
||||
|
||||
self->buffer = (float*)calloc(
|
||||
((size_t)self->real_spectrum_size * (size_t)self->buffer_size),
|
||||
sizeof(float));
|
||||
|
||||
if (!self->buffer) {
|
||||
spectral_trailing_buffer_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void spectral_trailing_buffer_free(SpectralTrailingBuffer* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
free(self->buffer);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
bool spectral_trailing_buffer_push_back(SpectralTrailingBuffer* self,
|
||||
const float* input_spectrum) {
|
||||
if (!input_spectrum) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memmove(self->buffer, &self->buffer[self->real_spectrum_size],
|
||||
sizeof(float) * self->real_spectrum_size * (self->buffer_size - 1U));
|
||||
memcpy(&self->buffer[(size_t)self->real_spectrum_size *
|
||||
(size_t)(self->buffer_size - 1U)],
|
||||
input_spectrum, sizeof(float) * self->real_spectrum_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float* get_trailing_spectral_buffer(SpectralTrailingBuffer* self) {
|
||||
return self->buffer;
|
||||
}
|
||||
|
||||
uint32_t get_spectrum_buffer_size(SpectralTrailingBuffer* self) {
|
||||
return self->buffer_size;
|
||||
}
|
||||
|
||||
uint32_t get_spectrum_size(SpectralTrailingBuffer* self) {
|
||||
return self->real_spectrum_size;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef SPECTRAL_TRAILING_BUFFER_H
|
||||
#define SPECTRAL_TRAILING_BUFFER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct SpectralTrailingBuffer SpectralTrailingBuffer;
|
||||
|
||||
SpectralTrailingBuffer* spectral_trailing_buffer_initialize(
|
||||
uint32_t real_spectrum_size, uint32_t buffer_size);
|
||||
void spectral_trailing_buffer_free(SpectralTrailingBuffer* self);
|
||||
bool spectral_trailing_buffer_push_back(SpectralTrailingBuffer* self,
|
||||
const float* input_spectrum);
|
||||
float* get_trailing_spectral_buffer(SpectralTrailingBuffer* self);
|
||||
uint32_t get_spectrum_buffer_size(SpectralTrailingBuffer* self);
|
||||
uint32_t get_spectrum_size(SpectralTrailingBuffer* self);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "spectral_utils.h"
|
||||
#include "../configurations.h"
|
||||
#include "general_utils.h"
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static float blackman(const uint32_t bin_index, const uint32_t fft_size) {
|
||||
const float p = ((float)(bin_index)) / ((float)(fft_size));
|
||||
return sanitize_denormal(0.42F - (0.5F * cosf(2.F * M_PIf * p)) +
|
||||
(0.08F * cosf(4.F * M_PIf * p)));
|
||||
}
|
||||
|
||||
static float hanning(const uint32_t bin_index, const uint32_t fft_size) {
|
||||
const float p = ((float)(bin_index)) / ((float)(fft_size));
|
||||
return sanitize_denormal(0.5F - (0.5F * cosf(2.F * M_PIf * p)));
|
||||
}
|
||||
|
||||
static float hamming(const uint32_t bin_index, const uint32_t fft_size) {
|
||||
const float p = ((float)(bin_index)) / ((float)(fft_size));
|
||||
return sanitize_denormal(0.54F - (0.46F * cosf(2.F * M_PIf * p)));
|
||||
}
|
||||
|
||||
static float vorbis(const uint32_t bin_index, const uint32_t fft_size) {
|
||||
const float p = ((float)(bin_index)) / ((float)(fft_size));
|
||||
return sanitize_denormal(sinf(M_PIf / 2.F * powf(sinf(M_PIf * p), 2.F)));
|
||||
}
|
||||
|
||||
bool get_fft_window(float* window, const uint32_t fft_size,
|
||||
const WindowTypes window_type) {
|
||||
if (!window || !fft_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t k = 0; k < fft_size; k++) {
|
||||
switch (window_type) {
|
||||
case HANN_WINDOW:
|
||||
window[k] = hanning(k, fft_size);
|
||||
break;
|
||||
case HAMMING_WINDOW:
|
||||
window[k] = hamming(k, fft_size);
|
||||
break;
|
||||
case BLACKMAN_WINDOW:
|
||||
window[k] = blackman(k, fft_size);
|
||||
break;
|
||||
case VORBIS_WINDOW:
|
||||
window[k] = vorbis(k, fft_size);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool initialize_spectrum_with_value(float* spectrum, uint32_t spectrum_size,
|
||||
const float value) {
|
||||
if (!spectrum || spectrum_size == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0U; i < spectrum_size; i++) {
|
||||
spectrum[i] = value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float max_spectral_value(const float* spectrum,
|
||||
const uint32_t real_spectrum_size) {
|
||||
if (!spectrum || real_spectrum_size == 0U) {
|
||||
return 0.F;
|
||||
}
|
||||
|
||||
float max = spectrum[0];
|
||||
for (uint32_t k = 1U; k < real_spectrum_size; k++) {
|
||||
max = fmaxf(spectrum[k], max);
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
float min_spectral_value(const float* spectrum,
|
||||
const uint32_t real_spectrum_size) {
|
||||
if (!spectrum || real_spectrum_size == 0U) {
|
||||
return 0.F;
|
||||
}
|
||||
|
||||
float min = spectrum[0];
|
||||
for (uint32_t k = 1U; k < real_spectrum_size; k++) {
|
||||
min = fminf(spectrum[k], min);
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
bool min_spectrum_float(float* spectrum_one, const float* spectrum_two,
|
||||
const uint32_t spectrum_size) {
|
||||
if (!spectrum_one || !spectrum_two || spectrum_size == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t k = 0; k < spectrum_size; k++) {
|
||||
spectrum_one[k] = fminf(spectrum_one[k], spectrum_two[k]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool max_spectrum_float(float* spectrum_one, const float* spectrum_two,
|
||||
const uint32_t spectrum_size) {
|
||||
if (!spectrum_one || !spectrum_two || spectrum_size == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t k = 0; k < spectrum_size; k++) {
|
||||
spectrum_one[k] = fmaxf(spectrum_one[k], spectrum_two[k]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool min_spectrum_double(double* spectrum_one, const double* spectrum_two,
|
||||
const uint32_t spectrum_size) {
|
||||
if (!spectrum_one || !spectrum_two || spectrum_size == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t k = 0; k < spectrum_size; k++) {
|
||||
spectrum_one[k] = fmin(spectrum_one[k], spectrum_two[k]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool max_spectrum_double(double* spectrum_one, const double* spectrum_two,
|
||||
const uint32_t spectrum_size) {
|
||||
if (!spectrum_one || !spectrum_two || spectrum_size == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t k = 0; k < spectrum_size; k++) {
|
||||
spectrum_one[k] = fmax(spectrum_one[k], spectrum_two[k]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool direct_matrix_to_vector_spectral_convolution(const float* matrix_spectum,
|
||||
const float* spectrum,
|
||||
float* out_spectrum,
|
||||
uint32_t spectrum_size) {
|
||||
if (!matrix_spectum || !spectrum || !out_spectrum || spectrum_size == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0U; i < spectrum_size; i++) {
|
||||
out_spectrum[i] = 0.F;
|
||||
for (uint32_t j = 0U; j < spectrum_size; j++) {
|
||||
out_spectrum[i] +=
|
||||
(matrix_spectum[(i * spectrum_size) + j] * spectrum[j]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float fft_bin_to_freq(const uint32_t bin_index, const uint32_t sample_rate,
|
||||
const uint32_t fft_size) {
|
||||
return (float)bin_index * ((float)sample_rate / (float)fft_size);
|
||||
}
|
||||
|
||||
uint32_t freq_to_fft_bin(const float freq, const uint32_t sample_rate,
|
||||
const uint32_t fft_size) {
|
||||
return (uint32_t)((freq / ((float)sample_rate / (float)fft_size)) + 0.5f);
|
||||
}
|
||||
|
||||
float spectral_flux(const float* spectrum, const float* previous_spectrum,
|
||||
const uint32_t spectrum_size) {
|
||||
if (!spectrum || !previous_spectrum || spectrum_size == 0U) {
|
||||
return 0.F;
|
||||
}
|
||||
|
||||
float spectral_flux = 0.F;
|
||||
|
||||
for (uint32_t i = 0U; i < spectrum_size; i++) {
|
||||
const float temp = sqrtf(spectrum[i]) - sqrtf(previous_spectrum[i]);
|
||||
spectral_flux += (temp + fabsf(temp)) / 2.F;
|
||||
}
|
||||
return spectral_flux;
|
||||
}
|
||||
|
||||
bool get_rolling_mean_spectrum(float* averaged_spectrum,
|
||||
const float* current_spectrum,
|
||||
const uint32_t number_of_blocks,
|
||||
const uint32_t spectrum_size) {
|
||||
if (!averaged_spectrum || !current_spectrum || spectrum_size == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t k = 0U; k < spectrum_size; k++) {
|
||||
if (number_of_blocks <= 1U) {
|
||||
averaged_spectrum[k] = current_spectrum[k];
|
||||
} else {
|
||||
averaged_spectrum[k] += (current_spectrum[k] - averaged_spectrum[k]) /
|
||||
(float)number_of_blocks;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int min_max_comparator(const void* a, const void* b) {
|
||||
float x = *(const float*)a;
|
||||
float y = *(const float*)b;
|
||||
|
||||
return x >= y ? 1 : -1;
|
||||
}
|
||||
|
||||
static float find_median(const float* array, uint32_t array_size) {
|
||||
float median = 0.F;
|
||||
|
||||
if (array_size % 2 == 0) {
|
||||
// if number of elements are even
|
||||
median = (array[(array_size - 1U) / 2U] + array[array_size / 2U]) / 2.F;
|
||||
} else {
|
||||
// if number of elements are odd
|
||||
median = array[array_size / 2U];
|
||||
}
|
||||
|
||||
return median;
|
||||
}
|
||||
|
||||
bool get_rolling_median_spectrum(float* median_spectrum,
|
||||
const float* current_spectrum_buffer,
|
||||
const uint32_t number_of_blocks,
|
||||
const uint32_t spectrum_size) {
|
||||
if (!median_spectrum || !current_spectrum_buffer || spectrum_size == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float tmp_buffer[number_of_blocks];
|
||||
|
||||
for (uint32_t i = 0U; i < spectrum_size; i++) {
|
||||
for (uint32_t j = 0U; j < number_of_blocks; j++) {
|
||||
tmp_buffer[j] = current_spectrum_buffer[(j * spectrum_size) + i];
|
||||
}
|
||||
|
||||
// Sorting array
|
||||
qsort(tmp_buffer, number_of_blocks, sizeof(float), min_max_comparator);
|
||||
|
||||
float median_of_buffer = find_median(tmp_buffer, number_of_blocks);
|
||||
|
||||
// Taking the max of the median
|
||||
if (median_of_buffer > median_spectrum[i]) {
|
||||
median_spectrum[i] = median_of_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
libspecbleach - A spectral processing library
|
||||
|
||||
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef SPECTRAL_UTILS_H
|
||||
#define SPECTRAL_UTILS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum WindowTypes {
|
||||
HANN_WINDOW = 0,
|
||||
HAMMING_WINDOW = 1,
|
||||
BLACKMAN_WINDOW = 2,
|
||||
VORBIS_WINDOW = 3
|
||||
} WindowTypes;
|
||||
|
||||
bool get_fft_window(float* window, uint32_t fft_size, WindowTypes window_type);
|
||||
bool initialize_spectrum_with_value(float* spectrum, uint32_t spectrum_size,
|
||||
float value);
|
||||
bool direct_matrix_to_vector_spectral_convolution(const float* matrix_spectum,
|
||||
const float* spectrum,
|
||||
float* out_spectrum,
|
||||
uint32_t spectrum_size);
|
||||
float max_spectral_value(const float* spectrum, uint32_t real_spectrum_size);
|
||||
float min_spectral_value(const float* spectrum, uint32_t real_spectrum_size);
|
||||
|
||||
#define min_spectrum(spectrum_one, spectrum_two, spectrum_size) \
|
||||
_Generic((spectrum_one), \
|
||||
float*: min_spectrum_float, \
|
||||
double*: min_spectrum_double, \
|
||||
default: min_spectrum_float)(spectrum_one, spectrum_two, spectrum_size)
|
||||
|
||||
#define max_spectrum(spectrum_one, spectrum_two, spectrum_size) \
|
||||
_Generic((spectrum_one), \
|
||||
float*: max_spectrum_float, \
|
||||
double*: max_spectrum_double, \
|
||||
default: max_spectrum_float)(spectrum_one, spectrum_two, spectrum_size)
|
||||
|
||||
bool min_spectrum_float(float* spectrum_one, const float* spectrum_two,
|
||||
uint32_t spectrum_size);
|
||||
bool max_spectrum_float(float* spectrum_one, const float* spectrum_two,
|
||||
uint32_t spectrum_size);
|
||||
bool min_spectrum_double(double* spectrum_one, const double* spectrum_two,
|
||||
uint32_t spectrum_size);
|
||||
bool max_spectrum_double(double* spectrum_one, const double* spectrum_two,
|
||||
uint32_t spectrum_size);
|
||||
float fft_bin_to_freq(uint32_t bin_index, uint32_t sample_rate,
|
||||
uint32_t fft_size);
|
||||
uint32_t freq_to_fft_bin(float freq, uint32_t sample_rate, uint32_t fft_size);
|
||||
float spectral_flux(const float* spectrum, const float* previous_spectrum,
|
||||
uint32_t spectrum_size);
|
||||
bool get_rolling_mean_spectrum(float* averaged_spectrum,
|
||||
const float* current_spectrum,
|
||||
uint32_t number_of_blocks,
|
||||
uint32_t spectrum_size);
|
||||
bool get_rolling_median_spectrum(float* median_spectrum,
|
||||
const float* current_spectrum_buffer,
|
||||
uint32_t number_of_blocks,
|
||||
uint32_t spectrum_size);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
Vendored
+1
@@ -0,0 +1 @@
|
||||
Jean-Marc Valin <jmvalin@jmvalin.ca>
|
||||
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
Copyright (c) 2007-2017, 2024 Jean-Marc Valin
|
||||
Copyright (c) 2023 Amazon
|
||||
Copyright (c) 2017, Mozilla
|
||||
Copyright (c) 2005-2017, Xiph.Org Foundation
|
||||
Copyright (c) 2003-2004, Mark Borgerding
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of the Xiph.Org Foundation nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
Vendored
+69
@@ -0,0 +1,69 @@
|
||||
#
|
||||
# Makefile for RNNOISE
|
||||
# This one creates librnnoise.a intended for static linking
|
||||
#
|
||||
# DL1YCF NOTE:
|
||||
# the "full model", rnnoise_data.c, does not compile on RaspPis
|
||||
# with only 1 GByte of memory, therefore this has now been split
|
||||
# into 6 files that can be compiled separately.
|
||||
#
|
||||
|
||||
CFLAGS?= -pthread -O3 -D_GNU_SOURCE -Wno-parentheses -Iinclude -Isrc
|
||||
|
||||
COMPILE=$(CC) $(CFLAGS)
|
||||
|
||||
SOURCES= \
|
||||
src/denoise.c \
|
||||
src/celt_lpc.c \
|
||||
src/kiss_fft.c \
|
||||
src/nnet.c \
|
||||
src/nnet_default.c \
|
||||
src/parse_lpcnet_weights.c \
|
||||
src/pitch.c \
|
||||
src/rnn.c \
|
||||
src/rnnoise_data.c \
|
||||
src/rnnoise_data_1.c \
|
||||
src/rnnoise_data_2.c \
|
||||
src/rnnoise_data_3.c \
|
||||
src/rnnoise_data_4.c \
|
||||
src/rnnoise_data_5.c \
|
||||
src/rnnoise_data_6.c \
|
||||
src/rnnoise_tables.c
|
||||
|
||||
OBJS= \
|
||||
src/denoise.o \
|
||||
src/celt_lpc.o \
|
||||
src/kiss_fft.o \
|
||||
src/nnet.o \
|
||||
src/nnet_default.o \
|
||||
src/parse_lpcnet_weights.o \
|
||||
src/pitch.o \
|
||||
src/rnn.o \
|
||||
src/rnnoise_data.o \
|
||||
src/rnnoise_data_1.o \
|
||||
src/rnnoise_data_2.o \
|
||||
src/rnnoise_data_3.o \
|
||||
src/rnnoise_data_4.o \
|
||||
src/rnnoise_data_5.o \
|
||||
src/rnnoise_data_6.o \
|
||||
src/rnnoise_tables.o
|
||||
|
||||
librnnoise.a: $(OBJS)
|
||||
ar rv librnnoise.a $(OBJS)
|
||||
ranlib librnnoise.a
|
||||
|
||||
.c.o:
|
||||
$(COMPILE) -c -o $@ $<
|
||||
|
||||
|
||||
clean:
|
||||
-rm -f librnnoise.a $(OBJS)
|
||||
|
||||
#############################################################################
|
||||
#
|
||||
# What follows is automatically generated by the "makedepend" program
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
# DO NOT DELETE
|
||||
|
||||
Vendored
+125
@@ -0,0 +1,125 @@
|
||||
RNNoise is a noise suppression library based on a recurrent neural network.
|
||||
A description of the algorithm is provided in the following paper:
|
||||
|
||||
J.-M. Valin, A Hybrid DSP/Deep Learning Approach to Real-Time Full-Band Speech
|
||||
Enhancement, Proceedings of IEEE Multimedia Signal Processing (MMSP) Workshop,
|
||||
arXiv:1709.08243, 2018.
|
||||
https://arxiv.org/pdf/1709.08243.pdf
|
||||
|
||||
An interactive demo of version 0.1 is available at: https://jmvalin.ca/demo/rnnoise/
|
||||
|
||||
To compile, just type:
|
||||
% ./autogen.sh
|
||||
% ./configure
|
||||
% make
|
||||
|
||||
Optionally:
|
||||
% make install
|
||||
|
||||
It is recommended to either set -march= in the CFLAGS to an architecture
|
||||
with AVX2 support or to add --enable-x86-rtcd to the configure script
|
||||
so that AVX2 (or SSE4.1) can at least be used as an option.
|
||||
Note that the autogen.sh script will automatically download the model files
|
||||
from the Xiph.Org servers, since those are too large to put in Git.
|
||||
|
||||
While it is meant to be used as a library, a simple command-line tool is
|
||||
provided as an example. It operates on RAW 16-bit (machine endian) mono
|
||||
PCM files sampled at 48 kHz. It can be used as:
|
||||
|
||||
% ./examples/rnnoise_demo <noisy speech> <output denoised>
|
||||
|
||||
The output is also a 16-bit raw PCM file.
|
||||
NOTE AGAIN, THE INPUT and OUTPUT ARE IN RAW FORMAT, NOT WAV.
|
||||
|
||||
The latest version of the source is available from
|
||||
https://gitlab.xiph.org/xiph/rnnoise . The GitHub repository
|
||||
is a convenience copy.
|
||||
|
||||
== Training ==
|
||||
|
||||
The models distributed with RNNoise are now trained using only the publicly
|
||||
available datasets listed below and using the training precedure described
|
||||
here. Exact results will still depend on the the exact mix of data used,
|
||||
on how long the training is performed and on the various random seeds involved.
|
||||
|
||||
To train an RNNoise model, you need both clean speech data, and noise data.
|
||||
Both need to be sampled at 48 kHz, in 16-bit PCM format (machine endian).
|
||||
Clean speech data can be obtained from the datasets listed in the datasets.txt
|
||||
file, or by downloaded the already-concatenation of those files in
|
||||
https://media.xiph.org/rnnoise/data/tts_speech_48k.sw
|
||||
For noise data, we suggest the background_noise.sw and foreground_noise.sw
|
||||
(or later versions) noise files from https://media.xiph.org/rnnoise/data/
|
||||
The foreground_noise.sw file contains noise signals that are meant to be added
|
||||
to the background noise (e.g. keyboard sounds). Optionally, the foreground noise
|
||||
file can even be denoised with a traditional denoiser (e.g. libspeexdsp) to
|
||||
keep only the transient components. For background noise, the data from the
|
||||
original RNNoise noise collection have now been sufficiently filtered to
|
||||
provide good results -- either alone or in combination with the
|
||||
background_noise.sw file. The dataset can be downloaded (updated Jan 30th 2025)
|
||||
from: https://media.xiph.org/rnnoise/rnnoise_contributions.tar.gz
|
||||
|
||||
The first step is to take the speech and noise, and mix them in a variety of
|
||||
ways to simulate real life conditions (including pauses, filtering and more).
|
||||
Assuming the files are called speech.pcm and noise.pcm, start by generating
|
||||
the training feature data with:
|
||||
|
||||
% ./dump_features speech.pcm background_noise.pcm foreground_noise.pcm features.f32 <count>
|
||||
where <count> is the number of sequences to process. The number of sequences
|
||||
should be at least 10000, but the more the better (200000 or more is
|
||||
recommended).
|
||||
|
||||
Optionally, training can also simulate reverberation, in which case room impulse
|
||||
responses (RIR) are also needed. Limited RIR data is available at:
|
||||
https://media.xiph.org/rnnoise/data/measured_rirs-v2.tar.gz
|
||||
The format for those is raw 32-bit floating-point (files are little endian).
|
||||
Assuming a list of all the RIR files is contained in a rir_list.txt file,
|
||||
the training feature data can be generated with:
|
||||
|
||||
% ./dump_features -rir_list rir_list.txt speech.pcm background_noise.pcm foreground_noise.pcm features.f32 <count>
|
||||
|
||||
To make the feature generation faster, you can use the script provided in
|
||||
script/dump_features_parallel.sh (you will need to modify the script if you
|
||||
want to add RIR augmentation).
|
||||
|
||||
To use it:
|
||||
% script/dump_features_parallel.sh ./dump_features speech.pcm background_noise.pcm foreground_noise.pcm features.f32 <count> rir_list.txt
|
||||
which will run nb_processes processes, each for count sequences, and
|
||||
concatenate the output to a single file.
|
||||
|
||||
Once the feature file is computed, you can start the training with:
|
||||
% python3 train_rnnoise.py features.f32 output_directory
|
||||
|
||||
Choose a number of epochs (using --epochs) that leads to about 75000 weight
|
||||
updates. The training will produce .pth files, e.g. rnnoise_50.pth .
|
||||
The next step is to convert the model to C files using:
|
||||
|
||||
% python3 dump_rnnoise_weights.py --quantize rnnoise_50.pth rnnoise_c
|
||||
|
||||
which will produce the rnnoise_data.c and rnnoise_data.h files in the
|
||||
rnnoise_c directory.
|
||||
|
||||
Copy these files to src/ and then build RNNoise using the instructions above.
|
||||
|
||||
For slightly better results, a trained model can be used to remove any noise
|
||||
from the "clean" training speech, before restaring the denoising process
|
||||
again (no need to do that more than once).
|
||||
|
||||
== Loadable Models ==
|
||||
|
||||
The model format has changed since v0.1.1. Models now use a binary
|
||||
"machine endian" format. To output a model in that format, build RNNoise
|
||||
with that model and use the dump_weights_blob executable to output a
|
||||
weights_blob.bin binary file. That file can then be used with the
|
||||
rnnoise_model_from_file() API call. Note that the model object MUST NOT
|
||||
be deleted while the RNNoise state is active and the file MUST NOT
|
||||
be closed.
|
||||
|
||||
To avoid including the default model in the build (e.g. to reduce download
|
||||
size) and rely only on model loading, add -DUSE_WEIGHTS_FILE to the CFLAGS.
|
||||
To be able to load different models, the model size (and header file) needs
|
||||
to patch the size use during build. Otherwise the model will not load
|
||||
We provide a "little" model with half as an alternative. To use the smaller
|
||||
model, rename rnnoise_data_little.c to rnnoise_data.c. It is possible
|
||||
to build both the regular and little binary weights and load any of them
|
||||
at run time since the little model has the same size as the regular one
|
||||
(except for the increased sparsity).
|
||||
Vendored
+61
@@ -0,0 +1,61 @@
|
||||
========================================================================================
|
||||
Notes from DL1YCF (Start)
|
||||
========================================================================================
|
||||
|
||||
The material put into piHPDSR is meant as a minimal model for the ease of the user,
|
||||
it is generally recommended to use "installed" versions of RNNoise compiled
|
||||
with CPU-specific optimisations etc.
|
||||
|
||||
The RNNoise code within pihpsdr comes from
|
||||
|
||||
https://github.com/xiph/rnnoise.git
|
||||
|
||||
A new "Makefile" has been provided that just compiles the files needed with standard
|
||||
optimisation levels. This means, that only the file
|
||||
|
||||
rnnoise/Makefile
|
||||
|
||||
within the pihpsdr directory differ from those in https://github.com/xiph/rnnoise.git.
|
||||
|
||||
The RNNnoise model is not contained in the above repository but downloaded during
|
||||
installation of rnnoise. The model is originally contained in the files
|
||||
|
||||
rnnoise/src/rnnoise_data.c (originally, 80 MByte)
|
||||
rnnoise/src/rnnoise_data.h (1 KByte)
|
||||
|
||||
The file rnnoise_data.c (80 MByte) is not only larger that the recommended
|
||||
maximum file size in github (50 MByte), its compilation runs out of memory
|
||||
on RaspPis with only 1 GByte of main memory. Therefore it has been split
|
||||
into six parts. This means, rnnoise_data.c has been changed (it is now only
|
||||
16 KByte long) and most of its contents have been moved to the following
|
||||
six header files:
|
||||
|
||||
rnnoise/src/rnnoise_data_1.h (16 MByte)
|
||||
rnnoise/src/rnnoise_data_2.h (13 MByte)
|
||||
rnnoise/src/rnnoise_data_3.h (12 MByte)
|
||||
rnnoise/src/rnnoise_data_4.h (14 MByte)
|
||||
rnnoise/src/rnnoise_data_5.h (11 MByte)
|
||||
rnnoise/src/rnnoise_data_6.h ( 9 MByte)
|
||||
|
||||
The following six *.c files, each of this is < 100 Bytes long, each include one
|
||||
of these header files and can be compiled separately:
|
||||
|
||||
rnnoise/src/rnnoise_data_1.c
|
||||
rnnoise/src/rnnoise_data_2.c
|
||||
rnnoise/src/rnnoise_data_3.c
|
||||
rnnoise/src/rnnoise_data_4.c
|
||||
rnnoise/src/rnnoise_data_5.c
|
||||
rnnoise/src/rnnoise_data_6.c
|
||||
|
||||
These changes now make it possible to compile pihpsdr with rnnnoise on a RaspPi
|
||||
or a RaspPi ComputeModul with only 1 GByte of main memory.
|
||||
|
||||
Consequences:
|
||||
|
||||
Upgrading the model (that is, adapting a new file rnnoise/src/rnnoise_data.c) is somewhat
|
||||
involved. Upgrading rnnoise itself (*.h and *.c files in rnnoise/src other than rnnoise_data.c
|
||||
and rnnoise_data.h) is straightforward.
|
||||
|
||||
========================================================================================
|
||||
Notes from DL1YCF (End)
|
||||
========================================================================================
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/* Copyright (c) 2018 Gregor Richards
|
||||
* Copyright (c) 2017 Mozilla */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef RNNOISE_H
|
||||
#define RNNOISE_H 1
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef RNNOISE_EXPORT
|
||||
# if defined(WIN32)
|
||||
# if defined(RNNOISE_BUILD) && defined(DLL_EXPORT)
|
||||
# define RNNOISE_EXPORT __declspec(dllexport)
|
||||
# else
|
||||
# define RNNOISE_EXPORT
|
||||
# endif
|
||||
# elif defined(__GNUC__) && defined(RNNOISE_BUILD)
|
||||
# define RNNOISE_EXPORT __attribute__ ((visibility ("default")))
|
||||
# else
|
||||
# define RNNOISE_EXPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
typedef struct DenoiseState DenoiseState;
|
||||
typedef struct RNNModel RNNModel;
|
||||
|
||||
/**
|
||||
* Return the size of DenoiseState
|
||||
*/
|
||||
RNNOISE_EXPORT int rnnoise_get_size(void);
|
||||
|
||||
/**
|
||||
* Return the number of samples processed by rnnoise_process_frame at a time
|
||||
*/
|
||||
RNNOISE_EXPORT int rnnoise_get_frame_size(void);
|
||||
|
||||
/**
|
||||
* Initializes a pre-allocated DenoiseState
|
||||
*
|
||||
* If model is NULL the default model is used.
|
||||
*
|
||||
* See: rnnoise_create() and rnnoise_model_from_file()
|
||||
*/
|
||||
RNNOISE_EXPORT int rnnoise_init(DenoiseState *st, RNNModel *model);
|
||||
|
||||
/**
|
||||
* Allocate and initialize a DenoiseState
|
||||
*
|
||||
* If model is NULL the default model is used.
|
||||
*
|
||||
* The returned pointer MUST be freed with rnnoise_destroy().
|
||||
*/
|
||||
RNNOISE_EXPORT DenoiseState *rnnoise_create(RNNModel *model);
|
||||
|
||||
/**
|
||||
* Free a DenoiseState produced by rnnoise_create.
|
||||
*
|
||||
* The optional custom model must be freed by rnnoise_model_free() after.
|
||||
*/
|
||||
RNNOISE_EXPORT void rnnoise_destroy(DenoiseState *st);
|
||||
|
||||
/**
|
||||
* Denoise a frame of samples
|
||||
*
|
||||
* in and out must be at least rnnoise_get_frame_size() large.
|
||||
*/
|
||||
RNNOISE_EXPORT float rnnoise_process_frame(DenoiseState *st, float *out, const float *in);
|
||||
|
||||
/**
|
||||
* Load a model from a memory buffer
|
||||
*
|
||||
* It must be deallocated with rnnoise_model_free() and the buffer must remain
|
||||
* valid until after the returned object is destroyed.
|
||||
*/
|
||||
RNNOISE_EXPORT RNNModel *rnnoise_model_from_buffer(const void *ptr, int len);
|
||||
|
||||
|
||||
/**
|
||||
* Load a model from a file
|
||||
*
|
||||
* It must be deallocated with rnnoise_model_free() and the file must not be
|
||||
* closed until the returned object is destroyed.
|
||||
*/
|
||||
RNNOISE_EXPORT RNNModel *rnnoise_model_from_file(FILE *f);
|
||||
|
||||
/**
|
||||
* Load a model from a file name
|
||||
*
|
||||
* It must be deallocated with rnnoise_model_free()
|
||||
*/
|
||||
RNNOISE_EXPORT RNNModel *rnnoise_model_from_filename(const char *filename);
|
||||
|
||||
/**
|
||||
* Free a custom model
|
||||
*
|
||||
* It must be called after all the DenoiseStates referring to it are freed.
|
||||
*/
|
||||
RNNOISE_EXPORT void rnnoise_model_free(RNNModel *model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Vendored
BIN
Binary file not shown.
+182
@@ -0,0 +1,182 @@
|
||||
/*Copyright (c) 2003-2004, Mark Borgerding
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.*/
|
||||
|
||||
#ifndef KISS_FFT_GUTS_H
|
||||
#define KISS_FFT_GUTS_H
|
||||
|
||||
#define MIN(a,b) ((a)<(b) ? (a):(b))
|
||||
#define MAX(a,b) ((a)>(b) ? (a):(b))
|
||||
|
||||
/* kiss_fft.h
|
||||
defines kiss_fft_scalar as either short or a float type
|
||||
and defines
|
||||
typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */
|
||||
#include "kiss_fft.h"
|
||||
|
||||
/*
|
||||
Explanation of macros dealing with complex math:
|
||||
|
||||
C_MUL(m,a,b) : m = a*b
|
||||
C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise
|
||||
C_SUB( res, a,b) : res = a - b
|
||||
C_SUBFROM( res , a) : res -= a
|
||||
C_ADDTO( res , a) : res += a
|
||||
* */
|
||||
#ifdef FIXED_POINT
|
||||
#include "arch.h"
|
||||
|
||||
|
||||
#define SAMP_MAX 2147483647
|
||||
#define TWID_MAX 32767
|
||||
#define TRIG_UPSCALE 1
|
||||
|
||||
#define SAMP_MIN -SAMP_MAX
|
||||
|
||||
|
||||
# define S_MUL(a,b) MULT16_32_Q15(b, a)
|
||||
|
||||
# define C_MUL(m,a,b) \
|
||||
do{ (m).r = SUB32_ovflw(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
|
||||
(m).i = ADD32_ovflw(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)); }while(0)
|
||||
|
||||
# define C_MULC(m,a,b) \
|
||||
do{ (m).r = ADD32_ovflw(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
|
||||
(m).i = SUB32_ovflw(S_MUL((a).i,(b).r) , S_MUL((a).r,(b).i)); }while(0)
|
||||
|
||||
# define C_MULBYSCALAR( c, s ) \
|
||||
do{ (c).r = S_MUL( (c).r , s ) ;\
|
||||
(c).i = S_MUL( (c).i , s ) ; }while(0)
|
||||
|
||||
# define DIVSCALAR(x,k) \
|
||||
(x) = S_MUL( x, (TWID_MAX-((k)>>1))/(k)+1 )
|
||||
|
||||
# define C_FIXDIV(c,div) \
|
||||
do { DIVSCALAR( (c).r , div); \
|
||||
DIVSCALAR( (c).i , div); }while (0)
|
||||
|
||||
#define C_ADD( res, a,b)\
|
||||
do {(res).r=ADD32_ovflw((a).r,(b).r); (res).i=ADD32_ovflw((a).i,(b).i); \
|
||||
}while(0)
|
||||
#define C_SUB( res, a,b)\
|
||||
do {(res).r=SUB32_ovflw((a).r,(b).r); (res).i=SUB32_ovflw((a).i,(b).i); \
|
||||
}while(0)
|
||||
#define C_ADDTO( res , a)\
|
||||
do {(res).r = ADD32_ovflw((res).r, (a).r); (res).i = ADD32_ovflw((res).i,(a).i);\
|
||||
}while(0)
|
||||
|
||||
#define C_SUBFROM( res , a)\
|
||||
do {(res).r = ADD32_ovflw((res).r,(a).r); (res).i = SUB32_ovflw((res).i,(a).i); \
|
||||
}while(0)
|
||||
|
||||
#if defined(OPUS_ARM_INLINE_ASM)
|
||||
#include "arm/kiss_fft_armv4.h"
|
||||
#endif
|
||||
|
||||
#if defined(OPUS_ARM_INLINE_EDSP)
|
||||
#include "arm/kiss_fft_armv5e.h"
|
||||
#endif
|
||||
#if defined(MIPSr1_ASM)
|
||||
#include "mips/kiss_fft_mipsr1.h"
|
||||
#endif
|
||||
|
||||
#else /* not FIXED_POINT*/
|
||||
|
||||
# define S_MUL(a,b) ( (a)*(b) )
|
||||
#define C_MUL(m,a,b) \
|
||||
do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
|
||||
(m).i = (a).r*(b).i + (a).i*(b).r; }while(0)
|
||||
#define C_MULC(m,a,b) \
|
||||
do{ (m).r = (a).r*(b).r + (a).i*(b).i;\
|
||||
(m).i = (a).i*(b).r - (a).r*(b).i; }while(0)
|
||||
|
||||
#define C_MUL4(m,a,b) C_MUL(m,a,b)
|
||||
|
||||
# define C_FIXDIV(c,div) /* NOOP */
|
||||
# define C_MULBYSCALAR( c, s ) \
|
||||
do{ (c).r *= (s);\
|
||||
(c).i *= (s); }while(0)
|
||||
#endif
|
||||
|
||||
#ifndef CHECK_OVERFLOW_OP
|
||||
# define CHECK_OVERFLOW_OP(a,op,b) /* noop */
|
||||
#endif
|
||||
|
||||
#ifndef C_ADD
|
||||
#define C_ADD( res, a,b)\
|
||||
do { \
|
||||
CHECK_OVERFLOW_OP((a).r,+,(b).r)\
|
||||
CHECK_OVERFLOW_OP((a).i,+,(b).i)\
|
||||
(res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \
|
||||
}while(0)
|
||||
#define C_SUB( res, a,b)\
|
||||
do { \
|
||||
CHECK_OVERFLOW_OP((a).r,-,(b).r)\
|
||||
CHECK_OVERFLOW_OP((a).i,-,(b).i)\
|
||||
(res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \
|
||||
}while(0)
|
||||
#define C_ADDTO( res , a)\
|
||||
do { \
|
||||
CHECK_OVERFLOW_OP((res).r,+,(a).r)\
|
||||
CHECK_OVERFLOW_OP((res).i,+,(a).i)\
|
||||
(res).r += (a).r; (res).i += (a).i;\
|
||||
}while(0)
|
||||
|
||||
#define C_SUBFROM( res , a)\
|
||||
do {\
|
||||
CHECK_OVERFLOW_OP((res).r,-,(a).r)\
|
||||
CHECK_OVERFLOW_OP((res).i,-,(a).i)\
|
||||
(res).r -= (a).r; (res).i -= (a).i; \
|
||||
}while(0)
|
||||
#endif /* C_ADD defined */
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
/*# define KISS_FFT_COS(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase))))
|
||||
# define KISS_FFT_SIN(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase))))*/
|
||||
# define KISS_FFT_COS(phase) floor(.5+TWID_MAX*cos (phase))
|
||||
# define KISS_FFT_SIN(phase) floor(.5+TWID_MAX*sin (phase))
|
||||
# define HALF_OF(x) ((x)>>1)
|
||||
#elif defined(USE_SIMD)
|
||||
# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) )
|
||||
# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) )
|
||||
# define HALF_OF(x) ((x)*_mm_set1_ps(.5f))
|
||||
#else
|
||||
# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase)
|
||||
# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase)
|
||||
# define HALF_OF(x) ((x)*.5f)
|
||||
#endif
|
||||
|
||||
#define kf_cexp(x,phase) \
|
||||
do{ \
|
||||
(x)->r = KISS_FFT_COS(phase);\
|
||||
(x)->i = KISS_FFT_SIN(phase);\
|
||||
}while(0)
|
||||
|
||||
#define kf_cexp2(x,phase) \
|
||||
do{ \
|
||||
(x)->r = TRIG_UPSCALE*celt_cos_norm((phase));\
|
||||
(x)->i = TRIG_UPSCALE*celt_cos_norm((phase)-32768);\
|
||||
}while(0)
|
||||
|
||||
#endif /* KISS_FFT_GUTS_H */
|
||||
Vendored
+261
@@ -0,0 +1,261 @@
|
||||
/* Copyright (c) 2003-2008 Jean-Marc Valin
|
||||
Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/**
|
||||
@file arch.h
|
||||
@brief Various architecture definitions for CELT
|
||||
*/
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef ARCH_H
|
||||
#define ARCH_H
|
||||
|
||||
#include "opus_types.h"
|
||||
#include "common.h"
|
||||
|
||||
# if !defined(__GNUC_PREREQ)
|
||||
# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
|
||||
# define __GNUC_PREREQ(_maj,_min) \
|
||||
((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
|
||||
# else
|
||||
# define __GNUC_PREREQ(_maj,_min) 0
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#define CELT_SIG_SCALE 32768.f
|
||||
|
||||
#define celt_fatal(str) _celt_fatal(str, __FILE__, __LINE__);
|
||||
#ifdef ENABLE_ASSERTIONS
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef __GNUC__
|
||||
__attribute__((noreturn))
|
||||
#endif
|
||||
static OPUS_INLINE void _celt_fatal(const char *str, const char *file, int line)
|
||||
{
|
||||
fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str);
|
||||
abort();
|
||||
}
|
||||
#define celt_assert(cond) {if (!(cond)) {celt_fatal("assertion failed: " #cond);}}
|
||||
#define celt_assert2(cond, message) {if (!(cond)) {celt_fatal("assertion failed: " #cond "\n" message);}}
|
||||
#else
|
||||
#define celt_assert(cond)
|
||||
#define celt_assert2(cond, message)
|
||||
#endif
|
||||
|
||||
#define IMUL32(a,b) ((a)*(b))
|
||||
|
||||
#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 16-bit value. */
|
||||
#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */
|
||||
#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 32-bit value. */
|
||||
#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */
|
||||
#define IMIN(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum int value. */
|
||||
#define IMAX(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum int value. */
|
||||
#define UADD32(a,b) ((a)+(b))
|
||||
#define USUB32(a,b) ((a)-(b))
|
||||
|
||||
/* Set this if opus_int64 is a native type of the CPU. */
|
||||
/* Assume that all LP64 architectures have fast 64-bit types; also x86_64
|
||||
(which can be ILP32 for x32) and Win64 (which is LLP64). */
|
||||
#if defined(__x86_64__) || defined(__LP64__) || defined(_WIN64)
|
||||
#define OPUS_FAST_INT64 1
|
||||
#else
|
||||
#define OPUS_FAST_INT64 0
|
||||
#endif
|
||||
|
||||
#define PRINT_MIPS(file)
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
|
||||
typedef opus_int16 opus_val16;
|
||||
typedef opus_int32 opus_val32;
|
||||
typedef opus_int64 opus_val64;
|
||||
|
||||
typedef opus_val32 celt_sig;
|
||||
typedef opus_val16 celt_norm;
|
||||
typedef opus_val32 celt_ener;
|
||||
|
||||
#define Q15ONE 32767
|
||||
|
||||
#define SIG_SHIFT 12
|
||||
/* Safe saturation value for 32-bit signals. Should be less than
|
||||
2^31*(1-0.85) to avoid blowing up on DC at deemphasis.*/
|
||||
#define SIG_SAT (300000000)
|
||||
|
||||
#define NORM_SCALING 16384
|
||||
|
||||
#define DB_SHIFT 10
|
||||
|
||||
#define EPSILON 1
|
||||
#define VERY_SMALL 0
|
||||
#define VERY_LARGE16 ((opus_val16)32767)
|
||||
#define Q15_ONE ((opus_val16)32767)
|
||||
|
||||
#define SCALEIN(a) (a)
|
||||
#define SCALEOUT(a) (a)
|
||||
|
||||
#define ABS16(x) ((x) < 0 ? (-(x)) : (x))
|
||||
#define ABS32(x) ((x) < 0 ? (-(x)) : (x))
|
||||
|
||||
static OPUS_INLINE opus_int16 SAT16(opus_int32 x) {
|
||||
return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x;
|
||||
}
|
||||
|
||||
#ifdef FIXED_DEBUG
|
||||
#include "fixed_debug.h"
|
||||
#else
|
||||
|
||||
#include "fixed_generic.h"
|
||||
|
||||
#ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR
|
||||
#include "arm/fixed_arm64.h"
|
||||
#elif OPUS_ARM_INLINE_EDSP
|
||||
#include "arm/fixed_armv5e.h"
|
||||
#elif defined (OPUS_ARM_INLINE_ASM)
|
||||
#include "arm/fixed_armv4.h"
|
||||
#elif defined (BFIN_ASM)
|
||||
#include "fixed_bfin.h"
|
||||
#elif defined (TI_C5X_ASM)
|
||||
#include "fixed_c5x.h"
|
||||
#elif defined (TI_C6X_ASM)
|
||||
#include "fixed_c6x.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#else /* FIXED_POINT */
|
||||
|
||||
typedef float opus_val16;
|
||||
typedef float opus_val32;
|
||||
typedef float opus_val64;
|
||||
|
||||
typedef float celt_sig;
|
||||
typedef float celt_norm;
|
||||
typedef float celt_ener;
|
||||
|
||||
#ifdef FLOAT_APPROX
|
||||
/* This code should reliably detect NaN/inf even when -ffast-math is used.
|
||||
Assumes IEEE 754 format. */
|
||||
static OPUS_INLINE int celt_isnan(float x)
|
||||
{
|
||||
union {float f; opus_uint32 i;} in;
|
||||
in.f = x;
|
||||
return ((in.i>>23)&0xFF)==0xFF && (in.i&0x007FFFFF)!=0;
|
||||
}
|
||||
#else
|
||||
#ifdef __FAST_MATH__
|
||||
#error Cannot build libopus with -ffast-math unless FLOAT_APPROX is defined. This could result in crashes on extreme (e.g. NaN) input
|
||||
#endif
|
||||
#define celt_isnan(x) ((x)!=(x))
|
||||
#endif
|
||||
|
||||
#define Q15ONE 1.0f
|
||||
|
||||
#define NORM_SCALING 1.f
|
||||
|
||||
#define EPSILON 1e-15f
|
||||
#define VERY_SMALL 1e-30f
|
||||
#define VERY_LARGE16 1e15f
|
||||
#define Q15_ONE ((opus_val16)1.f)
|
||||
|
||||
/* This appears to be the same speed as C99's fabsf() but it's more portable. */
|
||||
#define ABS16(x) ((float)fabs(x))
|
||||
#define ABS32(x) ((float)fabs(x))
|
||||
|
||||
#define QCONST16(x,bits) (x)
|
||||
#define QCONST32(x,bits) (x)
|
||||
|
||||
#define NEG16(x) (-(x))
|
||||
#define NEG32(x) (-(x))
|
||||
#define NEG32_ovflw(x) (-(x))
|
||||
#define EXTRACT16(x) (x)
|
||||
#define EXTEND32(x) (x)
|
||||
#define SHR16(a,shift) (a)
|
||||
#define SHL16(a,shift) (a)
|
||||
#define SHR32(a,shift) (a)
|
||||
#define SHL32(a,shift) (a)
|
||||
#define PSHR32(a,shift) (a)
|
||||
#define VSHR32(a,shift) (a)
|
||||
|
||||
#define PSHR(a,shift) (a)
|
||||
#define SHR(a,shift) (a)
|
||||
#define SHL(a,shift) (a)
|
||||
#define SATURATE(x,a) (x)
|
||||
#define SATURATE16(x) (x)
|
||||
|
||||
#define ROUND16(a,shift) (a)
|
||||
#define SROUND16(a,shift) (a)
|
||||
#define HALF16(x) (.5f*(x))
|
||||
#define HALF32(x) (.5f*(x))
|
||||
|
||||
#define ADD16(a,b) ((a)+(b))
|
||||
#define SUB16(a,b) ((a)-(b))
|
||||
#define ADD32(a,b) ((a)+(b))
|
||||
#define SUB32(a,b) ((a)-(b))
|
||||
#define ADD32_ovflw(a,b) ((a)+(b))
|
||||
#define SUB32_ovflw(a,b) ((a)-(b))
|
||||
#define MULT16_16_16(a,b) ((a)*(b))
|
||||
#define MULT16_16(a,b) ((opus_val32)(a)*(opus_val32)(b))
|
||||
#define MAC16_16(c,a,b) ((c)+(opus_val32)(a)*(opus_val32)(b))
|
||||
|
||||
#define MULT16_32_Q15(a,b) ((a)*(b))
|
||||
#define MULT16_32_Q16(a,b) ((a)*(b))
|
||||
|
||||
#define MULT32_32_Q31(a,b) ((a)*(b))
|
||||
|
||||
#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b))
|
||||
#define MAC16_32_Q16(c,a,b) ((c)+(a)*(b))
|
||||
|
||||
#define MULT16_16_Q11_32(a,b) ((a)*(b))
|
||||
#define MULT16_16_Q11(a,b) ((a)*(b))
|
||||
#define MULT16_16_Q13(a,b) ((a)*(b))
|
||||
#define MULT16_16_Q14(a,b) ((a)*(b))
|
||||
#define MULT16_16_Q15(a,b) ((a)*(b))
|
||||
#define MULT16_16_P15(a,b) ((a)*(b))
|
||||
#define MULT16_16_P13(a,b) ((a)*(b))
|
||||
#define MULT16_16_P14(a,b) ((a)*(b))
|
||||
#define MULT16_32_P16(a,b) ((a)*(b))
|
||||
|
||||
#define DIV32_16(a,b) (((opus_val32)(a))/(opus_val16)(b))
|
||||
#define DIV32(a,b) (((opus_val32)(a))/(opus_val32)(b))
|
||||
|
||||
#define SCALEIN(a) ((a)*CELT_SIG_SCALE)
|
||||
#define SCALEOUT(a) ((a)*(1/CELT_SIG_SCALE))
|
||||
|
||||
#define SIG2WORD16(x) (x)
|
||||
|
||||
#endif /* !FIXED_POINT */
|
||||
|
||||
#ifndef GLOBAL_STACK_SIZE
|
||||
#ifdef FIXED_POINT
|
||||
#define GLOBAL_STACK_SIZE 120000
|
||||
#else
|
||||
#define GLOBAL_STACK_SIZE 120000
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* ARCH_H */
|
||||
Vendored
+174
@@ -0,0 +1,174 @@
|
||||
/* Copyright (c) 2009-2010 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "celt_lpc.h"
|
||||
#include "arch.h"
|
||||
#include "common.h"
|
||||
#include "pitch.h"
|
||||
#include "denoise.h"
|
||||
|
||||
void rnn_lpc(
|
||||
opus_val16 *_lpc, /* out: [0...p-1] LPC coefficients */
|
||||
const opus_val32 *ac, /* in: [0...p] autocorrelation values */
|
||||
int p
|
||||
)
|
||||
{
|
||||
int i, j;
|
||||
opus_val32 r;
|
||||
opus_val32 error = ac[0];
|
||||
#ifdef FIXED_POINT
|
||||
opus_val32 lpc[LPC_ORDER];
|
||||
#else
|
||||
float *lpc = _lpc;
|
||||
#endif
|
||||
|
||||
RNN_CLEAR(lpc, p);
|
||||
if (ac[0] != 0)
|
||||
{
|
||||
for (i = 0; i < p; i++) {
|
||||
/* Sum up this iteration's reflection coefficient */
|
||||
opus_val32 rr = 0;
|
||||
for (j = 0; j < i; j++)
|
||||
rr += MULT32_32_Q31(lpc[j],ac[i - j]);
|
||||
rr += SHR32(ac[i + 1],3);
|
||||
r = -SHL32(rr,3)/error;
|
||||
/* Update LPC coefficients and total error */
|
||||
lpc[i] = SHR32(r,3);
|
||||
for (j = 0; j < (i+1)>>1; j++)
|
||||
{
|
||||
opus_val32 tmp1, tmp2;
|
||||
tmp1 = lpc[j];
|
||||
tmp2 = lpc[i-1-j];
|
||||
lpc[j] = tmp1 + MULT32_32_Q31(r,tmp2);
|
||||
lpc[i-1-j] = tmp2 + MULT32_32_Q31(r,tmp1);
|
||||
}
|
||||
|
||||
error = error - MULT32_32_Q31(MULT32_32_Q31(r,r),error);
|
||||
/* Bail out once we get 30 dB gain */
|
||||
#ifdef FIXED_POINT
|
||||
if (error<SHR32(ac[0],10))
|
||||
break;
|
||||
#else
|
||||
if (error<.001f*ac[0])
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef FIXED_POINT
|
||||
for (i=0;i<p;i++)
|
||||
_lpc[i] = ROUND16(lpc[i],16);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int rnn_autocorr(
|
||||
const opus_val16 *x, /* in: [0...n-1] samples x */
|
||||
opus_val32 *ac, /* out: [0...lag-1] ac values */
|
||||
const opus_val16 *window,
|
||||
int overlap,
|
||||
int lag,
|
||||
int n)
|
||||
{
|
||||
opus_val32 d;
|
||||
int i, k;
|
||||
int fastN=n-lag;
|
||||
int shift;
|
||||
const opus_val16 *xptr;
|
||||
opus_val16 xx[PITCH_BUF_SIZE/2];
|
||||
celt_assert(n>0);
|
||||
celt_assert(n<=PITCH_BUF_SIZE/2)
|
||||
celt_assert(overlap>=0);
|
||||
if (overlap == 0)
|
||||
{
|
||||
xptr = x;
|
||||
} else {
|
||||
for (i=0;i<n;i++)
|
||||
xx[i] = x[i];
|
||||
for (i=0;i<overlap;i++)
|
||||
{
|
||||
xx[i] = MULT16_16_Q15(x[i],window[i]);
|
||||
xx[n-i-1] = MULT16_16_Q15(x[n-i-1],window[i]);
|
||||
}
|
||||
xptr = xx;
|
||||
}
|
||||
shift=0;
|
||||
#ifdef FIXED_POINT
|
||||
{
|
||||
opus_val32 ac0;
|
||||
ac0 = 1+(n<<7);
|
||||
if (n&1) ac0 += SHR32(MULT16_16(xptr[0],xptr[0]),9);
|
||||
for(i=(n&1);i<n;i+=2)
|
||||
{
|
||||
ac0 += SHR32(MULT16_16(xptr[i],xptr[i]),9);
|
||||
ac0 += SHR32(MULT16_16(xptr[i+1],xptr[i+1]),9);
|
||||
}
|
||||
|
||||
shift = celt_ilog2(ac0)-30+10;
|
||||
shift = (shift)/2;
|
||||
if (shift>0)
|
||||
{
|
||||
for(i=0;i<n;i++)
|
||||
xx[i] = PSHR32(xptr[i], shift);
|
||||
xptr = xx;
|
||||
} else
|
||||
shift = 0;
|
||||
}
|
||||
#endif
|
||||
rnn_pitch_xcorr(xptr, xptr, ac, fastN, lag+1);
|
||||
for (k=0;k<=lag;k++)
|
||||
{
|
||||
for (i = k+fastN, d = 0; i < n; i++)
|
||||
d = MAC16_16(d, xptr[i], xptr[i-k]);
|
||||
ac[k] += d;
|
||||
}
|
||||
#ifdef FIXED_POINT
|
||||
shift = 2*shift;
|
||||
if (shift<=0)
|
||||
ac[0] += SHL32((opus_int32)1, -shift);
|
||||
if (ac[0] < 268435456)
|
||||
{
|
||||
int shift2 = 29 - EC_ILOG(ac[0]);
|
||||
for (i=0;i<=lag;i++)
|
||||
ac[i] = SHL32(ac[i], shift2);
|
||||
shift -= shift2;
|
||||
} else if (ac[0] >= 536870912)
|
||||
{
|
||||
int shift2=1;
|
||||
if (ac[0] >= 1073741824)
|
||||
shift2++;
|
||||
for (i=0;i<=lag;i++)
|
||||
ac[i] = SHR32(ac[i], shift2);
|
||||
shift += shift2;
|
||||
}
|
||||
#endif
|
||||
|
||||
return shift;
|
||||
}
|
||||
Vendored
+45
@@ -0,0 +1,45 @@
|
||||
/* Copyright (c) 2009-2010 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef PLC_H
|
||||
#define PLC_H
|
||||
|
||||
#include "arch.h"
|
||||
#include "common.h"
|
||||
|
||||
#if defined(OPUS_X86_MAY_HAVE_SSE4_1)
|
||||
#include "x86/celt_lpc_sse.h"
|
||||
#endif
|
||||
|
||||
#define LPC_ORDER 24
|
||||
|
||||
void rnn_lpc(opus_val16 *_lpc, const opus_val32 *ac, int p);
|
||||
|
||||
int rnn_autocorr(const opus_val16 *x, opus_val32 *ac,
|
||||
const opus_val16 *window, int overlap, int lag, int n);
|
||||
|
||||
#endif /* PLC_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user