Major peakmeter rework: * Changed set/get functions for dbfs mode to bool type. * Removed performance setting, leaving (slightly adapted) high performance mode only. * Refresh rate is always 20 Hz now. * Readout doesn't do an extra (hidden) peek, should allow for slightly better clip detection. * Brought back high performance peakmeter for recording. Peakmeter stops hogging the CPU when the disk is spinning; this is enough to avoid the performance problem when saving data. * Optimisations, code cleanup and code policeing. * (iriver) Reduced CPU load of peakmeter by not calculating excessive overlaps. ** Bumped config block version, so save your settings before upgrading.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7415 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Jens Arnold 2005-08-29 20:07:17 +00:00
parent 89a8ca4408
commit 99a0598c28
12 changed files with 304 additions and 372 deletions

View File

@ -79,12 +79,12 @@
#endif
/* increase this every time the api struct changes */
#define CODEC_API_VERSION 41
#define CODEC_API_VERSION 42
/* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any
backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */
#define CODEC_MIN_API_VERSION 40
#define CODEC_MIN_API_VERSION 42
/* codec return codes */
enum codec_status {
@ -314,8 +314,8 @@ struct codec_api {
#if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
unsigned short (*peak_meter_scale_value)(unsigned short val,
int meterwidth);
void (*peak_meter_set_use_dbfs)(int use);
int (*peak_meter_get_use_dbfs)(void);
void (*peak_meter_set_use_dbfs)(bool use);
bool (*peak_meter_get_use_dbfs)(void);
#endif
/* new stuff at the end, sort into place next time

View File

@ -878,21 +878,21 @@ voice: "Numeric"
new:
id: LANG_PM_PERFORMANCE
desc: in the peak meter menu
eng: "Performance"
voice: "Performance"
desc: DEPRECATED
eng: ""
voice:
new:
id: LANG_PM_HIGH_PERFORMANCE
desc: in the peak meter menu
eng: "High performance"
voice: "High performance"
desc: DEPRECATED
eng: ""
voice: ""
new:
id: LANG_PM_ENERGY_SAVER
desc: in the peak meter menu
eng: "Save Energy"
voice: "Save Energy"
desc: DEPRECATED
eng: ""
voice: ""
new:
id: LANG_PM_SCALE

View File

@ -88,12 +88,12 @@
#endif
/* increase this every time the api struct changes */
#define PLUGIN_API_VERSION 47
#define PLUGIN_API_VERSION 48
/* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */
#define PLUGIN_MIN_API_VERSION 47
#define PLUGIN_MIN_API_VERSION 48
/* plugin return codes */
enum plugin_status {
@ -413,8 +413,8 @@ struct plugin_api {
#if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
unsigned short (*peak_meter_scale_value)(unsigned short val,
int meterwidth);
void (*peak_meter_set_use_dbfs)(int use);
int (*peak_meter_get_use_dbfs)(void);
void (*peak_meter_set_use_dbfs)(bool use);
bool (*peak_meter_get_use_dbfs)(void);
#endif
#ifdef HAVE_LCD_BITMAP
int (*read_bmp_file)(char* filename, int *get_width, int *get_height,

View File

@ -271,7 +271,7 @@ static void update_icons(void)
#if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
/* The scale icon */
rb->lcd_mono_bitmap(SCALE_BMP[rb->peak_meter_get_use_dbfs()],
rb->lcd_mono_bitmap(SCALE_BMP[rb->peak_meter_get_use_dbfs() ? 1 : 0],
2 *LCD_WIDTH/3 + LCD_WIDTH/3 / 2 - BMPWIDTH/2, LCD_HEIGHT - BMPHEIGHT,
BMPWIDTH, BMPHEIGHT);
#else
@ -1134,7 +1134,7 @@ unsigned long splitedit_editor(struct mp3entry * mp3_to_split,
case SPLITEDIT_SCALE:
#if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
rb->peak_meter_set_use_dbfs(rb->peak_meter_get_use_dbfs() +1);
rb->peak_meter_set_use_dbfs(!rb->peak_meter_get_use_dbfs());
#endif
splitedit_invalidate_osci();
update_icons();

View File

@ -21,6 +21,7 @@
#include "thread.h"
#include "kernel.h"
#include "settings.h"
#include "ata.h"
#include "lcd.h"
#include "widgets.h"
#include "wps-display.h"
@ -36,41 +37,48 @@
#include "pcm_playback.h"
#endif
/* no inline in simulator mode */
#ifdef SIMULATOR
#define inline
#if !defined(SIMULATOR) && CONFIG_HWCODEC != MASNONE
/* Data source */
static int pm_src_left = MAS_REG_DQPEAK_L;
static int pm_src_right = MAS_REG_DQPEAK_R;
#endif
/* buffer the read peak value */
static int peak_meter_max_l;
static int peak_meter_max_r;
/* Current values and cumulation */
static int pm_cur_left; /* current values (last peak_meter_peek) */
static int pm_cur_right;
static int pm_max_left; /* maximum values between peak meter draws */
static int pm_max_right;
/* point in time when peak_meter_max_x becomes invalid */
static long peak_meter_timeout_l;
static long peak_meter_timeout_r;
/* Peak hold */
static int pm_peak_left; /* buffered peak values */
static int pm_peak_right;
static long pm_peak_timeout_l; /* peak hold timeouts */
static long pm_peak_timeout_r;
/* when true a clip has occurred */
static bool peak_meter_l_clip = false;
static bool peak_meter_r_clip = false;
/* Clip hold */
static bool pm_clip_left = false; /* when true a clip has occurred */
static bool pm_clip_right = false;
static long pm_clip_timeout_l; /* clip hold timeouts */
static long pm_clip_timeout_r;
/* point in time when peak_meter_x_oveflow becomes invalid */
static long peak_meter_clip_timeout_l;
static long peak_meter_clip_timeout_r;
/* 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;
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;
static unsigned short peak_meter_range;
/* if set to true clip timeout is disabled */
static bool peak_meter_clip_eternal = false;
static bool peak_meter_use_dbfs = true;
static unsigned short db_min = 0;
static unsigned short db_max = 9000;
static unsigned short db_range = 9000;
/** Parameters **/
/* Range */
unsigned short peak_meter_range_min; /* minimum of range in samples */
unsigned short peak_meter_range_max; /* maximum of range in samples */
static unsigned short pm_range; /* range width in samples */
static bool pm_use_dbfs = true; /* true if peakmeter displays dBfs */
static unsigned short pm_db_min = 0; /* minimum of range in 1/100 dB */
static unsigned short pm_db_max = 9000; /* maximum of range in 1/100 dB */
static unsigned short pm_db_range = 9000; /* range width in 1/100 dB */
/* Timing behaviour */
static int pm_peak_hold = 1; /* peak hold timeout index */
static int pm_peak_release = 8; /* peak release in units per read */
static int pm_clip_hold = 16; /* clip hold timeout index */
static bool pm_clip_eternal = false; /* true if clip timeout is disabled */
#ifdef HAVE_RECORDING
static unsigned short trig_strt_threshold;
@ -92,34 +100,6 @@ static int trig_status = TRIG_OFF;
static void (*trigger_listener)(int) = NULL;
#endif
#if CONFIG_HWCODEC == MASNONE
#define MAS_REG_DQPEAK_L 0
#define MAS_REG_DQPEAK_R 0
#endif
#if !defined(SIMULATOR) && CONFIG_HWCODEC != MASNONE
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;
@ -132,7 +112,7 @@ static unsigned int ticks_per_redraw[TICKS_PER_DRAW_SIZE];
#endif
/* time out values for max */
static const long max_time_out[] = {
static const short peak_time_out[] = {
0 * HZ, HZ / 5, 30, HZ / 2, HZ, 2 * HZ,
3 * HZ, 4 * HZ, 5 * HZ, 6 * HZ, 7 * HZ, 8 * HZ,
9 * HZ, 10 * HZ, 15 * HZ, 20 * HZ, 30 * HZ, 60 * HZ
@ -150,22 +130,6 @@ static const long clip_time_out[] = {
/* precalculated peak values that represent magical
dBfs values. Used to draw the scale */
#define DB_SCALE_SRC_VALUES_SIZE 12
#if 0
static const int db_scale_src_values[DB_SCALE_SRC_VALUES_SIZE] = {
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 */
1, /* -inf */
};
#else
static const int db_scale_src_values[DB_SCALE_SRC_VALUES_SIZE] = {
32752, /* 0 db */
22784, /* - 3 db */
@ -180,11 +144,10 @@ static const int db_scale_src_values[DB_SCALE_SRC_VALUES_SIZE] = {
33, /* -60 db */
0, /* -inf */
};
#endif
static int db_scale_count = DB_SCALE_SRC_VALUES_SIZE;
/* if db_scale_valid is false the content of
/* if db_scale_valid is false the content of
db_scale_lcd_coord needs recalculation */
static bool db_scale_valid = false;
@ -211,7 +174,8 @@ static int db_scale_lcd_coord[sizeof db_scale_src_values / sizeof (int)];
* for-loops.
*/
int calc_db (int isample) {
int calc_db (int isample)
{
/* return n+m*(isample-istart)/100 */
int n;
long m;
@ -312,7 +276,8 @@ int calc_db (int isample) {
* 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){
static int db_to_sample_bin_search(int min, int max, int db)
{
int test = min + (max - min) / 2;
if (min < max) {
@ -339,7 +304,8 @@ static int db_to_sample_bin_search(int min, int max, int db){
* @return int - The return value is in the range of
* 0 <= return value < MAX_PEAK
*/
int peak_meter_db2sample(int db) {
int peak_meter_db2sample(int db)
{
int retval = 0;
/* what is the maximum pseudo db value */
@ -371,13 +337,14 @@ int peak_meter_db2sample(int db) {
/**
* Set the min value for restriction of the value range.
* @param int newmin - depending wether dBfs is used
* @param int newmin - depending whether 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) {
void peak_meter_set_min(int newmin)
{
if (pm_use_dbfs) {
peak_meter_range_min = peak_meter_db2sample(newmin);
} else {
@ -386,10 +353,10 @@ void peak_meter_set_min(int newmin) {
}
}
peak_meter_range = peak_meter_range_max - peak_meter_range_min;
pm_range = peak_meter_range_max - peak_meter_range_min;
db_min = calc_db(peak_meter_range_min);
db_range = db_max - db_min;
pm_db_min = calc_db(peak_meter_range_min);
pm_db_range = pm_db_max - pm_db_min;
db_scale_valid = false;
}
@ -400,9 +367,10 @@ void peak_meter_set_min(int newmin) {
* @return: using dBfs : -9000 < value <= 0
* using linear scale: 0 <= value <= 100
*/
int peak_meter_get_min(void) {
int peak_meter_get_min(void)
{
int retval = 0;
if (peak_meter_use_dbfs) {
if (pm_use_dbfs) {
retval = calc_db(peak_meter_range_min) - calc_db(MAX_PEAK - 1);
} else {
retval = peak_meter_range_min * 100 / MAX_PEAK;
@ -417,8 +385,9 @@ int peak_meter_get_min(void) {
* for dBfs: -9000 < newmax <= 0
* for linear: 0 <= newmax <= 100
*/
void peak_meter_set_max(int newmax) {
if (peak_meter_use_dbfs) {
void peak_meter_set_max(int newmax)
{
if (pm_use_dbfs) {
peak_meter_range_max = peak_meter_db2sample(newmax);
} else {
if (newmax > peak_meter_range_min) {
@ -426,10 +395,10 @@ void peak_meter_set_max(int newmax) {
}
}
peak_meter_range = peak_meter_range_max - peak_meter_range_min;
pm_range = peak_meter_range_max - peak_meter_range_min;
db_max = calc_db(peak_meter_range_max);
db_range = db_max - db_min;
pm_db_max = calc_db(peak_meter_range_max);
pm_db_range = pm_db_max - pm_db_min;
db_scale_valid = false;
}
@ -440,9 +409,10 @@ void peak_meter_set_max(int newmax) {
* @return: using dBfs : -9000 < value <= 0
* using linear scale: 0 <= value <= 100
*/
int peak_meter_get_max(void) {
int peak_meter_get_max(void)
{
int retval = 0;
if (peak_meter_use_dbfs) {
if (pm_use_dbfs) {
retval = calc_db(peak_meter_range_max) - calc_db(MAX_PEAK - 1);
} else {
retval = peak_meter_range_max * 100 / MAX_PEAK;
@ -451,23 +421,24 @@ int peak_meter_get_max(void) {
}
/**
* Returns 1 if the meter currently is
* displaying dBfs values, 0 if the meter
* displays percent values.
* @return int - returns 0 or 1.
* Returns whether the meter is currently displaying dBfs or percent values.
* @return bool - true if the meter is displaying dBfs
false if the meter is displaying percent values.
*/
int peak_meter_get_use_dbfs(void) {
return peak_meter_use_dbfs ? 1 : 0;
bool peak_meter_get_use_dbfs(void)
{
return pm_use_dbfs;
}
/**
* Specifies wether the values displayed are scaled
* Specifies whether 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.
* @param use - set to true for dBfs,
* set to false for linear scaling in percent
*/
void peak_meter_set_use_dbfs(int use){
peak_meter_use_dbfs = ((use & 1) == 1);
void peak_meter_set_use_dbfs(bool use)
{
pm_use_dbfs = use;
db_scale_valid = false;
}
@ -486,7 +457,7 @@ void peak_meter_set_use_dbfs(int use){
*/
void peak_meter_init_range( bool dbfs, int range_min, int range_max)
{
peak_meter_use_dbfs = dbfs;
pm_use_dbfs = dbfs;
peak_meter_set_min(range_min);
peak_meter_set_max(range_max);
}
@ -497,15 +468,16 @@ void peak_meter_init_range( bool dbfs, int range_min, int range_max)
* 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.
* stored in peak_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;
void peak_meter_init_times(int release, int hold, int clip_hold)
{
pm_peak_hold = hold;
pm_peak_release = release;
pm_clip_hold = clip_hold;
}
/**
@ -523,17 +495,18 @@ void peak_meter_playback(bool playback)
(void)playback;
#else
if (playback) {
peak_meter_src_l = MAS_REG_DQPEAK_L;
peak_meter_src_r = MAS_REG_DQPEAK_R;
pm_src_left = MAS_REG_DQPEAK_L;
pm_src_right = MAS_REG_DQPEAK_R;
} else {
peak_meter_src_l = MAS_REG_QPEAK_L;
peak_meter_src_r = MAS_REG_QPEAK_R;
pm_src_left = MAS_REG_QPEAK_L;
pm_src_right = MAS_REG_QPEAK_R;
}
#endif
}
#ifdef HAVE_RECORDING
static void set_trig_status(int new_state) {
static void set_trig_status(int new_state)
{
if (trig_status != new_state) {
trig_status = new_state;
if (trigger_listener != NULL) {
@ -545,24 +518,25 @@ static void set_trig_status(int new_state) {
/**
* Reads peak values from the MAS, and detects clips. The
* values are stored in peak_meter_l peak_meter_r for later
* values are stored in pm_max_left pm_max_right for later
* evauluation. Consecutive calls to peak_meter_peek detect
* that ocurred. This function could be used by a thread for
* busy reading the MAS.
*/
inline void peak_meter_peek(void)
void peak_meter_peek(void)
{
int left, right;
/* read current values */
#ifdef SIMULATOR
int left = 8000;
int right = 9000;
pm_cur_left = left = 8000;
pm_cur_right = right = 9000;
#elif CONFIG_HWCODEC == MASNONE
int left;
int right;
pcm_calculate_peaks(&left, &right);
pcm_calculate_peaks(&pm_cur_left, &pm_cur_right);
left = pm_cur_left;
right = pm_cur_right;
#else
/* read the peak values */
int left = mas_codec_readreg(peak_meter_src_l);
int right = mas_codec_readreg(peak_meter_src_r);
pm_cur_left = left = mas_codec_readreg(pm_src_left);
pm_cur_right = right = mas_codec_readreg(pm_src_right);
#endif
/* check for clips
@ -571,26 +545,34 @@ inline void peak_meter_peek(void)
to be inaccurate in both ways: it may detect clips
when no clip occurred and it may fail to detect
a real clip. */
if ((left == peak_meter_l) &&
(left == MAX_PEAK - 1)) {
peak_meter_l_clip = true;
peak_meter_clip_timeout_l =
current_tick + clip_time_out[peak_meter_clip_hold];
if ((left == pm_max_left) &&
(left == MAX_PEAK - 1)) {
pm_clip_left = true;
pm_clip_timeout_l =
current_tick + clip_time_out[pm_clip_hold];
}
if ((right == peak_meter_r) &&
if ((right == pm_max_right) &&
(right == MAX_PEAK - 1)) {
peak_meter_r_clip = true;
peak_meter_clip_timeout_r =
current_tick + clip_time_out[peak_meter_clip_hold];
pm_clip_right = true;
pm_clip_timeout_r =
current_tick + clip_time_out[pm_clip_hold];
}
/* peaks are searched -> we have to find the maximum. When
many calls of peak_meter_peek the maximum value will be
stored in pm_max_xxx. This maximum is reset by the
functions peak_meter_read_x. */
pm_max_left = MAX(pm_max_left, left);
pm_max_right = MAX(pm_max_right, right);
#ifdef HAVE_RECORDING
switch (trig_status) {
case TRIG_READY:
/* no more changes, if trigger was activated as release trigger */
/* threshold exceeded? */
if ((left > trig_strt_threshold) || (right > trig_strt_threshold)) {
if ((left > trig_strt_threshold)
|| (right > trig_strt_threshold)) {
if (trig_strt_duration) {
/* reset trigger duration */
trig_hightime = current_tick;
@ -614,8 +596,8 @@ inline void peak_meter_peek(void)
set_trig_status(TRIG_GO);
} else {
/* threshold exceeded? */
if ((left > trig_strt_threshold) ||
(right > trig_strt_threshold)) {
if ((left > trig_strt_threshold)
|| (right > trig_strt_threshold)) {
/* reset lowtime */
trig_lowtime = current_tick;
}
@ -640,7 +622,8 @@ inline void peak_meter_peek(void)
case TRIG_GO:
case TRIG_CONTINUE:
/* threshold exceeded? */
if ((left > trig_stp_threshold) || (right > trig_stp_threshold)) {
if ((left > trig_stp_threshold)
|| (right > trig_stp_threshold)) {
/* restart hold time countdown */
trig_lowtime = current_tick;
} else {
@ -653,8 +636,8 @@ inline void peak_meter_peek(void)
/* gap time expired? */
if (current_tick - trig_lowtime > trig_rstrt_gap){
/* start threshold exceeded? */
if ((left > trig_strt_threshold) ||
(right > trig_strt_threshold)) {
if ((left > trig_strt_threshold)
|| (right > trig_strt_threshold)) {
set_trig_status(TRIG_RETRIG);
trig_hightime = current_tick;
@ -662,8 +645,8 @@ inline void peak_meter_peek(void)
else
/* stop threshold exceeded */
if ((left > trig_stp_threshold) ||
(right > trig_stp_threshold)) {
if ((left > trig_stp_threshold)
|| (right > trig_stp_threshold)) {
if (current_tick - trig_hightime > trig_stp_hold){
trig_lowtime = current_tick;
set_trig_status(TRIG_CONTINUE);
@ -685,8 +668,8 @@ inline void peak_meter_peek(void)
/* still within the gap time */
else {
/* stop threshold exceeded */
if ((left > trig_stp_threshold) ||
(right > trig_stp_threshold)) {
if ((left > trig_stp_threshold)
|| (right > trig_stp_threshold)) {
set_trig_status(TRIG_CONTINUE);
trig_lowtime = current_tick;
}
@ -702,13 +685,6 @@ inline void peak_meter_peek(void)
}
#endif
/* 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
@ -720,26 +696,18 @@ inline void peak_meter_peek(void)
* since the last call of peak_meter_read_l. The value
* is in the range 0 <= value < MAX_PEAK.
*/
static int peak_meter_read_l (void)
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;
/* pm_max_left contains the maximum of all peak values that were read
by peak_meter_peek since the last call of peak_meter_read_l */
int retval = pm_max_left;
#ifdef PM_DEBUG
peek_calls = 0;
#endif
#ifdef SIMULATOR
peak_meter_l = 8000;
#elif CONFIG_HWCODEC == MASNONE
pcm_calculate_peaks(&peak_meter_l, NULL);
#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
/* reset pm_max_left so that subsequent calls of peak_meter_peek don't
get fooled by an old maximum value */
pm_max_left = pm_cur_left;
return retval;
}
@ -749,25 +717,18 @@ static int peak_meter_read_l (void)
* since the last call of peak_meter_read_l. The value
* 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;
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 = pm_max_right;
#ifdef PM_DEBUG
peek_calls = 0;
#endif
#ifdef SIMULATOR
peak_meter_l = 8000;
#elif CONFIG_HWCODEC == MASNONE
pcm_calculate_peaks(NULL, &peak_meter_r);
#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
/* reset pm_max_right so that subsequent calls of peak_meter_peek don't
get fooled by an old maximum value */
pm_max_right = pm_cur_right;
return retval;
}
@ -777,13 +738,14 @@ static int peak_meter_read_r (void) {
* @param int unused - This parameter was added to
* make the function compatible with set_int
*/
void peak_meter_set_clip_hold(int time) {
peak_meter_clip_eternal = false;
void peak_meter_set_clip_hold(int time)
{
pm_clip_eternal = false;
if (time <= 0) {
peak_meter_l_clip = false;
peak_meter_r_clip = false;
peak_meter_clip_eternal = true;
pm_clip_left = false;
pm_clip_right = false;
pm_clip_eternal = true;
}
}
@ -795,7 +757,8 @@ void peak_meter_set_clip_hold(int time) {
* @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){
unsigned short peak_meter_scale_value(unsigned short val, int meterwidth)
{
int retval;
if (val <= peak_meter_range_min) {
@ -809,10 +772,10 @@ unsigned short peak_meter_scale_value(unsigned short val, int meterwidth){
retval = val;
/* different scaling is used for dBfs and linear percent */
if (peak_meter_use_dbfs) {
if (pm_use_dbfs) {
/* scale the samples dBfs */
retval = (calc_db(retval) - db_min) * meterwidth / db_range;
retval = (calc_db(retval) - pm_db_min) * meterwidth / pm_db_range;
}
/* Scale for linear percent display */
@ -820,7 +783,7 @@ unsigned short peak_meter_scale_value(unsigned short val, int meterwidth){
{
/* scale the samples */
retval = ((retval - peak_meter_range_min) * meterwidth)
/ peak_meter_range;
/ pm_range;
}
return retval;
}
@ -854,8 +817,7 @@ void peak_meter_draw(int x, int y, int width, int height)
/* read the volume info from MAS */
left = peak_meter_read_l();
right = peak_meter_read_r();
/*peak_meter_peek();*/
right = peak_meter_read_r();
/* scale the samples dBfs */
left = peak_meter_scale_value(left, meterwidth);
@ -865,7 +827,7 @@ void peak_meter_draw(int x, int y, int width, int height)
(The scale becomes invalid when the range changed.) */
if (!db_scale_valid){
if (peak_meter_use_dbfs) {
if (pm_use_dbfs) {
db_scale_count = DB_SCALE_SRC_VALUES_SIZE;
for (i = 0; i < db_scale_count; i++){
/* find the real x-coords for predefined interesting
@ -884,7 +846,7 @@ void peak_meter_draw(int x, int y, int width, int height)
for (i = 0; i < db_scale_count; i++) {
db_scale_lcd_coord[i] =
(i * (MAX_PEAK / 10) - peak_meter_range_min) *
meterwidth / peak_meter_range;
meterwidth / pm_range;
}
}
@ -894,41 +856,41 @@ void peak_meter_draw(int x, int y, int width, int height)
}
/* apply release */
left = MAX(left , last_left - peak_meter_release);
right = MAX(right, last_right - peak_meter_release);
left = MAX(left , last_left - pm_peak_release);
right = MAX(right, last_right - pm_peak_release);
/* reset max values after timeout */
if (TIME_AFTER(current_tick, peak_meter_timeout_l)){
peak_meter_max_l = 0;
if (TIME_AFTER(current_tick, pm_peak_timeout_l)){
pm_peak_left = 0;
}
if (TIME_AFTER(current_tick, peak_meter_timeout_r)){
peak_meter_max_r = 0;
if (TIME_AFTER(current_tick, pm_peak_timeout_r)){
pm_peak_right = 0;
}
if (!peak_meter_clip_eternal) {
if (peak_meter_l_clip &&
TIME_AFTER(current_tick, peak_meter_clip_timeout_l)){
peak_meter_l_clip = false;
if (!pm_clip_eternal) {
if (pm_clip_left &&
TIME_AFTER(current_tick, pm_clip_timeout_l)){
pm_clip_left = false;
}
if (peak_meter_r_clip &&
TIME_AFTER(current_tick, peak_meter_clip_timeout_r)){
peak_meter_r_clip = false;
if (pm_clip_right &&
TIME_AFTER(current_tick, pm_clip_timeout_r)){
pm_clip_right = false;
}
}
/* check for new max values */
if (left > peak_meter_max_l) {
peak_meter_max_l = left - 1;
peak_meter_timeout_l =
current_tick + max_time_out[peak_meter_hold];
if (left > pm_peak_left) {
pm_peak_left = left - 1;
pm_peak_timeout_l =
current_tick + peak_time_out[pm_peak_hold];
}
if (right > peak_meter_max_r) {
peak_meter_max_r = right - 1;
peak_meter_timeout_r =
current_tick + max_time_out[peak_meter_hold];
if (right > pm_peak_right) {
pm_peak_right = right - 1;
pm_peak_timeout_r =
current_tick + peak_time_out[pm_peak_hold];
}
}
@ -939,19 +901,19 @@ void peak_meter_draw(int x, int y, int width, int height)
/* draw left */
lcd_fillrect (x, y, left, height / 2 - 2 );
if (peak_meter_max_l > 0) {
lcd_vline(x + peak_meter_max_l, y, y + height / 2 - 2 );
if (pm_peak_left > 0) {
lcd_vline(x + pm_peak_left, y, y + height / 2 - 2 );
}
if (peak_meter_l_clip) {
if (pm_clip_left) {
lcd_fillrect(x + meterwidth, y, 3, height / 2 - 1);
}
/* draw right */
lcd_fillrect(x, y + height / 2 + 1, right, height / 2 - 2);
if (peak_meter_max_r > 0) {
lcd_vline( x + peak_meter_max_r, y + height / 2, y + height - 2);
if (pm_peak_right > 0) {
lcd_vline( x + pm_peak_right, y + height / 2, y + height - 2);
}
if (peak_meter_r_clip) {
if (pm_clip_right) {
lcd_fillrect(x + meterwidth, y + height / 2, 3, height / 2 - 1);
}
@ -1071,7 +1033,8 @@ void peak_meter_define_trigger(
* Enables or disables the trigger.
* @param on - If true the trigger is turned on.
*/
void peak_meter_trigger(bool on) {
void peak_meter_trigger(bool on)
{
/* don't use set_trigger here as that would fire an undesired event */
trig_status = on ? TRIG_READY : TRIG_OFF;
}
@ -1081,7 +1044,8 @@ void peak_meter_trigger(bool on) {
* @param listener - The function that is called with each change of
* trig_status. May be set to NULL if no callback is desired.
*/
void peak_meter_set_trigger_listener(void (*listener)(int status)) {
void peak_meter_set_trigger_listener(void (*listener)(int status))
{
trigger_listener = listener;
}
@ -1097,78 +1061,99 @@ void peak_meter_set_trigger_listener(void (*listener)(int status)) {
* peak_meter_release_trigger. To turn the trigger off call
* peak_meter_trigger_off.
*/
int peak_meter_trigger_status(void) {
int peak_meter_trigger_status(void)
{
return trig_status; /* & TRIG_PIT_MASK;*/
}
void peak_meter_draw_trig(int xpos, int ypos) {
int x = xpos + ICON_PLAY_STATE_WIDTH + 1;
void peak_meter_draw_trig(int xpos, int ypos)
{
int barstart, barend;
int icon, ixpos;
switch (trig_status) {
long time_left;
case TRIG_READY:
scrollbar(x, ypos + 1, TRIGBAR_WIDTH, TRIG_HEIGHT - 2,
TRIGBAR_WIDTH, 0, 0, HORIZONTAL);
lcd_mono_bitmap(bitmap_icons_7x8[Icon_Stop], xpos, ypos,
ICON_PLAY_STATE_WIDTH, STATUSBAR_HEIGHT);
barstart = 0;
barend = 0;
icon = Icon_Stop;
ixpos = xpos;
break;
case TRIG_STEADY:
case TRIG_RETRIG:
time_left = trig_strt_duration - (current_tick - trig_hightime);
time_left = time_left * TRIGBAR_WIDTH / trig_strt_duration;
scrollbar(x, ypos + 1, TRIGBAR_WIDTH, TRIG_HEIGHT - 2,
TRIGBAR_WIDTH, 0, TRIGBAR_WIDTH - time_left, HORIZONTAL);
lcd_mono_bitmap(bitmap_icons_7x8[Icon_Stop], xpos, ypos,
ICON_PLAY_STATE_WIDTH, STATUSBAR_HEIGHT);
case TRIG_RETRIG:
barstart = 0;
barend = TRIGBAR_WIDTH * (current_tick - trig_hightime)
/ trig_strt_duration;
icon = Icon_Stop;
ixpos = xpos;
break;
case TRIG_GO:
case TRIG_CONTINUE:
scrollbar(x, ypos + 1, TRIGBAR_WIDTH, TRIG_HEIGHT - 2,
TRIGBAR_WIDTH, TRIGBAR_WIDTH, TRIGBAR_WIDTH, HORIZONTAL);
lcd_mono_bitmap(bitmap_icons_7x8[Icon_Record],
TRIG_WIDTH - ICON_PLAY_STATE_WIDTH, ypos,
ICON_PLAY_STATE_WIDTH, STATUSBAR_HEIGHT);
barstart = TRIGBAR_WIDTH;
barend = TRIGBAR_WIDTH;
icon = Icon_Record;
ixpos = TRIG_WIDTH - ICON_PLAY_STATE_WIDTH;
break;
case TRIG_POSTREC:
time_left = trig_stp_hold - (current_tick - trig_lowtime);
time_left = time_left * TRIGBAR_WIDTH / trig_stp_hold;
scrollbar(x, ypos + 1, TRIGBAR_WIDTH, TRIG_HEIGHT - 2,
TRIGBAR_WIDTH, time_left, TRIGBAR_WIDTH, HORIZONTAL);
lcd_mono_bitmap(bitmap_icons_7x8[Icon_Record],
TRIG_WIDTH - ICON_PLAY_STATE_WIDTH, ypos,
ICON_PLAY_STATE_WIDTH, STATUSBAR_HEIGHT);
case TRIG_POSTREC:
barstart = TRIGBAR_WIDTH
- TRIGBAR_WIDTH * (current_tick - trig_lowtime)
/ trig_stp_hold;
barend = TRIGBAR_WIDTH;
icon = Icon_Record;
ixpos = TRIG_WIDTH - ICON_PLAY_STATE_WIDTH;
break;
default:
return;
}
scrollbar(xpos + ICON_PLAY_STATE_WIDTH + 1, ypos + 1,
TRIGBAR_WIDTH, TRIG_HEIGHT - 2,
TRIGBAR_WIDTH, barstart, barend, HORIZONTAL);
lcd_mono_bitmap(bitmap_icons_7x8[icon], ixpos, ypos,
ICON_PLAY_STATE_WIDTH, STATUSBAR_HEIGHT);
}
#endif
int peak_meter_draw_get_btn(int x, int y, int width, int height)
{
int button;
int button = BUTTON_NONE;
long next_refresh = current_tick;
long next_big_refresh = current_tick + HZ / 10;
button = BUTTON_NONE;
#ifndef SIMULATOR
bool highperf = !ata_disk_is_active();
#else
bool highperf = false;
#endif
bool dopeek = true;
while (!TIME_AFTER(current_tick, next_big_refresh)) {
while (TIME_BEFORE(current_tick, next_big_refresh)) {
button = button_get(false);
if (button != BUTTON_NONE) {
break;
}
sleep(MAX(next_refresh - current_tick, 0) - 1);
next_refresh = current_tick + HZ / peak_meter_fps;
peak_meter_peek();
peak_meter_draw(x, y, width, height);
lcd_update_rect(x, y, width, height);
if (dopeek) { /* Peek only once per refresh when disk is */
peak_meter_peek(); /* spinning, but as often as possible */
dopeek = highperf; /* otherwise. */
yield();
} else {
sleep(0); /* Sleep until end of current tick. */
}
if (TIME_AFTER(current_tick, next_refresh)) {
peak_meter_draw(x, y, width, height);
lcd_update_rect(x, y, width, height);
next_refresh += HZ / PEAK_METER_FPS;
dopeek = true;
}
}
return button;
}
#ifdef PM_DEBUG
static void peak_meter_clear_histogram(void) {
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;
@ -1179,7 +1164,8 @@ static void peak_meter_clear_histogram(void) {
}
}
bool peak_meter_histogram(void) {
bool peak_meter_histogram(void)
{
int i;
int btn = BUTTON_NONE;
while ((btn & BUTTON_OFF) != BUTTON_OFF )
@ -1210,7 +1196,7 @@ bool peak_meter_histogram(void) {
lcd_hline(0, x, y + i);
}
lcd_update();
btn = button_get(true);
if (btn == BUTTON_PLAY) {
peak_meter_clear_histogram();

View File

@ -19,13 +19,14 @@
#ifndef __PEAKMETER_H__
#define __PEAKMETER_H__
#define PEAK_METER_FPS 20
/*#define PM_DEBUG */
#ifdef PM_DEBUG
extern bool peak_meter_histogram(void);
#endif
extern bool peak_meter_enabled;
extern int peak_meter_fps;
extern void peak_meter_playback(bool playback);
extern void peak_meter_draw(int x, int y, int width, int height);
@ -39,8 +40,8 @@ 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 void peak_meter_set_use_dbfs(bool use);
extern bool peak_meter_get_use_dbfs(void);
extern int calc_db (int isample);
extern int peak_meter_db2sample(int db);
extern unsigned short peak_meter_scale_value(unsigned short val, int meterwidth);

View File

@ -304,7 +304,7 @@ bool radio_screen(void)
if(search_dir)
button = button_get(false);
else
button = button_get_w_tmo(HZ / peak_meter_fps);
button = button_get_w_tmo(HZ / PEAK_METER_FPS);
switch(button)
{
case FM_STOP:
@ -479,13 +479,10 @@ bool radio_screen(void)
/* Only display the peak meter when not recording */
if(!audio_status())
{
lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
lcd_fillrect(0, 8 + fh*(top_of_screen + 3), LCD_WIDTH, fh);
lcd_set_drawmode(DRMODE_SOLID);
peak_meter_draw(0, 8 + fh*(top_of_screen + 3), LCD_WIDTH, fh);
lcd_update_rect(0, 8 + fh*(top_of_screen + 3), LCD_WIDTH, fh);
}
if(TIME_AFTER(current_tick, timeout))
{
timeout = current_tick + HZ;

View File

@ -78,7 +78,7 @@ const char rec_base_directory[] = REC_BASE_DIR;
#include "pcm_playback.h"
#endif
#define CONFIG_BLOCK_VERSION 25
#define CONFIG_BLOCK_VERSION 26
#define CONFIG_BLOCK_SIZE 512
#define RTC_BLOCK_SIZE 44
@ -349,8 +349,7 @@ static const struct bit_entry hd_bits[] =
/* peak meter */
{5, S_O(peak_meter_clip_hold), 16, "peak meter clip hold", /* 0...25 */
"on,1,2,3,4,5,6,7,8,9,10,15,20,25,30,45,60,90,2min,3min,5min,10min,20min,45min,90min" },
{1, S_O(peak_meter_performance), false, "peak meter busy", off_on },
{5, S_O(peak_meter_hold), 3, "peak meter hold",
{5, S_O(peak_meter_hold), 3, "peak meter hold",
"off,200ms,300ms,500ms,1,2,3,4,5,6,7,8,9,10,15,20,30,1min" },
{7, S_O(peak_meter_release), 8, "peak meter release", NULL }, /* 0...126 */
{1, S_O(peak_meter_dbfs), true, "peak meter dbfs", off_on },

View File

@ -250,7 +250,6 @@ struct user_settings
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*/
int peak_meter_min; /* range minimum */
int peak_meter_max; /* range maximum */
bool car_adapter_mode; /* 0=off 1=on */

View File

@ -318,16 +318,6 @@ static bool volume_type(void)
INT, names, 2, NULL);
}
#ifdef PM_DEBUG
static bool peak_meter_fps_menu(void) {
bool retval = false;
retval = set_int( "Refresh rate", "/s", UNIT_PER_SEC,
&peak_meter_fps,
NULL, 1, 5, 40, NULL);
return retval;
}
#endif /* PM_DEBUG */
/**
* Menu to set the hold time of normal peaks.
*/
@ -544,25 +534,6 @@ static bool peak_meter_max(void) {
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),
NULL);
if (global_settings.peak_meter_performance) {
peak_meter_fps = 25;
} else {
peak_meter_fps = 20;
}
return retval;
}
/**
* Menu to configure the peak meter
*/
@ -575,10 +546,6 @@ static bool peak_meter_menu(void)
{ ID2P(LANG_PM_RELEASE) , peak_meter_release },
{ ID2P(LANG_PM_PEAK_HOLD), peak_meter_hold },
{ ID2P(LANG_PM_CLIP_HOLD), peak_meter_clip_hold },
{ ID2P(LANG_PM_PERFORMANCE), peak_meter_performance },
#ifdef PM_DEBUG
{ "Refresh rate" , -1 , peak_meter_fps_menu },
#endif
{ ID2P(LANG_PM_SCALE) , peak_meter_scale },
{ ID2P(LANG_PM_MIN) , peak_meter_min },
{ ID2P(LANG_PM_MAX) , peak_meter_max },

View File

@ -391,46 +391,29 @@ long wps_show(void)
#ifdef HAVE_LCD_BITMAP
/* when the peak meter is enabled we want to have a
few extra updates to make it look smooth. On the
other hand we don't want to waste energy if it
other hand we don't want to waste energy if it
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();
sleep(1);
if (TIME_AFTER(current_tick, next_refresh)) {
wps_refresh(id3, nid3, 0, WPS_REFRESH_PEAK_METER);
next_refresh = current_tick + HZ / peak_meter_fps;
}
long next_refresh = current_tick;
long next_big_refresh = current_tick + HZ / 5;
button = BUTTON_NONE;
while (TIME_BEFORE(current_tick, next_big_refresh)) {
button = button_get(false);
if (button != BUTTON_NONE) {
break;
}
}
/* 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 / peak_meter_fps);
if (button != 0) {
break;
}
peak_meter_peek();
sleep(0); /* Sleep until end of current tick. */
if (TIME_AFTER(current_tick, next_refresh)) {
wps_refresh(id3, nid3, 0, WPS_REFRESH_PEAK_METER);
next_refresh += HZ / PEAK_METER_FPS;
}
}
}
/* The peak meter is disabled
}
/* The peak meter is disabled
-> no additional screen updates needed */
else {
button = button_get_w_tmo(HZ/5);

View File

@ -99,15 +99,15 @@ static void dma_stop(void)
/*
* This function goes directly into the DMA buffer to calculate the left and
* right peak values. To avoid missing peaks it tries to look forward a full
* refresh period (1/20 sec) although it's always possible that the entire
* period will not be visible. To reduce CPU load it only looks at every
* third sample, and this can be reduced even further if needed (even every
* tenth sample would still be pretty accurate).
* right peak values. To avoid missing peaks it tries to look forward two full
* peek periods (2/HZ sec, 100% overlap), although it's always possible that
* the entire period will not be visible. To reduce CPU load it only looks at
* every third sample, and this can be reduced even further if needed (even
* every tenth sample would still be pretty accurate).
*/
#define PEAK_SAMPLES 2205 /* 44100 sample rate / 20 Hz refresh */
#define PEAK_STRIDE 3 /* every 3rd sample is plenty... */
#define PEAK_SAMPLES (44100*2/HZ) /* 44100 samples * 2 / 100 Hz tick */
#define PEAK_STRIDE 3 /* every 3rd sample is plenty... */
void pcm_calculate_peaks(int *left, int *right)
{