mirror of
https://github.com/mborgerding/kissfft.git
synced 2025-06-04 01:28:23 -04:00
Compare commits
62 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
febd4caeed | ||
|
26992ad1e4 | ||
|
00cc50ebaa | ||
|
1c3c9a5c94 | ||
|
f5f2a3b2f2 | ||
|
59c8cdfb08 | ||
|
8f47a67f59 | ||
|
0a4394045f | ||
|
478c35e653 | ||
|
7c9a5586a9 | ||
|
7eeda21377 | ||
|
cccf41adf2 | ||
|
2e2747c129 | ||
|
7811f7d428 | ||
|
e321f7a4d7 | ||
|
d11f1a889c | ||
|
f88d5af578 | ||
|
c2e82a30e8 | ||
|
7651bdaaa1 | ||
|
cc862cb0f2 | ||
|
15debe8ed3 | ||
|
1487038a8a | ||
|
2d5de8378c | ||
|
a63dfc7f11 | ||
|
609845bc9e | ||
|
fcf9fa9a47 | ||
|
5c708d85db | ||
|
0a70dfd0cf | ||
|
4e4a738a53 | ||
|
b2e0e600e5 | ||
|
c524b0b0e1 | ||
|
efff86ac1c | ||
|
159874bffa | ||
|
6fcc85dbaf | ||
|
f0a47de6aa | ||
|
5fb101ecb3 | ||
|
7c47cc9957 | ||
|
cf5813a1b4 | ||
|
e53d6d4bea | ||
|
07ccd8162e | ||
|
b30b93cd97 | ||
|
58cf0c0fc1 | ||
|
33d9ad3bad | ||
|
c2c0c0be03 | ||
|
b39de321ca | ||
|
1d7e76e0af | ||
|
fffc26e89a | ||
|
4193457bf4 | ||
|
3f3fc6ab55 | ||
|
592bdf7da8 | ||
|
b420613372 | ||
|
1efe72041e | ||
|
f4496dc080 | ||
|
3050076ab3 | ||
|
d06e7a7106 | ||
|
033f759ee3 | ||
|
24d23ffbb8 | ||
|
b24d80769b | ||
|
36dbc05760 | ||
|
d1f9113c51 | ||
|
a75f08488c | ||
|
bd550240fa |
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
*.o
|
||||
*.swp
|
||||
*.so
|
||||
*.so.*
|
||||
*.a
|
||||
*.dylib
|
||||
test/testcpp
|
||||
@ -44,3 +45,5 @@ tools/fft_float
|
||||
tools/fft_int16_t
|
||||
tools/fft_int32_t
|
||||
tools/fft_simd
|
||||
test/test_simd
|
||||
build
|
||||
|
10
.hgignore
10
.hgignore
@ -1,10 +0,0 @@
|
||||
syntax:glob
|
||||
test/bm_*
|
||||
test/st_*
|
||||
test/tkfc_*
|
||||
test/tr_*
|
||||
tools/fastconv_*
|
||||
tools/fastconvr_*
|
||||
tools/fft_*
|
||||
*.swp
|
||||
*~
|
18
.travis.yml
18
.travis.yml
@ -1,9 +1,9 @@
|
||||
language: python
|
||||
|
||||
python:
|
||||
- "2.6"
|
||||
- "3.7"
|
||||
|
||||
dist: trusty
|
||||
dist: focal
|
||||
|
||||
before_install:
|
||||
- sudo apt-get install -y libfftw3-dev
|
||||
@ -14,6 +14,14 @@ addons:
|
||||
|
||||
install: true
|
||||
|
||||
script:
|
||||
- make all
|
||||
- make testall
|
||||
jobs:
|
||||
include:
|
||||
- name: "build (make)"
|
||||
script:
|
||||
- make all
|
||||
- make testall
|
||||
- name: "build (cmake)"
|
||||
script:
|
||||
- mkdir build && cd build
|
||||
- cmake ..
|
||||
- make
|
||||
|
371
CMakeLists.txt
Normal file
371
CMakeLists.txt
Normal file
@ -0,0 +1,371 @@
|
||||
# Directory for easier includes
|
||||
# Anywhere you see include(...) you can check <root>/cmake for that file
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
|
||||
#
|
||||
# Extract version from Makefile
|
||||
#
|
||||
|
||||
file(READ Makefile _MAKEFILE_CONTENTS)
|
||||
|
||||
string(REGEX MATCH "KFVER_MAJOR = ([0-9]+)\n" KFVER_MAJOR_MATCH "${_MAKEFILE_CONTENTS}")
|
||||
if(NOT KFVER_MAJOR_MATCH)
|
||||
message(FATAL_ERROR "Cannot extract major (ABI) version from Makefile")
|
||||
endif()
|
||||
set(KFVER_MAJOR "${CMAKE_MATCH_1}")
|
||||
|
||||
string(REGEX MATCH "KFVER_MINOR = ([0-9]+)\n" KFVER_MINOR_MATCH "${_MAKEFILE_CONTENTS}")
|
||||
if(NOT KFVER_MINOR_MATCH)
|
||||
message(FATAL_ERROR "Cannot extract minor version from Makefile")
|
||||
endif()
|
||||
set(KFVER_MINOR "${CMAKE_MATCH_1}")
|
||||
|
||||
string(REGEX MATCH "KFVER_PATCH = ([0-9]+)\n" KFVER_PATCH_MATCH "${_MAKEFILE_CONTENTS}")
|
||||
if(NOT KFVER_PATCH_MATCH)
|
||||
message(FATAL_ERROR "Cannot extract patch version from Makefile")
|
||||
endif()
|
||||
set(KFVER_PATCH "${CMAKE_MATCH_1}")
|
||||
|
||||
set(MAKEFILE_EXTRACTED_VERSION "${KFVER_MAJOR}.${KFVER_MINOR}.${KFVER_PATCH}")
|
||||
|
||||
#
|
||||
# Declare CMake project
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
project(kissfft VERSION "${MAKEFILE_EXTRACTED_VERSION}")
|
||||
|
||||
#
|
||||
# CMake configuration options
|
||||
#
|
||||
|
||||
# Principal datatype: double, float (default), int16_t, int32_t, simd
|
||||
|
||||
set(KISSFFT_DATATYPE "float" CACHE STRING "Principal datatype of kissfft: double, float (default), int16_t, int32_t, simd")
|
||||
|
||||
# Additional options
|
||||
|
||||
option(KISSFFT_OPENMP "Build kissfft with OpenMP support" OFF)
|
||||
option(KISSFFT_PKGCONFIG "Build pkg-config files" ON)
|
||||
option(KISSFFT_STATIC "Build kissfft as static (ON) or shared library (OFF)" OFF)
|
||||
option(KISSFFT_TEST "Build kissfft tests" ON)
|
||||
option(KISSFFT_TOOLS "Build kissfft command-line tools" ON)
|
||||
option(KISSFFT_USE_ALLOCA "Use alloca instead of malloc" OFF)
|
||||
|
||||
#
|
||||
# Validate datatype
|
||||
#
|
||||
|
||||
if (NOT KISSFFT_DATATYPE MATCHES "^double$" AND
|
||||
NOT KISSFFT_DATATYPE MATCHES "^float$" AND
|
||||
NOT KISSFFT_DATATYPE MATCHES "^int16_t$" AND
|
||||
NOT KISSFFT_DATATYPE MATCHES "^int32_t$" AND
|
||||
NOT KISSFFT_DATATYPE MATCHES "^simd$")
|
||||
message(FATAL_ERROR "Incorrect value of KISSFFT_DATATYPE! It can be one of: double, float, int16_t, int32_t, simd")
|
||||
endif()
|
||||
|
||||
#
|
||||
# Print principal datatype
|
||||
#
|
||||
|
||||
message(STATUS "Building KissFFT with datatype: ${KISSFFT_DATATYPE}")
|
||||
set(KISSFFT_OUTPUT_NAME "kissfft-${KISSFFT_DATATYPE}")
|
||||
|
||||
#
|
||||
# Validate KISSFFT_STATIC
|
||||
#
|
||||
|
||||
if (BUILD_SHARED_LIBS AND KISSFFT_STATIC)
|
||||
message(FATAL_ERROR "Conflicting CMake configuration: -DBUILD_SHARED_LIBS=ON and -DKISSFFT_STATIC=ON")
|
||||
endif()
|
||||
|
||||
#
|
||||
# Enable BUILD_SHARED_LIBS for shared library build before
|
||||
# kissfft library is declared
|
||||
#
|
||||
|
||||
if (NOT KISSFFT_STATIC)
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
message(STATUS "Building shared library")
|
||||
else()
|
||||
message(STATUS "Building static library")
|
||||
endif()
|
||||
|
||||
#
|
||||
# Detect C compiler and pass appropriate flags
|
||||
#
|
||||
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
|
||||
add_compile_options(-ffast-math -fomit-frame-pointer
|
||||
-W -Wall -Wcast-align -Wcast-qual -Wshadow -Wwrite-strings
|
||||
"$<$<COMPILE_LANGUAGE:C>:-Wstrict-prototypes;-Wmissing-prototypes;-Wnested-externs;-Wbad-function-cast>")
|
||||
endif()
|
||||
|
||||
#
|
||||
# Add GNUInstallDirs for GNU infrastructure before target)include_directories
|
||||
#
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$" AND NOT CMAKE_CROSSCOMPILING)
|
||||
include(GNUInstallDirs)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Declare PKGINCLUDEDIR for kissfft include path
|
||||
#
|
||||
|
||||
set(PKGINCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/kissfft")
|
||||
message(STATUS "PKGINCLUDEDIR is ${PKGINCLUDEDIR}")
|
||||
|
||||
#
|
||||
# Declare kissfft library ( libkissfft.a / libkissfft-${KISSFFT_DATATYPE}.so.${MAKEFILE_EXTRACTED_VERSION} )
|
||||
#
|
||||
|
||||
add_library(kissfft
|
||||
kiss_fft.c
|
||||
kfc.c
|
||||
kiss_fftnd.c
|
||||
kiss_fftndr.c
|
||||
kiss_fftr.c)
|
||||
|
||||
target_include_directories(kissfft PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
|
||||
$<INSTALL_INTERFACE:${PKGINCLUDEDIR}>)
|
||||
|
||||
#
|
||||
# Set compile definitions based on datatype and additional support flags
|
||||
#
|
||||
|
||||
set(KISSFFT_COMPILE_DEFINITIONS)
|
||||
|
||||
#
|
||||
# double / float
|
||||
#
|
||||
|
||||
if(KISSFFT_DATATYPE MATCHES "^float$" OR KISSFFT_DATATYPE MATCHES "^double$")
|
||||
list(APPEND KISSFFT_COMPILE_DEFINITIONS kiss_fft_scalar=${KISSFFT_DATATYPE})
|
||||
else()
|
||||
|
||||
#
|
||||
# int16_t
|
||||
#
|
||||
|
||||
if(KISSFFT_DATATYPE MATCHES "^int16_t$")
|
||||
list(APPEND KISSFFT_COMPILE_DEFINITIONS FIXED_POINT=16)
|
||||
else()
|
||||
|
||||
#
|
||||
# int32_t
|
||||
#
|
||||
|
||||
if(KISSFFT_DATATYPE MATCHES "^int32_t$")
|
||||
list(APPEND KISSFFT_COMPILE_DEFINITIONS FIXED_POINT=32)
|
||||
else()
|
||||
|
||||
#
|
||||
# simd
|
||||
#
|
||||
|
||||
if(KISSFFT_DATATYPE MATCHES "^simd$")
|
||||
list(APPEND KISSFFT_COMPILE_DEFINITIONS USE_SIMD)
|
||||
if (NOT MSVC)
|
||||
target_compile_options(kissfft PRIVATE -msse)
|
||||
else()
|
||||
target_compile_options(kissfft PRIVATE "/arch:SSE")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#
|
||||
# OpenMP support
|
||||
#
|
||||
|
||||
if(KISSFFT_OPENMP)
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
|
||||
if (NOT MSVC)
|
||||
target_compile_options(kissfft PRIVATE -fopenmp)
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13.0")
|
||||
target_link_libraries(kissfft PRIVATE "-fopenmp")
|
||||
else()
|
||||
target_link_options(kissfft PRIVATE -fopenmp)
|
||||
endif()
|
||||
else()
|
||||
target_compile_options(kissfft PRIVATE "/openmp")
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13.0")
|
||||
target_link_libraries(kissfft PRIVATE "/openmp")
|
||||
else()
|
||||
target_link_options(kissfft PRIVATE "/openmp")
|
||||
endif()
|
||||
endif()
|
||||
set(KISSFFT_EXPORT_SUFFIX "-openmp")
|
||||
set(KISSFFT_OUTPUT_NAME "kissfft-${KISSFFT_DATATYPE}-openmp")
|
||||
else()
|
||||
message(FATAL_ERROR "Don't know how to enable OpenMP for this compiler")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#
|
||||
# Shared / static library
|
||||
#
|
||||
|
||||
if(NOT KISSFFT_STATIC)
|
||||
list(APPEND KISSFFT_COMPILE_DEFINITIONS KISS_FFT_SHARED)
|
||||
set_target_properties(kissfft PROPERTIES
|
||||
C_VISIBILITY_PRESET hidden)
|
||||
set(KISSFFT_EXPORT_SUFFIX "${KISSFFT_EXPORT_SUFFIX}-shared")
|
||||
else()
|
||||
set(KISSFFT_EXPORT_SUFFIX "${KISSFFT_EXPORT_SUFFIX}-static")
|
||||
endif()
|
||||
|
||||
#
|
||||
# Alloca support
|
||||
#
|
||||
|
||||
if(KISSFFT_USE_ALLOCA)
|
||||
list(APPEND KISSFFT_COMPILE_DEFINITIONS KISS_FFT_USE_ALLOCA)
|
||||
endif()
|
||||
|
||||
# Set library name, version, soversion and aliases
|
||||
|
||||
target_compile_definitions(kissfft PUBLIC ${KISSFFT_COMPILE_DEFINITIONS})
|
||||
set_target_properties(kissfft PROPERTIES
|
||||
OUTPUT_NAME "${KISSFFT_OUTPUT_NAME}"
|
||||
DEFINE_SYMBOL KISS_FFT_BUILD
|
||||
EXPORT_NAME "${KISSFFT_OUTPUT_NAME}"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${KFVER_MAJOR})
|
||||
add_library(kissfft::kissfft ALIAS kissfft)
|
||||
add_library(kissfft::kissfft-${KISSFFT_DATATYPE} ALIAS kissfft)
|
||||
|
||||
#
|
||||
# Build with libm (-lm) on Linux and kFreeBSD
|
||||
#
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$" AND NOT CMAKE_CROSSCOMPILING)
|
||||
target_link_libraries(kissfft PRIVATE m)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Define a helper function to define executable file
|
||||
#
|
||||
|
||||
function(add_kissfft_executable NAME)
|
||||
add_executable(${NAME} ${ARGN})
|
||||
target_link_libraries(${NAME} PRIVATE kissfft::kissfft)
|
||||
|
||||
#
|
||||
# Build with libm (-lm) on Linux and kFreeBSD
|
||||
#
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$" AND NOT CMAKE_CROSSCOMPILING)
|
||||
target_link_libraries(${NAME} PRIVATE m)
|
||||
endif()
|
||||
|
||||
if (NOT KISSFFT_OPENMP)
|
||||
set_target_properties(${NAME} PROPERTIES
|
||||
OUTPUT_NAME "${NAME}-${KISSFFT_DATATYPE}")
|
||||
else()
|
||||
if (NOT MSVC)
|
||||
target_compile_options(${NAME} PRIVATE -fopenmp)
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13.0")
|
||||
target_link_libraries(${NAME} PRIVATE "-fopenmp")
|
||||
else()
|
||||
target_link_options(${NAME} PRIVATE -fopenmp)
|
||||
endif()
|
||||
else()
|
||||
target_compile_options(${NAME} PRIVATE "/openmp")
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13.0")
|
||||
target_link_libraries(${NAME} PRIVATE "/openmp")
|
||||
else()
|
||||
target_link_options(${NAME} PRIVATE "/openmp")
|
||||
endif()
|
||||
endif()
|
||||
set_target_properties(${NAME} PROPERTIES
|
||||
OUTPUT_NAME "${NAME}-${KISSFFT_DATATYPE}-openmp")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
#
|
||||
# Perform installation of kissfft library and development files
|
||||
#
|
||||
|
||||
install(TARGETS kissfft EXPORT kissfft
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||
|
||||
install(FILES kiss_fft.h
|
||||
kissfft.hh
|
||||
kiss_fftnd.h
|
||||
kiss_fftndr.h
|
||||
kiss_fftr.h
|
||||
DESTINATION "${PKGINCLUDEDIR}")
|
||||
|
||||
set(KISSFFT_INSTALL_CMAKE "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
|
||||
CACHE FILEPATH "Install destination of kissfft cmake modules")
|
||||
mark_as_advanced(KISSFFT_INSTALL_CMAKE)
|
||||
|
||||
install(EXPORT kissfft DESTINATION "${KISSFFT_INSTALL_CMAKE}"
|
||||
NAMESPACE "kissfft::"
|
||||
FILE "${PROJECT_NAME}-${KISSFFT_DATATYPE}${KISSFFT_EXPORT_SUFFIX}-targets.cmake")
|
||||
include(CMakePackageConfigHelpers)
|
||||
configure_package_config_file(kissfft-config.cmake.in kissfft-config.cmake
|
||||
INSTALL_DESTINATION "${KISSFFT_INSTALL_CMAKE}")
|
||||
write_basic_package_version_file(kissfft-config-version.cmake COMPATIBILITY AnyNewerVersion)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kissfft-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/kissfft-config-version.cmake"
|
||||
DESTINATION "${KISSFFT_INSTALL_CMAKE}")
|
||||
|
||||
set(PKG_KISSFFT_DEFS)
|
||||
foreach(_def ${KISSFFT_COMPILE_DEFINITIONS})
|
||||
set(PKG_KISSFFT_DEFS "${PKG_KISSFFT_DEFS} -D${_def}")
|
||||
endforeach()
|
||||
if (KISSFFT_PKGCONFIG)
|
||||
include(JoinPaths)
|
||||
set(PKGCONFIG_KISSFFT_PKGINCLUDEDIR "\${includedir}/kissfft")
|
||||
set(PKGCONFIG_KISSFFT_PREFIX "${CMAKE_INSTALL_PREFIX}")
|
||||
set(PKGCONFIG_KISSFFT_VERSION "${kissfft_VERSION}")
|
||||
join_paths(PKGCONFIG_KISSFFT_LIBDIR "\${prefix}" "${CMAKE_INSTALL_LIBDIR}")
|
||||
join_paths(PKGCONFIG_KISSFFT_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
if(KISSFFT_DATATYPE MATCHES "^simd$")
|
||||
list(APPEND KISSFFT_COMPILE_DEFINITIONS USE_SIMD)
|
||||
if (NOT MSVC)
|
||||
set(PKG_KISSFFT_DEFS "${PKG_KISSFFT_DEFS} -msse")
|
||||
else()
|
||||
set(PKG_KISSFFT_DEFS "${PKG_KISSFFT_DEFS} /ARCH:SSE")
|
||||
endif()
|
||||
endif()
|
||||
if (NOT KISSFFT_OPENMP)
|
||||
configure_file(kissfft.pc.in "kissfft-${KISSFFT_DATATYPE}.pc" @ONLY)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kissfft-${KISSFFT_DATATYPE}.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
else()
|
||||
if (NOT MSVC)
|
||||
set(PKG_OPENMP "-fopenmp")
|
||||
set(PKG_KISSFFT_DEFS "${PKG_KISSFFT_DEFS} -fopenmp")
|
||||
else()
|
||||
set(PKG_KISSFFT_DEFS "${PKG_KISSFFT_DEFS} /openmp")
|
||||
set(PKG_OPENMP "/openmp")
|
||||
endif()
|
||||
configure_file(kissfft.pc.in "kissfft-${KISSFFT_DATATYPE}-openmp.pc" @ONLY)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kissfft-${KISSFFT_DATATYPE}-openmp.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#
|
||||
# Build and install tools if requested by user
|
||||
#
|
||||
|
||||
if(KISSFFT_TOOLS)
|
||||
add_subdirectory(tools)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Build and run tests if requested by user
|
||||
#
|
||||
|
||||
if(KISSFFT_TEST)
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
endif()
|
329
Makefile
329
Makefile
@ -1,48 +1,323 @@
|
||||
KFVER=131
|
||||
#
|
||||
# Semantic versioning
|
||||
#
|
||||
# KFVER_MAJOR denotes the ABI version.
|
||||
#
|
||||
# - It must be bumped only if API public members are removed or
|
||||
# changed in the incompatible
|
||||
#
|
||||
# KFVER_MINOR denotes the minor version within a compatible ABI.
|
||||
#
|
||||
# - It should be bumped if new API public members are added
|
||||
# (but not removed!) so programs linked against the same library
|
||||
# version continue operating properly
|
||||
#
|
||||
# KFVER_PATCH denotes bugfix count since the last minor update.
|
||||
#
|
||||
# - It should be bumped whenever a bug fix is pushed.
|
||||
#
|
||||
|
||||
ifeq ($(shell uname -s),Darwin)
|
||||
SHARED := -Wl,-install_name,libkissfft.dylib -o libkissfft.dylib
|
||||
else
|
||||
SHARED := -Wl,-soname,libkissfft.so -o libkissfft.so
|
||||
export KFVER_MAJOR = 131
|
||||
export KFVER_MINOR = 1
|
||||
export KFVER_PATCH = 0
|
||||
|
||||
#
|
||||
# Data type (float / int16_t / int32_t / simd)
|
||||
#
|
||||
|
||||
export KISSFFT_DATATYPE ?= float
|
||||
|
||||
#
|
||||
# Default options
|
||||
#
|
||||
|
||||
export KISSFFT_OPENMP ?= 0
|
||||
export KISSFFT_STATIC ?= 0
|
||||
export KISSFFT_TOOLS ?= 1
|
||||
export KISSFFT_USE_ALLOCA ?= 0
|
||||
|
||||
#
|
||||
# Installation directories
|
||||
#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
export ABS_PREFIX = $(abspath $(PREFIX))
|
||||
|
||||
BINDIR ?= $(ABS_PREFIX)/bin
|
||||
export ABS_BINDIR = $(abspath $(BINDIR))
|
||||
|
||||
INCLUDEDIR ?= $(ABS_PREFIX)/include
|
||||
export ABS_INCLUDEDIR = $(abspath $(INCLUDEDIR))
|
||||
export ABS_PKGINCLUDEDIR = $(ABS_INCLUDEDIR)/kissfft
|
||||
|
||||
#
|
||||
# Override LIBDIR with lib64 following CMake's
|
||||
# GNUInstallDirs logic:
|
||||
#
|
||||
|
||||
CANDIDATE_LIBDIR_NAME = lib
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
ifeq ($(shell uname -s),Linux)
|
||||
_UNAME_ARCH = $(shell uname -i)
|
||||
|
||||
ifeq (,$(_UNAME_ARCH))
|
||||
_UNAME_ARCH = $(shell uname -m)
|
||||
|
||||
ifeq (,$(_UNAME_ARCH))
|
||||
$(warning WARNING: Can not detect system architecture!)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(_UNAME_ARCH),x86_64)
|
||||
CANDIDATE_LIBDIR_NAME = lib64
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
all:
|
||||
gcc -Wall -fPIC -c *.c -Dkiss_fft_scalar=float -o kiss_fft.o
|
||||
ar crus libkissfft.a kiss_fft.o
|
||||
gcc -shared $(SHARED) kiss_fft.o
|
||||
CANDIDATE_LIBDIR = $(PREFIX)/$(CANDIDATE_LIBDIR_NAME)
|
||||
LIBDIR ?= $(CANDIDATE_LIBDIR)
|
||||
|
||||
export ABS_LIBDIR = $(abspath $(LIBDIR))
|
||||
|
||||
export INSTALL ?= install
|
||||
|
||||
#
|
||||
# Library name and version
|
||||
#
|
||||
|
||||
ifeq ($(KISSFFT_OPENMP), 1)
|
||||
KISSFFTLIB_SHORTNAME = kissfft-$(KISSFFT_DATATYPE)-openmp
|
||||
KISSFFT_PKGCONFIG = kissfft-$(KISSFFT_DATATYPE)-openmp.pc
|
||||
KISSFFTLIB_FLAGS = -fopenmp
|
||||
TYPEFLAGS = -fopenmp
|
||||
PKGCONFIG_OPENMP = -fopenmp
|
||||
else
|
||||
KISSFFTLIB_SHORTNAME = kissfft-$(KISSFFT_DATATYPE)
|
||||
KISSFFT_PKGCONFIG = kissfft-$(KISSFFT_DATATYPE).pc
|
||||
TYPEFLAGS =
|
||||
PKGCONFIG_OPENMP =
|
||||
endif
|
||||
|
||||
ifeq ($(KISSFFT_STATIC), 1)
|
||||
KISSFFTLIB_NAME = lib$(KISSFFTLIB_SHORTNAME).a
|
||||
KISSFFTLIB_FLAGS += -static
|
||||
else ifeq ($(shell uname -s),Darwin)
|
||||
KISSFFTLIB_NAME = lib$(KISSFFTLIB_SHORTNAME).dylib
|
||||
KISSFFTLIB_FLAGS += -shared -Wl,-install_name,$(KISSFFTLIB_NAME)
|
||||
else
|
||||
KISSFFTLIB_SODEVELNAME = lib$(KISSFFTLIB_SHORTNAME).so
|
||||
KISSFFTLIB_SONAME = $(KISSFFTLIB_SODEVELNAME).$(KFVER_MAJOR)
|
||||
KISSFFTLIB_NAME = $(KISSFFTLIB_SONAME).$(KFVER_MINOR).$(KFVER_PATCH)
|
||||
KISSFFTLIB_FLAGS += -shared -Wl,-soname,$(KISSFFTLIB_SONAME)
|
||||
endif
|
||||
|
||||
export KISSFFTLIB_SHORTNAME
|
||||
|
||||
#
|
||||
# Compile-time definitions by datatype
|
||||
#
|
||||
#
|
||||
# Note: -DKISS_FFT_BUILD and -DKISS_FFT_SHARED control
|
||||
# C symbol visibility.
|
||||
#
|
||||
|
||||
ifeq "$(KISSFFT_DATATYPE)" "int32_t"
|
||||
TYPEFLAGS += -DFIXED_POINT=32
|
||||
else ifeq "$(KISSFFT_DATATYPE)" "int16_t"
|
||||
TYPEFLAGS += -DFIXED_POINT=16
|
||||
else ifeq "$(KISSFFT_DATATYPE)" "simd"
|
||||
TYPEFLAGS += -DUSE_SIMD=1 -msse
|
||||
else ifeq "$(KISSFFT_DATATYPE)" "float"
|
||||
TYPEFLAGS += -Dkiss_fft_scalar=$(KISSFFT_DATATYPE)
|
||||
else ifeq "$(KISSFFT_DATATYPE)" "double"
|
||||
TYPEFLAGS += -Dkiss_fft_scalar=$(KISSFFT_DATATYPE)
|
||||
else
|
||||
$(error ERROR: KISSFFT_DATATYPE must be one of: float double int16_t int32_t simd)
|
||||
endif
|
||||
|
||||
ifneq ($(KISSFFT_STATIC), 1)
|
||||
TYPEFLAGS += -DKISS_FFT_SHARED
|
||||
endif
|
||||
|
||||
ifeq ($(KISSFFT_USE_ALLOCA), 1)
|
||||
TYPEFLAGS += -DKISS_FFT_USE_ALLOCA=1
|
||||
endif
|
||||
|
||||
#
|
||||
# Compile-time definitions
|
||||
#
|
||||
|
||||
#
|
||||
# Save pkgconfig variables before appending
|
||||
# -DKISS_FFT_BUILD to TYPEFLAGS
|
||||
#
|
||||
|
||||
ifneq ($(shell uname -s),Darwin)
|
||||
PKGCONFIG_KISSFFT_VERSION = $(KFVER_MAJOR).$(KFVER_MINOR).$(KFVER_PATCH)
|
||||
PKGCONFIG_KISSFFT_OUTPUT_NAME = $(KISSFFTLIB_SHORTNAME)
|
||||
PKGCONFIG_PKG_KISSFFT_DEFS = $(TYPEFLAGS)
|
||||
PKGCONFIG_KISSFFT_PREFIX = $(ABS_PREFIX)
|
||||
ifeq ($(ABS_INCLUDEDIR),$(ABS_PREFIX)/include)
|
||||
PKGCONFIG_KISSFFT_INCLUDEDIR = $${prefix}/include
|
||||
else
|
||||
PKGCONFIG_KISSFFT_INCLUDEDIR = $(ABS_INCLUDEDIR)
|
||||
|
||||
endif
|
||||
ifeq ($(ABS_LIBDIR),$(ABS_PREFIX)/$(CANDIDATE_LIBDIR_NAME))
|
||||
PKGCONFIG_KISSFFT_LIBDIR = $${prefix}/$(CANDIDATE_LIBDIR_NAME)
|
||||
else
|
||||
PKGCONFIG_KISSFFT_LIBDIR = $(ABS_LIBDIR)
|
||||
endif
|
||||
PKGCONFIG_KISSFFT_PKGINCLUDEDIR = $${includedir}/kissfft
|
||||
endif
|
||||
|
||||
export TYPEFLAGS
|
||||
|
||||
# Compile .c into .o
|
||||
#
|
||||
|
||||
#
|
||||
# -DKISS_FFT_BUILD is used for library artifacts, so
|
||||
# consumer executable in 'test' and 'tools' do _NOT_
|
||||
# need it. pkg-config output does not need it either.
|
||||
#
|
||||
|
||||
%.c.o: %.c
|
||||
$(CC) -Wall -fPIC \
|
||||
-o $@ \
|
||||
$(CFLAGS) $(TYPEFLAGS) -DKISS_FFT_BUILD \
|
||||
-c $<
|
||||
|
||||
#
|
||||
# Target: "make all"
|
||||
#
|
||||
|
||||
all: kfc.c.o kiss_fft.c.o kiss_fftnd.c.o kiss_fftndr.c.o kiss_fftr.c.o
|
||||
ifneq ($(KISSFFT_STATIC), 1)
|
||||
$(CC) $(KISSFFTLIB_FLAGS) -o $(KISSFFTLIB_NAME) $^
|
||||
ifneq ($(shell uname -s),Darwin)
|
||||
ln -sf $(KISSFFTLIB_NAME) $(KISSFFTLIB_SONAME)
|
||||
ln -sf $(KISSFFTLIB_NAME) $(KISSFFTLIB_SODEVELNAME)
|
||||
endif
|
||||
else
|
||||
$(AR) crus $(KISSFFTLIB_NAME) $^
|
||||
endif
|
||||
ifneq ($(KISSFFT_TOOLS), 0)
|
||||
$(MAKE) -C tools CFLAGADD="$(CFLAGADD)" all
|
||||
endif
|
||||
|
||||
#
|
||||
# Target: "make install"
|
||||
#
|
||||
|
||||
install: all
|
||||
cp libkissfft.so /usr/local/lib/
|
||||
$(INSTALL) -Dt $(ABS_PKGINCLUDEDIR) -m 644 \
|
||||
kiss_fft.h \
|
||||
kissfft.hh \
|
||||
kiss_fftnd.h \
|
||||
kiss_fftndr.h \
|
||||
kiss_fftr.h
|
||||
$(INSTALL) -Dt $(ABS_LIBDIR) -m 644 $(KISSFFTLIB_NAME)
|
||||
ifneq ($(KISSFFT_STATIC), 1)
|
||||
ifneq ($(shell uname -s),Darwin)
|
||||
cd $(LIBDIR) && \
|
||||
ln -sf $(KISSFFTLIB_NAME) $(KISSFFTLIB_SONAME) && \
|
||||
ln -sf $(KISSFFTLIB_NAME) $(KISSFFTLIB_SODEVELNAME)
|
||||
endif
|
||||
endif
|
||||
ifneq ($(shell uname -s),Darwin)
|
||||
mkdir "$(ABS_LIBDIR)/pkgconfig"
|
||||
sed \
|
||||
-e 's+@PKGCONFIG_KISSFFT_VERSION@+$(PKGCONFIG_KISSFFT_VERSION)+' \
|
||||
-e 's+@KISSFFT_OUTPUT_NAME@+$(PKGCONFIG_KISSFFT_OUTPUT_NAME)+' \
|
||||
-e 's+@PKG_KISSFFT_DEFS@+$(PKGCONFIG_PKG_KISSFFT_DEFS)+' \
|
||||
-e 's+@PKG_OPENMP@+$(PKGCONFIG_OPENMP)+' \
|
||||
-e 's+@PKGCONFIG_KISSFFT_PREFIX@+$(PKGCONFIG_KISSFFT_PREFIX)+' \
|
||||
-e 's+@PKGCONFIG_KISSFFT_INCLUDEDIR@+$(PKGCONFIG_KISSFFT_INCLUDEDIR)+' \
|
||||
-e 's+@PKGCONFIG_KISSFFT_LIBDIR@+$(PKGCONFIG_KISSFFT_LIBDIR)+' \
|
||||
-e 's+@PKGCONFIG_KISSFFT_PKGINCLUDEDIR@+$(PKGCONFIG_KISSFFT_PKGINCLUDEDIR)+' \
|
||||
kissfft.pc.in 1>"$(ABS_LIBDIR)/pkgconfig/$(KISSFFT_PKGCONFIG)"
|
||||
endif
|
||||
ifneq ($(KISSFFT_TOOLS), 0)
|
||||
$(MAKE) -C tools install
|
||||
endif
|
||||
|
||||
#
|
||||
# Target: "make doc"
|
||||
#
|
||||
|
||||
doc:
|
||||
@echo "Start by reading the README file. If you want to build and test lots of stuff, do a 'make testall'"
|
||||
@echo "but be aware that 'make testall' has dependencies that the basic kissfft software does not."
|
||||
@echo "It is generally unneeded to run these tests yourself, unless you plan on changing the inner workings"
|
||||
@echo "of kissfft and would like to make use of its regression tests."
|
||||
$(warning Start by reading the README file. If you want to build and test lots of stuff, do a 'make testall')
|
||||
$(warning but be aware that 'make testall' has dependencies that the basic kissfft software does not.)
|
||||
$(warning It is generally unneeded to run these tests yourself, unless you plan on changing the inner workings)
|
||||
$(warning of kissfft and would like to make use of its regression tests.)
|
||||
|
||||
#
|
||||
# Target: "make testsingle"
|
||||
#
|
||||
|
||||
testsingle:
|
||||
$(MAKE) clean
|
||||
$(MAKE) all
|
||||
$(MAKE) -C test CFLAGADD="$(CFLAGADD)" test testcpp
|
||||
|
||||
#
|
||||
# Target: "make testall"
|
||||
#
|
||||
|
||||
testall:
|
||||
# The simd and int32_t types may or may not work on your machine
|
||||
make -C test testcpp && test/testcpp
|
||||
make -C test DATATYPE=simd CFLAGADD="$(CFLAGADD)" test
|
||||
make -C test DATATYPE=int32_t CFLAGADD="$(CFLAGADD)" test
|
||||
make -C test DATATYPE=int16_t CFLAGADD="$(CFLAGADD)" test
|
||||
make -C test DATATYPE=float CFLAGADD="$(CFLAGADD)" test
|
||||
make -C test DATATYPE=double CFLAGADD="$(CFLAGADD)" test
|
||||
echo "all tests passed"
|
||||
# Shared libraries
|
||||
$(MAKE) KISSFFT_DATATYPE=double testsingle
|
||||
$(MAKE) KISSFFT_DATATYPE=float testsingle
|
||||
$(MAKE) KISSFFT_DATATYPE=int16_t testsingle
|
||||
# The simd and int32_t types may or may not work on your machine
|
||||
$(MAKE) KISSFFT_DATATYPE=int32_t testsingle
|
||||
$(MAKE) KISSFFT_DATATYPE=simd testsingle
|
||||
# Static libraries
|
||||
$(MAKE) KISSFFT_DATATYPE=double KISSFFT_STATIC=1 testsingle
|
||||
$(MAKE) KISSFFT_DATATYPE=float KISSFFT_STATIC=1 testsingle
|
||||
$(MAKE) KISSFFT_DATATYPE=int16_t KISSFFT_STATIC=1 testsingle
|
||||
# The simd and int32_t types may or may not work on your machine
|
||||
$(MAKE) KISSFFT_DATATYPE=int32_t KISSFFT_STATIC=1 testsingle
|
||||
$(MAKE) KISSFFT_DATATYPE=simd KISSFFT_STATIC=1 testsingle
|
||||
# OpenMP libraries
|
||||
$(MAKE) KISSFFT_DATATYPE=double KISSFFT_OPENMP=1 testsingle
|
||||
$(MAKE) KISSFFT_DATATYPE=float KISSFFT_OPENMP=1 testsingle
|
||||
$(MAKE) KISSFFT_DATATYPE=int16_t KISSFFT_OPENMP=1 testsingle
|
||||
# The simd and int32_t types may or may not work on your machine
|
||||
$(MAKE) KISSFFT_DATATYPE=int32_t KISSFFT_OPENMP=1 testsingle
|
||||
$(MAKE) KISSFFT_DATATYPE=simd KISSFFT_OPENMP=1 testsingle
|
||||
$(warning All tests passed!)
|
||||
|
||||
#
|
||||
# Target: "make tarball"
|
||||
#
|
||||
|
||||
tarball: clean
|
||||
git archive --prefix=kissfft/ -o kissfft$(KFVER).tar.gz v$(KFVER)
|
||||
git archive --prefix=kissfft/ -o kissfft$(KFVER).zip v$(KFVER)
|
||||
|
||||
#
|
||||
# Target: "make clean"
|
||||
#
|
||||
|
||||
clean:
|
||||
cd test && make clean
|
||||
cd tools && make clean
|
||||
rm -f kiss_fft*.tar.gz *~ *.pyc kiss_fft*.zip
|
||||
rm -f *.o *.a *.so *.so.*
|
||||
cd test && $(MAKE) clean
|
||||
cd tools && $(MAKE) clean
|
||||
rm -f kiss_fft*.tar.gz *~ *.pyc kiss_fft*.zip
|
||||
|
||||
#
|
||||
# Target: "make asm"
|
||||
#
|
||||
|
||||
asm: kiss_fft.s
|
||||
|
||||
# TODO: Sort out if we should add kfc / other C headers
|
||||
|
||||
kiss_fft.s: kiss_fft.c kiss_fft.h _kiss_fft_guts.h
|
||||
[ -e kiss_fft.s ] && mv kiss_fft.s kiss_fft.s~ || true
|
||||
gcc -S kiss_fft.c -O3 -mtune=native -ffast-math -fomit-frame-pointer -unroll-loops -dA -fverbose-asm
|
||||
gcc -o kiss_fft_short.s -S kiss_fft.c -O3 -mtune=native -ffast-math -fomit-frame-pointer -dA -fverbose-asm -DFIXED_POINT
|
||||
$(CC) -S kiss_fft.c -O3 -mtune=native -ffast-math -fomit-frame-pointer -unroll-loops -dA -fverbose-asm
|
||||
$(CC) -o kiss_fft_short.s -S kiss_fft.c -O3 -mtune=native -ffast-math -fomit-frame-pointer -dA -fverbose-asm -DFIXED_POINT
|
||||
[ -e kiss_fft.s~ ] && diff kiss_fft.s~ kiss_fft.s || true
|
||||
|
131
README
131
README
@ -1,131 +0,0 @@
|
||||
KISS FFT - A mixed-radix Fast Fourier Transform based up on the principle,
|
||||
"Keep It Simple, Stupid."
|
||||
|
||||
There are many great fft libraries already around. Kiss FFT is not trying
|
||||
to be better than any of them. It only attempts to be a reasonably efficient,
|
||||
moderately useful FFT that can use fixed or floating data types and can be
|
||||
incorporated into someone's C program in a few minutes with trivial licensing.
|
||||
|
||||
USAGE:
|
||||
|
||||
The basic usage for 1-d complex FFT is:
|
||||
|
||||
#include "kiss_fft.h"
|
||||
|
||||
kiss_fft_cfg cfg = kiss_fft_alloc( nfft ,is_inverse_fft ,0,0 );
|
||||
|
||||
while ...
|
||||
|
||||
... // put kth sample in cx_in[k].r and cx_in[k].i
|
||||
|
||||
kiss_fft( cfg , cx_in , cx_out );
|
||||
|
||||
... // transformed. DC is in cx_out[0].r and cx_out[0].i
|
||||
|
||||
kiss_fft_free(cfg);
|
||||
|
||||
Note: frequency-domain data is stored from dc up to 2pi.
|
||||
so cx_out[0] is the dc bin of the FFT
|
||||
and cx_out[nfft/2] is the Nyquist bin (if exists)
|
||||
|
||||
Declarations are in "kiss_fft.h", along with a brief description of the
|
||||
functions you'll need to use.
|
||||
|
||||
Code definitions for 1d complex FFTs are in kiss_fft.c.
|
||||
|
||||
You can do other cool stuff with the extras you'll find in tools/
|
||||
|
||||
* multi-dimensional FFTs
|
||||
* real-optimized FFTs (returns the positive half-spectrum: (nfft/2+1) complex frequency bins)
|
||||
* fast convolution FIR filtering (not available for fixed point)
|
||||
* spectrum image creation
|
||||
|
||||
The core fft and most tools/ code can be compiled to use float, double,
|
||||
Q15 short or Q31 samples. The default is float.
|
||||
|
||||
|
||||
BACKGROUND:
|
||||
|
||||
I started coding this because I couldn't find a fixed point FFT that didn't
|
||||
use assembly code. I started with floating point numbers so I could get the
|
||||
theory straight before working on fixed point issues. In the end, I had a
|
||||
little bit of code that could be recompiled easily to do ffts with short, float
|
||||
or double (other types should be easy too).
|
||||
|
||||
Once I got my FFT working, I was curious about the speed compared to
|
||||
a well respected and highly optimized fft library. I don't want to criticize
|
||||
this great library, so let's call it FFT_BRANDX.
|
||||
During this process, I learned:
|
||||
|
||||
1. FFT_BRANDX has more than 100K lines of code. The core of kiss_fft is about 500 lines (cpx 1-d).
|
||||
2. It took me an embarrassingly long time to get FFT_BRANDX working.
|
||||
3. A simple program using FFT_BRANDX is 522KB. A similar program using kiss_fft is 18KB (without optimizing for size).
|
||||
4. FFT_BRANDX is roughly twice as fast as KISS FFT in default mode.
|
||||
|
||||
It is wonderful that free, highly optimized libraries like FFT_BRANDX exist.
|
||||
But such libraries carry a huge burden of complexity necessary to extract every
|
||||
last bit of performance.
|
||||
|
||||
Sometimes simpler is better, even if it's not better.
|
||||
|
||||
FREQUENTLY ASKED QUESTIONS:
|
||||
Q: Can I use kissfft in a project with a ___ license?
|
||||
A: Yes. See LICENSE below.
|
||||
|
||||
Q: Why don't I get the output I expect?
|
||||
A: The two most common causes of this are
|
||||
1) scaling : is there a constant multiplier between what you got and what you want?
|
||||
2) mixed build environment -- all code must be compiled with same preprocessor
|
||||
definitions for FIXED_POINT and kiss_fft_scalar
|
||||
|
||||
Q: Will you write/debug my code for me?
|
||||
A: Probably not unless you pay me. I am happy to answer pointed and topical questions, but
|
||||
I may refer you to a book, a forum, or some other resource.
|
||||
|
||||
|
||||
PERFORMANCE:
|
||||
(on Athlon XP 2100+, with gcc 2.96, float data type)
|
||||
|
||||
Kiss performed 10000 1024-pt cpx ffts in .63 s of cpu time.
|
||||
For comparison, it took md5sum twice as long to process the same amount of data.
|
||||
|
||||
Transforming 5 minutes of CD quality audio takes less than a second (nfft=1024).
|
||||
|
||||
DO NOT:
|
||||
... use Kiss if you need the Fastest Fourier Transform in the World
|
||||
... ask me to add features that will bloat the code
|
||||
|
||||
UNDER THE HOOD:
|
||||
|
||||
Kiss FFT uses a time decimation, mixed-radix, out-of-place FFT. If you give it an input buffer
|
||||
and output buffer that are the same, a temporary buffer will be created to hold the data.
|
||||
|
||||
No static data is used. The core routines of kiss_fft are thread-safe (but not all of the tools directory).
|
||||
|
||||
No scaling is done for the floating point version (for speed).
|
||||
Scaling is done both ways for the fixed-point version (for overflow prevention).
|
||||
|
||||
Optimized butterflies are used for factors 2,3,4, and 5.
|
||||
|
||||
The real (i.e. not complex) optimization code only works for even length ffts. It does two half-length
|
||||
FFTs in parallel (packed into real&imag), and then combines them via twiddling. The result is
|
||||
nfft/2+1 complex frequency bins from DC to Nyquist. If you don't know what this means, search the web.
|
||||
|
||||
The fast convolution filtering uses the overlap-scrap method, slightly
|
||||
modified to put the scrap at the tail.
|
||||
|
||||
LICENSE:
|
||||
Revised BSD License, see COPYING for verbiage.
|
||||
Basically, "free to use&change, give credit where due, no guarantees"
|
||||
Note this license is compatible with GPL at one end of the spectrum and closed, commercial software at
|
||||
the other end. See http://www.fsf.org/licensing/licenses
|
||||
|
||||
TODO:
|
||||
*) Add real optimization for odd length FFTs
|
||||
*) Document/revisit the input/output fft scaling
|
||||
*) Make doc describing the overlap (tail) scrap fast convolution filtering in kiss_fastfir.c
|
||||
*) Test all the ./tools/ code with fixed point (kiss_fastfir.c doesn't work, maybe others)
|
||||
|
||||
AUTHOR:
|
||||
Mark Borgerding
|
||||
Mark@Borgerding.net
|
114
README.md
114
README.md
@ -44,6 +44,120 @@ You can do other cool stuff with the extras you'll find in tools/
|
||||
The core fft and most tools/ code can be compiled to use float, double,
|
||||
Q15 short or Q31 samples. The default is float.
|
||||
|
||||
## BUILDING:
|
||||
|
||||
There are two functionally-equivalent build systems supported by kissfft:
|
||||
|
||||
- Make (traditional Makefiles for Unix / Linux systems)
|
||||
- CMake (more modern and feature-rich build system developed by Kitware)
|
||||
|
||||
To build kissfft, the following build environment can be used:
|
||||
|
||||
- GNU build environment with GCC, Clang and GNU Make or CMake (>= 3.6)
|
||||
- Microsoft Visual C++ (MSVC) with CMake (>= 3.6)
|
||||
|
||||
Additional libraries required to build and test kissfft include:
|
||||
|
||||
- libpng for psdpng tool,
|
||||
- libfftw3 to validate kissfft results against it,
|
||||
- python 2/3 with Numpy to validate kissfft results against it.
|
||||
- OpenMP supported by GCC, Clang or MSVC for multi-core FFT transformations
|
||||
|
||||
Environments like Cygwin and MinGW can be highly likely used to build kissfft
|
||||
targeting Windows platform, but no tests were performed to the date.
|
||||
|
||||
Both Make and CMake builds are easily configurable:
|
||||
|
||||
- `KISSFFT_DATATYPE=<datatype>` (for Make) or `-DKISSFFT_DATATYPE=<datatype>`
|
||||
(for CMake) denote the principal datatype used by kissfft. It can be one
|
||||
of the following:
|
||||
|
||||
- float (default)
|
||||
- double
|
||||
- int16_t
|
||||
- int32_t
|
||||
- SIMD (requires SSE instruction set support on target CPU)
|
||||
|
||||
- `KISSFFT_OPENMP=1` (for Make) or `-DKISSFFT_OPENMP=ON` (for CMake) builds kissfft
|
||||
with OpenMP support. Please note that a supported compiler is required and this
|
||||
option is turned off by default.
|
||||
|
||||
- `KISSFFT_STATIC=1` (for Make) or `-DKISSFFT_STATIC=ON` (for CMake) instructs
|
||||
the builder to create static library ('.lib' for Windows / '.a' for Unix or Linux).
|
||||
By default, this option is turned off and the shared library is created
|
||||
('.dll' for Windows, '.so' for Linux or Unix, '.dylib' for Mac OSX)
|
||||
|
||||
- `-DKISSFFT_TEST=OFF` (for CMake) disables building tests for kissfft. On Make,
|
||||
building tests is done separately by 'make testall' or 'make testsingle', so
|
||||
no specific setting is required.
|
||||
|
||||
- `KISSFFT_TOOLS=0` (for Make) or `-DKISSFFT_TOOLS=OFF` (for CMake) builds kissfft
|
||||
without command-line tools like 'fastconv'. By default the tools are built.
|
||||
|
||||
- `KISSFFT_USE_ALLOCA=1` (for Make) or `-DKISSFFT_USE_ALLOCA=ON` (for CMake)
|
||||
build kissfft with 'alloca' usage instead of 'malloc' / 'free'.
|
||||
|
||||
- `PREFIX=/full/path/to/installation/prefix/directory` (for Make) or
|
||||
`-DCMAKE_INSTALL_PREFIX=/full/path/to/installation/prefix/directory` (for CMake)
|
||||
specifies the prefix directory to install kissfft into.
|
||||
|
||||
For example, to build kissfft as a static library with 'int16_t' datatype and
|
||||
OpenMP support using Make, run the command from kissfft source tree:
|
||||
|
||||
```
|
||||
make KISSFFT_DATATYPE=int16_t KISSFFT_STATIC=1 KISSFFT_OPENMP=1 all
|
||||
```
|
||||
|
||||
The same configuration for CMake is:
|
||||
|
||||
```
|
||||
mkdir build && cd build
|
||||
cmake -DKISSFFT_DATATYPE=int16_t -DKISSFFT_STATIC=ON -DKISSFFT_OPENMP=ON ..
|
||||
make all
|
||||
```
|
||||
|
||||
To specify '/tmp/1234' as installation prefix directory, run:
|
||||
|
||||
|
||||
```
|
||||
make PREFIX=/tmp/1234 KISSFFT_DATATYPE=int16_t KISSFFT_STATIC=1 KISSFFT_OPENMP=1 install
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
mkdir build && cd build
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/1234 -DKISSFFT_DATATYPE=int16_t -DKISSFFT_STATIC=ON -DKISSFFT_OPENMP=ON ..
|
||||
make all
|
||||
make install
|
||||
```
|
||||
|
||||
## TESTING:
|
||||
|
||||
To validate the build configured as an example above, run the following command from
|
||||
kissfft source tree:
|
||||
|
||||
```
|
||||
make KISSFFT_DATATYPE=int16_t KISSFFT_STATIC=1 KISSFFT_OPENMP=1 testsingle
|
||||
```
|
||||
|
||||
if using Make, or:
|
||||
|
||||
```
|
||||
make test
|
||||
```
|
||||
|
||||
if using CMake.
|
||||
|
||||
To test all possible build configurations, please run an extended testsuite from
|
||||
kissfft source tree:
|
||||
|
||||
```
|
||||
sh test/kissfft-testsuite.sh
|
||||
```
|
||||
|
||||
Please note that the extended testsuite takes around 20-40 minutes depending on device
|
||||
it runs on. This testsuite is useful for reporting bugs or testing the pull requests.
|
||||
|
||||
## BACKGROUND
|
||||
|
||||
|
@ -10,11 +10,16 @@
|
||||
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
|
||||
/* e.g. an fft of length 128 has 4 factors
|
||||
/* e.g. an fft of length 128 has 4 factors
|
||||
as far as kissfft is concerned
|
||||
4*4*4*2
|
||||
*/
|
||||
@ -36,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 SAMPPROD int32_t
|
||||
#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
|
||||
|
||||
|
||||
@ -65,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 ) ) ;\
|
||||
@ -93,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)
|
||||
|
||||
|
||||
@ -129,30 +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:
|
||||
// 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)
|
||||
#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 */
|
||||
|
||||
|
23
cmake/JoinPaths.cmake
Normal file
23
cmake/JoinPaths.cmake
Normal file
@ -0,0 +1,23 @@
|
||||
# This module provides function for joining paths
|
||||
# known from most languages
|
||||
#
|
||||
# SPDX-License-Identifier: (MIT OR CC0-1.0)
|
||||
# Copyright 2020 Jan Tojnar
|
||||
# https://github.com/jtojnar/cmake-snips
|
||||
#
|
||||
# Modelled after Python’s os.path.join
|
||||
# https://docs.python.org/3.7/library/os.path.html#os.path.join
|
||||
# Windows not supported
|
||||
function(join_paths joined_path first_path_segment)
|
||||
set(temp_path "${first_path_segment}")
|
||||
foreach(current_segment IN LISTS ARGN)
|
||||
if(NOT ("${current_segment}" STREQUAL ""))
|
||||
if(IS_ABSOLUTE "${current_segment}")
|
||||
set(temp_path "${current_segment}")
|
||||
else()
|
||||
set(temp_path "${temp_path}/${current_segment}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
set(${joined_path} "${temp_path}" PARENT_SCOPE)
|
||||
endfunction()
|
@ -40,12 +40,12 @@ call kfc_cleanup.
|
||||
*/
|
||||
|
||||
/*forward complex FFT */
|
||||
void kfc_fft(int nfft, const kiss_fft_cpx * fin,kiss_fft_cpx * fout);
|
||||
void KISS_FFT_API kfc_fft(int nfft, const kiss_fft_cpx * fin,kiss_fft_cpx * fout);
|
||||
/*reverse complex FFT */
|
||||
void kfc_ifft(int nfft, const kiss_fft_cpx * fin,kiss_fft_cpx * fout);
|
||||
void KISS_FFT_API kfc_ifft(int nfft, const kiss_fft_cpx * fin,kiss_fft_cpx * fout);
|
||||
|
||||
/*free all cached objects*/
|
||||
void kfc_cleanup(void);
|
||||
void KISS_FFT_API kfc_cleanup(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
44
kiss_fft.c
44
kiss_fft.c
@ -203,6 +203,10 @@ static void kf_bfly_generic(
|
||||
int Norig = st->nfft;
|
||||
|
||||
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;
|
||||
@ -244,23 +248,23 @@ void kf_work(
|
||||
const kiss_fft_cpx * Fout_end = Fout + p*m;
|
||||
|
||||
#ifdef _OPENMP
|
||||
// use openmp extensions at the
|
||||
// use openmp extensions at the
|
||||
// top-level (not recursive)
|
||||
if (fstride==1 && p<=5)
|
||||
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)
|
||||
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 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;
|
||||
case 5: kf_bfly5(Fout,fstride,st,m); break;
|
||||
default: kf_bfly_generic(Fout,fstride,st,m,p); break;
|
||||
}
|
||||
return;
|
||||
@ -276,7 +280,7 @@ void kf_work(
|
||||
do{
|
||||
// recursive call:
|
||||
// DFT of size m*p performed by doing
|
||||
// p instances of smaller DFTs of size m,
|
||||
// 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;
|
||||
@ -285,21 +289,21 @@ void kf_work(
|
||||
|
||||
Fout=Fout_beg;
|
||||
|
||||
// recombine the p smaller DFTs
|
||||
// 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;
|
||||
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;
|
||||
case 5: kf_bfly5(Fout,fstride,st,m); break;
|
||||
default: kf_bfly_generic(Fout,fstride,st,m,p); break;
|
||||
}
|
||||
}
|
||||
|
||||
/* facbuf is populated by p1,m1,p2,m2, ...
|
||||
where
|
||||
where
|
||||
p[i] * m[i] = m[i-1]
|
||||
m0 = n */
|
||||
static
|
||||
static
|
||||
void kf_factor(int n,int * facbuf)
|
||||
{
|
||||
int p=4;
|
||||
@ -332,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 );
|
||||
@ -367,7 +373,19 @@ void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,
|
||||
if (fin == fout) {
|
||||
//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);
|
||||
|
52
kiss_fft.h
52
kiss_fft.h
@ -14,6 +14,21 @@
|
||||
#include <math.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
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -31,19 +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) _mm_malloc(nbytes,16)
|
||||
#define KISS_FFT_FREE _mm_free
|
||||
#else
|
||||
#define KISS_FFT_MALLOC malloc
|
||||
#define KISS_FFT_FREE free
|
||||
#endif
|
||||
# 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_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
|
||||
@ -86,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)
|
||||
@ -98,12 +126,12 @@ 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*/
|
||||
@ -113,13 +141,13 @@ void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout
|
||||
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) \
|
||||
|
36
kiss_fft_log.h
Normal file
36
kiss_fft_log.h
Normal 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 */
|
@ -19,11 +19,13 @@ struct kiss_fftnd_state{
|
||||
|
||||
kiss_fftnd_cfg kiss_fftnd_alloc(const int *dims,int ndims,int inverse_fft,void*mem,size_t*lenmem)
|
||||
{
|
||||
KISS_FFT_ALIGN_CHECK(mem)
|
||||
|
||||
kiss_fftnd_cfg st = NULL;
|
||||
int i;
|
||||
int dimprod=1;
|
||||
size_t memneeded = sizeof(struct kiss_fftnd_state);
|
||||
char * ptr;
|
||||
size_t memneeded = KISS_FFT_ALIGN_SIZE_UP(sizeof(struct kiss_fftnd_state));
|
||||
char * ptr = NULL;
|
||||
|
||||
for (i=0;i<ndims;++i) {
|
||||
size_t sublen=0;
|
||||
@ -31,32 +33,33 @@ kiss_fftnd_cfg kiss_fftnd_alloc(const int *dims,int ndims,int inverse_fft,void*m
|
||||
memneeded += sublen; /* st->states[i] */
|
||||
dimprod *= dims[i];
|
||||
}
|
||||
memneeded += sizeof(int) * ndims;/* st->dims */
|
||||
memneeded += sizeof(void*) * ndims;/* st->states */
|
||||
memneeded += sizeof(kiss_fft_cpx) * dimprod; /* st->tmpbuf */
|
||||
memneeded += KISS_FFT_ALIGN_SIZE_UP(sizeof(int) * ndims);/* st->dims */
|
||||
memneeded += KISS_FFT_ALIGN_SIZE_UP(sizeof(void*) * ndims);/* st->states */
|
||||
memneeded += KISS_FFT_ALIGN_SIZE_UP(sizeof(kiss_fft_cpx) * dimprod); /* st->tmpbuf */
|
||||
|
||||
if (lenmem == NULL) {/* allocate for the caller*/
|
||||
st = (kiss_fftnd_cfg) malloc (memneeded);
|
||||
ptr = (char *) malloc (memneeded);
|
||||
} else { /* initialize supplied buffer if big enough */
|
||||
if (*lenmem >= memneeded)
|
||||
st = (kiss_fftnd_cfg) mem;
|
||||
ptr = (char *) mem;
|
||||
*lenmem = memneeded; /*tell caller how big struct is (or would be) */
|
||||
}
|
||||
if (!st)
|
||||
if (!ptr)
|
||||
return NULL; /*malloc failed or buffer too small */
|
||||
|
||||
st = (kiss_fftnd_cfg) ptr;
|
||||
st->dimprod = dimprod;
|
||||
st->ndims = ndims;
|
||||
ptr=(char*)(st+1);
|
||||
ptr += KISS_FFT_ALIGN_SIZE_UP(sizeof(struct kiss_fftnd_state));
|
||||
|
||||
st->states = (kiss_fft_cfg *)ptr;
|
||||
ptr += sizeof(void*) * ndims;
|
||||
ptr += KISS_FFT_ALIGN_SIZE_UP(sizeof(void*) * ndims);
|
||||
|
||||
st->dims = (int*)ptr;
|
||||
ptr += sizeof(int) * ndims;
|
||||
ptr += KISS_FFT_ALIGN_SIZE_UP(sizeof(int) * ndims);
|
||||
|
||||
st->tmpbuf = (kiss_fft_cpx*)ptr;
|
||||
ptr += sizeof(kiss_fft_cpx) * dimprod;
|
||||
ptr += KISS_FFT_ALIGN_SIZE_UP(sizeof(kiss_fft_cpx) * dimprod);
|
||||
|
||||
for (i=0;i<ndims;++i) {
|
||||
size_t len;
|
@ -17,8 +17,8 @@ extern "C" {
|
||||
|
||||
typedef struct kiss_fftnd_state * kiss_fftnd_cfg;
|
||||
|
||||
kiss_fftnd_cfg kiss_fftnd_alloc(const int *dims,int ndims,int inverse_fft,void*mem,size_t*lenmem);
|
||||
void kiss_fftnd(kiss_fftnd_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
|
||||
kiss_fftnd_cfg KISS_FFT_API kiss_fftnd_alloc(const int *dims,int ndims,int inverse_fft,void*mem,size_t*lenmem);
|
||||
void KISS_FFT_API kiss_fftnd(kiss_fftnd_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
@ -29,36 +29,44 @@ static int prod(const int *dims, int ndims)
|
||||
|
||||
kiss_fftndr_cfg kiss_fftndr_alloc(const int *dims,int ndims,int inverse_fft,void*mem,size_t*lenmem)
|
||||
{
|
||||
KISS_FFT_ALIGN_CHECK(mem)
|
||||
|
||||
kiss_fftndr_cfg st = NULL;
|
||||
size_t nr=0 , nd=0,ntmp=0;
|
||||
int dimReal = dims[ndims-1];
|
||||
int dimOther = prod(dims,ndims-1);
|
||||
size_t memneeded;
|
||||
|
||||
char * ptr = NULL;
|
||||
|
||||
(void)kiss_fftr_alloc(dimReal,inverse_fft,NULL,&nr);
|
||||
(void)kiss_fftnd_alloc(dims,ndims-1,inverse_fft,NULL,&nd);
|
||||
ntmp =
|
||||
MAX( 2*dimOther , dimReal+2) * sizeof(kiss_fft_scalar) // freq buffer for one pass
|
||||
+ dimOther*(dimReal+2) * sizeof(kiss_fft_scalar); // large enough to hold entire input in case of in-place
|
||||
|
||||
memneeded = sizeof( struct kiss_fftndr_state ) + nr + nd + ntmp;
|
||||
memneeded = KISS_FFT_ALIGN_SIZE_UP(sizeof( struct kiss_fftndr_state )) + KISS_FFT_ALIGN_SIZE_UP(nr) + KISS_FFT_ALIGN_SIZE_UP(nd) + KISS_FFT_ALIGN_SIZE_UP(ntmp);
|
||||
|
||||
if (lenmem==NULL) {
|
||||
st = (kiss_fftndr_cfg) malloc(memneeded);
|
||||
ptr = (char*) malloc(memneeded);
|
||||
}else{
|
||||
if (*lenmem >= memneeded)
|
||||
st = (kiss_fftndr_cfg)mem;
|
||||
ptr = (char *)mem;
|
||||
*lenmem = memneeded;
|
||||
}
|
||||
if (st==NULL)
|
||||
if (ptr==NULL)
|
||||
return NULL;
|
||||
|
||||
st = (kiss_fftndr_cfg) ptr;
|
||||
memset( st , 0 , memneeded);
|
||||
ptr += KISS_FFT_ALIGN_SIZE_UP(sizeof(struct kiss_fftndr_state));
|
||||
|
||||
st->dimReal = dimReal;
|
||||
st->dimOther = dimOther;
|
||||
st->cfg_r = kiss_fftr_alloc( dimReal,inverse_fft,st+1,&nr);
|
||||
st->cfg_nd = kiss_fftnd_alloc(dims,ndims-1,inverse_fft, ((char*) st->cfg_r)+nr,&nd);
|
||||
st->tmpbuf = (char*)st->cfg_nd + nd;
|
||||
st->cfg_r = kiss_fftr_alloc( dimReal,inverse_fft,ptr,&nr);
|
||||
ptr += KISS_FFT_ALIGN_SIZE_UP(nr);
|
||||
st->cfg_nd = kiss_fftnd_alloc(dims,ndims-1,inverse_fft, ptr,&nd);
|
||||
ptr += KISS_FFT_ALIGN_SIZE_UP(nd);
|
||||
st->tmpbuf = ptr;
|
||||
|
||||
return st;
|
||||
}
|
@ -20,7 +20,7 @@ extern "C" {
|
||||
typedef struct kiss_fftndr_state *kiss_fftndr_cfg;
|
||||
|
||||
|
||||
kiss_fftndr_cfg kiss_fftndr_alloc(const int *dims,int ndims,int inverse_fft,void*mem,size_t*lenmem);
|
||||
kiss_fftndr_cfg KISS_FFT_API kiss_fftndr_alloc(const int *dims,int ndims,int inverse_fft,void*mem,size_t*lenmem);
|
||||
/*
|
||||
dims[0] must be even
|
||||
|
||||
@ -28,7 +28,7 @@ kiss_fftndr_cfg kiss_fftndr_alloc(const int *dims,int ndims,int inverse_fft,voi
|
||||
*/
|
||||
|
||||
|
||||
void kiss_fftndr(
|
||||
void KISS_FFT_API kiss_fftndr(
|
||||
kiss_fftndr_cfg cfg,
|
||||
const kiss_fft_scalar *timedata,
|
||||
kiss_fft_cpx *freqdata);
|
||||
@ -37,7 +37,7 @@ void kiss_fftndr(
|
||||
output freqdata has dims[0] X dims[1] X ... X dims[ndims-1]/2+1 complex points
|
||||
*/
|
||||
|
||||
void kiss_fftndri(
|
||||
void KISS_FFT_API kiss_fftndri(
|
||||
kiss_fftndr_cfg cfg,
|
||||
const kiss_fft_cpx *freqdata,
|
||||
kiss_fft_scalar *timedata);
|
@ -20,12 +20,14 @@ struct kiss_fftr_state{
|
||||
|
||||
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 = 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;
|
||||
@ -65,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;
|
||||
@ -77,12 +79,12 @@ void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *fr
|
||||
* contains the sum of the even-numbered elements of the input time sequence
|
||||
* The imag part is the sum of the odd-numbered elements
|
||||
*
|
||||
* The sum of tdc.r and tdc.i is the sum of the input time sequence.
|
||||
* The sum of tdc.r and tdc.i is the sum of the input time sequence.
|
||||
* yielding DC of input time sequence
|
||||
* The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1...
|
||||
* The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1...
|
||||
* yielding Nyquist bin of input time sequence
|
||||
*/
|
||||
|
||||
|
||||
tdc.r = st->tmpbuf[0].r;
|
||||
tdc.i = st->tmpbuf[0].i;
|
||||
C_FIXDIV(tdc,2);
|
||||
@ -90,14 +92,14 @@ void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *fr
|
||||
CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i);
|
||||
freqdata[0].r = tdc.r + tdc.i;
|
||||
freqdata[ncfft].r = tdc.r - tdc.i;
|
||||
#ifdef USE_SIMD
|
||||
#ifdef USE_SIMD
|
||||
freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0);
|
||||
#else
|
||||
freqdata[ncfft].i = freqdata[0].i = 0;
|
||||
#endif
|
||||
|
||||
for ( k=1;k <= ncfft/2 ; ++k ) {
|
||||
fpk = st->tmpbuf[k];
|
||||
fpk = st->tmpbuf[k];
|
||||
fpnk.r = st->tmpbuf[ncfft-k].r;
|
||||
fpnk.i = - st->tmpbuf[ncfft-k].i;
|
||||
C_FIXDIV(fpk,2);
|
||||
@ -120,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;
|
||||
@ -143,7 +145,7 @@ void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *t
|
||||
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
|
||||
#ifdef USE_SIMD
|
||||
st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0);
|
||||
#else
|
||||
st->tmpbuf[ncfft - k].i *= -1;
|
@ -26,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
|
||||
|
||||
@ -34,13 +34,13 @@ 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
|
82
kissfft-config.cmake.in
Normal file
82
kissfft-config.cmake.in
Normal file
@ -0,0 +1,82 @@
|
||||
# kissfft-config.ccmake accept the following components:
|
||||
#
|
||||
# SHARED/STATIC:
|
||||
# This components allows one to choose a shared/static kissfft library.
|
||||
# The default is selected by BUILD_SHARED_LIBS.
|
||||
# They are to be used exclusively. Using them together is an error.
|
||||
#
|
||||
# example:
|
||||
# find_package(kissfft CONFIG REQUIRED COMPONENTS STATIC)
|
||||
#
|
||||
# simd/int16/int32/float/double:
|
||||
# This components allows one to choose the datatype.
|
||||
# When using this component, the target kissfft::kissfft becomes available.
|
||||
# When not using this component, you will have to choose the correct kissfft target.
|
||||
#
|
||||
# example:
|
||||
# find_package(kissfft CONFIG REQUIRED)
|
||||
# # - kissfft::kissfft-float, kissfft::kissfft-int32_t/ ... are available (if they are installed)
|
||||
# # - kissfft::kissfft is not available,
|
||||
#
|
||||
# find_package(kissfft CONFIG REQUIRED COMPONENTS int32_t)
|
||||
# # - kissfft::kissfft-float, kissfft::kissfft-int32_t/ ... are available (if they are installed)
|
||||
# # - kissfft::kissfft is available (as an alias for kissfft::kissfft-int32_t),
|
||||
|
||||
@PACKAGE_INIT@
|
||||
|
||||
cmake_minimum_required(VERSION 3.3)
|
||||
|
||||
# Set include glob of config files using SHARED/static component, BUILD_SHARED_LIBS by default
|
||||
set(_kissfft_shared_detected OFF)
|
||||
set(_kissfft_shared ${BUILD_SHARED_LIBS})
|
||||
if("SHARED" IN_LIST kissfft_FIND_COMPONENTS)
|
||||
set(_kissfft_shared_detected ON)
|
||||
set(_kissfft_shared ON)
|
||||
endif()
|
||||
if("STATIC" IN_LIST kissfft_FIND_COMPONENTS)
|
||||
if(_kissfft_shared_detected)
|
||||
message(FATAL_ERROR "SHARED and STATIC components cannot be used together")
|
||||
endif()
|
||||
set(_kissfft_shared_detected ON)
|
||||
set(_kissfft_shared OFF)
|
||||
endif()
|
||||
|
||||
if(_kissfft_shared)
|
||||
set(_kissfft_config_glob "kissfft-*-shared-targets.cmake")
|
||||
else()
|
||||
set(_kissfft_config_glob "kissfft-*-static-targets.cmake")
|
||||
endif()
|
||||
|
||||
# Load information for all configured kissfft
|
||||
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
file(GLOB CONFIG_FILES "${_DIR}/${_kissfft_config_glob}")
|
||||
foreach(f ${CONFIG_FILES})
|
||||
include(${f})
|
||||
endforeach()
|
||||
|
||||
# If a datatype component is passed, create kissfft::kissfft
|
||||
set(_kissfft_datatype_detected)
|
||||
foreach(_kissfft_datatype simd int16 int32 float double)
|
||||
if(_kissfft_datatype IN_LIST kissfft_FIND_COMPONENTS)
|
||||
if(_kissfft_datatype_detected)
|
||||
message(FATAL_ERROR "Cannot define datatype COMPONENT twice: ${_kissfft_datatype_detected} and ${_kissfft_datatype}")
|
||||
endif()
|
||||
set(_kissfft_datatype_detected ${_kissfft_datatype})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(_kissfft_datatype_detected)
|
||||
if(NOT TARGET kissfft::kissfft-${_kissfft_datatype_detected})
|
||||
message(FATAL_ERROR "kissfft with datatype=${_kissfft_datatype_detected} is not installed")
|
||||
endif()
|
||||
if(TARGET kissfft::kissfft)
|
||||
message(SEND_ERROR "kissfft::kissfft already exists. You cannot use 2 find_package's with datatype that are visible to eachother.")
|
||||
else()
|
||||
add_library(kissfft::kissfft INTERFACE IMPORTED)
|
||||
set_property(TARGET kissfft::kissfft PROPERTY INTERFACE_LINK_LIBRARIES kissfft::kissfft-${_kissfft_datatype_detected})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(kissfft_FOUND ON)
|
||||
set(KISSFFT_VERSION @kissfft_VERSION@)
|
||||
|
@ -126,7 +126,7 @@ class kissfft
|
||||
/// of size @c 2*N.
|
||||
///
|
||||
/// The 0-th and N-th value of the DFT are real numbers. These are
|
||||
/// stored in @c dst[0].real() and @c dst[1].imag() respectively.
|
||||
/// stored in @c dst[0].real() and @c dst[0].imag() respectively.
|
||||
/// The remaining DFT values up to the index N-1 are stored in
|
||||
/// @c dst[1] to @c dst[N-1].
|
||||
/// The other half of the DFT values can be calculated from the
|
||||
|
10
kissfft.pc.in
Normal file
10
kissfft.pc.in
Normal file
@ -0,0 +1,10 @@
|
||||
prefix=@PKGCONFIG_KISSFFT_PREFIX@
|
||||
libdir=@PKGCONFIG_KISSFFT_LIBDIR@
|
||||
includedir=@PKGCONFIG_KISSFFT_INCLUDEDIR@
|
||||
|
||||
Name: kissfft
|
||||
Description: A Fast Fourier Transform (FFT) library that tries to Keep it Simple, Stupid
|
||||
Version: @PKGCONFIG_KISSFFT_VERSION@
|
||||
|
||||
Libs: @PKG_OPENMP@ -L${libdir} -l@KISSFFT_OUTPUT_NAME@
|
||||
Cflags: -I@PKGCONFIG_KISSFFT_PKGINCLUDEDIR@ @PKG_KISSFFT_DEFS@
|
63
test/CMakeLists.txt
Normal file
63
test/CMakeLists.txt
Normal file
@ -0,0 +1,63 @@
|
||||
function(add_kissfft_test_executable NAME)
|
||||
add_kissfft_executable(${NAME} ${ARGN})
|
||||
target_include_directories(${NAME} PRIVATE ..)
|
||||
|
||||
add_test(NAME ${NAME} COMMAND ${NAME})
|
||||
set_tests_properties(${NAME} PROPERTIES TIMEOUT 3600)
|
||||
endfunction()
|
||||
|
||||
set(KISSFFT_TEST_NUMFFTS 10000)
|
||||
|
||||
#
|
||||
# Add tools-independent fastfilt_* (../tools/fft_*) executable without adding a test
|
||||
#
|
||||
|
||||
add_kissfft_executable(fastfilt ../tools/fftutil.c)
|
||||
target_include_directories(fastfilt PRIVATE ..)
|
||||
|
||||
#
|
||||
# Add test executables and define tests
|
||||
#
|
||||
|
||||
add_kissfft_test_executable(bm_kiss benchkiss.c pstats.c)
|
||||
# add_test(NAME benchmar COMMAND ${NAME})
|
||||
# set_tests_properties(${NAME} PROPERTIES TIMEOUT 3600)
|
||||
|
||||
include(FindPkgConfig)
|
||||
if(KISSFFT_FLOAT)
|
||||
set(fftw3_pkg fftw3f)
|
||||
else()
|
||||
set(fftw3_pkg fftw3)
|
||||
endif()
|
||||
pkg_check_modules(fftw3 REQUIRED IMPORTED_TARGET ${fftw3_pkg})
|
||||
add_kissfft_test_executable(bm_fftw benchfftw.c pstats.c)
|
||||
target_link_libraries(bm_fftw PRIVATE PkgConfig::fftw3)
|
||||
|
||||
add_kissfft_test_executable(st twotonetest.c)
|
||||
|
||||
add_kissfft_test_executable(tkfc twotonetest.c)
|
||||
target_compile_definitions(tkfc PRIVATE KFC_TEST)
|
||||
|
||||
add_kissfft_test_executable(ffr twotonetest.c)
|
||||
add_kissfft_test_executable(tr test_real.c)
|
||||
|
||||
add_kissfft_test_executable(testcpp testcpp.cc)
|
||||
|
||||
if(KISSFFT_DATATYPE MATCHES "^simd$")
|
||||
add_kissfft_test_executable(tsimd test_simd.c)
|
||||
target_compile_definitions(tsimd PRIVATE USE_SIMD)
|
||||
if (NOT MSVC)
|
||||
target_compile_options(kissfft PRIVATE -msse)
|
||||
else()
|
||||
target_compile_options(kissfft PRIVATE "/arch:SSE")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(PythonInterp REQUIRED)
|
||||
add_test(NAME testkiss.py COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/testkiss.py")
|
||||
list(APPEND TESTKISS_PY_ENV "KISSFFT_DATATYPE=${KISSFFT_DATATYPE}")
|
||||
list(APPEND TESTKISS_PY_ENV "KISSFFT_OPENMP=${KISSFFT_OPENMP}")
|
||||
set_tests_properties(testkiss.py PROPERTIES
|
||||
TIMEOUT 3600
|
||||
ENVIRONMENT "${TESTKISS_PY_ENV}"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
229
test/Makefile
229
test/Makefile
@ -1,101 +1,188 @@
|
||||
#
|
||||
# Warnings
|
||||
#
|
||||
|
||||
WARNINGS=-W -Wall -Wstrict-prototypes -Wmissing-prototypes -Waggregate-return \
|
||||
WARNINGS = -W -Wall -Wstrict-prototypes -Wmissing-prototypes \
|
||||
-Wcast-align -Wcast-qual -Wnested-externs -Wshadow -Wbad-function-cast \
|
||||
-Wwrite-strings
|
||||
|
||||
CFLAGS=-O3 -I.. -I../tools $(WARNINGS)
|
||||
CFLAGS+=-ffast-math -fomit-frame-pointer
|
||||
#CFLAGS+=-funroll-loops
|
||||
#CFLAGS+=-march=prescott
|
||||
#CFLAGS+= -mtune=native
|
||||
# TIP: try adding -openmp or -fopenmp to enable OPENMP directives and use of multiple cores
|
||||
#CFLAGS+=-fopenmp
|
||||
CFLAGS+= $(CFLAGADD)
|
||||
#
|
||||
# Compile-time definitions
|
||||
#
|
||||
|
||||
CFLAGS = -O3 -I.. -I../tools $(WARNINGS)
|
||||
CFLAGS += -ffast-math -fomit-frame-pointer
|
||||
#CFLAGS += -funroll-loops
|
||||
#CFLAGS += -march=prescott
|
||||
#CFLAGS += -mtune=native
|
||||
# TIP: try adding -openmp or -fopenmp to enable OPENMP directives and use of multiple cores
|
||||
#CFLAGS += -fopenmp
|
||||
CFLAGS += $(CFLAGADD)
|
||||
|
||||
CXXFLAGS = -O3 -ffast-math -fomit-frame-pointer -I.. -W -Wall -march=native -mtune=native
|
||||
|
||||
#
|
||||
# Count of FFT runs tested
|
||||
#
|
||||
|
||||
ifeq "$(NFFT)" ""
|
||||
NFFT=1800
|
||||
NFFT = 1800
|
||||
endif
|
||||
ifeq "$(NUMFFTS)" ""
|
||||
NUMFFTS=10000
|
||||
NUMFFTS = 10000
|
||||
endif
|
||||
|
||||
ifeq "$(DATATYPE)" ""
|
||||
DATATYPE=float
|
||||
endif
|
||||
#
|
||||
# Test binary executable names
|
||||
#
|
||||
|
||||
BENCHKISS=bm_kiss_$(DATATYPE)
|
||||
BENCHFFTW=bm_fftw_$(DATATYPE)
|
||||
SELFTEST=st_$(DATATYPE)
|
||||
TESTREAL=tr_$(DATATYPE)
|
||||
TESTKFC=tkfc_$(DATATYPE)
|
||||
FASTFILTREAL=ffr_$(DATATYPE)
|
||||
SELFTESTSRC=twotonetest.c
|
||||
SELFTESTSRC = twotonetest.c
|
||||
|
||||
|
||||
TYPEFLAGS=-Dkiss_fft_scalar=$(DATATYPE)
|
||||
|
||||
ifeq "$(DATATYPE)" "int16_t"
|
||||
TYPEFLAGS=-DFIXED_POINT=16
|
||||
endif
|
||||
|
||||
ifeq "$(DATATYPE)" "int32_t"
|
||||
TYPEFLAGS=-DFIXED_POINT=32
|
||||
endif
|
||||
|
||||
ifeq "$(DATATYPE)" "simd"
|
||||
TYPEFLAGS=-DUSE_SIMD=1 -msse
|
||||
endif
|
||||
|
||||
|
||||
ifeq "$(DATATYPE)" "float"
|
||||
# fftw needs to be built with --enable-float to build this lib
|
||||
FFTWLIB=-lfftw3f
|
||||
ifneq ($(KISSFFT_OPENMP),1)
|
||||
BENCHKISS = bm-kiss-$(KISSFFT_DATATYPE)
|
||||
BENCHFFTW = bm-fftw-$(KISSFFT_DATATYPE)
|
||||
SELFTEST = st-$(KISSFFT_DATATYPE)
|
||||
TESTREAL = tr-$(KISSFFT_DATATYPE)
|
||||
TESTKFC = tkfc-$(KISSFFT_DATATYPE)
|
||||
TESTFASTFILT = fastfilt-$(KISSFFT_DATATYPE)
|
||||
TESTCPP = testcpp-$(KISSFFT_DATATYPE)
|
||||
TESTSIMD = testsimd
|
||||
else
|
||||
FFTWLIB=-lfftw3
|
||||
BENCHKISS = bm-kiss-$(KISSFFT_DATATYPE)-openmp
|
||||
BENCHFFTW = bm-fftw-$(KISSFFT_DATATYPE)-openmp
|
||||
SELFTEST = st-$(KISSFFT_DATATYPE)-openmp
|
||||
TESTREAL = tr-$(KISSFFT_DATATYPE)-openmp
|
||||
TESTKFC = tkfc-$(KISSFFT_DATATYPE)-openmp
|
||||
TESTFASTFILT = fastfilt-$(KISSFFT_DATATYPE)-openmp
|
||||
TESTCPP = testcpp-$(KISSFFT_DATATYPE)-openmp
|
||||
TESTSIMD = testsimd-openmp
|
||||
CFLAGS += -fopenmp
|
||||
CXXFLAGS += -fopenmp
|
||||
endif
|
||||
|
||||
FFTWLIBDIR=-L/usr/local/lib/
|
||||
ifeq "$(KISSFFT_DATATYPE)" "float"
|
||||
# fftw needs to be built with --enable-float to build this lib
|
||||
FFTWLIB = -lfftw3f
|
||||
else
|
||||
FFTWLIB = -lfftw3
|
||||
endif
|
||||
|
||||
SRCFILES=../kiss_fft.c ../tools/kiss_fftnd.c ../tools/kiss_fftr.c pstats.c ../tools/kfc.c ../tools/kiss_fftndr.c
|
||||
FFTWLIBDIR ?= $(ABS_LIBDIR)
|
||||
ABS_FFTWLIBDIR = $(abspath $(FFTWLIBDIR))
|
||||
|
||||
all: tools $(BENCHKISS) $(SELFTEST) $(BENCHFFTW) $(TESTREAL) $(TESTKFC)
|
||||
#
|
||||
# Check missing external libraries
|
||||
#
|
||||
|
||||
tools:
|
||||
cd ../tools && make all
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
LIBFFTW_MISSING = $(shell echo "int main(){return 0;}" > _test_library_dummy.c; \
|
||||
$(CC) -o _test_library_dummy _test_library_dummy.c $(FFTWLIB) -L$(ABS_FFTWLIBDIR); \
|
||||
echo $$?; \
|
||||
rm -f _test_library_dummy.c _test_library_dummy)
|
||||
endif
|
||||
|
||||
#
|
||||
# Find Python interpreter
|
||||
#
|
||||
|
||||
$(SELFTEST): $(SELFTESTSRC) $(SRCFILES)
|
||||
$(CC) -o $@ $(CFLAGS) $(TYPEFLAGS) $+ -lm
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
PYTHON_INTERPRETER = $(shell python --version)
|
||||
ifeq ($(PYTHON_INTERPRETER), )
|
||||
PYTHON_INTERPRETER = $(shell python2 --version)
|
||||
ifeq ($(PYTHON_INTERPRETER), )
|
||||
PYTHON_INTERPRETER = $(shell python3 --version)
|
||||
ifeq ($(PYTHON_INTERPRETER), )
|
||||
$(error ERROR: Can not find Python interpreter!)
|
||||
else
|
||||
PYTHON_INTERPRETER = "python3"
|
||||
endif
|
||||
else
|
||||
PYTHON_INTERPRETER = "python2"
|
||||
endif
|
||||
else
|
||||
PYTHON_INTERPRETER = "python"
|
||||
endif
|
||||
endif
|
||||
|
||||
$(TESTKFC): $(SRCFILES)
|
||||
$(CC) -o $@ $(CFLAGS) -DKFC_TEST $(TYPEFLAGS) $+ -lm
|
||||
|
||||
$(TESTREAL): test_real.c $(SRCFILES)
|
||||
$(CC) -o $@ $(CFLAGS) $(TYPEFLAGS) $+ -lm
|
||||
#
|
||||
# Target: "make all"
|
||||
#
|
||||
|
||||
$(BENCHKISS): benchkiss.c $(SRCFILES)
|
||||
$(CC) -o $@ $(CFLAGS) $(TYPEFLAGS) $+ -lm
|
||||
all: $(BENCHKISS) $(SELFTEST) $(BENCHFFTW) $(TESTREAL) $(TESTKFC) $(TESTFASTFILT)
|
||||
|
||||
#
|
||||
# Individual test make rules
|
||||
#
|
||||
|
||||
$(SELFTEST): $(SELFTESTSRC)
|
||||
$(CC) -o $@ $(CFLAGS) $(TYPEFLAGS) $< -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
|
||||
|
||||
$(TESTKFC): ../kfc.c
|
||||
$(CC) -o $@ $(CFLAGS) -DKFC_TEST $(TYPEFLAGS) $^ -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
|
||||
|
||||
$(TESTREAL): test_real.c
|
||||
$(CC) -o $@ $(CFLAGS) $(TYPEFLAGS) $< -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
|
||||
|
||||
$(BENCHKISS): benchkiss.c pstats.c
|
||||
$(CC) -o $@ $(CFLAGS) $(TYPEFLAGS) $^ -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
|
||||
|
||||
$(TESTFASTFILT): ../tools/fftutil.c
|
||||
$(CC) -o $@ $(CFLAGS) -DKFC_TEST $(TYPEFLAGS) $^ -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
|
||||
|
||||
$(BENCHFFTW): benchfftw.c pstats.c
|
||||
@echo "======attempting to build FFTW benchmark"
|
||||
@$(CC) -o $@ $(CFLAGS) -DDATATYPE$(DATATYPE) $+ $(FFTWLIB) $(FFTWLIBDIR) -lm || echo "FFTW not available for comparison"
|
||||
$(warning ======attempting to build FFTW benchmark)
|
||||
ifeq ($(LIBFFTW_MISSING), 0)
|
||||
$(CC) -o $@ $(CFLAGS) -DDATATYPE$(KISSFFT_DATATYPE) $^ $(FFTWLIB) -L$(ABS_FFTWLIBDIR) -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
|
||||
else
|
||||
$(warning WARNING: No FFTW development files found! FFTW not available for comparison!)
|
||||
endif
|
||||
|
||||
#
|
||||
# Test SSE
|
||||
#
|
||||
|
||||
$(TESTSIMD): test_simd.c
|
||||
ifeq "$(KISSFFT_DATATYPE)" "simd"
|
||||
$(CC) -o $@ -g $(CFLAGS) -DUSE_SIMD=1 -msse $< -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
|
||||
else
|
||||
$(error ERROR: This test makes sense only with KISSFFT_DATATYPE=simd)
|
||||
endif
|
||||
|
||||
testsse: $(TESTSIMD)
|
||||
LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):.." ./$(TESTSIMD)
|
||||
|
||||
#
|
||||
# Test C++
|
||||
#
|
||||
|
||||
$(TESTCPP): testcpp.cc ../kissfft.hh
|
||||
$(CXX) -o $@ $(CXXFLAGS) testcpp.cc -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
|
||||
|
||||
testcpp: $(TESTCPP)
|
||||
LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):.." ./$(TESTCPP)
|
||||
|
||||
#
|
||||
# Target: "make test"
|
||||
#
|
||||
|
||||
test: all
|
||||
@./$(TESTKFC)
|
||||
@echo "======1d & 2-d complex fft self test (type= $(DATATYPE) )"
|
||||
@./$(SELFTEST)
|
||||
@echo "======real FFT (type= $(DATATYPE) )"
|
||||
@./$(TESTREAL)
|
||||
@echo "======timing test (type=$(DATATYPE))"
|
||||
@./$(BENCHKISS) -x $(NUMFFTS) -n $(NFFT)
|
||||
@[ -x ./$(BENCHFFTW) ] && ./$(BENCHFFTW) -x $(NUMFFTS) -n $(NFFT) ||true
|
||||
@echo "======higher dimensions type=$(DATATYPE))"
|
||||
@./testkiss.py
|
||||
ifeq "$(KISSFFT_DATATYPE)" "simd"
|
||||
$(MAKE) testsse
|
||||
endif
|
||||
@LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):.." ./$(TESTKFC)
|
||||
$(warning ======1d & 2-d complex fft self test (type= $(KISSFFT_DATATYPE) ))
|
||||
@LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):.." ./$(SELFTEST)
|
||||
$(warning ======real FFT (type= $(KISSFFT_DATATYPE) ))
|
||||
@LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):.." ./$(TESTREAL)
|
||||
$(warning ======timing test (type=$(KISSFFT_DATATYPE)))
|
||||
@LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):.." ./$(BENCHKISS) -x $(NUMFFTS) -n $(NFFT)
|
||||
@[ -x ./$(BENCHFFTW) ] && LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):.." ./$(BENCHFFTW) -x $(NUMFFTS) -n $(NFFT) || true
|
||||
$(warning ======higher dimensions (type=$(KISSFFT_DATATYPE)))
|
||||
@LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):.." $(PYTHON_INTERPRETER) ./testkiss.py
|
||||
|
||||
CXXFLAGS=-O3 -ffast-math -fomit-frame-pointer -I.. -I../tools -W -Wall -march=native -mtune=native
|
||||
testcpp: testcpp.cc ../kissfft.hh
|
||||
$(CXX) -o $@ $(CXXFLAGS) testcpp.cc -lm
|
||||
#
|
||||
# Target: "make clean"
|
||||
#
|
||||
|
||||
clean:
|
||||
rm -f *~ bm_* st_* tr_* kf_* tkfc_* ff_* ffr_* *.pyc *.pyo *.dat testcpp
|
||||
rm -f *~ bm-* st-* tr-* kf-* tkfc-* ff-* fastfilt-* *.pyc *.pyo *.dat testcpp-* testsimd testsimd-* _test_library_dummy _test_library_dummy.c
|
||||
|
@ -1,97 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# 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.
|
||||
|
||||
# use FFTPACK as a baseline
|
||||
import FFT
|
||||
from Numeric import *
|
||||
import math
|
||||
import random
|
||||
import sys
|
||||
import struct
|
||||
import fft
|
||||
|
||||
pi=math.pi
|
||||
e=math.e
|
||||
j=complex(0,1)
|
||||
lims=(-32768,32767)
|
||||
|
||||
def randbuf(n,cpx=1):
|
||||
res = array( [ random.uniform( lims[0],lims[1] ) for i in range(n) ] )
|
||||
if cpx:
|
||||
res = res + j*randbuf(n,0)
|
||||
return res
|
||||
|
||||
def main():
|
||||
from getopt import getopt
|
||||
import popen2
|
||||
opts,args = getopt( sys.argv[1:],'u:n:Rt:' )
|
||||
opts=dict(opts)
|
||||
exitcode=0
|
||||
|
||||
util = opts.get('-u','./kf_float')
|
||||
|
||||
try:
|
||||
dims = [ int(d) for d in opts['-n'].split(',')]
|
||||
cpx = opts.get('-R') is None
|
||||
fmt=opts.get('-t','f')
|
||||
except KeyError:
|
||||
sys.stderr.write("""
|
||||
usage: compfft.py
|
||||
-n d1[,d2,d3...] : FFT dimension(s)
|
||||
-u utilname : see sample_code/fftutil.c, default = ./kf_float
|
||||
-R : real-optimized version\n""")
|
||||
sys.exit(1)
|
||||
|
||||
x = fft.make_random( dims )
|
||||
|
||||
cmd = '%s -n %s ' % ( util, ','.join([ str(d) for d in dims]) )
|
||||
if cpx:
|
||||
xout = FFT.fftnd(x)
|
||||
xout = reshape(xout,(size(xout),))
|
||||
else:
|
||||
cmd += '-R '
|
||||
xout = FFT.real_fft(x)
|
||||
|
||||
proc = popen2.Popen3( cmd , bufsize=len(x) )
|
||||
|
||||
proc.tochild.write( dopack( x , fmt ,cpx ) )
|
||||
proc.tochild.close()
|
||||
xoutcomp = dounpack( proc.fromchild.read( ) , fmt ,1 )
|
||||
#xoutcomp = reshape( xoutcomp , dims )
|
||||
|
||||
sig = xout * conjugate(xout)
|
||||
sigpow = sum( sig )
|
||||
|
||||
diff = xout-xoutcomp
|
||||
noisepow = sum( diff * conjugate(diff) )
|
||||
|
||||
snr = 10 * math.log10(abs( sigpow / noisepow ) )
|
||||
if snr<100:
|
||||
print xout
|
||||
print xoutcomp
|
||||
exitcode=1
|
||||
print 'NFFT=%s,SNR = %f dB' % (str(dims),snr)
|
||||
sys.exit(exitcode)
|
||||
|
||||
def dopack(x,fmt,cpx):
|
||||
x = reshape( x, ( size(x),) )
|
||||
if cpx:
|
||||
s = ''.join( [ struct.pack('ff',c.real,c.imag) for c in x ] )
|
||||
else:
|
||||
s = ''.join( [ struct.pack('f',c) for c in x ] )
|
||||
return s
|
||||
|
||||
def dounpack(x,fmt,cpx):
|
||||
uf = fmt * ( len(x) / 4 )
|
||||
s = struct.unpack(uf,x)
|
||||
if cpx:
|
||||
return array(s[::2]) + array( s[1::2] )*j
|
||||
else:
|
||||
return array(s )
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
107
test/fastfir.py
107
test/fastfir.py
@ -1,107 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# 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.
|
||||
|
||||
from Numeric import *
|
||||
from FFT import *
|
||||
|
||||
def make_random(len):
|
||||
import random
|
||||
res=[]
|
||||
for i in range(int(len)):
|
||||
r=random.uniform(-1,1)
|
||||
i=random.uniform(-1,1)
|
||||
res.append( complex(r,i) )
|
||||
return res
|
||||
|
||||
def slowfilter(sig,h):
|
||||
translen = len(h)-1
|
||||
return convolve(sig,h)[translen:-translen]
|
||||
|
||||
def nextpow2(x):
|
||||
return 2 ** math.ceil(math.log(x)/math.log(2))
|
||||
|
||||
def fastfilter(sig,h,nfft=None):
|
||||
if nfft is None:
|
||||
nfft = int( nextpow2( 2*len(h) ) )
|
||||
H = fft( h , nfft )
|
||||
scraplen = len(h)-1
|
||||
keeplen = nfft-scraplen
|
||||
res=[]
|
||||
isdone = 0
|
||||
lastidx = nfft
|
||||
idx0 = 0
|
||||
while not isdone:
|
||||
idx1 = idx0 + nfft
|
||||
if idx1 >= len(sig):
|
||||
idx1 = len(sig)
|
||||
lastidx = idx1-idx0
|
||||
if lastidx <= scraplen:
|
||||
break
|
||||
isdone = 1
|
||||
Fss = fft(sig[idx0:idx1],nfft)
|
||||
fm = Fss * H
|
||||
m = inverse_fft(fm)
|
||||
res.append( m[scraplen:lastidx] )
|
||||
idx0 += keeplen
|
||||
return concatenate( res )
|
||||
|
||||
def main():
|
||||
import sys
|
||||
from getopt import getopt
|
||||
opts,args = getopt(sys.argv[1:],'rn:l:')
|
||||
opts=dict(opts)
|
||||
|
||||
siglen = int(opts.get('-l',1e4 ) )
|
||||
hlen =50
|
||||
|
||||
nfft = int(opts.get('-n',128) )
|
||||
usereal = opts.has_key('-r')
|
||||
|
||||
print 'nfft=%d'%nfft
|
||||
# make a signal
|
||||
sig = make_random( siglen )
|
||||
# make an impulse response
|
||||
h = make_random( hlen )
|
||||
#h=[1]*2+[0]*3
|
||||
if usereal:
|
||||
sig=[c.real for c in sig]
|
||||
h=[c.real for c in h]
|
||||
|
||||
# perform MAC filtering
|
||||
yslow = slowfilter(sig,h)
|
||||
#print '<YSLOW>',yslow,'</YSLOW>'
|
||||
#yfast = fastfilter(sig,h,nfft)
|
||||
yfast = utilfastfilter(sig,h,nfft,usereal)
|
||||
#print yfast
|
||||
print 'len(yslow)=%d'%len(yslow)
|
||||
print 'len(yfast)=%d'%len(yfast)
|
||||
diff = yslow-yfast
|
||||
snr = 10*log10( abs( vdot(yslow,yslow) / vdot(diff,diff) ) )
|
||||
print 'snr=%s' % snr
|
||||
if snr < 10.0:
|
||||
print 'h=',h
|
||||
print 'sig=',sig[:5],'...'
|
||||
print 'yslow=',yslow[:5],'...'
|
||||
print 'yfast=',yfast[:5],'...'
|
||||
|
||||
def utilfastfilter(sig,h,nfft,usereal):
|
||||
import compfft
|
||||
import os
|
||||
open( 'sig.dat','w').write( compfft.dopack(sig,'f',not usereal) )
|
||||
open( 'h.dat','w').write( compfft.dopack(h,'f',not usereal) )
|
||||
if usereal:
|
||||
util = './fastconvr'
|
||||
else:
|
||||
util = './fastconv'
|
||||
cmd = 'time %s -n %d -i sig.dat -h h.dat -o out.dat' % (util, nfft)
|
||||
print cmd
|
||||
ec = os.system(cmd)
|
||||
print 'exited->',ec
|
||||
return compfft.dounpack(open('out.dat').read(),'f',not usereal)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
201
test/fft.py
201
test/fft.py
@ -1,201 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# 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.
|
||||
|
||||
import math
|
||||
import sys
|
||||
import random
|
||||
|
||||
pi=math.pi
|
||||
e=math.e
|
||||
j=complex(0,1)
|
||||
|
||||
def fft(f,inv):
|
||||
n=len(f)
|
||||
if n==1:
|
||||
return f
|
||||
|
||||
for p in 2,3,5:
|
||||
if n%p==0:
|
||||
break
|
||||
else:
|
||||
raise Exception('%s not factorable ' % n)
|
||||
|
||||
m = n/p
|
||||
Fout=[]
|
||||
for q in range(p): # 0,1
|
||||
fp = f[q::p] # every p'th time sample
|
||||
Fp = fft( fp ,inv)
|
||||
Fout.extend( Fp )
|
||||
|
||||
for u in range(m):
|
||||
scratch = Fout[u::m] # u to end in strides of m
|
||||
for q1 in range(p):
|
||||
k = q1*m + u # indices to Fout above that became scratch
|
||||
Fout[ k ] = scratch[0] # cuz e**0==1 in loop below
|
||||
for q in range(1,p):
|
||||
if inv:
|
||||
t = e ** ( j*2*pi*k*q/n )
|
||||
else:
|
||||
t = e ** ( -j*2*pi*k*q/n )
|
||||
Fout[ k ] += scratch[q] * t
|
||||
|
||||
return Fout
|
||||
|
||||
def rifft(F):
|
||||
N = len(F) - 1
|
||||
Z = [0] * (N)
|
||||
for k in range(N):
|
||||
Fek = ( F[k] + F[-k-1].conjugate() )
|
||||
Fok = ( F[k] - F[-k-1].conjugate() ) * e ** (j*pi*k/N)
|
||||
Z[k] = Fek + j*Fok
|
||||
|
||||
fp = fft(Z , 1)
|
||||
|
||||
f = []
|
||||
for c in fp:
|
||||
f.append(c.real)
|
||||
f.append(c.imag)
|
||||
return f
|
||||
|
||||
def real_fft( f,inv ):
|
||||
if inv:
|
||||
return rifft(f)
|
||||
|
||||
N = len(f) / 2
|
||||
|
||||
res = f[::2]
|
||||
ims = f[1::2]
|
||||
|
||||
fp = [ complex(r,i) for r,i in zip(res,ims) ]
|
||||
print 'fft input ', fp
|
||||
Fp = fft( fp ,0 )
|
||||
print 'fft output ', Fp
|
||||
|
||||
F = [ complex(0,0) ] * ( N+1 )
|
||||
|
||||
F[0] = complex( Fp[0].real + Fp[0].imag , 0 )
|
||||
|
||||
for k in range(1,N/2+1):
|
||||
tw = e ** ( -j*pi*(.5+float(k)/N ) )
|
||||
|
||||
F1k = Fp[k] + Fp[N-k].conjugate()
|
||||
F2k = Fp[k] - Fp[N-k].conjugate()
|
||||
F2k *= tw
|
||||
F[k] = ( F1k + F2k ) * .5
|
||||
F[N-k] = ( F1k - F2k ).conjugate() * .5
|
||||
#F[N-k] = ( F1kp + e ** ( -j*pi*(.5+float(N-k)/N ) ) * F2kp ) * .5
|
||||
#F[N-k] = ( F1k.conjugate() - tw.conjugate() * F2k.conjugate() ) * .5
|
||||
|
||||
F[N] = complex( Fp[0].real - Fp[0].imag , 0 )
|
||||
return F
|
||||
|
||||
def main():
|
||||
#fft_func = fft
|
||||
fft_func = real_fft
|
||||
|
||||
tvec = [0.309655,0.815653,0.768570,0.591841,0.404767,0.637617,0.007803,0.012665]
|
||||
Ftvec = [ complex(r,i) for r,i in zip(
|
||||
[3.548571,-0.378761,-0.061950,0.188537,-0.566981,0.188537,-0.061950,-0.378761],
|
||||
[0.000000,-1.296198,-0.848764,0.225337,0.000000,-0.225337,0.848764,1.296198] ) ]
|
||||
|
||||
F = fft_func( tvec,0 )
|
||||
|
||||
nerrs= 0
|
||||
for i in range(len(Ftvec)/2 + 1):
|
||||
if abs( F[i] - Ftvec[i] )> 1e-5:
|
||||
print 'F[%d]: %s != %s' % (i,F[i],Ftvec[i])
|
||||
nerrs += 1
|
||||
|
||||
print '%d errors in forward fft' % nerrs
|
||||
if nerrs:
|
||||
return
|
||||
|
||||
trec = fft_func( F , 1 )
|
||||
|
||||
for i in range(len(trec) ):
|
||||
trec[i] /= len(trec)
|
||||
|
||||
for i in range(len(tvec) ):
|
||||
if abs( trec[i] - tvec[i] )> 1e-5:
|
||||
print 't[%d]: %s != %s' % (i,tvec[i],trec[i])
|
||||
nerrs += 1
|
||||
|
||||
print '%d errors in reverse fft' % nerrs
|
||||
|
||||
|
||||
def make_random(dims=[1]):
|
||||
import Numeric
|
||||
res = []
|
||||
for i in range(dims[0]):
|
||||
if len(dims)==1:
|
||||
r=random.uniform(-1,1)
|
||||
i=random.uniform(-1,1)
|
||||
res.append( complex(r,i) )
|
||||
else:
|
||||
res.append( make_random( dims[1:] ) )
|
||||
return Numeric.array(res)
|
||||
|
||||
def flatten(x):
|
||||
import Numeric
|
||||
ntotal = Numeric.product(Numeric.shape(x))
|
||||
return Numeric.reshape(x,(ntotal,))
|
||||
|
||||
def randmat( ndims ):
|
||||
dims=[]
|
||||
for i in range( ndims ):
|
||||
curdim = int( random.uniform(2,4) )
|
||||
dims.append( curdim )
|
||||
return make_random(dims )
|
||||
|
||||
def test_fftnd(ndims=3):
|
||||
import FFT
|
||||
import Numeric
|
||||
|
||||
x=randmat( ndims )
|
||||
print 'dimensions=%s' % str( Numeric.shape(x) )
|
||||
#print 'x=%s' %str(x)
|
||||
xver = FFT.fftnd(x)
|
||||
x2=myfftnd(x)
|
||||
err = xver - x2
|
||||
errf = flatten(err)
|
||||
xverf = flatten(xver)
|
||||
errpow = Numeric.vdot(errf,errf)+1e-10
|
||||
sigpow = Numeric.vdot(xverf,xverf)+1e-10
|
||||
snr = 10*math.log10(abs(sigpow/errpow) )
|
||||
if snr<80:
|
||||
print xver
|
||||
print x2
|
||||
print 'SNR=%sdB' % str( snr )
|
||||
|
||||
def myfftnd(x):
|
||||
import Numeric
|
||||
xf = flatten(x)
|
||||
Xf = fftndwork( xf , Numeric.shape(x) )
|
||||
return Numeric.reshape(Xf,Numeric.shape(x) )
|
||||
|
||||
def fftndwork(x,dims):
|
||||
import Numeric
|
||||
dimprod=Numeric.product( dims )
|
||||
|
||||
for k in range( len(dims) ):
|
||||
cur_dim=dims[ k ]
|
||||
stride=dimprod/cur_dim
|
||||
next_x = [complex(0,0)]*len(x)
|
||||
for i in range(stride):
|
||||
next_x[i*cur_dim:(i+1)*cur_dim] = fft(x[i:(i+cur_dim)*stride:stride],0)
|
||||
x = next_x
|
||||
return x
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
nd = int(sys.argv[1])
|
||||
except:
|
||||
nd=None
|
||||
if nd:
|
||||
test_fftnd( nd )
|
||||
else:
|
||||
sys.exit(0)
|
275
test/kissfft-testsuite.sh
Normal file
275
test/kissfft-testsuite.sh
Normal file
@ -0,0 +1,275 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Test suite for kissfft
|
||||
#
|
||||
# Copyright (c) 2021, Vasyl Gello.
|
||||
# This file is part of KISS FFT - https://github.com/mborgerding/kissfft
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# See COPYING file for more information.
|
||||
#
|
||||
|
||||
if [ ! -f CHANGELOG ] && [ ! -f kiss_fft.h ]; then
|
||||
echo "ERROR: Please run this testsuite from top level of kissfft source tree!" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
TESTSUITEOUTDIR="$2"
|
||||
|
||||
if [ -z "$TESTSUITEOUTDIR" ]; then
|
||||
TESTSUITEOUTDIR="/tmp/kissfft-testsuite"
|
||||
fi
|
||||
|
||||
if ! mkdir -p "$TESTSUITEOUTDIR"; then
|
||||
echo "ERROR: Can not create directory '$TESTSUITEOUTDIR'!" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Test runner function
|
||||
#
|
||||
# Parameters:
|
||||
#
|
||||
# $1 - Action: "test" or "install"
|
||||
# $2 - Build type: "make" or "cmake"
|
||||
# $3 - Data type: "float" "double" "int16_t" "int32_t" "simd"
|
||||
# $4 - library type: "shared" or "static"
|
||||
# $5 - Include tools: "yes" or "no"
|
||||
# $6 - Install root dir: "existing writable directory"
|
||||
#
|
||||
|
||||
test_runner() {
|
||||
_ACTION="$1"
|
||||
_BUILD_TYPE="$2"
|
||||
_DATA_TYPE="$3"
|
||||
_LIB_TYPE="$4"
|
||||
_OPENMP="$5"
|
||||
_INCLUDE_TOOLS="$6"
|
||||
_INSTALL_ROOT_DIR="$7"
|
||||
|
||||
_CMAKE_OPTS=""
|
||||
_MAKE_OPTS=""
|
||||
|
||||
# Prepare install directory name without "$_OPENMP" and "$_INCLUDE_TOOLS"
|
||||
|
||||
_INSTALL_DIR="$_INSTALL_ROOT_DIR/$_BUILD_TYPE/$_DATA_TYPE/$_LIB_TYPE"
|
||||
|
||||
# Prepare log file without "$_OPENMP" and "$_INCLUDE_TOOLS"
|
||||
|
||||
_LOG_FILE="$_INSTALL_ROOT_DIR/$_ACTION-$_BUILD_TYPE-$_DATA_TYPE-$_LIB_TYPE"
|
||||
|
||||
# Validate parameters
|
||||
|
||||
# Create install root directory
|
||||
|
||||
if [ -z "$_INSTALL_ROOT_DIR" ]; then
|
||||
echo "" >&2
|
||||
echo "ERROR: Empty path to writeable directory" >&2
|
||||
echo "" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$_INSTALL_ROOT_DIR" ]; then
|
||||
if ! mkdir -p "$_INSTALL_ROOT_DIR"; then
|
||||
echo "" >&2
|
||||
echo "ERROR: Can not create directory '$_INSTALL_ROOT_DIR'" >&2
|
||||
echo "" >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$_BUILD_TYPE" != "make" ] && [ "$_BUILD_TYPE" != "cmake" ]; then
|
||||
echo "ERROR: Build type must be one of: cmake make" >&2
|
||||
echo "" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$_DATA_TYPE" != "double" ] &&
|
||||
[ "$_DATA_TYPE" != "float" ] &&
|
||||
[ "$_DATA_TYPE" != "int16_t" ] &&
|
||||
[ "$_DATA_TYPE" != "int32_t" ] &&
|
||||
[ "$_DATA_TYPE" != "simd" ];
|
||||
then
|
||||
echo "ERROR: Data type must be one of: double float int16_t int32_t simd" >&2
|
||||
echo "" >&2
|
||||
return 1
|
||||
else
|
||||
_MAKE_OPTS="$_MAKE_OPTS KISSFFT_DATATYPE=$_DATA_TYPE"
|
||||
_CMAKE_OPTS="$_CMAKE_OPTS -DKISSFFT_DATATYPE=$_DATA_TYPE"
|
||||
fi
|
||||
|
||||
if [ "$_LIB_TYPE" != "shared" ] && [ "$_LIB_TYPE" != "static" ]; then
|
||||
echo "ERROR: Library type must be one of: shared static" >&2
|
||||
echo "" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
case "$_LIB_TYPE" in
|
||||
"shared")
|
||||
;;
|
||||
"static")
|
||||
_MAKE_OPTS="$_MAKE_OPTS KISSFFT_STATIC=1"
|
||||
_CMAKE_OPTS="$_CMAKE_OPTS -DKISSFFT_STATIC=ON"
|
||||
;;
|
||||
"*")
|
||||
echo "ERROR: OpenMP inclusion must be one of: no yes" >&2
|
||||
echo "" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$_OPENMP" in
|
||||
"yes")
|
||||
_INSTALL_DIR="$_INSTALL_DIR/openmp"
|
||||
_LOG_FILE="$_LOG_FILE-openmp"
|
||||
_MAKE_OPTS="$_MAKE_OPTS KISSFFT_OPENMP=1"
|
||||
_CMAKE_OPTS="$_CMAKE_OPTS -DKISSFFT_OPENMP=ON"
|
||||
;;
|
||||
"no")
|
||||
_INSTALL_DIR="$_INSTALL_DIR/noopenmp"
|
||||
_LOG_FILE="$_LOG_FILE-noopenmp"
|
||||
;;
|
||||
"*")
|
||||
echo "ERROR: OpenMP inclusion must be one of: no yes" >&2
|
||||
echo "" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$_INCLUDE_TOOLS" in
|
||||
"yes")
|
||||
_INSTALL_DIR="$_INSTALL_DIR/tools"
|
||||
_LOG_FILE="$_LOG_FILE-tools"
|
||||
;;
|
||||
"no")
|
||||
_INSTALL_DIR="$_INSTALL_DIR/notools"
|
||||
_LOG_FILE="$_LOG_FILE-notools"
|
||||
_MAKE_OPTS="$_MAKE_OPTS KISSFFT_TOOLS=0"
|
||||
_CMAKE_OPTS="$_CMAKE_OPTS -DKISSFFT_TOOLS=OFF"
|
||||
;;
|
||||
"*")
|
||||
echo "ERROR: Tools inclusion must be one of: no yes" >&2
|
||||
echo "" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Clean kissfft
|
||||
|
||||
rm -rf build 1>/dev/null 2>/dev/null
|
||||
make clean 1>/dev/null 2>&1
|
||||
|
||||
# Prepare status line
|
||||
|
||||
_STATUS_LINE="Running: $(printf "% 10s" "$_ACTION") |"
|
||||
_STATUS_LINE="$_STATUS_LINE Build Type: $(printf "% 7s" "$_BUILD_TYPE") |"
|
||||
_STATUS_LINE="$_STATUS_LINE Data Type: $(printf "% 7s" "$_DATA_TYPE") |"
|
||||
_STATUS_LINE="$_STATUS_LINE Lib Type: $(printf "% 7s" "$_LIB_TYPE") |"
|
||||
_STATUS_LINE="$_STATUS_LINE OpenMP: $(printf "% 3s" "$_OPENMP") |"
|
||||
_STATUS_LINE="$_STATUS_LINE Tools: $(printf "% 3s" "$_INCLUDE_TOOLS") |"
|
||||
|
||||
# Skip tests with tools not installed as they are same as with tools
|
||||
|
||||
if [ "$_ACTION" = "test" ] && [ "$_INCLUDE_TOOLS" = "no" ]; then
|
||||
return 2
|
||||
fi
|
||||
|
||||
# Run selected action
|
||||
|
||||
echo "$_STATUS_LINE"
|
||||
|
||||
case "$_ACTION" in
|
||||
"test")
|
||||
_MAKE_OPTS="$_MAKE_OPTS PREFIX=$_INSTALL_DIR"
|
||||
_CMAKE_OPTS="$_CMAKE_OPTS -DCMAKE_INSTALL_PREFIX=$_INSTALL_DIR"
|
||||
|
||||
case "$_BUILD_TYPE" in
|
||||
"make")
|
||||
make $_MAKE_OPTS all 1>>"$_LOG_FILE" 2>&1 &&
|
||||
make $_MAKE_OPTS testsingle 1>>"$_LOG_FILE" 2>&1 &&
|
||||
_RET=$?
|
||||
;;
|
||||
"cmake")
|
||||
mkdir build 1>/dev/null 2>&1 &&
|
||||
cd build &&
|
||||
cmake $_CMAKE_OPTS .. 1>"$_LOG_FILE" 2>&1 &&
|
||||
make all 1>>"$_LOG_FILE" 2>&1 &&
|
||||
make test 1>>"$_LOG_FILE" 2>&1
|
||||
_RET=$?
|
||||
cd ..
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
"install")
|
||||
_MAKE_OPTS="$_MAKE_OPTS PREFIX=$_INSTALL_DIR"
|
||||
_CMAKE_OPTS="$_CMAKE_OPTS -DCMAKE_INSTALL_PREFIX=$_INSTALL_DIR"
|
||||
|
||||
case "$_BUILD_TYPE" in
|
||||
"make")
|
||||
make $_MAKE_OPTS install 1>>"$_LOG_FILE" 2>&1
|
||||
_RET=$?
|
||||
;;
|
||||
"cmake")
|
||||
mkdir build 1>/dev/null 2>&1 &&
|
||||
cd build &&
|
||||
cmake $_CMAKE_OPTS .. 1>"$_LOG_FILE" 2>&1 &&
|
||||
make all 1>>"$_LOG_FILE" 2>&1 &&
|
||||
make install 1>>"$_LOG_FILE" 2>&1
|
||||
_RET=$?
|
||||
cd ..
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: Action must be one of: test install" >&2
|
||||
echo "" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Clean kissfft
|
||||
|
||||
rm -rf build 1>/dev/null 2>/dev/null
|
||||
make clean 1>/dev/null 2>&1
|
||||
|
||||
# Return result
|
||||
|
||||
[ $_RET -eq 0 ] && return 0 || return 1
|
||||
}
|
||||
|
||||
# Main script
|
||||
|
||||
for ACTION in test install; do
|
||||
for BUILD_TYPE in make cmake; do
|
||||
for DATA_TYPE in float double int16_t int32_t simd; do
|
||||
for LIB_TYPE in shared static; do
|
||||
for OPENMP in no yes; do
|
||||
for INCLUDE_TOOLS in no yes; do
|
||||
test_runner \
|
||||
"$ACTION" \
|
||||
"$BUILD_TYPE" \
|
||||
"$DATA_TYPE" \
|
||||
"$LIB_TYPE" \
|
||||
"$OPENMP" \
|
||||
"$INCLUDE_TOOLS" \
|
||||
"$TESTSUITEOUTDIR"
|
||||
|
||||
case $? in
|
||||
0)
|
||||
echo "Result: OK"
|
||||
;;
|
||||
1)
|
||||
echo "Result: FAIL"
|
||||
;;
|
||||
2)
|
||||
# Ignore it
|
||||
echo "Result: IGNORE" 1>/dev/null
|
||||
;;
|
||||
esac
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
||||
done 2>&1 | tee "$TESTSUITEOUTDIR/all-tests.log"
|
@ -1,26 +0,0 @@
|
||||
function maxabsdiff=tailscrap()
|
||||
% test code for circular convolution with the scrapped portion
|
||||
% at the tail of the buffer, rather than the front
|
||||
%
|
||||
% The idea is to rotate the zero-padded h (impulse response) buffer
|
||||
% to the left nh-1 samples, rotating the junk samples as well.
|
||||
% This could be very handy in avoiding buffer copies during fast filtering.
|
||||
nh=10;
|
||||
nfft=256;
|
||||
|
||||
h=rand(1,nh);
|
||||
x=rand(1,nfft);
|
||||
|
||||
hpad=[ h(nh) zeros(1,nfft-nh) h(1:nh-1) ];
|
||||
|
||||
% baseline comparison
|
||||
y1 = filter(h,1,x);
|
||||
y1_notrans = y1(nh:nfft);
|
||||
|
||||
% fast convolution
|
||||
y2 = ifft( fft(hpad) .* fft(x) );
|
||||
y2_notrans=y2(1:nfft-nh+1);
|
||||
|
||||
maxabsdiff = max(abs(y2_notrans - y1_notrans))
|
||||
|
||||
end
|
25
test/test_simd.c
Normal file
25
test/test_simd.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include <kiss_fftnd.h>
|
||||
|
||||
static void test1(void)
|
||||
{
|
||||
int is_inverse = 1;
|
||||
int n[2] = {256,256};
|
||||
size_t nbytes = sizeof(kiss_fft_cpx)*n[0]*n[1];
|
||||
|
||||
kiss_fft_cpx * inbuf = _mm_malloc(nbytes,16);
|
||||
kiss_fft_cpx * outbuf = _mm_malloc(nbytes,16);
|
||||
memset(inbuf,0,nbytes);
|
||||
memset(outbuf,0,nbytes);
|
||||
|
||||
kiss_fftnd_cfg cfg = kiss_fftnd_alloc(n,2,is_inverse,0,0);
|
||||
kiss_fftnd(cfg,inbuf,outbuf);
|
||||
kiss_fft_free(cfg);
|
||||
_mm_free(inbuf);
|
||||
_mm_free(outbuf);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test1();
|
||||
return 0;
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* 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.h"
|
||||
|
||||
|
||||
void check(kiss_fft_cpx * in,kiss_fft_cpx * out,int nfft,int isinverse)
|
||||
{
|
||||
int bin,k;
|
||||
double errpow=0,sigpow=0;
|
||||
|
||||
for (bin=0;bin<nfft;++bin) {
|
||||
double ansr = 0;
|
||||
double ansi = 0;
|
||||
double difr;
|
||||
double difi;
|
||||
|
||||
for (k=0;k<nfft;++k) {
|
||||
double phase = -2*M_PI*bin*k/nfft;
|
||||
double re = cos(phase);
|
||||
double im = sin(phase);
|
||||
if (isinverse)
|
||||
im = -im;
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
re /= nfft;
|
||||
im /= nfft;
|
||||
#endif
|
||||
|
||||
ansr += in[k].r * re - in[k].i * im;
|
||||
ansi += in[k].r * im + in[k].i * re;
|
||||
}
|
||||
difr = ansr - out[bin].r;
|
||||
difi = ansi - out[bin].i;
|
||||
errpow += difr*difr + difi*difi;
|
||||
sigpow += ansr*ansr+ansi*ansi;
|
||||
}
|
||||
printf("nfft=%d inverse=%d,snr = %f\n",nfft,isinverse,10*log10(sigpow/errpow) );
|
||||
}
|
||||
|
||||
void test1d(int nfft,int isinverse)
|
||||
{
|
||||
size_t buflen = sizeof(kiss_fft_cpx)*nfft;
|
||||
|
||||
kiss_fft_cpx * in = (kiss_fft_cpx*)malloc(buflen);
|
||||
kiss_fft_cpx * out= (kiss_fft_cpx*)malloc(buflen);
|
||||
kiss_fft_cfg cfg = kiss_fft_alloc(nfft,isinverse,0,0);
|
||||
int k;
|
||||
|
||||
for (k=0;k<nfft;++k) {
|
||||
in[k].r = (rand() % 65536) - 32768;
|
||||
in[k].i = (rand() % 65536) - 32768;
|
||||
}
|
||||
|
||||
kiss_fft(cfg,in,out);
|
||||
|
||||
check(in,out,nfft,isinverse);
|
||||
|
||||
free(in);
|
||||
free(out);
|
||||
free(cfg);
|
||||
}
|
||||
|
||||
int main(int argc,char ** argv)
|
||||
{
|
||||
if (argc>1) {
|
||||
int k;
|
||||
for (k=1;k<argc;++k) {
|
||||
test1d(atoi(argv[k]),0);
|
||||
test1d(atoi(argv[k]),1);
|
||||
}
|
||||
}else{
|
||||
test1d(32,0);
|
||||
test1d(32,1);
|
||||
}
|
||||
return 0;
|
||||
}
|
196
test/testkiss.py
196
test/testkiss.py
@ -4,158 +4,140 @@
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# See COPYING file for more information.
|
||||
from __future__ import division,print_function
|
||||
from __future__ import absolute_import, division, print_function
|
||||
import math
|
||||
import sys
|
||||
import os
|
||||
import random
|
||||
import struct
|
||||
import getopt
|
||||
import numpy
|
||||
import numpy as np
|
||||
|
||||
pi=math.pi
|
||||
e=math.e
|
||||
po = math.pi
|
||||
e = math.e
|
||||
do_real = False
|
||||
datatype = os.environ.get('KISSFFT_DATATYPE', 'float')
|
||||
openmp = os.environ.get('KISSFFT_OPENMP', 'float')
|
||||
|
||||
doreal=0
|
||||
util = './fastfilt-' + datatype
|
||||
|
||||
datatype = os.environ.get('DATATYPE','float')
|
||||
if openmp == '1' or openmp == 'ON':
|
||||
util = util + '-openmp'
|
||||
|
||||
util = '../tools/fft_' + datatype
|
||||
minsnr=90
|
||||
minsnr = 90
|
||||
if datatype == 'double':
|
||||
fmt='d'
|
||||
elif datatype=='int16_t':
|
||||
fmt='h'
|
||||
minsnr=10
|
||||
elif datatype=='int32_t':
|
||||
fmt='i'
|
||||
elif datatype=='simd':
|
||||
fmt='4f'
|
||||
dtype = np.float64
|
||||
elif datatype == 'float':
|
||||
dtype = np.float32
|
||||
elif datatype == 'int16_t':
|
||||
dtype = np.int16
|
||||
minsnr = 10
|
||||
elif datatype == 'int32_t':
|
||||
dtype = np.int32
|
||||
elif datatype == 'simd':
|
||||
sys.stderr.write('testkiss.py does not yet test simd')
|
||||
sys.exit(0)
|
||||
elif datatype=='float':
|
||||
fmt='f'
|
||||
else:
|
||||
sys.stderr.write('unrecognized datatype %s\n' % datatype)
|
||||
sys.stderr.write('unrecognized datatype {0}\n'.format(datatype))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def dopack(x,cpx=1):
|
||||
x = numpy.reshape( x, ( numpy.size(x),) )
|
||||
|
||||
def dopack(x):
|
||||
if np.iscomplexobj(x):
|
||||
x = x.astype(np.complex128).view(np.float64)
|
||||
else:
|
||||
x = x.astype(np.float64)
|
||||
return x.astype(dtype).tobytes()
|
||||
|
||||
def dounpack(x, cpx):
|
||||
x = np.frombuffer(x, dtype).astype(np.float64)
|
||||
if cpx:
|
||||
s = ''.join( [ struct.pack(fmt*2,c.real,c.imag) for c in x ] )
|
||||
x = x[::2] + 1j * x[1::2]
|
||||
return x
|
||||
|
||||
def make_random(shape):
|
||||
'create random uniform (-1,1) data of the given shape'
|
||||
if do_real:
|
||||
return np.random.uniform(-1, 1, shape)
|
||||
else:
|
||||
s = ''.join( [ struct.pack(fmt,c.real) for c in x ] )
|
||||
return s
|
||||
return (np.random.uniform(-1, 1, shape) + 1j * np.random.uniform(-1, 1, shape))
|
||||
|
||||
def dounpack(x,cpx):
|
||||
uf = fmt * ( len(x) // struct.calcsize(fmt) )
|
||||
s = struct.unpack(uf,x)
|
||||
if cpx:
|
||||
return numpy.array(s[::2]) + numpy.array( s[1::2] )*1j
|
||||
def randmat(ndim):
|
||||
'create a random multidimensional array in range (-1,1)'
|
||||
dims = np.random.randint(2, 5, ndim)
|
||||
if do_real:
|
||||
dims[-1] = (dims[-1] // 2) * 2 # force even last dimension if real
|
||||
return make_random(dims)
|
||||
|
||||
def test_fft(ndim):
|
||||
x = randmat(ndim)
|
||||
|
||||
if do_real:
|
||||
xver = np.fft.rfftn(x)
|
||||
else:
|
||||
return numpy.array(s )
|
||||
xver = np.fft.fftn(x)
|
||||
|
||||
def make_random(dims=[1]):
|
||||
res = []
|
||||
for i in range(dims[0]):
|
||||
if len(dims)==1:
|
||||
r=random.uniform(-1,1)
|
||||
if doreal:
|
||||
res.append( r )
|
||||
else:
|
||||
i=random.uniform(-1,1)
|
||||
res.append( complex(r,i) )
|
||||
else:
|
||||
res.append( make_random( dims[1:] ) )
|
||||
return numpy.array(res)
|
||||
|
||||
def flatten(x):
|
||||
ntotal = numpy.size(x)
|
||||
return numpy.reshape(x,(ntotal,))
|
||||
|
||||
def randmat( ndims ):
|
||||
dims=[]
|
||||
for i in range( ndims ):
|
||||
curdim = int( random.uniform(2,5) )
|
||||
if doreal and i==(ndims-1):
|
||||
curdim = int(curdim/2)*2 # force even last dimension if real
|
||||
dims.append( curdim )
|
||||
return make_random(dims )
|
||||
|
||||
def test_fft(ndims):
|
||||
x=randmat( ndims )
|
||||
|
||||
if doreal:
|
||||
xver = numpy.fft.rfftn(x)
|
||||
else:
|
||||
xver = numpy.fft.fftn(x)
|
||||
|
||||
x2=dofft(x,doreal)
|
||||
x2 = dofft(x, do_real)
|
||||
err = xver - x2
|
||||
errf = flatten(err)
|
||||
xverf = flatten(xver)
|
||||
errpow = numpy.vdot(errf,errf)+1e-10
|
||||
sigpow = numpy.vdot(xverf,xverf)+1e-10
|
||||
snr = 10*math.log10(abs(sigpow/errpow) )
|
||||
print( 'SNR (compared to NumPy) : {0:.1f}dB'.format( float(snr) ) )
|
||||
errf = err.ravel()
|
||||
xverf = xver.ravel()
|
||||
errpow = np.vdot(errf, errf) + 1e-10
|
||||
sigpow = np.vdot(xverf, xverf) + 1e-10
|
||||
snr = 10 * math.log10(abs(sigpow / errpow))
|
||||
print('SNR (compared to NumPy) : {0:.1f}dB'.format(float(snr)))
|
||||
|
||||
if snr<minsnr:
|
||||
print( 'xver=',xver )
|
||||
print( 'x2=',x2)
|
||||
print( 'err',err)
|
||||
if snr < minsnr:
|
||||
print('xver=', xver)
|
||||
print('x2=', x2)
|
||||
print('err', err)
|
||||
sys.exit(1)
|
||||
|
||||
def dofft(x,isreal):
|
||||
dims=list( numpy.shape(x) )
|
||||
x = flatten(x)
|
||||
|
||||
scale=1
|
||||
if datatype=='int16_t':
|
||||
def dofft(x, isreal):
|
||||
dims = list(np.shape(x))
|
||||
x = x.ravel()
|
||||
|
||||
scale = 1
|
||||
if datatype == 'int16_t':
|
||||
x = 32767 * x
|
||||
scale = len(x) / 32767.0
|
||||
elif datatype=='int32_t':
|
||||
elif datatype == 'int32_t':
|
||||
x = 2147483647.0 * x
|
||||
scale = len(x) / 2147483647.0
|
||||
|
||||
cmd='%s -n ' % util
|
||||
cmd = util + ' -n '
|
||||
cmd += ','.join([str(d) for d in dims])
|
||||
if doreal:
|
||||
if do_real:
|
||||
cmd += ' -R '
|
||||
|
||||
print( cmd)
|
||||
print(cmd)
|
||||
|
||||
from subprocess import Popen,PIPE
|
||||
p = Popen(cmd,shell=True,stdin=PIPE,stdout=PIPE )
|
||||
from subprocess import Popen, PIPE
|
||||
p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE)
|
||||
|
||||
p.stdin.write( dopack( x , isreal==False ) )
|
||||
p.stdin.write(dopack(x))
|
||||
p.stdin.close()
|
||||
|
||||
res = dounpack( p.stdout.read() , 1 )
|
||||
if doreal:
|
||||
dims[-1] = int( dims[-1]/2 ) + 1
|
||||
res = dounpack(p.stdout.read(), 1)
|
||||
if do_real:
|
||||
dims[-1] = (dims[-1] // 2) + 1
|
||||
|
||||
res = scale * res
|
||||
|
||||
p.wait()
|
||||
return numpy.reshape(res,dims)
|
||||
return np.reshape(res, dims)
|
||||
|
||||
def main():
|
||||
opts,args = getopt.getopt(sys.argv[1:],'r')
|
||||
opts=dict(opts)
|
||||
|
||||
global doreal
|
||||
doreal = opts.has_key('-r')
|
||||
|
||||
if doreal:
|
||||
print( 'Testing multi-dimensional real FFTs')
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'r')
|
||||
opts = dict(opts)
|
||||
global do_real
|
||||
do_real = '-r' in opts
|
||||
if do_real:
|
||||
print('Testing multi-dimensional real FFTs')
|
||||
else:
|
||||
print( 'Testing multi-dimensional FFTs')
|
||||
print('Testing multi-dimensional FFTs')
|
||||
|
||||
for dim in range(1, 4):
|
||||
test_fft(dim)
|
||||
|
||||
for dim in range(1,4):
|
||||
test_fft( dim )
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
29
tools/CMakeLists.txt
Normal file
29
tools/CMakeLists.txt
Normal file
@ -0,0 +1,29 @@
|
||||
add_kissfft_executable(fastconvr kiss_fastfir.c)
|
||||
target_compile_definitions(fastconvr PRIVATE REAL_FASTFIR FAST_FILT_UTIL)
|
||||
|
||||
add_kissfft_executable(fastconv kiss_fastfir.c)
|
||||
target_compile_definitions(fastconv PRIVATE FAST_FILT_UTIL)
|
||||
|
||||
add_kissfft_executable(fft fftutil.c)
|
||||
|
||||
install(TARGETS fastconv fastconvr fft
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
PUBLIC_HEADER DESTINATION ${PKGINCLUDEDIR})
|
||||
|
||||
# psdpng does not build with "simd" datatype
|
||||
if(NOT KISSFFT_DATATYPE MATCHES "simd")
|
||||
include(FindPkgConfig)
|
||||
pkg_check_modules(libpng REQUIRED IMPORTED_TARGET libpng)
|
||||
add_kissfft_executable(psdpng psdpng.c)
|
||||
target_link_libraries(psdpng PRIVATE PkgConfig::libpng)
|
||||
install(TARGETS psdpng
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
PUBLIC_HEADER DESTINATION ${PKGINCLUDEDIR})
|
||||
endif()
|
||||
|
||||
#FIXME: dumphdr.c is not available
|
||||
#add_kissfft_executable(dumphdr dumphdr.c)
|
137
tools/Makefile
137
tools/Makefile
@ -1,62 +1,101 @@
|
||||
WARNINGS=-W -Wall -Wstrict-prototypes -Wmissing-prototypes -Waggregate-return \
|
||||
#
|
||||
# Warnings
|
||||
#
|
||||
|
||||
WARNINGS = -W -Wall -Wstrict-prototypes -Wmissing-prototypes \
|
||||
-Wcast-align -Wcast-qual -Wnested-externs -Wshadow -Wbad-function-cast \
|
||||
-Wwrite-strings
|
||||
|
||||
ifeq "$(DATATYPE)" ""
|
||||
DATATYPE=float
|
||||
endif
|
||||
#
|
||||
# Compile-time definitions
|
||||
#
|
||||
|
||||
ifeq "$(DATATYPE)" "int32_t"
|
||||
TYPEFLAGS=-DFIXED_POINT=32
|
||||
endif
|
||||
|
||||
ifeq "$(DATATYPE)" "int16_t"
|
||||
TYPEFLAGS=-DFIXED_POINT=16
|
||||
endif
|
||||
|
||||
ifeq "$(DATATYPE)" "simd"
|
||||
TYPEFLAGS=-DUSE_SIMD=1 -msse
|
||||
endif
|
||||
|
||||
ifeq "$(TYPEFLAGS)" ""
|
||||
TYPEFLAGS=-Dkiss_fft_scalar=$(DATATYPE)
|
||||
endif
|
||||
|
||||
ifneq ("$(KISS_FFT_USE_ALLOCA)","")
|
||||
CFLAGS+= -DKISS_FFT_USE_ALLOCA=1
|
||||
endif
|
||||
CFLAGS+= $(CFLAGADD)
|
||||
|
||||
|
||||
FFTUTIL=fft_$(DATATYPE)
|
||||
FASTFILT=fastconv_$(DATATYPE)
|
||||
FASTFILTREAL=fastconvr_$(DATATYPE)
|
||||
PSDPNG=psdpng_$(DATATYPE)
|
||||
DUMPHDR=dumphdr_$(DATATYPE)
|
||||
|
||||
all: $(FFTUTIL) $(FASTFILT) $(FASTFILTREAL)
|
||||
# $(PSDPNG)
|
||||
# $(DUMPHDR)
|
||||
|
||||
#CFLAGS=-Wall -O3 -pedantic -march=pentiumpro -ffast-math -fomit-frame-pointer $(WARNINGS)
|
||||
CFLAGS = -Wall -O3 $(WARNINGS)
|
||||
#CFLAGS = -Wall -O3 -pedantic -march=pentiumpro -ffast-math -fomit-frame-pointer $(WARNINGS)
|
||||
# If the above flags do not work, try the following
|
||||
CFLAGS=-Wall -O3 $(WARNINGS)
|
||||
# tip: try -openmp or -fopenmp to use multiple cores
|
||||
|
||||
$(FASTFILTREAL): ../kiss_fft.c kiss_fastfir.c kiss_fftr.c
|
||||
$(CC) -o $@ $(CFLAGS) -I.. $(TYPEFLAGS) -DREAL_FASTFIR $+ -DFAST_FILT_UTIL -lm
|
||||
CFLAGS += $(CFLAGADD)
|
||||
|
||||
$(FASTFILT): ../kiss_fft.c kiss_fastfir.c
|
||||
$(CC) -o $@ $(CFLAGS) -I.. $(TYPEFLAGS) $+ -DFAST_FILT_UTIL -lm
|
||||
#
|
||||
# Check missing external libraries
|
||||
#
|
||||
|
||||
$(FFTUTIL): ../kiss_fft.c fftutil.c kiss_fftnd.c kiss_fftr.c kiss_fftndr.c
|
||||
$(CC) -o $@ $(CFLAGS) -I.. $(TYPEFLAGS) $+ -lm
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
LIBPNG_MISSING = $(shell echo "int main(){return 0;}" > _test_library_dummy.c; \
|
||||
$(CC) -o _test_library_dummy _test_library_dummy.c -lpng; \
|
||||
echo $$?; \
|
||||
rm -f _test_library_dummy.c _test_library_dummy)
|
||||
endif
|
||||
|
||||
$(PSDPNG): ../kiss_fft.c psdpng.c kiss_fftr.c
|
||||
$(CC) -o $@ $(CFLAGS) -I.. $(TYPEFLAGS) $+ -lpng -lm
|
||||
#
|
||||
# Tool names
|
||||
#
|
||||
|
||||
$(DUMPHDR): ../kiss_fft.c dumphdr.c
|
||||
$(CC) -o $@ $(CFLAGS) -I.. $(TYPEFLAGS) $+ -lm
|
||||
ifneq ($(KISSFFT_OPENMP),1)
|
||||
FFTUTIL = fft-$(KISSFFT_DATATYPE)
|
||||
FASTFILT = fastconv-$(KISSFFT_DATATYPE)
|
||||
FASTFILTREAL = fastconvr-$(KISSFFT_DATATYPE)
|
||||
PSDPNG = psdpng-$(KISSFFT_DATATYPE)
|
||||
DUMPHDR = dumphdr-$(KISSFFT_DATATYPE)
|
||||
else
|
||||
FFTUTIL = fft-$(KISSFFT_DATATYPE)-openmp
|
||||
FASTFILT = fastconv-$(KISSFFT_DATATYPE)-openmp
|
||||
FASTFILTREAL = fastconvr-$(KISSFFT_DATATYPE)-openmp
|
||||
PSDPNG = psdpng-$(KISSFFT_DATATYPE)-openmp
|
||||
DUMPHDR = dumphdr-$(KISSFFT_DATATYPE)-openmp
|
||||
endif
|
||||
|
||||
#
|
||||
# Target: "make all"
|
||||
#
|
||||
|
||||
all: $(FFTUTIL) $(FASTFILT) $(FASTFILTREAL) $(PSDPNG)
|
||||
# $(DUMPHDR)
|
||||
|
||||
#
|
||||
# Individual tool make rules
|
||||
#
|
||||
|
||||
$(FASTFILTREAL): kiss_fastfir.c
|
||||
$(CC) -o $@ $(CFLAGS) -I.. $(TYPEFLAGS) -DREAL_FASTFIR $< -DFAST_FILT_UTIL -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
|
||||
|
||||
$(FASTFILT): kiss_fastfir.c
|
||||
$(CC) -o $@ $(CFLAGS) -I.. $(TYPEFLAGS) $< -DFAST_FILT_UTIL -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
|
||||
|
||||
$(FFTUTIL): fftutil.c
|
||||
$(CC) -o $@ $(CFLAGS) -I.. $(TYPEFLAGS) $< -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
|
||||
|
||||
$(PSDPNG): psdpng.c
|
||||
ifeq "$(KISSFFT_DATATYPE)" "simd"
|
||||
$(warning WARNING: psdpng can not utilize SIMD!)
|
||||
else ifeq ($(LIBPNG_MISSING), 0)
|
||||
$(CC) -o $@ $(CFLAGS) -I.. $(TYPEFLAGS) $< -L.. -l$(KISSFFTLIB_SHORTNAME) -lpng -lm
|
||||
else
|
||||
$(error ERROR: no libpng development files found!)
|
||||
endif
|
||||
|
||||
$(DUMPHDR): dumphdr.c
|
||||
$(CC) -o $@ $(CFLAGS) -I.. $(TYPEFLAGS) $< -L.. -l$(KISSFFTLIB_SHORTNAME) -lm
|
||||
|
||||
#
|
||||
# Target: "make install"
|
||||
#
|
||||
|
||||
install: all
|
||||
$(INSTALL) -Dt $(ABS_BINDIR) -m 755 \
|
||||
$(FFTUTIL) \
|
||||
$(FASTFILT) \
|
||||
$(FASTFILTREAL)
|
||||
|
||||
ifneq "$(KISSFFT_DATATYPE)" "simd"
|
||||
$(INSTALL) -Dt $(ABS_BINDIR) -m 755 \
|
||||
$(PSDPNG)
|
||||
endif
|
||||
|
||||
#
|
||||
# Target: "make clean"
|
||||
#
|
||||
|
||||
clean:
|
||||
rm -f *~ fft fft_* fastconv fastconv_* fastconvr fastconvr_* psdpng psdpng_*
|
||||
rm -f *~ fft fft-* fastconv fastconv-* fastconvr fastconvr-* psdpng psdpng-* _test_library_dummy _test_library_dummy.c
|
||||
|
@ -46,6 +46,7 @@ void config(int argc,char** argv)
|
||||
"\t-s : input is stereo, channels will be combined before fft\n"
|
||||
"16 bit machine format real input is assumed\n"
|
||||
);
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, "bad %c\n", c);
|
||||
exit (1);
|
||||
|
Loading…
x
Reference in New Issue
Block a user