/* ======================================================================== */
/*  TEXAS INSTRUMENTS, INC.                                                 */
/*                                                                          */
/*  NAME                                                                    */
/*      tw_r4fft                                                            */
/*                                                                          */
/*  USAGE                                                                   */
/*      This is a stand-alone program intended to generate twiddle-factor   */
/*      arrays for the DSPF_sp_cfftr4_dif FFT library routine. It is called */
/*      as:                                                                 */
/*                                                                          */
/*          tw_r4fft N > outputfile.c                                       */
/*                                                                          */
/*      The argument 'N' specifies the size of the FFT.  This value         */
/*      must be a power of 4.                                               */
/*                                                                          */
/*      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 DSPLIB             */
/*      FFT function DSPF_sp_cfftr4_dif. 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 3 * N / 2 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)                                */
/*                                                                          */
/*          float  *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 3*N/2 elements long.      */
/* ======================================================================== */
int gen_twiddle(float *w, int n)
{
    double angle, step;
    int i;

    step = (2.0 * PI) / (double)n;
    for (i = 0, angle = 0.0; i < 3*n/4; i++, angle += step)
    {
        w[2*i + 1] = sin(angle);
        w[2*i + 0] = cos(angle);
    }

    return 3*n/2;
}

/* ======================================================================== */
/*  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 DSPF_sp_cfftr4_dif library routine. It is called as  \n"
"    follows:                                                            \n"
"                                                                        \n"
"        tw_r4fft  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_4 = 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 < 8  || n > 16384)
                usage("FFT size must be between 8  and 16384 points.");

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

            is_pow_4 = !(i & 1);

            if (i >= 24 || !is_pow_4)
            {
                usage("FFT size must be a power of 4\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:    DSPF_sp_cfftr4_dif                         */\n"
"/*      Required alignment:  8 byte (double word)                       */\n"
"/* -------------------------------------------------------------------- */\n"
"/*  NOTE:  It is suggested that this array be aligned to an odd         */\n"
"/*  starting bank to reduce bank conflicts.  This can be achieved by    */\n"
"/*  using the DATA_MEM_BANK pragma.  Please see the TMS320C6000         */\n"
"/*  Optimizing C Compiler Reference (SPRU187E) for details on using     */\n"
"/*  \"#pragma DATA_MEM_BANK\".                                            */\n"
"/* -------------------------------------------------------------------- */\n"
"\n"
"#ifdef _TMS320C6400\n"
"# pragma DATA_MEM_BANK(w, 1);  /* C64x has 32-bit banks */\n"
"#else\n"
"# pragma DATA_MEM_BANK(w, 2);  /* C62x and C67x have 16-bit banks */\n"
"#endif\n"
"\n",
        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;
}
