2010-02-10 19:44:11 +00:00
|
|
|
/***************************************************************************
|
2012-12-19 01:32:23 +00:00
|
|
|
* __________ __ ___.
|
2010-02-10 19:44:11 +00:00
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
* \/ \/ \/ \/ \/
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* Copyright (C) 2009 Delyan Kratunov
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
* KIND, either express or implied.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
#include "plugin.h"
|
|
|
|
|
|
|
|
#include "lib/helper.h"
|
2012-12-19 01:32:23 +00:00
|
|
|
#include "lib/pluginlib_exit.h"
|
|
|
|
#include "lib/configfile.h"
|
2010-02-10 19:44:11 +00:00
|
|
|
#include "lib/xlcd.h"
|
|
|
|
#include "math.h"
|
2010-06-02 08:34:10 +00:00
|
|
|
#include "fracmul.h"
|
2010-02-10 19:44:11 +00:00
|
|
|
#ifndef HAVE_LCD_COLOR
|
|
|
|
#include "lib/grey.h"
|
|
|
|
#endif
|
2010-06-04 13:22:50 +00:00
|
|
|
#include "lib/mylcd.h"
|
2012-12-19 01:32:23 +00:00
|
|
|
#include "lib/osd.h"
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-08-24 14:30:46 +00:00
|
|
|
|
2010-02-10 19:44:11 +00:00
|
|
|
|
|
|
|
#ifndef HAVE_LCD_COLOR
|
|
|
|
GREY_INFO_STRUCT
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if CONFIG_KEYPAD == ARCHOS_AV300_PAD
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
2010-02-10 19:44:11 +00:00
|
|
|
# define FFT_ORIENTATION BUTTON_F3
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_WINDOW BUTTON_F1
|
|
|
|
# define FFT_AMP_SCALE BUTTON_UP
|
|
|
|
# define FFT_QUIT BUTTON_OFF
|
2013-02-22 01:14:33 +00:00
|
|
|
/* Need FFT_FREQ_SCALE key */
|
2010-02-10 19:44:11 +00:00
|
|
|
|
|
|
|
#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
|
|
|
|
(CONFIG_KEYPAD == IRIVER_H300_PAD)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
2010-02-10 19:44:11 +00:00
|
|
|
# define FFT_ORIENTATION BUTTON_REC
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_WINDOW BUTTON_SELECT
|
|
|
|
# define FFT_AMP_SCALE BUTTON_UP
|
|
|
|
# define FFT_FREQ_SCALE BUTTON_DOWN
|
|
|
|
# define FFT_QUIT BUTTON_OFF
|
2010-02-10 19:44:11 +00:00
|
|
|
|
|
|
|
#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
|
|
|
|
(CONFIG_KEYPAD == IPOD_3G_PAD) || \
|
|
|
|
(CONFIG_KEYPAD == IPOD_1G2G_PAD)
|
|
|
|
# define MINESWP_SCROLLWHEEL
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
2010-02-10 19:44:11 +00:00
|
|
|
# define FFT_ORIENTATION (BUTTON_SELECT | BUTTON_LEFT)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_WINDOW (BUTTON_SELECT | BUTTON_RIGHT)
|
|
|
|
# define FFT_AMP_SCALE BUTTON_MENU
|
|
|
|
# define FFT_FREQ_SCALE BUTTON_PLAY
|
|
|
|
# define FFT_QUIT (BUTTON_SELECT | BUTTON_MENU)
|
2010-02-10 19:44:11 +00:00
|
|
|
|
|
|
|
#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
2010-02-10 19:44:11 +00:00
|
|
|
# define FFT_ORIENTATION BUTTON_SELECT
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_WINDOW BUTTON_PLAY
|
|
|
|
# define FFT_AMP_SCALE BUTTON_UP
|
|
|
|
# define FFT_FREQ_SCALE BUTTON_DOWN
|
|
|
|
# define FFT_QUIT BUTTON_POWER
|
2010-02-10 19:44:11 +00:00
|
|
|
|
|
|
|
#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
|
|
|
# define FFT_AMP_SCALE BUTTON_UP
|
|
|
|
# define FFT_FREQ_SCALE BUTTON_DOWN
|
2010-02-10 19:44:11 +00:00
|
|
|
# define FFT_ORIENTATION BUTTON_SELECT
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_WINDOW BUTTON_A
|
|
|
|
# define FFT_QUIT BUTTON_POWER
|
2010-02-10 19:44:11 +00:00
|
|
|
|
|
|
|
#elif (CONFIG_KEYPAD == SANSA_E200_PAD)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
2010-02-10 19:44:11 +00:00
|
|
|
# define FFT_ORIENTATION BUTTON_SELECT
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_WINDOW BUTTON_REC
|
|
|
|
# define FFT_AMP_SCALE BUTTON_UP
|
|
|
|
# define FFT_FREQ_SCALE BUTTON_DOWN
|
|
|
|
# define FFT_QUIT BUTTON_POWER
|
2010-02-10 19:44:11 +00:00
|
|
|
|
|
|
|
#elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
2010-02-10 19:44:11 +00:00
|
|
|
# define FFT_ORIENTATION (BUTTON_SELECT | BUTTON_LEFT)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_WINDOW (BUTTON_SELECT | BUTTON_RIGHT)
|
|
|
|
# define FFT_AMP_SCALE BUTTON_UP
|
|
|
|
# define FFT_FREQ_SCALE BUTTON_DOWN
|
2010-06-01 09:01:13 +00:00
|
|
|
# define FFT_QUIT (BUTTON_HOME|BUTTON_REPEAT)
|
2010-02-10 19:44:11 +00:00
|
|
|
|
|
|
|
#elif (CONFIG_KEYPAD == SANSA_C200_PAD)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
2010-02-10 19:44:11 +00:00
|
|
|
# define FFT_ORIENTATION BUTTON_UP
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_WINDOW BUTTON_REC
|
|
|
|
# define FFT_AMP_SCALE BUTTON_SELECT
|
|
|
|
# define FFT_QUIT BUTTON_POWER
|
2013-02-22 01:14:33 +00:00
|
|
|
/* Need FFT_FREQ_SCALE key */
|
2010-02-10 19:44:11 +00:00
|
|
|
#elif (CONFIG_KEYPAD == SANSA_M200_PAD)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
2010-02-10 19:44:11 +00:00
|
|
|
# define FFT_ORIENTATION BUTTON_UP
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_WINDOW BUTTON_DOWN
|
|
|
|
# define FFT_AMP_SCALE BUTTON_SELECT
|
|
|
|
# define FFT_QUIT BUTTON_POWER
|
2013-02-22 01:14:33 +00:00
|
|
|
/* Need FFT_FREQ_SCALE key */
|
2010-02-10 19:44:11 +00:00
|
|
|
#elif (CONFIG_KEYPAD == SANSA_CLIP_PAD)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
2010-02-10 19:44:11 +00:00
|
|
|
# define FFT_ORIENTATION BUTTON_UP
|
2013-02-22 01:14:33 +00:00
|
|
|
# define FFT_FREQ_SCALE BUTTON_DOWN
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_WINDOW BUTTON_HOME
|
|
|
|
# define FFT_AMP_SCALE BUTTON_SELECT
|
|
|
|
# define FFT_QUIT BUTTON_POWER
|
2013-02-22 01:14:33 +00:00
|
|
|
/* Need FFT_FREQ_SCALE key */
|
2010-02-10 19:44:11 +00:00
|
|
|
#elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
|
|
|
# define FFT_ORIENTATION BUTTON_FF
|
2010-02-10 19:44:11 +00:00
|
|
|
# define FFT_WINDOW BUTTON_SCROLL_UP
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_AMP_SCALE BUTTON_REW
|
|
|
|
# define FFT_FREQ_SCALE BUTTON_PLAY
|
|
|
|
# define FFT_QUIT BUTTON_POWER
|
2010-02-10 19:44:11 +00:00
|
|
|
|
|
|
|
#elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
|
|
|
# define FFT_ORIENTATION BUTTON_MENU
|
|
|
|
# define FFT_WINDOW BUTTON_PREV
|
|
|
|
# define FFT_AMP_SCALE BUTTON_UP
|
|
|
|
# define FFT_FREQ_SCALE BUTTON_DOWN
|
|
|
|
# define FFT_QUIT BUTTON_BACK
|
2010-02-10 19:44:11 +00:00
|
|
|
|
|
|
|
#elif (CONFIG_KEYPAD == MROBE100_PAD)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
|
|
|
# define FFT_ORIENTATION BUTTON_PLAY
|
|
|
|
# define FFT_WINDOW BUTTON_SELECT
|
|
|
|
# define FFT_AMP_SCALE BUTTON_UP
|
|
|
|
# define FFT_FREQ_SCALE BUTTON_DOWN
|
|
|
|
# define FFT_QUIT BUTTON_POWER
|
2010-02-10 19:44:11 +00:00
|
|
|
|
|
|
|
#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_RC_REW
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RC_FF
|
|
|
|
# define FFT_ORIENTATION BUTTON_RC_MODE
|
|
|
|
# define FFT_WINDOW BUTTON_RC_PLAY
|
|
|
|
# define FFT_AMP_SCALE BUTTON_RC_VOL_UP
|
|
|
|
# define FFT_QUIT BUTTON_RC_REC
|
2013-02-22 01:14:33 +00:00
|
|
|
/* Need FFT_FREQ_SCALE key */
|
2010-02-10 19:44:11 +00:00
|
|
|
#elif (CONFIG_KEYPAD == COWON_D2_PAD)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_QUIT BUTTON_POWER
|
|
|
|
# define FFT_PREV_GRAPH BUTTON_PLUS
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_MINUS
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2014-03-21 21:16:02 +00:00
|
|
|
#elif CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD
|
|
|
|
# define FFT_PREV_GRAPH BUTTON_BACK
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_MENU
|
|
|
|
# define FFT_ORIENTATION (BUTTON_PLAY | BUTTON_LEFT)
|
|
|
|
# define FFT_WINDOW (BUTTON_PLAY | BUTTON_RIGHT)
|
|
|
|
# define FFT_AMP_SCALE BUTTON_UP
|
|
|
|
# define FFT_FREQ_SCALE BUTTON_DOWN
|
|
|
|
# define FFT_QUIT (BUTTON_PLAY|BUTTON_REPEAT)
|
|
|
|
|
2010-02-10 19:44:11 +00:00
|
|
|
#elif CONFIG_KEYPAD == CREATIVEZVM_PAD
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
|
|
|
# define FFT_ORIENTATION BUTTON_MENU
|
|
|
|
# define FFT_WINDOW BUTTON_SELECT
|
|
|
|
# define FFT_AMP_SCALE BUTTON_UP
|
|
|
|
# define FFT_FREQ_SCALE BUTTON_DOWN
|
|
|
|
# define FFT_QUIT BUTTON_BACK
|
2010-02-10 19:44:11 +00:00
|
|
|
|
|
|
|
#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
|
|
|
# define FFT_ORIENTATION BUTTON_SELECT
|
|
|
|
# define FFT_WINDOW BUTTON_MENU
|
|
|
|
# define FFT_AMP_SCALE BUTTON_UP
|
2010-10-21 02:45:06 +00:00
|
|
|
# define FFT_FREQ_SCALE BUTTON_DOWN
|
|
|
|
# define FFT_QUIT BUTTON_POWER
|
|
|
|
|
2010-11-02 14:36:08 +00:00
|
|
|
#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
|
|
|
|
# define FFT_PREV_GRAPH BUTTON_PREV
|
2010-11-03 03:23:14 +00:00
|
|
|
# define FFT_NEXT_GRAPH BUTTON_NEXT
|
2010-11-02 14:36:08 +00:00
|
|
|
# define FFT_ORIENTATION BUTTON_PLAY
|
|
|
|
# define FFT_WINDOW BUTTON_MENU
|
|
|
|
# define FFT_AMP_SCALE BUTTON_UP
|
|
|
|
# define FFT_FREQ_SCALE BUTTON_DOWN
|
|
|
|
# define FFT_QUIT BUTTON_POWER
|
|
|
|
|
2010-10-21 02:45:06 +00:00
|
|
|
#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
|
|
|
|
# define FFT_PREV_GRAPH BUTTON_PREV
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_NEXT
|
|
|
|
# define FFT_ORIENTATION BUTTON_PLAY
|
|
|
|
# define FFT_WINDOW BUTTON_MENU
|
|
|
|
# define FFT_AMP_SCALE BUTTON_UP
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_FREQ_SCALE BUTTON_DOWN
|
|
|
|
# define FFT_QUIT BUTTON_POWER
|
2010-02-10 19:44:11 +00:00
|
|
|
|
|
|
|
#elif (CONFIG_KEYPAD == SAMSUNG_YH_PAD)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
2010-02-10 19:44:11 +00:00
|
|
|
# define FFT_ORIENTATION BUTTON_UP
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_WINDOW BUTTON_DOWN
|
|
|
|
# define FFT_AMP_SCALE BUTTON_FFWD
|
|
|
|
# define FFT_QUIT BUTTON_PLAY
|
2013-02-22 01:14:33 +00:00
|
|
|
/* Need FFT_FREQ_SCALE key */
|
2010-02-11 23:27:44 +00:00
|
|
|
#elif (CONFIG_KEYPAD == MROBE500_PAD)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_QUIT BUTTON_POWER
|
2010-02-11 23:27:44 +00:00
|
|
|
|
|
|
|
#elif (CONFIG_KEYPAD == ONDAVX747_PAD)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_QUIT BUTTON_POWER
|
2010-02-11 23:27:44 +00:00
|
|
|
|
|
|
|
#elif (CONFIG_KEYPAD == ONDAVX777_PAD)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_QUIT BUTTON_POWER
|
2010-02-11 23:27:44 +00:00
|
|
|
|
2010-02-14 21:56:53 +00:00
|
|
|
#elif (CONFIG_KEYPAD == PBELL_VIBE500_PAD)
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_PREV
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_NEXT
|
|
|
|
# define FFT_ORIENTATION BUTTON_MENU
|
|
|
|
# define FFT_WINDOW BUTTON_OK
|
|
|
|
# define FFT_AMP_SCALE BUTTON_PLAY
|
|
|
|
# define FFT_QUIT BUTTON_REC
|
2013-02-22 01:14:33 +00:00
|
|
|
/* Need FFT_FREQ_SCALE key */
|
2010-04-26 21:40:00 +00:00
|
|
|
#elif CONFIG_KEYPAD == MPIO_HD200_PAD
|
2010-11-02 10:44:34 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_REW
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_FF
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_ORIENTATION BUTTON_REC
|
2010-11-02 10:44:34 +00:00
|
|
|
# define FFT_WINDOW BUTTON_FUNC
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_AMP_SCALE BUTTON_PLAY
|
|
|
|
# define FFT_QUIT (BUTTON_REC | BUTTON_PLAY)
|
2013-02-22 01:14:33 +00:00
|
|
|
/* Need FFT_FREQ_SCALE key */
|
2010-11-30 10:52:14 +00:00
|
|
|
#elif CONFIG_KEYPAD == MPIO_HD300_PAD
|
|
|
|
# define FFT_PREV_GRAPH BUTTON_REW
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_FF
|
|
|
|
# define FFT_ORIENTATION BUTTON_REC
|
|
|
|
# define FFT_WINDOW BUTTON_ENTER
|
|
|
|
# define FFT_AMP_SCALE BUTTON_PLAY
|
|
|
|
# define FFT_QUIT (BUTTON_REC | BUTTON_REPEAT)
|
2013-02-22 01:14:33 +00:00
|
|
|
/* Need FFT_FREQ_SCALE key */
|
2011-10-02 17:34:47 +00:00
|
|
|
#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
|
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
2012-02-26 00:29:20 +00:00
|
|
|
# define FFT_ORIENTATION BUTTON_PLAYPAUSE
|
2011-10-02 17:34:47 +00:00
|
|
|
# define FFT_WINDOW BUTTON_SELECT
|
2012-02-26 00:29:20 +00:00
|
|
|
# define FFT_AMP_SCALE BUTTON_BOTTOMLEFT
|
|
|
|
# define FFT_FREQ_SCALE BUTTON_BOTTOMRIGHT
|
2011-10-02 17:34:47 +00:00
|
|
|
# define FFT_QUIT BUTTON_POWER
|
|
|
|
|
2011-11-16 14:08:01 +00:00
|
|
|
#elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
|
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
|
|
|
# define FFT_ORIENTATION BUTTON_SELECT
|
|
|
|
# define FFT_WINDOW BUTTON_VOL_DOWN
|
|
|
|
# define FFT_AMP_SCALE BUTTON_UP
|
|
|
|
# define FFT_FREQ_SCALE BUTTON_DOWN
|
|
|
|
# define FFT_QUIT BUTTON_POWER
|
|
|
|
|
Initial commit of the Samsung YP-R0 port.
This port is a hybrid native/RaaA port. It runs on a embedded linux system,
but is the only application. It therefore can implement lots of stuff that
native targets also implement, while leveraging the underlying linux kernel.
The port is quite advanced. User interface, audio playback, plugins work
mostly fine. Missing is e.g. power mangement and USB (see SamsungYPR0 wiki page).
Included in utils/ypr0tools are scripts and programs required to generate
a patched firmware. The patched firmware has the rootfs modified to load
Rockbox. It includes a early/safe USB mode.
This port needs a new toolchain, one that includes glibc headers and libraries.
rockboxdev.sh can generate it, but e.g. codesourcey and distro packages may
also work.
Most of the initial effort is done by Lorenzo Miori and others (on ABI),
including reverse engineering and patching of the original firmware,
initial drivers, and more. Big thanks to you.
Flyspray: FS#12348
Author: Lorenzo Miori, myself
Merry christmas to ypr0 owners! :)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31415 a1c6a512-1295-4272-9138-f99709370657
2011-12-24 11:56:46 +00:00
|
|
|
#elif CONFIG_KEYPAD == SAMSUNG_YPR0_PAD
|
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
|
|
|
# define FFT_ORIENTATION BUTTON_USER
|
|
|
|
# define FFT_WINDOW BUTTON_MENU
|
|
|
|
# define FFT_AMP_SCALE BUTTON_SELECT
|
|
|
|
# define FFT_FREQ_SCALE BUTTON_DOWN
|
|
|
|
# define FFT_QUIT BUTTON_BACK
|
|
|
|
|
2012-03-23 18:32:50 +00:00
|
|
|
#elif (CONFIG_KEYPAD == HM60X_PAD)
|
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
|
|
|
# define FFT_AMP_SCALE BUTTON_UP
|
|
|
|
# define FFT_FREQ_SCALE BUTTON_DOWN
|
|
|
|
# define FFT_ORIENTATION BUTTON_SELECT
|
|
|
|
# define FFT_WINDOW (BUTTON_POWER|BUTTON_SELECT)
|
|
|
|
# define FFT_QUIT BUTTON_POWER
|
|
|
|
|
2012-04-06 16:17:27 +00:00
|
|
|
#elif (CONFIG_KEYPAD == HM801_PAD)
|
|
|
|
# define FFT_PREV_GRAPH BUTTON_LEFT
|
|
|
|
# define FFT_NEXT_GRAPH BUTTON_RIGHT
|
|
|
|
# define FFT_AMP_SCALE BUTTON_UP
|
|
|
|
# define FFT_FREQ_SCALE BUTTON_DOWN
|
|
|
|
# define FFT_ORIENTATION BUTTON_SELECT
|
|
|
|
# define FFT_WINDOW BUTTON_PLAY
|
|
|
|
# define FFT_QUIT BUTTON_POWER
|
|
|
|
|
2012-01-26 22:59:23 +00:00
|
|
|
#elif !defined(HAVE_TOUCHSCREEN)
|
2010-02-10 19:44:11 +00:00
|
|
|
#error No keymap defined!
|
|
|
|
#endif
|
|
|
|
|
2010-02-11 23:10:09 +00:00
|
|
|
#ifdef HAVE_TOUCHSCREEN
|
|
|
|
#ifndef FFT_PREV_GRAPH
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_PREV_GRAPH BUTTON_MIDLEFT
|
2010-02-11 23:10:09 +00:00
|
|
|
#endif
|
|
|
|
#ifndef FFT_NEXT_GRAPH
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_NEXT_GRAPH BUTTON_MIDRIGHT
|
2010-02-11 23:10:09 +00:00
|
|
|
#endif
|
|
|
|
#ifndef FFT_ORIENTATION
|
|
|
|
# define FFT_ORIENTATION BUTTON_CENTER
|
|
|
|
#endif
|
|
|
|
#ifndef FFT_WINDOW
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_WINDOW BUTTON_TOPLEFT
|
2010-02-11 23:10:09 +00:00
|
|
|
#endif
|
2010-06-02 08:34:10 +00:00
|
|
|
#ifndef FFT_AMP_SCALE
|
|
|
|
# define FFT_AMP_SCALE BUTTON_TOPRIGHT
|
2010-02-11 23:10:09 +00:00
|
|
|
#endif
|
|
|
|
#ifndef FFT_QUIT
|
2010-06-02 08:34:10 +00:00
|
|
|
# define FFT_QUIT BUTTON_BOTTOMLEFT
|
2010-02-11 23:10:09 +00:00
|
|
|
#endif
|
2013-02-22 01:14:33 +00:00
|
|
|
/* Need FFT_FREQ_SCALE key */
|
2010-06-02 08:34:10 +00:00
|
|
|
#endif /* HAVE_TOUCHSCREEN */
|
2010-02-11 23:10:09 +00:00
|
|
|
|
2010-02-10 19:44:11 +00:00
|
|
|
#ifdef HAVE_LCD_COLOR
|
|
|
|
#include "pluginbitmaps/fft_colors.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "kiss_fftr.h"
|
|
|
|
#include "_kiss_fft_guts.h" /* sizeof(struct kiss_fft_state) */
|
|
|
|
#include "const.h"
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
|
|
|
|
/******************************* FFT globals *******************************/
|
|
|
|
|
2010-06-03 08:55:36 +00:00
|
|
|
#define LCD_SIZE MAX(LCD_WIDTH, LCD_HEIGHT)
|
2010-02-12 00:07:00 +00:00
|
|
|
|
2010-06-03 08:55:36 +00:00
|
|
|
#if (LCD_SIZE <= 511)
|
|
|
|
#define FFT_SIZE 1024 /* 512*2 */
|
|
|
|
#elif (LCD_SIZE <= 1023)
|
|
|
|
#define FFT_SIZE 2048 /* 1024*2 */
|
2010-02-12 00:07:00 +00:00
|
|
|
#else
|
2010-06-03 08:55:36 +00:00
|
|
|
#define FFT_SIZE 4096 /* 2048*2 */
|
2010-02-12 00:07:00 +00:00
|
|
|
#endif
|
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
#define ARRAYLEN_IN (FFT_SIZE)
|
2010-06-03 08:55:36 +00:00
|
|
|
#define ARRAYLEN_OUT (FFT_SIZE)
|
|
|
|
#define ARRAYLEN_PLOT (FFT_SIZE/2-1) /* FFT is symmetric, ignore DC */
|
2012-12-19 01:32:23 +00:00
|
|
|
#define BUFSIZE_FFT (sizeof(struct kiss_fft_state)+\
|
|
|
|
sizeof(kiss_fft_cpx)*(FFT_SIZE-1))
|
2010-02-10 19:44:11 +00:00
|
|
|
|
|
|
|
#define __COEFF(type,size) type##_##size
|
2012-12-19 01:32:23 +00:00
|
|
|
#define _COEFF(x, y) __COEFF(x,y) /* force CPP evaluation of FFT_SIZE */
|
2010-02-10 19:44:11 +00:00
|
|
|
#define HANN_COEFF _COEFF(hann, FFT_SIZE)
|
|
|
|
#define HAMMING_COEFF _COEFF(hamming, FFT_SIZE)
|
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
/* cacheline-aligned buffers with COP, otherwise word-aligned */
|
2010-06-03 00:59:05 +00:00
|
|
|
/* CPU/COP only applies when compiled for more than one core */
|
2010-06-02 08:34:10 +00:00
|
|
|
|
|
|
|
#define CACHEALIGN_UP_SIZE(type, len) \
|
|
|
|
(CACHEALIGN_UP((len)*sizeof(type) + (sizeof(type)-1)) / sizeof(type))
|
|
|
|
/* Shared */
|
|
|
|
/* COP + CPU PCM */
|
2010-06-03 08:55:36 +00:00
|
|
|
static kiss_fft_cpx input[CACHEALIGN_UP_SIZE(kiss_fft_scalar, ARRAYLEN_IN)]
|
2010-06-02 08:34:10 +00:00
|
|
|
CACHEALIGN_AT_LEAST_ATTR(4);
|
|
|
|
/* CPU+COP */
|
2010-06-03 00:59:05 +00:00
|
|
|
#if NUM_CORES > 1
|
|
|
|
/* Output queue indexes */
|
|
|
|
static volatile int output_head SHAREDBSS_ATTR = 0;
|
|
|
|
static volatile int output_tail SHAREDBSS_ATTR = 0;
|
2010-06-03 08:55:36 +00:00
|
|
|
/* The result is nfft/2 complex frequency bins from DC to Nyquist. */
|
|
|
|
static kiss_fft_cpx output[2][CACHEALIGN_UP_SIZE(kiss_fft_cpx, ARRAYLEN_OUT)]
|
2010-06-03 00:59:05 +00:00
|
|
|
SHAREDBSS_ATTR;
|
|
|
|
#else
|
|
|
|
/* Only one output buffer */
|
|
|
|
#define output_head 0
|
|
|
|
#define output_tail 0
|
2010-06-03 08:55:36 +00:00
|
|
|
/* The result is nfft/2 complex frequency bins from DC to Nyquist. */
|
|
|
|
static kiss_fft_cpx output[1][ARRAYLEN_OUT];
|
2010-06-03 00:59:05 +00:00
|
|
|
#endif
|
2010-06-02 08:34:10 +00:00
|
|
|
|
|
|
|
/* Unshared */
|
|
|
|
/* COP */
|
2010-06-03 08:55:36 +00:00
|
|
|
static kiss_fft_cfg fft_state SHAREDBSS_ATTR;
|
|
|
|
static char fft_buffer[CACHEALIGN_UP_SIZE(char, BUFSIZE_FFT)]
|
2010-06-02 08:34:10 +00:00
|
|
|
CACHEALIGN_AT_LEAST_ATTR(4);
|
|
|
|
/* CPU */
|
2012-12-19 01:32:23 +00:00
|
|
|
static uint32_t linf_magnitudes[ARRAYLEN_PLOT]; /* ling freq bin plot */
|
|
|
|
static uint32_t logf_magnitudes[ARRAYLEN_PLOT]; /* log freq plot output */
|
|
|
|
static uint32_t *plot; /* use this to plot */
|
2010-06-02 08:34:10 +00:00
|
|
|
static struct
|
|
|
|
{
|
|
|
|
int16_t bin; /* integer bin number */
|
|
|
|
uint16_t frac; /* interpolation fraction */
|
|
|
|
} binlog[ARRAYLEN_PLOT] __attribute__((aligned(4)));
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
/**************************** End of FFT globals ***************************/
|
|
|
|
|
|
|
|
|
|
|
|
/********************************* Settings ********************************/
|
|
|
|
|
|
|
|
enum fft_orientation
|
2010-06-02 08:34:10 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
FFT_MIN_OR = 0,
|
|
|
|
FFT_OR_VERT = 0, /* Amplitude vertical, frequency horizontal * */
|
|
|
|
FFT_OR_HORZ, /* Amplitude horizontal, frequency vertical */
|
|
|
|
FFT_MAX_OR,
|
2010-06-02 08:34:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum fft_display_mode
|
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
FFT_MIN_DM = 0,
|
|
|
|
FFT_DM_LINES = 0, /* Bands are displayed as single-pixel lines * */
|
|
|
|
FFT_DM_BARS, /* Bands are combined into wide bars */
|
|
|
|
FFT_DM_SPECTROGRAM, /* Band amplitudes are denoted by color */
|
|
|
|
FFT_MAX_DM,
|
2010-06-02 08:34:10 +00:00
|
|
|
};
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
enum fft_amp_scale
|
|
|
|
{
|
|
|
|
FFT_MIN_AS = 0,
|
|
|
|
FFT_AS_LOG = 0, /* Amplitude is plotted on log scale * */
|
|
|
|
FFT_AS_LIN, /* Amplitude is plotted on linear scale */
|
|
|
|
FFT_MAX_AS,
|
|
|
|
};
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
enum fft_freq_scale
|
|
|
|
{
|
|
|
|
FFT_MIN_FS = 0,
|
|
|
|
FFT_FS_LOG = 0, /* Frequency is plotted on log scale * */
|
|
|
|
FFT_FS_LIN, /* Frequency is plotted on linear scale */
|
|
|
|
FFT_MAX_FS
|
|
|
|
};
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
enum fft_window_func
|
|
|
|
{
|
|
|
|
FFT_MIN_WF = 0,
|
|
|
|
FFT_WF_HAMMING = 0, /* Hamming window applied to each input frame * */
|
|
|
|
FFT_WF_HANN, /* Hann window applied to each input frame */
|
|
|
|
FFT_MAX_WF,
|
|
|
|
};
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
static struct fft_config
|
|
|
|
{
|
|
|
|
int orientation;
|
|
|
|
int drawmode;
|
|
|
|
int amp_scale;
|
|
|
|
int freq_scale;
|
|
|
|
int window_func;
|
|
|
|
} fft_disk =
|
2010-06-02 08:34:10 +00:00
|
|
|
{
|
|
|
|
/* Defaults */
|
2012-12-19 01:32:23 +00:00
|
|
|
.orientation = FFT_OR_VERT,
|
|
|
|
.drawmode = FFT_DM_LINES,
|
|
|
|
.amp_scale = FFT_AS_LOG,
|
|
|
|
.freq_scale = FFT_FS_LOG,
|
|
|
|
.window_func = FFT_WF_HAMMING,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define CFGFILE_VERSION 0
|
|
|
|
#define CFGFILE_MINVERSION 0
|
|
|
|
|
|
|
|
static const char cfg_filename[] = "fft.cfg";
|
|
|
|
static struct configdata disk_config[] =
|
|
|
|
{
|
|
|
|
{ TYPE_ENUM, FFT_MIN_OR, FFT_MAX_OR,
|
|
|
|
{ .int_p = &fft_disk.orientation }, "orientation",
|
|
|
|
(char * []){ [FFT_OR_VERT] = "vertical",
|
|
|
|
[FFT_OR_HORZ] = "horizontal" } },
|
|
|
|
{ TYPE_ENUM, FFT_MIN_DM, FFT_MAX_DM,
|
|
|
|
{ .int_p = &fft_disk.drawmode }, "drawmode",
|
|
|
|
(char * []){ [FFT_DM_LINES] = "lines",
|
|
|
|
[FFT_DM_BARS] = "bars",
|
|
|
|
[FFT_DM_SPECTROGRAM] = "spectrogram" } },
|
|
|
|
{ TYPE_ENUM, FFT_MIN_AS, FFT_MAX_AS,
|
|
|
|
{ .int_p = &fft_disk.amp_scale }, "amp scale",
|
|
|
|
(char * []){ [FFT_AS_LOG] = "logarithmic",
|
|
|
|
[FFT_AS_LIN] = "linear" } },
|
|
|
|
{ TYPE_ENUM, FFT_MIN_FS, FFT_MAX_FS,
|
|
|
|
{ .int_p = &fft_disk.freq_scale }, "freq scale",
|
|
|
|
(char * []){ [FFT_FS_LOG] = "logarithmic",
|
|
|
|
[FFT_FS_LIN] = "linear" } },
|
|
|
|
{ TYPE_ENUM, FFT_MIN_WF, FFT_MAX_WF,
|
|
|
|
{ .int_p = &fft_disk.window_func }, "window function",
|
|
|
|
(char * []){ [FFT_WF_HAMMING] = "hamming",
|
|
|
|
[FFT_WF_HANN] = "hann" } },
|
2010-06-02 08:34:10 +00:00
|
|
|
};
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
/* Hint flags for setting changes */
|
|
|
|
enum fft_setting_flags
|
|
|
|
{
|
|
|
|
FFT_SETF_OR = 1 << 0,
|
|
|
|
FFT_SETF_DM = 1 << 1,
|
|
|
|
FFT_SETF_AS = 1 << 2,
|
|
|
|
FFT_SETF_FS = 1 << 3,
|
|
|
|
FFT_SETF_WF = 1 << 4,
|
|
|
|
FFT_SETF_ALL = 0x1f
|
|
|
|
};
|
|
|
|
|
|
|
|
/***************************** End of settings *****************************/
|
|
|
|
|
|
|
|
|
|
|
|
/**************************** Operational data *****************************/
|
|
|
|
|
|
|
|
#define COLOR_DEFAULT_FG MYLCD_DEFAULT_FG
|
|
|
|
#define COLOR_DEFAULT_BG MYLCD_DEFAULT_BG
|
|
|
|
|
|
|
|
#ifdef HAVE_LCD_COLOR
|
|
|
|
#define COLOR_MESSAGE_FRAME LCD_RGBPACK(0xc6, 0x00, 0x00)
|
|
|
|
#define COLOR_MESSAGE_BG LCD_BLACK
|
|
|
|
#define COLOR_MESSAGE_FG LCD_WHITE
|
|
|
|
#else
|
|
|
|
#define COLOR_MESSAGE_FRAME GREY_DARKGRAY
|
|
|
|
#define COLOR_MESSAGE_BG GREY_WHITE
|
|
|
|
#define COLOR_MESSAGE_FG GREY_BLACK
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define FFT_OSD_MARGIN_SIZE 1
|
|
|
|
|
|
|
|
#define FFT_PERIOD (HZ/50) /* How fast to try to go */
|
|
|
|
|
|
|
|
/* Based on feeding-in a 0db sinewave at FS/4 */
|
|
|
|
#define QLOG_MAX 0x0009154B
|
|
|
|
/* Fudge it a little or it's not very visbile */
|
|
|
|
#define QLIN_MAX (0x00002266 >> 1)
|
|
|
|
|
|
|
|
static struct fft_config fft;
|
|
|
|
typedef void (* fft_drawfn_t)(unsigned, unsigned);
|
|
|
|
static fft_drawfn_t fft_drawfn = NULL; /* plotting function */
|
|
|
|
static int fft_spectrogram_pos = -1; /* row or column - only used by one at a time */
|
|
|
|
static uint32_t fft_graph_scale = 0; /* max level over time, for scaling display */
|
|
|
|
static int fft_message_id = -1; /* current message id displayed */
|
|
|
|
static char fft_osd_message[32]; /* current message string displayed */
|
|
|
|
static long fft_next_frame_tick = 0; /* next tick to attempt drawing */
|
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
#ifdef HAVE_LCD_COLOR
|
|
|
|
#define SHADES BMPWIDTH_fft_colors
|
|
|
|
#define SPECTROGRAPH_PALETTE(index) (fft_colors[index])
|
|
|
|
#else
|
|
|
|
#define SHADES 256
|
|
|
|
#define SPECTROGRAPH_PALETTE(index) (255 - (index))
|
|
|
|
#endif
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
/************************* End of operational data *************************/
|
2010-02-10 19:44:11 +00:00
|
|
|
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
/***************************** Math functions ******************************/
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
/* Apply window function to input */
|
2010-06-03 01:38:50 +00:00
|
|
|
static void apply_window_func(enum fft_window_func mode)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
static const int16_t * const coefs[] =
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
[FFT_WF_HAMMING] = HAMMING_COEFF,
|
|
|
|
[FFT_WF_HANN] = HANN_COEFF,
|
|
|
|
};
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
const int16_t * const c = coefs[mode];
|
|
|
|
|
|
|
|
for(int i = 0; i < ARRAYLEN_IN; ++i)
|
|
|
|
input[i].r = (input[i].r * c[i] + 16384) >> 15;
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculates the magnitudes from complex numbers and returns the maximum */
|
2012-12-19 01:32:23 +00:00
|
|
|
static unsigned calc_magnitudes(enum fft_amp_scale scale)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2010-05-02 20:30:44 +00:00
|
|
|
/* A major assumption made when calculating the Q*MAX constants
|
|
|
|
* is that the maximum magnitude is 29 bits long. */
|
2012-12-19 01:32:23 +00:00
|
|
|
unsigned this_max = 0;
|
2010-06-02 08:34:10 +00:00
|
|
|
kiss_fft_cpx *this_output = output[output_head] + 1; /* skip DC */
|
2010-05-02 20:30:44 +00:00
|
|
|
|
|
|
|
/* Calculate the magnitude, discarding the phase. */
|
2012-12-19 01:32:23 +00:00
|
|
|
for(int i = 0; i < ARRAYLEN_PLOT; ++i)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2010-06-02 08:34:10 +00:00
|
|
|
int32_t re = this_output[i].r;
|
|
|
|
int32_t im = this_output[i].i;
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
uint32_t d = re*re + im*im;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
if(d > 0)
|
2010-05-02 20:30:44 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
if(d > 0x7FFFFFFF) /* clip */
|
2010-06-02 08:34:10 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
d = 0x7FFFFFFF; /* if our assumptions are correct,
|
|
|
|
this should never happen. It's just
|
|
|
|
a safeguard. */
|
2010-06-02 08:34:10 +00:00
|
|
|
}
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
if(scale == FFT_AS_LOG)
|
2010-06-02 08:34:10 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
if(d < 0x8000) /* be more precise */
|
2010-06-02 08:34:10 +00:00
|
|
|
{
|
|
|
|
/* ln(x ^ .5) = .5*ln(x) */
|
2012-12-19 01:32:23 +00:00
|
|
|
d = fp16_log(d << 16) >> 1;
|
2010-06-02 08:34:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
d = isqrt(d); /* linear scaling, nothing
|
|
|
|
bad should happen */
|
|
|
|
d = fp16_log(d << 16); /* the log function
|
|
|
|
expects s15.16 values */
|
2010-06-02 08:34:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
d = isqrt(d); /* linear scaling, nothing
|
|
|
|
bad should happen */
|
2010-06-02 08:34:10 +00:00
|
|
|
}
|
2010-05-02 20:30:44 +00:00
|
|
|
}
|
2010-06-02 08:34:10 +00:00
|
|
|
|
|
|
|
/* Length 2 moving average - last transform and this one */
|
2012-12-19 01:32:23 +00:00
|
|
|
linf_magnitudes[i] = (linf_magnitudes[i] + d) >> 1;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
if(d > this_max)
|
|
|
|
this_max = d;
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
return this_max;
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
2010-06-02 08:34:10 +00:00
|
|
|
|
|
|
|
/* Move plot bins into a logarithmic scale by sliding them towards the
|
|
|
|
* Nyquist bin according to the translation in the binlog array. */
|
2012-12-19 01:32:23 +00:00
|
|
|
static void log_plot_translate(void)
|
2010-06-02 08:34:10 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
for(int i = ARRAYLEN_PLOT-1; i > 0; --i)
|
2010-06-02 08:34:10 +00:00
|
|
|
{
|
|
|
|
int s = binlog[i].bin;
|
|
|
|
int e = binlog[i-1].bin;
|
2012-12-19 01:32:23 +00:00
|
|
|
unsigned frac = binlog[i].frac;
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
int bin = linf_magnitudes[s];
|
2010-06-02 08:34:10 +00:00
|
|
|
|
|
|
|
if(frac)
|
|
|
|
{
|
|
|
|
/* slope < 1, Interpolate stretched bins (linear for now) */
|
2012-12-19 01:32:23 +00:00
|
|
|
int diff = linf_magnitudes[s+1] - bin;
|
2010-06-02 08:34:10 +00:00
|
|
|
|
|
|
|
do
|
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
logf_magnitudes[i] = bin + FRACMUL(frac << 15, diff);
|
2010-06-02 08:34:10 +00:00
|
|
|
frac = binlog[--i].frac;
|
|
|
|
}
|
|
|
|
while(frac);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* slope > 1, Find peak of two or more bins */
|
|
|
|
while(--s > e)
|
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
int val = linf_magnitudes[s];
|
2010-06-02 08:34:10 +00:00
|
|
|
|
|
|
|
if (val > bin)
|
|
|
|
bin = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
logf_magnitudes[i] = bin;
|
2010-06-02 08:34:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculates the translation for logarithmic plot bins */
|
2010-06-03 01:38:50 +00:00
|
|
|
static void logarithmic_plot_init(void)
|
2010-06-02 08:34:10 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* log: y = round(n * ln(x) / ln(n))
|
|
|
|
* anti: y = round(exp(x * ln(n) / n))
|
|
|
|
*/
|
2012-12-19 01:32:23 +00:00
|
|
|
int j = fp16_log((ARRAYLEN_PLOT - 1) << 16);
|
|
|
|
for(int i = 0; i < ARRAYLEN_PLOT; ++i)
|
2010-06-02 08:34:10 +00:00
|
|
|
{
|
|
|
|
binlog[i].bin = (fp16_exp(i * j / (ARRAYLEN_PLOT - 1)) + 32768) >> 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* setup fractions for interpolation of stretched bins */
|
2012-12-19 01:32:23 +00:00
|
|
|
for(int i = 0; i < ARRAYLEN_PLOT-1; i = j)
|
2010-06-02 08:34:10 +00:00
|
|
|
{
|
|
|
|
j = i + 1;
|
|
|
|
|
|
|
|
/* stop when we have two different values */
|
|
|
|
while(binlog[j].bin == binlog[i].bin)
|
|
|
|
j++; /* if here, local slope of curve is < 1 */
|
|
|
|
|
|
|
|
if(j > i + 1)
|
|
|
|
{
|
|
|
|
/* distribute pieces evenly over stretched interval */
|
|
|
|
int diff = j - i;
|
|
|
|
int x = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
binlog[i].frac = (x++ << 16) / diff;
|
|
|
|
}
|
|
|
|
while(++i < j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
/************************** End of math functions **************************/
|
2010-02-10 19:44:11 +00:00
|
|
|
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
/*********************** Plotting functions (modes) ************************/
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
static void draw_lines_vertical(unsigned this_max, unsigned graph_max)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2010-06-02 08:34:10 +00:00
|
|
|
#if LCD_WIDTH < ARRAYLEN_PLOT /* graph compression */
|
|
|
|
const int offset = 0;
|
|
|
|
const int plotwidth = LCD_WIDTH;
|
|
|
|
#else
|
|
|
|
const int offset = (LCD_HEIGHT - ARRAYLEN_PLOT) / 2;
|
|
|
|
const int plotwidth = ARRAYLEN_PLOT;
|
|
|
|
#endif
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
mylcd_clear_display();
|
2010-06-02 08:34:10 +00:00
|
|
|
|
|
|
|
if(this_max == 0)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2010-06-04 08:43:32 +00:00
|
|
|
mylcd_hline(0, LCD_WIDTH - 1, LCD_HEIGHT - 1); /* Draw all "zero" */
|
2010-06-02 08:34:10 +00:00
|
|
|
return;
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
/* take the maximum of neighboring bins if we have to scale down the
|
|
|
|
* graph horizontally */
|
2010-06-02 08:34:10 +00:00
|
|
|
if(LCD_WIDTH < ARRAYLEN_PLOT) /* graph compression */
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2010-06-02 08:34:10 +00:00
|
|
|
int bins_acc = LCD_WIDTH / 2;
|
2012-12-19 01:32:23 +00:00
|
|
|
unsigned bins_max = 0;
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
for(int i = 0, x = 0; i < ARRAYLEN_PLOT; ++i)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
unsigned bin = plot[i];
|
2010-06-02 08:34:10 +00:00
|
|
|
|
|
|
|
if(bin > bins_max)
|
|
|
|
bins_max = bin;
|
|
|
|
|
|
|
|
bins_acc += LCD_WIDTH;
|
|
|
|
|
|
|
|
if(bins_acc >= ARRAYLEN_PLOT)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
int h = LCD_HEIGHT*bins_max / graph_max;
|
|
|
|
mylcd_vline(x, LCD_HEIGHT - h, LCD_HEIGHT-1);
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
x++;
|
2010-06-02 08:34:10 +00:00
|
|
|
bins_acc -= ARRAYLEN_PLOT;
|
|
|
|
bins_max = 0;
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-02 08:34:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
for(int i = 0; i < plotwidth; ++i)
|
|
|
|
{
|
|
|
|
int h = LCD_HEIGHT*plot[i] / graph_max;
|
|
|
|
mylcd_vline(i + offset, LCD_HEIGHT - h, LCD_HEIGHT-1);
|
|
|
|
}
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
static void draw_lines_horizontal(unsigned this_max, unsigned graph_max)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2010-06-02 08:34:10 +00:00
|
|
|
#if LCD_WIDTH < ARRAYLEN_PLOT /* graph compression */
|
|
|
|
const int offset = 0;
|
|
|
|
const int plotwidth = LCD_HEIGHT;
|
|
|
|
#else
|
|
|
|
const int offset = (LCD_HEIGHT - ARRAYLEN_PLOT) / 2;
|
|
|
|
const int plotwidth = ARRAYLEN_PLOT;
|
|
|
|
#endif
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
mylcd_clear_display();
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
if(this_max == 0)
|
|
|
|
{
|
2010-06-04 08:43:32 +00:00
|
|
|
mylcd_vline(0, 0, LCD_HEIGHT-1); /* Draw all "zero" */
|
2010-02-10 19:44:11 +00:00
|
|
|
return;
|
2010-06-02 08:34:10 +00:00
|
|
|
}
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
/* take the maximum of neighboring bins if we have to scale the graph
|
|
|
|
* horizontally */
|
|
|
|
if(LCD_HEIGHT < ARRAYLEN_PLOT) /* graph compression */
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2010-06-02 08:34:10 +00:00
|
|
|
int bins_acc = LCD_HEIGHT / 2;
|
2012-12-19 01:32:23 +00:00
|
|
|
unsigned bins_max = 0;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
for(int i = 0, y = 0; i < ARRAYLEN_PLOT; ++i)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
unsigned bin = plot[i];
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
if(bin > bins_max)
|
2010-06-02 08:34:10 +00:00
|
|
|
bins_max = bin;
|
|
|
|
|
|
|
|
bins_acc += LCD_HEIGHT;
|
|
|
|
|
|
|
|
if(bins_acc >= ARRAYLEN_PLOT)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
int w = LCD_WIDTH*bins_max / graph_max;
|
|
|
|
mylcd_hline(0, w - 1, y);
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
y++;
|
2010-06-02 08:34:10 +00:00
|
|
|
bins_acc -= ARRAYLEN_PLOT;
|
|
|
|
bins_max = 0;
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-02 08:34:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
for(int i = 0; i < plotwidth; ++i)
|
|
|
|
{
|
|
|
|
int w = LCD_WIDTH*plot[i] / graph_max;
|
|
|
|
mylcd_hline(0, w - 1, i + offset);
|
|
|
|
}
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
static void draw_bars_vertical(unsigned this_max, unsigned graph_max)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2010-06-02 08:34:10 +00:00
|
|
|
#if LCD_WIDTH < LCD_HEIGHT
|
|
|
|
const int bars = 15;
|
|
|
|
#else
|
|
|
|
const int bars = 20;
|
|
|
|
#endif
|
|
|
|
const int border = 2;
|
|
|
|
const int barwidth = LCD_WIDTH / (bars + border);
|
|
|
|
const int width = barwidth - border;
|
2012-12-19 01:32:23 +00:00
|
|
|
const int offset = (LCD_WIDTH - bars*barwidth + border) / 2;
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
mylcd_clear_display();
|
2010-06-04 08:43:32 +00:00
|
|
|
mylcd_hline(0, LCD_WIDTH-1, LCD_HEIGHT-1); /* Draw baseline */
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
if(this_max == 0)
|
2010-06-02 08:34:10 +00:00
|
|
|
return; /* nothing more to draw */
|
|
|
|
|
|
|
|
int bins_acc = bars / 2;
|
2012-12-19 01:32:23 +00:00
|
|
|
unsigned bins_max = 0;
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
for(int i = 0, x = offset;; ++i)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
unsigned bin = plot[i];
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
if(bin > bins_max)
|
|
|
|
bins_max = bin;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
bins_acc += bars;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
if(bins_acc >= ARRAYLEN_PLOT)
|
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
int h = LCD_HEIGHT*bins_max / graph_max;
|
|
|
|
mylcd_fillrect(x, LCD_HEIGHT - h, width, h - 1);
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
if(i >= ARRAYLEN_PLOT-1)
|
2010-06-02 08:34:10 +00:00
|
|
|
break;
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
x += barwidth;
|
2010-06-02 08:34:10 +00:00
|
|
|
bins_acc -= ARRAYLEN_PLOT;
|
|
|
|
bins_max = 0;
|
|
|
|
}
|
|
|
|
}
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
static void draw_bars_horizontal(unsigned this_max, unsigned graph_max)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2010-06-02 08:34:10 +00:00
|
|
|
#if LCD_WIDTH < LCD_HEIGHT
|
|
|
|
const int bars = 20;
|
|
|
|
#else
|
|
|
|
const int bars = 15;
|
|
|
|
#endif
|
|
|
|
const int border = 2;
|
|
|
|
const int barwidth = LCD_HEIGHT / (bars + border);
|
|
|
|
const int height = barwidth - border;
|
2012-12-19 01:32:23 +00:00
|
|
|
const int offset = (LCD_HEIGHT - bars*barwidth + border) / 2;
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
mylcd_clear_display();
|
2010-06-04 08:43:32 +00:00
|
|
|
mylcd_vline(0, 0, LCD_HEIGHT-1); /* Draw baseline */
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
if(this_max == 0)
|
2010-06-02 08:34:10 +00:00
|
|
|
return; /* nothing more to draw */
|
|
|
|
|
|
|
|
int bins_acc = bars / 2;
|
2012-12-19 01:32:23 +00:00
|
|
|
unsigned bins_max = 0;
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
for(int i = 0, y = offset;; ++i)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
unsigned bin = plot[i];
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
if(bin > bins_max)
|
2010-06-02 08:34:10 +00:00
|
|
|
bins_max = bin;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
bins_acc += bars;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
if(bins_acc >= ARRAYLEN_PLOT)
|
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
int w = LCD_WIDTH*bins_max / graph_max;
|
|
|
|
mylcd_fillrect(1, y, w, height);
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
if(i >= ARRAYLEN_PLOT-1)
|
2010-06-02 08:34:10 +00:00
|
|
|
break;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
y += barwidth;
|
2010-06-02 08:34:10 +00:00
|
|
|
bins_acc -= ARRAYLEN_PLOT;
|
|
|
|
bins_max = 0;
|
|
|
|
}
|
|
|
|
}
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
static void draw_spectrogram_vertical(unsigned this_max, unsigned graph_max)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
const int scale_factor = MIN(LCD_HEIGHT, ARRAYLEN_PLOT);
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
if(fft_spectrogram_pos < LCD_WIDTH-1)
|
|
|
|
fft_spectrogram_pos++;
|
|
|
|
else
|
|
|
|
mylcd_scroll_left(1);
|
2010-06-02 08:34:10 +00:00
|
|
|
|
|
|
|
int bins_acc = scale_factor / 2;
|
2012-12-19 01:32:23 +00:00
|
|
|
unsigned bins_max = 0;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
for(int i = 0, y = LCD_HEIGHT-1;; ++i)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
unsigned bin = plot[i];
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
if(bin > bins_max)
|
|
|
|
bins_max = bin;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
bins_acc += scale_factor;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
if(bins_acc >= ARRAYLEN_PLOT)
|
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
unsigned index = (SHADES-1)*bins_max / graph_max;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
/* These happen because we exaggerate the graph a little for
|
|
|
|
* linear mode */
|
|
|
|
if(index >= SHADES)
|
|
|
|
index = SHADES-1;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-04 08:43:32 +00:00
|
|
|
mylcd_set_foreground(SPECTROGRAPH_PALETTE(index));
|
2012-12-19 01:32:23 +00:00
|
|
|
mylcd_drawpixel(fft_spectrogram_pos, y);
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
if(--y < 0)
|
2010-06-02 08:34:10 +00:00
|
|
|
break;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
bins_acc -= ARRAYLEN_PLOT;
|
|
|
|
bins_max = 0;
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
(void)this_max;
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
static void draw_spectrogram_horizontal(unsigned this_max, unsigned graph_max)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
const int scale_factor = MIN(LCD_WIDTH, ARRAYLEN_PLOT);
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
if(fft_spectrogram_pos < LCD_HEIGHT-1)
|
|
|
|
fft_spectrogram_pos++;
|
|
|
|
else
|
|
|
|
mylcd_scroll_up(1);
|
2010-06-02 08:34:10 +00:00
|
|
|
|
|
|
|
int bins_acc = scale_factor / 2;
|
2012-12-19 01:32:23 +00:00
|
|
|
unsigned bins_max = 0;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
for(int i = 0, x = 0;; ++i)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
unsigned bin = plot[i];
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
if(bin > bins_max)
|
|
|
|
bins_max = bin;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
bins_acc += scale_factor;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
if(bins_acc >= ARRAYLEN_PLOT)
|
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
unsigned index = (SHADES-1)*bins_max / graph_max;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
/* These happen because we exaggerate the graph a little for
|
|
|
|
* linear mode */
|
|
|
|
if(index >= SHADES)
|
|
|
|
index = SHADES-1;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-04 08:43:32 +00:00
|
|
|
mylcd_set_foreground(SPECTROGRAPH_PALETTE(index));
|
2012-12-19 01:32:23 +00:00
|
|
|
mylcd_drawpixel(x, fft_spectrogram_pos);
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
if(++x >= LCD_WIDTH)
|
2010-06-02 08:34:10 +00:00
|
|
|
break;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
bins_acc -= ARRAYLEN_PLOT;
|
|
|
|
bins_max = 0;
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
(void)this_max;
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
/******************** End of plotting functions (modes) ********************/
|
|
|
|
|
|
|
|
|
|
|
|
/***************************** FFT functions *******************************/
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2011-06-29 06:37:04 +00:00
|
|
|
static bool is_playing(void)
|
|
|
|
{
|
|
|
|
return rb->mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) == CHANNEL_PLAYING;
|
|
|
|
}
|
2010-06-03 00:59:05 +00:00
|
|
|
|
|
|
|
/** functions use in single/multi configuration **/
|
|
|
|
static inline bool fft_init_fft_lib(void)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2010-06-03 08:55:36 +00:00
|
|
|
size_t size = sizeof(fft_buffer);
|
|
|
|
fft_state = kiss_fft_alloc(FFT_SIZE, 0, fft_buffer, &size);
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2010-06-03 00:59:05 +00:00
|
|
|
if(fft_state == NULL)
|
2010-06-02 08:34:10 +00:00
|
|
|
{
|
|
|
|
DEBUGF("needed data: %i", (int) size);
|
2010-06-03 00:59:05 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool fft_get_fft(void)
|
|
|
|
{
|
|
|
|
int count;
|
2012-02-23 13:14:46 +00:00
|
|
|
const int16_t *value =
|
|
|
|
rb->mixer_channel_get_buffer(PCM_MIXER_CHAN_PLAYBACK, &count);
|
2010-06-03 00:59:05 +00:00
|
|
|
/* This block can introduce discontinuities in our data. Meaning, the
|
|
|
|
* FFT will not be done a continuous segment of the signal. Which can
|
|
|
|
* be bad. Or not.
|
|
|
|
*
|
|
|
|
* Anyway, this is a demo, not a scientific tool. If you want accuracy,
|
|
|
|
* do a proper spectrum analysis.*/
|
|
|
|
|
|
|
|
/* there are cases when we don't have enough data to fill the buffer */
|
2010-06-03 08:55:36 +00:00
|
|
|
if(count != ARRAYLEN_IN)
|
2010-06-03 00:59:05 +00:00
|
|
|
{
|
2010-06-03 08:55:36 +00:00
|
|
|
if(count < ARRAYLEN_IN)
|
2010-06-03 00:59:05 +00:00
|
|
|
return false;
|
|
|
|
|
2010-06-03 08:55:36 +00:00
|
|
|
count = ARRAYLEN_IN; /* too much - limit */
|
2010-06-03 00:59:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int fft_idx = 0; /* offset in 'input' */
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
kiss_fft_scalar left = *value++;
|
|
|
|
kiss_fft_scalar right = *value++;
|
2010-06-03 08:55:36 +00:00
|
|
|
input[fft_idx].r = (left + right) >> 1; /* to mono */
|
|
|
|
} while (fft_idx++, --count > 0);
|
2010-06-03 00:59:05 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
apply_window_func(fft.window_func);
|
2010-06-03 00:59:05 +00:00
|
|
|
|
|
|
|
rb->yield();
|
|
|
|
|
2010-06-03 08:55:36 +00:00
|
|
|
kiss_fft(fft_state, input, output[output_tail]);
|
2010-06-03 00:59:05 +00:00
|
|
|
|
|
|
|
rb->yield();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if NUM_CORES > 1
|
|
|
|
/* use a worker thread if there is another processor core */
|
|
|
|
static volatile bool fft_thread_run SHAREDDATA_ATTR = false;
|
2012-12-19 01:32:23 +00:00
|
|
|
static unsigned long fft_thread = 0;
|
2010-06-03 00:59:05 +00:00
|
|
|
|
|
|
|
static long fft_thread_stack[CACHEALIGN_UP(DEFAULT_STACK_SIZE*4/sizeof(long))]
|
|
|
|
CACHEALIGN_AT_LEAST_ATTR(4);
|
|
|
|
|
|
|
|
static void fft_thread_entry(void)
|
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
if(!fft_init_fft_lib())
|
2010-06-03 00:59:05 +00:00
|
|
|
{
|
2010-06-02 08:34:10 +00:00
|
|
|
output_tail = -1; /* tell that we bailed */
|
|
|
|
fft_thread_run = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fft_thread_run = true;
|
|
|
|
|
|
|
|
while(fft_thread_run)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2011-06-29 06:37:04 +00:00
|
|
|
if (!is_playing())
|
2010-06-02 08:34:10 +00:00
|
|
|
{
|
|
|
|
rb->sleep(HZ/5);
|
|
|
|
continue;
|
|
|
|
}
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2010-06-03 00:59:05 +00:00
|
|
|
if (!fft_get_fft())
|
|
|
|
{
|
|
|
|
rb->sleep(0); /* not enough - ease up */
|
|
|
|
continue;
|
2010-06-02 08:34:10 +00:00
|
|
|
}
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
/* write back output for other processor and invalidate for next
|
|
|
|
frame read */
|
2011-12-17 07:27:24 +00:00
|
|
|
rb->commit_discard_dcache();
|
2011-02-21 14:54:08 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
int new_tail = output_tail ^ 1;
|
|
|
|
|
|
|
|
/* if full, block waiting until reader has freed a slot */
|
2010-06-03 00:59:05 +00:00
|
|
|
while(fft_thread_run)
|
|
|
|
{
|
|
|
|
if(new_tail != output_head)
|
|
|
|
{
|
|
|
|
output_tail = new_tail;
|
|
|
|
break;
|
|
|
|
}
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2010-06-03 00:59:05 +00:00
|
|
|
rb->sleep(0);
|
|
|
|
}
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-03 00:59:05 +00:00
|
|
|
static bool fft_have_fft(void)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2010-06-03 00:59:05 +00:00
|
|
|
return output_head != output_tail;
|
|
|
|
}
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2010-06-03 00:59:05 +00:00
|
|
|
/* Call only after fft_have_fft() has returned true */
|
|
|
|
static inline void fft_free_fft_output(void)
|
|
|
|
{
|
|
|
|
output_head ^= 1; /* finished with this */
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool fft_init_fft(void)
|
|
|
|
{
|
2010-06-02 08:34:10 +00:00
|
|
|
/* create worker thread - on the COP for dual-core targets */
|
2010-06-03 00:59:05 +00:00
|
|
|
fft_thread = rb->create_thread(fft_thread_entry,
|
2010-06-02 08:34:10 +00:00
|
|
|
fft_thread_stack, sizeof(fft_thread_stack), 0, "fft output thread"
|
|
|
|
IF_PRIO(, PRIORITY_USER_INTERFACE+1) IF_COP(, COP));
|
|
|
|
|
|
|
|
if(fft_thread == 0)
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
2010-06-02 08:34:10 +00:00
|
|
|
rb->splash(HZ, "FFT thread failed create");
|
2010-06-03 00:59:05 +00:00
|
|
|
return false;
|
2010-06-02 08:34:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* wait for it to indicate 'ready' */
|
|
|
|
while(fft_thread_run == false)
|
|
|
|
rb->sleep(0);
|
|
|
|
|
|
|
|
if(output_tail == -1)
|
|
|
|
{
|
|
|
|
/* FFT thread bailed-out like The Fed */
|
|
|
|
rb->thread_wait(fft_thread);
|
|
|
|
rb->splash(HZ, "FFT thread failed to init");
|
2010-06-03 00:59:05 +00:00
|
|
|
return false;
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2010-06-03 00:59:05 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fft_close_fft(void)
|
|
|
|
{
|
|
|
|
/* Handle our FFT thread. */
|
|
|
|
fft_thread_run = false;
|
|
|
|
rb->thread_wait(fft_thread);
|
2011-12-17 07:27:24 +00:00
|
|
|
rb->commit_discard_dcache();
|
2010-06-03 00:59:05 +00:00
|
|
|
}
|
|
|
|
#else /* NUM_CORES == 1 */
|
|
|
|
/* everything serialize on single-core and FFT gets to use IRAM main stack if
|
|
|
|
* target uses IRAM */
|
|
|
|
static bool fft_have_fft(void)
|
|
|
|
{
|
2011-06-29 06:37:04 +00:00
|
|
|
return is_playing() && fft_get_fft();
|
2010-06-03 00:59:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void fft_free_fft_output(void)
|
|
|
|
{
|
|
|
|
/* nothing to do */
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool fft_init_fft(void)
|
|
|
|
{
|
|
|
|
return fft_init_fft_lib();
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void fft_close_fft(void)
|
|
|
|
{
|
|
|
|
/* nothing to do */
|
|
|
|
}
|
|
|
|
#endif /* NUM_CORES */
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
/************************** End of FFT functions ***************************/
|
|
|
|
|
|
|
|
|
|
|
|
/****************************** OSD functions ******************************/
|
|
|
|
|
|
|
|
/* Format a message to display */
|
|
|
|
static void fft_osd_format_message(enum fft_setting_flags id)
|
2010-06-03 00:59:05 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
const char *msg = "";
|
2010-06-03 00:59:05 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
switch (id)
|
|
|
|
{
|
|
|
|
case FFT_SETF_DM:
|
|
|
|
msg = (const char * [FFT_MAX_DM]) {
|
|
|
|
[FFT_DM_LINES] = "Lines",
|
|
|
|
[FFT_DM_BARS] = "Bars",
|
|
|
|
[FFT_DM_SPECTROGRAM] = "Spectrogram",
|
|
|
|
}[fft.drawmode];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FFT_SETF_WF:
|
|
|
|
msg = (const char * [FFT_MAX_WF]) {
|
|
|
|
[FFT_WF_HAMMING] = "Hamming window",
|
|
|
|
[FFT_WF_HANN] = "Hann window",
|
|
|
|
}[fft.window_func];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FFT_SETF_AS:
|
|
|
|
msg = (const char * [FFT_MAX_AS]) {
|
|
|
|
[FFT_AS_LOG] = "Logarithmic amplitude",
|
|
|
|
[FFT_AS_LIN] = "Linear amplitude"
|
|
|
|
}[fft.amp_scale];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FFT_SETF_FS:
|
|
|
|
msg = (const char * [FFT_MAX_FS]) {
|
|
|
|
[FFT_FS_LOG] = "Logarithmic frequency",
|
|
|
|
[FFT_FS_LIN] = "Linear frequency",
|
|
|
|
}[fft.freq_scale];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FFT_SETF_OR:
|
|
|
|
rb->snprintf(fft_osd_message, sizeof (fft_osd_message),
|
|
|
|
(const char * [FFT_MAX_OR]) {
|
|
|
|
[FFT_OR_VERT] = "Vertical %s",
|
|
|
|
[FFT_OR_HORZ] = "Horizontal %s",
|
|
|
|
}[fft.orientation],
|
|
|
|
(const char * [FFT_MAX_DM]) {
|
|
|
|
[FFT_DM_LINES ... FFT_DM_BARS] = "amplitude",
|
|
|
|
[FFT_DM_SPECTROGRAM] = "frequency"
|
|
|
|
}[fft.drawmode]);
|
|
|
|
return;
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
/* Pertentially */
|
|
|
|
case FFT_SETF_VOLUME:
|
|
|
|
rb->snprintf(fft_osd_message, sizeof (fft_osd_message),
|
|
|
|
"Volume: %d%s",
|
|
|
|
rb->sound_val2phys(SOUND_VOLUME, global_settings.volume),
|
|
|
|
rb->sound_unit(SOUND_VOLUME));
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Default action: copy string */
|
|
|
|
rb->strlcpy(fft_osd_message, msg, sizeof (fft_osd_message));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fft_osd_draw_cb(int x, int y, int width, int height)
|
|
|
|
{
|
|
|
|
#if LCD_DEPTH > 1
|
|
|
|
mylcd_set_foreground(COLOR_MESSAGE_FG);
|
|
|
|
mylcd_set_background(COLOR_MESSAGE_BG);
|
|
|
|
#endif
|
|
|
|
#if FFT_OSD_MARGIN_SIZE != 0
|
|
|
|
mylcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
|
|
|
|
mylcd_fillrect(1, 1, width - 2, height - 2);
|
|
|
|
mylcd_set_drawmode(DRMODE_SOLID);
|
|
|
|
#endif
|
|
|
|
mylcd_putsxy(1+FFT_OSD_MARGIN_SIZE, 1+FFT_OSD_MARGIN_SIZE,
|
|
|
|
fft_osd_message);
|
|
|
|
#if LCD_DEPTH > 1
|
|
|
|
mylcd_set_foreground(COLOR_MESSAGE_FRAME);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
mylcd_drawrect(0, 0, width, height);
|
|
|
|
|
|
|
|
(void)x; (void)y;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fft_osd_show_message(enum fft_setting_flags id)
|
|
|
|
{
|
|
|
|
fft_osd_format_message(id);
|
|
|
|
|
|
|
|
if(!myosd_enabled())
|
|
|
|
return;
|
|
|
|
|
|
|
|
int width, height;
|
|
|
|
int maxwidth, maxheight;
|
|
|
|
|
|
|
|
mylcd_set_viewport(myosd_get_viewport());
|
|
|
|
myosd_get_max_dims(&maxwidth, &maxheight);
|
|
|
|
mylcd_setfont(FONT_UI);
|
|
|
|
mylcd_getstringsize(fft_osd_message, &width, &height);
|
|
|
|
mylcd_set_viewport(NULL);
|
|
|
|
|
|
|
|
width += 2 + 2*FFT_OSD_MARGIN_SIZE;
|
|
|
|
if(width > maxwidth)
|
|
|
|
width = maxwidth;
|
|
|
|
|
|
|
|
height += 2 + 2*FFT_OSD_MARGIN_SIZE;
|
|
|
|
if(height > maxheight)
|
|
|
|
height = maxheight;
|
|
|
|
|
|
|
|
bool drawn = myosd_update_pos((LCD_WIDTH - width) / 2,
|
|
|
|
(LCD_HEIGHT - height) / 2,
|
|
|
|
width, height);
|
|
|
|
|
|
|
|
myosd_show(OSD_SHOW | (drawn ? 0 : OSD_UPDATENOW));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fft_popupmsg(enum fft_setting_flags id)
|
|
|
|
{
|
|
|
|
fft_message_id = id;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************** End of OSD functions ***************************/
|
|
|
|
|
|
|
|
|
|
|
|
static void fft_setting_update(unsigned which)
|
|
|
|
{
|
|
|
|
static fft_drawfn_t fft_drawfns[FFT_MAX_DM][FFT_MAX_OR] =
|
|
|
|
{
|
|
|
|
[FFT_DM_LINES] =
|
|
|
|
{
|
|
|
|
[FFT_OR_HORZ] = draw_lines_horizontal,
|
|
|
|
[FFT_OR_VERT] = draw_lines_vertical,
|
|
|
|
},
|
|
|
|
[FFT_DM_BARS] =
|
|
|
|
{
|
|
|
|
[FFT_OR_HORZ] = draw_bars_horizontal,
|
|
|
|
[FFT_OR_VERT] = draw_bars_vertical,
|
|
|
|
},
|
|
|
|
[FFT_DM_SPECTROGRAM] =
|
|
|
|
{
|
|
|
|
[FFT_OR_HORZ] = draw_spectrogram_horizontal,
|
|
|
|
[FFT_OR_VERT] = draw_spectrogram_vertical,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
if(which & (FFT_SETF_DM | FFT_SETF_OR))
|
|
|
|
{
|
|
|
|
fft_drawfn = fft_drawfns[fft.drawmode]
|
|
|
|
[fft.orientation];
|
|
|
|
|
|
|
|
if(fft.drawmode == FFT_DM_SPECTROGRAM)
|
|
|
|
{
|
|
|
|
fft_spectrogram_pos = -1;
|
|
|
|
myosd_lcd_update_prepare();
|
|
|
|
mylcd_clear_display();
|
|
|
|
myosd_lcd_update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(which & (FFT_SETF_DM | FFT_SETF_AS))
|
|
|
|
{
|
|
|
|
if(fft.drawmode == FFT_DM_SPECTROGRAM)
|
|
|
|
{
|
|
|
|
fft_graph_scale = fft.amp_scale == FFT_AS_LIN ?
|
|
|
|
QLIN_MAX : QLOG_MAX;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fft_graph_scale = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(which & FFT_SETF_FS)
|
|
|
|
{
|
|
|
|
plot = fft.freq_scale == FFT_FS_LIN ?
|
|
|
|
linf_magnitudes : logf_magnitudes;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(which & FFT_SETF_AS)
|
|
|
|
{
|
|
|
|
memset(linf_magnitudes, 0, sizeof (linf_magnitudes));
|
|
|
|
memset(logf_magnitudes, 0, sizeof (logf_magnitudes));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static long fft_draw(void)
|
|
|
|
{
|
|
|
|
long tick = *rb->current_tick;
|
|
|
|
|
|
|
|
if(fft_message_id != -1)
|
|
|
|
{
|
|
|
|
/* Show a new message */
|
|
|
|
fft_osd_show_message((enum fft_setting_flags)fft_message_id);
|
|
|
|
fft_message_id = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Monitor OSD timeout */
|
|
|
|
myosd_monitor_timeout();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(TIME_BEFORE(tick, fft_next_frame_tick))
|
|
|
|
return fft_next_frame_tick - tick; /* Too early */
|
|
|
|
|
|
|
|
unsigned this_max;
|
|
|
|
|
|
|
|
if(!fft_have_fft())
|
|
|
|
{
|
|
|
|
if(is_playing())
|
|
|
|
return HZ/100;
|
|
|
|
|
|
|
|
/* All magnitudes == 0 thus this_max == 0 */
|
|
|
|
for(int i = 0; i < ARRAYLEN_PLOT; i++)
|
|
|
|
linf_magnitudes[i] >>= 1; /* decay */
|
2010-06-03 00:59:05 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
this_max = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this_max = calc_magnitudes(fft.amp_scale);
|
|
|
|
|
|
|
|
fft_free_fft_output(); /* COP only */
|
|
|
|
|
|
|
|
if(fft.drawmode != FFT_DM_SPECTROGRAM &&
|
|
|
|
this_max > fft_graph_scale)
|
|
|
|
{
|
|
|
|
fft_graph_scale = this_max;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fft.freq_scale == FFT_FS_LOG)
|
|
|
|
log_plot_translate();
|
|
|
|
|
|
|
|
myosd_lcd_update_prepare();
|
|
|
|
|
|
|
|
mylcd_set_foreground(COLOR_DEFAULT_FG);
|
|
|
|
mylcd_set_background(COLOR_DEFAULT_BG);
|
|
|
|
|
|
|
|
fft_drawfn(this_max, fft_graph_scale);
|
|
|
|
|
|
|
|
myosd_lcd_update();
|
|
|
|
|
|
|
|
fft_next_frame_tick = tick + FFT_PERIOD;
|
|
|
|
return fft_next_frame_tick - *rb->current_tick;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fft_osd_init(void *buf, size_t bufsize)
|
|
|
|
{
|
|
|
|
int width, height;
|
|
|
|
mylcd_setfont(FONT_UI);
|
|
|
|
mylcd_getstringsize("M", NULL, &height);
|
|
|
|
width = LCD_WIDTH;
|
|
|
|
height += 2 + 2*FFT_OSD_MARGIN_SIZE;
|
|
|
|
myosd_init(OSD_INIT_MAJOR_HEIGHT | OSD_INIT_MINOR_MAX, buf, bufsize,
|
|
|
|
fft_osd_draw_cb, &width, &height, NULL);
|
|
|
|
myosd_set_timeout(HZ);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fft_cleanup(void)
|
|
|
|
{
|
|
|
|
myosd_destroy();
|
|
|
|
|
|
|
|
fft_close_fft();
|
|
|
|
|
|
|
|
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
|
|
|
rb->cancel_cpu_boost();
|
|
|
|
#endif
|
2010-02-10 19:44:11 +00:00
|
|
|
#ifndef HAVE_LCD_COLOR
|
2012-12-19 01:32:23 +00:00
|
|
|
grey_release();
|
|
|
|
#endif
|
|
|
|
backlight_use_settings();
|
|
|
|
|
|
|
|
/* save settings if changed */
|
|
|
|
if (rb->memcmp(&fft, &fft_disk, sizeof(fft)))
|
|
|
|
{
|
|
|
|
fft_disk = fft;
|
|
|
|
configfile_save(cfg_filename, disk_config, ARRAYLEN(disk_config),
|
|
|
|
CFGFILE_VERSION);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool fft_setup(void)
|
|
|
|
{
|
|
|
|
atexit(fft_cleanup);
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
configfile_load(cfg_filename, disk_config, ARRAYLEN(disk_config),
|
|
|
|
CFGFILE_MINVERSION);
|
|
|
|
fft = fft_disk; /* copy to running config */
|
|
|
|
|
|
|
|
if(!fft_init_fft())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* get the remainder of the plugin buffer for OSD and perhaps
|
|
|
|
greylib */
|
|
|
|
size_t bufsize = 0;
|
|
|
|
unsigned char *buf = rb->plugin_get_buffer(&bufsize);
|
|
|
|
|
|
|
|
#ifndef HAVE_LCD_COLOR
|
2010-02-10 19:44:11 +00:00
|
|
|
/* initialize the greyscale buffer.*/
|
2012-12-19 01:32:23 +00:00
|
|
|
long grey_size;
|
|
|
|
if(!grey_init(buf, bufsize, GREY_ON_COP | GREY_BUFFERED,
|
|
|
|
LCD_WIDTH, LCD_HEIGHT, &grey_size))
|
2010-02-10 19:44:11 +00:00
|
|
|
{
|
|
|
|
rb->splash(HZ, "Couldn't init greyscale display");
|
2012-12-19 01:32:23 +00:00
|
|
|
return false;
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
grey_show(true);
|
|
|
|
|
|
|
|
buf += grey_size;
|
|
|
|
bufsize -= grey_size;
|
|
|
|
#endif /* !HAVE_LCD_COLOR */
|
|
|
|
|
|
|
|
fft_osd_init(buf, bufsize);
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2010-02-10 19:44:11 +00:00
|
|
|
#if LCD_DEPTH > 1
|
2012-12-19 01:32:23 +00:00
|
|
|
myosd_lcd_update_prepare();
|
2010-02-10 19:44:11 +00:00
|
|
|
rb->lcd_set_backdrop(NULL);
|
2010-06-04 08:43:32 +00:00
|
|
|
mylcd_clear_display();
|
2012-12-19 01:32:23 +00:00
|
|
|
myosd_lcd_update();
|
2010-02-10 19:44:11 +00:00
|
|
|
#endif
|
2011-01-24 12:29:16 +00:00
|
|
|
backlight_ignore_timeout();
|
2010-02-10 19:44:11 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
2012-12-19 01:32:23 +00:00
|
|
|
rb->trigger_cpu_boost();
|
2010-02-10 19:44:11 +00:00
|
|
|
#endif
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
logarithmic_plot_init();
|
|
|
|
fft_setting_update(FFT_SETF_ALL);
|
|
|
|
fft_next_frame_tick = *rb->current_tick;
|
2010-06-03 00:59:05 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
return true;
|
|
|
|
}
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
enum plugin_status plugin_start(const void* parameter)
|
|
|
|
{
|
|
|
|
bool run = true;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
if(!fft_setup())
|
|
|
|
return PLUGIN_ERROR;
|
2010-02-10 19:44:11 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
while(run)
|
|
|
|
{
|
|
|
|
long delay = fft_draw();
|
2010-06-03 00:59:05 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
if(delay <= 0)
|
2010-06-03 04:21:27 +00:00
|
|
|
{
|
2012-12-19 01:32:23 +00:00
|
|
|
delay = 0;
|
2010-06-03 04:21:27 +00:00
|
|
|
rb->yield(); /* tmo = 0 won't yield */
|
|
|
|
}
|
2010-06-02 08:34:10 +00:00
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
int button = rb->button_get_w_tmo(delay);
|
|
|
|
|
2010-02-10 19:44:11 +00:00
|
|
|
switch (button)
|
|
|
|
{
|
|
|
|
case FFT_QUIT:
|
|
|
|
run = false;
|
|
|
|
break;
|
2012-12-19 01:32:23 +00:00
|
|
|
|
|
|
|
case FFT_ORIENTATION:
|
|
|
|
if (++fft.orientation >= FFT_MAX_OR)
|
|
|
|
fft.orientation = FFT_MIN_OR;
|
|
|
|
|
|
|
|
fft_setting_update(FFT_SETF_OR);
|
|
|
|
fft_popupmsg(FFT_SETF_OR);
|
2010-02-10 19:44:11 +00:00
|
|
|
break;
|
2012-12-19 01:32:23 +00:00
|
|
|
|
|
|
|
case FFT_PREV_GRAPH:
|
|
|
|
if (fft.drawmode-- <= FFT_MIN_DM)
|
|
|
|
fft.drawmode = FFT_MAX_DM-1;
|
|
|
|
|
|
|
|
fft_setting_update(FFT_SETF_DM);
|
|
|
|
fft_popupmsg(FFT_SETF_DM);
|
2010-02-10 19:44:11 +00:00
|
|
|
break;
|
2012-12-19 01:32:23 +00:00
|
|
|
|
|
|
|
case FFT_NEXT_GRAPH:
|
|
|
|
if (++fft.drawmode >= FFT_MAX_DM)
|
|
|
|
fft.drawmode = FFT_MIN_DM;
|
|
|
|
|
|
|
|
fft_setting_update(FFT_SETF_DM);
|
|
|
|
fft_popupmsg(FFT_SETF_DM);
|
2010-06-02 08:34:10 +00:00
|
|
|
break;
|
2012-12-19 01:32:23 +00:00
|
|
|
|
|
|
|
case FFT_AMP_SCALE:
|
|
|
|
if (++fft.amp_scale >= FFT_MAX_AS)
|
|
|
|
fft.amp_scale = FFT_MIN_AS;
|
|
|
|
|
|
|
|
fft_setting_update(FFT_SETF_AS);
|
|
|
|
fft_popupmsg(FFT_SETF_AS);
|
2010-02-10 19:44:11 +00:00
|
|
|
break;
|
2012-12-19 01:32:23 +00:00
|
|
|
|
2010-06-02 08:34:10 +00:00
|
|
|
#ifdef FFT_FREQ_SCALE /* 'Till all keymaps are defined */
|
2012-12-19 01:32:23 +00:00
|
|
|
case FFT_FREQ_SCALE:
|
|
|
|
if (++fft.freq_scale >= FFT_MAX_FS)
|
|
|
|
fft.freq_scale = FFT_MIN_FS;
|
|
|
|
|
|
|
|
fft_setting_update(FFT_SETF_FS);
|
|
|
|
fft_popupmsg(FFT_SETF_FS);
|
2010-02-10 19:44:11 +00:00
|
|
|
break;
|
2010-06-02 08:34:10 +00:00
|
|
|
#endif
|
2012-12-19 01:32:23 +00:00
|
|
|
case FFT_WINDOW:
|
|
|
|
if(++fft.window_func >= FFT_MAX_WF)
|
|
|
|
fft.window_func = FFT_MIN_WF;
|
|
|
|
|
|
|
|
fft_setting_update(FFT_SETF_WF);
|
|
|
|
fft_popupmsg(FFT_SETF_WF);
|
2010-02-10 19:44:11 +00:00
|
|
|
break;
|
|
|
|
|
2012-12-19 01:32:23 +00:00
|
|
|
default:
|
|
|
|
exit_on_usb(button);
|
|
|
|
break;
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-03 00:59:05 +00:00
|
|
|
|
2010-02-10 19:44:11 +00:00
|
|
|
return PLUGIN_OK;
|
2010-06-02 08:34:10 +00:00
|
|
|
(void)parameter;
|
2010-02-10 19:44:11 +00:00
|
|
|
}
|