diff options
-rw-r--r-- | apps/debug_menu.c | 7 | ||||
-rw-r--r-- | apps/lang/english.lang | 40 | ||||
-rw-r--r-- | apps/recorder/peakmeter.c | 631 | ||||
-rw-r--r-- | apps/recorder/peakmeter.h | 22 | ||||
-rw-r--r-- | apps/settings.c | 86 | ||||
-rw-r--r-- | apps/settings.h | 5 | ||||
-rw-r--r-- | apps/settings_menu.c | 194 | ||||
-rw-r--r-- | apps/wps-display.c | 72 | ||||
-rw-r--r-- | apps/wps-display.h | 13 | ||||
-rw-r--r-- | apps/wps.c | 62 |
10 files changed, 1034 insertions, 98 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 97db40ee7d..4dd98e0498 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c @@ -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 */ - diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 3f1eb6efb8..373e072395 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -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" diff --git a/apps/recorder/peakmeter.c b/apps/recorder/peakmeter.c index df7c672617..e1850a4bb0 100644 --- a/apps/recorder/peakmeter.c +++ b/apps/recorder/peakmeter.c @@ -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,20 +502,58 @@ 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. @@ -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); + + 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); + } + } - /* scale the samples */ - left /= (MAX_PEAK / meterwidth); - right /= (MAX_PEAK / meterwidth); + /* 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 diff --git a/apps/recorder/peakmeter.h b/apps/recorder/peakmeter.h index a5f25808e6..356926f9de 100644 --- a/apps/recorder/peakmeter.h +++ b/apps/recorder/peakmeter.h @@ -19,12 +19,32 @@ #ifndef __PEAKMETER_H__ #define __PEAKMETER_H__ +/*#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__ */ diff --git a/apps/settings.c b/apps/settings.c index cee7a286f6..c17f42fd52 100644 --- a/apps/settings.c +++ b/apps/settings.c @@ -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; diff --git a/apps/settings.h b/apps/settings.h index bc8767d532..655b2e0245 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -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); diff --git a/apps/settings_menu.c b/apps/settings_menu.c index 6f527f5224..ed2f97e390 100644 --- a/apps/settings_menu.c +++ b/apps/settings_menu.c @@ -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) { diff --git a/apps/wps-display.c b/apps/wps-display.c index 6bca8cb40d..b70c1359d1 100644 --- a/apps/wps-display.c +++ b/apps/wps-display.c @@ -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; diff --git a/apps/wps-display.h b/apps/wps-display.h index fc40e19136..cda90ffffe 100644 --- a/apps/wps-display.h +++ b/apps/wps-display.h @@ -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); diff --git a/apps/wps.c b/apps/wps.c index 3e48333818..8f9295a293 100644 --- a/apps/wps.c +++ b/apps/wps.c @@ -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; |