summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/fft/fft.c1235
1 files changed, 652 insertions, 583 deletions
diff --git a/apps/plugins/fft/fft.c b/apps/plugins/fft/fft.c
index 1e323ec..709fbf9 100644
--- a/apps/plugins/fft/fft.c
+++ b/apps/plugins/fft/fft.c
@@ -1,5 +1,5 @@
/***************************************************************************
-* __________ __ ___.
+ * __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
@@ -21,6 +21,8 @@
#include "plugin.h"
#include "lib/helper.h"
+#include "lib/pluginlib_exit.h"
+#include "lib/configfile.h"
#include "lib/xlcd.h"
#include "math.h"
#include "fracmul.h"
@@ -28,6 +30,7 @@
#include "lib/grey.h"
#endif
#include "lib/mylcd.h"
+#include "lib/osd.h"
@@ -318,6 +321,9 @@ GREY_INFO_STRUCT
#include "_kiss_fft_guts.h" /* sizeof(struct kiss_fft_state) */
#include "const.h"
+
+/******************************* FFT globals *******************************/
+
#define LCD_SIZE MAX(LCD_WIDTH, LCD_HEIGHT)
#if (LCD_SIZE <= 511)
@@ -331,14 +337,14 @@ GREY_INFO_STRUCT
#define ARRAYLEN_IN (FFT_SIZE)
#define ARRAYLEN_OUT (FFT_SIZE)
#define ARRAYLEN_PLOT (FFT_SIZE/2-1) /* FFT is symmetric, ignore DC */
-#define BUFSIZE_FFT (sizeof(struct kiss_fft_state)+sizeof(kiss_fft_cpx)*(FFT_SIZE-1))
+#define BUFSIZE_FFT (sizeof(struct kiss_fft_state)+\
+ sizeof(kiss_fft_cpx)*(FFT_SIZE-1))
#define __COEFF(type,size) type##_##size
-#define _COEFF(x, y) __COEFF(x,y) /* force the preprocessor to evaluate FFT_SIZE) */
+#define _COEFF(x, y) __COEFF(x,y) /* force CPP evaluation of FFT_SIZE */
#define HANN_COEFF _COEFF(hann, FFT_SIZE)
#define HAMMING_COEFF _COEFF(hamming, FFT_SIZE)
-/****************************** Globals ****************************/
/* cacheline-aligned buffers with COP, otherwise word-aligned */
/* CPU/COP only applies when compiled for more than one core */
@@ -370,75 +376,156 @@ static kiss_fft_cfg fft_state SHAREDBSS_ATTR;
static char fft_buffer[CACHEALIGN_UP_SIZE(char, BUFSIZE_FFT)]
CACHEALIGN_AT_LEAST_ATTR(4);
/* CPU */
-static int32_t plot_history[ARRAYLEN_PLOT];
-static int32_t plot[ARRAYLEN_PLOT];
+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 */
static struct
{
int16_t bin; /* integer bin number */
uint16_t frac; /* interpolation fraction */
} binlog[ARRAYLEN_PLOT] __attribute__((aligned(4)));
-enum fft_window_func
+/**************************** End of FFT globals ***************************/
+
+
+/********************************* Settings ********************************/
+
+enum fft_orientation
{
- FFT_WF_FIRST = 0,
- FFT_WF_HAMMING = 0,
- FFT_WF_HANN,
+ FFT_MIN_OR = 0,
+ FFT_OR_VERT = 0, /* Amplitude vertical, frequency horizontal * */
+ FFT_OR_HORZ, /* Amplitude horizontal, frequency vertical */
+ FFT_MAX_OR,
};
-#define FFT_WF_COUNT (FFT_WF_HANN+1)
enum fft_display_mode
{
- FFT_DM_FIRST = 0,
- FFT_DM_LINES = 0,
- FFT_DM_BARS,
- FFT_DM_SPECTROGRAPH,
+ 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,
};
-#define FFT_DM_COUNT (FFT_DM_SPECTROGRAPH+1)
-
-static const unsigned char* const modes_text[FFT_DM_COUNT] =
-{ "Lines", "Bars", "Spectrogram" };
-static const unsigned char* const amp_scales_text[2] =
-{ "Linear amplitude", "Logarithmic amplitude" };
+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,
+};
-static const unsigned char* const freq_scales_text[2] =
-{ "Linear frequency", "Logarithmic frequency" };
+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
+};
-static const unsigned char* const window_text[FFT_WF_COUNT] =
-{ "Hamming window", "Hann window" };
+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,
+};
-static struct {
- bool orientation_vertical;
- enum fft_display_mode mode;
- bool logarithmic_amp;
- bool logarithmic_freq;
- enum fft_window_func window_func;
- int spectrogram_pos; /* row or column - only used by one at a time */
- union
- {
- struct
- {
- bool orientation : 1;
- bool mode : 1;
- bool amp_scale : 1;
- bool freq_scale : 1;
- bool window_func : 1;
- bool do_clear : 1;
- };
- bool clear_all; /* Write 'false' to clear all above */
- } changed;
-} graph_settings SHAREDDATA_ATTR =
+static struct fft_config
+{
+ int orientation;
+ int drawmode;
+ int amp_scale;
+ int freq_scale;
+ int window_func;
+} fft_disk =
{
/* Defaults */
- .orientation_vertical = true,
- .mode = FFT_DM_LINES,
- .logarithmic_amp = true,
- .logarithmic_freq = true,
- .window_func = FFT_WF_HAMMING,
- .spectrogram_pos = 0,
- .changed = { .clear_all = false },
+ .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" } },
};
+/* Hint flags for setting changes */
+enum fft_setting_flags
+{
+ FFT_SETF_OR = 1 << 0,
+ FFT_SETF_DM = 1 << 1,
+ FFT_SETF_AS = 1 << 2,
+#ifdef FFT_FREQ_SCALE /* 'Till all keymaps are defined */
+ FFT_SETF_FS = 1 << 3,
+#endif
+ 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 */
+
#ifdef HAVE_LCD_COLOR
#define SHADES BMPWIDTH_fft_colors
#define SPECTROGRAPH_PALETTE(index) (fft_colors[index])
@@ -447,121 +534,103 @@ static struct {
#define SPECTROGRAPH_PALETTE(index) (255 - (index))
#endif
-/************************* End of globals *************************/
+/************************* End of operational data *************************/
-/************************* Math functions *************************/
-/* 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)
+/***************************** Math functions ******************************/
/* Apply window function to input */
static void apply_window_func(enum fft_window_func mode)
{
- int i;
-
- switch(mode)
+ static const int16_t * const coefs[] =
{
- case FFT_WF_HAMMING:
- for(i = 0; i < ARRAYLEN_IN; ++i)
- {
- input[i].r = (input[i].r * HAMMING_COEFF[i] + 16384) >> 15;
- }
- break;
+ [FFT_WF_HAMMING] = HAMMING_COEFF,
+ [FFT_WF_HANN] = HANN_COEFF,
+ };
- case FFT_WF_HANN:
- for(i = 0; i < ARRAYLEN_IN; ++i)
- {
- input[i].r = (input[i].r * HANN_COEFF[i] + 16384) >> 15;
- }
- break;
- }
+ 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;
}
/* Calculates the magnitudes from complex numbers and returns the maximum */
-static int32_t calc_magnitudes(bool logarithmic_amp)
+static unsigned calc_magnitudes(enum fft_amp_scale scale)
{
/* A major assumption made when calculating the Q*MAX constants
* is that the maximum magnitude is 29 bits long. */
- uint32_t max = 0;
+ unsigned this_max = 0;
kiss_fft_cpx *this_output = output[output_head] + 1; /* skip DC */
- int i;
/* Calculate the magnitude, discarding the phase. */
- for(i = 0; i < ARRAYLEN_PLOT; ++i)
+ for(int i = 0; i < ARRAYLEN_PLOT; ++i)
{
int32_t re = this_output[i].r;
int32_t im = this_output[i].i;
- uint32_t tmp = re*re + im*im;
+ uint32_t d = re*re + im*im;
- if(tmp > 0)
+ if(d > 0)
{
- if(tmp > 0x7FFFFFFF) /* clip */
+ if(d > 0x7FFFFFFF) /* clip */
{
- tmp = 0x7FFFFFFF; /* if our assumptions are correct,
- this should never happen. It's just
- a safeguard. */
+ d = 0x7FFFFFFF; /* if our assumptions are correct,
+ this should never happen. It's just
+ a safeguard. */
}
- if(logarithmic_amp)
+ if(scale == FFT_AS_LOG)
{
- if(tmp < 0x8000) /* be more precise */
+ if(d < 0x8000) /* be more precise */
{
/* ln(x ^ .5) = .5*ln(x) */
- tmp = fp16_log(tmp << 16) >> 1;
+ d = fp16_log(d << 16) >> 1;
}
else
{
- tmp = isqrt(tmp); /* linear scaling, nothing
- bad should happen */
- tmp = fp16_log(tmp << 16); /* the log function
- expects s15.16 values */
+ d = isqrt(d); /* linear scaling, nothing
+ bad should happen */
+ d = fp16_log(d << 16); /* the log function
+ expects s15.16 values */
}
}
else
{
- tmp = isqrt(tmp); /* linear scaling, nothing
- bad should happen */
+ d = isqrt(d); /* linear scaling, nothing
+ bad should happen */
}
}
/* Length 2 moving average - last transform and this one */
- tmp = (plot_history[i] + tmp) >> 1;
- plot[i] = tmp;
- plot_history[i] = tmp;
+ linf_magnitudes[i] = (linf_magnitudes[i] + d) >> 1;
- if(tmp > max)
- max = tmp;
+ if(d > this_max)
+ this_max = d;
}
- return max;
+ return this_max;
}
/* Move plot bins into a logarithmic scale by sliding them towards the
* Nyquist bin according to the translation in the binlog array. */
-static void logarithmic_plot_translate(void)
+static void log_plot_translate(void)
{
- int i;
-
- for(i = ARRAYLEN_PLOT-1; i > 0; --i)
+ for(int i = ARRAYLEN_PLOT-1; i > 0; --i)
{
- int bin;
int s = binlog[i].bin;
int e = binlog[i-1].bin;
- int frac = binlog[i].frac;
+ unsigned frac = binlog[i].frac;
- bin = plot[s];
+ int bin = linf_magnitudes[s];
if(frac)
{
/* slope < 1, Interpolate stretched bins (linear for now) */
- int diff = plot[s+1] - bin;
+ int diff = linf_magnitudes[s+1] - bin;
do
{
- plot[i] = bin + FRACMUL(frac << 15, diff);
+ logf_magnitudes[i] = bin + FRACMUL(frac << 15, diff);
frac = binlog[--i].frac;
}
while(frac);
@@ -571,33 +640,32 @@ static void logarithmic_plot_translate(void)
/* slope > 1, Find peak of two or more bins */
while(--s > e)
{
- int val = plot[s];
+ int val = linf_magnitudes[s];
if (val > bin)
bin = val;
}
}
- plot[i] = bin;
+ logf_magnitudes[i] = bin;
}
}
/* Calculates the translation for logarithmic plot bins */
static void logarithmic_plot_init(void)
{
- int i, j;
/*
* log: y = round(n * ln(x) / ln(n))
* anti: y = round(exp(x * ln(n) / n))
*/
- j = fp16_log((ARRAYLEN_PLOT - 1) << 16);
- for(i = 0; i < ARRAYLEN_PLOT; ++i)
+ int j = fp16_log((ARRAYLEN_PLOT - 1) << 16);
+ for(int i = 0; i < ARRAYLEN_PLOT; ++i)
{
binlog[i].bin = (fp16_exp(i * j / (ARRAYLEN_PLOT - 1)) + 32768) >> 16;
}
/* setup fractions for interpolation of stretched bins */
- for(i = 0; i < ARRAYLEN_PLOT-1; i = j)
+ for(int i = 0; i < ARRAYLEN_PLOT-1; i = j)
{
j = i + 1;
@@ -619,192 +687,13 @@ static void logarithmic_plot_init(void)
}
}
-/************************ End of math functions ***********************/
-
-/********************* Plotting functions (modes) *********************/
-static void draw_lines_vertical(void);
-static void draw_lines_horizontal(void);
-static void draw_bars_vertical(void);
-static void draw_bars_horizontal(void);
-static void draw_spectrogram_vertical(void);
-static void draw_spectrogram_horizontal(void);
-
-#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 POPUP_HPADDING 3 /* 3 px of horizontal padding and */
-#define POPUP_VPADDING 2 /* 2 px of vertical padding */
-
-static void draw_message_string(const unsigned char *message, bool active)
-{
- int x, y;
- mylcd_getstringsize(message, &x, &y);
-
- /* x and y give the size of the box for the popup */
- x += POPUP_HPADDING*2;
- y += POPUP_VPADDING*2;
-
- /* In vertical spectrogram mode, leave space for the popup
- * before actually drawing it (if space is needed) */
- if(active &&
- graph_settings.mode == FFT_DM_SPECTROGRAPH &&
- graph_settings.orientation_vertical &&
- graph_settings.spectrogram_pos >= LCD_WIDTH - x)
- {
- mylcd_scroll_left(graph_settings.spectrogram_pos -
- LCD_WIDTH + x);
- graph_settings.spectrogram_pos = LCD_WIDTH - x - 1;
- }
-
- mylcd_set_foreground(COLOR_MESSAGE_FRAME);
- mylcd_fillrect(LCD_WIDTH - x, 0, LCD_WIDTH - 1, y);
-
- mylcd_set_foreground(COLOR_MESSAGE_FG);
- mylcd_set_background(COLOR_MESSAGE_BG);
- mylcd_putsxy(LCD_WIDTH - x + POPUP_HPADDING,
- POPUP_VPADDING, message);
- mylcd_set_foreground(COLOR_DEFAULT_FG);
- mylcd_set_background(COLOR_DEFAULT_BG);
-}
-
-static void draw(const unsigned char* message)
-{
- static long show_message_tick = 0;
- static const unsigned char* last_message = 0;
-
- if(message != NULL)
- {
- last_message = message;
- show_message_tick = (*rb->current_tick + HZ) | 1;
- }
-
- /* maybe take additional actions depending upon the changed setting */
- if(graph_settings.changed.orientation)
- {
- graph_settings.changed.amp_scale = true;
- graph_settings.changed.do_clear = true;
- }
-
- if(graph_settings.changed.mode)
- {
- graph_settings.changed.amp_scale = true;
- graph_settings.changed.do_clear = true;
- }
-
- if(graph_settings.changed.amp_scale)
- memset(plot_history, 0, sizeof (plot_history));
-
- if(graph_settings.changed.freq_scale)
- graph_settings.changed.freq_scale = true;
-
- mylcd_set_foreground(COLOR_DEFAULT_FG);
- mylcd_set_background(COLOR_DEFAULT_BG);
+/************************** End of math functions **************************/
- switch (graph_settings.mode)
- {
- default:
- case FFT_DM_LINES: {
-
- mylcd_clear_display();
-
- if (graph_settings.orientation_vertical)
- draw_lines_vertical();
- else
- draw_lines_horizontal();
- break;
- }
- case FFT_DM_BARS: {
- mylcd_clear_display();
-
- if(graph_settings.orientation_vertical)
- draw_bars_vertical();
- else
- draw_bars_horizontal();
-
- break;
- }
- case FFT_DM_SPECTROGRAPH: {
-
- if(graph_settings.changed.do_clear)
- {
- graph_settings.spectrogram_pos = 0;
- mylcd_clear_display();
- }
-
- if(graph_settings.orientation_vertical)
- draw_spectrogram_vertical();
- else
- draw_spectrogram_horizontal();
- break;
- }
- }
+/*********************** Plotting functions (modes) ************************/
- if(show_message_tick != 0)
- {
- if(TIME_BEFORE(*rb->current_tick, show_message_tick))
- {
- /* We have a message to show */
- draw_message_string(last_message, true);
- }
- else
- {
- /* Stop drawing message */
- show_message_tick = 0;
- }
- }
- else if(last_message != NULL)
- {
- if(graph_settings.mode == FFT_DM_SPECTROGRAPH)
- {
- /* Spectrogram mode - need to erase the popup */
- int x, y;
- mylcd_getstringsize(last_message, &x, &y);
- /* Recalculate the size */
- x += POPUP_HPADDING*2;
- y += POPUP_VPADDING*2;
-
- if(!graph_settings.orientation_vertical)
- {
- /* In horizontal spectrogram mode, just scroll up by Y lines */
- mylcd_scroll_up(y);
- graph_settings.spectrogram_pos -= y;
- if(graph_settings.spectrogram_pos < 0)
- graph_settings.spectrogram_pos = 0;
- }
- else
- {
- /* In vertical spectrogram mode, erase the popup */
- mylcd_set_foreground(COLOR_DEFAULT_BG);
- mylcd_fillrect(graph_settings.spectrogram_pos + 1, 0,
- LCD_WIDTH, y);
- mylcd_set_foreground(COLOR_DEFAULT_FG);
- }
- }
- /* else These modes clear the screen themselves */
-
- last_message = NULL;
- }
-
- mylcd_update();
-
- graph_settings.changed.clear_all = false;
-}
-
-static void draw_lines_vertical(void)
+static void draw_lines_vertical(unsigned this_max, unsigned graph_max)
{
- static int max = 0;
-
#if LCD_WIDTH < ARRAYLEN_PLOT /* graph compression */
const int offset = 0;
const int plotwidth = LCD_WIDTH;
@@ -813,13 +702,7 @@ static void draw_lines_vertical(void)
const int plotwidth = ARRAYLEN_PLOT;
#endif
- int this_max;
- int i, x;
-
- if(graph_settings.changed.amp_scale)
- max = 0; /* reset the graph on scaling mode change */
-
- this_max = calc_magnitudes(graph_settings.logarithmic_amp);
+ mylcd_clear_display();
if(this_max == 0)
{
@@ -827,21 +710,16 @@ static void draw_lines_vertical(void)
return;
}
- if(graph_settings.logarithmic_freq)
- logarithmic_plot_translate();
-
- /* take the maximum of neighboring bins if we have to scale the graph
- * horizontally */
+ /* take the maximum of neighboring bins if we have to scale down the
+ * graph horizontally */
if(LCD_WIDTH < ARRAYLEN_PLOT) /* graph compression */
{
int bins_acc = LCD_WIDTH / 2;
- int bins_max = 0;
+ unsigned bins_max = 0;
- i = 0, x = 0;
-
- for(;;)
+ for(int i = 0, x = 0; i < ARRAYLEN_PLOT; ++i)
{
- int bin = plot[i++];
+ unsigned bin = plot[i];
if(bin > bins_max)
bins_max = bin;
@@ -850,14 +728,10 @@ static void draw_lines_vertical(void)
if(bins_acc >= ARRAYLEN_PLOT)
{
- plot[x] = bins_max;
-
- if(bins_max > max)
- max = bins_max;
-
- if(++x >= LCD_WIDTH)
- break;
+ int h = LCD_HEIGHT*bins_max / graph_max;
+ mylcd_vline(x, LCD_HEIGHT - h, LCD_HEIGHT-1);
+ x++;
bins_acc -= ARRAYLEN_PLOT;
bins_max = 0;
}
@@ -865,21 +739,16 @@ static void draw_lines_vertical(void)
}
else
{
- if(this_max > max)
- max = this_max;
- }
-
- for(x = 0; x < plotwidth; ++x)
- {
- int h = LCD_HEIGHT*plot[x] / max;
- mylcd_vline(x + offset, LCD_HEIGHT - h, LCD_HEIGHT-1);
+ 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);
+ }
}
}
-static void draw_lines_horizontal(void)
+static void draw_lines_horizontal(unsigned this_max, unsigned graph_max)
{
- static int max = 0;
-
#if LCD_WIDTH < ARRAYLEN_PLOT /* graph compression */
const int offset = 0;
const int plotwidth = LCD_HEIGHT;
@@ -888,13 +757,7 @@ static void draw_lines_horizontal(void)
const int plotwidth = ARRAYLEN_PLOT;
#endif
- int this_max;
- int y;
-
- if(graph_settings.changed.amp_scale)
- max = 0; /* reset the graph on scaling mode change */
-
- this_max = calc_magnitudes(graph_settings.logarithmic_amp);
+ mylcd_clear_display();
if(this_max == 0)
{
@@ -902,38 +765,28 @@ static void draw_lines_horizontal(void)
return;
}
- if(graph_settings.logarithmic_freq)
- logarithmic_plot_translate();
-
/* take the maximum of neighboring bins if we have to scale the graph
* horizontally */
if(LCD_HEIGHT < ARRAYLEN_PLOT) /* graph compression */
{
int bins_acc = LCD_HEIGHT / 2;
- int bins_max = 0;
- int i = 0;
-
- y = 0;
+ unsigned bins_max = 0;
- for(;;)
+ for(int i = 0, y = 0; i < ARRAYLEN_PLOT; ++i)
{
- int bin = plot[i++];
+ unsigned bin = plot[i];
- if (bin > bins_max)
+ if(bin > bins_max)
bins_max = bin;
bins_acc += LCD_HEIGHT;
if(bins_acc >= ARRAYLEN_PLOT)
{
- plot[y] = bins_max;
-
- if(bins_max > max)
- max = bins_max;
-
- if(++y >= LCD_HEIGHT)
- break;
+ int w = LCD_WIDTH*bins_max / graph_max;
+ mylcd_hline(0, w - 1, y);
+ y++;
bins_acc -= ARRAYLEN_PLOT;
bins_max = 0;
}
@@ -941,21 +794,16 @@ static void draw_lines_horizontal(void)
}
else
{
- if(this_max > max)
- max = this_max;
- }
-
- for(y = 0; y < plotwidth; ++y)
- {
- int w = LCD_WIDTH*plot[y] / max;
- mylcd_hline(0, w - 1, y + offset);
+ for(int i = 0; i < plotwidth; ++i)
+ {
+ int w = LCD_WIDTH*plot[i] / graph_max;
+ mylcd_hline(0, w - 1, i + offset);
+ }
}
}
-static void draw_bars_vertical(void)
+static void draw_bars_vertical(unsigned this_max, unsigned graph_max)
{
- static int max = 0;
-
#if LCD_WIDTH < LCD_HEIGHT
const int bars = 15;
#else
@@ -964,26 +812,20 @@ static void draw_bars_vertical(void)
const int border = 2;
const int barwidth = LCD_WIDTH / (bars + border);
const int width = barwidth - border;
- const int offset = (LCD_WIDTH - bars*barwidth) / 2;
-
- if(graph_settings.changed.amp_scale)
- max = 0; /* reset the graph on scaling mode change */
+ const int offset = (LCD_WIDTH - bars*barwidth + border) / 2;
+ mylcd_clear_display();
mylcd_hline(0, LCD_WIDTH-1, LCD_HEIGHT-1); /* Draw baseline */
- if(calc_magnitudes(graph_settings.logarithmic_amp) == 0)
+ if(this_max == 0)
return; /* nothing more to draw */
- if(graph_settings.logarithmic_freq)
- logarithmic_plot_translate();
-
int bins_acc = bars / 2;
- int bins_max = 0;
- int x = 0, i = 0;
+ unsigned bins_max = 0;
- for(;;)
+ for(int i = 0, x = offset;; ++i)
{
- int bin = plot[i++];
+ unsigned bin = plot[i];
if(bin > bins_max)
bins_max = bin;
@@ -992,30 +834,21 @@ static void draw_bars_vertical(void)
if(bins_acc >= ARRAYLEN_PLOT)
{
- plot[x] = bins_max;
+ int h = LCD_HEIGHT*bins_max / graph_max;
+ mylcd_fillrect(x, LCD_HEIGHT - h, width, h - 1);
- if(bins_max > max)
- max = bins_max;
-
- if(++x >= bars)
+ if(i >= ARRAYLEN_PLOT-1)
break;
+ x += barwidth;
bins_acc -= ARRAYLEN_PLOT;
bins_max = 0;
}
}
-
- for(i = 0, x = offset; i < bars; ++i, x += barwidth)
- {
- int h = LCD_HEIGHT * plot[i] / max;
- mylcd_fillrect(x, LCD_HEIGHT - h, width, h - 1);
- }
}
-static void draw_bars_horizontal(void)
+static void draw_bars_horizontal(unsigned this_max, unsigned graph_max)
{
- static int max = 0;
-
#if LCD_WIDTH < LCD_HEIGHT
const int bars = 20;
#else
@@ -1024,70 +857,56 @@ static void draw_bars_horizontal(void)
const int border = 2;
const int barwidth = LCD_HEIGHT / (bars + border);
const int height = barwidth - border;
- const int offset = (LCD_HEIGHT - bars*barwidth) / 2;
-
- if(graph_settings.changed.amp_scale)
- max = 0; /* reset the graph on scaling mode change */
+ const int offset = (LCD_HEIGHT - bars*barwidth + border) / 2;
+ mylcd_clear_display();
mylcd_vline(0, 0, LCD_HEIGHT-1); /* Draw baseline */
- if(calc_magnitudes(graph_settings.logarithmic_amp) == 0)
+ if(this_max == 0)
return; /* nothing more to draw */
- if(graph_settings.logarithmic_freq)
- logarithmic_plot_translate();
-
int bins_acc = bars / 2;
- int bins_max = 0;
- int y = 0, i = 0;
+ unsigned bins_max = 0;
- for(;;)
+ for(int i = 0, y = offset;; ++i)
{
- int bin = plot[i++];
+ unsigned bin = plot[i];
- if (bin > bins_max)
+ if(bin > bins_max)
bins_max = bin;
bins_acc += bars;
if(bins_acc >= ARRAYLEN_PLOT)
{
- plot[y] = bins_max;
-
- if(bins_max > max)
- max = bins_max;
+ int w = LCD_WIDTH*bins_max / graph_max;
+ mylcd_fillrect(1, y, w, height);
- if(++y >= bars)
+ if(i >= ARRAYLEN_PLOT-1)
break;
+ y += barwidth;
bins_acc -= ARRAYLEN_PLOT;
bins_max = 0;
}
}
-
- for(i = 0, y = offset; i < bars; ++i, y += barwidth)
- {
- int w = LCD_WIDTH * plot[i] / max;
- mylcd_fillrect(1, y, w, height);
- }
}
-static void draw_spectrogram_vertical(void)
+static void draw_spectrogram_vertical(unsigned this_max, unsigned graph_max)
{
- const int32_t scale_factor = MIN(LCD_HEIGHT, ARRAYLEN_PLOT);
-
- calc_magnitudes(graph_settings.logarithmic_amp);
+ const int scale_factor = MIN(LCD_HEIGHT, ARRAYLEN_PLOT);
- if(graph_settings.logarithmic_freq)
- logarithmic_plot_translate();
+ if(fft_spectrogram_pos < LCD_WIDTH-1)
+ fft_spectrogram_pos++;
+ else
+ mylcd_scroll_left(1);
int bins_acc = scale_factor / 2;
- int bins_max = 0;
- int y = 0, i = 0;
+ unsigned bins_max = 0;
- for(;;)
+ for(int i = 0, y = LCD_HEIGHT-1;; ++i)
{
- int bin = plot[i++];
+ unsigned bin = plot[i];
if(bin > bins_max)
bins_max = bin;
@@ -1096,12 +915,7 @@ static void draw_spectrogram_vertical(void)
if(bins_acc >= ARRAYLEN_PLOT)
{
- unsigned index;
-
- if(graph_settings.logarithmic_amp)
- index = (SHADES-1)*bins_max / QLOG_MAX;
- else
- index = (SHADES-1)*bins_max / QLIN_MAX;
+ unsigned index = (SHADES-1)*bins_max / graph_max;
/* These happen because we exaggerate the graph a little for
* linear mode */
@@ -1109,10 +923,9 @@ static void draw_spectrogram_vertical(void)
index = SHADES-1;
mylcd_set_foreground(SPECTROGRAPH_PALETTE(index));
- mylcd_drawpixel(graph_settings.spectrogram_pos,
- scale_factor-1 - y);
+ mylcd_drawpixel(fft_spectrogram_pos, y);
- if(++y >= scale_factor)
+ if(--y < 0)
break;
bins_acc -= ARRAYLEN_PLOT;
@@ -1120,28 +933,24 @@ static void draw_spectrogram_vertical(void)
}
}
- if(graph_settings.spectrogram_pos < LCD_WIDTH-1)
- graph_settings.spectrogram_pos++;
- else
- mylcd_scroll_left(1);
+ (void)this_max;
}
-static void draw_spectrogram_horizontal(void)
+static void draw_spectrogram_horizontal(unsigned this_max, unsigned graph_max)
{
- const int32_t scale_factor = MIN(LCD_WIDTH, ARRAYLEN_PLOT);
+ const int scale_factor = MIN(LCD_WIDTH, ARRAYLEN_PLOT);
- calc_magnitudes(graph_settings.logarithmic_amp);
-
- if(graph_settings.logarithmic_freq)
- logarithmic_plot_translate();
+ if(fft_spectrogram_pos < LCD_HEIGHT-1)
+ fft_spectrogram_pos++;
+ else
+ mylcd_scroll_up(1);
int bins_acc = scale_factor / 2;
- int bins_max = 0;
- int x = 0, i = 0;
+ unsigned bins_max = 0;
- for(;;)
+ for(int i = 0, x = 0;; ++i)
{
- int bin = plot[i++];
+ unsigned bin = plot[i];
if(bin > bins_max)
bins_max = bin;
@@ -1150,12 +959,7 @@ static void draw_spectrogram_horizontal(void)
if(bins_acc >= ARRAYLEN_PLOT)
{
- unsigned index;
-
- if(graph_settings.logarithmic_amp)
- index = (SHADES-1)*bins_max / QLOG_MAX;
- else
- index = (SHADES-1)*bins_max / QLIN_MAX;
+ unsigned index = (SHADES-1)*bins_max / graph_max;
/* These happen because we exaggerate the graph a little for
* linear mode */
@@ -1163,9 +967,9 @@ static void draw_spectrogram_horizontal(void)
index = SHADES-1;
mylcd_set_foreground(SPECTROGRAPH_PALETTE(index));
- mylcd_drawpixel(x, graph_settings.spectrogram_pos);
+ mylcd_drawpixel(x, fft_spectrogram_pos);
- if(++x >= scale_factor)
+ if(++x >= LCD_WIDTH)
break;
bins_acc -= ARRAYLEN_PLOT;
@@ -1173,15 +977,14 @@ static void draw_spectrogram_horizontal(void)
}
}
- if(graph_settings.spectrogram_pos < LCD_HEIGHT-1)
- graph_settings.spectrogram_pos++;
- else
- mylcd_scroll_up(1);
+ (void)this_max;
}
-/********************* End of plotting functions (modes) *********************/
+/******************** End of plotting functions (modes) ********************/
+
+
+/***************************** FFT functions *******************************/
-/****************************** FFT functions ********************************/
static bool is_playing(void)
{
return rb->mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) == CHANNEL_PLAYING;
@@ -1232,7 +1035,7 @@ static inline bool fft_get_fft(void)
input[fft_idx].r = (left + right) >> 1; /* to mono */
} while (fft_idx++, --count > 0);
- apply_window_func(graph_settings.window_func);
+ apply_window_func(fft.window_func);
rb->yield();
@@ -1246,14 +1049,14 @@ static inline bool fft_get_fft(void)
#if NUM_CORES > 1
/* use a worker thread if there is another processor core */
static volatile bool fft_thread_run SHAREDDATA_ATTR = false;
-static unsigned long fft_thread;
+static unsigned long fft_thread = 0;
static long fft_thread_stack[CACHEALIGN_UP(DEFAULT_STACK_SIZE*4/sizeof(long))]
CACHEALIGN_AT_LEAST_ATTR(4);
static void fft_thread_entry(void)
{
- if (!fft_init_fft_lib())
+ if(!fft_init_fft_lib())
{
output_tail = -1; /* tell that we bailed */
fft_thread_run = true;
@@ -1276,7 +1079,8 @@ static void fft_thread_entry(void)
continue;
}
- /* write back output for other processor and invalidate for next frame read */
+ /* write back output for other processor and invalidate for next
+ frame read */
rb->commit_discard_dcache();
int new_tail = output_tail ^ 1;
@@ -1364,168 +1168,433 @@ static inline void fft_close_fft(void)
/* nothing to do */
}
#endif /* NUM_CORES */
-/*************************** End of FFT functions ****************************/
-enum plugin_status plugin_start(const void* parameter)
+/************************** End of FFT functions ***************************/
+
+
+/****************************** OSD functions ******************************/
+
+/* Format a message to display */
+static void fft_osd_format_message(enum fft_setting_flags id)
{
- /* Defaults */
- bool run = true;
- bool showing_warning = false;
+ const char *msg = "";
- if (!fft_init_fft())
- return PLUGIN_ERROR;
+ 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;
+
+#ifdef FFT_FREQ_SCALE /* 'Till all keymaps are defined */
+ case FFT_SETF_FS:
+ msg = (const char * [FFT_MAX_FS]) {
+ [FFT_FS_LOG] = "Logarithmic frequency",
+ [FFT_FS_LIN] = "Linear frequency",
+ }[fft.freq_scale];
+ break;
+#endif
+
+ 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;
+ }
+ }
+
+#ifdef FFT_FREQ_SCALE /* 'Till all keymaps are defined */
+ if(which & FFT_SETF_FS)
+ {
+ plot = fft.freq_scale == FFT_FS_LIN ?
+ linf_magnitudes : logf_magnitudes;
+ }
+#endif
+
+ 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 */
+ 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
#ifndef HAVE_LCD_COLOR
- unsigned char *gbuf;
- size_t gbuf_size = 0;
- /* get the remainder of the plugin buffer */
- gbuf = (unsigned char *) rb->plugin_get_buffer(&gbuf_size);
+ 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);
+ 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
/* initialize the greyscale buffer.*/
- if (!grey_init(gbuf, gbuf_size, GREY_ON_COP | GREY_BUFFERED,
- LCD_WIDTH, LCD_HEIGHT, NULL))
+ long grey_size;
+ if(!grey_init(buf, bufsize, GREY_ON_COP | GREY_BUFFERED,
+ LCD_WIDTH, LCD_HEIGHT, &grey_size))
{
rb->splash(HZ, "Couldn't init greyscale display");
- fft_close_fft();
- return PLUGIN_ERROR;
+ return false;
}
- grey_show(true);
-#endif
- logarithmic_plot_init();
+ grey_show(true);
+
+ buf += grey_size;
+ bufsize -= grey_size;
+#endif /* !HAVE_LCD_COLOR */
+
+ fft_osd_init(buf, bufsize);
#if LCD_DEPTH > 1
+ myosd_lcd_update_prepare();
rb->lcd_set_backdrop(NULL);
mylcd_clear_display();
- mylcd_update();
+ myosd_lcd_update();
#endif
backlight_ignore_timeout();
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
- rb->cpu_boost(true);
+ rb->trigger_cpu_boost();
#endif
- while (run)
- {
- /* Unless otherwise specified, HZ/50 is around the window length
- * and quite fast. We want to be done with drawing by this time. */
- long next_frame_tick = *rb->current_tick + HZ/50;
- int button;
-
- while (!fft_have_fft())
- {
- int timeout;
-
- if(!is_playing())
- {
- showing_warning = true;
- mylcd_clear_display();
- draw_message_string("No audio playing", false);
- mylcd_update();
- timeout = HZ/5;
- }
- else
- {
- if(showing_warning)
- {
- showing_warning = false;
- mylcd_clear_display();
- mylcd_update();
- }
+ logarithmic_plot_init();
+ fft_setting_update(FFT_SETF_ALL);
+ fft_next_frame_tick = *rb->current_tick;
- timeout = HZ/100; /* 'till end of curent tick, don't use 100% CPU */
- }
+ return true;
+}
- /* Make sure the FFT has produced something before doing anything
- * but watching for buttons. Music might not be playing or things
- * just aren't going well for picking up buffers so keys are
- * scanned to avoid lockup. */
- button = rb->button_get_w_tmo(timeout);
- if (button != BUTTON_NONE)
- goto read_button;
- }
+enum plugin_status plugin_start(const void* parameter)
+{
+ bool run = true;
- draw(NULL);
+ if(!fft_setup())
+ return PLUGIN_ERROR;
- fft_free_fft_output(); /* COP only */
+ while(run)
+ {
+ long delay = fft_draw();
- long tick = *rb->current_tick;
- if(TIME_BEFORE(tick, next_frame_tick))
- {
- tick = next_frame_tick - tick;
- }
- else
+ if(delay <= 0)
{
+ delay = 0;
rb->yield(); /* tmo = 0 won't yield */
- tick = 0;
}
- button = rb->button_get_w_tmo(tick);
- read_button:
+ int button = rb->button_get_w_tmo(delay);
+
switch (button)
{
case FFT_QUIT:
run = false;
break;
- case FFT_PREV_GRAPH: {
- if (graph_settings.mode-- <= FFT_DM_FIRST)
- graph_settings.mode = FFT_DM_COUNT-1;
- graph_settings.changed.mode = true;
- draw(modes_text[graph_settings.mode]);
+
+ 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);
break;
- }
- case FFT_NEXT_GRAPH: {
- if (++graph_settings.mode >= FFT_DM_COUNT)
- graph_settings.mode = FFT_DM_FIRST;
- graph_settings.changed.mode = true;
- draw(modes_text[graph_settings.mode]);
+
+ 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);
break;
- }
- case FFT_WINDOW: {
- if(++graph_settings.window_func >= FFT_WF_COUNT)
- graph_settings.window_func = FFT_WF_FIRST;
- graph_settings.changed.window_func = true;
- draw(window_text[graph_settings.window_func]);
+
+ 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);
break;
- }
- case FFT_AMP_SCALE: {
- graph_settings.logarithmic_amp = !graph_settings.logarithmic_amp;
- graph_settings.changed.amp_scale = true;
- draw(amp_scales_text[graph_settings.logarithmic_amp ? 1 : 0]);
+
+ 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);
break;
- }
+
#ifdef FFT_FREQ_SCALE /* 'Till all keymaps are defined */
- case FFT_FREQ_SCALE: {
- graph_settings.logarithmic_freq = !graph_settings.logarithmic_freq;
- graph_settings.changed.freq_scale = true;
- draw(freq_scales_text[graph_settings.logarithmic_freq ? 1 : 0]);
+ 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);
break;
- }
#endif
- case FFT_ORIENTATION: {
- graph_settings.orientation_vertical =
- !graph_settings.orientation_vertical;
- graph_settings.changed.orientation = true;
- draw(NULL);
+ 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);
break;
- }
- default: {
- if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
- return PLUGIN_USB_CONNECTED;
- }
+ default:
+ exit_on_usb(button);
+ break;
}
}
- fft_close_fft();
-
-#ifdef HAVE_ADJUSTABLE_CPU_FREQ
- rb->cpu_boost(false);
-#endif
-#ifndef HAVE_LCD_COLOR
- grey_release();
-#endif
- backlight_use_settings();
return PLUGIN_OK;
(void)parameter;
}