/* ======================================================================== */
/*  TEXAS INSTRUMENTS, INC.                                                 */
/*                                                                          */
/*  NAME                                                                    */
/*      tw_fftSPxSP_C67                                                     */
/*                                                                          */
/*  USAGE                                                                   */
/*      This is a stand-alone program intended to generate twiddle-factor   */
/*      arrays for the C67x DSPF_sp_fftSPxSP  library routine.              */
/*      It is called as follows:                                            */
/*                                                                          */
/*          tw_fftSPxSP_C67 N > outputfile.c                                */
/*                                                                          */
/*      The argument 'N' specifies the size of the FFT.  This value         */
/*      must be a power of 2.                                               */
/*                                                                          */
/*      This program will generate the twiddle factor array 'w' and         */
/*      output the result to the display.  Redirect the output to           */
/*      a file as shown above.                                              */
/*                                                                          */
/*  DESCRIPTION                                                             */
/*      This program contains the twiddle-factor generation routine         */
/*      that is described within the source code for the C67x DSPLIB        */
/*      FFT functions DSPF_sp_fftSPxSP  It does not 						*/
/*      produce appropriate twiddle-factor arrays for the other FFT         */
/*      implementations.                                                    */
/*                                                                          */
/*      Please consult the specific FFT that you are using for details.     */
/*                                                                          */
/*      The final twiddle-factor array generated by the routine will        */
/*      be 2 * N elements long.                                             */
/*                                                                          */
/*  NOTES                                                                   */
/*      The code below may be adapted to run directly on the target,        */
/*      rather than running as a separate program running off-line.         */
/*      Such adaptation is not recommended for time-critical applications.  */
/*      To adapt this program, remove the 'usage' and 'main' functions,     */
/*      and call 'gen_twiddle' directly.                                    */
/*                                                                          */
/* ------------------------------------------------------------------------ */
/*            Copyright (c) 2001 Texas Instruments, Incorporated.           */
/*                           All Rights Reserved.                           */
/* ======================================================================== */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#ifndef PI
# ifdef M_PI
#  define PI M_PI
# else
#  define PI 3.14159265358979323846
# endif
#endif

/* ======================================================================== */
/*  GEN_TWIDDLE -- Generate twiddle factors for TI's custom FFTs.           */
/*                                                                          */
/*  USAGE                                                                   */
/*      This routine is called as follows:                                  */
/*                                                                          */
/*          int gen_twiddle(float *w, int n)                                */
/*                                                                          */
/*          short  *w     Pointer to twiddle-factor array                   */
/*          int    n      Size of FFT                                       */
/*                                                                          */
/*      The routine will generate the twiddle-factors directly into the     */
/*      array you specify.  The array needs to be approximately 2*N         */
/*      elements long.  (The actual size, which is slightly smaller, is     */
/*      returned by the function.)                                          */
/* ======================================================================== */
int gen_twiddle(float *w, int n)
{
    int i, j, k;

    for (j = 1, k = 0; j < n >> 2; j = j << 2)
    {
        for (i = 0; i < n >> 2; i += j)
        {
            w[k +  5] =  sin(6.0 * PI * i / n);
            w[k +  4] =  cos(6.0 * PI * i / n);

            w[k +  3] =  sin(4.0 * PI * i / n);
            w[k +  2] =  cos(4.0 * PI * i / n);

            w[k +  1] =  sin(2.0 * PI * i / n);
            w[k +  0] =  cos(2.0 * PI * i / n);

            k += 6;
        }
    }

    return k;
}

/* ======================================================================== */
/*  USAGE -- Print usage information and optionally an error message.       */
/* ======================================================================== */
void usage(char *error)
{
    fprintf(stderr,
"                                                                        \n"
"USAGE                                                                   \n"
"    This is a stand-alone program intended to generate twiddle-factor   \n"
"    arrays for the C67x DSPF_sp_fftSPxSP FFT library routines.          \n"
"    It is called as follows:                                            \n"
"                                                                        \n"
"        tw_fftSPxSP_C67 N > outputfile.c                                \n"
"                                                                        \n"
"    The argument 'N' specifies the size of the FFT.  This value         \n"
"    must be a power of 2.                                               \n"
"                                                                        \n"
"    This program will generate the twiddle factor array 'w' and         \n"
"    output the result to the display.  Redirect the output to           \n"
"    a file as shown above.                                              \n"
"                                                                        \n");

    if (error)
        fprintf(stderr, "ERROR:  %s\n", error);

    exit(1);
}


/* ======================================================================== */
/*  MAIN -- Where the action happens.                                       */
/* ======================================================================== */
int main(int argc, char *argv[])
{
    int i, n = -1, size;
    int is_pow_2 = 0;
    float *w;
    char *s;
    char buf[80];

    /* -------------------------------------------------------------------- */
    /*  Parse the arguments.                                                */
    /* -------------------------------------------------------------------- */
    if (argc < 2) { usage(NULL); }

    while (argc-->1)
    {
            if (!isdigit(argv[1][0]) || sscanf(argv[1], "%d", &n) != 1)
            {
                sprintf(buf, "Unrecognized argument:  %-.32s\n",
                        argv[1][0]);
                usage(buf);
            }

            if (n < 16 || n > 32768)
                usage("FFT size must be between 16 and 32768 points.");

            for (i = 2; i < 24; i++)
                if ((1 << i) == n) break;

            is_pow_2 = !(i & 1);

            if (i >= 24)
            {
                usage("FFT size must be a power of 2\n");
                exit(1);
            }
        }

    if (n == -1)
        usage("Must specify FFT size.");

    /* -------------------------------------------------------------------- */
    /*  Allocate memory for the FFT twiddle factors.                        */
    /* -------------------------------------------------------------------- */
    w = calloc(2 * sizeof(float), n);
    if (!w)
    {
        fprintf(stderr, "ERROR:  Unable to allocate memory for "
                        "twiddle factors\n");
        exit(1);
    }


    /* -------------------------------------------------------------------- */
    /*  Generate the twiddle-factor array.                                  */
    /* -------------------------------------------------------------------- */
    size = gen_twiddle(w, n);


    /* -------------------------------------------------------------------- */
    /*  Print out the resulting twiddle factors.                            */
    /* -------------------------------------------------------------------- */

    printf(
"/* -------------------------------------------------------------------- */\n"
"/*  Automatically generated twiddle-factor array.                       */\n"
"/*      Number of points:    %-5d                                       */\n"
"/*      Appropriate FFTs:    C67x DSPF_sp_fftSPxSP                      */\n"
"/*      Required alignment:  8 byte (double-word)                       */\n"
"/* -------------------------------------------------------------------- */\n",
        n);

    printf("#pragma DATA_ALIGN(w, 8);\n");

    printf("const float w[2 * %d] =\n{", size / 2);
    for (i = 0; i < size; i++)
    {
        printf("%s%c%f",
               i == 0 ? "\n    " : (i & 7) == 0 ? ",\n    " : ", ",
               w[i] < 0 ? '-' : ' ', fabs(w[i]));
    }
    printf("\n};\n");

    return 0;
}
