Blame libcelt/kiss_fftr.c

Packit 664db3
/*
Packit 664db3
Original version:
Packit 664db3
Copyright (c) 2003-2004, Mark Borgerding
Packit 664db3
Followed by heavy modifications:
Packit 664db3
Copyright (c) 2007-2008, Jean-Marc Valin
Packit 664db3
Packit 664db3
Packit 664db3
All rights reserved.
Packit 664db3
Packit 664db3
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Packit 664db3
Packit 664db3
    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Packit 664db3
    * 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.
Packit 664db3
    * 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.
Packit 664db3
Packit 664db3
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.
Packit 664db3
*/
Packit 664db3
Packit 664db3
#ifndef SKIP_CONFIG_H
Packit 664db3
#  ifdef HAVE_CONFIG_H
Packit 664db3
#    include "config.h"
Packit 664db3
#  endif
Packit 664db3
#endif
Packit 664db3
Packit 664db3
#include "os_support.h"
Packit 664db3
#include "mathops.h"
Packit 664db3
#include "kiss_fftr.h"
Packit 664db3
#include "_kiss_fft_guts.h"
Packit 664db3
Packit 664db3
Packit 664db3
kiss_fftr_cfg kiss_fftr_alloc(int nfft,void * mem,size_t * lenmem)
Packit 664db3
{
Packit 664db3
    int i;
Packit 664db3
    int twiddle_size;
Packit 664db3
    kiss_fftr_cfg st = NULL;
Packit 664db3
    size_t subsize, memneeded;
Packit 664db3
Packit 664db3
    if (nfft & 1) {
Packit 664db3
        celt_warning("Real FFT optimization must be even.\n");
Packit 664db3
        return NULL;
Packit 664db3
    }
Packit 664db3
    nfft >>= 1;
Packit 664db3
    twiddle_size = nfft/2+1;
Packit 664db3
    kiss_fft_alloc (nfft, NULL, &subsize);
Packit 664db3
    memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_twiddle_cpx)*twiddle_size;
Packit 664db3
Packit 664db3
    if (lenmem == NULL) {
Packit 664db3
        st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded);
Packit 664db3
    } else {
Packit 664db3
        if (*lenmem >= memneeded)
Packit 664db3
            st = (kiss_fftr_cfg) mem;
Packit 664db3
        *lenmem = memneeded;
Packit 664db3
    }
Packit 664db3
    if (!st)
Packit 664db3
        return NULL;
Packit 664db3
Packit 664db3
    st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */
Packit 664db3
    st->super_twiddles = (kiss_twiddle_cpx*) (((char *) st->substate) + subsize);
Packit 664db3
    kiss_fft_alloc(nfft, st->substate, &subsize);
Packit 664db3
#ifndef FIXED_POINT
Packit 664db3
    st->substate->scale *= .5;
Packit 664db3
#endif
Packit 664db3
Packit 664db3
#if defined (FIXED_POINT) && (!defined(DOUBLE_PRECISION) || defined(MIXED_PRECISION))
Packit 664db3
    for (i=0;i
Packit 664db3
       celt_word32_t phase = i+(nfft>>1);
Packit 664db3
       kf_cexp2(st->super_twiddles+i, DIV32(SHL32(phase,16),nfft));
Packit 664db3
    }
Packit 664db3
#else
Packit 664db3
    for (i=0;i
Packit 664db3
       const double pi=3.14159265358979323846264338327;
Packit 664db3
       double phase = pi*(((double)i) /nfft + .5);
Packit 664db3
       kf_cexp(st->super_twiddles+i, phase );
Packit 664db3
    }
Packit 664db3
#endif
Packit 664db3
    return st;
Packit 664db3
}
Packit 664db3
Packit 664db3
void kiss_fftr_twiddles(kiss_fftr_cfg st,kiss_fft_scalar *freqdata)
Packit 664db3
{
Packit 664db3
   /* input buffer timedata is stored row-wise */
Packit 664db3
   int k,ncfft;
Packit 664db3
   kiss_fft_cpx f2k,f1k,tdc,tw;
Packit 664db3
Packit 664db3
   ncfft = st->substate->nfft;
Packit 664db3
Packit 664db3
    /* The real part of the DC element of the frequency spectrum in st->tmpbuf
Packit 664db3
   * contains the sum of the even-numbered elements of the input time sequence
Packit 664db3
   * The imag part is the sum of the odd-numbered elements
Packit 664db3
   *
Packit 664db3
   * The sum of tdc.r and tdc.i is the sum of the input time sequence. 
Packit 664db3
   *      yielding DC of input time sequence
Packit 664db3
   * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... 
Packit 664db3
   *      yielding Nyquist bin of input time sequence
Packit 664db3
    */
Packit 664db3
 
Packit 664db3
   tdc.r = freqdata[0];
Packit 664db3
   tdc.i = freqdata[1];
Packit 664db3
   C_FIXDIV(tdc,2);
Packit 664db3
   CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i);
Packit 664db3
   CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i);
Packit 664db3
   freqdata[0] = tdc.r + tdc.i;
Packit 664db3
   freqdata[1] = tdc.r - tdc.i;
Packit 664db3
Packit 664db3
   for ( k=1;k <= ncfft/2 ; ++k )
Packit 664db3
   {
Packit 664db3
      f2k.r = SHR32(SUB32(EXT32(freqdata[2*k]), EXT32(freqdata[2*(ncfft-k)])),1);
Packit 664db3
      f2k.i = PSHR32(ADD32(EXT32(freqdata[2*k+1]), EXT32(freqdata[2*(ncfft-k)+1])),1);
Packit 664db3
      
Packit 664db3
      f1k.r = SHR32(ADD32(EXT32(freqdata[2*k]), EXT32(freqdata[2*(ncfft-k)])),1);
Packit 664db3
      f1k.i = SHR32(SUB32(EXT32(freqdata[2*k+1]), EXT32(freqdata[2*(ncfft-k)+1])),1);
Packit 664db3
      
Packit 664db3
      C_MULC( tw , f2k , st->super_twiddles[k]);
Packit 664db3
      
Packit 664db3
      freqdata[2*k] = HALF_OF(f1k.r + tw.r);
Packit 664db3
      freqdata[2*k+1] = HALF_OF(f1k.i + tw.i);
Packit 664db3
      freqdata[2*(ncfft-k)] = HALF_OF(f1k.r - tw.r);
Packit 664db3
      freqdata[2*(ncfft-k)+1] = HALF_OF(tw.i - f1k.i);
Packit 664db3
Packit 664db3
   }
Packit 664db3
}
Packit 664db3
Packit 664db3
void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar *freqdata)
Packit 664db3
{
Packit 664db3
   /*perform the parallel fft of two real signals packed in real,imag*/
Packit 664db3
   kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, (kiss_fft_cpx *)freqdata );
Packit 664db3
Packit 664db3
   kiss_fftr_twiddles(st,freqdata);
Packit 664db3
}
Packit 664db3
Packit 664db3
void kiss_fftr_inplace(kiss_fftr_cfg st, kiss_fft_scalar *X)
Packit 664db3
{
Packit 664db3
   kf_work((kiss_fft_cpx*)X, NULL, 1,1, st->substate->factors,st->substate, 1, 1, 1);
Packit 664db3
   kiss_fftr_twiddles(st,X);
Packit 664db3
}
Packit 664db3
Packit 664db3
void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_scalar *freqdata,kiss_fft_scalar *timedata)
Packit 664db3
{
Packit 664db3
   /* input buffer timedata is stored row-wise */
Packit 664db3
   int k, ncfft;
Packit 664db3
Packit 664db3
   ncfft = st->substate->nfft;
Packit 664db3
Packit 664db3
   timedata[2*st->substate->bitrev[0]] = freqdata[0] + freqdata[1];
Packit 664db3
   timedata[2*st->substate->bitrev[0]+1] = freqdata[0] - freqdata[1];
Packit 664db3
   for (k = 1; k <= ncfft / 2; ++k) {
Packit 664db3
      kiss_fft_cpx fk, fnkc, fek, fok, tmp;
Packit 664db3
      int k1, k2;
Packit 664db3
      k1 = st->substate->bitrev[k];
Packit 664db3
      k2 = st->substate->bitrev[ncfft-k];
Packit 664db3
      fk.r = freqdata[2*k];
Packit 664db3
      fk.i = freqdata[2*k+1];
Packit 664db3
      fnkc.r = freqdata[2*(ncfft-k)];
Packit 664db3
      fnkc.i = -freqdata[2*(ncfft-k)+1];
Packit 664db3
Packit 664db3
      C_ADD (fek, fk, fnkc);
Packit 664db3
      C_SUB (tmp, fk, fnkc);
Packit 664db3
      C_MUL (fok, tmp, st->super_twiddles[k]);
Packit 664db3
      timedata[2*k1] = fek.r + fok.r;
Packit 664db3
      timedata[2*k1+1] = fek.i + fok.i;
Packit 664db3
      timedata[2*k2] = fek.r - fok.r;
Packit 664db3
      timedata[2*k2+1] = fok.i - fek.i;
Packit 664db3
   }
Packit 664db3
   ki_work((kiss_fft_cpx*)timedata, NULL, 1,1, st->substate->factors,st->substate, 1, 1, 1);
Packit 664db3
}