/*
 *  TwoLAME: an optimized MPEG Audio Layer Two encoder
 *
 *  Copyright (C) 2001-2004 Michael Cheng
 *  Copyright (C) 2004-2006 The TwoLAME Project
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *  $Id: fft.c,v 1.3 2008-02-01 19:44:32 richardash1981 Exp $
 *
 */



/*
** FFT and FHT routines
**  Copyright 1988, 1993; Ron Mayer
**  
**  fht(fz,n);
**    Does a hartley transform of "n" points in the array "fz".
**    
** NOTE: This routine uses at least 2 patented algorithms, and may be
**       under the restrictions of a bunch of different organizations.
**       Although I wrote it completely myself; it is kind of a derivative
**       of a routine I once authored and released under the GPL, so it
**       may fall under the free software foundation's restrictions;
**       it was worked on as a Stanford Univ project, so they claim
**       some rights to it; it was further optimized at work here, so
**       I think this company claims parts of it.  The patents are
**       held by R. Bracewell (the FHT algorithm) and O. Buneman (the
**       trig generator), both at Stanford Univ.
**       If it were up to me, I'd say go do whatever you want with it;
**       but it would be polite to give credit to the following people
**       if you use this anywhere:
**           Euler     - probable inventor of the fourier transform.
**           Gauss     - probable inventor of the FFT.
**           Hartley   - probable inventor of the hartley transform.
**           Buneman   - for a really cool trig generator
**           Mayer(me) - for authoring this particular version and
**                       including all the optimizations in one package.
**       Thanks,
**       Ron Mayer; mayer@acuson.com
**
*/

#include <stdio.h>
#include <math.h>

#include "twolame.h"
#include "common.h"
#include "fft.h"



#define	SQRT2		1.4142135623730951454746218587388284504414


static const FLOAT costab[20] = {
	.00000000000000000000000000000000000000000000000000,
	.70710678118654752440084436210484903928483593768847,
	.92387953251128675612818318939678828682241662586364,
	.98078528040323044912618223613423903697393373089333,
	.99518472667219688624483695310947992157547486872985,
	.99879545620517239271477160475910069444320361470461,
	.99969881869620422011576564966617219685006108125772,
	.99992470183914454092164649119638322435060646880221,
	.99998117528260114265699043772856771617391725094433,
	.99999529380957617151158012570011989955298763362218,
	.99999882345170190992902571017152601904826792288976,
	.99999970586288221916022821773876567711626389934930,
	.99999992646571785114473148070738785694820115568892,
	.99999998161642929380834691540290971450507605124278,
	.99999999540410731289097193313960614895889430318945,
	.99999999885102682756267330779455410840053741619428
};
static const FLOAT sintab[20] = {
	1.0000000000000000000000000000000000000000000000000,
	.70710678118654752440084436210484903928483593768846,
	.38268343236508977172845998403039886676134456248561,
	.19509032201612826784828486847702224092769161775195,
	.09801714032956060199419556388864184586113667316749,
	.04906767432741801425495497694268265831474536302574,
	.02454122852291228803173452945928292506546611923944,
	.01227153828571992607940826195100321214037231959176,
	.00613588464915447535964023459037258091705788631738,
	.00306795676296597627014536549091984251894461021344,
	.00153398018628476561230369715026407907995486457522,
	.00076699031874270452693856835794857664314091945205,
	.00038349518757139558907246168118138126339502603495,
	.00019174759731070330743990956198900093346887403385,
	.00009587379909597734587051721097647635118706561284,
	.00004793689960306688454900399049465887274686668768
};

/* This is a simplified version for n an even power of 2 */
/* MFC: In the case of LayerII encoding, n==1024 always. */

static void fht (FLOAT * fz)
{
	int i, k, k1, k2, k3, k4, kx;
	FLOAT *fi, *fn, *gi;
	FLOAT t_c, t_s;
	
	FLOAT a;
	static const struct {
		unsigned short k1, k2;
	}
	
	k1k2tab[8 * 62] = {
		{ 0x020, 0x010 }, { 0x040, 0x008 }, { 0x050, 0x028 }, { 0x060, 0x018 }, { 0x068, 0x058 }, 
		{ 0x070, 0x038 }, { 0x080, 0x004 }, { 0x088, 0x044 }, { 0x090, 0x024 }, { 0x098, 0x064 }, 
		{ 0x0a0, 0x014 }, { 0x0a4, 0x094 }, { 0x0a8, 0x054 }, { 0x0b0, 0x034 }, { 0x0b8, 0x074 }, 
		{ 0x0c0, 0x00c }, { 0x0c4, 0x08c }, { 0x0c8, 0x04c }, { 0x0d0, 0x02c }, { 0x0d4, 0x0ac }, 
		{ 0x0d8, 0x06c }, { 0x0e0, 0x01c }, { 0x0e4, 0x09c }, { 0x0e8, 0x05c }, { 0x0ec, 0x0dc }, 
		{ 0x0f0, 0x03c }, { 0x0f4, 0x0bc }, { 0x0f8, 0x07c }, { 0x100, 0x002 }, { 0x104, 0x082 }, 
		{ 0x108, 0x042 }, { 0x10c, 0x0c2 }, { 0x110, 0x022 }, { 0x114, 0x0a2 }, { 0x118, 0x062 }, 
		{ 0x11c, 0x0e2 }, { 0x120, 0x012 }, { 0x122, 0x112 }, { 0x124, 0x092 }, { 0x128, 0x052 }, 
		{ 0x12c, 0x0d2 }, { 0x130, 0x032 }, { 0x134, 0x0b2 }, { 0x138, 0x072 }, { 0x13c, 0x0f2 }, 
		{ 0x140, 0x00a }, { 0x142, 0x10a }, { 0x144, 0x08a }, { 0x148, 0x04a }, { 0x14c, 0x0ca }, 
		{ 0x150, 0x02a }, { 0x152, 0x12a }, { 0x154, 0x0aa }, { 0x158, 0x06a }, { 0x15c, 0x0ea }, 
		{ 0x160, 0x01a }, { 0x162, 0x11a }, { 0x164, 0x09a }, { 0x168, 0x05a }, { 0x16a, 0x15a }, 
		{ 0x16c, 0x0da }, { 0x170, 0x03a }, { 0x172, 0x13a }, { 0x174, 0x0ba }, { 0x178, 0x07a }, 
		{ 0x17c, 0x0fa }, { 0x180, 0x006 }, { 0x182, 0x106 }, { 0x184, 0x086 }, { 0x188, 0x046 }, 
		{ 0x18a, 0x146 }, { 0x18c, 0x0c6 }, { 0x190, 0x026 }, { 0x192, 0x126 }, { 0x194, 0x0a6 }, 
		{ 0x198, 0x066 }, { 0x19a, 0x166 }, { 0x19c, 0x0e6 }, { 0x1a0, 0x016 }, { 0x1a2, 0x116 }, 
		{ 0x1a4, 0x096 }, { 0x1a6, 0x196 }, { 0x1a8, 0x056 }, { 0x1aa, 0x156 }, { 0x1ac, 0x0d6 }, 
		{ 0x1b0, 0x036 }, { 0x1b2, 0x136 }, { 0x1b4, 0x0b6 }, { 0x1b8, 0x076 }, { 0x1ba, 0x176 }, 
		{ 0x1bc, 0x0f6 }, { 0x1c0, 0x00e }, { 0x1c2, 0x10e }, { 0x1c4, 0x08e }, { 0x1c6, 0x18e }, 
		{ 0x1c8, 0x04e }, { 0x1ca, 0x14e }, { 0x1cc, 0x0ce }, { 0x1d0, 0x02e }, { 0x1d2, 0x12e }, 
		{ 0x1d4, 0x0ae }, { 0x1d6, 0x1ae }, { 0x1d8, 0x06e }, { 0x1da, 0x16e }, { 0x1dc, 0x0ee }, 
		{ 0x1e0, 0x01e }, { 0x1e2, 0x11e }, { 0x1e4, 0x09e }, { 0x1e6, 0x19e }, { 0x1e8, 0x05e }, 
		{ 0x1ea, 0x15e }, { 0x1ec, 0x0de }, { 0x1ee, 0x1de }, { 0x1f0, 0x03e }, { 0x1f2, 0x13e }, 
		{ 0x1f4, 0x0be }, { 0x1f6, 0x1be }, { 0x1f8, 0x07e }, { 0x1fa, 0x17e }, { 0x1fc, 0x0fe }, 
		{ 0x200, 0x001 }, { 0x202, 0x101 }, { 0x204, 0x081 }, { 0x206, 0x181 }, { 0x208, 0x041 }, 
		{ 0x20a, 0x141 }, { 0x20c, 0x0c1 }, { 0x20e, 0x1c1 }, { 0x210, 0x021 }, { 0x212, 0x121 }, 
		{ 0x214, 0x0a1 }, { 0x216, 0x1a1 }, { 0x218, 0x061 }, { 0x21a, 0x161 }, { 0x21c, 0x0e1 }, 
		{ 0x21e, 0x1e1 }, { 0x220, 0x011 }, { 0x221, 0x211 }, { 0x222, 0x111 }, { 0x224, 0x091 }, 
		{ 0x226, 0x191 }, { 0x228, 0x051 }, { 0x22a, 0x151 }, { 0x22c, 0x0d1 }, { 0x22e, 0x1d1 }, 
		{ 0x230, 0x031 }, { 0x232, 0x131 }, { 0x234, 0x0b1 }, { 0x236, 0x1b1 }, { 0x238, 0x071 }, 
		{ 0x23a, 0x171 }, { 0x23c, 0x0f1 }, { 0x23e, 0x1f1 }, { 0x240, 0x009 }, { 0x241, 0x209 }, 
		{ 0x242, 0x109 }, { 0x244, 0x089 }, { 0x246, 0x189 }, { 0x248, 0x049 }, { 0x24a, 0x149 }, 
		{ 0x24c, 0x0c9 }, { 0x24e, 0x1c9 }, { 0x250, 0x029 }, { 0x251, 0x229 }, { 0x252, 0x129 }, 
		{ 0x254, 0x0a9 }, { 0x256, 0x1a9 }, { 0x258, 0x069 }, { 0x25a, 0x169 }, { 0x25c, 0x0e9 }, 
		{ 0x25e, 0x1e9 }, { 0x260, 0x019 }, { 0x261, 0x219 }, { 0x262, 0x119 }, { 0x264, 0x099 }, 
		{ 0x266, 0x199 }, { 0x268, 0x059 }, { 0x269, 0x259 }, { 0x26a, 0x159 }, { 0x26c, 0x0d9 }, 
		{ 0x26e, 0x1d9 }, { 0x270, 0x039 }, { 0x271, 0x239 }, { 0x272, 0x139 }, { 0x274, 0x0b9 }, 
		{ 0x276, 0x1b9 }, { 0x278, 0x079 }, { 0x27a, 0x179 }, { 0x27c, 0x0f9 }, { 0x27e, 0x1f9 }, 
		{ 0x280, 0x005 }, { 0x281, 0x205 }, { 0x282, 0x105 }, { 0x284, 0x085 }, { 0x286, 0x185 }, 
		{ 0x288, 0x045 }, { 0x289, 0x245 }, { 0x28a, 0x145 }, { 0x28c, 0x0c5 }, { 0x28e, 0x1c5 }, 
		{ 0x290, 0x025 }, { 0x291, 0x225 }, { 0x292, 0x125 }, { 0x294, 0x0a5 }, { 0x296, 0x1a5 }, 
		{ 0x298, 0x065 }, { 0x299, 0x265 }, { 0x29a, 0x165 }, { 0x29c, 0x0e5 }, { 0x29e, 0x1e5 }, 
		{ 0x2a0, 0x015 }, { 0x2a1, 0x215 }, { 0x2a2, 0x115 }, { 0x2a4, 0x095 }, { 0x2a5, 0x295 }, 
		{ 0x2a6, 0x195 }, { 0x2a8, 0x055 }, { 0x2a9, 0x255 }, { 0x2aa, 0x155 }, { 0x2ac, 0x0d5 }, 
		{ 0x2ae, 0x1d5 }, { 0x2b0, 0x035 }, { 0x2b1, 0x235 }, { 0x2b2, 0x135 }, { 0x2b4, 0x0b5 }, 
		{ 0x2b6, 0x1b5 }, { 0x2b8, 0x075 }, { 0x2b9, 0x275 }, { 0x2ba, 0x175 }, { 0x2bc, 0x0f5 }, 
		{ 0x2be, 0x1f5 }, { 0x2c0, 0x00d }, { 0x2c1, 0x20d }, { 0x2c2, 0x10d }, { 0x2c4, 0x08d }, 
		{ 0x2c5, 0x28d }, { 0x2c6, 0x18d }, { 0x2c8, 0x04d }, { 0x2c9, 0x24d }, { 0x2ca, 0x14d }, 
		{ 0x2cc, 0x0cd }, { 0x2ce, 0x1cd }, { 0x2d0, 0x02d }, { 0x2d1, 0x22d }, { 0x2d2, 0x12d }, 
		{ 0x2d4, 0x0ad }, { 0x2d5, 0x2ad }, { 0x2d6, 0x1ad }, { 0x2d8, 0x06d }, { 0x2d9, 0x26d }, 
		{ 0x2da, 0x16d }, { 0x2dc, 0x0ed }, { 0x2de, 0x1ed }, { 0x2e0, 0x01d }, { 0x2e1, 0x21d }, 
		{ 0x2e2, 0x11d }, { 0x2e4, 0x09d }, { 0x2e5, 0x29d }, { 0x2e6, 0x19d }, { 0x2e8, 0x05d }, 
		{ 0x2e9, 0x25d }, { 0x2ea, 0x15d }, { 0x2ec, 0x0dd }, { 0x2ed, 0x2dd }, { 0x2ee, 0x1dd }, 
		{ 0x2f0, 0x03d }, { 0x2f1, 0x23d }, { 0x2f2, 0x13d }, { 0x2f4, 0x0bd }, { 0x2f5, 0x2bd }, 
		{ 0x2f6, 0x1bd }, { 0x2f8, 0x07d }, { 0x2f9, 0x27d }, { 0x2fa, 0x17d }, { 0x2fc, 0x0fd }, 
		{ 0x2fe, 0x1fd }, { 0x300, 0x003 }, { 0x301, 0x203 }, { 0x302, 0x103 }, { 0x304, 0x083 }, 
		{ 0x305, 0x283 }, { 0x306, 0x183 }, { 0x308, 0x043 }, { 0x309, 0x243 }, { 0x30a, 0x143 }, 
		{ 0x30c, 0x0c3 }, { 0x30d, 0x2c3 }, { 0x30e, 0x1c3 }, { 0x310, 0x023 }, { 0x311, 0x223 }, 
		{ 0x312, 0x123 }, { 0x314, 0x0a3 }, { 0x315, 0x2a3 }, { 0x316, 0x1a3 }, { 0x318, 0x063 }, 
		{ 0x319, 0x263 }, { 0x31a, 0x163 }, { 0x31c, 0x0e3 }, { 0x31d, 0x2e3 }, { 0x31e, 0x1e3 }, 
		{ 0x320, 0x013 }, { 0x321, 0x213 }, { 0x322, 0x113 }, { 0x323, 0x313 }, { 0x324, 0x093 }, 
		{ 0x325, 0x293 }, { 0x326, 0x193 }, { 0x328, 0x053 }, { 0x329, 0x253 }, { 0x32a, 0x153 }, 
		{ 0x32c, 0x0d3 }, { 0x32d, 0x2d3 }, { 0x32e, 0x1d3 }, { 0x330, 0x033 }, { 0x331, 0x233 }, 
		{ 0x332, 0x133 }, { 0x334, 0x0b3 }, { 0x335, 0x2b3 }, { 0x336, 0x1b3 }, { 0x338, 0x073 }, 
		{ 0x339, 0x273 }, { 0x33a, 0x173 }, { 0x33c, 0x0f3 }, { 0x33d, 0x2f3 }, { 0x33e, 0x1f3 }, 
		{ 0x340, 0x00b }, { 0x341, 0x20b }, { 0x342, 0x10b }, { 0x343, 0x30b }, { 0x344, 0x08b }, 
		{ 0x345, 0x28b }, { 0x346, 0x18b }, { 0x348, 0x04b }, { 0x349, 0x24b }, { 0x34a, 0x14b }, 
		{ 0x34c, 0x0cb }, { 0x34d, 0x2cb }, { 0x34e, 0x1cb }, { 0x350, 0x02b }, { 0x351, 0x22b }, 
		{ 0x352, 0x12b }, { 0x353, 0x32b }, { 0x354, 0x0ab }, { 0x355, 0x2ab }, { 0x356, 0x1ab }, 
		{ 0x358, 0x06b }, { 0x359, 0x26b }, { 0x35a, 0x16b }, { 0x35c, 0x0eb }, { 0x35d, 0x2eb }, 
		{ 0x35e, 0x1eb }, { 0x360, 0x01b }, { 0x361, 0x21b }, { 0x362, 0x11b }, { 0x363, 0x31b }, 
		{ 0x364, 0x09b }, { 0x365, 0x29b }, { 0x366, 0x19b }, { 0x368, 0x05b }, { 0x369, 0x25b }, 
		{ 0x36a, 0x15b }, { 0x36b, 0x35b }, { 0x36c, 0x0db }, { 0x36d, 0x2db }, { 0x36e, 0x1db }, 
		{ 0x370, 0x03b }, { 0x371, 0x23b }, { 0x372, 0x13b }, { 0x373, 0x33b }, { 0x374, 0x0bb }, 
		{ 0x375, 0x2bb }, { 0x376, 0x1bb }, { 0x378, 0x07b }, { 0x379, 0x27b }, { 0x37a, 0x17b }, 
		{ 0x37c, 0x0fb }, { 0x37d, 0x2fb }, { 0x37e, 0x1fb }, { 0x380, 0x007 }, { 0x381, 0x207 }, 
		{ 0x382, 0x107 }, { 0x383, 0x307 }, { 0x384, 0x087 }, { 0x385, 0x287 }, { 0x386, 0x187 }, 
		{ 0x388, 0x047 }, { 0x389, 0x247 }, { 0x38a, 0x147 }, { 0x38b, 0x347 }, { 0x38c, 0x0c7 }, 
		{ 0x38d, 0x2c7 }, { 0x38e, 0x1c7 }, { 0x390, 0x027 }, { 0x391, 0x227 }, { 0x392, 0x127 }, 
		{ 0x393, 0x327 }, { 0x394, 0x0a7 }, { 0x395, 0x2a7 }, { 0x396, 0x1a7 }, { 0x398, 0x067 }, 
		{ 0x399, 0x267 }, { 0x39a, 0x167 }, { 0x39b, 0x367 }, { 0x39c, 0x0e7 }, { 0x39d, 0x2e7 }, 
		{ 0x39e, 0x1e7 }, { 0x3a0, 0x017 }, { 0x3a1, 0x217 }, { 0x3a2, 0x117 }, { 0x3a3, 0x317 }, 
		{ 0x3a4, 0x097 }, { 0x3a5, 0x297 }, { 0x3a6, 0x197 }, { 0x3a7, 0x397 }, { 0x3a8, 0x057 }, 
		{ 0x3a9, 0x257 }, { 0x3aa, 0x157 }, { 0x3ab, 0x357 }, { 0x3ac, 0x0d7 }, { 0x3ad, 0x2d7 }, 
		{ 0x3ae, 0x1d7 }, { 0x3b0, 0x037 }, { 0x3b1, 0x237 }, { 0x3b2, 0x137 }, { 0x3b3, 0x337 }, 
		{ 0x3b4, 0x0b7 }, { 0x3b5, 0x2b7 }, { 0x3b6, 0x1b7 }, { 0x3b8, 0x077 }, { 0x3b9, 0x277 }, 
		{ 0x3ba, 0x177 }, { 0x3bb, 0x377 }, { 0x3bc, 0x0f7 }, { 0x3bd, 0x2f7 }, { 0x3be, 0x1f7 }, 
		{ 0x3c0, 0x00f }, { 0x3c1, 0x20f }, { 0x3c2, 0x10f }, { 0x3c3, 0x30f }, { 0x3c4, 0x08f }, 
		{ 0x3c5, 0x28f }, { 0x3c6, 0x18f }, { 0x3c7, 0x38f }, { 0x3c8, 0x04f }, { 0x3c9, 0x24f }, 
		{ 0x3ca, 0x14f }, { 0x3cb, 0x34f }, { 0x3cc, 0x0cf }, { 0x3cd, 0x2cf }, { 0x3ce, 0x1cf }, 
		{ 0x3d0, 0x02f }, { 0x3d1, 0x22f }, { 0x3d2, 0x12f }, { 0x3d3, 0x32f }, { 0x3d4, 0x0af }, 
		{ 0x3d5, 0x2af }, { 0x3d6, 0x1af }, { 0x3d7, 0x3af }, { 0x3d8, 0x06f }, { 0x3d9, 0x26f }, 
		{ 0x3da, 0x16f }, { 0x3db, 0x36f }, { 0x3dc, 0x0ef }, { 0x3dd, 0x2ef }, { 0x3de, 0x1ef }, 
		{ 0x3e0, 0x01f }, { 0x3e1, 0x21f }, { 0x3e2, 0x11f }, { 0x3e3, 0x31f }, { 0x3e4, 0x09f }, 
		{ 0x3e5, 0x29f }, { 0x3e6, 0x19f }, { 0x3e7, 0x39f }, { 0x3e8, 0x05f }, { 0x3e9, 0x25f }, 
		{ 0x3ea, 0x15f }, { 0x3eb, 0x35f }, { 0x3ec, 0x0df }, { 0x3ed, 0x2df }, { 0x3ee, 0x1df }, 
		{ 0x3ef, 0x3df }, { 0x3f0, 0x03f }, { 0x3f1, 0x23f }, { 0x3f2, 0x13f }, { 0x3f3, 0x33f }, 
		{ 0x3f4, 0x0bf }, { 0x3f5, 0x2bf }, { 0x3f6, 0x1bf }, { 0x3f7, 0x3bf }, { 0x3f8, 0x07f }, 
		{ 0x3f9, 0x27f }, { 0x3fa, 0x17f }, { 0x3fb, 0x37f }, { 0x3fc, 0x0ff }, { 0x3fd, 0x2ff }, 
		{ 0x3fe, 0x1ff }
	};
  
  
	{
		int i;
		for (i = 0; i < sizeof k1k2tab / sizeof k1k2tab[0]; ++i) {
			k1 = k1k2tab[i].k1;
			k2 = k1k2tab[i].k2;
			a = fz[k1];
			fz[k1] = fz[k2];
			fz[k2] = a;
		}
	}

	for (fi = fz, fn = fz + 1024; fi < fn; fi += 4) {
		FLOAT f0, f1, f2, f3;
		f1 = fi[0] - fi[1];
		f0 = fi[0] + fi[1];
		f3 = fi[2] - fi[3];
		f2 = fi[2] + fi[3];
		fi[2] = (f0 - f2);
		fi[0] = (f0 + f2);
		fi[3] = (f1 - f3);
		fi[1] = (f1 + f3);
	}

	k = 0;
	do {
		FLOAT s1, c1;
		k += 2;
		k1 = 1 << k;
		k2 = k1 << 1;
		k4 = k2 << 1;
		k3 = k2 + k1;
		kx = k1 >> 1;
		fi = fz;
		gi = fi + kx;
		fn = fz + 1024;
		do {
			FLOAT g0, f0, f1, g1, f2, g2, f3, g3;
			f1 = fi[0] - fi[k1];
			f0 = fi[0] + fi[k1];
			f3 = fi[k2] - fi[k3];
			f2 = fi[k2] + fi[k3];
			fi[k2] = f0 - f2;
			fi[0] = f0 + f2;
			fi[k3] = f1 - f3;
			fi[k1] = f1 + f3;
			g1 = gi[0] - gi[k1];
			g0 = gi[0] + gi[k1];
			g3 = SQRT2 * gi[k3];
			g2 = SQRT2 * gi[k2];
			gi[k2] = g0 - g2;
			gi[0] = g0 + g2;
			gi[k3] = g1 - g3;
			gi[k1] = g1 + g3;
			gi += k4;
			fi += k4;
		}
		while (fi < fn);
		
		t_c = costab[k];
		t_s = sintab[k];
		c1 = 1;
		s1 = 0;
		for (i = 1; i < kx; i++) {
			FLOAT c2, s2;
			FLOAT t = c1;
			c1 = t * t_c - s1 * t_s;
			s1 = t * t_s + s1 * t_c;
			c2 = c1 * c1 - s1 * s1;
			s2 = 2 * (c1 * s1);
			fn = fz + 1024;
			fi = fz + i;
			gi = fz + k1 - i;
			do {
				FLOAT a, b, g0, f0, f1, g1, f2, g2, f3, g3;
				b = s2 * fi[k1] - c2 * gi[k1];
				a = c2 * fi[k1] + s2 * gi[k1];
				f1 = fi[0] - a;
				f0 = fi[0] + a;
				g1 = gi[0] - b;
				g0 = gi[0] + b;
				b = s2 * fi[k3] - c2 * gi[k3];
				a = c2 * fi[k3] + s2 * gi[k3];
				f3 = fi[k2] - a;
				f2 = fi[k2] + a;
				g3 = gi[k2] - b;
				g2 = gi[k2] + b;
				b = s1 * f2 - c1 * g3;
				a = c1 * f2 + s1 * g3;
				fi[k2] = f0 - a;
				fi[0] = f0 + a;
				gi[k3] = g1 - b;
				gi[k1] = g1 + b;
				b = c1 * g2 - s1 * f3;
				a = s1 * g2 + c1 * f3;
				gi[k2] = g0 - a;
				gi[0] = g0 + a;
				fi[k3] = f1 - b;
				fi[k1] = f1 + b;
				gi += k4;
				fi += k4;
			}
			while (fi < fn);
		}
		}
		while (k4 < 1024);
}

#ifdef NEWATAN
#define ATANSIZE 6000
#define ATANSCALE 100.0
/* Create a table of ATAN2 values.
   Valid for ratios of (y/x) from 0 to ATANSIZE/ATANSCALE (60) 
   Largest absolute error in angle: 0.0167 radians i.e. ATANSCALE/ATANSIZE 
   Depending on how you want to trade off speed/accuracy and mem usage, twiddle the defines
   MFC March 2003 */
static FLOAT atan_t[ATANSIZE];

static inline FLOAT atan_table(FLOAT y, FLOAT x) {
	int index;
	
	index = (int)(ATANSCALE * fabs(y/x));
	if (index>=ATANSIZE) index = ATANSIZE-1;
	
	/* Have to work out the correct quadrant as well */
	if (y>0 && x<0)
		return( PI - atan_t[index] );
	
	if (y<0 && x>0)
		return( -atan_t[index] );
	
	if (y<0 && x<0)
		return( atan_t[index] - PI );
	
	return(atan_t[index]);
}

static void atan_table_init(void) {
	int i;
	for (i=0;i<ATANSIZE;i++)
		atan_t[i] = atan((FLOAT)i/ATANSCALE);
}

#endif //NEWATAN

/* For variations on psycho model 2:
   N always equals 1024
   BUT in the returned values, no energy/phi is used at or above an index of 513 */
void psycho_2_fft (FLOAT * x_real, FLOAT * energy, FLOAT * phi) 
/* got rid of size "N" argument as it is always 1024 for layerII */
{
	FLOAT imag, real;
	int i, j;
#ifdef NEWATAN
  static int init=0;

	if (!init) {
		atan_table_init();
		init++;
	}
#endif


	fht (x_real);


	energy[0] = x_real[0] * x_real[0];

	for (i = 1, j = 1023; i < 512; i++, j--) {
		imag = x_real[i];
		real = x_real[j];
		/* MFC FIXME Mar03 Why is this divided by 2.0?
		if a and b are the real and imaginary components then
		r = sqrt(a^2 + b^2),
		but, back in the psycho2 model, they calculate r=sqrt(energy), 
		which, if you look at the original equation below is different */
		energy[i] = (imag * imag + real * real) / 2.0;
		if (energy[i] < 0.0005) {
			energy[i] = 0.0005;
			phi[i] = 0;
		} else	
#ifdef NEWATAN
		{		
			phi[i] = atan_table(-imag, real) + PI/4;	
		}
#else
		{
			phi[i] = atan2(-(FLOAT)imag, (FLOAT)real) + PI/4;
		}
#endif
	}
	energy[512] = x_real[512] * x_real[512];
	phi[512] = atan2 (0.0, (FLOAT) x_real[512]);
}


void psycho_1_fft (FLOAT * x_real, FLOAT * energy, int N)
{
	FLOAT a, b;
	int i, j;
	
	fht (x_real);
	
	energy[0] = x_real[0] * x_real[0];
	
	for (i = 1, j = N - 1; i < N / 2; i++, j--) {
		a = x_real[i];
		b = x_real[j];
		energy[i] = (a * a + b * b) / 2.0;
	}
	energy[N / 2] = x_real[N / 2] * x_real[N / 2];
}


// vim:ts=4:sw=4:nowrap: