Part of Slepp's ProjectsPastebinTURLImagebinFilebin
Feedback -- English French German Japanese
Create Upload Newest Tools Donate
Sign In | Create Account

Something
Tuesday, April 7th, 2009 at 9:58:33pm UTC 

  1. diff --git a/apps/plugin.c b/apps/plugin.c
  2. index 17e9ac6..68d7c43 100644
  3. --- a/apps/plugin.c
  4. +++ b/apps/plugin.c
  5. @@ -427,6 +427,7 @@ static const struct plugin_api rockbox_api = {
  6.     pcm_play_pause,
  7.     pcm_get_bytes_waiting,
  8.     pcm_calculate_peaks,
  9. +    pcm_get_peak_buffer,
  10.     pcm_play_lock,
  11.     pcm_play_unlock,
  12. #ifdef HAVE_RECORDING
  13. diff --git a/apps/plugin.h b/apps/plugin.h
  14. index fdcf3c2..52d513c 100644
  15. --- a/apps/plugin.h
  16. +++ b/apps/plugin.h
  17. @@ -549,6 +549,7 @@ struct plugin_api {
  18.     void (*pcm_play_pause)(bool play);
  19.     size_t (*pcm_get_bytes_waiting)(void);
  20.     void (*pcm_calculate_peaks)(int *left, int *right);
  21. +    const void* (*pcm_get_peak_buffer)(int *count);
  22.     void (*pcm_play_lock)(void);
  23.     void (*pcm_play_unlock)(void);
  24. #ifdef HAVE_RECORDING
  25. diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES
  26. index d6753ac..8e69099 100644
  27. --- a/apps/plugins/CATEGORIES
  28. +++ b/apps/plugins/CATEGORIES
  29. @@ -20,6 +20,7 @@ dict,apps
  30. disktidy,apps
  31. doom,games
  32. euroconverter,apps
  33. +fft,demos
  34. fire,demos
  35. fireworks,demos
  36. firmware_flash,apps
  37. diff --git a/apps/plugins/SUBDIRS b/apps/plugins/SUBDIRS
  38. index af5e1d0..6317683 100644
  39. --- a/apps/plugins/SUBDIRS
  40. +++ b/apps/plugins/SUBDIRS
  41. @@ -16,6 +16,9 @@ rockboy
  42. /* For all targets with a bitmap display */
  43. #ifdef HAVE_LCD_BITMAP
  44. +#if CONFIG_CODEC == SWCODEC
  45. +fft
  46. +#endif
  47. chessbox
  48. jpeg
  49. sudoku
  50. diff --git a/apps/plugins/fft/SOURCES b/apps/plugins/fft/SOURCES
  51. new file mode 100644
  52. index 0000000..bc5660d
  53. --- /dev/null
  54. +++ b/apps/plugins/fft/SOURCES
  55. @@ -0,0 +1,3 @@
  56. +kiss_fft.c
  57. +fft.c
  58. +math.c
  59. diff --git a/apps/plugins/fft/_kiss_fft_guts.h b/apps/plugins/fft/_kiss_fft_guts.h
  60. new file mode 100644
  61. index 0000000..0bd5138
  62. --- /dev/null
  63. +++ b/apps/plugins/fft/_kiss_fft_guts.h
  64. @@ -0,0 +1,145 @@
  65. +/*
  66. +Copyright (c) 2003-2004, Mark Borgerding
  67. +
  68. +All rights reserved.
  69. +
  70. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
  71. +
  72. +    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  73. +    * 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.
  74. +    * 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.
  75. +
  76. +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.
  77. +*/
  78. +
  79. +/* kiss_fft.h
  80. +   defines kiss_fft_scalar as either short or a float type
  81. +   and defines
  82. +   typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */
  83. +#include "kiss_fft.h"
  84. +#include "math.h"
  85. +#include <limits.h>
  86. +
  87. +#define MAXFACTORS 32
  88. +/* e.g. an fft of length 128 has 4 factors
  89. + as far as kissfft is concerned
  90. + 4*4*4*2
  91. + */
  92. +
  93. +struct kiss_fft_state{
  94. +    int nfft;
  95. +    int inverse;
  96. +    int factors[2*MAXFACTORS];
  97. +    kiss_fft_cpx twiddles[1];
  98. +};
  99. +
  100. +/*
  101. +  Explanation of macros dealing with complex math:
  102. +
  103. +   C_MUL(m,a,b)         : m = a*b
  104. +   C_FIXDIV( c , div )  : if a fixed point impl., c /= div. noop otherwise
  105. +   C_SUB( res, a,b)     : res = a - b
  106. +   C_SUBFROM( res , a)  : res -= a
  107. +   C_ADDTO( res , a)    : res += a
  108. + * */
  109. +#ifdef FIXED_POINT
  110. +#if (FIXED_POINT==32)
  111. +# define FRACBITS 31
  112. +# define SAMPPROD int64_t
  113. +#define SAMP_MAX 2147483647
  114. +#else
  115. +# define FRACBITS 15
  116. +# define SAMPPROD int32_t
  117. +#define SAMP_MAX 32767
  118. +#endif
  119. +
  120. +#define SAMP_MIN -SAMP_MAX
  121. +
  122. +#if defined(CHECK_OVERFLOW)
  123. +#  define CHECK_OVERFLOW_OP(a,op,b)  \
  124. +        if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \
  125. +                fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) );  }
  126. +#endif
  127. +
  128. +
  129. +#   define smul(a,b) ( (SAMPPROD)(a)*(b) )
  130. +#   define sround( x )  (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS )
  131. +
  132. +#   define S_MUL(a,b) sround( smul(a,b) )
  133. +
  134. +#   define C_MUL(m,a,b) \
  135. +      do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \
  136. +          (m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0)
  137. +
  138. +#   define DIVSCALAR(x,k) \
  139. +        (x) = sround( smul(  x, SAMP_MAX/k ) )
  140. +
  141. +#   define C_FIXDIV(c,div) \
  142. +        do {    DIVSCALAR( (c).r , div);  \
  143. +                DIVSCALAR( (c).i  , div); }while (0)
  144. +
  145. +#   define C_MULBYSCALAR( c, s ) \
  146. +    do{ (c).r =  sround( smul( (c).r , s ) ) ;\
  147. +        (c).i =  sround( smul( (c).i , s ) ) ; }while(0)
  148. +
  149. +#else  /* not FIXED_POINT*/
  150. +
  151. +#   define S_MUL(a,b) ( (a)*(b) )
  152. +#define C_MUL(m,a,b) \
  153. +    do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
  154. +        (m).i = (a).r*(b).i + (a).i*(b).r; }while(0)
  155. +#   define C_FIXDIV(c,div) /* NOOP */
  156. +#   define C_MULBYSCALAR( c, s ) \
  157. +    do{ (c).r *= (s);\
  158. +        (c).i *= (s); }while(0)
  159. +#endif
  160. +
  161. +#ifndef CHECK_OVERFLOW_OP
  162. +#  define CHECK_OVERFLOW_OP(a,op,b) /* noop */
  163. +#endif
  164. +
  165. +#define  C_ADD( res, a,b)\
  166. +    do { \
  167. +           CHECK_OVERFLOW_OP((a).r,+,(b).r)\
  168. +           CHECK_OVERFLOW_OP((a).i,+,(b).i)\
  169. +           (res).r=(a).r+(b).r;  (res).i=(a).i+(b).i; \
  170. +    }while(0)
  171. +#define  C_SUB( res, a,b)\
  172. +    do { \
  173. +           CHECK_OVERFLOW_OP((a).r,-,(b).r)\
  174. +           CHECK_OVERFLOW_OP((a).i,-,(b).i)\
  175. +           (res).r=(a).r-(b).r;  (res).i=(a).i-(b).i; \
  176. +    }while(0)
  177. +#define C_ADDTO( res , a)\
  178. +    do { \
  179. +           CHECK_OVERFLOW_OP((res).r,+,(a).r)\
  180. +           CHECK_OVERFLOW_OP((res).i,+,(a).i)\
  181. +           (res).r += (a).r;  (res).i += (a).i;\
  182. +    }while(0)
  183. +
  184. +#define C_SUBFROM( res , a)\
  185. +    do {\
  186. +           CHECK_OVERFLOW_OP((res).r,-,(a).r)\
  187. +           CHECK_OVERFLOW_OP((res).i,-,(a).i)\
  188. +           (res).r -= (a).r;  (res).i -= (a).i; \
  189. +    }while(0)
  190. +
  191. +
  192. +#ifdef FIXED_POINT
  193. +#  define HALF_OF(x) ((x)>>1)
  194. +#else
  195. +#  define HALF_OF(x) ((x)*.5)
  196. +#endif
  197. +
  198. +#define  kf_cexp(x, k, n) \
  199. +        do{ \
  200. +                int32_t div = Q_DIV( (k) << 16, (n) << 16, 16 ); \
  201. +                long cos, sin = fsincos(div << 16, &cos); \
  202. +                (x)->r = ( Q_MUL(SAMP_MAX << 16, cos >> 15, 16) ) >> 16; \
  203. +                (x)->i = ( Q_MUL(SAMP_MAX << 16, -1*(sin >> 15), 16) ) >> 16; \
  204. +        }while(0)
  205. +
  206. +
  207. +/* a debugging function */
  208. +#define pcpx(c)\
  209. +    fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) )
  210. diff --git a/apps/plugins/fft/fft.c b/apps/plugins/fft/fft.c
  211. new file mode 100644
  212. index 0000000..5b4302d
  213. --- /dev/null
  214. +++ b/apps/plugins/fft/fft.c
  215. @@ -0,0 +1,1204 @@
  216. +/***************************************************************************
  217. +*             __________               __   ___.
  218. + *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
  219. + *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
  220. + *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
  221. + *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
  222. + *                     \/            \/     \/    \/            \/
  223. + * $Id$
  224. + *
  225. + * Copyright (C) 2009 Delyan Kratunov
  226. + *
  227. + * This program is free software; you can redistribute it and/or
  228. + * modify it under the terms of the GNU General Public License
  229. + * as published by the Free Software Foundation; either version 2
  230. + * of the License, or (at your option) any later version.
  231. + *
  232. + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  233. + * KIND, either express or implied.
  234. + *
  235. + ****************************************************************************/
  236. +#include "plugin.h"
  237. +
  238. +#include "lib/helper.h"
  239. +#include "lib/xlcd.h"
  240. +#include "math.h"
  241. +
  242. +PLUGIN_HEADER
  243. +
  244. +#if CONFIG_KEYPAD == ARCHOS_AV300_PAD
  245. +#   define FFT_PREV_GRAPH     BUTTON_LEFT
  246. +#   define FFT_NEXT_GRAPH    BUTTON_RIGHT
  247. +#   define FFT_ORIENTATION  BUTTON_F3
  248. +#   define FFT_WINDOW     BUTTON_F1
  249. +#   define FFT_SCALE       BUTTON_UP
  250. +#   define FFT_COLOR     BUTTON_DOWN
  251. +#   define FFT_QUIT     BUTTON_OFF
  252. +
  253. +#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
  254. +      (CONFIG_KEYPAD == IRIVER_H300_PAD)
  255. +#   define FFT_PREV_GRAPH     BUTTON_LEFT
  256. +#   define FFT_NEXT_GRAPH    BUTTON_RIGHT
  257. +#   define FFT_ORIENTATION  BUTTON_REC
  258. +#   define FFT_WINDOW     BUTTON_SELECT
  259. +#   define FFT_SCALE       BUTTON_UP
  260. +#   define FFT_COLOR     BUTTON_DOWN
  261. +#   define FFT_QUIT     BUTTON_OFF
  262. +
  263. +#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
  264. +      (CONFIG_KEYPAD == IPOD_3G_PAD) || \
  265. +      (CONFIG_KEYPAD == IPOD_1G2G_PAD)
  266. +#   define MINESWP_SCROLLWHEEL
  267. +#   define FFT_PREV_GRAPH       BUTTON_LEFT
  268. +#   define FFT_NEXT_GRAPH      BUTTON_RIGHT
  269. +#   define FFT_ORIENTATION  (BUTTON_SELECT | BUTTON_LEFT)
  270. +#   define FFT_WINDOW     (BUTTON_SELECT | BUTTON_RIGHT)
  271. +#   define FFT_SCALE         BUTTON_MENU
  272. +#   define FFT_COLOR       BUTTON_PLAY
  273. +#   define FFT_QUIT       (BUTTON_SELECT | BUTTON_MENU)
  274. +
  275. +#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
  276. +#   define FFT_PREV_GRAPH     BUTTON_LEFT
  277. +#   define FFT_NEXT_GRAPH    BUTTON_RIGHT
  278. +#   define FFT_ORIENTATION  BUTTON_SELECT
  279. +#   define FFT_WINDOW     BUTTON_PLAY
  280. +#   define FFT_SCALE       BUTTON_UP
  281. +#   define FFT_COLOR     BUTTON_DOWN
  282. +#   define FFT_QUIT     BUTTON_POWER
  283. +
  284. +#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
  285. +#   define FFT_PREV_GRAPH     BUTTON_LEFT
  286. +#   define FFT_NEXT_GRAPH    BUTTON_RIGHT
  287. +#   define FFT_SCALE       BUTTON_UP
  288. +#   define FFT_ORIENTATION  BUTTON_SELECT
  289. +#   define FFT_WINDOW        BUTTON_A
  290. +#   define FFT_COLOR     BUTTON_DOWN
  291. +#   define FFT_QUIT     BUTTON_POWER
  292. +
  293. +#elif (CONFIG_KEYPAD == SANSA_E200_PAD)
  294. +#   define FFT_PREV_GRAPH     BUTTON_LEFT
  295. +#   define FFT_NEXT_GRAPH    BUTTON_RIGHT
  296. +#   define FFT_ORIENTATION  BUTTON_SELECT
  297. +#   define FFT_WINDOW        BUTTON_REC
  298. +#   define FFT_SCALE       BUTTON_UP
  299. +#   define FFT_COLOR     BUTTON_DOWN
  300. +#   define FFT_QUIT     BUTTON_POWER
  301. +
  302. +#elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
  303. +#   define FFT_PREV_GRAPH     BUTTON_LEFT
  304. +#   define FFT_NEXT_GRAPH    BUTTON_RIGHT
  305. +#   define FFT_ORIENTATION  (BUTTON_SELECT | BUTTON_LEFT)
  306. +#   define FFT_WINDOW     (BUTTON_SELECT | BUTTON_RIGHT)
  307. +#   define FFT_SCALE       BUTTON_UP
  308. +#   define FFT_COLOR     BUTTON_DOWN
  309. +#   define FFT_QUIT     BUTTON_POWER
  310. +
  311. +#elif (CONFIG_KEYPAD == SANSA_C200_PAD) || \
  312. +(CONFIG_KEYPAD == SANSA_M200_PAD)
  313. +#   define FFT_PREV_GRAPH       BUTTON_LEFT
  314. +#   define FFT_NEXT_GRAPH      BUTTON_RIGHT
  315. +#   define FFT_ORIENTATION  BUTTON_UP
  316. +#   define FFT_WINDOW        BUTTON_REC
  317. +#   define FFT_SCALE         BUTTON_SELECT
  318. +#   define FFT_COLOR       BUTTON_DOWN
  319. +#   define FFT_QUIT       BUTTON_POWER
  320. +#elif (CONFIG_KEYPAD == SANSA_CLIP_PAD)
  321. +#   define FFT_PREV_GRAPH       BUTTON_LEFT
  322. +#   define FFT_NEXT_GRAPH      BUTTON_RIGHT
  323. +#   define FFT_ORIENTATION  BUTTON_UP
  324. +#   define FFT_WINDOW        BUTTON_HOME
  325. +#   define FFT_SCALE         BUTTON_SELECT
  326. +#   define FFT_COLOR       BUTTON_DOWN
  327. +#   define FFT_QUIT       BUTTON_POWER
  328. +
  329. +#elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
  330. +#   define FFT_PREV_GRAPH       BUTTON_LEFT
  331. +#   define FFT_NEXT_GRAPH       BUTTON_RIGHT
  332. +#   define FFT_ORIENTATION      BUTTON_FF
  333. +#   define FFT_WINDOW       BUTTON_SCROLL_UP
  334. +#   define FFT_SCALE            BUTTON_REW
  335. +#   define FFT_COLOR            BUTTON_PLAY
  336. +#   define FFT_QUIT             BUTTON_POWER
  337. +
  338. +#elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
  339. +#   define FFT_PREV_GRAPH       BUTTON_LEFT
  340. +#   define FFT_NEXT_GRAPH       BUTTON_RIGHT
  341. +#   define FFT_ORIENTATION      BUTTON_MENU
  342. +#   define FFT_WINDOW     BUTTON_PREV
  343. +#   define FFT_SCALE            BUTTON_UP
  344. +#   define FFT_COLOR            BUTTON_DOWN
  345. +#   define FFT_QUIT             BUTTON_BACK
  346. +
  347. +#elif (CONFIG_KEYPAD == MROBE100_PAD)
  348. +#   define FFT_PREV_GRAPH       BUTTON_LEFT
  349. +#   define FFT_NEXT_GRAPH       BUTTON_RIGHT
  350. +#   define FFT_ORIENTATION      BUTTON_PLAY
  351. +#   define FFT_WINDOW     BUTTON_SELECT
  352. +#   define FFT_SCALE            BUTTON_UP
  353. +#   define FFT_COLOR            BUTTON_DOWN
  354. +#   define FFT_QUIT             BUTTON_POWER
  355. +
  356. +#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
  357. +#   define FFT_PREV_GRAPH       BUTTON_RC_REW
  358. +#   define FFT_NEXT_GRAPH       BUTTON_RC_FF
  359. +#   define FFT_ORIENTATION      BUTTON_RC_MODE
  360. +#   define FFT_WINDOW        BUTTON_RC_PLAY
  361. +#   define FFT_SCALE            BUTTON_RC_VOL_UP
  362. +#   define FFT_COLOR            BUTTON_RC_VOL_DOWN
  363. +#   define FFT_QUIT             BUTTON_RC_REC
  364. +
  365. +#elif (CONFIG_KEYPAD == COWOND2_PAD)
  366. +#   define FFT_QUIT             BUTTON_POWER
  367. +#   define FFT_PREV_GRAPH       BUTTON_PLUS
  368. +#   define FFT_NEXT_GRAPH       BUTTON_MINUS
  369. +
  370. +#elif CONFIG_KEYPAD == CREATIVEZVM_PAD
  371. +#   define FFT_PREV_GRAPH       BUTTON_LEFT
  372. +#   define FFT_NEXT_GRAPH       BUTTON_RIGHT
  373. +#   define FFT_ORIENTATION      BUTTON_MENU
  374. +#   define FFT_WINDOW     BUTTON_SELECT
  375. +#   define FFT_SCALE            BUTTON_UP
  376. +#   define FFT_COLOR            BUTTON_DOWN
  377. +#   define FFT_QUIT             BUTTON_BACK
  378. +
  379. +#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
  380. +#   define FFT_PREV_GRAPH       BUTTON_LEFT
  381. +#   define FFT_NEXT_GRAPH       BUTTON_RIGHT
  382. +#   define FFT_ORIENTATION      BUTTON_SELECT
  383. +#   define FFT_WINDOW     BUTTON_MENU
  384. +#   define FFT_SCALE            BUTTON_UP
  385. +#   define FFT_COLOR            BUTTON_DOWN
  386. +#   define FFT_QUIT             BUTTON_POWER
  387. +
  388. +#else
  389. +#error No keymap defined!
  390. +#endif
  391. +
  392. +#define FFT_SIZE (1024)
  393. +
  394. +#include "kiss_fft.h"
  395. +#include "_kiss_fft_guts.h" /* sizeof(struct kiss_fft_state) */
  396. +
  397. +#define ARRAYSIZE_IN FFT_SIZE
  398. +#define ARRAYSIZE_OUT FFT_SIZE
  399. +#define ARRAYSIZE_PLOT FFT_SIZE/2
  400. +#define BUFSIZE (sizeof(struct kiss_fft_state)+sizeof(kiss_fft_cpx)*(FFT_SIZE-1))
  401. +#define FFT_ALLOC kiss_fft_alloc
  402. +#define FFT_FFT   kiss_fft
  403. +#define FFT_CFG   kiss_fft_cfg
  404. +
  405. +static kiss_fft_cpx input[ARRAYSIZE_IN];
  406. +static kiss_fft_cpx output[ARRAYSIZE_OUT];
  407. +static int32_t plot[ARRAYSIZE_PLOT];
  408. +static char buffer[BUFSIZE];
  409. +
  410. +/************************* Math functions *************************/
  411. +#define QLOG_MAX (4 << 16)
  412. +#define LIN_MAX 1034
  413. +#define QLIN_MAX 67795525
  414. +
  415. +/* Returns logarithmically scaled values in S15.16 format */
  416. +int32_t get_log_value(int32_t value, bool fraction)
  417. +{
  418. +    int32_t result;
  419. +
  420. +    if(fraction)
  421. +        value = Q16_MUL(30720 << 16, Q16_DIV(value, QLIN_MAX)) >> 16;
  422. +    else
  423. +        value = Q16_MUL(30720 << 16, Q16_DIV(value << 16, QLIN_MAX)) >> 16;
  424. +
  425. +    result = ilog2(value+2048); /* only positive values */
  426. +    result = Q16_DIV(result << 16, 2048 << 16);
  427. +    return result;
  428. +}
  429. +
  430. +/* Apply window function to input
  431. + * 0 - Hamming window
  432. + * 1 - Hann window */
  433. +#define WINDOW_COUNT 2
  434. +void apply_window_func(char mode)
  435. +{
  436. +    switch(mode)
  437. +    {
  438. +        case 0: /* Hamming window */
  439. +        {
  440. +            const int32_t hamming_a = float_q(0.53836, 15), hamming_b =
  441. +                    float_q(0.46164, 15);
  442. +            size_t i;
  443. +            for (i = 0; i < ARRAYSIZE_IN; ++i)
  444. +            {
  445. +                int32_t cos;
  446. +                (void) fsincos(Q16_DIV(i << 16, (ARRAYSIZE_IN - 1) << 16) << 16,
  447. +                               &cos);
  448. +                cos >>= 16;
  449. +
  450. +                /* value = value * (hamming_a - hamming_b * cos( 2 * pi * i/(ArraySize - 1) ) ) */
  451. +                input[i].r = Q15_MUL(input[i].r << 15,
  452. +                                   (hamming_a - Q15_MUL(cos, hamming_b))) >> 15;
  453. +                input[i].i = Q15_MUL(input[i].i << 15,
  454. +                                   (hamming_a - Q15_MUL(cos, hamming_b))) >> 15;
  455. +            }
  456. +            break;
  457. +        }
  458. +        case 1: /* Hann window */
  459. +        {
  460. +            size_t i;
  461. +            for (i = 0; i < ARRAYSIZE_IN; ++i)
  462. +            {
  463. +                int32_t factor;
  464. +                (void) fsincos(Q16_DIV(i << 16, (ARRAYSIZE_IN - 1) << 16) << 16,
  465. +                               &factor);
  466. +                /* s16.15; cos( 2* pi * i/(ArraySize - 1))*/
  467. +                factor >>= 16;
  468. +                /* 0.5 * cos( 2* pi * i/(ArraySize - 1))*/
  469. +                factor = Q15_MUL( (1 << 14), factor);
  470. +                /* 0.5 - 0.5 * cos( 2* pi * i/(ArraySize - 1)))*/
  471. +                factor = (1 << 14) - factor;
  472. +
  473. +                input[i].r = Q15_MUL(input[i].r << 15, factor) >> 15;
  474. +                input[i].i = Q15_MUL(input[i].i << 15, factor) >> 15;
  475. +            }
  476. +            break;
  477. +        }
  478. +    }
  479. +}
  480. +
  481. +/* Calculates the magnitudes from complex numbers and returns the maximum */
  482. +int32_t calc_magnitudes(bool logarithmic)
  483. +{
  484. +    int64_t tmp;
  485. +    size_t i;
  486. +
  487. +    int32_t max = -2147483647;
  488. +
  489. +    for (i = 0; i < ARRAYSIZE_PLOT; ++i)
  490. +    {
  491. +        tmp = Q16_MUL( ((int32_t) output[i].r) << 16,
  492. +                     ((int32_t) output[i].r) << 16);
  493. +        tmp += Q16_MUL( ((int32_t) output[i].i) << 16,
  494. +                      ((int32_t) output[i].i) << 16);
  495. +
  496. +        tmp = fsqrt(tmp & 0x7FFFFFFF , 16);
  497. +
  498. +        if (logarithmic)
  499. +        {
  500. +            tmp = get_log_value(tmp, true);
  501. +            plot[i] = tmp;
  502. +        }
  503. +        else
  504. +            plot[i] = tmp >> 16;
  505. +
  506. +        if (plot[i] > max)
  507. +            max = plot[i];
  508. +    }
  509. +    return max;
  510. +}
  511. +/************************ End of math functions ***********************/
  512. +
  513. +/********************* Plotting functions (modes) *********************/
  514. +
  515. +const unsigned char* modes_text[] = { "Lines", "Bars", "Spectrogram" };
  516. +const unsigned char* scales_text[] = { "Linear scale", "Logarithmic scale" };
  517. +const unsigned char* window_text[] = { "Hamming window", "Hann window" };
  518. +#ifdef HAVE_LCD_COLOR
  519. +#   define MODES_COUNT 3
  520. +#else
  521. +#   define MODES_COUNT 2
  522. +#endif
  523. +#define REFRESH_RATE 10
  524. +
  525. +struct {
  526. +    bool logarithmic;
  527. +    bool orientation_vertical;
  528. +    int window_func;
  529. +#ifdef HAVE_LCD_COLOR
  530. +    bool colored;
  531. +#endif
  532. +} graph_settings;
  533. +struct {
  534. +    int column;
  535. +    int row;
  536. +} spectrogram_settings;
  537. +
  538. +#ifdef HAVE_LCD_COLOR
  539. +#define COLORS 256
  540. +static unsigned int colors[COLORS] = { LCD_RGBPACK(0, 0, 23), LCD_RGBPACK(0, 0, 26),
  541. +        LCD_RGBPACK(0, 0, 28), LCD_RGBPACK(0, 0, 31), LCD_RGBPACK(0, 0, 33),
  542. +        LCD_RGBPACK(0, 0, 36), LCD_RGBPACK(0, 0, 38), LCD_RGBPACK(0, 0, 41),
  543. +        LCD_RGBPACK(0, 0, 43), LCD_RGBPACK(0, 0, 46), LCD_RGBPACK(0, 0, 48),
  544. +        LCD_RGBPACK(0, 0, 50), LCD_RGBPACK(0, 0, 53), LCD_RGBPACK(0, 0, 55),
  545. +        LCD_RGBPACK(0, 0, 58), LCD_RGBPACK(0, 0, 59), LCD_RGBPACK(0, 0, 62),
  546. +        LCD_RGBPACK(0, 0, 64), LCD_RGBPACK(0, 0, 66), LCD_RGBPACK(0, 0, 69),
  547. +        LCD_RGBPACK(0, 0, 71), LCD_RGBPACK(0, 0, 73), LCD_RGBPACK(0, 0, 75),
  548. +        LCD_RGBPACK(0, 0, 77), LCD_RGBPACK(0, 0, 79), LCD_RGBPACK(1, 0, 81),
  549. +        LCD_RGBPACK(4, 0, 83), LCD_RGBPACK(7, 0, 85), LCD_RGBPACK(9, 0, 87),
  550. +        LCD_RGBPACK(9, 0, 87), LCD_RGBPACK(12, 0, 89), LCD_RGBPACK(15, 0, 91),
  551. +        LCD_RGBPACK(16, 0, 92), LCD_RGBPACK(19, 0, 94), LCD_RGBPACK(22, 0, 96),
  552. +        LCD_RGBPACK(24, 0, 97), LCD_RGBPACK(27, 0, 99),
  553. +        LCD_RGBPACK(30, 0, 101), LCD_RGBPACK(32, 0, 102),
  554. +        LCD_RGBPACK(35, 0, 104), LCD_RGBPACK(38, 0, 105),
  555. +        LCD_RGBPACK(40, 0, 107), LCD_RGBPACK(43, 0, 108),
  556. +        LCD_RGBPACK(45, 0, 109), LCD_RGBPACK(47, 0, 111),
  557. +        LCD_RGBPACK(50, 0, 112), LCD_RGBPACK(53, 0, 113),
  558. +        LCD_RGBPACK(55, 0, 114), LCD_RGBPACK(58, 0, 115),
  559. +        LCD_RGBPACK(60, 0, 116), LCD_RGBPACK(63, 0, 118),
  560. +        LCD_RGBPACK(65, 0, 119), LCD_RGBPACK(68, 0, 120),
  561. +        LCD_RGBPACK(70, 0, 120), LCD_RGBPACK(72, 0, 121),
  562. +        LCD_RGBPACK(75, 0, 122), LCD_RGBPACK(78, 0, 123),
  563. +        LCD_RGBPACK(80, 0, 123), LCD_RGBPACK(83, 0, 124),
  564. +        LCD_RGBPACK(85, 0, 125), LCD_RGBPACK(88, 0, 125),
  565. +        LCD_RGBPACK(90, 0, 126), LCD_RGBPACK(93, 0, 125),
  566. +        LCD_RGBPACK(95, 0, 126), LCD_RGBPACK(97, 0, 126),
  567. +        LCD_RGBPACK(99, 0, 127), LCD_RGBPACK(101, 0, 127),
  568. +        LCD_RGBPACK(101, 0, 127), LCD_RGBPACK(104, 0, 127),
  569. +        LCD_RGBPACK(106, 0, 126), LCD_RGBPACK(109, 0, 127),
  570. +        LCD_RGBPACK(111, 0, 127), LCD_RGBPACK(114, 0, 126),
  571. +        LCD_RGBPACK(116, 0, 127), LCD_RGBPACK(118, 0, 127),
  572. +        LCD_RGBPACK(120, 0, 127), LCD_RGBPACK(123, 0, 126),
  573. +        LCD_RGBPACK(125, 0, 125), LCD_RGBPACK(127, 0, 126),
  574. +        LCD_RGBPACK(130, 0, 125), LCD_RGBPACK(131, 0, 124),
  575. +        LCD_RGBPACK(134, 0, 124), LCD_RGBPACK(136, 0, 123),
  576. +        LCD_RGBPACK(138, 0, 122), LCD_RGBPACK(140, 0, 122),
  577. +        LCD_RGBPACK(142, 0, 121), LCD_RGBPACK(144, 0, 120),
  578. +        LCD_RGBPACK(147, 0, 119), LCD_RGBPACK(149, 0, 119),
  579. +        LCD_RGBPACK(151, 0, 118), LCD_RGBPACK(153, 0, 117),
  580. +        LCD_RGBPACK(155, 0, 115), LCD_RGBPACK(157, 0, 114),
  581. +        LCD_RGBPACK(159, 0, 113), LCD_RGBPACK(162, 0, 112),
  582. +        LCD_RGBPACK(164, 0, 111), LCD_RGBPACK(165, 0, 110),
  583. +        LCD_RGBPACK(167, 0, 109), LCD_RGBPACK(169, 0, 108),
  584. +        LCD_RGBPACK(171, 0, 106), LCD_RGBPACK(173, 0, 105),
  585. +        LCD_RGBPACK(175, 0, 103), LCD_RGBPACK(176, 0, 102),
  586. +        LCD_RGBPACK(178, 0, 100), LCD_RGBPACK(178, 0, 100),
  587. +        LCD_RGBPACK(180, 0, 98), LCD_RGBPACK(182, 0, 97),
  588. +        LCD_RGBPACK(184, 0, 95), LCD_RGBPACK(186, 0, 93),
  589. +        LCD_RGBPACK(188, 0, 91), LCD_RGBPACK(189, 0, 89),
  590. +        LCD_RGBPACK(190, 0, 87), LCD_RGBPACK(192, 0, 86),
  591. +        LCD_RGBPACK(194, 0, 84), LCD_RGBPACK(196, 0, 82),
  592. +        LCD_RGBPACK(197, 0, 80), LCD_RGBPACK(199, 0, 78),
  593. +        LCD_RGBPACK(201, 0, 76), LCD_RGBPACK(202, 0, 74),
  594. +        LCD_RGBPACK(204, 0, 72), LCD_RGBPACK(206, 0, 70),
  595. +        LCD_RGBPACK(207, 0, 67), LCD_RGBPACK(209, 0, 65),
  596. +        LCD_RGBPACK(210, 0, 63), LCD_RGBPACK(212, 0, 60),
  597. +        LCD_RGBPACK(213, 0, 58), LCD_RGBPACK(215, 0, 56),
  598. +        LCD_RGBPACK(216, 0, 53), LCD_RGBPACK(216, 0, 52),
  599. +        LCD_RGBPACK(218, 0, 49), LCD_RGBPACK(219, 0, 47),
  600. +        LCD_RGBPACK(221, 0, 44), LCD_RGBPACK(222, 0, 42),
  601. +        LCD_RGBPACK(223, 0, 39), LCD_RGBPACK(224, 0, 37),
  602. +        LCD_RGBPACK(226, 0, 34), LCD_RGBPACK(227, 0, 32),
  603. +        LCD_RGBPACK(228, 0, 29), LCD_RGBPACK(229, 0, 27),
  604. +        LCD_RGBPACK(230, 0, 25), LCD_RGBPACK(231, 0, 22),
  605. +        LCD_RGBPACK(232, 0, 19), LCD_RGBPACK(232, 0, 19),
  606. +        LCD_RGBPACK(233, 0, 17), LCD_RGBPACK(235, 0, 14),
  607. +        LCD_RGBPACK(236, 0, 12), LCD_RGBPACK(237, 0, 9),
  608. +        LCD_RGBPACK(238, 0, 6), LCD_RGBPACK(239, 0, 4), LCD_RGBPACK(239, 0, 1),
  609. +        LCD_RGBPACK(240, 1, 0), LCD_RGBPACK(241, 6, 0),
  610. +        LCD_RGBPACK(242, 11, 0), LCD_RGBPACK(243, 16, 0),
  611. +        LCD_RGBPACK(244, 21, 0), LCD_RGBPACK(244, 26, 0),
  612. +        LCD_RGBPACK(245, 31, 0), LCD_RGBPACK(246, 36, 0),
  613. +        LCD_RGBPACK(247, 41, 0), LCD_RGBPACK(247, 46, 0),
  614. +        LCD_RGBPACK(247, 50, 0), LCD_RGBPACK(248, 55, 0),
  615. +        LCD_RGBPACK(248, 60, 0), LCD_RGBPACK(249, 65, 0),
  616. +        LCD_RGBPACK(249, 70, 0), LCD_RGBPACK(250, 75, 0),
  617. +        LCD_RGBPACK(250, 79, 0), LCD_RGBPACK(251, 84, 0),
  618. +        LCD_RGBPACK(252, 89, 0), LCD_RGBPACK(251, 94, 0),
  619. +        LCD_RGBPACK(252, 99, 0), LCD_RGBPACK(253, 103, 0),
  620. +        LCD_RGBPACK(252, 108, 0),
  621. +        LCD_RGBPACK(253, 112, 0), LCD_RGBPACK(254, 117, 0),
  622. +        LCD_RGBPACK(254, 121, 0), LCD_RGBPACK(253, 125, 0),
  623. +        LCD_RGBPACK(254, 130, 0), LCD_RGBPACK(255, 134, 0),
  624. +        LCD_RGBPACK(255, 137, 0), LCD_RGBPACK(255, 138, 0),
  625. +        LCD_RGBPACK(255, 142, 0), LCD_RGBPACK(255, 147, 0),
  626. +        LCD_RGBPACK(255, 151, 0), LCD_RGBPACK(255, 154, 0),
  627. +        LCD_RGBPACK(255, 158, 0), LCD_RGBPACK(255, 162, 0),
  628. +        LCD_RGBPACK(255, 166, 0), LCD_RGBPACK(255, 170, 0),
  629. +        LCD_RGBPACK(255, 174, 0), LCD_RGBPACK(255, 178, 0),
  630. +        LCD_RGBPACK(255, 181, 0), LCD_RGBPACK(255, 184, 0),
  631. +        LCD_RGBPACK(255, 187, 0), LCD_RGBPACK(255, 191, 0),
  632. +        LCD_RGBPACK(255, 194, 0), LCD_RGBPACK(255, 197, 0),
  633. +        LCD_RGBPACK(255, 201, 0), LCD_RGBPACK(255, 204, 3),
  634. +        LCD_RGBPACK(255, 207, 8), LCD_RGBPACK(255, 210, 12),
  635. +        LCD_RGBPACK(255, 213, 17), LCD_RGBPACK(255, 215, 21),
  636. +        LCD_RGBPACK(255, 217, 26), LCD_RGBPACK(255, 220,30),
  637. +        LCD_RGBPACK(255, 223, 34), LCD_RGBPACK(255, 225, 39),
  638. +        LCD_RGBPACK(255, 228, 44),
  639. +        LCD_RGBPACK(255, 229, 48), LCD_RGBPACK(255, 231, 53),
  640. +        LCD_RGBPACK(255, 233, 57),
  641. +        LCD_RGBPACK(255, 235, 61), LCD_RGBPACK(255, 237, 66),
  642. +        LCD_RGBPACK(255, 239, 71),
  643. +        LCD_RGBPACK(255, 241, 75), LCD_RGBPACK(255, 243, 80),
  644. +        LCD_RGBPACK(255, 244, 84),
  645. +        LCD_RGBPACK(255, 246, 88), LCD_RGBPACK(255, 246, 88),
  646. +        LCD_RGBPACK(255, 247, 93),
  647. +        LCD_RGBPACK(255, 248, 97), LCD_RGBPACK(255, 249, 102),
  648. +        LCD_RGBPACK(255, 250, 107), LCD_RGBPACK(255, 251, 111),
  649. +        LCD_RGBPACK(255, 251, 115), LCD_RGBPACK(255, 252, 120),
  650. +        LCD_RGBPACK(255, 252, 124), LCD_RGBPACK(255, 253, 129),
  651. +        LCD_RGBPACK(255, 253, 133), LCD_RGBPACK(255, 254, 138),
  652. +        LCD_RGBPACK(255, 255, 143), LCD_RGBPACK(255, 255, 147),
  653. +        LCD_RGBPACK(255, 255, 151), LCD_RGBPACK(255, 255, 156),
  654. +        LCD_RGBPACK(255, 255, 160), LCD_RGBPACK(255, 255, 165),
  655. +        LCD_RGBPACK(255, 255, 170), LCD_RGBPACK(255, 255, 174),
  656. +        LCD_RGBPACK(255, 255, 178), LCD_RGBPACK(255, 255, 183),
  657. +        LCD_RGBPACK(255, 255, 187), LCD_RGBPACK(255, 255, 192),
  658. +        LCD_RGBPACK(255, 255, 196), LCD_RGBPACK(255, 255, 200),
  659. +        LCD_RGBPACK(255, 255, 205), LCD_RGBPACK(255, 255, 210),
  660. +        LCD_RGBPACK(255, 255, 214), LCD_RGBPACK(255, 255, 219),
  661. +        LCD_RGBPACK(255, 255, 223), LCD_RGBPACK(255, 255, 227),
  662. +        LCD_RGBPACK(255, 255, 232), LCD_RGBPACK(255, 255, 236),
  663. +        LCD_RGBPACK(255, 255, 241), LCD_RGBPACK(255, 255, 246),
  664. +        LCD_RGBPACK(255, 255, 250), LCD_RGBPACK(255, 255, 255) };
  665. +#endif
  666. +static long next_update = 0;
  667. +
  668. +void draw_lines_vertical(void);
  669. +void draw_lines_horizontal(void);
  670. +void draw_bars_vertical(void);
  671. +void draw_bars_horizontal(void);
  672. +void draw_spectrogram_vertical(void);
  673. +void draw_spectrogram_horizontal(void);
  674. +
  675. +void draw(char mode, const unsigned char* message)
  676. +{
  677. +    static uint32_t show_message = 0, last_mode = 0;
  678. +    static bool last_orientation = true;
  679. +    static unsigned char* last_message = 0;
  680. +    if (message != 0)
  681. +    {
  682. +        last_message = (unsigned char*) message;
  683. +        show_message = 5;
  684. +    }
  685. +
  686. +    switch (mode)
  687. +    {
  688. +        default:
  689. +        case 0: {
  690. +            rb->lcd_clear_display();
  691. +
  692. +            if (graph_settings.orientation_vertical)
  693. +                draw_lines_vertical();
  694. +            else
  695. +                draw_lines_horizontal();
  696. +
  697. +            last_mode = 0;
  698. +            spectrogram_settings.row = 0; spectrogram_settings.column = 0;
  699. +            break;
  700. +        }
  701. +        case 1: {
  702. +            rb->lcd_clear_display();
  703. +
  704. +            if(graph_settings.orientation_vertical)
  705. +                draw_bars_vertical();
  706. +            else
  707. +                draw_bars_horizontal();
  708. +
  709. +            last_mode = 1;
  710. +            spectrogram_settings.row = 0; spectrogram_settings.column = 0;
  711. +            break;
  712. +        }
  713. +#   ifdef HAVE_LCD_COLOR
  714. +        case 2: {
  715. +            if(last_mode != 2 ||
  716. +               graph_settings.orientation_vertical != last_orientation)
  717. +            {
  718. +                spectrogram_settings.row = 0; spectrogram_settings.column = 0;
  719. +                rb->lcd_clear_display();
  720. +            }
  721. +            if(graph_settings.orientation_vertical)
  722. +                draw_spectrogram_vertical();
  723. +            else
  724. +                draw_spectrogram_horizontal();
  725. +
  726. +            last_mode = 2;
  727. +            break;
  728. +        }
  729. +#   endif
  730. +    }
  731. +
  732. +    if (show_message > 0)
  733. +    {
  734. +        int x, y;
  735. +        rb->lcd_getstringsize(last_message, &x, &y);
  736. +        x += 6; /* 3 px of horizontal padding and */
  737. +        y += 4; /* 2 px of vertical padding */
  738. +
  739. +#   ifdef HAVE_LCD_COLOR
  740. +        if(mode == 2)
  741. +        {
  742. +            if (graph_settings.orientation_vertical)
  743. +            {
  744. +                if(spectrogram_settings.column > LCD_WIDTH-x-2)
  745. +                {
  746. +                    xlcd_scroll_left(spectrogram_settings.column -
  747. +                                     (LCD_WIDTH - x - 1));
  748. +                    spectrogram_settings.column = LCD_WIDTH - x - 2;
  749. +                }
  750. +            }
  751. +        }
  752. +#   endif
  753. +
  754. +#if LCD_DEPTH > 2
  755. +        rb->lcd_set_foreground(LCD_DARKGRAY);
  756. +        rb->lcd_fillrect(LCD_WIDTH-1-x, 0, LCD_WIDTH-1, y);
  757. +
  758. +        rb->lcd_set_foreground(LCD_DEFAULT_FG);
  759. +        rb->lcd_set_background(LCD_DARKGRAY);
  760. +#endif
  761. +        rb->lcd_putsxy(LCD_WIDTH-1-x+3, 2, last_message);
  762. +#if LCD_DEPTH > 1
  763. +        rb->lcd_set_background(LCD_DEFAULT_BG);
  764. +#endif
  765. +
  766. +        show_message--;
  767. +
  768. +#   ifdef HAVE_LCD_COLOR
  769. +        if(show_message == 0 && mode == 2)
  770. +        {
  771. +            if(graph_settings.orientation_vertical)
  772. +            {
  773. +                rb->lcd_set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
  774. +                rb->lcd_fillrect(LCD_WIDTH-2-x, 0, LCD_WIDTH-1, y);
  775. +                rb->lcd_set_drawmode(DRMODE_SOLID);
  776. +            }
  777. +            else
  778. +            {
  779. +                xlcd_scroll_up(y);
  780. +                spectrogram_settings.row -= y;
  781. +                if(spectrogram_settings.row < 0)
  782. +                    spectrogram_settings.row = 0;
  783. +            }
  784. +        }
  785. +#   endif
  786. +    }
  787. +
  788. +    last_orientation = graph_settings.orientation_vertical;
  789. +
  790. +    rb->lcd_update();
  791. +
  792. +    /* we still have time in our time slot, so we sleep() */
  793. +    if (*rb->current_tick < next_update)
  794. +        rb->sleep(next_update - *rb->current_tick);
  795. +
  796. +    /* end of next time slot */
  797. +    next_update = *rb->current_tick + HZ / REFRESH_RATE;
  798. +}
  799. +
  800. +void draw_lines_vertical(void)
  801. +{
  802. +    static int max = 0;
  803. +    static bool last_mode = false;
  804. +
  805. +    static const int32_t hfactor =
  806. +            Q15_DIV(LCD_WIDTH << 15, (ARRAYSIZE_PLOT) << 15),
  807. +            bins_per_pixel = (ARRAYSIZE_PLOT) / LCD_WIDTH;
  808. +
  809. +    if (graph_settings.logarithmic != last_mode)
  810. +    {
  811. +        max = 0; /* reset the graph on scaling mode change */
  812. +        last_mode = graph_settings.logarithmic;
  813. +    }
  814. +    int32_t new_max = calc_magnitudes(graph_settings.logarithmic);
  815. +
  816. +    if (new_max > max)
  817. +        max = new_max;
  818. +
  819. +    if (new_max == 0 || max == 0) /* nothing to draw */
  820. +        return;
  821. +
  822. +    int32_t vfactor;
  823. +
  824. +    if (graph_settings.logarithmic)
  825. +        vfactor = Q16_DIV(LCD_HEIGHT << 16, max); /* s15.16 */
  826. +    else
  827. +        vfactor = Q15_DIV(LCD_HEIGHT << 15, max << 15); /* s16.15 */
  828. +
  829. +#ifdef HAVE_LCD_COLOR
  830. +    if(graph_settings.colored)
  831. +    {
  832. +        int line;
  833. +        for(line = 0; line < LCD_HEIGHT; ++line)
  834. +        {
  835. +            int32_t color = Q16_DIV((line+1) << 16, LCD_HEIGHT << 16);
  836. +            color = Q16_MUL(color, (COLORS-1) << 16) >> 16;
  837. +            rb->lcd_set_foreground(colors[color]);
  838. +            rb->lcd_hline(0, LCD_WIDTH-1, LCD_HEIGHT-line-1);
  839. +        }
  840. +        /* Erase the lines with the background color */
  841. +        rb->lcd_set_foreground(rb->lcd_get_background());
  842. +    }
  843. +#endif
  844. +
  845. +    /* take the average of neighboring bins
  846. +     * if we have to scale the graph horizontally */
  847. +    int64_t bins_avg = 0;
  848. +    bool draw = true;
  849. +    int32_t i;
  850. +    for (i = 0; i < ARRAYSIZE_PLOT; ++i)
  851. +    {
  852. +        int32_t x = 0, y = 0;
  853. +
  854. +        x = Q15_MUL(hfactor, i << 15);
  855. +        x += (1 << 14);
  856. +        x >>= 15;
  857. +
  858. +        if (hfactor < 32768) /* hfactor < 0, graph compression */
  859. +        {
  860. +            draw = false;
  861. +            bins_avg += plot[i];
  862. +
  863. +            /* fix the division by zero warning:
  864. +             * bins_per_pixel is zero when the graph is expanding;
  865. +             * execution won't even reach this point - this is a dummy constant
  866. +             */
  867. +            const int32_t div = bins_per_pixel > 0 ? bins_per_pixel : 1;
  868. +            if ((i + 1) % div == 0)
  869. +            {
  870. +                if (graph_settings.logarithmic)
  871. +                {
  872. +                    bins_avg = Q16_DIV(bins_avg, div << 16);
  873. +                    y = Q16_MUL(vfactor, bins_avg) >> 16;
  874. +                }
  875. +                else
  876. +                {
  877. +                    bins_avg = Q15_DIV(bins_avg << 15, div << 15);
  878. +                    bins_avg += (1 << 14); /* rounding up */
  879. +
  880. +                    y = Q15_MUL(vfactor, bins_avg) >> 15;
  881. +                }
  882. +
  883. +                bins_avg = 0;
  884. +                draw = true;
  885. +            }
  886. +        }
  887. +        else
  888. +        {
  889. +            y = Q15_MUL(vfactor, plot[i] << 15) >> 15;
  890. +            draw = true;
  891. +        }
  892. +
  893. +        if (draw)
  894. +        {
  895. +#       ifdef HAVE_LCD_COLOR
  896. +            if(graph_settings.colored)
  897. +                rb->lcd_vline(x, 0, LCD_HEIGHT-y);
  898. +            else
  899. +#       endif
  900. +            rb->lcd_vline(x, LCD_HEIGHT-1, LCD_HEIGHT-y-1);
  901. +        }
  902. +    }
  903. +#   ifdef HAVE_LCD_COLOR
  904. +    rb->lcd_set_foreground(LCD_DEFAULT_FG);
  905. +#   endif
  906. +}
  907. +
  908. +void draw_lines_horizontal(void)
  909. +{
  910. +    static int max = 0;
  911. +    static bool last_mode = false;
  912. +
  913. +    static const int32_t vfactor =
  914. +            Q15_DIV(LCD_HEIGHT << 15, (ARRAYSIZE_PLOT) << 15),
  915. +            bins_per_pixel = (ARRAYSIZE_PLOT) / LCD_HEIGHT;
  916. +
  917. +    if (graph_settings.logarithmic != last_mode)
  918. +    {
  919. +        max = 0; /* reset the graph on scaling mode change */
  920. +        last_mode = graph_settings.logarithmic;
  921. +    }
  922. +    int32_t new_max = calc_magnitudes(graph_settings.logarithmic);
  923. +
  924. +    if (new_max > max)
  925. +        max = new_max;
  926. +
  927. +    if (new_max == 0 || max == 0) /* nothing to draw */
  928. +        return;
  929. +
  930. +    int32_t hfactor;
  931. +
  932. +    if (graph_settings.logarithmic)
  933. +        hfactor = Q16_DIV((LCD_WIDTH - 1) << 16, max); /* s15.16 */
  934. +    else
  935. +        hfactor = Q15_DIV((LCD_WIDTH - 1) << 15, max << 15); /* s16.15 */
  936. +
  937. +#ifdef HAVE_LCD_COLOR
  938. +    if(graph_settings.colored)
  939. +    {
  940. +        int line;
  941. +        for(line = 0; line < LCD_WIDTH; ++line)
  942. +        {
  943. +            int32_t color = Q16_DIV((line+1) << 16, LCD_WIDTH << 16);
  944. +            color = Q16_MUL(color, (COLORS-1) << 16) >> 16;
  945. +            rb->lcd_set_foreground(colors[color]);
  946. +            rb->lcd_vline(line, 0, LCD_HEIGHT-1);
  947. +        }
  948. +        /* Erase the lines with the background color */
  949. +        rb->lcd_set_foreground(rb->lcd_get_background());
  950. +    }
  951. +#endif
  952. +
  953. +    /* take the average of neighboring bins
  954. +     * if we have to scale the graph horizontally */
  955. +    int64_t bins_avg = 0;
  956. +    bool draw = true;
  957. +    int32_t i;
  958. +    for (i = 0; i < ARRAYSIZE_PLOT; ++i)
  959. +    {
  960. +        int32_t x = 0, y = 0;
  961. +
  962. +        y = Q15_MUL(vfactor, i << 15) + (1 << 14);
  963. +        y >>= 15;
  964. +
  965. +        if (vfactor < 32768) /* vfactor < 0, graph compression */
  966. +        {
  967. +            draw = false;
  968. +            bins_avg += plot[i];
  969. +
  970. +            /* fix the division by zero warning:
  971. +             * bins_per_pixel is zero when the graph is expanding;
  972. +             * execution won't even reach this point - this is a dummy constant
  973. +             */
  974. +            const int32_t div = bins_per_pixel > 0 ? bins_per_pixel : 1;
  975. +            if ((i + 1) % div == 0)
  976. +            {
  977. +                if (graph_settings.logarithmic)
  978. +                {
  979. +                    bins_avg = Q16_DIV(bins_avg, div << 16);
  980. +
  981. +                    x = Q16_MUL(hfactor, bins_avg) >> 16;
  982. +                }
  983. +                else
  984. +                {
  985. +                    bins_avg = Q15_DIV(bins_avg << 15, div << 15);
  986. +                    bins_avg += (1 << 14); /* rounding up */
  987. +
  988. +                    x = Q15_MUL(hfactor, bins_avg) >> 15;
  989. +                }
  990. +
  991. +                bins_avg = 0;
  992. +                draw = true;
  993. +            }
  994. +        }
  995. +        else
  996. +        {
  997. +            y = Q15_MUL(hfactor, plot[i] << 15) >> 15;
  998. +            draw = true;
  999. +        }
  1000. +
  1001. +        if (draw)
  1002. +        {
  1003. +#       ifdef HAVE_LCD_COLOR
  1004. +            if(graph_settings.colored)
  1005. +            {
  1006. +                rb->lcd_hline(LCD_WIDTH-1, x, y);
  1007. +            }
  1008. +            else
  1009. +#       endif
  1010. +            rb->lcd_hline(0, x, y);
  1011. +        }
  1012. +    }
  1013. +#   ifdef HAVE_LCD_COLOR
  1014. +    rb->lcd_set_foreground(LCD_DEFAULT_FG);
  1015. +#   endif
  1016. +}
  1017. +
  1018. +void draw_bars_vertical(void)
  1019. +{
  1020. +    static const unsigned int bars = 12, border = 3, items = ARRAYSIZE_PLOT
  1021. +            / bars, width = (LCD_WIDTH - ((bars - 1) * border)) / bars;
  1022. +
  1023. +    calc_magnitudes(graph_settings.logarithmic);
  1024. +
  1025. +    rb->lcd_set_foreground(LCD_DEFAULT_FG);
  1026. +    int64_t bars_values[bars], bars_max = 0, avg = 0;
  1027. +    unsigned int i, bars_idx = 0;
  1028. +    for (i = 0; i < ARRAYSIZE_PLOT; ++i)
  1029. +    {
  1030. +        avg += plot[i];
  1031. +        if ((i + 1) % items == 0)
  1032. +        {
  1033. +            /* Calculate the average value and keep the fractional part
  1034. +             * for some added precision */
  1035. +            if (graph_settings.logarithmic)
  1036. +                avg = Q16_DIV(avg, items << 16); /* s15.16 */
  1037. +            else
  1038. +                avg = Q15_DIV(avg << 15, items << 15); /* s16.15 */
  1039. +            bars_values[bars_idx] = avg;
  1040. +
  1041. +            if (bars_values[bars_idx] > bars_max)
  1042. +                bars_max = bars_values[bars_idx];
  1043. +
  1044. +            bars_idx++;
  1045. +            avg = 0;
  1046. +        }
  1047. +    }
  1048. +
  1049. +    if(bars_max == 0) /* nothing to draw */
  1050. +        return;
  1051. +
  1052. +    /* Give the graph some headroom */
  1053. +    bars_max = Q15_MUL(bars_max, float_q15(1.1));
  1054. +
  1055. +    int64_t vfactor;
  1056. +    if (graph_settings.logarithmic)
  1057. +        vfactor = Q16_DIV(LCD_HEIGHT << 16, bars_max);
  1058. +    else
  1059. +        vfactor = Q15_DIV(LCD_HEIGHT << 15, bars_max);
  1060. +
  1061. +    for (i = 0; i < bars; ++i)
  1062. +    {
  1063. +        int x = (i) * (border + width);
  1064. +        int y;
  1065. +        if (graph_settings.logarithmic)
  1066. +        {
  1067. +            y = Q16_MUL(vfactor, bars_values[i]);
  1068. +            y += (1 << 15);
  1069. +            y >>= 16;
  1070. +        }
  1071. +        else
  1072. +        {
  1073. +            y = Q15_MUL(vfactor, bars_values[i]);
  1074. +            y += (1 << 14);
  1075. +            y >>= 15;
  1076. +        }
  1077. +
  1078. +        rb->lcd_fillrect(x, LCD_HEIGHT - y, width, y);
  1079. +    }
  1080. +}
  1081. +
  1082. +void draw_bars_horizontal(void)
  1083. +{
  1084. +    static const unsigned int bars = 12, border = 3, items = ARRAYSIZE_PLOT
  1085. +            / bars, height = (LCD_HEIGHT - ((bars - 1) * border)) / bars;
  1086. +
  1087. +    calc_magnitudes(graph_settings.logarithmic);
  1088. +
  1089. +    rb->lcd_set_foreground(LCD_DEFAULT_FG);
  1090. +    int64_t bars_values[bars], bars_max = 0, avg = 0;
  1091. +    unsigned int i, bars_idx = 0;
  1092. +    for (i = 0; i < ARRAYSIZE_PLOT; ++i)
  1093. +    {
  1094. +        avg += plot[i];
  1095. +        if ((i + 1) % items == 0)
  1096. +        {
  1097. +            /* Calculate the average value and keep the fractional part
  1098. +             * for some added precision */
  1099. +            if (graph_settings.logarithmic)
  1100. +                avg = Q16_DIV(avg, items << 16); /* s15.16 */
  1101. +            else
  1102. +                avg = Q15_DIV(avg << 15, items << 15); /* s16.15 */
  1103. +            bars_values[bars_idx] = avg;
  1104. +
  1105. +            if (bars_values[bars_idx] > bars_max)
  1106. +                bars_max = bars_values[bars_idx];
  1107. +
  1108. +            bars_idx++;
  1109. +            avg = 0;
  1110. +        }
  1111. +    }
  1112. +
  1113. +    if(bars_max == 0) /* nothing to draw */
  1114. +        return;
  1115. +
  1116. +    /* Give the graph some headroom */
  1117. +    bars_max = Q15_MUL(bars_max, float_q15(1.1));
  1118. +
  1119. +    int64_t hfactor;
  1120. +    if (graph_settings.logarithmic)
  1121. +        hfactor = Q16_DIV(LCD_WIDTH << 16, bars_max);
  1122. +    else
  1123. +        hfactor = Q15_DIV(LCD_WIDTH << 15, bars_max);
  1124. +
  1125. +    for (i = 0; i < bars; ++i)
  1126. +    {
  1127. +        int y = (i) * (border + height);
  1128. +        int x;
  1129. +        if (graph_settings.logarithmic)
  1130. +        {
  1131. +            x = Q16_MUL(hfactor, bars_values[i]);
  1132. +            x += (1 << 15);
  1133. +            x >>= 16;
  1134. +        }
  1135. +        else
  1136. +        {
  1137. +            x = Q15_MUL(hfactor, bars_values[i]);
  1138. +            x += (1 << 14);
  1139. +            x >>= 15;
  1140. +        }
  1141. +
  1142. +        rb->lcd_fillrect(0, y, x, height);
  1143. +    }
  1144. +}
  1145. +
  1146. +#ifdef HAVE_LCD_COLOR
  1147. +void draw_spectrogram_vertical(void)
  1148. +{
  1149. +    const int32_t scale_factor =
  1150. +            ( Q15_DIV(ARRAYSIZE_PLOT << 15, LCD_HEIGHT << 15) + (1<<14) ) >> 15,
  1151. +        remaining_div =
  1152. +            ( Q15_DIV((scale_factor*LCD_HEIGHT) << 15,
  1153. +                      (ARRAYSIZE_PLOT-scale_factor*LCD_HEIGHT) << 15)
  1154. +             + (1<<14) ) >> 15;
  1155. +
  1156. +    calc_magnitudes(graph_settings.logarithmic);
  1157. +
  1158. +    int i, y = LCD_HEIGHT-1, count = 0, rem_count = 0;
  1159. +    int64_t avg = 0;
  1160. +    for(i = 0; i < ARRAYSIZE_PLOT; ++i)
  1161. +    {
  1162. +        avg += plot[i];
  1163. +        ++count;
  1164. +        ++rem_count;
  1165. +
  1166. +        /* Kinda hacky - due to the rounding in scale_factor, we try to
  1167. +         * uniformly interweave the extra values in our calculations */
  1168. +        if(remaining_div > 0 && rem_count == remaining_div &&
  1169. +                (i+1) < ARRAYSIZE_PLOT)
  1170. +        {
  1171. +            ++i;
  1172. +            avg += plot[i];
  1173. +            rem_count = 0;
  1174. +        }
  1175. +
  1176. +        if(count >= scale_factor)
  1177. +        {
  1178. +            if(rem_count == 0) /* if we just added an extra value */
  1179. +                ++count;
  1180. +
  1181. +            int32_t color;
  1182. +            if(graph_settings.logarithmic)
  1183. +            {
  1184. +                avg = Q16_DIV(avg, count << 16);
  1185. +                color = Q16_DIV(avg, QLOG_MAX);
  1186. +                color = Q16_MUL(color, (COLORS-1) << 16) >> 16;
  1187. +            }
  1188. +            else
  1189. +            {
  1190. +                avg = Q15_DIV(avg << 15, count << 15);
  1191. +                color = Q15_DIV(avg, LIN_MAX << 15);
  1192. +                color = Q15_MUL(color, (COLORS-1) << 15) >> 15;
  1193. +            }
  1194. +            rb->lcd_set_foreground(colors[color]);
  1195. +            rb->lcd_drawpixel(spectrogram_settings.column, y);
  1196. +
  1197. +            y--;
  1198. +
  1199. +            avg = 0;
  1200. +            count = 0;
  1201. +        }
  1202. +    }
  1203. +    if(spectrogram_settings.column != LCD_WIDTH - 1)
  1204. +        spectrogram_settings.column++;
  1205. +    else
  1206. +        xlcd_scroll_left(1);
  1207. +}
  1208. +void draw_spectrogram_horizontal(void)
  1209. +{
  1210. +    const int32_t scale_factor =
  1211. +            ( Q15_DIV(ARRAYSIZE_PLOT << 15, LCD_WIDTH << 15)) >> 15,
  1212. +        remaining_div =
  1213. +            ( Q15_DIV((scale_factor*LCD_WIDTH) << 15,
  1214. +                      (ARRAYSIZE_PLOT-scale_factor*LCD_WIDTH) << 15)
  1215. +             + (1<<14) ) >> 15;
  1216. +
  1217. +    calc_magnitudes(graph_settings.logarithmic);
  1218. +
  1219. +    int i, x = 0, count = 0, rem_count = 0;
  1220. +    int64_t avg = 0;
  1221. +    for(i = 0; i < ARRAYSIZE_PLOT; ++i)
  1222. +    {
  1223. +        avg += plot[i];
  1224. +        ++count;
  1225. +        ++rem_count;
  1226. +
  1227. +        /* Kinda hacky - due to the rounding in scale_factor, we try to
  1228. +         * uniformly interweave the extra values in our calculations */
  1229. +        if(remaining_div > 0 && rem_count == remaining_div &&
  1230. +                (i+1) < ARRAYSIZE_PLOT)
  1231. +        {
  1232. +            ++i;
  1233. +            avg += plot[i];
  1234. +            rem_count = 0;
  1235. +        }
  1236. +
  1237. +        if(count >= scale_factor)
  1238. +        {
  1239. +            if(rem_count == 0) /* if we just added an extra value */
  1240. +                ++count;
  1241. +
  1242. +            int32_t color;
  1243. +            if(graph_settings.logarithmic)
  1244. +            {
  1245. +                avg = Q16_DIV(avg, count << 16);
  1246. +                color = Q16_DIV(avg, QLOG_MAX);
  1247. +                color = Q16_MUL(color, (COLORS-1) << 16) >> 16;
  1248. +            }
  1249. +            else
  1250. +            {
  1251. +                avg = Q15_DIV(avg << 15, count << 15);
  1252. +                color = Q15_DIV(avg, LIN_MAX << 15);
  1253. +                color = Q15_MUL(color, (COLORS-1) << 15) >> 15;
  1254. +            }
  1255. +            rb->lcd_set_foreground(colors[color]);
  1256. +            rb->lcd_drawpixel(x, spectrogram_settings.row);
  1257. +
  1258. +            x++;
  1259. +
  1260. +            avg = 0;
  1261. +            count = 0;
  1262. +        }
  1263. +    }
  1264. +    if(spectrogram_settings.row != LCD_HEIGHT-1)
  1265. +        spectrogram_settings.row++;
  1266. +    else
  1267. +        xlcd_scroll_up(1);
  1268. +}
  1269. +#endif
  1270. +/********************* End of plotting functions (modes) *********************/
  1271. +
  1272. +enum plugin_status plugin_start(const void* parameter)
  1273. +{
  1274. +    (void) parameter;
  1275. +    if ((rb->audio_status() & AUDIO_STATUS_PLAY) == 0)
  1276. +    {
  1277. +        rb->splash(HZ * 2, "No track playing. Exiting..");
  1278. +        return PLUGIN_OK;
  1279. +    }
  1280. +
  1281. +#if LCD_DEPTH > 1
  1282. +    rb->lcd_set_backdrop(NULL);
  1283. +#endif
  1284. +    backlight_force_on();
  1285. +
  1286. +#ifdef HAVE_ADJUSTABLE_CPU_FREQ
  1287. +    rb->cpu_boost(true);
  1288. +#endif
  1289. +
  1290. +    /* Defaults */
  1291. +    bool run = true;
  1292. +    int mode = 0;
  1293. +    graph_settings.logarithmic = true;
  1294. +    graph_settings.orientation_vertical = true;
  1295. +    graph_settings.window_func = 0;
  1296. +#ifdef HAVE_LCD_COLOR
  1297. +    graph_settings.colored = false;
  1298. +#endif
  1299. +    bool changed_window = false;
  1300. +
  1301. +    /* set the end of the first time slot - rest of the
  1302. +     * next_update work is done in draw() */
  1303. +    next_update = *rb->current_tick + HZ / REFRESH_RATE;
  1304. +
  1305. +    size_t size = sizeof(buffer);
  1306. +    FFT_CFG state = FFT_ALLOC(FFT_SIZE, 0, buffer, &size);
  1307. +
  1308. +    if (state == 0)
  1309. +    {
  1310. +        DEBUGF("needed data: %i", (int) size);
  1311. +        return PLUGIN_ERROR;
  1312. +    }
  1313. +
  1314. +    /* taken out of the main loop for efficiency (?)*/
  1315. +    kiss_fft_scalar left, right;
  1316. +    kiss_fft_scalar* value;
  1317. +    int count;
  1318. +
  1319. +    while (run)
  1320. +    {
  1321. +        value = (kiss_fft_scalar*) rb->pcm_get_peak_buffer(&count);
  1322. +        if (value == 0 || count == 0)
  1323. +        {
  1324. +            rb->yield();
  1325. +            continue;
  1326. +        }
  1327. +
  1328. +        int idx = 0; /* offset in the buffer */
  1329. +        int fft_idx = 0; /* offset in input */
  1330. +
  1331. +        do
  1332. +        {
  1333. +            left = *(value + idx);
  1334. +            idx += 2;
  1335. +
  1336. +            right = *(value + idx);
  1337. +            idx += 2;
  1338. +
  1339. +            input[fft_idx].r = left;
  1340. +            input[fft_idx].i = right;
  1341. +            fft_idx++;
  1342. +
  1343. +            if (fft_idx == ARRAYSIZE_IN)
  1344. +                break;
  1345. +        } while (idx < count);
  1346. +
  1347. +        if (fft_idx == ARRAYSIZE_IN)
  1348. +        {
  1349. +            apply_window_func(graph_settings.window_func);
  1350. +
  1351. +            /* Play nice - the sleep at the end of draw()
  1352. +             * only tries to maintain the frame rate */
  1353. +            rb->yield();
  1354. +            FFT_FFT(state, input, output);
  1355. +            if(changed_window)
  1356. +            {
  1357. +                draw(mode, window_text[graph_settings.window_func]);
  1358. +                changed_window = false;
  1359. +            }
  1360. +            else
  1361. +                draw(mode, 0);
  1362. +
  1363. +            fft_idx = 0;
  1364. +        };
  1365. +
  1366. +        int button = rb->button_get(false);
  1367. +        switch (button)
  1368. +        {
  1369. +            case FFT_QUIT:
  1370. +                run = false;
  1371. +                break;
  1372. +            case FFT_PREV_GRAPH: {
  1373. +                mode -= 1;
  1374. +                if (mode < 0)
  1375. +                    mode = MODES_COUNT-1;
  1376. +                draw(mode, modes_text[(int) mode]);
  1377. +                break;
  1378. +            }
  1379. +            case FFT_NEXT_GRAPH: {
  1380. +                mode += 1;
  1381. +                if (mode >= MODES_COUNT)
  1382. +                    mode = 0;
  1383. +                draw(mode, modes_text[(int) mode]);
  1384. +                break;
  1385. +            }
  1386. +            case FFT_WINDOW: {
  1387. +                changed_window = true;
  1388. +                graph_settings.window_func ++;
  1389. +                if(graph_settings.window_func >= WINDOW_COUNT)
  1390. +                    graph_settings.window_func = 0;
  1391. +                break;
  1392. +            }
  1393. +            case FFT_SCALE: {
  1394. +                graph_settings.logarithmic = !graph_settings.logarithmic;
  1395. +                draw(mode, scales_text[graph_settings.logarithmic ? 1 : 0]);
  1396. +                break;
  1397. +            }
  1398. +            case FFT_ORIENTATION: {
  1399. +                graph_settings.orientation_vertical = !graph_settings.orientation_vertical;
  1400. +                draw(mode, 0);
  1401. +                break;
  1402. +            }
  1403. +#       ifdef HAVE_LCD_COLOR
  1404. +            case FFT_COLOR: {
  1405. +                graph_settings.colored = !graph_settings.colored;
  1406. +                draw(mode, 0);
  1407. +                break;
  1408. +            }
  1409. +#       endif
  1410. +            default: {
  1411. +                if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
  1412. +                    return PLUGIN_USB_CONNECTED;
  1413. +            }
  1414. +
  1415. +        }
  1416. +    }
  1417. +    backlight_use_settings();
  1418. +    return PLUGIN_OK;
  1419. +}
  1420. diff --git a/apps/plugins/fft/fft.make b/apps/plugins/fft/fft.make
  1421. new file mode 100644
  1422. index 0000000..b14566c
  1423. --- /dev/null
  1424. +++ b/apps/plugins/fft/fft.make
  1425. @@ -0,0 +1,27 @@
  1426. +#             __________               __   ___.
  1427. +#   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
  1428. +#   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
  1429. +#   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
  1430. +#   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
  1431. +#                     \/            \/     \/    \/            \/
  1432. +# $Id$
  1433. +#
  1434. +
  1435. +FFTSRCDIR := $(APPSDIR)/plugins/fft
  1436. +FFTBUILDDIR := $(BUILDDIR)/apps/plugins/fft
  1437. +
  1438. +ROCKS += $(FFTBUILDDIR)/fft.rock
  1439. +
  1440. +FFT_SRC := $(call preprocess, $(FFTSRCDIR)/SOURCES)
  1441. +FFT_OBJ := $(call c2obj, $(FFT_SRC))
  1442. +
  1443. +# add source files to OTHER_SRC to get automatic dependencies
  1444. +OTHER_SRC += $(FFT_SRC)
  1445. +
  1446. +FFTFLAGS = $(filter-out -O%,$(PLUGINFLAGS)) -O3 -DFIXED_POINT=16
  1447. +
  1448. +$(FFTBUILDDIR)/fft.rock: $(FFT_OBJ)
  1449. +
  1450. +$(FFTBUILDDIR)/%.o: $(FFTSRCDIR)/%.c $(FFTSRCDIR)/fft.make
  1451. +        $(SILENT)mkdir -p $(dir $@)
  1452. +        $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(dir $<) $(FFTFLAGS) -c $< -o $@
  1453. diff --git a/apps/plugins/fft/kiss_fft.c b/apps/plugins/fft/kiss_fft.c
  1454. new file mode 100644
  1455. index 0000000..b3fb50c
  1456. --- /dev/null
  1457. +++ b/apps/plugins/fft/kiss_fft.c
  1458. @@ -0,0 +1,428 @@
  1459. +/*
  1460. +Copyright (c) 2003-2004, Mark Borgerding
  1461. +
  1462. +All rights reserved.
  1463. +
  1464. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
  1465. +
  1466. +    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  1467. +    * 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.
  1468. +    * 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.
  1469. +
  1470. +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.
  1471. +*/
  1472. +
  1473. +
  1474. +#include "_kiss_fft_guts.h"
  1475. +/* The guts header contains all the multiplication and addition macros that are defined for
  1476. + fixed or floating point complex numbers.  It also delares the kf_ internal functions.
  1477. + */
  1478. +
  1479. +static kiss_fft_cpx *scratchbuf=NULL;
  1480. +static size_t nscratchbuf=0;
  1481. +static kiss_fft_cpx *tmpbuf=NULL;
  1482. +static size_t ntmpbuf=0;
  1483. +
  1484. +#define CHECKBUF(buf,nbuf,n) \
  1485. +    do { \
  1486. +        if ( nbuf < (size_t)(n) ) {\
  1487. +                DEBUGF("CHECKBUF NOT IMPLEMENTED!");\
  1488. +                break;\
  1489. +        } \
  1490. +   }while(0)
  1491. +
  1492. +
  1493. +static void kf_bfly2(
  1494. +        kiss_fft_cpx * Fout,
  1495. +        const size_t fstride,
  1496. +        const kiss_fft_cfg st,
  1497. +        int m
  1498. +        )
  1499. +{
  1500. +    kiss_fft_cpx * Fout2;
  1501. +    kiss_fft_cpx * tw1 = st->twiddles;
  1502. +    kiss_fft_cpx t;
  1503. +    Fout2 = Fout + m;
  1504. +    do{
  1505. +        C_FIXDIV(*Fout,2); C_FIXDIV(*Fout2,2);
  1506. +
  1507. +        C_MUL (t,  *Fout2 , *tw1);
  1508. +        tw1 += fstride;
  1509. +        C_SUB( *Fout2 ,  *Fout , t );
  1510. +        C_ADDTO( *Fout ,  t );
  1511. +        ++Fout2;
  1512. +        ++Fout;
  1513. +    }while (--m);
  1514. +}
  1515. +
  1516. +static void kf_bfly4(
  1517. +        kiss_fft_cpx * Fout,
  1518. +        const size_t fstride,
  1519. +        const kiss_fft_cfg st,
  1520. +        const size_t m
  1521. +        )
  1522. +{
  1523. +    kiss_fft_cpx *tw1,*tw2,*tw3;
  1524. +    kiss_fft_cpx scratch[6];
  1525. +    size_t k=m;
  1526. +    const size_t m2=2*m;
  1527. +    const size_t m3=3*m;
  1528. +
  1529. +    tw3 = tw2 = tw1 = st->twiddles;
  1530. +
  1531. +    do {
  1532. +        C_FIXDIV(*Fout,4); C_FIXDIV(Fout[m],4); C_FIXDIV(Fout[m2],4); C_FIXDIV(Fout[m3],4);
  1533. +
  1534. +        C_MUL(scratch[0],Fout[m] , *tw1 );
  1535. +        C_MUL(scratch[1],Fout[m2] , *tw2 );
  1536. +        C_MUL(scratch[2],Fout[m3] , *tw3 );
  1537. +
  1538. +        C_SUB( scratch[5] , *Fout, scratch[1] );
  1539. +        C_ADDTO(*Fout, scratch[1]);
  1540. +        C_ADD( scratch[3] , scratch[0] , scratch[2] );
  1541. +        C_SUB( scratch[4] , scratch[0] , scratch[2] );
  1542. +        C_SUB( Fout[m2], *Fout, scratch[3] );
  1543. +        tw1 += fstride;
  1544. +        tw2 += fstride*2;
  1545. +        tw3 += fstride*3;
  1546. +        C_ADDTO( *Fout , scratch[3] );
  1547. +
  1548. +        if(st->inverse) {
  1549. +            Fout[m].r = scratch[5].r - scratch[4].i;
  1550. +            Fout[m].i = scratch[5].i + scratch[4].r;
  1551. +            Fout[m3].r = scratch[5].r + scratch[4].i;
  1552. +            Fout[m3].i = scratch[5].i - scratch[4].r;
  1553. +        }else{
  1554. +            Fout[m].r = scratch[5].r + scratch[4].i;
  1555. +            Fout[m].i = scratch[5].i - scratch[4].r;
  1556. +            Fout[m3].r = scratch[5].r - scratch[4].i;
  1557. +            Fout[m3].i = scratch[5].i + scratch[4].r;
  1558. +        }
  1559. +        ++Fout;
  1560. +    }while(--k);
  1561. +}
  1562. +
  1563. +static void kf_bfly3(
  1564. +         kiss_fft_cpx * Fout,
  1565. +         const size_t fstride,
  1566. +         const kiss_fft_cfg st,
  1567. +         size_t m
  1568. +         )
  1569. +{
  1570. +     size_t k=m;
  1571. +     const size_t m2 = 2*m;
  1572. +     kiss_fft_cpx *tw1,*tw2;
  1573. +     kiss_fft_cpx scratch[5];
  1574. +     kiss_fft_cpx epi3;
  1575. +     epi3 = st->twiddles[fstride*m];
  1576. +
  1577. +     tw1=tw2=st->twiddles;
  1578. +
  1579. +     do{
  1580. +         C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3);
  1581. +
  1582. +         C_MUL(scratch[1],Fout[m] , *tw1);
  1583. +         C_MUL(scratch[2],Fout[m2] , *tw2);
  1584. +
  1585. +         C_ADD(scratch[3],scratch[1],scratch[2]);
  1586. +         C_SUB(scratch[0],scratch[1],scratch[2]);
  1587. +         tw1 += fstride;
  1588. +         tw2 += fstride*2;
  1589. +
  1590. +         Fout[m].r = Fout->r - HALF_OF(scratch[3].r);
  1591. +         Fout[m].i = Fout->i - HALF_OF(scratch[3].i);
  1592. +
  1593. +         C_MULBYSCALAR( scratch[0] , epi3.i );
  1594. +
  1595. +         C_ADDTO(*Fout,scratch[3]);
  1596. +
  1597. +         Fout[m2].r = Fout[m].r + scratch[0].i;
  1598. +         Fout[m2].i = Fout[m].i - scratch[0].r;
  1599. +
  1600. +         Fout[m].r -= scratch[0].i;
  1601. +         Fout[m].i += scratch[0].r;
  1602. +
  1603. +         ++Fout;
  1604. +     }while(--k);
  1605. +}
  1606. +
  1607. +static void kf_bfly5(
  1608. +        kiss_fft_cpx * Fout,
  1609. +        const size_t fstride,
  1610. +        const kiss_fft_cfg st,
  1611. +        int m
  1612. +        )
  1613. +{
  1614. +    kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
  1615. +    int u;
  1616. +    kiss_fft_cpx scratch[13];
  1617. +    kiss_fft_cpx * twiddles = st->twiddles;
  1618. +    kiss_fft_cpx *tw;
  1619. +    kiss_fft_cpx ya,yb;
  1620. +    ya = twiddles[fstride*m];
  1621. +    yb = twiddles[fstride*2*m];
  1622. +
  1623. +    Fout0=Fout;
  1624. +    Fout1=Fout0+m;
  1625. +    Fout2=Fout0+2*m;
  1626. +    Fout3=Fout0+3*m;
  1627. +    Fout4=Fout0+4*m;
  1628. +
  1629. +    tw=st->twiddles;
  1630. +    for ( u=0; u<m; ++u ) {
  1631. +        C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5);
  1632. +        scratch[0] = *Fout0;
  1633. +
  1634. +        C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
  1635. +        C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
  1636. +        C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
  1637. +        C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);
  1638. +
  1639. +        C_ADD( scratch[7],scratch[1],scratch[4]);
  1640. +        C_SUB( scratch[10],scratch[1],scratch[4]);
  1641. +        C_ADD( scratch[8],scratch[2],scratch[3]);
  1642. +        C_SUB( scratch[9],scratch[2],scratch[3]);
  1643. +
  1644. +        Fout0->r += scratch[7].r + scratch[8].r;
  1645. +        Fout0->i += scratch[7].i + scratch[8].i;
  1646. +
  1647. +        scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r);
  1648. +        scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r);
  1649. +
  1650. +        scratch[6].r =  S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i);
  1651. +        scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i);
  1652. +
  1653. +        C_SUB(*Fout1,scratch[5],scratch[6]);
  1654. +        C_ADD(*Fout4,scratch[5],scratch[6]);
  1655. +
  1656. +        scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r);
  1657. +        scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r);
  1658. +        scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i);
  1659. +        scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i);
  1660. +
  1661. +        C_ADD(*Fout2,scratch[11],scratch[12]);
  1662. +        C_SUB(*Fout3,scratch[11],scratch[12]);
  1663. +
  1664. +        ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
  1665. +    }
  1666. +}
  1667. +
  1668. +/* perform the butterfly for one stage of a mixed radix FFT */
  1669. +static void kf_bfly_generic(
  1670. +        kiss_fft_cpx * Fout,
  1671. +        const size_t fstride,
  1672. +        const kiss_fft_cfg st,
  1673. +        int m,
  1674. +        int p
  1675. +        )
  1676. +{
  1677. +    int u,k,q1,q;
  1678. +    kiss_fft_cpx * twiddles = st->twiddles;
  1679. +    kiss_fft_cpx t;
  1680. +    int Norig = st->nfft;
  1681. +
  1682. +    CHECKBUF(scratchbuf,nscratchbuf,p);
  1683. +
  1684. +    for ( u=0; u<m; ++u ) {
  1685. +        k=u;
  1686. +        for ( q1=0 ; q1<p ; ++q1 ) {
  1687. +            scratchbuf[q1] = Fout[ k  ];
  1688. +            C_FIXDIV(scratchbuf[q1],p);
  1689. +            k += m;
  1690. +        }
  1691. +
  1692. +        k=u;
  1693. +        for ( q1=0 ; q1<p ; ++q1 ) {
  1694. +            int twidx=0;
  1695. +            Fout[ k ] = scratchbuf[0];
  1696. +            for (q=1;q<p;++q ) {
  1697. +                twidx += fstride * k;
  1698. +                if (twidx>=Norig) twidx-=Norig;
  1699. +                C_MUL(t,scratchbuf[q] , twiddles[twidx] );
  1700. +                C_ADDTO( Fout[ k ] ,t);
  1701. +            }
  1702. +            k += m;
  1703. +        }
  1704. +    }
  1705. +}
  1706. +
  1707. +static
  1708. +void kf_work(
  1709. +        kiss_fft_cpx * Fout,
  1710. +        const kiss_fft_cpx * f,
  1711. +        const size_t fstride,
  1712. +        int in_stride,
  1713. +        int * factors,
  1714. +        const kiss_fft_cfg st
  1715. +        )
  1716. +{
  1717. +    kiss_fft_cpx * Fout_beg=Fout;
  1718. +    const int p=*factors++; /* the radix  */
  1719. +    const int m=*factors++; /* stage's fft length/p */
  1720. +    const kiss_fft_cpx * Fout_end = Fout + p*m;
  1721. +
  1722. +#ifdef _OPENMP
  1723. +    // use openmp extensions at the
  1724. +    // top-level (not recursive)
  1725. +    if (fstride==1) {
  1726. +        int k;
  1727. +
  1728. +        // execute the p different work units in different threads
  1729. +#       pragma omp parallel for
  1730. +        for (k=0;k<p;++k)
  1731. +            kf_work( Fout +k*m, f+ fstride*in_stride*k,fstride*p,in_stride,factors,st);
  1732. +        // all threads have joined by this point
  1733. +
  1734. +        switch (p) {
  1735. +            case 2: kf_bfly2(Fout,fstride,st,m); break;
  1736. +            case 3: kf_bfly3(Fout,fstride,st,m); break;
  1737. +            case 4: kf_bfly4(Fout,fstride,st,m); break;
  1738. +            case 5: kf_bfly5(Fout,fstride,st,m); break;
  1739. +            default: kf_bfly_generic(Fout,fstride,st,m,p); break;
  1740. +        }
  1741. +        return;
  1742. +    }
  1743. +#endif
  1744. +
  1745. +    if (m==1) {
  1746. +        do{
  1747. +            *Fout = *f;
  1748. +            f += fstride*in_stride;
  1749. +        }while(++Fout != Fout_end );
  1750. +    }else{
  1751. +        do{
  1752. +            // recursive call:
  1753. +            // DFT of size m*p performed by doing
  1754. +            // p instances of smaller DFTs of size m,
  1755. +            // each one takes a decimated version of the input
  1756. +            kf_work( Fout , f, fstride*p, in_stride, factors,st);
  1757. +            f += fstride*in_stride;
  1758. +        }while( (Fout += m) != Fout_end );
  1759. +    }
  1760. +
  1761. +    Fout=Fout_beg;
  1762. +
  1763. +    // recombine the p smaller DFTs
  1764. +    switch (p) {
  1765. +        case 2: kf_bfly2(Fout,fstride,st,m); break;
  1766. +        case 3: kf_bfly3(Fout,fstride,st,m); break;
  1767. +        case 4: kf_bfly4(Fout,fstride,st,m); break;
  1768. +        case 5: kf_bfly5(Fout,fstride,st,m); break;
  1769. +        default: kf_bfly_generic(Fout,fstride,st,m,p); break;
  1770. +    }
  1771. +}
  1772. +
  1773. +/*  facbuf is populated by p1,m1,p2,m2, ...
  1774. +    where
  1775. +    p[i] * m[i] = m[i-1]
  1776. +    m0 = n                  */
  1777. +static
  1778. +void kf_factor(int n,int * facbuf)
  1779. +{
  1780. +    int p=4;
  1781. +    int32_t floor_sqrt = fsqrt(n, 15) >> 15;
  1782. +
  1783. +    /*factor out powers of 4, powers of 2, then any remaining primes */
  1784. +    do {
  1785. +        while (n % p) {
  1786. +            switch (p) {
  1787. +                case 4: p = 2; break;
  1788. +                case 2: p = 3; break;
  1789. +                default: p += 2; break;
  1790. +            }
  1791. +            if (p > floor_sqrt)
  1792. +                p = n;          /* no more factors, skip to end */
  1793. +        }
  1794. +        n /= p;
  1795. +        *facbuf++ = p;
  1796. +        *facbuf++ = n;
  1797. +    } while (n > 1);
  1798. +}
  1799. +
  1800. +/*
  1801. + *
  1802. + * User-callable function to allocate all necessary storage space for the fft.
  1803. + *
  1804. + * The return value is a contiguous block of memory, allocated with malloc.  As such,
  1805. + * It can be freed with free(), rather than a kiss_fft-specific function.
  1806. + * */
  1807. +kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem )
  1808. +{
  1809. +    kiss_fft_cfg st=NULL;
  1810. +    size_t memneeded = sizeof(struct kiss_fft_state)
  1811. +        + sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/
  1812. +
  1813. +    if ( lenmem==NULL ) {
  1814. +            DEBUGF("This version of kiss fft can't use malloc");
  1815. +            return st;
  1816. +        /* st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded ); */
  1817. +    }else{
  1818. +        if (mem != NULL && *lenmem >= memneeded)
  1819. +            st = (kiss_fft_cfg)mem;
  1820. +        *lenmem = memneeded;
  1821. +    }
  1822. +    if (st) {
  1823. +                int i;
  1824. +                st->nfft=nfft;
  1825. +                st->inverse = inverse_fft;
  1826. +
  1827. +                for (i=0;i<nfft;++i) {
  1828. +                        /* const double pi=3.141592653589793238462643383279502884197169399375105820974944;
  1829. +                        double phase = -2*pi*i / nfft; */
  1830. +                        if (st->inverse)
  1831. +                                DEBUGF("Inverse FFT not implemented!"); /* kf_cexp(st->twiddles+i, -1*i, nfft ); */
  1832. +                        else
  1833. +                                kf_cexp( st->twiddles+i, i, nfft );
  1834. +                }
  1835. +
  1836. +                kf_factor(nfft,st->factors);
  1837. +        }
  1838. +    return st;
  1839. +}
  1840. +
  1841. +
  1842. +
  1843. +
  1844. +void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride)
  1845. +{
  1846. +    if (fin == fout) {
  1847. +        CHECKBUF(tmpbuf,ntmpbuf,st->nfft);
  1848. +        kf_work(tmpbuf,fin,1,in_stride, st->factors,st);
  1849. +        memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft);
  1850. +    }else{
  1851. +        kf_work( fout, fin, 1,in_stride, st->factors,st );
  1852. +    }
  1853. +}
  1854. +
  1855. +void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
  1856. +{
  1857. +    kiss_fft_stride(cfg,fin,fout,1);
  1858. +}
  1859. +
  1860. +
  1861. +/* not really necessary to call, but if someone is doing in-place ffts, they may want to free the
  1862. +   buffers from CHECKBUF
  1863. + */
  1864. +void kiss_fft_cleanup(void)
  1865. +{
  1866. +    /* free(scratchbuf); */
  1867. +    scratchbuf = NULL;
  1868. +    nscratchbuf=0;
  1869. +    /* free(tmpbuf); */
  1870. +    tmpbuf=NULL;
  1871. +    ntmpbuf=0;
  1872. +}
  1873. +
  1874. +int kiss_fft_next_fast_size(int n)
  1875. +{
  1876. +    while(1) {
  1877. +        int m=n;
  1878. +        while ( (m%2) == 0 ) m/=2;
  1879. +        while ( (m%3) == 0 ) m/=3;
  1880. +        while ( (m%5) == 0 ) m/=5;
  1881. +        if (m<=1)
  1882. +            break; /* n is completely factorable by twos, threes, and fives */
  1883. +        n++;
  1884. +    }
  1885. +    return n;
  1886. +}
  1887. diff --git a/apps/plugins/fft/kiss_fft.h b/apps/plugins/fft/kiss_fft.h
  1888. new file mode 100644
  1889. index 0000000..35c8648
  1890. --- /dev/null
  1891. +++ b/apps/plugins/fft/kiss_fft.h
  1892. @@ -0,0 +1,119 @@
  1893. +#ifndef KISS_FFT_H
  1894. +#define KISS_FFT_H
  1895. +
  1896. +#include <stdlib.h>
  1897. +#include <stdio.h>
  1898. +#include <math.h>
  1899. +#include <string.h>
  1900. +#include <malloc.h>
  1901. +#include "plugin.h"
  1902. +#include "lib/helper.h"
  1903. +
  1904. +#ifdef __cplusplus
  1905. +extern "C" {
  1906. +#endif
  1907. +
  1908. +/*
  1909. + ATTENTION!
  1910. + If you would like a :
  1911. + -- a utility that will handle the caching of fft objects
  1912. + -- real-only (no imaginary time component ) FFT
  1913. + -- a multi-dimensional FFT
  1914. + -- a command-line utility to perform ffts
  1915. + -- a command-line utility to perform fast-convolution filtering
  1916. +
  1917. + Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c
  1918. +  in the tools/ directory.
  1919. +*/
  1920. +
  1921. +#define KISS_FFT_MALLOC malloc
  1922. +
  1923. +
  1924. +#ifdef FIXED_POINT
  1925. +#include <inttypes.h>
  1926. +# if (FIXED_POINT == 32)
  1927. +#  define kiss_fft_scalar int32_t
  1928. +# else
  1929. +#  define kiss_fft_scalar int16_t
  1930. +# endif
  1931. +#else
  1932. +# ifndef kiss_fft_scalar
  1933. +/*  default is float */
  1934. +#   define kiss_fft_scalar float
  1935. +# endif
  1936. +#endif
  1937. +
  1938. +typedef struct {
  1939. +    kiss_fft_scalar r;
  1940. +    kiss_fft_scalar i;
  1941. +}kiss_fft_cpx;
  1942. +
  1943. +typedef struct kiss_fft_state* kiss_fft_cfg;
  1944. +
  1945. +/*
  1946. + *  kiss_fft_alloc
  1947. + *
  1948. + *  Initialize a FFT (or IFFT) algorithm's cfg/state buffer.
  1949. + *
  1950. + *  typical usage:      kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL);
  1951. + *
  1952. + *  The return value from fft_alloc is a cfg buffer used internally
  1953. + *  by the fft routine or NULL.
  1954. + *
  1955. + *  If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc.
  1956. + *  The returned value should be free()d when done to avoid memory leaks.
  1957. + *
  1958. + *  The state can be placed in a user supplied buffer 'mem':
  1959. + *  If lenmem is not NULL and mem is not NULL and *lenmem is large enough,
  1960. + *      then the function places the cfg in mem and the size used in *lenmem
  1961. + *      and returns mem.
  1962. + *
  1963. + *  If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough),
  1964. + *      then the function returns NULL and places the minimum cfg
  1965. + *      buffer size in *lenmem.
  1966. + * */
  1967. +
  1968. +kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem);
  1969. +
  1970. +/*
  1971. + * kiss_fft(cfg,in_out_buf)
  1972. + *
  1973. + * Perform an FFT on a complex input buffer.
  1974. + * for a forward FFT,
  1975. + * fin should be  f[0] , f[1] , ... ,f[nfft-1]
  1976. + * fout will be   F[0] , F[1] , ... ,F[nfft-1]
  1977. + * Note that each element is complex and can be accessed like
  1978. +    f[k].r and f[k].i
  1979. + * */
  1980. +void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
  1981. +
  1982. +/*
  1983. + A more generic version of the above function. It reads its input from every Nth sample.
  1984. + * */
  1985. +void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride);
  1986. +
  1987. +/* If kiss_fft_alloc allocated a buffer, it is one contiguous
  1988. +   buffer and can be simply free()d when no longer needed*/
  1989. +#define kiss_fft_free free
  1990. +
  1991. +/*
  1992. + Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up
  1993. + your compiler output to call this before you exit.
  1994. +*/
  1995. +void kiss_fft_cleanup(void);
  1996. +
  1997. +
  1998. +/*
  1999. + * Returns the smallest integer k, such that k>=n and k has only "fast" factors (2,3,5)
  2000. + */
  2001. +int kiss_fft_next_fast_size(int n);
  2002. +
  2003. +/* for real ffts, we need an even size */
  2004. +#define kiss_fftr_next_fast_size_real(n) \
  2005. +        (kiss_fft_next_fast_size( ((n)+1)>>1)<<1)
  2006. +
  2007. +#ifdef __cplusplus
  2008. +}
  2009. +#endif
  2010. +
  2011. +#endif
  2012. diff --git a/apps/plugins/fft/math.c b/apps/plugins/fft/math.c
  2013. new file mode 100644
  2014. index 0000000..15e630e
  2015. --- /dev/null
  2016. +++ b/apps/plugins/fft/math.c
  2017. @@ -0,0 +1,100 @@
  2018. +/*
  2019. + * math.c
  2020. + *
  2021. + *  Created on: Apr 7, 2009
  2022. + *      Author: archivator
  2023. + */
  2024. +
  2025. +#include "math.h"
  2026. +int16_t ilog2(int16_t i)
  2027. +/*
  2028. + Computation of 2048 * log2 ( i / 2048 )
  2029. + The admissible range for i is 1 <= i <=32767,
  2030. + the range of the result is -22528 <= ilog2 <= 8192.
  2031. + -32768 is returned for i <= 0.
  2032. + The maximum difference from the exact real value is +- 0.65
  2033. +
  2034. + Author: Hugo Pfoertner, http://www.pfoertner.org/
  2035. +
  2036. + Version history:
  2037. + 04.10.95 Check for emergency output corrected
  2038. + 02.10.95 Initial version, redesigned bearing in mind all earlier
  2039. + versions since 1985. Tables are now tuned for maximum accuracy.
  2040. + */
  2041. +{
  2042. +    /* Local variables */
  2043. +    int16_t j, v, s, d, n;
  2044. +    int32_t klong;
  2045. +
  2046. +    /*
  2047. +     The entries of the tables were obtained by an optimization procedure,
  2048. +     which shifts the "exact" values by small amounts to minimize the
  2049. +     maximum difference between the exact real value and the integer results
  2050. +     over the 32 sub-intervals of the argument interval 16384 <= i <= 32767.
  2051. +     The starting values for the optimization are
  2052. +     logtab[i] = 32768 * log2 ( 1 + i/32 ), i=0,1,...,31 and
  2053. +     logdiv[i] = 16 * ( logtab[i+1] - logtab[i] )
  2054. +     */
  2055. +    static const int16_t logtab[32] = { 11, 1465, 2877, 4248, 5578, 6873, 8134,
  2056. +            9362, 10559, 11726, 12865, 13977, 15064, 16127, 17166, 18182,
  2057. +            19177, 20152, 21107, 22043, 22961, 23861, 24745, 25613, 26464,
  2058. +            27301, 28123, 28931, 29726, 30507, 31276, 32033 };
  2059. +    static const int16_t logdiv[32] = { 23276, 22595, 21933, 21282, 20736, 20197,
  2060. +            19654, 19166, 18696, 18230, 17809, 17397, 17007, 16627, 16269,
  2061. +            15929, 15598, 15286, 14974, 14699, 14417, 14151, 13890, 13612,
  2062. +            13399, 13156, 12942, 12729, 12502, 12291, 12104, 11897 };
  2063. +
  2064. +    /* Emergency exit for illegal input */
  2065. +
  2066. +    if (i <= 0)
  2067. +        return -32768;
  2068. +
  2069. +    /*
  2070. +     Start search for matching decade beginning from the top of
  2071. +     the range, since this is the most probable case.
  2072. +     j is the result for i = integer powers of 2,
  2073. +     v lower bound of dual decade,
  2074. +     2**s is the length of the intervals for linear interpolation
  2075. +     */
  2076. +
  2077. +    j = 6144;
  2078. +    v = 16384;
  2079. +    s = 9;
  2080. +
  2081. +    /* Loop over dual "decades" */
  2082. +
  2083. +    while (i < v)
  2084. +    {
  2085. +        j -= 2048;
  2086. +        v = v >> 1;
  2087. +        s--;
  2088. +    } /* endwhile */
  2089. +
  2090. +    /* Distance from lower bound of dual decade */
  2091. +    d = i - v;
  2092. +
  2093. +    /* Check if interpolation is necessary */
  2094. +    if (s >= 0)
  2095. +    {
  2096. +        /* Determine interval n */
  2097. +        n = d >> s;
  2098. +
  2099. +        /* Compute remaining distance in interval and scale back */
  2100. +        d -= (n << s) << (9 - s);
  2101. +
  2102. +        /* Perform linear interpolation */
  2103. +        klong = logtab[n] + (d * logdiv[n] >> 13);
  2104. +
  2105. +    }
  2106. +    else
  2107. +    {
  2108. +        /* No interpolation necessary, function value is in the table */
  2109. +        n = d << -s;
  2110. +        klong = logtab[n];
  2111. +
  2112. +    } /* endif */
  2113. +
  2114. +    /* Add contribution of dual decade and scaled interpolation result */
  2115. +    return (j + (klong >> 4));
  2116. +
  2117. +} /* End of function ilog2 */
  2118. diff --git a/apps/plugins/fft/math.h b/apps/plugins/fft/math.h
  2119. new file mode 100644
  2120. index 0000000..e37807b
  2121. --- /dev/null
  2122. +++ b/apps/plugins/fft/math.h
  2123. @@ -0,0 +1,21 @@
  2124. +#ifndef __MATH_H_
  2125. +#define __MATH_H_
  2126. +
  2127. +#include <inttypes.h>
  2128. +#include <math.h>
  2129. +#include "lib/fixedpoint.h"
  2130. +
  2131. +#define Q_MUL(a, b, bits) (( (int64_t) (a) * (int64_t) (b) ) >> (bits))
  2132. +#define Q15_MUL(a, b) Q_MUL(a,b,15)
  2133. +#define Q16_MUL(a, b) Q_MUL(a,b,16)
  2134. +
  2135. +#define Q_DIV(a, b, bits) ( (((int64_t) (a)) << (bits)) / (b) )
  2136. +#define Q15_DIV(a, b) Q_DIV(a,b,15)
  2137. +#define Q16_DIV(a, b) Q_DIV(a,b,16)
  2138. +
  2139. +#define float_q(a, bits) (int32_t)( ((float)(a)) *(1<<(bits)))
  2140. +#define float_q15(a) float_q(a, 15)
  2141. +#define float_q16(a) float_q(a, 16)
  2142. +
  2143. +short ilog2(short i);
  2144. +#endif
  2145. diff --git a/firmware/export/pcm.h b/firmware/export/pcm.h
  2146. index 444e0c9..b9ad913 100644
  2147. --- a/firmware/export/pcm.h
  2148. +++ b/firmware/export/pcm.h
  2149. @@ -75,6 +75,7 @@ void pcm_play_data(pcm_more_callback_type get_more,
  2150.                    unsigned char* start, size_t size);
  2151. void pcm_calculate_peaks(int *left, int *right);
  2152. +const void* pcm_get_peak_buffer(int* count);
  2153. size_t pcm_get_bytes_waiting(void);
  2154. void pcm_play_stop(void);
  2155. diff --git a/firmware/pcm.c b/firmware/pcm.c
  2156. index bc7ec02..a4c3c94 100644
  2157. --- a/firmware/pcm.c
  2158. +++ b/firmware/pcm.c
  2159. @@ -180,6 +180,11 @@ void pcm_calculate_peaks(int *left, int *right)
  2160.         *right = peaks[1];
  2161. }
  2162. +const void* pcm_get_peak_buffer(int * count)
  2163. +{
  2164. +    return pcm_play_dma_get_peak_buffer(count);
  2165. +}
  2166. +
  2167. /****************************************************************************
  2168.  * Functions that do not require targeted implementation but only a targeted
  2169.  * interface

Update the Post

Either update this post and resubmit it with changes, or make a new post.

You may also comment on this post.

update paste below
details of the post (optional)

Note: Only the paste content is required, though the following information can be useful to others.

Save name / title?

(space separated, optional)



Please note that information posted here will expire by default in one month. If you do not want it to expire, please set the expiry time above. If it is set to expire, web search engines will not be allowed to index it prior to it expiring. Items that are not marked to expire will be indexable by search engines. Be careful with your passwords. All illegal activities will be reported and any information will be handed over to the authorities, so be good.

comments powered by Disqus
worth-right worth-right