Merge from branch bqresample

This commit is contained in:
Chris Cannam
2021-05-11 08:21:17 +01:00
26 changed files with 635 additions and 215 deletions

View File

@@ -11,3 +11,4 @@ efbc861f9b9460068c48a250232d343ffa7d5726 v1.7
d4911a276d96f6232a68c6b8448056d3946043b9 v1.8.1
fa6a54be7e6bf0c5adffd19ccec622481a8140a5 v1.8.2
37b18c17c042eafc39483ffb58837de844ba3289 v1.9
7af7a76bbb1dc75f630555e22ca8f6ae9da79529 v1.9.1

View File

@@ -1,4 +1,24 @@
Changes in Rubber Band v1.9.1
* Switch build system from Makefiles and Visual Studio project to
Meson/Ninja for all platforms. There are still Makefiles and VS
projects included in otherbuilds/ for those who wish to use them to
build the static library directly
* Make various fixes to improve sound quality when pitch-shifting
dynamically in real-time (requires libsamplerate)
* Fix floating-point exception when a very very long stretch factor
is presented
* Move the two directories that together provide the .NET interface
(rubberband-sharp and rubberband-dll) into their own subdir (dotnet)
* Ensure the library builds and runs correctly on ARM Mac (Apple
Silicon, M1), and also on Windows using the Visual C++ Clang
front-end
The API is unchanged and the library is binary compatible with
version 1.7.
Changes in Rubber Band v1.9
* Fix incorrect numbering of pitch speed/quality flags in the

View File

@@ -31,7 +31,7 @@ PROJECT_NAME = "Rubber Band Library"
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER = 1.9.0
PROJECT_NUMBER = 1.9.1
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.

View File

@@ -225,25 +225,28 @@ $ make -f otherbuilds/Makefile.linux
Ensure the Xcode command-line tools are installed, and ideally also
install libsamplerate and libsndfile.
To build for the native architecture of the build machine:
To build for the default architecture:
```
$ meson build && ninja -C build
```
To build for Intel (x86_64) regardless of the native architecture:
Which architecture is the default may depend on the version of Meson
and/or the current shell. To force a particular architecture you can
use a Meson cross-file, as follows.
```
$ meson build --cross-file cross/macos-x86_64.txt && ninja -C build
```
To build for Apple Silicon (arm64) regardless of the native
architecture:
To build for Apple Silicon (arm64):
```
$ meson build --cross-file cross/macos-arm64.txt && ninja -C build
```
To build for Intel (x86_64):
```
$ meson build --cross-file cross/macos-x86_64.txt && ninja -C build
```
You can build a universal binary library for both architectures like
this:
@@ -317,6 +320,13 @@ The Rubber Band code is compatible with both the traditional Visual
C++ compiler (`cl`) and the Clang front-end (`clang`), and the build
system will use whichever appears (first) in your path.
To build against a specific Visual C++ runtime, use the built-in Meson
option `b_vscrt`:
```
> meson build -Db_vscrt=mt
```
See "FFT and resampler selection" below for further build options.
Alternatively, if you only need the static library and prefer a Visual

View File

@@ -11,6 +11,7 @@ needs_exe_wrapper = false
c = 'cc'
cpp = 'c++'
strip = 'strip'
pkgconfig = 'pkg-config'
[built-in options]
c_args = ['-arch', 'arm64']

View File

@@ -11,6 +11,7 @@ needs_exe_wrapper = false
c = 'cc'
cpp = 'c++'
strip = 'strip'
pkgconfig = 'pkg-config'
[built-in options]
c_args = ['-arch', 'arm64', '-arch', 'x86_64']

View File

@@ -11,6 +11,7 @@ needs_exe_wrapper = false
c = 'cc'
cpp = 'c++'
strip = 'strip'
pkgconfig = 'pkg-config'
[built-in options]
c_args = ['-arch', 'x86_64']

View File

@@ -799,11 +799,19 @@ int main(int argc, char **argv)
usleep(10000);
}
}
delete[] fbuf;
for (size_t i = 0; i < channels; ++i) delete[] ibuf[i];
delete[] ibuf;
}
sf_close(sndfile);
sf_close(sndfileOut);
free(fileName);
free(fileNameOut);
if (!quiet) {
cerr << "in: " << countIn << ", out: " << countOut << ", ratio: " << float(countOut)/float(countIn) << ", ideal output: " << lrint(countIn * ratio) << ", error: " << abs(lrint(countIn * ratio) - int(countOut)) << endl;

View File

@@ -2,7 +2,7 @@
project(
'Rubber Band Library',
'c', 'cpp',
version: '1.9.0',
version: '1.9.1',
license: 'GPL-2.0-or-later',
default_options: [
# All Rubber Band code is actually C++98, but some compilers no
@@ -15,9 +15,9 @@ project(
meson_version: '>= 0.53.0'
)
rubberband_dynamic_library_version = '2.1.2'
rubberband_dynamic_library_version = '2.1.3'
system = build_machine.system()
system = host_machine.system()
architecture = host_machine.cpu_family()
cpp = meson.get_compiler('cpp')
@@ -90,12 +90,21 @@ general_include_dirs = [
# Scan for any dependencies we may use later; all are optional
extra_include_args = []
foreach d: get_option('extra_include_dirs')
extra_include_args += [ '-I' + d ]
endforeach
fftw3_dep = dependency('fftw3', version: '>= 3.0.0', required: false)
samplerate_dep = dependency('samplerate', version: '>= 0.1.8', required: false)
sndfile_dep = dependency('sndfile', version: '>= 1.0.16', required: false)
vamp_dep = dependency('vamp-sdk', version: '>= 2.9', required: false)
thread_dep = dependency('threads')
have_ladspa = cpp.has_header('ladspa.h')
have_ladspa = cpp.has_header('ladspa.h', args: extra_include_args)
have_jni = cpp.has_header('jni.h', args: extra_include_args)
javac = find_program('javac', required: false)
jar = find_program('jar', required: false)
# Check FFT and resampler options and set up dependencies and paths
@@ -131,11 +140,6 @@ if resampler == 'auto'
endif
endif
extra_include_args = []
foreach d: get_option('extra_include_dirs')
extra_include_args += [ '-I' + d ]
endforeach
if fft == 'kissfft'
config_summary += { 'FFT': 'KissFFT' }
message('For FFT: using KissFFT')
@@ -362,6 +366,7 @@ if system == 'windows'
rubberband_program_name = 'rubberband-program'
rubberband_ladspa_name = 'ladspa-rubberband'
rubberband_vamp_name = 'vamp-rubberband'
rubberband_jni_name = 'rubberband-jni'
# Meson likes libxxx.a even on Windows, and so might we for a
# new library, but not here
platform_static_name_prefix = ''
@@ -372,13 +377,14 @@ else
rubberband_program_name = 'rubberband'
rubberband_ladspa_name = 'ladspa-rubberband'
rubberband_vamp_name = 'vamp-rubberband'
rubberband_jni_name = 'rubberband-jni'
platform_static_name_prefix = 'lib'
platform_static_name_suffix = 'a'
endif
# And the build targets: Static and dynamic libraries, command-line
# utility, LADSPA plugin, Vamp plugin
# utility, LADSPA plugin, Vamp plugin, JNI library
message('Will build Rubber Band Library static library')
target_summary += { 'Static library': [ true, 'Name: ' + rubberband_static_name ] }
@@ -419,6 +425,55 @@ else
message('Not building Rubber Band Library dynamic library: no_shared option set')
endif
if have_jni and javac.found() and jar.found()
target_summary += { 'JNI library': [ true, 'Name: ' + rubberband_jni_name ] }
message('Will build Java Native Interface')
rubberband_jni = shared_library(
rubberband_jni_name,
jni_sources,
include_directories: general_include_dirs,
cpp_args: general_compile_args,
c_args: general_compile_args,
link_args: [
arch_flags,
feature_libraries,
],
dependencies: [
rubberband_static_dep,
general_dependencies,
],
# NB the JNI library is not versioned
install: true,
)
rubberband_class = custom_target(
'rubberband_class',
input: 'com/breakfastquay/rubberband/RubberBandStretcher.java',
output: 'RubberBandStretcher.class',
command: [ javac, '@INPUT@', '-d', '@OUTDIR@' ],
)
rubberband_jar = custom_target(
'rubberband_jar',
input: rubberband_class,
output: 'rubberband.jar',
command: [ jar, 'cvf', '@OUTPUT@', 'com/breakfastquay/rubberband/@INPUT@' ],
build_by_default: true,
)
else
target_summary += { 'JNI library': false }
if not have_jni
message('Not building Java Native Interface: jni.h header not found')
else
message('Not building Java Native Interface: Java compiler not found')
endif
endif
install_headers(
[ 'rubberband/RubberBandStretcher.h',
'rubberband/rubberband-c.h'
],
subdir: 'rubberband'
)
if have_ladspa
target_summary += { 'LADSPA plugin': [ true, 'Name: ' + rubberband_ladspa_name ] }
message('Will build LADSPA plugin')

33
otherbuilds/deploy/macos.sh Executable file
View File

@@ -0,0 +1,33 @@
#!/bin/bash
set -eu
if [ ! -f ../rba/deploy/macos/notarize.sh ]; then
echo "need notarize script in ../rba/deploy/macos"
fi
version=$(grep '^ *version:' meson.build | head -1 | sed "s/^.*'\([0-9][0-9.]*\)'.*$/\1/")
echo
echo "Packaging command-line utility for Mac for Rubber Band v$version..."
echo
rm -rf build
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig/ meson build --cross-file ./cross/macos-universal.txt
ninja -C build
./build/rubberband -V
key="Developer ID Application: Particular Programs Ltd (73F996B92S)"
mkdir -p packages
( cd build
codesign -s "$key" -fv --options runtime rubberband
zipfile="rubberband-$version-gpl-executable-macos.zip"
rm -f "$zipfile"
ditto -c -k rubberband "$zipfile"
../../rba/deploy/macos/notarize.sh "$zipfile" com.breakfastquay.rubberband
)
package_dir="rubberband-$version-gpl-executable-macos"
rm -rf "$package_dir"
mkdir "$package_dir"
cp build/rubberband "$package_dir"
cp CHANGELOG README.md COPYING "$package_dir"
tar cvjf "$package_dir.tar.bz2" "$package_dir"
mv "$package_dir.tar.bz2" packages/
rm -rf "$package_dir"
echo
echo "Done, package is in packages/$package_dir.tar.bz2"

59
otherbuilds/deploy/source.sh Executable file
View File

@@ -0,0 +1,59 @@
#!/bin/bash
set -eu
version=$(grep '^ *version:' meson.build | head -1 | sed "s/^.*'\([0-9][0-9.]*\)'.*$/\1/")
check() {
text="$1"
echo -n "$text [yN] "
read yn
case "$yn" in [Yy]) ;; *) echo "Exiting"; exit 3 ;; esac
}
echo
echo "Preparing to make source package for Rubber Band v$version..."
echo
grep '^ *version:' meson.build | head -1
check "Is the above version number (in meson.build) correct?"
echo
echo "The dynamic library version should have a point increment for each"
echo "release, a minor increment for backward-compatible ABI changes, and"
echo "a major increment for incompatible ABI changes."
echo
grep 'rubberband_dynamic_library_version' meson.build | head -1
check "Is the above library version (from meson.build) correct?"
echo
echo "The API major version should increment for incompatible API changes,"
echo "and the minor version should increment for backward-compatible API"
echo "changes."
echo
grep 'RUBBERBAND.*VERSION' rubberband/RubberBandStretcher.h
check "Are the above version and API versions (from the C++ header) correct?"
echo
echo "The C header should contain the same versions as the C++ header."
echo
grep 'RUBBERBAND.*VERSION' rubberband/rubberband-c.h
check "Are the above version and API versions (from the C header) correct?"
echo
grep '^PROJECT_NUMBER' Doxyfile
check "Is the above version (from Doxyfile) correct?"
echo
echo "Going ahead..."
mkdir -p packages
output="packages/rubberband-$version.tar.bz2"
hg archive --exclude otherbuilds/deploy "$output"
echo "Checking that the package compiles..."
tmpdir=$(mktemp -d)
cleanup() {
rm -rf "$tmpdir"
}
trap cleanup 0
prevdir=$(pwd)
( cd "$tmpdir"
tar xvf "$prevdir/$output"
cd "rubberband-$version"
meson build
ninja -C build
)
echo
echo "Checked, package is in $output"

View File

@@ -0,0 +1,54 @@
echo on
set STARTPWD=%CD%
set ORIGINALPATH=%PATH%
set PATH=C:\Program Files (x86)\Windows Kits\10\bin\x64;%PATH%
set vcvarsall="C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat"
if not exist %vcvarsall% (
@ echo "Could not find MSVC vars batch file"
@ exit /b 2
)
set VERSION=%1
shift
if "%VERSION%" == "" (
@echo "Usage: win.bat <version>"
exit /b 1
)
@echo Building version %VERSION%
call %vcvarsall% amd64
if errorlevel 1 exit /b %errorlevel%
del /q /s build
meson build --buildtype release "-Dextra_include_dirs=C:\Program Files\libsndfile\include" "-Dextra_lib_dirs=C:\Program Files\libsndfile\lib" "-Db_vscrt=mt"
if errorlevel 1 exit /b %errorlevel%
ninja -C build
if errorlevel 1 exit /b %errorlevel%
cd build
ren rubberband-program.exe rubberband.exe
set NAME=Christopher Cannam
signtool sign /v /n "%NAME%" /t http://time.certum.pl /fd sha1 /a rubberband.exe
if errorlevel 1 exit /b %errorlevel%
cd ..
set DIR=rubberband-%VERSION%-gpl-executable-windows
del /q /s %DIR%
mkdir %DIR%
copy build\rubberband.exe %DIR%
copy "c:\Program Files\libsndfile\bin\sndfile.dll" %DIR%
copy COPYING %DIR%
copy README.md %DIR%
copy CHANGELOG %DIR%
set PATH=%ORIGINALPATH%
cd %STARTPWD%
@echo Done, now test and zip the directory %DIR%

View File

@@ -24,7 +24,7 @@
#ifndef RUBBERBAND_STRETCHER_H
#define RUBBERBAND_STRETCHER_H
#define RUBBERBAND_VERSION "1.9.0"
#define RUBBERBAND_VERSION "1.9.1"
#define RUBBERBAND_API_MAJOR_VERSION 2
#define RUBBERBAND_API_MINOR_VERSION 6
@@ -186,7 +186,7 @@ public:
* one processing thread per audio channel in offline mode if
* the stretcher is able to determine that more than one CPU is
* available, and one thread only in realtime mode. This is the
* defafult.
* default.
*
* \li \c OptionThreadingNever - Never use more than one thread.
*
@@ -464,7 +464,7 @@ public:
/**
* Change an OptionPitch configuration setting. This may be
* called at any time in RealTime mode. It may not be called in
* Offline mode (for which the transients option is fixed on
* Offline mode (for which the pitch option is fixed on
* construction).
*/
void setPitchOption(Options options);

View File

@@ -28,7 +28,7 @@
extern "C" {
#endif
#define RUBBERBAND_VERSION "1.9.0"
#define RUBBERBAND_VERSION "1.9.1"
#define RUBBERBAND_API_MAJOR_VERSION 2
#define RUBBERBAND_API_MINOR_VERSION 6

View File

@@ -58,7 +58,7 @@ HighFrequencyAudioCurve::processFloat(const float *R__ mag, int)
double
HighFrequencyAudioCurve::processDouble(const double *R__ mag, int)
{
float result = 0.0;
double result = 0.0;
const int sz = m_lastPerceivedBin;

View File

@@ -23,6 +23,8 @@
#include "Profiler.h"
#include "system/Thread.h"
#include <algorithm>
#include <set>
#include <string>
@@ -45,9 +47,13 @@ Profiler::m_profiles;
Profiler::WorstCallMap
Profiler::m_worstCalls;
static Mutex profileMutex;
void
Profiler::add(const char *id, float ms)
{
profileMutex.lock();
ProfileMap::iterator pmi = m_profiles.find(id);
if (pmi != m_profiles.end()) {
++pmi->second.first;
@@ -62,6 +68,8 @@ Profiler::add(const char *id, float ms)
} else {
m_worstCalls[id] = ms;
}
profileMutex.unlock();
}
void
@@ -74,6 +82,8 @@ Profiler::dump()
std::string
Profiler::getReport()
{
profileMutex.lock();
static const int buflen = 256;
char buffer[buflen];
std::string report;
@@ -167,6 +177,8 @@ Profiler::getReport()
report += buffer;
}
profileMutex.unlock();
return report;
}

View File

@@ -1851,7 +1851,7 @@ public:
dbuf[i] = realIn[i];
}
fftw_execute(m_dplanf);
v_convert(complexOut, (fft_double_type *)m_dpacked, sz + 2);
v_convert(complexOut, (const fft_double_type *)m_dpacked, sz + 2);
}
void forwardPolar(const double *R__ realIn, double *R__ magOut, double *R__ phaseOut) {
@@ -1865,8 +1865,8 @@ public:
dbuf[i] = realIn[i];
}
fftw_execute(m_dplanf);
v_cartesian_interleaved_to_polar(magOut, phaseOut,
(double *)m_dpacked, m_size/2+1);
v_cartesian_interleaved_to_polar
(magOut, phaseOut, (const fft_double_type *)m_dpacked, m_size/2+1);
}
void forwardMagnitude(const double *R__ realIn, double *R__ magOut) {
@@ -1880,11 +1880,8 @@ public:
dbuf[i] = realIn[i];
}
fftw_execute(m_dplanf);
const int hs = m_size/2;
for (int i = 0; i <= hs; ++i) {
magOut[i] = sqrt(m_dpacked[i][0] * m_dpacked[i][0] +
m_dpacked[i][1] * m_dpacked[i][1]);
}
v_cartesian_interleaved_to_magnitudes
(magOut, (const fft_double_type *)m_dpacked, m_size/2+1);
}
void forward(const float *R__ realIn, float *R__ realOut, float *R__ imagOut) {
@@ -1912,7 +1909,7 @@ public:
fbuf[i] = realIn[i];
}
fftwf_execute(m_fplanf);
v_convert(complexOut, (fft_float_type *)m_fpacked, sz + 2);
v_convert(complexOut, (const fft_float_type *)m_fpacked, sz + 2);
}
void forwardPolar(const float *R__ realIn, float *R__ magOut, float *R__ phaseOut) {
@@ -1926,8 +1923,8 @@ public:
fbuf[i] = realIn[i];
}
fftwf_execute(m_fplanf);
v_cartesian_interleaved_to_polar(magOut, phaseOut,
(float *)m_fpacked, m_size/2+1);
v_cartesian_interleaved_to_polar
(magOut, phaseOut, (fft_float_type *)m_fpacked, m_size/2+1);
}
void forwardMagnitude(const float *R__ realIn, float *R__ magOut) {
@@ -1941,11 +1938,8 @@ public:
fbuf[i] = realIn[i];
}
fftwf_execute(m_fplanf);
const int hs = m_size/2;
for (int i = 0; i <= hs; ++i) {
magOut[i] = sqrtf(m_fpacked[i][0] * m_fpacked[i][0] +
m_fpacked[i][1] * m_fpacked[i][1]);
}
v_cartesian_interleaved_to_magnitudes
(magOut, (const fft_float_type *)m_fpacked, m_size/2+1);
}
void inverse(const double *R__ realIn, const double *R__ imagIn, double *R__ realOut) {
@@ -1964,7 +1958,7 @@ public:
void inverseInterleaved(const double *R__ complexIn, double *R__ realOut) {
if (!m_dplanf) initDouble();
v_convert((double *)m_dpacked, complexIn, m_size + 2);
v_convert((fft_double_type *)m_dpacked, complexIn, m_size + 2);
fftw_execute(m_dplani);
const int sz = m_size;
fft_double_type *const R__ dbuf = m_dbuf;
@@ -1978,14 +1972,8 @@ public:
void inversePolar(const double *R__ magIn, const double *R__ phaseIn, double *R__ realOut) {
if (!m_dplanf) initDouble();
const int hs = m_size/2;
fftw_complex *const R__ dpacked = m_dpacked;
for (int i = 0; i <= hs; ++i) {
dpacked[i][0] = magIn[i] * cos(phaseIn[i]);
}
for (int i = 0; i <= hs; ++i) {
dpacked[i][1] = magIn[i] * sin(phaseIn[i]);
}
v_polar_to_cartesian_interleaved
((fft_double_type *)m_dpacked, magIn, phaseIn, m_size/2+1);
fftw_execute(m_dplani);
const int sz = m_size;
fft_double_type *const R__ dbuf = m_dbuf;
@@ -2034,7 +2022,7 @@ public:
void inverseInterleaved(const float *R__ complexIn, float *R__ realOut) {
if (!m_fplanf) initFloat();
v_copy((float *)m_fpacked, complexIn, m_size + 2);
v_convert((fft_float_type *)m_fpacked, complexIn, m_size + 2);
fftwf_execute(m_fplani);
const int sz = m_size;
fft_float_type *const R__ fbuf = m_fbuf;
@@ -2048,14 +2036,8 @@ public:
void inversePolar(const float *R__ magIn, const float *R__ phaseIn, float *R__ realOut) {
if (!m_fplanf) initFloat();
const int hs = m_size/2;
fftwf_complex *const R__ fpacked = m_fpacked;
for (int i = 0; i <= hs; ++i) {
fpacked[i][0] = magIn[i] * cosf(phaseIn[i]);
}
for (int i = 0; i <= hs; ++i) {
fpacked[i][1] = magIn[i] * sinf(phaseIn[i]);
}
v_polar_to_cartesian_interleaved
((fft_float_type *)m_fpacked, magIn, phaseIn, m_size/2+1);
fftwf_execute(m_fplani);
const int sz = m_size;
fft_float_type *const R__ fbuf = m_fbuf;
@@ -3258,6 +3240,7 @@ FFT::~FFT()
void
FFT::forward(const double *R__ realIn, double *R__ realOut, double *R__ imagOut)
{
Profiler profiler("FFT::forward");
CHECK_NOT_NULL(realIn);
CHECK_NOT_NULL(realOut);
CHECK_NOT_NULL(imagOut);
@@ -3267,6 +3250,7 @@ FFT::forward(const double *R__ realIn, double *R__ realOut, double *R__ imagOut)
void
FFT::forwardInterleaved(const double *R__ realIn, double *R__ complexOut)
{
Profiler profiler("FFT::forwardInterleaved");
CHECK_NOT_NULL(realIn);
CHECK_NOT_NULL(complexOut);
d->forwardInterleaved(realIn, complexOut);
@@ -3275,6 +3259,7 @@ FFT::forwardInterleaved(const double *R__ realIn, double *R__ complexOut)
void
FFT::forwardPolar(const double *R__ realIn, double *R__ magOut, double *R__ phaseOut)
{
Profiler profiler("FFT::forwardPolar");
CHECK_NOT_NULL(realIn);
CHECK_NOT_NULL(magOut);
CHECK_NOT_NULL(phaseOut);
@@ -3284,6 +3269,7 @@ FFT::forwardPolar(const double *R__ realIn, double *R__ magOut, double *R__ phas
void
FFT::forwardMagnitude(const double *R__ realIn, double *R__ magOut)
{
Profiler profiler("FFT::forwardMagnitude");
CHECK_NOT_NULL(realIn);
CHECK_NOT_NULL(magOut);
d->forwardMagnitude(realIn, magOut);
@@ -3292,6 +3278,7 @@ FFT::forwardMagnitude(const double *R__ realIn, double *R__ magOut)
void
FFT::forward(const float *R__ realIn, float *R__ realOut, float *R__ imagOut)
{
Profiler profiler("FFT::forward[float]");
CHECK_NOT_NULL(realIn);
CHECK_NOT_NULL(realOut);
CHECK_NOT_NULL(imagOut);
@@ -3301,6 +3288,7 @@ FFT::forward(const float *R__ realIn, float *R__ realOut, float *R__ imagOut)
void
FFT::forwardInterleaved(const float *R__ realIn, float *R__ complexOut)
{
Profiler profiler("FFT::forwardInterleaved[float]");
CHECK_NOT_NULL(realIn);
CHECK_NOT_NULL(complexOut);
d->forwardInterleaved(realIn, complexOut);
@@ -3309,6 +3297,7 @@ FFT::forwardInterleaved(const float *R__ realIn, float *R__ complexOut)
void
FFT::forwardPolar(const float *R__ realIn, float *R__ magOut, float *R__ phaseOut)
{
Profiler profiler("FFT::forwardPolar[float]");
CHECK_NOT_NULL(realIn);
CHECK_NOT_NULL(magOut);
CHECK_NOT_NULL(phaseOut);
@@ -3318,6 +3307,7 @@ FFT::forwardPolar(const float *R__ realIn, float *R__ magOut, float *R__ phaseOu
void
FFT::forwardMagnitude(const float *R__ realIn, float *R__ magOut)
{
Profiler profiler("FFT::forwardMagnitude[float]");
CHECK_NOT_NULL(realIn);
CHECK_NOT_NULL(magOut);
d->forwardMagnitude(realIn, magOut);
@@ -3326,6 +3316,7 @@ FFT::forwardMagnitude(const float *R__ realIn, float *R__ magOut)
void
FFT::inverse(const double *R__ realIn, const double *R__ imagIn, double *R__ realOut)
{
Profiler profiler("FFT::inverse");
CHECK_NOT_NULL(realIn);
CHECK_NOT_NULL(imagIn);
CHECK_NOT_NULL(realOut);
@@ -3335,6 +3326,7 @@ FFT::inverse(const double *R__ realIn, const double *R__ imagIn, double *R__ rea
void
FFT::inverseInterleaved(const double *R__ complexIn, double *R__ realOut)
{
Profiler profiler("FFT::inverseInterleaved");
CHECK_NOT_NULL(complexIn);
CHECK_NOT_NULL(realOut);
d->inverseInterleaved(complexIn, realOut);
@@ -3343,6 +3335,7 @@ FFT::inverseInterleaved(const double *R__ complexIn, double *R__ realOut)
void
FFT::inversePolar(const double *R__ magIn, const double *R__ phaseIn, double *R__ realOut)
{
Profiler profiler("FFT::inversePolar");
CHECK_NOT_NULL(magIn);
CHECK_NOT_NULL(phaseIn);
CHECK_NOT_NULL(realOut);
@@ -3352,6 +3345,7 @@ FFT::inversePolar(const double *R__ magIn, const double *R__ phaseIn, double *R_
void
FFT::inverseCepstral(const double *R__ magIn, double *R__ cepOut)
{
Profiler profiler("FFT::inverseCepstral");
CHECK_NOT_NULL(magIn);
CHECK_NOT_NULL(cepOut);
d->inverseCepstral(magIn, cepOut);
@@ -3360,6 +3354,7 @@ FFT::inverseCepstral(const double *R__ magIn, double *R__ cepOut)
void
FFT::inverse(const float *R__ realIn, const float *R__ imagIn, float *R__ realOut)
{
Profiler profiler("FFT::inverse[float]");
CHECK_NOT_NULL(realIn);
CHECK_NOT_NULL(imagIn);
CHECK_NOT_NULL(realOut);
@@ -3369,6 +3364,7 @@ FFT::inverse(const float *R__ realIn, const float *R__ imagIn, float *R__ realOu
void
FFT::inverseInterleaved(const float *R__ complexIn, float *R__ realOut)
{
Profiler profiler("FFT::inverseInterleaved[float]");
CHECK_NOT_NULL(complexIn);
CHECK_NOT_NULL(realOut);
d->inverseInterleaved(complexIn, realOut);
@@ -3377,6 +3373,7 @@ FFT::inverseInterleaved(const float *R__ complexIn, float *R__ realOut)
void
FFT::inversePolar(const float *R__ magIn, const float *R__ phaseIn, float *R__ realOut)
{
Profiler profiler("FFT::inversePolar[float]");
CHECK_NOT_NULL(magIn);
CHECK_NOT_NULL(phaseIn);
CHECK_NOT_NULL(realOut);
@@ -3386,6 +3383,7 @@ FFT::inversePolar(const float *R__ magIn, const float *R__ phaseIn, float *R__ r
void
FFT::inverseCepstral(const float *R__ magIn, float *R__ cepOut)
{
Profiler profiler("FFT::inverseCepstral[float]");
CHECK_NOT_NULL(magIn);
CHECK_NOT_NULL(cepOut);
d->inverseCepstral(magIn, cepOut);

View File

@@ -329,7 +329,6 @@ Java_com_breakfastquay_rubberband_RubberBandStretcher_study(JNIEnv *env, jobject
int channels = env->GetArrayLength(data);
float **arr = allocate<float *>(channels);
float **input = allocate<float *>(channels);
int samples = 0;
for (int c = 0; c < channels; ++c) {
jfloatArray cdata = (jfloatArray)env->GetObjectArrayElement(data, c);
arr[c] = env->GetFloatArrayElements(cdata, 0);
@@ -350,7 +349,6 @@ Java_com_breakfastquay_rubberband_RubberBandStretcher_process(JNIEnv *env, jobje
int channels = env->GetArrayLength(data);
float **arr = allocate<float *>(channels);
float **input = allocate<float *>(channels);
int samples = 0;
for (int c = 0; c < channels; ++c) {
jfloatArray cdata = (jfloatArray)env->GetObjectArrayElement(data, c);
arr[c] = env->GetFloatArrayElements(cdata, 0);
@@ -383,7 +381,7 @@ Java_com_breakfastquay_rubberband_RubberBandStretcher_retrieve(JNIEnv *env, jobj
float **outbuf = allocate_channels<float>(channels, n);
size_t retrieved = stretcher->retrieve(outbuf, n);
for (int c = 0; c < channels; ++c) {
for (size_t c = 0; c < channels; ++c) {
jfloatArray cdata = (jfloatArray)env->GetObjectArrayElement(output, c);
env->SetFloatArrayRegion(cdata, offset, retrieved, outbuf[c]);
}

View File

@@ -1,11 +1,11 @@
Copyright (c) 2003-2004 Mark Borgerding
Copyright (c) 2003-2010 Mark Borgerding . All rights reserved.
All rights reserved.
KISS FFT is provided under:
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
SPDX-License-Identifier: BSD-3-Clause
* 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 author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
Being under the terms of the BSD 3-clause "New" or "Revised" License,
according with:
LICENSES/BSD-3-Clause
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.

View File

@@ -1,25 +1,21 @@
/*
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.
* Neither the author nor the names of any 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 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
* Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
/* 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; */
#ifndef _kiss_fft_guts_h
#define _kiss_fft_guts_h
#include "kiss_fft.h"
#include "kiss_fft_log.h"
#include <limits.h>
#define MAXFACTORS 32
@@ -45,22 +41,23 @@ struct kiss_fft_state{
C_ADDTO( res , a) : res += a
* */
#ifdef FIXED_POINT
#include <stdint.h>
#if (FIXED_POINT==32)
# define FRACBITS 31
# define SAMPPROD int64_t
#define SAMP_MAX 2147483647
#define SAMP_MAX INT32_MAX
#define SAMP_MIN INT32_MIN
#else
# define FRACBITS 15
# define SAMPPROD int32_t
#define SAMP_MAX 32767
#define SAMP_MAX INT16_MAX
#define SAMP_MIN INT16_MIN
#endif
#define SAMP_MIN -SAMP_MAX
#if defined(CHECK_OVERFLOW)
# define CHECK_OVERFLOW_OP(a,op,b) \
if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \
fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) ); }
if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \
KISS_FFT_WARNING("overflow (%d " #op" %d) = %ld", (a),(b),(SAMPPROD)(a) op (SAMPPROD)(b)); }
#endif
@@ -74,11 +71,11 @@ struct kiss_fft_state{
(m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0)
# define DIVSCALAR(x,k) \
(x) = sround( smul( x, SAMP_MAX/k ) )
(x) = sround( smul( x, SAMP_MAX/k ) )
# define C_FIXDIV(c,div) \
do { DIVSCALAR( (c).r , div); \
DIVSCALAR( (c).i , div); }while (0)
do { DIVSCALAR( (c).r , div); \
DIVSCALAR( (c).i , div); }while (0)
# define C_MULBYSCALAR( c, s ) \
do{ (c).r = sround( smul( (c).r , s ) ) ;\
@@ -102,28 +99,28 @@ struct kiss_fft_state{
#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; \
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; \
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;\
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; \
CHECK_OVERFLOW_OP((res).r,-,(a).r)\
CHECK_OVERFLOW_OP((res).i,-,(a).i)\
(res).r -= (a).r; (res).i -= (a).i; \
}while(0)
@@ -138,18 +135,33 @@ struct kiss_fft_state{
#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)*.5)
# define HALF_OF(x) ((x)*((kiss_fft_scalar).5))
#endif
#define kf_cexp(x,phase) \
do{ \
(x)->r = KISS_FFT_COS(phase);\
(x)->i = KISS_FFT_SIN(phase);\
}while(0)
do{ \
(x)->r = KISS_FFT_COS(phase);\
(x)->i = KISS_FFT_SIN(phase);\
}while(0)
/* a debugging function */
#define pcpx(c)\
fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) )
KISS_FFT_DEBUG("%g + %gi\n",(double)((c)->r),(double)((c)->i))
#ifdef KISS_FFT_USE_ALLOCA
// define this to allow use of alloca instead of malloc for temporary buffers
// Temporary buffers are used in two case:
// 1. FFT sizes that have "bad" factors. i.e. not 2,3 and 5
// 2. "in-place" FFTs. Notice the quotes, since kissfft does not really do an in-place transform.
#include <alloca.h>
#define KISS_FFT_TMP_ALLOC(nbytes) alloca(nbytes)
#define KISS_FFT_TMP_FREE(ptr)
#else
#define KISS_FFT_TMP_ALLOC(nbytes) KISS_FFT_MALLOC(nbytes)
#define KISS_FFT_TMP_FREE(ptr) KISS_FFT_FREE(ptr)
#endif
#endif /* _kiss_fft_guts_h */

View File

@@ -1,16 +1,10 @@
/*
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.
* Neither the author nor the names of any 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 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.
*/
* Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#include "_kiss_fft_guts.h"
@@ -18,21 +12,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
fixed or floating point complex numbers. It also delares the kf_ internal functions.
*/
static kiss_fft_cpx *scratchbuf=NULL;
static size_t nscratchbuf=0;
static kiss_fft_cpx *tmpbuf=NULL;
static size_t ntmpbuf=0;
#define CHECKBUF(buf,nbuf,n) \
do { \
if ( nbuf < (size_t)(n) ) {\
free(buf); \
buf = (kiss_fft_cpx*)KISS_FFT_MALLOC(sizeof(kiss_fft_cpx)*(n)); \
nbuf = (size_t)(n); \
} \
}while(0)
static void kf_bfly2(
kiss_fft_cpx * Fout,
const size_t fstride,
@@ -69,6 +48,7 @@ static void kf_bfly4(
const size_t m2=2*m;
const size_t m3=3*m;
tw3 = tw2 = tw1 = st->twiddles;
do {
@@ -222,29 +202,34 @@ static void kf_bfly_generic(
kiss_fft_cpx t;
int Norig = st->nfft;
CHECKBUF(scratchbuf,nscratchbuf,p);
kiss_fft_cpx * scratch = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC(sizeof(kiss_fft_cpx)*p);
if (scratch == NULL){
KISS_FFT_ERROR("Memory allocation failed.");
return;
}
for ( u=0; u<m; ++u ) {
k=u;
for ( q1=0 ; q1<p ; ++q1 ) {
scratchbuf[q1] = Fout[ k ];
C_FIXDIV(scratchbuf[q1],p);
scratch[q1] = Fout[ k ];
C_FIXDIV(scratch[q1],p);
k += m;
}
k=u;
for ( q1=0 ; q1<p ; ++q1 ) {
int twidx=0;
Fout[ k ] = scratchbuf[0];
Fout[ k ] = scratch[0];
for (q=1;q<p;++q ) {
twidx += fstride * k;
if (twidx>=Norig) twidx-=Norig;
C_MUL(t,scratchbuf[q] , twiddles[twidx] );
C_MUL(t,scratch[q] , twiddles[twidx] );
C_ADDTO( Fout[ k ] ,t);
}
k += m;
}
}
KISS_FFT_TMP_FREE(scratch);
}
static
@@ -262,6 +247,30 @@ void kf_work(
const int m=*factors++; /* stage's fft length/p */
const kiss_fft_cpx * Fout_end = Fout + p*m;
#ifdef _OPENMP
// use openmp extensions at the
// top-level (not recursive)
if (fstride==1 && p<=5 && m!=1)
{
int k;
// execute the p different work units in different threads
# pragma omp parallel for
for (k=0;k<p;++k)
kf_work( Fout +k*m, f+ fstride*in_stride*k,fstride*p,in_stride,factors,st);
// all threads have joined by this point
switch (p) {
case 2: kf_bfly2(Fout,fstride,st,m); break;
case 3: kf_bfly3(Fout,fstride,st,m); break;
case 4: kf_bfly4(Fout,fstride,st,m); break;
case 5: kf_bfly5(Fout,fstride,st,m); break;
default: kf_bfly_generic(Fout,fstride,st,m,p); break;
}
return;
}
#endif
if (m==1) {
do{
*Fout = *f;
@@ -269,6 +278,10 @@ void kf_work(
}while(++Fout != Fout_end );
}else{
do{
// recursive call:
// DFT of size m*p performed by doing
// p instances of smaller DFTs of size m,
// each one takes a decimated version of the input
kf_work( Fout , f, fstride*p, in_stride, factors,st);
f += fstride*in_stride;
}while( (Fout += m) != Fout_end );
@@ -276,6 +289,7 @@ void kf_work(
Fout=Fout_beg;
// recombine the p smaller DFTs
switch (p) {
case 2: kf_bfly2(Fout,fstride,st,m); break;
case 3: kf_bfly3(Fout,fstride,st,m); break;
@@ -322,9 +336,11 @@ void kf_factor(int n,int * facbuf)
* */
kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem )
{
KISS_FFT_ALIGN_CHECK(mem)
kiss_fft_cfg st=NULL;
size_t memneeded = sizeof(struct kiss_fft_state)
+ sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/
size_t memneeded = KISS_FFT_ALIGN_SIZE_UP(sizeof(struct kiss_fft_state)
+ sizeof(kiss_fft_cpx)*(nfft-1)); /* twiddle factors*/
if ( lenmem==NULL ) {
st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded );
@@ -352,14 +368,27 @@ kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem
}
void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride)
{
if (fin == fout) {
CHECKBUF(tmpbuf,ntmpbuf,st->nfft);
//NOTE: this is not really an in-place FFT algorithm.
//It just performs an out-of-place FFT into a temp buffer
if (fout == NULL){
KISS_FFT_ERROR("fout buffer NULL.");
return;
}
kiss_fft_cpx * tmpbuf = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC( sizeof(kiss_fft_cpx)*st->nfft);
if (tmpbuf == NULL){
KISS_FFT_ERROR("Memory allocation error.");
return;
}
kf_work(tmpbuf,fin,1,in_stride, st->factors,st);
memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft);
KISS_FFT_TMP_FREE(tmpbuf);
}else{
kf_work( fout, fin, 1,in_stride, st->factors,st );
}
@@ -371,17 +400,9 @@ void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
}
/* not really necessary to call, but if someone is doing in-place ffts, they may want to free the
buffers from CHECKBUF
*/
void kiss_fft_cleanup(void)
{
free(scratchbuf);
scratchbuf = NULL;
nscratchbuf=0;
free(tmpbuf);
tmpbuf=NULL;
ntmpbuf=0;
// nothing needed any more
}
int kiss_fft_next_fast_size(int n)

View File

@@ -1,12 +1,32 @@
/*
* Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#ifndef KISS_FFT_H
#define KISS_FFT_H
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <memory.h>
#ifndef __APPLE__
#include <malloc.h>
#include <string.h>
// Define KISS_FFT_SHARED macro to properly export symbols
#ifdef KISS_FFT_SHARED
# ifdef _WIN32
# ifdef KISS_FFT_BUILD
# define KISS_FFT_API __declspec(dllexport)
# else
# define KISS_FFT_API __declspec(dllimport)
# endif
# else
# define KISS_FFT_API __attribute__ ((visibility ("default")))
# endif
#else
# define KISS_FFT_API
#endif
#ifdef __cplusplus
@@ -26,17 +46,32 @@ extern "C" {
in the tools/ directory.
*/
/* User may override KISS_FFT_MALLOC and/or KISS_FFT_FREE. */
#ifdef USE_SIMD
# include <xmmintrin.h>
# define kiss_fft_scalar __m128
#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes)
# ifndef KISS_FFT_MALLOC
# define KISS_FFT_MALLOC(nbytes) _mm_malloc(nbytes,16)
# define KISS_FFT_ALIGN_CHECK(ptr)
# define KISS_FFT_ALIGN_SIZE_UP(size) ((size + 15UL) & ~0xFUL)
# endif
# ifndef KISS_FFT_FREE
# define KISS_FFT_FREE _mm_free
# endif
#else
#define KISS_FFT_MALLOC malloc
# define KISS_FFT_ALIGN_CHECK(ptr)
# define KISS_FFT_ALIGN_SIZE_UP(size) (size)
# ifndef KISS_FFT_MALLOC
# define KISS_FFT_MALLOC malloc
# endif
# ifndef KISS_FFT_FREE
# define KISS_FFT_FREE free
# endif
#endif
#ifdef FIXED_POINT
#include <sys/types.h>
#include <stdint.h>
# if (FIXED_POINT == 32)
# define kiss_fft_scalar int32_t
# else
@@ -79,7 +114,7 @@ typedef struct kiss_fft_state* kiss_fft_cfg;
* buffer size in *lenmem.
* */
kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem);
kiss_fft_cfg KISS_FFT_API kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem);
/*
* kiss_fft(cfg,in_out_buf)
@@ -91,28 +126,32 @@ kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem)
* Note that each element is complex and can be accessed like
f[k].r and f[k].i
* */
void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
void KISS_FFT_API kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
/*
A more generic version of the above function. It reads its input from every Nth sample.
* */
void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride);
void KISS_FFT_API kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride);
/* If kiss_fft_alloc allocated a buffer, it is one contiguous
buffer and can be simply free()d when no longer needed*/
#define kiss_fft_free free
#define kiss_fft_free KISS_FFT_FREE
/*
Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up
your compiler output to call this before you exit.
*/
void kiss_fft_cleanup(void);
void KISS_FFT_API kiss_fft_cleanup(void);
/*
* Returns the smallest integer k, such that k>=n and k has only "fast" factors (2,3,5)
*/
int kiss_fft_next_fast_size(int n);
int KISS_FFT_API kiss_fft_next_fast_size(int n);
/* for real ffts, we need an even size */
#define kiss_fftr_next_fast_size_real(n) \
(kiss_fft_next_fast_size( ((n)+1)>>1)<<1)
#ifdef __cplusplus
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#ifndef kiss_fft_log_h
#define kiss_fft_log_h
#define ERROR 1
#define WARNING 2
#define INFO 3
#define DEBUG 4
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#if defined(NDEBUG)
# define KISS_FFT_LOG_MSG(severity, ...) ((void)0)
#else
# define KISS_FFT_LOG_MSG(severity, ...) \
fprintf(stderr, "[" #severity "] " __FILE__ ":" TOSTRING(__LINE__) " "); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n")
#endif
#define KISS_FFT_ERROR(...) KISS_FFT_LOG_MSG(ERROR, __VA_ARGS__)
#define KISS_FFT_WARNING(...) KISS_FFT_LOG_MSG(WARNING, __VA_ARGS__)
#define KISS_FFT_INFO(...) KISS_FFT_LOG_MSG(INFO, __VA_ARGS__)
#define KISS_FFT_DEBUG(...) KISS_FFT_LOG_MSG(DEBUG, __VA_ARGS__)
#endif /* kiss_fft_log_h */

View File

@@ -1,16 +1,10 @@
/*
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.
* Neither the author nor the names of any 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 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.
*/
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#include "kiss_fftr.h"
#include "_kiss_fft_guts.h"
@@ -20,24 +14,26 @@ struct kiss_fftr_state{
kiss_fft_cpx * tmpbuf;
kiss_fft_cpx * super_twiddles;
#ifdef USE_SIMD
long pad;
void * pad;
#endif
};
kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem)
{
KISS_FFT_ALIGN_CHECK(mem)
int i;
kiss_fftr_cfg st = NULL;
size_t subsize, memneeded;
size_t subsize = 0, memneeded;
if (nfft & 1) {
fprintf(stderr,"Real FFT optimization must be even.\n");
KISS_FFT_ERROR("Real FFT optimization must be even.");
return NULL;
}
nfft >>= 1;
kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize);
memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 2);
memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 3 / 2);
if (lenmem == NULL) {
st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded);
@@ -54,9 +50,9 @@ kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenme
st->super_twiddles = st->tmpbuf + nfft;
kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize);
for (i = 0; i < nfft; ++i) {
for (i = 0; i < nfft/2; ++i) {
double phase =
-3.14159265358979323846264338327 * ((double) i / nfft + .5);
-3.14159265358979323846264338327 * ((double) (i+1) / nfft + .5);
if (inverse_fft)
phase *= -1;
kf_cexp (st->super_twiddles+i,phase);
@@ -71,8 +67,8 @@ void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *fr
kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc;
if ( st->substate->inverse) {
fprintf(stderr,"kiss fft usage error: improper alloc\n");
exit(1);
KISS_FFT_ERROR("kiss fft usage error: improper alloc");
return;/* The caller did not call the correct function */
}
ncfft = st->substate->nfft;
@@ -111,7 +107,7 @@ void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *fr
C_ADD( f1k, fpk , fpnk );
C_SUB( f2k, fpk , fpnk );
C_MUL( tw , f2k , st->super_twiddles[k]);
C_MUL( tw , f2k , st->super_twiddles[k-1]);
freqdata[k].r = HALF_OF(f1k.r + tw.r);
freqdata[k].i = HALF_OF(f1k.i + tw.i);
@@ -126,8 +122,8 @@ void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *t
int k, ncfft;
if (st->substate->inverse == 0) {
fprintf (stderr, "kiss fft usage error: improper alloc\n");
exit (1);
KISS_FFT_ERROR("kiss fft usage error: improper alloc");
return;/* The caller did not call the correct function */
}
ncfft = st->substate->nfft;
@@ -146,7 +142,7 @@ void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *t
C_ADD (fek, fk, fnkc);
C_SUB (tmp, fk, fnkc);
C_MUL (fok, tmp, st->super_twiddles[k]);
C_MUL (fok, tmp, st->super_twiddles[k-1]);
C_ADD (st->tmpbuf[k], fek, fok);
C_SUB (st->tmpbuf[ncfft - k], fek, fok);
#ifdef USE_SIMD

View File

@@ -1,3 +1,11 @@
/*
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
*
* SPDX-License-Identifier: BSD-3-Clause
* See COPYING file for more information.
*/
#ifndef KISS_FTR_H
#define KISS_FTR_H
@@ -18,7 +26,7 @@ extern "C" {
typedef struct kiss_fftr_state *kiss_fftr_cfg;
kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem);
kiss_fftr_cfg KISS_FFT_API kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem);
/*
nfft must be even
@@ -26,19 +34,19 @@ kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenm
*/
void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata);
void KISS_FFT_API kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata);
/*
input timedata has nfft scalar points
output freqdata has nfft/2+1 complex points
*/
void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata);
void KISS_FFT_API kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata);
/*
input freqdata has nfft/2+1 complex points
output timedata has nfft scalar points
*/
#define kiss_fftr_free free
#define kiss_fftr_free KISS_FFT_FREE
#ifdef __cplusplus
}

View File

@@ -246,6 +246,63 @@ void v_cartesian_to_polar_interleaved_inplace(T *const R__ srcdst,
}
}
template<typename S, typename T> // S source, T target
void v_cartesian_to_magnitudes(T *const R__ mag,
const S *const R__ real,
const S *const R__ imag,
const int count)
{
for (int i = 0; i < count; ++i) {
mag[i] = T(sqrt(real[i] * real[i] + imag[i] * imag[i]));
}
}
template<typename S, typename T> // S source, T target
void v_cartesian_interleaved_to_magnitudes(T *const R__ mag,
const S *const R__ src,
const int count)
{
for (int i = 0; i < count; ++i) {
mag[i] = T(sqrt(src[i*2] * src[i*2] + src[i*2+1] * src[i*2+1]));
}
}
#ifdef HAVE_IPP
template<>
inline void v_cartesian_to_magnitudes(float *const R__ mag,
const float *const R__ real,
const float *const R__ imag,
const int count)
{
ippsMagnitude_32f(real, imag, mag, count);
}
template<>
inline void v_cartesian_to_magnitudes(double *const R__ mag,
const double *const R__ real,
const double *const R__ imag,
const int count)
{
ippsMagnitude_64f(real, imag, mag, count);
}
template<>
inline void v_cartesian_interleaved_to_magnitudes(float *const R__ mag,
const float *const R__ src,
const int count)
{
ippsMagnitude_32fc((const Ipp32fc *)src, mag, count);
}
template<>
inline void v_cartesian_interleaved_to_magnitudes(double *const R__ mag,
const double *const R__ src,
const int count)
{
ippsMagnitude_64fc((const Ipp64fc *)src, mag, count);
}
#endif
}
#endif