annotate src/ext/kissfft/tools/kiss_fftnd.c @ 196:da283326bcd3 tip master

Update plugin versions in RDF
author Chris Cannam <cannam@all-day-breakfast.com>
date Fri, 28 Feb 2020 09:43:02 +0000
parents 5ed6e970541b
children
rev   line source
c@174 1
c@174 2
c@174 3 /*
c@174 4 Copyright (c) 2003-2004, Mark Borgerding
c@174 5
c@174 6 All rights reserved.
c@174 7
c@174 8 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
c@174 9
c@174 10 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
c@174 11 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
c@174 12 * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
c@174 13
c@174 14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
c@174 15 */
c@174 16
c@174 17 #include "kiss_fftnd.h"
c@174 18 #include "_kiss_fft_guts.h"
c@174 19
c@174 20 struct kiss_fftnd_state{
c@174 21 int dimprod; /* dimsum would be mighty tasty right now */
c@174 22 int ndims;
c@174 23 int *dims;
c@174 24 kiss_fft_cfg *states; /* cfg states for each dimension */
c@174 25 kiss_fft_cpx * tmpbuf; /*buffer capable of hold the entire input */
c@174 26 };
c@174 27
c@174 28 kiss_fftnd_cfg kiss_fftnd_alloc(const int *dims,int ndims,int inverse_fft,void*mem,size_t*lenmem)
c@174 29 {
c@174 30 kiss_fftnd_cfg st = NULL;
c@174 31 int i;
c@174 32 int dimprod=1;
c@174 33 size_t memneeded = sizeof(struct kiss_fftnd_state);
c@174 34 char * ptr;
c@174 35
c@174 36 for (i=0;i<ndims;++i) {
c@174 37 size_t sublen=0;
c@174 38 kiss_fft_alloc (dims[i], inverse_fft, NULL, &sublen);
c@174 39 memneeded += sublen; /* st->states[i] */
c@174 40 dimprod *= dims[i];
c@174 41 }
c@174 42 memneeded += sizeof(int) * ndims;/* st->dims */
c@174 43 memneeded += sizeof(void*) * ndims;/* st->states */
c@174 44 memneeded += sizeof(kiss_fft_cpx) * dimprod; /* st->tmpbuf */
c@174 45
c@174 46 if (lenmem == NULL) {/* allocate for the caller*/
c@174 47 st = (kiss_fftnd_cfg) malloc (memneeded);
c@174 48 } else { /* initialize supplied buffer if big enough */
c@174 49 if (*lenmem >= memneeded)
c@174 50 st = (kiss_fftnd_cfg) mem;
c@174 51 *lenmem = memneeded; /*tell caller how big struct is (or would be) */
c@174 52 }
c@174 53 if (!st)
c@174 54 return NULL; /*malloc failed or buffer too small */
c@174 55
c@174 56 st->dimprod = dimprod;
c@174 57 st->ndims = ndims;
c@174 58 ptr=(char*)(st+1);
c@174 59
c@174 60 st->states = (kiss_fft_cfg *)ptr;
c@174 61 ptr += sizeof(void*) * ndims;
c@174 62
c@174 63 st->dims = (int*)ptr;
c@174 64 ptr += sizeof(int) * ndims;
c@174 65
c@174 66 st->tmpbuf = (kiss_fft_cpx*)ptr;
c@174 67 ptr += sizeof(kiss_fft_cpx) * dimprod;
c@174 68
c@174 69 for (i=0;i<ndims;++i) {
c@174 70 size_t len;
c@174 71 st->dims[i] = dims[i];
c@174 72 kiss_fft_alloc (st->dims[i], inverse_fft, NULL, &len);
c@174 73 st->states[i] = kiss_fft_alloc (st->dims[i], inverse_fft, ptr,&len);
c@174 74 ptr += len;
c@174 75 }
c@174 76 /*
c@174 77 Hi there!
c@174 78
c@174 79 If you're looking at this particular code, it probably means you've got a brain-dead bounds checker
c@174 80 that thinks the above code overwrites the end of the array.
c@174 81
c@174 82 It doesn't.
c@174 83
c@174 84 -- Mark
c@174 85
c@174 86 P.S.
c@174 87 The below code might give you some warm fuzzies and help convince you.
c@174 88 */
c@174 89 if ( ptr - (char*)st != (int)memneeded ) {
c@174 90 fprintf(stderr,
c@174 91 "################################################################################\n"
c@174 92 "Internal error! Memory allocation miscalculation\n"
c@174 93 "################################################################################\n"
c@174 94 );
c@174 95 }
c@174 96 return st;
c@174 97 }
c@174 98
c@174 99 /*
c@174 100 This works by tackling one dimension at a time.
c@174 101
c@174 102 In effect,
c@174 103 Each stage starts out by reshaping the matrix into a DixSi 2d matrix.
c@174 104 A Di-sized fft is taken of each column, transposing the matrix as it goes.
c@174 105
c@174 106 Here's a 3-d example:
c@174 107 Take a 2x3x4 matrix, laid out in memory as a contiguous buffer
c@174 108 [ [ [ a b c d ] [ e f g h ] [ i j k l ] ]
c@174 109 [ [ m n o p ] [ q r s t ] [ u v w x ] ] ]
c@174 110
c@174 111 Stage 0 ( D=2): treat the buffer as a 2x12 matrix
c@174 112 [ [a b ... k l]
c@174 113 [m n ... w x] ]
c@174 114
c@174 115 FFT each column with size 2.
c@174 116 Transpose the matrix at the same time using kiss_fft_stride.
c@174 117
c@174 118 [ [ a+m a-m ]
c@174 119 [ b+n b-n]
c@174 120 ...
c@174 121 [ k+w k-w ]
c@174 122 [ l+x l-x ] ]
c@174 123
c@174 124 Note fft([x y]) == [x+y x-y]
c@174 125
c@174 126 Stage 1 ( D=3) treats the buffer (the output of stage D=2) as an 3x8 matrix,
c@174 127 [ [ a+m a-m b+n b-n c+o c-o d+p d-p ]
c@174 128 [ e+q e-q f+r f-r g+s g-s h+t h-t ]
c@174 129 [ i+u i-u j+v j-v k+w k-w l+x l-x ] ]
c@174 130
c@174 131 And perform FFTs (size=3) on each of the columns as above, transposing
c@174 132 the matrix as it goes. The output of stage 1 is
c@174 133 (Legend: ap = [ a+m e+q i+u ]
c@174 134 am = [ a-m e-q i-u ] )
c@174 135
c@174 136 [ [ sum(ap) fft(ap)[0] fft(ap)[1] ]
c@174 137 [ sum(am) fft(am)[0] fft(am)[1] ]
c@174 138 [ sum(bp) fft(bp)[0] fft(bp)[1] ]
c@174 139 [ sum(bm) fft(bm)[0] fft(bm)[1] ]
c@174 140 [ sum(cp) fft(cp)[0] fft(cp)[1] ]
c@174 141 [ sum(cm) fft(cm)[0] fft(cm)[1] ]
c@174 142 [ sum(dp) fft(dp)[0] fft(dp)[1] ]
c@174 143 [ sum(dm) fft(dm)[0] fft(dm)[1] ] ]
c@174 144
c@174 145 Stage 2 ( D=4) treats this buffer as a 4*6 matrix,
c@174 146 [ [ sum(ap) fft(ap)[0] fft(ap)[1] sum(am) fft(am)[0] fft(am)[1] ]
c@174 147 [ sum(bp) fft(bp)[0] fft(bp)[1] sum(bm) fft(bm)[0] fft(bm)[1] ]
c@174 148 [ sum(cp) fft(cp)[0] fft(cp)[1] sum(cm) fft(cm)[0] fft(cm)[1] ]
c@174 149 [ sum(dp) fft(dp)[0] fft(dp)[1] sum(dm) fft(dm)[0] fft(dm)[1] ] ]
c@174 150
c@174 151 Then FFTs each column, transposing as it goes.
c@174 152
c@174 153 The resulting matrix is the 3d FFT of the 2x3x4 input matrix.
c@174 154
c@174 155 Note as a sanity check that the first element of the final
c@174 156 stage's output (DC term) is
c@174 157 sum( [ sum(ap) sum(bp) sum(cp) sum(dp) ] )
c@174 158 , i.e. the summation of all 24 input elements.
c@174 159
c@174 160 */
c@174 161 void kiss_fftnd(kiss_fftnd_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
c@174 162 {
c@174 163 int i,k;
c@174 164 const kiss_fft_cpx * bufin=fin;
c@174 165 kiss_fft_cpx * bufout;
c@174 166
c@174 167 /*arrange it so the last bufout == fout*/
c@174 168 if ( st->ndims & 1 ) {
c@174 169 bufout = fout;
c@174 170 if (fin==fout) {
c@174 171 memcpy( st->tmpbuf, fin, sizeof(kiss_fft_cpx) * st->dimprod );
c@174 172 bufin = st->tmpbuf;
c@174 173 }
c@174 174 }else
c@174 175 bufout = st->tmpbuf;
c@174 176
c@174 177 for ( k=0; k < st->ndims; ++k) {
c@174 178 int curdim = st->dims[k];
c@174 179 int stride = st->dimprod / curdim;
c@174 180
c@174 181 for ( i=0 ; i<stride ; ++i )
c@174 182 kiss_fft_stride( st->states[k], bufin+i , bufout+i*curdim, stride );
c@174 183
c@174 184 /*toggle back and forth between the two buffers*/
c@174 185 if (bufout == st->tmpbuf){
c@174 186 bufout = fout;
c@174 187 bufin = st->tmpbuf;
c@174 188 }else{
c@174 189 bufout = st->tmpbuf;
c@174 190 bufin = fout;
c@174 191 }
c@174 192 }
c@174 193 }