Phil Pertermann's dB peak meter patch

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@2774 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Linus Nielsen Feltzing 2002-10-29 12:09:15 +00:00
parent 8f11dc00ac
commit fd0cc3b2b1
10 changed files with 1035 additions and 99 deletions

View file

@ -40,6 +40,7 @@
#include "mpeg.h"
#ifdef HAVE_LCD_BITMAP
#include "widgets.h"
#include "peakmeter.h"
#endif
/*---------------------------------------------------*/
@ -1031,7 +1032,10 @@ bool debug_menu(void)
{ "View partitions", dbg_partitions },
#ifdef HAVE_LCD_BITMAP
{ "View mpeg thread", dbg_mpeg_thread },
#endif
#ifdef PM_DEBUG
{ "pm histogram", peak_meter_histogram},
#endif /* PM_DEBUG */
#endif /* HAVE_LCD_BITMAP */
};
m=menu_init( items, sizeof items / sizeof(struct menu_items) );
@ -1042,4 +1046,3 @@ bool debug_menu(void)
}
#endif /* SIMULATOR */

View file

@ -866,6 +866,46 @@ desc: in the peak meter menu
eng: "Units Per Read"
new:
id: LANG_PM_PERFORMANCE
desc: in the peak meter menu
eng: "Performance"
new:
id: LANG_PM_HIGH_PERFORMANCE
desc: in the peak meter menu
eng: "High performance"
new:
id: LANG_PM_ENERGY_SAVER
desc: in the peak meter menu
eng: "Save energy"
new:
id: LANG_PM_SCALE
desc: in the peak meter menu
eng: "dBfs <-> linear"
new:
id: LANG_PM_DBFS
desc: in the peak meter menu
eng: "dBfs"
new:
id: LANG_PM_LINEAR
desc: in the peak meter menu
eng: "linear"
new:
id: LANG_PM_MIN
desc: in the peak meter menu
eng: "Minimum of range"
new:
id: LANG_PM_MAX
desc: in the peak meter menu
eng: "Maximum of range"
new:
id: LANG_BACKLIGHT_ON_WHEN_CHARGING
desc: in display_settings_menu
eng: "Backlight On When Plugged"

View file

@ -46,24 +46,52 @@ static bool peak_meter_r_clip = false;
static long peak_meter_clip_timeout_l;
static long peak_meter_clip_timeout_r;
static int peak_meter_clip_hold;
/* specifies the value range in peak volume values */
unsigned short peak_meter_range_min;
unsigned short peak_meter_range_max;
/* if set to true clip timeout is disabled */
static bool peak_meter_clip_eternal = false;
static bool peak_meter_use_dbfs = true;
#ifndef SIMULATOR
static int peak_meter_src_l = MAS_REG_DQPEAK_L;
static int peak_meter_src_r = MAS_REG_DQPEAK_R;
#endif
/* temporarily en- / disables peak meter. This is
especially for external applications to detect
if the peak_meter is in use and needs drawing at all */
bool peak_meter_enabled = true;
/*
bool peak_meter_use_thread = false;
static char peak_meter_stack[DEFAULT_STACK_SIZE];
*/
/* used in wps.c to set the display frame rate of the peak meter */
int peak_meter_fps = 20;
static int peak_meter_l;
static int peak_meter_r;
static int peak_meter_hold = 1;
static int peak_meter_release = 8;
/* debug only */
#ifdef PM_DEBUG
static int peek_calls = 0;
#define PEEKS_PER_DRAW_SIZE 40
static unsigned int peeks_per_redraw[PEEKS_PER_DRAW_SIZE];
#define TICKS_PER_DRAW_SIZE 20
static unsigned int ticks_per_redraw[TICKS_PER_DRAW_SIZE];
#endif
/* time out values for max */
static long max_time_out[] = {
0 * HZ, HZ / 5, 30, HZ / 2, HZ, 2 * HZ,
@ -80,6 +108,353 @@ static long clip_time_out[] = {
2700 * HZ, 5400 * HZ
};
/* precalculated peak values that represent magical
dBfs values. Used to draw the scale */
#if 0
static int db_scale_src_values[] = {
32767, /* 0 db */
23197, /* - 3 db */
16422, /* - 6 db */
11626, /* - 9 db */
8231, /* -12 db */
4125, /* -18 db */
2067, /* -24 db */
1036, /* -30 db */
328, /* -40 db */
104, /* -50 db */
33, /* -60 db */
};
#else
static int db_scale_src_values[] = {
32752, /* 0 db */
22784, /* - 3 db */
14256, /* - 6 db */
11752, /* - 9 db */
9256, /* -12 db */
4256, /* -18 db */
2186, /* -24 db */
1186, /* -30 db */
373, /* -40 db */
102, /* -50 db */
33, /* -60 db */
};
#endif
int db_scale_count = sizeof db_scale_src_values / sizeof (int);
/* if db_scale_valid is false the content of
db_scale_lcd_coord needs recalculation */
static bool db_scale_valid = false;
/* contains the lcd x coordinates of the magical
scale values in db_scale_src_values */
static int db_scale_lcd_coord[sizeof db_scale_src_values / sizeof (int)];
/**
* Calculates dB Value for the peak meter, uses peak value as input
* @param int sample - The input value
* Make sure that 0 <= value < SAMPLE_RANGE
*
* @return int - The 2 digit fixed comma result of the euation
* 20 * log (sample / SAMPLE_RANGE) + 90
* Output range is 0-8961 (that is 0,0 - 89,6 dB).
* Normally 0dB is full scale, here it is shifted +90dB.
* The calculation is based on the results of a linear
* approximation tool written specifically for this problem
* by Andreas Zwirtes (radhard@gmx.de). The result hat an
* accurracy of better than 2%. It is highly runtime optimized,
* the cascading if-clauses do an successive approximation on
* the input value. This avoids big lookup-tables and
* for-loops.
*/
int calc_db (int isample) {
/* return n+m*(isample-istart)/100 */
int n;
long m;
int istart;
/* Range 1-4 */
if (isample < 119) {
/* Range 1-2 */
if (isample < 5) {
/* Range 1 */
if (isample < 1) {
istart = 0;
n = 0;
m = 5900;
}
/* Range 2 */
else {
istart = 1;
n = 59;
m = 34950;
}
}
/* Range 3-4 */
else {
/* Range 3 */
if (isample < 24) {
istart = 5;
n = 1457;
m = 7168;
}
/* Range 4 */
else {
istart = 24;
n = 2819;
m = 1464;
}
}
}
/* Range 5-8 */
else {
/* Range 5-6 */
if (isample < 2918) {
/* Range 5 */
if (isample < 592) {
istart = 119;
n = 4210;
m = 295;
}
/* Range 6 */
else {
istart = 592;
n = 5605;
m = 60;
}
}
/* Range 7-8 */
else {
/* Range 7 */
if (isample < 15352) {
istart = 2918;
n = 7001;
m = 12;
}
/* Range 8 */
else {
istart = 15352;
n = 8439;
m = 3;
}
}
}
return n + (m * (long)(isample - istart)) / 100L;
}
/**
* A helper function for db_to_sample. Don't call it separately but
* use db_to_sample. If one or both of min and max are outside the
* range 0 <= min (or max) < 8961 the behaviour of this function is
* undefined. It may not return.
* @param int min - The minimum of the value range that is searched.
* @param int max - The maximum of the value range that is searched.
* @param int db - The value in dBfs * (-100) for which the according
* minimal peak sample is searched.
* @return int - A linear volume value with 0 <= value < MAX_PEAK
*/
static int db_to_sample_bin_search(int min, int max, int db){
int test = min + (max - min) / 2;
if (min < max) {
if (calc_db(test) < db) {
test = db_to_sample_bin_search(test, max, db);
} else {
if (calc_db(test-1) > db) {
test = db_to_sample_bin_search(min, test, db);
}
}
}
return test;
}
/**
* Converts a value representing dBfs to a linear
* scaled volume info as it is used by the MAS.
* An incredibly inefficiant function which is
* the vague inverse of calc_db. This really
* should be replaced by something better soon.
*
* @param int db - A dBfs * 100 value with
* -9000 < value <= 0
* @return int - The return value is in the range of
* 0 <= return value < MAX_PEAK
*/
static int db_to_sample(int db) {
int retval = 0;
/* what is the maximum pseudo db value */
int max_peak_db = calc_db(MAX_PEAK - 1);
/* range check: db value to big */
if (max_peak_db + db < 0) {
retval = 0;
}
/* range check: db value too small */
else if (max_peak_db + db >= max_peak_db) {
retval = MAX_PEAK -1;
}
/* value in range: find the matching linear value */
else {
retval = db_to_sample_bin_search(0, MAX_PEAK, max_peak_db + db);
/* as this is a dirty function anyway, we want to adjust the
full scale hit manually to avoid users complaining that when
they adjust maximum for 0 dBfs and display it in percent it
shows 99%. That is due to precision loss and this is the
optical fix */
}
return retval;
}
/**
* Set the min value for restriction of the value range.
* @param int newmin - depending wether dBfs is used
* newmin is a value in dBfs * 100 or in linear percent values.
* for dBfs: -9000 < newmin <= 0
* for linear: 0 <= newmin <= 100
*/
void peak_meter_set_min(int newmin) {
if (peak_meter_use_dbfs) {
peak_meter_range_min = db_to_sample(newmin);
} else {
if (newmin < peak_meter_range_max) {
peak_meter_range_min = newmin * MAX_PEAK / 100;
}
}
db_scale_valid = false;
}
/**
* Returns the minimum value of the range the meter
* displays. If the scale is set to dBfs it returns
* dBfs values * 100 or linear percent values.
* @return: using dBfs : -9000 < value <= 0
* using linear scale: 0 <= value <= 100
*/
int peak_meter_get_min(void) {
int retval = 0;
if (peak_meter_use_dbfs) {
retval = calc_db(peak_meter_range_min) - calc_db(MAX_PEAK - 1);
} else {
retval = peak_meter_range_min * 100 / MAX_PEAK;
}
return retval;
}
/**
* Set the max value for restriction of the value range.
* @param int newmax - depending wether dBfs is used
* newmax is a value in dBfs * 100 or in linear percent values.
* for dBfs: -9000 < newmax <= 0
* for linear: 0 <= newmax <= 100
*/
void peak_meter_set_max(int newmax) {
if (peak_meter_use_dbfs) {
peak_meter_range_max = db_to_sample(newmax);
} else {
if (newmax > peak_meter_range_min) {
peak_meter_range_max = newmax * MAX_PEAK / 100;
}
}
db_scale_valid = false;
}
/**
* Returns the minimum value of the range the meter
* displays. If the scale is set to dBfs it returns
* dBfs values * 100 or linear percent values
* @return: using dBfs : -9000 < value <= 0
* using linear scale: 0 <= value <= 100
*/
int peak_meter_get_max(void) {
int retval = 0;
if (peak_meter_use_dbfs) {
retval = calc_db(peak_meter_range_max) - calc_db(MAX_PEAK - 1);
} else {
retval = peak_meter_range_max * 100 / MAX_PEAK;
}
return retval;
}
/**
* Returns 1 if the meter currently is
* displaying dBfs values, 0 if the meter
* displays percent values.
* @return int - returns 0 or 1.
*/
int peak_meter_get_use_dbfs(void) {
return peak_meter_use_dbfs ? 1 : 0;
}
/**
* Specifies wether the values displayed are scaled
* as dBfs or as linear percent values.
* @param int - Set to 0 for linear percent scale. Any other value
* switches on dBfs.
*/
void peak_meter_set_use_dbfs(int use){
peak_meter_use_dbfs = ((use & 1) == 1);
db_scale_valid = false;
}
/**
* Initialize the range of the meter. Only values
* that are in the range of [range_min ... range_max]
* are displayed.
* @param bool dbfs - set to true for dBfs,
* set to false for linear scaling in percent
* @param int range_min - Specifies the lower value of the range.
* Pass a value dBfs * 100 when dbfs is set to true.
* Pass a percent value when dbfs is set to false.
* @param int range_max - Specifies the upper value of the range.
* Pass a value dBfs * 100 when dbfs is set to true.
* Pass a percent value when dbfs is set to false.
*/
void peak_meter_init_range( bool dbfs, int range_min, int range_max) {
peak_meter_use_dbfs = dbfs;
peak_meter_set_min(range_min);
peak_meter_set_max(range_max);
}
/**
* Initialize the peak meter with all relevant values concerning times.
* @param int release - Set the maximum amount of pixels the meter is allowed
* to decrease with each redraw
* @param int hold - Select the time preset for the time the peak indicator
* is reset after a peak occurred. The preset values are
* stored in max_time_out.
* @param int clip_hold - Select the time preset for the time the peak
* indicator is reset after a peak occurred. The preset
* values are stored in clip_time_out.
*/
void peak_meter_init_times(int release, int hold, int clip_hold) {
peak_meter_hold = hold;
peak_meter_release = release;
peak_meter_clip_hold = clip_hold;
}
/**
* Set the source of the peak meter to playback or to
* record.
@ -127,21 +502,59 @@ void peak_meter_peek(void) {
(left == MAX_PEAK - 1)) {
peak_meter_l_clip = true;
peak_meter_clip_timeout_l =
current_tick + clip_time_out[global_settings.peak_meter_clip_hold];
current_tick + clip_time_out[peak_meter_clip_hold];
}
if ((right == peak_meter_r) &&
(right == MAX_PEAK - 1)) {
peak_meter_r_clip = true;
peak_meter_clip_timeout_r =
current_tick + clip_time_out[global_settings.peak_meter_clip_hold];
current_tick + clip_time_out[peak_meter_clip_hold];
}
/* peaks are searched -> we have to find the maximum */
/* peaks are searched -> we have to find the maximum. When
many calls of peak_meter_peek the maximum value will be
stored in peak_meter_x. This maximum is reset by the
functions peak_meter_read_x. */
peak_meter_l = MAX(peak_meter_l, left);
peak_meter_r = MAX(peak_meter_r, right);
#ifdef PM_DEBUG
peek_calls++;
#endif
}
/**
* The thread function for the peak meter calls peak_meter_peek
* to reas out the mas and find maxima, clips, etc. No display
* is performed.
*/
/*
void peak_meter_thread(void) {
sleep(5000);
while (1) {
if (peak_meter_enabled && peak_meter_use_thread){
peak_meter_peek();
}
yield();
}
}
*/
/**
* Creates the peak meter thread
*/
/*
void peak_meter_init(void) {
create_thread(
peak_meter_thread,
peak_meter_stack,
sizeof peak_meter_stack,
"peakmeter");
}
*/
/**
* Reads out the peak volume of the left channel.
* @return int - The maximum value that has been detected
@ -149,10 +562,20 @@ void peak_meter_peek(void) {
* is in the range 0 <= value < MAX_PEAK.
*/
static int peak_meter_read_l (void) {
/* peak_meter_l contains the maximum of
all peak values that were read by peak_meter_peek
since the last call of peak_meter_read_r */
int retval = peak_meter_l;
#ifdef PM_DEBUG
peek_calls = 0;
#endif
#ifdef SIMULATOR
peak_meter_l = 8000;
#else
/* reset peak_meter_l so that subsequent calls of
peak_meter_peek doesn't get fooled by an old
maximum value */
peak_meter_l = mas_codec_readreg(peak_meter_src_l);
#endif
return retval;
@ -165,10 +588,20 @@ static int peak_meter_read_l (void) {
* is in the range 0 <= value < MAX_PEAK.
*/
static int peak_meter_read_r (void) {
/* peak_meter_r contains the maximum of
all peak values that were read by peak_meter_peek
since the last call of peak_meter_read_r */
int retval = peak_meter_r;
#ifdef PM_DEBUG
peek_calls = 0;
#endif
#ifdef SIMULATOR
peak_meter_l = 8000;
#else
/* reset peak_meter_r so that subsequent calls of
peak_meter_peek doesn't get fooled by an old
maximum value */
peak_meter_r = mas_codec_readreg(peak_meter_src_r);
#endif
return retval;
@ -190,6 +623,51 @@ void peak_meter_set_clip_hold(int time) {
}
}
/**
* Scales a peak value as read from the MAS to the range of meterwidth.
* The scaling is performed according to the scaling method (dBfs / linear)
* and the range (peak_meter_range_min .. peak_meter_range_max).
* @param unsigned short val - The volume value. Range: 0 <= val < MAX_PEAK
* @param int meterwidht - The widht of the meter in pixel
* @return unsigned short - A value 0 <= return value <= meterwidth
*/
unsigned short peak_meter_scale_value(unsigned short val, int meterwidth){
int range;
int retval;
if (val <= peak_meter_range_min) {
return 0;
}
if (val >= peak_meter_range_max) {
return meterwidth;
}
retval = val;
/* different scaling is used for dBfs and linear percent */
if (peak_meter_use_dbfs) {
/* needed the offset in 'zoomed' meters */
int dbmin = calc_db(peak_meter_range_min);
range = calc_db(peak_meter_range_max) - dbmin;
/* scale the samples dBfs */
retval = (calc_db(retval) - dbmin) * meterwidth / range;
}
/* Scale for linear percent display */
else
{
range =(peak_meter_range_max - peak_meter_range_min);
/* scale the samples */
retval = ((retval - peak_meter_range_min) * meterwidth) / range;
}
return retval;
}
/**
* Draws a peak meter in the specified size at the specified position.
@ -208,22 +686,66 @@ void peak_meter_draw(int x, int y, int width, int height) {
int meterwidth = width - 3;
int i;
#ifdef PM_DEBUG
static long pm_tick = 0;
int tmp = peek_calls;
#endif
/* if disabled only draw the peak meter */
if (peak_meter_enabled) {
/* read the volume info from MAS */
left = peak_meter_read_l();
right = peak_meter_read_r();
peak_meter_peek();
/* restrict the range to avoid drawing outside the lcd */
left = MAX(peak_meter_range_min, left);
left = MIN(peak_meter_range_max, left);
/* scale the samples */
left /= (MAX_PEAK / meterwidth);
right /= (MAX_PEAK / meterwidth);
right = MAX(peak_meter_range_min, right);
right = MIN(peak_meter_range_max, right);
/* scale the samples dBfs */
left = peak_meter_scale_value(left, meterwidth);
right = peak_meter_scale_value(right, meterwidth);
/* if the scale has changed -> recalculate the scale
(The scale becomes invalid when the range changed.) */
if (!db_scale_valid){
if (peak_meter_use_dbfs) {
db_scale_count = sizeof db_scale_src_values / sizeof (int);
for (i = 0; i < db_scale_count; i++){
/* find the real x-coords for predefined interesting
dBfs values. These only are recalculated when the
scaling of the meter changed. */
db_scale_lcd_coord[i] =
peak_meter_scale_value(
db_scale_src_values[i],
meterwidth - 1);
}
}
/* when scaling linear we simly make 10% steps */
else {
int range = peak_meter_range_max - peak_meter_range_min;
db_scale_count = 10;
for (i = 0; i < db_scale_count; i++) {
db_scale_lcd_coord[i] =
(i * (MAX_PEAK / 10) - peak_meter_range_min) *
meterwidth / range;
}
}
/* mark scale valid to avoid recalculating dBfs values
of the scale. */
db_scale_valid = true;
}
/* apply release */
left = MAX(left , last_left - global_settings.peak_meter_release);
right = MAX(right, last_right - global_settings.peak_meter_release);
left = MAX(left , last_left - peak_meter_release);
right = MAX(right, last_right - peak_meter_release);
/* reset max values after timeout */
if (TIME_AFTER(current_tick, peak_meter_timeout_l)){
@ -250,13 +772,13 @@ void peak_meter_draw(int x, int y, int width, int height) {
if (left > peak_meter_max_l) {
peak_meter_max_l = left - 1;
peak_meter_timeout_l =
current_tick + max_time_out[global_settings.peak_meter_hold];
current_tick + max_time_out[peak_meter_hold];
}
if (right > peak_meter_max_r) {
peak_meter_max_r = right - 1;
peak_meter_timeout_r =
current_tick + max_time_out[global_settings.peak_meter_hold];
current_tick + max_time_out[peak_meter_hold];
}
}
@ -283,13 +805,90 @@ void peak_meter_draw(int x, int y, int width, int height) {
lcd_fillrect(x + meterwidth, y + height / 2, 3, height / 2 - 1);
}
/* draw scale */
/* draw scale end */
lcd_drawline(x + meterwidth, y,
x + meterwidth, y + height - 2);
for (i = 0; i < 10; i++) {
lcd_invertpixel(x + meterwidth * i / 10, y + height / 2 - 1);
/* draw dots for scale marks */
for (i = 0; i < db_scale_count; i++) {
/* The x-coordinates of interesting scale mark points
have been calculated before */
lcd_invertpixel(db_scale_lcd_coord[i], y + height / 2 - 1);
}
#ifdef PM_DEBUG
/* display a bar to show how many calls to peak_meter_peek
have ocurred since the last display */
lcd_invertrect(x, y, tmp, 3);
if (tmp < PEEKS_PER_DRAW_SIZE) {
peeks_per_redraw[tmp]++;
}
tmp = current_tick - pm_tick;
if (tmp < TICKS_PER_DRAW_SIZE ){
ticks_per_redraw[tmp] ++;
}
/* display a bar to show how many ticks have passed since
the last redraw */
lcd_invertrect(x, y + height / 2, current_tick - pm_tick, 2);
pm_tick = current_tick;
#endif
last_left = left;
last_right = right;
}
#ifdef PM_DEBUG
static void peak_meter_clear_histogram(void) {
int i = 0;
for (i = 0; i < TICKS_PER_DRAW_SIZE; i++) {
ticks_per_redraw[i] = (unsigned int)0;
}
for (i = 0; i < PEEKS_PER_DRAW_SIZE; i++) {
peeks_per_redraw[i] = (unsigned int)0;
}
}
bool peak_meter_histogram(void) {
int i;
int btn = BUTTON_NONE;
while ((btn & BUTTON_OFF) != BUTTON_OFF )
{
unsigned int max = 0;
int y = 0;
int x = 0;
lcd_clear_display();
for (i = 0; i < PEEKS_PER_DRAW_SIZE; i++) {
max = MAX(max, peeks_per_redraw[i]);
}
for (i = 0; i < PEEKS_PER_DRAW_SIZE; i++) {
x = peeks_per_redraw[i] * (LCD_WIDTH - 1)/ max;
lcd_drawline(0, y + i, x, y + i);
}
y = PEEKS_PER_DRAW_SIZE + 1;
max = 0;
for (i = 0; i < TICKS_PER_DRAW_SIZE; i++) {
max = MAX(max, ticks_per_redraw[i]);
}
for (i = 0; i < TICKS_PER_DRAW_SIZE; i++) {
x = ticks_per_redraw[i] * (LCD_WIDTH - 1)/ max;
lcd_drawline(0, y + i, x, y + i);
}
lcd_update();
btn = button_get(true);
if (btn == BUTTON_PLAY) {
peak_meter_clear_histogram();
}
}
return false;
}
#endif

View file

@ -19,12 +19,32 @@
#ifndef __PEAKMETER_H__
#define __PEAKMETER_H__
extern bool peak_meter_enabled;
/*#define PM_DEBUG */
#ifdef PM_DEBUG
extern bool peak_meter_histogramm(void);
#endif
extern bool peak_meter_enabled;
extern int peak_meter_fps;
extern void peak_meter_init(void);
extern void peak_meter_playback(bool playback);
extern void peak_meter_draw(int x, int y, int width, int height);
extern void peak_meter_set_clip_hold(int time);
extern void peak_meter_peek(void);
extern void peak_meter_init_range( bool dbfs, int range_min, int range_max);
extern void peak_meter_init_times(int release, int hold, int clip_hold);
extern void peak_meter_set_min(int newmin);
extern int peak_meter_get_min(void);
extern void peak_meter_set_max(int newmax);
extern int peak_meter_get_max(void);
extern void peak_meter_set_use_dbfs(int use);
extern int peak_meter_get_use_dbfs(void);
extern int calc_db (int isample);
extern unsigned short peak_meter_scale_value(unsigned short val, int meterwidth);
extern unsigned short peak_meter_range_min;
extern unsigned short peak_meter_range_max;
#endif /* __PEAKMETER_H__ */

View file

@ -44,6 +44,7 @@
#ifdef HAVE_LCD_BITMAP
#include "icons.h"
#include "font.h"
#include "peakmeter.h"
#endif
#include "lang.h"
#include "language.h"
@ -52,7 +53,7 @@
struct user_settings global_settings;
char rockboxdir[] = ROCKBOX_DIR; /* config/font/data file directory */
#define CONFIG_BLOCK_VERSION 2
#define CONFIG_BLOCK_VERSION 3
#define CONFIG_BLOCK_SIZE 512
#define RTC_BLOCK_SIZE 44
@ -89,10 +90,14 @@ offset abs
0x16 0x2a <(int) Byte offset into resume file>
0x1a 0x2e <time until disk spindown>
0x1b 0x2f <browse current, play selected>
0x1c 0x30 <peak meter hold timeout (bit 0-4)>
0x1d 0x31 <peak meter clip hold timeout (bit 0-4)>
0x1e 0x32 <peak meter release step size>
0x1f 0x33 <repeat mode>
0x1c 0x30 <peak meter hold timeout (bit 0-4)>,
peak_meter_performance (bit 7)
0x1d 0x31 <peak meter clip hold timeout (bit 0-4)
0x1e 0x32 <peak meter release step size,
peak_meter_dbfs (bit 7)
0x1f 0x33 <peak meter min either in -db or in percent>
0x20 0x34 <peak meter max either in -db or in percent>
0x21 0x35 <repeat mode>
<all unused space filled with 0xff>
@ -316,9 +321,13 @@ int settings_save( void )
((global_settings.play_selected & 1) << 1));
config_block[0x1c] = (unsigned char)global_settings.peak_meter_hold;
config_block[0x1d] = (unsigned char)global_settings.peak_meter_clip_hold;
config_block[0x1e] = (unsigned char)global_settings.peak_meter_release;
config_block[0x1f] = (unsigned char)global_settings.repeat_mode;
config_block[0x1d] = (unsigned char)global_settings.peak_meter_clip_hold |
(global_settings.peak_meter_performance ? 0x80 : 0);
config_block[0x1e] = global_settings.peak_meter_release |
(global_settings.peak_meter_dbfs ? 0x80 : 0);
config_block[0x1f] = (unsigned char)global_settings.peak_meter_min;
config_block[0x20] = (unsigned char)global_settings.peak_meter_max;
config_block[0x21] = (unsigned char)global_settings.repeat_mode;
memcpy(&config_block[0x24], &global_settings.total_uptime, 4);
@ -355,6 +364,35 @@ int settings_save( void )
return 0;
}
#ifdef HAVE_LCD_BITMAP
/**
* Applies the range infos stored in global_settings to
* the peak meter.
*/
void settings_apply_pm_range(void)
{
int pm_min, pm_max;
/* depending on the scale mode (dBfs or percent) the values
of global_settings.peak_meter_dbfs have different meanings */
if (global_settings.peak_meter_dbfs)
{
/* convert to dBfs * 100 */
pm_min = -(((int)global_settings.peak_meter_min) * 100);
pm_max = -(((int)global_settings.peak_meter_max) * 100);
}
else
{
/* percent is stored directly -> no conversion */
pm_min = global_settings.peak_meter_min;
pm_max = global_settings.peak_meter_max;
}
/* apply the range */
peak_meter_init_range(global_settings.peak_meter_dbfs, pm_min, pm_max);
}
#endif /* HAVE_LCD_BITMAP */
void settings_apply(void)
{
char buf[64];
@ -381,6 +419,13 @@ void settings_apply(void)
CHARGE_RESTART_LO : CHARGE_RESTART_HI;
#endif
#ifdef HAVE_LCD_BITMAP
settings_apply_pm_range();
peak_meter_init_times(
global_settings.peak_meter_release, global_settings.peak_meter_hold,
global_settings.peak_meter_clip_hold);
#endif
if ( global_settings.wps_file[0] &&
global_settings.wps_file[0] != 0xff ) {
snprintf(buf, sizeof buf, ROCKBOX_DIR "/%s.wps",
@ -500,14 +545,25 @@ void settings_load(void)
if (config_block[0x1c] != 0xFF)
global_settings.peak_meter_hold = (config_block[0x1c]) & 0x1f;
if (config_block[0x1d] != 0xFF)
if (config_block[0x1d] != 0xFF) {
global_settings.peak_meter_clip_hold = (config_block[0x1d]) & 0x1f;
global_settings.peak_meter_performance =
(config_block[0x1d] & 0x80) != 0;
}
if (config_block[0x1e] != 0xFF)
global_settings.peak_meter_release = config_block[0x1e];
if (config_block[0x1e] != 0xFF) {
global_settings.peak_meter_release = config_block[0x1e] & 0x7f;
global_settings.peak_meter_dbfs = (config_block[0x1e] & 0x80) != 0;
}
if (config_block[0x1f] != 0xFF)
global_settings.repeat_mode = config_block[0x1f];
global_settings.peak_meter_min = config_block[0x1f];
if (config_block[0x20] != 0xFF)
global_settings.peak_meter_max = config_block[0x20];
if (config_block[0x21] != 0xFF)
global_settings.repeat_mode = config_block[0x21];
if (config_block[0x24] != 0xFF)
memcpy(&global_settings.total_uptime, &config_block[0x24], 4);
@ -685,8 +741,12 @@ void settings_reset(void) {
global_settings.browse_current = false;
global_settings.play_selected = true;
global_settings.peak_meter_release = 8;
global_settings.peak_meter_hold = 1;
global_settings.peak_meter_hold = 3;
global_settings.peak_meter_clip_hold = 16;
global_settings.peak_meter_dbfs = true;
global_settings.peak_meter_min = 60;
global_settings.peak_meter_max = 0;
global_settings.peak_meter_performance = false;
global_settings.wps_file[0] = 0;
global_settings.font_file[0] = 0;
global_settings.lang_file[0] = 0;

View file

@ -100,6 +100,10 @@ struct user_settings
int peak_meter_release; /* units per read out */
int peak_meter_hold; /* hold time for peak meter in 1/100 s */
int peak_meter_clip_hold; /* hold time for clips */
bool peak_meter_dbfs; /* show linear or dbfs values */
bool peak_meter_performance; /* true: high performance, else save energy*/
unsigned char peak_meter_min; /* range minimum */
unsigned char peak_meter_max; /* range maximum */
/* show status bar */
bool statusbar; /* 0=hide, 1=show */
@ -121,6 +125,7 @@ int settings_save(void);
void settings_load(void);
void settings_reset(void);
void settings_apply(void);
void settings_apply_pm_range(void);
void settings_display(void);
bool settings_load_config(char* file);

View file

@ -74,27 +74,44 @@ static bool volume_type(void)
names, 2, NULL);
}
#ifdef PM_DEBUG
static bool peak_meter_fps_menu(void) {
bool retval = false;
retval = set_int( "Refresh rate", "/s",
&peak_meter_fps,
NULL, 1, 5, 40);
return retval;
}
#endif /* PM_DEBUG */
/**
* Menu to set the hold time of normal peaks.
*/
static bool peak_meter_hold(void)
{
static bool peak_meter_hold(void) {
bool retval = false;
char* names[] = { str(LANG_OFF),
"200 ms ", "300 ms ", "500 ms ", "1 s ", "2 s ",
"3 s ", "4 s ", "5 s ", "6 s ", "7 s",
"8 s", "9 s", "10 s", "15 s", "20 s",
"30 s", "1 min"
};
return set_option( str(LANG_PM_PEAK_HOLD),
retval = set_option( str(LANG_PM_PEAK_HOLD),
&global_settings.peak_meter_hold, names,
18, NULL);
peak_meter_init_times(global_settings.peak_meter_release,
global_settings.peak_meter_hold,
global_settings.peak_meter_clip_hold);
return retval;
}
/**
* Menu to set the hold time of clips.
*/
static bool peak_meter_clip_hold(void)
{
static bool peak_meter_clip_hold(void) {
bool retval = false;
char* names[] = { str(LANG_PM_ETERNAL),
"1s ", "2s ", "3s ", "4s ", "5s ",
"6s ", "7s ", "8s ", "9s ", "10s",
@ -103,19 +120,167 @@ static bool peak_meter_clip_hold(void)
"10min", "20min", "45min", "90min"
};
return set_option( str(LANG_PM_CLIP_HOLD),
retval = set_option( str(LANG_PM_CLIP_HOLD),
&global_settings.peak_meter_clip_hold, names,
25, peak_meter_set_clip_hold);
peak_meter_init_times(global_settings.peak_meter_release,
global_settings.peak_meter_hold,
global_settings.peak_meter_clip_hold);
return retval;
}
/**
* Menu to set the release time of the peak meter.
*/
static bool peak_meter_release(void)
{
return set_int( str(LANG_PM_RELEASE), str(LANG_PM_UNITS_PER_READ),
static bool peak_meter_release(void) {
bool retval = false;
/* The range of peak_meter_release is restricted so that it
fits into a 7 bit number. The 8th bit is used for storing
something else in the rtc ram.
Also, the max value is 0x7e, since the RTC value 0xff is reserved */
retval = set_int( str(LANG_PM_RELEASE), str(LANG_PM_UNITS_PER_READ),
&global_settings.peak_meter_release,
NULL, 1, 1, LCD_WIDTH);
NULL, 1, 1, 0x7e);
peak_meter_init_times(global_settings.peak_meter_release,
global_settings.peak_meter_hold,
global_settings.peak_meter_clip_hold);
return retval;
}
/**
* Menu to select wether the scale of the meter
* displays dBfs of linear values.
*/
static bool peak_meter_scale(void) {
bool retval = false;
bool use_dbfs = global_settings.peak_meter_dbfs;
retval = set_bool_options(str(LANG_PM_SCALE),
&use_dbfs,
str(LANG_PM_DBFS), str(LANG_PM_LINEAR));
/* has the user really changed the scale? */
if (use_dbfs != global_settings.peak_meter_dbfs) {
/* store the change */
global_settings.peak_meter_dbfs = use_dbfs;
peak_meter_set_use_dbfs(use_dbfs);
/* If the user changed the scale mode the meaning of
peak_meter_min (peak_meter_max) has changed. Thus we have
to convert the values stored in global_settings. */
if (use_dbfs) {
/* we only store -dBfs */
global_settings.peak_meter_min = -peak_meter_get_min() / 100;
global_settings.peak_meter_max = -peak_meter_get_max() / 100;
} else {
int max;
/* linear percent */
global_settings.peak_meter_min = peak_meter_get_min();
/* converting dBfs -> percent results in a precision loss.
I assume that the user doesn't bother that conversion
dBfs <-> percent isn't symmetrical for odd values but that
he wants 0 dBfs == 100%. Thus I 'correct' the percent value
resulting from dBfs -> percent manually here */
max = peak_meter_get_max();
global_settings.peak_meter_max = max < 99 ? max : 100;
}
settings_apply_pm_range();
}
return retval;
}
/**
* Adjust the min value of the value range that
* the peak meter shall visualize.
*/
static bool peak_meter_min(void) {
bool retval = false;
if (global_settings.peak_meter_dbfs) {
/* for dBfs scale */
int range_max = -global_settings.peak_meter_max;
int min = -global_settings.peak_meter_min;
retval = set_int(str(LANG_PM_MIN), str(LANG_PM_DBFS),
&min, NULL, 1, -89, range_max);
global_settings.peak_meter_min = - min;
}
/* for linear scale */
else {
int min = global_settings.peak_meter_min;
retval = set_int(str(LANG_PM_MIN), "%",
&min, NULL,
1, 0, global_settings.peak_meter_max - 1);
global_settings.peak_meter_min = (unsigned char)min;
}
settings_apply_pm_range();
return retval;
}
/**
* Adjust the max value of the value range that
* the peak meter shall visualize.
*/
static bool peak_meter_max(void) {
bool retval = false;
if (global_settings.peak_meter_dbfs) {
/* for dBfs scale */
int range_min = -global_settings.peak_meter_min;
int max = -global_settings.peak_meter_max;;
retval = set_int(str(LANG_PM_MAX), str(LANG_PM_DBFS),
&max, NULL, 1, range_min, 0);
global_settings.peak_meter_max = - max;
}
/* for linear scale */
else {
int max = global_settings.peak_meter_max;
retval = set_int(str(LANG_PM_MAX), "%",
&max, NULL,
1, global_settings.peak_meter_min + 1, 100);
global_settings.peak_meter_max = (unsigned char)max;
}
settings_apply_pm_range();
return retval;
}
/**
* Menu to select wether the meter is in
* precision or in energy saver mode
*/
static bool peak_meter_performance(void) {
bool retval = false;
retval = set_bool_options(str(LANG_PM_PERFORMANCE),
&global_settings.peak_meter_performance,
str(LANG_PM_HIGH_PERFORMANCE), str(LANG_PM_ENERGY_SAVER));
if (global_settings.peak_meter_performance) {
peak_meter_fps = 25;
} else {
peak_meter_fps = 20;
}
return retval;
}
/**
@ -130,6 +295,13 @@ static bool peak_meter_menu(void)
{ str(LANG_PM_RELEASE) , peak_meter_release },
{ str(LANG_PM_PEAK_HOLD), peak_meter_hold },
{ str(LANG_PM_CLIP_HOLD), peak_meter_clip_hold },
{ str(LANG_PM_PERFORMANCE), peak_meter_performance },
#ifdef PM_DEBUG
{ "Refresh rate" , peak_meter_fps_menu },
#endif
{ str(LANG_PM_SCALE) , peak_meter_scale },
{ str(LANG_PM_MIN) , peak_meter_min },
{ str(LANG_PM_MAX) , peak_meter_max },
};
m=menu_init( items, sizeof items / sizeof(struct menu_items) );
@ -137,7 +309,7 @@ static bool peak_meter_menu(void)
menu_exit(m);
return result;
}
#endif
#endif /* HAVE_LCD_BITMAP */
static bool shuffle(void)
{

View file

@ -55,17 +55,10 @@
#endif
#define FORMAT_BUFFER_SIZE 300
struct format_flags
{
bool dynamic;
bool scroll;
bool player_progress;
bool peak_meter;
};
static char format_buffer[FORMAT_BUFFER_SIZE];
static char* format_lines[MAX_LINES];
static bool dynamic_lines[MAX_LINES];
static unsigned char line_type[MAX_LINES];
static int ff_rewind_count;
bool wps_time_countup = true;
static bool wps_loaded = false;
@ -218,9 +211,7 @@ static char* get_dir(char* buf, int buf_size, char* path, int level)
* buf - buffer to certain tags, such as track number, play time or
* directory name.
* buf_size - size of buffer.
* flags - flags in this struct will be set depending on the tag:
* dynamic - if the tag data changes over time (like play time);
* player_progress - set if the tag is %pb.
* flags - returns the type of the line. See constants i wps-display.h
*
* Returns the tag. NULL indicates the tag wasn't available.
*/
@ -228,7 +219,7 @@ static char* get_tag(struct mp3entry* id3,
char* tag,
char* buf,
int buf_size,
struct format_flags* flags)
unsigned char* flags)
{
if ((0 == tag[0]) || (0 == tag[1]))
{
@ -238,6 +229,7 @@ static char* get_tag(struct mp3entry* id3,
switch (tag[0])
{
case 'i': /* ID3 Information */
*flags |= WPS_REFRESH_STATIC;
switch (tag[1])
{
case 't': /* ID3 Title */
@ -263,6 +255,7 @@ static char* get_tag(struct mp3entry* id3,
break;
case 'f': /* File Information */
*flags |= WPS_REFRESH_STATIC;
switch(tag[1])
{
case 'v': /* VBR file? */
@ -310,40 +303,42 @@ static char* get_tag(struct mp3entry* id3,
switch(tag[1])
{
case 'b': /* progress bar */
flags->player_progress = true;
flags->dynamic = true;
*flags |= WPS_REFRESH_PLAYER_PROGRESS;
return "\x01";
case 'p': /* Playlist Position */
*flags |= WPS_REFRESH_STATIC;
snprintf(buf, buf_size, "%d", id3->index + 1);
return buf;
case 'n': /* Playlist Name (without path) */
*flags |= WPS_REFRESH_STATIC;
return playlist_name(buf, buf_size);
case 'e': /* Playlist Total Entries */
*flags |= WPS_REFRESH_STATIC;
snprintf(buf, buf_size, "%d", playlist_amount());
return buf;
case 'c': /* Current Time in Song */
flags->dynamic = true;
*flags |= WPS_REFRESH_DYNAMIC;
format_time(buf, buf_size, id3->elapsed + ff_rewind_count);
return buf;
case 'r': /* Remaining Time in Song */
flags->dynamic = true;
*flags |= WPS_REFRESH_DYNAMIC;
format_time(buf, buf_size,
id3->length - id3->elapsed - ff_rewind_count);
return buf;
case 't': /* Total Time */
*flags |= WPS_REFRESH_STATIC;
format_time(buf, buf_size, id3->length);
return buf;
#ifdef HAVE_LCD_BITMAP
case 'm': /* Peak Meter */
flags->peak_meter = true;
flags->dynamic = true;
*flags |= WPS_REFRESH_PEAK_METER;
return "\x01";
#endif
}
@ -351,6 +346,7 @@ static char* get_tag(struct mp3entry* id3,
case 'd': /* Directory path information */
{
*flags |= WPS_REFRESH_STATIC;
int level = tag[1] - '0';
/* d1 through d9 */
if ((0 < level) && (9 > level))
@ -437,16 +433,13 @@ static char* skip_conditional(char* fmt, bool to_else)
* buf_size - the size of buffer.
* id3 - the ID3 data to format with.
* fmt - format description.
* flags - flags in this struct will be set depending on the tag:
* dynamic - if the tag data changes over time (like play time);
* player_progress - set if the tag is %pb.
* scroll - if line scrolling is requested.
* flags - returns the type of the line. See constants i wps-display.h
*/
static void format_display(char* buf,
int buf_size,
struct mp3entry* id3,
char* fmt,
struct format_flags* flags)
unsigned char* flags)
{
char temp_buf[128];
char* buf_end = buf + buf_size - 1; /* Leave room for end null */
@ -483,7 +476,7 @@ static void format_display(char* buf,
break;
case 's':
flags->scroll = true;
*flags |= WPS_REFRESH_SCROLL;
++fmt;
break;
@ -526,10 +519,10 @@ static void format_display(char* buf,
*buf = 0;
}
bool wps_refresh(struct mp3entry* id3, int ffwd_offset, bool refresh_all)
bool wps_refresh(struct mp3entry* id3, int ffwd_offset, unsigned char refresh_mode)
{
char buf[MAX_PATH];
struct format_flags flags;
unsigned char flags;
int i;
#ifdef HAVE_LCD_BITMAP
/* to find out wether the peak meter is enabled we
@ -554,16 +547,15 @@ bool wps_refresh(struct mp3entry* id3, int ffwd_offset, bool refresh_all)
if ( !format_lines[i] )
break;
if (dynamic_lines[i] || refresh_all)
if ((line_type[i] & refresh_mode) ||
(refresh_mode == WPS_REFRESH_ALL))
{
flags.dynamic = false;
flags.scroll = false;
flags.player_progress = false;
flags.peak_meter = false;
flags = 0;
format_display(buf, sizeof(buf), id3, format_lines[i], &flags);
dynamic_lines[i] = flags.dynamic;
line_type[i] = flags;
if (flags.player_progress) {
/* progress */
if (flags & refresh_mode & WPS_REFRESH_PLAYER_PROGRESS) {
#ifdef HAVE_LCD_CHARCELLS
draw_player_progress(id3, ff_rewind_count);
#else
@ -578,11 +570,12 @@ bool wps_refresh(struct mp3entry* id3, int ffwd_offset, bool refresh_all)
}
#ifdef HAVE_LCD_BITMAP
if (flags.peak_meter) {
/* peak meter */
if (flags & refresh_mode & WPS_REFRESH_PEAK_METER) {
int peak_meter_y;
int w,h;
struct font *fnt = font_get(FONT_UI);
int h = fnt->height;
int offset = global_settings.statusbar ? STATUSBAR_HEIGHT : 0;
lcd_getstringsize("M",&w,&h);
peak_meter_y = i * h + offset;
@ -601,10 +594,13 @@ bool wps_refresh(struct mp3entry* id3, int ffwd_offset, bool refresh_all)
}
#endif
if (flags.scroll && !flags.dynamic)
/* static line */
if (flags & WPS_REFRESH_SCROLL)
{
if (refresh_mode & WPS_REFRESH_SCROLL) {
lcd_puts_scroll(0, i, buf);
}
}
else
{
lcd_puts(0, i, buf);
@ -656,7 +652,7 @@ bool wps_display(struct mp3entry* id3)
}
}
}
wps_refresh(id3, 0, true);
wps_refresh(id3, 0, WPS_REFRESH_ALL);
status_draw();
lcd_update();
return false;

View file

@ -22,7 +22,18 @@
#include <stdbool.h>
#include "id3.h"
bool wps_refresh(struct mp3entry* id3, int ffwd_offset, bool refresh_scroll);
/* constants used in line_type and as refresh_mode for wps_refresh */
#define WPS_REFRESH_STATIC 1 /* line doesn't change over time */
#define WPS_REFRESH_DYNAMIC 2 /* line may change (e.g. time flag) */
#define WPS_REFRESH_SCROLL 4 /* line scrolls */
#define WPS_REFRESH_PLAYER_PROGRESS 8 /* line contains a progress bar */
#define WPS_REFRESH_PEAK_METER 16 /* line contains a peak meter */
#define WPS_REFRESH_ALL 0xff /* to refresh all line types */
/* to refresh only those lines that change over time */
#define WPS_REFRESH_NON_STATIC (WPS_REFRESH_ALL & ~WPS_REFRESH_STATIC & ~WPS_REFRESH_SCROLL)
bool wps_refresh(struct mp3entry* id3, int ffwd_offset, unsigned char refresh_mode);
bool wps_display(struct mp3entry* id3);
bool wps_load(char* file, bool display);
void wps_reset(void);

View file

@ -68,7 +68,7 @@ void player_change_volume(int button)
if(global_settings.volume > mpeg_sound_max(SOUND_VOLUME))
global_settings.volume = mpeg_sound_max(SOUND_VOLUME);
mpeg_sound_set(SOUND_VOLUME, global_settings.volume);
wps_refresh(id3,0,false);
wps_refresh(id3, 0, WPS_REFRESH_NON_STATIC);
settings_save();
break;
@ -78,7 +78,7 @@ void player_change_volume(int button)
if(global_settings.volume < mpeg_sound_min(SOUND_VOLUME))
global_settings.volume = mpeg_sound_min(SOUND_VOLUME);
mpeg_sound_set(SOUND_VOLUME, global_settings.volume);
wps_refresh(id3,0,false);
wps_refresh(id3, 0, WPS_REFRESH_NON_STATIC);
settings_save();
break;
@ -100,7 +100,7 @@ void player_change_volume(int button)
button = button_get(true);
}
status_draw();
wps_refresh(id3,0,true);
wps_refresh(id3,0, WPS_REFRESH_ALL);
}
#endif
@ -366,9 +366,9 @@ static bool ffwd_rew(int button)
}
if(wps_time_countup == false)
wps_refresh(id3, -ff_rewind_count, false);
wps_refresh(id3, -ff_rewind_count, WPS_REFRESH_PLAYER_PROGRESS);
else
wps_refresh(id3, ff_rewind_count, false);
wps_refresh(id3, ff_rewind_count, WPS_REFRESH_PLAYER_PROGRESS);
break;
@ -399,7 +399,7 @@ static bool ffwd_rew(int button)
if (!exit)
button = button_get(true);
}
wps_refresh(id3,0,true);
wps_refresh(id3, 0, WPS_REFRESH_ALL);
return usb;
}
@ -415,11 +415,11 @@ static bool update(void)
if (wps_display(id3))
retcode = true;
else
wps_refresh(id3,0,true);
wps_refresh(id3, 0, WPS_REFRESH_ALL);
}
if (id3)
wps_refresh(id3,0,false);
wps_refresh(id3, 0, WPS_REFRESH_NON_STATIC);
status_draw();
@ -453,7 +453,7 @@ static bool keylock(void)
#endif
display_keylock_text(true);
keys_locked = true;
wps_refresh(id3,0,true);
wps_refresh(id3, 0, WPS_REFRESH_ALL);
if (wps_display(id3)) {
keys_locked = false;
#ifdef HAVE_LCD_CHARCELLS
@ -511,7 +511,7 @@ static bool keylock(void)
default:
display_keylock_text(true);
while (button_get(false)); /* clear button queue */
wps_refresh(id3,0,true);
wps_refresh(id3, 0, WPS_REFRESH_ALL);
if (wps_display(id3)) {
keys_locked = false;
#ifdef HAVE_LCD_CHARCELLS
@ -628,7 +628,7 @@ static bool menu(void)
#endif
wps_display(id3);
wps_refresh(id3,0,true);
wps_refresh(id3, 0, WPS_REFRESH_ALL);
return false;
}
@ -659,7 +659,7 @@ int wps_show(void)
if (id3) {
if (wps_display(id3))
return 0;
wps_refresh(id3,0,true);
wps_refresh(id3, 0, WPS_REFRESH_ALL);
}
restore = true;
}
@ -674,14 +674,44 @@ int wps_show(void)
isn't displayed */
if (peak_meter_enabled) {
int i;
/* In high performance mode we read out the mas as
often as we can. There is no sleep for cpu */
if (global_settings.peak_meter_performance) {
long next_refresh = current_tick;
long next_big_refresh = current_tick + HZ / 5;
button = BUTTON_NONE;
while (!TIME_AFTER(current_tick, next_big_refresh)) {
button = button_get(false);
if (button != BUTTON_NONE) {
break;
}
peak_meter_peek();
yield();
if (TIME_AFTER(current_tick, next_refresh)) {
wps_refresh(id3, 0, WPS_REFRESH_PEAK_METER);
next_refresh = current_tick + HZ / peak_meter_fps;
}
}
}
/* In energy saver mode the cpu may sleep a
little bit while waiting for buttons */
else {
for (i = 0; i < 4; i++) {
button = button_get_w_tmo(HZ / 20);
button = button_get_w_tmo(HZ / peak_meter_fps);
if (button != 0) {
break;
}
wps_refresh(id3, 0, false);
wps_refresh(id3, 0, WPS_REFRESH_PEAK_METER);
}
}
} else {
}
/* The peak meter is disabled
-> no additional screen updates needed */
else {
button = button_get_w_tmo(HZ/5);
}
#else
@ -880,7 +910,7 @@ int wps_show(void)
if (wps_display(id3))
return 0;
if (id3)
wps_refresh(id3,0,false);
wps_refresh(id3, 0, WPS_REFRESH_NON_STATIC);
}
if(button != BUTTON_NONE)
lastbutton = button;