annotate ext/kissfft/tools/kiss_fftnd.c @ 199:cc51baf8e37e

Remove unused field
author Chris Cannam
date Thu, 26 May 2016 14:16:29 +0100
parents 76ec2365b250
children
rev   line source
Chris@184 1
Chris@184 2
Chris@184 3 /*
Chris@184 4 Copyright (c) 2003-2004, Mark Borgerding
Chris@184 5
Chris@184 6 All rights reserved.
Chris@184 7
Chris@184 8 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Chris@184 9
Chris@184 10 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Chris@184 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.
Chris@184 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.
Chris@184 13
Chris@184 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.
Chris@184 15 */
Chris@184 16
Chris@184 17 #include "kiss_fftnd.h"
Chris@184 18 #include "_kiss_fft_guts.h"
Chris@184 19
Chris@184 20 struct kiss_fftnd_state{
Chris@184 21 int dimprod; /* dimsum would be mighty tasty right now */
Chris@184 22 int ndims;
Chris@184 23 int *dims;
Chris@184 24 kiss_fft_cfg *states; /* cfg states for each dimension */
Chris@184 25 kiss_fft_cpx * tmpbuf; /*buffer capable of hold the entire input */
Chris@184 26 };
Chris@184 27
Chris@184 28 kiss_fftnd_cfg kiss_fftnd_alloc(const int *dims,int ndims,int inverse_fft,void*mem,size_t*lenmem)
Chris@184 29 {
Chris@184 30 kiss_fftnd_cfg st = NULL;
Chris@184 31 int i;
Chris@184 32 int dimprod=1;
Chris@184 33 size_t memneeded = sizeof(struct kiss_fftnd_state);
Chris@184 34 char * ptr;
Chris@184 35
Chris@184 36 for (i=0;i<ndims;++i) {
Chris@184 37 size_t sublen=0;
Chris@184 38 kiss_fft_alloc (dims[i], inverse_fft, NULL, &sublen);
Chris@184 39 memneeded += sublen; /* st->states[i] */
Chris@184 40 dimprod *= dims[i];
Chris@184 41 }
Chris@184 42 memneeded += sizeof(int) * ndims;/* st->dims */
Chris@184 43 memneeded += sizeof(void*) * ndims;/* st->states */
Chris@184 44 memneeded += sizeof(kiss_fft_cpx) * dimprod; /* st->tmpbuf */
Chris@184 45
Chris@184 46 if (lenmem == NULL) {/* allocate for the caller*/
Chris@184 47 st = (kiss_fftnd_cfg) malloc (memneeded);
Chris@184 48 } else { /* initialize supplied buffer if big enough */
Chris@184 49 if (*lenmem >= memneeded)
Chris@184 50 st = (kiss_fftnd_cfg) mem;
Chris@184 51 *lenmem = memneeded; /*tell caller how big struct is (or would be) */
Chris@184 52 }
Chris@184 53 if (!st)
Chris@184 54 return NULL; /*malloc failed or buffer too small */
Chris@184 55
Chris@184 56 st->dimprod = dimprod;
Chris@184 57 st->ndims = ndims;
Chris@184 58 ptr=(char*)(st+1);
Chris@184 59
Chris@184 60 st->states = (kiss_fft_cfg *)ptr;
Chris@184 61 ptr += sizeof(void*) * ndims;
Chris@184 62
Chris@184 63 st->dims = (int*)ptr;
Chris@184 64 ptr += sizeof(int) * ndims;
Chris@184 65
Chris@184 66 st->tmpbuf = (kiss_fft_cpx*)ptr;
Chris@184 67 ptr += sizeof(kiss_fft_cpx) * dimprod;
Chris@184 68
Chris@184 69 for (i=0;i<ndims;++i) {
Chris@184 70 size_t len;
Chris@184 71 st->dims[i] = dims[i];
Chris@184 72 kiss_fft_alloc (st->dims[i], inverse_fft, NULL, &len);
Chris@184 73 st->states[i] = kiss_fft_alloc (st->dims[i], inverse_fft, ptr,&len);
Chris@184 74 ptr += len;
Chris@184 75 }
Chris@184 76 /*
Chris@184 77 Hi there!
Chris@184 78
Chris@184 79 If you're looking at this particular code, it probably means you've got a brain-dead bounds checker
Chris@184 80 that thinks the above code overwrites the end of the array.
Chris@184 81
Chris@184 82 It doesn't.
Chris@184 83
Chris@184 84 -- Mark
Chris@184 85
Chris@184 86 P.S.
Chris@184 87 The below code might give you some warm fuzzies and help convince you.
Chris@184 88 */
Chris@184 89 if ( ptr - (char*)st != (int)memneeded ) {
Chris@184 90 fprintf(stderr,
Chris@184 91 "################################################################################\n"
Chris@184 92 "Internal error! Memory allocation miscalculation\n"
Chris@184 93 "################################################################################\n"
Chris@184 94 );
Chris@184 95 }
Chris@184 96 return st;
Chris@184 97 }
Chris@184 98
Chris@184 99 /*
Chris@184 100 This works by tackling one dimension at a time.
Chris@184 101
Chris@184 102 In effect,
Chris@184 103 Each stage starts out by reshaping the matrix into a DixSi 2d matrix.
Chris@184 104 A Di-sized fft is taken of each column, transposing the matrix as it goes.
Chris@184 105
Chris@184 106 Here's a 3-d example:
Chris@184 107 Take a 2x3x4 matrix, laid out in memory as a contiguous buffer
Chris@184 108 [ [ [ a b c d ] [ e f g h ] [ i j k l ] ]
Chris@184 109 [ [ m n o p ] [ q r s t ] [ u v w x ] ] ]
Chris@184 110
Chris@184 111 Stage 0 ( D=2): treat the buffer as a 2x12 matrix
Chris@184 112 [ [a b ... k l]
Chris@184 113 [m n ... w x] ]
Chris@184 114
Chris@184 115 FFT each column with size 2.
Chris@184 116 Transpose the matrix at the same time using kiss_fft_stride.
Chris@184 117
Chris@184 118 [ [ a+m a-m ]
Chris@184 119 [ b+n b-n]
Chris@184 120 ...
Chris@184 121 [ k+w k-w ]
Chris@184 122 [ l+x l-x ] ]
Chris@184 123
Chris@184 124 Note fft([x y]) == [x+y x-y]
Chris@184 125
Chris@184 126 Stage 1 ( D=3) treats the buffer (the output of stage D=2) as an 3x8 matrix,
Chris@184 127 [ [ a+m a-m b+n b-n c+o c-o d+p d-p ]
Chris@184 128 [ e+q e-q f+r f-r g+s g-s h+t h-t ]
Chris@184 129 [ i+u i-u j+v j-v k+w k-w l+x l-x ] ]
Chris@184 130
Chris@184 131 And perform FFTs (size=3) on each of the columns as above, transposing
Chris@184 132 the matrix as it goes. The output of stage 1 is
Chris@184 133 (Legend: ap = [ a+m e+q i+u ]
Chris@184 134 am = [ a-m e-q i-u ] )
Chris@184 135
Chris@184 136 [ [ sum(ap) fft(ap)[0] fft(ap)[1] ]
Chris@184 137 [ sum(am) fft(am)[0] fft(am)[1] ]
Chris@184 138 [ sum(bp) fft(bp)[0] fft(bp)[1] ]
Chris@184 139 [ sum(bm) fft(bm)[0] fft(bm)[1] ]
Chris@184 140 [ sum(cp) fft(cp)[0] fft(cp)[1] ]
Chris@184 141 [ sum(cm) fft(cm)[0] fft(cm)[1] ]
Chris@184 142 [ sum(dp) fft(dp)[0] fft(dp)[1] ]
Chris@184 143 [ sum(dm) fft(dm)[0] fft(dm)[1] ] ]
Chris@184 144
Chris@184 145 Stage 2 ( D=4) treats this buffer as a 4*6 matrix,
Chris@184 146 [ [ sum(ap) fft(ap)[0] fft(ap)[1] sum(am) fft(am)[0] fft(am)[1] ]
Chris@184 147 [ sum(bp) fft(bp)[0] fft(bp)[1] sum(bm) fft(bm)[0] fft(bm)[1] ]
Chris@184 148 [ sum(cp) fft(cp)[0] fft(cp)[1] sum(cm) fft(cm)[0] fft(cm)[1] ]
Chris@184 149 [ sum(dp) fft(dp)[0] fft(dp)[1] sum(dm) fft(dm)[0] fft(dm)[1] ] ]
Chris@184 150
Chris@184 151 Then FFTs each column, transposing as it goes.
Chris@184 152
Chris@184 153 The resulting matrix is the 3d FFT of the 2x3x4 input matrix.
Chris@184 154
Chris@184 155 Note as a sanity check that the first element of the final
Chris@184 156 stage's output (DC term) is
Chris@184 157 sum( [ sum(ap) sum(bp) sum(cp) sum(dp) ] )
Chris@184 158 , i.e. the summation of all 24 input elements.
Chris@184 159
Chris@184 160 */
Chris@184 161 void kiss_fftnd(kiss_fftnd_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
Chris@184 162 {
Chris@184 163 int i,k;
Chris@184 164 const kiss_fft_cpx * bufin=fin;
Chris@184 165 kiss_fft_cpx * bufout;
Chris@184 166
Chris@184 167 /*arrange it so the last bufout == fout*/
Chris@184 168 if ( st->ndims & 1 ) {
Chris@184 169 bufout = fout;
Chris@184 170 if (fin==fout) {
Chris@184 171 memcpy( st->tmpbuf, fin, sizeof(kiss_fft_cpx) * st->dimprod );
Chris@184 172 bufin = st->tmpbuf;
Chris@184 173 }
Chris@184 174 }else
Chris@184 175 bufout = st->tmpbuf;
Chris@184 176
Chris@184 177 for ( k=0; k < st->ndims; ++k) {
Chris@184 178 int curdim = st->dims[k];
Chris@184 179 int stride = st->dimprod / curdim;
Chris@184 180
Chris@184 181 for ( i=0 ; i<stride ; ++i )
Chris@184 182 kiss_fft_stride( st->states[k], bufin+i , bufout+i*curdim, stride );
Chris@184 183
Chris@184 184 /*toggle back and forth between the two buffers*/
Chris@184 185 if (bufout == st->tmpbuf){
Chris@184 186 bufout = fout;
Chris@184 187 bufin = st->tmpbuf;
Chris@184 188 }else{
Chris@184 189 bufout = st->tmpbuf;
Chris@184 190 bufin = fout;
Chris@184 191 }
Chris@184 192 }
Chris@184 193 }