mirror of
https://github.com/mborgerding/kissfft.git
synced 2025-09-08 14:24:18 -04:00
Overhaul Make makefiles
* Header files and correspondent C sources that define functions recently added to public API moved from 'tools' directory to root * By default, install prefix is '/usr/local/', and header install path is '${PREFIX}/include/kissfft' * Added detection of external libraries like FFTW or libPNG Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
This commit is contained in:
137
tools/Makefile
137
tools/Makefile
@ -1,62 +1,101 @@
|
||||
WARNINGS=-W -Wall -Wstrict-prototypes -Wmissing-prototypes \
|
||||
#
|
||||
# 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
|
||||
|
109
tools/kfc.c
109
tools/kfc.c
@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
|
||||
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
* See COPYING file for more information.
|
||||
*/
|
||||
|
||||
#include "kfc.h"
|
||||
|
||||
typedef struct cached_fft *kfc_cfg;
|
||||
|
||||
struct cached_fft
|
||||
{
|
||||
int nfft;
|
||||
int inverse;
|
||||
kiss_fft_cfg cfg;
|
||||
kfc_cfg next;
|
||||
};
|
||||
|
||||
static kfc_cfg cache_root=NULL;
|
||||
static int ncached=0;
|
||||
|
||||
static kiss_fft_cfg find_cached_fft(int nfft,int inverse)
|
||||
{
|
||||
size_t len;
|
||||
kfc_cfg cur=cache_root;
|
||||
kfc_cfg prev=NULL;
|
||||
while ( cur ) {
|
||||
if ( cur->nfft == nfft && inverse == cur->inverse )
|
||||
break;/*found the right node*/
|
||||
prev = cur;
|
||||
cur = prev->next;
|
||||
}
|
||||
if (cur== NULL) {
|
||||
/* no cached node found, need to create a new one*/
|
||||
kiss_fft_alloc(nfft,inverse,0,&len);
|
||||
#ifdef USE_SIMD
|
||||
int padding = (16-sizeof(struct cached_fft)) & 15;
|
||||
// make sure the cfg aligns on a 16 byte boundary
|
||||
len += padding;
|
||||
#endif
|
||||
cur = (kfc_cfg)KISS_FFT_MALLOC((sizeof(struct cached_fft) + len ));
|
||||
if (cur == NULL)
|
||||
return NULL;
|
||||
cur->cfg = (kiss_fft_cfg)(cur+1);
|
||||
#ifdef USE_SIMD
|
||||
cur->cfg = (kiss_fft_cfg) ((char*)(cur+1)+padding);
|
||||
#endif
|
||||
kiss_fft_alloc(nfft,inverse,cur->cfg,&len);
|
||||
cur->nfft=nfft;
|
||||
cur->inverse=inverse;
|
||||
cur->next = NULL;
|
||||
if ( prev )
|
||||
prev->next = cur;
|
||||
else
|
||||
cache_root = cur;
|
||||
++ncached;
|
||||
}
|
||||
return cur->cfg;
|
||||
}
|
||||
|
||||
void kfc_cleanup(void)
|
||||
{
|
||||
kfc_cfg cur=cache_root;
|
||||
kfc_cfg next=NULL;
|
||||
while (cur){
|
||||
next = cur->next;
|
||||
free(cur);
|
||||
cur=next;
|
||||
}
|
||||
ncached=0;
|
||||
cache_root = NULL;
|
||||
}
|
||||
void kfc_fft(int nfft, const kiss_fft_cpx * fin,kiss_fft_cpx * fout)
|
||||
{
|
||||
kiss_fft( find_cached_fft(nfft,0),fin,fout );
|
||||
}
|
||||
|
||||
void kfc_ifft(int nfft, const kiss_fft_cpx * fin,kiss_fft_cpx * fout)
|
||||
{
|
||||
kiss_fft( find_cached_fft(nfft,1),fin,fout );
|
||||
}
|
||||
|
||||
#ifdef KFC_TEST
|
||||
static void check(int nc)
|
||||
{
|
||||
if (ncached != nc) {
|
||||
fprintf(stderr,"ncached should be %d,but it is %d\n",nc,ncached);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
kiss_fft_cpx buf1[1024],buf2[1024];
|
||||
memset(buf1,0,sizeof(buf1));
|
||||
check(0);
|
||||
kfc_fft(512,buf1,buf2);
|
||||
check(1);
|
||||
kfc_fft(512,buf1,buf2);
|
||||
check(1);
|
||||
kfc_ifft(512,buf1,buf2);
|
||||
check(2);
|
||||
kfc_cleanup();
|
||||
check(0);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
54
tools/kfc.h
54
tools/kfc.h
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
|
||||
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
* See COPYING file for more information.
|
||||
*/
|
||||
|
||||
#ifndef KFC_H
|
||||
#define KFC_H
|
||||
#include "kiss_fft.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
KFC -- Kiss FFT Cache
|
||||
|
||||
Not needing to deal with kiss_fft_alloc and a config
|
||||
object may be handy for a lot of programs.
|
||||
|
||||
KFC uses the underlying KISS FFT functions, but caches the config object.
|
||||
The first time kfc_fft or kfc_ifft for a given FFT size, the cfg
|
||||
object is created for it. All subsequent calls use the cached
|
||||
configuration object.
|
||||
|
||||
NOTE:
|
||||
You should probably not use this if your program will be using a lot
|
||||
of various sizes of FFTs. There is a linear search through the
|
||||
cached objects. If you are only using one or two FFT sizes, this
|
||||
will be negligible. Otherwise, you may want to use another method
|
||||
of managing the cfg objects.
|
||||
|
||||
There is no automated cleanup of the cached objects. This could lead
|
||||
to large memory usage in a program that uses a lot of *DIFFERENT*
|
||||
sized FFTs. If you want to force all cached cfg objects to be freed,
|
||||
call kfc_cleanup.
|
||||
|
||||
*/
|
||||
|
||||
/*forward complex FFT */
|
||||
void KISS_FFT_API kfc_fft(int nfft, const kiss_fft_cpx * fin,kiss_fft_cpx * fout);
|
||||
/*reverse complex FFT */
|
||||
void KISS_FFT_API kfc_ifft(int nfft, const kiss_fft_cpx * fin,kiss_fft_cpx * fout);
|
||||
|
||||
/*free all cached objects*/
|
||||
void KISS_FFT_API kfc_cleanup(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,188 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
|
||||
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
* See COPYING file for more information.
|
||||
*/
|
||||
|
||||
#include "kiss_fftnd.h"
|
||||
#include "_kiss_fft_guts.h"
|
||||
|
||||
struct kiss_fftnd_state{
|
||||
int dimprod; /* dimsum would be mighty tasty right now */
|
||||
int ndims;
|
||||
int *dims;
|
||||
kiss_fft_cfg *states; /* cfg states for each dimension */
|
||||
kiss_fft_cpx * tmpbuf; /*buffer capable of hold the entire input */
|
||||
};
|
||||
|
||||
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 = KISS_FFT_ALIGN_SIZE_UP(sizeof(struct kiss_fftnd_state));
|
||||
char * ptr = NULL;
|
||||
|
||||
for (i=0;i<ndims;++i) {
|
||||
size_t sublen=0;
|
||||
kiss_fft_alloc (dims[i], inverse_fft, NULL, &sublen);
|
||||
memneeded += sublen; /* st->states[i] */
|
||||
dimprod *= dims[i];
|
||||
}
|
||||
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*/
|
||||
ptr = (char *) malloc (memneeded);
|
||||
} else { /* initialize supplied buffer if big enough */
|
||||
if (*lenmem >= memneeded)
|
||||
ptr = (char *) mem;
|
||||
*lenmem = memneeded; /*tell caller how big struct is (or would be) */
|
||||
}
|
||||
if (!ptr)
|
||||
return NULL; /*malloc failed or buffer too small */
|
||||
|
||||
st = (kiss_fftnd_cfg) ptr;
|
||||
st->dimprod = dimprod;
|
||||
st->ndims = ndims;
|
||||
ptr += KISS_FFT_ALIGN_SIZE_UP(sizeof(struct kiss_fftnd_state));
|
||||
|
||||
st->states = (kiss_fft_cfg *)ptr;
|
||||
ptr += KISS_FFT_ALIGN_SIZE_UP(sizeof(void*) * ndims);
|
||||
|
||||
st->dims = (int*)ptr;
|
||||
ptr += KISS_FFT_ALIGN_SIZE_UP(sizeof(int) * ndims);
|
||||
|
||||
st->tmpbuf = (kiss_fft_cpx*)ptr;
|
||||
ptr += KISS_FFT_ALIGN_SIZE_UP(sizeof(kiss_fft_cpx) * dimprod);
|
||||
|
||||
for (i=0;i<ndims;++i) {
|
||||
size_t len;
|
||||
st->dims[i] = dims[i];
|
||||
kiss_fft_alloc (st->dims[i], inverse_fft, NULL, &len);
|
||||
st->states[i] = kiss_fft_alloc (st->dims[i], inverse_fft, ptr,&len);
|
||||
ptr += len;
|
||||
}
|
||||
/*
|
||||
Hi there!
|
||||
|
||||
If you're looking at this particular code, it probably means you've got a brain-dead bounds checker
|
||||
that thinks the above code overwrites the end of the array.
|
||||
|
||||
It doesn't.
|
||||
|
||||
-- Mark
|
||||
|
||||
P.S.
|
||||
The below code might give you some warm fuzzies and help convince you.
|
||||
*/
|
||||
if ( ptr - (char*)st != (int)memneeded ) {
|
||||
fprintf(stderr,
|
||||
"################################################################################\n"
|
||||
"Internal error! Memory allocation miscalculation\n"
|
||||
"################################################################################\n"
|
||||
);
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
/*
|
||||
This works by tackling one dimension at a time.
|
||||
|
||||
In effect,
|
||||
Each stage starts out by reshaping the matrix into a DixSi 2d matrix.
|
||||
A Di-sized fft is taken of each column, transposing the matrix as it goes.
|
||||
|
||||
Here's a 3-d example:
|
||||
Take a 2x3x4 matrix, laid out in memory as a contiguous buffer
|
||||
[ [ [ a b c d ] [ e f g h ] [ i j k l ] ]
|
||||
[ [ m n o p ] [ q r s t ] [ u v w x ] ] ]
|
||||
|
||||
Stage 0 ( D=2): treat the buffer as a 2x12 matrix
|
||||
[ [a b ... k l]
|
||||
[m n ... w x] ]
|
||||
|
||||
FFT each column with size 2.
|
||||
Transpose the matrix at the same time using kiss_fft_stride.
|
||||
|
||||
[ [ a+m a-m ]
|
||||
[ b+n b-n]
|
||||
...
|
||||
[ k+w k-w ]
|
||||
[ l+x l-x ] ]
|
||||
|
||||
Note fft([x y]) == [x+y x-y]
|
||||
|
||||
Stage 1 ( D=3) treats the buffer (the output of stage D=2) as an 3x8 matrix,
|
||||
[ [ a+m a-m b+n b-n c+o c-o d+p d-p ]
|
||||
[ e+q e-q f+r f-r g+s g-s h+t h-t ]
|
||||
[ i+u i-u j+v j-v k+w k-w l+x l-x ] ]
|
||||
|
||||
And perform FFTs (size=3) on each of the columns as above, transposing
|
||||
the matrix as it goes. The output of stage 1 is
|
||||
(Legend: ap = [ a+m e+q i+u ]
|
||||
am = [ a-m e-q i-u ] )
|
||||
|
||||
[ [ sum(ap) fft(ap)[0] fft(ap)[1] ]
|
||||
[ sum(am) fft(am)[0] fft(am)[1] ]
|
||||
[ sum(bp) fft(bp)[0] fft(bp)[1] ]
|
||||
[ sum(bm) fft(bm)[0] fft(bm)[1] ]
|
||||
[ sum(cp) fft(cp)[0] fft(cp)[1] ]
|
||||
[ sum(cm) fft(cm)[0] fft(cm)[1] ]
|
||||
[ sum(dp) fft(dp)[0] fft(dp)[1] ]
|
||||
[ sum(dm) fft(dm)[0] fft(dm)[1] ] ]
|
||||
|
||||
Stage 2 ( D=4) treats this buffer as a 4*6 matrix,
|
||||
[ [ sum(ap) fft(ap)[0] fft(ap)[1] sum(am) fft(am)[0] fft(am)[1] ]
|
||||
[ sum(bp) fft(bp)[0] fft(bp)[1] sum(bm) fft(bm)[0] fft(bm)[1] ]
|
||||
[ sum(cp) fft(cp)[0] fft(cp)[1] sum(cm) fft(cm)[0] fft(cm)[1] ]
|
||||
[ sum(dp) fft(dp)[0] fft(dp)[1] sum(dm) fft(dm)[0] fft(dm)[1] ] ]
|
||||
|
||||
Then FFTs each column, transposing as it goes.
|
||||
|
||||
The resulting matrix is the 3d FFT of the 2x3x4 input matrix.
|
||||
|
||||
Note as a sanity check that the first element of the final
|
||||
stage's output (DC term) is
|
||||
sum( [ sum(ap) sum(bp) sum(cp) sum(dp) ] )
|
||||
, i.e. the summation of all 24 input elements.
|
||||
|
||||
*/
|
||||
void kiss_fftnd(kiss_fftnd_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
|
||||
{
|
||||
int i,k;
|
||||
const kiss_fft_cpx * bufin=fin;
|
||||
kiss_fft_cpx * bufout;
|
||||
|
||||
/*arrange it so the last bufout == fout*/
|
||||
if ( st->ndims & 1 ) {
|
||||
bufout = fout;
|
||||
if (fin==fout) {
|
||||
memcpy( st->tmpbuf, fin, sizeof(kiss_fft_cpx) * st->dimprod );
|
||||
bufin = st->tmpbuf;
|
||||
}
|
||||
}else
|
||||
bufout = st->tmpbuf;
|
||||
|
||||
for ( k=0; k < st->ndims; ++k) {
|
||||
int curdim = st->dims[k];
|
||||
int stride = st->dimprod / curdim;
|
||||
|
||||
for ( i=0 ; i<stride ; ++i )
|
||||
kiss_fft_stride( st->states[k], bufin+i , bufout+i*curdim, stride );
|
||||
|
||||
/*toggle back and forth between the two buffers*/
|
||||
if (bufout == st->tmpbuf){
|
||||
bufout = fout;
|
||||
bufin = st->tmpbuf;
|
||||
}else{
|
||||
bufout = st->tmpbuf;
|
||||
bufin = fout;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
|
||||
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
* See COPYING file for more information.
|
||||
*/
|
||||
|
||||
#ifndef KISS_FFTND_H
|
||||
#define KISS_FFTND_H
|
||||
|
||||
#include "kiss_fft.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct kiss_fftnd_state * kiss_fftnd_cfg;
|
||||
|
||||
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
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
|
||||
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
* See COPYING file for more information.
|
||||
*/
|
||||
|
||||
#include "kiss_fftndr.h"
|
||||
#include "_kiss_fft_guts.h"
|
||||
#define MAX(x,y) ( ( (x)<(y) )?(y):(x) )
|
||||
|
||||
struct kiss_fftndr_state
|
||||
{
|
||||
int dimReal;
|
||||
int dimOther;
|
||||
kiss_fftr_cfg cfg_r;
|
||||
kiss_fftnd_cfg cfg_nd;
|
||||
void * tmpbuf;
|
||||
};
|
||||
|
||||
static int prod(const int *dims, int ndims)
|
||||
{
|
||||
int x=1;
|
||||
while (ndims--)
|
||||
x *= *dims++;
|
||||
return x;
|
||||
}
|
||||
|
||||
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 = 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) {
|
||||
ptr = (char*) malloc(memneeded);
|
||||
}else{
|
||||
if (*lenmem >= memneeded)
|
||||
ptr = (char *)mem;
|
||||
*lenmem = memneeded;
|
||||
}
|
||||
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,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;
|
||||
}
|
||||
|
||||
void kiss_fftndr(kiss_fftndr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata)
|
||||
{
|
||||
int k1,k2;
|
||||
int dimReal = st->dimReal;
|
||||
int dimOther = st->dimOther;
|
||||
int nrbins = dimReal/2+1;
|
||||
|
||||
kiss_fft_cpx * tmp1 = (kiss_fft_cpx*)st->tmpbuf;
|
||||
kiss_fft_cpx * tmp2 = tmp1 + MAX(nrbins,dimOther);
|
||||
|
||||
// timedata is N0 x N1 x ... x Nk real
|
||||
|
||||
// take a real chunk of data, fft it and place the output at correct intervals
|
||||
for (k1=0;k1<dimOther;++k1) {
|
||||
kiss_fftr( st->cfg_r, timedata + k1*dimReal , tmp1 ); // tmp1 now holds nrbins complex points
|
||||
for (k2=0;k2<nrbins;++k2)
|
||||
tmp2[ k2*dimOther+k1 ] = tmp1[k2];
|
||||
}
|
||||
|
||||
for (k2=0;k2<nrbins;++k2) {
|
||||
kiss_fftnd(st->cfg_nd, tmp2+k2*dimOther, tmp1); // tmp1 now holds dimOther complex points
|
||||
for (k1=0;k1<dimOther;++k1)
|
||||
freqdata[ k1*(nrbins) + k2] = tmp1[k1];
|
||||
}
|
||||
}
|
||||
|
||||
void kiss_fftndri(kiss_fftndr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata)
|
||||
{
|
||||
int k1,k2;
|
||||
int dimReal = st->dimReal;
|
||||
int dimOther = st->dimOther;
|
||||
int nrbins = dimReal/2+1;
|
||||
kiss_fft_cpx * tmp1 = (kiss_fft_cpx*)st->tmpbuf;
|
||||
kiss_fft_cpx * tmp2 = tmp1 + MAX(nrbins,dimOther);
|
||||
|
||||
for (k2=0;k2<nrbins;++k2) {
|
||||
for (k1=0;k1<dimOther;++k1)
|
||||
tmp1[k1] = freqdata[ k1*(nrbins) + k2 ];
|
||||
kiss_fftnd(st->cfg_nd, tmp1, tmp2+k2*dimOther);
|
||||
}
|
||||
|
||||
for (k1=0;k1<dimOther;++k1) {
|
||||
for (k2=0;k2<nrbins;++k2)
|
||||
tmp1[k2] = tmp2[ k2*dimOther+k1 ];
|
||||
kiss_fftri( st->cfg_r,tmp1,timedata + k1*dimReal);
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
|
||||
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
* See COPYING file for more information.
|
||||
*/
|
||||
|
||||
#ifndef KISS_NDR_H
|
||||
#define KISS_NDR_H
|
||||
|
||||
#include "kiss_fft.h"
|
||||
#include "kiss_fftr.h"
|
||||
#include "kiss_fftnd.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct kiss_fftndr_state *kiss_fftndr_cfg;
|
||||
|
||||
|
||||
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
|
||||
|
||||
If you don't care to allocate space, use mem = lenmem = NULL
|
||||
*/
|
||||
|
||||
|
||||
void KISS_FFT_API kiss_fftndr(
|
||||
kiss_fftndr_cfg cfg,
|
||||
const kiss_fft_scalar *timedata,
|
||||
kiss_fft_cpx *freqdata);
|
||||
/*
|
||||
input timedata has dims[0] X dims[1] X ... X dims[ndims-1] scalar points
|
||||
output freqdata has dims[0] X dims[1] X ... X dims[ndims-1]/2+1 complex points
|
||||
*/
|
||||
|
||||
void KISS_FFT_API kiss_fftndri(
|
||||
kiss_fftndr_cfg cfg,
|
||||
const kiss_fft_cpx *freqdata,
|
||||
kiss_fft_scalar *timedata);
|
||||
/*
|
||||
input and output dimensions are the exact opposite of kiss_fftndr
|
||||
*/
|
||||
|
||||
|
||||
#define kiss_fftndr_free free
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,155 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
|
||||
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
* See COPYING file for more information.
|
||||
*/
|
||||
|
||||
#include "kiss_fftr.h"
|
||||
#include "_kiss_fft_guts.h"
|
||||
|
||||
struct kiss_fftr_state{
|
||||
kiss_fft_cfg substate;
|
||||
kiss_fft_cpx * tmpbuf;
|
||||
kiss_fft_cpx * super_twiddles;
|
||||
#ifdef USE_SIMD
|
||||
void * pad;
|
||||
#endif
|
||||
};
|
||||
|
||||
kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem)
|
||||
{
|
||||
KISS_FFT_ALIGN_CHECK(mem)
|
||||
|
||||
int i;
|
||||
kiss_fftr_cfg st = NULL;
|
||||
size_t subsize = 0, memneeded;
|
||||
|
||||
if (nfft & 1) {
|
||||
KISS_FFT_ERROR("Real FFT optimization must be even.");
|
||||
return NULL;
|
||||
}
|
||||
nfft >>= 1;
|
||||
|
||||
kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize);
|
||||
memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 3 / 2);
|
||||
|
||||
if (lenmem == NULL) {
|
||||
st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded);
|
||||
} else {
|
||||
if (*lenmem >= memneeded)
|
||||
st = (kiss_fftr_cfg) mem;
|
||||
*lenmem = memneeded;
|
||||
}
|
||||
if (!st)
|
||||
return NULL;
|
||||
|
||||
st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */
|
||||
st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize);
|
||||
st->super_twiddles = st->tmpbuf + nfft;
|
||||
kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize);
|
||||
|
||||
for (i = 0; i < nfft/2; ++i) {
|
||||
double phase =
|
||||
-3.14159265358979323846264338327 * ((double) (i+1) / nfft + .5);
|
||||
if (inverse_fft)
|
||||
phase *= -1;
|
||||
kf_cexp (st->super_twiddles+i,phase);
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata)
|
||||
{
|
||||
/* input buffer timedata is stored row-wise */
|
||||
int k,ncfft;
|
||||
kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc;
|
||||
|
||||
if ( st->substate->inverse) {
|
||||
KISS_FFT_ERROR("kiss fft usage error: improper alloc");
|
||||
return;/* The caller did not call the correct function */
|
||||
}
|
||||
|
||||
ncfft = st->substate->nfft;
|
||||
|
||||
/*perform the parallel fft of two real signals packed in real,imag*/
|
||||
kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf );
|
||||
/* The real part of the DC element of the frequency spectrum in st->tmpbuf
|
||||
* 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.
|
||||
* 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...
|
||||
* yielding Nyquist bin of input time sequence
|
||||
*/
|
||||
|
||||
tdc.r = st->tmpbuf[0].r;
|
||||
tdc.i = st->tmpbuf[0].i;
|
||||
C_FIXDIV(tdc,2);
|
||||
CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i);
|
||||
CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i);
|
||||
freqdata[0].r = tdc.r + tdc.i;
|
||||
freqdata[ncfft].r = tdc.r - tdc.i;
|
||||
#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];
|
||||
fpnk.r = st->tmpbuf[ncfft-k].r;
|
||||
fpnk.i = - st->tmpbuf[ncfft-k].i;
|
||||
C_FIXDIV(fpk,2);
|
||||
C_FIXDIV(fpnk,2);
|
||||
|
||||
C_ADD( f1k, fpk , fpnk );
|
||||
C_SUB( f2k, fpk , fpnk );
|
||||
C_MUL( tw , f2k , st->super_twiddles[k-1]);
|
||||
|
||||
freqdata[k].r = HALF_OF(f1k.r + tw.r);
|
||||
freqdata[k].i = HALF_OF(f1k.i + tw.i);
|
||||
freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r);
|
||||
freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i);
|
||||
}
|
||||
}
|
||||
|
||||
void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata)
|
||||
{
|
||||
/* input buffer timedata is stored row-wise */
|
||||
int k, ncfft;
|
||||
|
||||
if (st->substate->inverse == 0) {
|
||||
KISS_FFT_ERROR("kiss fft usage error: improper alloc");
|
||||
return;/* The caller did not call the correct function */
|
||||
}
|
||||
|
||||
ncfft = st->substate->nfft;
|
||||
|
||||
st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r;
|
||||
st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r;
|
||||
C_FIXDIV(st->tmpbuf[0],2);
|
||||
|
||||
for (k = 1; k <= ncfft / 2; ++k) {
|
||||
kiss_fft_cpx fk, fnkc, fek, fok, tmp;
|
||||
fk = freqdata[k];
|
||||
fnkc.r = freqdata[ncfft - k].r;
|
||||
fnkc.i = -freqdata[ncfft - k].i;
|
||||
C_FIXDIV( fk , 2 );
|
||||
C_FIXDIV( fnkc , 2 );
|
||||
|
||||
C_ADD (fek, fk, fnkc);
|
||||
C_SUB (tmp, fk, fnkc);
|
||||
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
|
||||
st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0);
|
||||
#else
|
||||
st->tmpbuf[ncfft - k].i *= -1;
|
||||
#endif
|
||||
}
|
||||
kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata);
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
|
||||
* This file is part of KISS FFT - https://github.com/mborgerding/kissfft
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
* See COPYING file for more information.
|
||||
*/
|
||||
|
||||
#ifndef KISS_FTR_H
|
||||
#define KISS_FTR_H
|
||||
|
||||
#include "kiss_fft.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Real optimized version can save about 45% cpu time vs. complex fft of a real seq.
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
typedef struct kiss_fftr_state *kiss_fftr_cfg;
|
||||
|
||||
|
||||
kiss_fftr_cfg KISS_FFT_API kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem);
|
||||
/*
|
||||
nfft must be even
|
||||
|
||||
If you don't care to allocate space, use mem = lenmem = NULL
|
||||
*/
|
||||
|
||||
|
||||
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_FFT_API kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata);
|
||||
/*
|
||||
input freqdata has nfft/2+1 complex points
|
||||
output timedata has nfft scalar points
|
||||
*/
|
||||
|
||||
#define kiss_fftr_free KISS_FFT_FREE
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
Reference in New Issue
Block a user