Histogram display on recording screen. Based on the work of Jvo Studer in FS #5021 but reduced and reworked since the recording screen code changed quite a bit since his patch. For now enabled on iriver h1x0 and h3x0 only.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25007 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Peter D'Hoye 2010-03-03 22:16:08 +00:00
parent 5c80a838e4
commit be90f74e89
9 changed files with 286 additions and 66 deletions

View File

@ -148,6 +148,10 @@ recording_mic
#endif
#endif
#if defined(HAVE_RECORDING_HISTOGRAM)
recording_histogram
#endif
#if defined(HAVE_REMOTE_LCD)
remote
remote_lcd_invert

View File

@ -13349,3 +13349,38 @@
remote: "Remote Screen"
</voice>
</phrase>
<phrase>
id: LANG_RECORDING_HISTOGRAM_MODE
desc: in record settings menu
user: core
<source>
*: none
recording_histogram: "Histogram mode"
</source>
<dest>
*: none
recording_histogram: "Histogram mode"
</dest>
<voice>
*: none
recording_histogram: "Histogram mode"
</voice>
</phrase>
<phrase>
id: LANG_RECORDING_HISTOGRAM_INTERVAL
desc: in record settings menu
user: core
<source>
*: none
recording_histogram: "Histogram interval"
</source>
<dest>
*: none
recording_histogram: "Histogram interval"
</dest>
<voice>
*: none
recording_histogram: "Histogram interval"
</voice>
</phrase>

View File

@ -350,7 +350,7 @@ static int clear_rec_directory(void)
}
MENUITEM_FUNCTION(clear_rec_directory_item, 0, ID2P(LANG_CLEAR_REC_DIR),
clear_rec_directory, NULL, NULL, Icon_Folder);
MENUITEM_SETTING(cliplight, &global_settings.cliplight, NULL);
#ifdef HAVE_AGC
@ -393,6 +393,26 @@ MENUITEM_FUNCTION(agc_cliptime, 0, ID2P(LANG_RECORDING_AGC_CLIPTIME),
agc_cliptime_func, NULL, NULL, Icon_Menu_setting);
#endif /* HAVE_AGC */
#if defined(HAVE_RECORDING_HISTOGRAM)
static bool history_interval(void)
{
static const struct opt_items names[] = {
{ "0s", TALK_ID(0, UNIT_SEC) },
{ "1s", TALK_ID(1, UNIT_SEC) },
{ "2s", TALK_ID(2, UNIT_SEC) },
{ "4s", TALK_ID(5, UNIT_SEC) }
};
return set_option(str(LANG_RECORDING_HISTOGRAM_INTERVAL),
&global_settings.rec_histogram_interval,
INT, names, 4, NULL );
}
MENUITEM_FUNCTION(recording_histogram, 0,
ID2P(LANG_RECORDING_HISTOGRAM_INTERVAL),
history_interval, NULL, NULL, Icon_Menu_setting);
#endif
/** Rec trigger **/
enum trigger_menu_option
{
@ -647,6 +667,9 @@ MAKE_MENU(recording_settings_menu, ID2P(LANG_RECORDING_SETTINGS),
#ifdef HAVE_AGC
&agc_preset, &agc_cliptime,
#endif
#if defined(HAVE_RECORDING_HISTOGRAM)
&recording_histogram,
#endif
#ifdef HAVE_LCD_BITMAP
&peak_meter_menu,
#endif

View File

@ -66,7 +66,7 @@ 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;
#ifdef HAVE_AGC
#if defined(HAVE_AGC) || defined(HAVE_RECORDING_HISTOGRAM)
static int pm_peakhold_left; /* max. peak values between peakhold calls */
static int pm_peakhold_right; /* used for AGC and histogram display */
#endif
@ -799,9 +799,16 @@ static int peak_meter_read_l(void)
{
/* 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;
int retval;
#ifdef HAVE_AGC
#if defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC)
srand(current_tick);
pm_max_left = rand()%MAX_PEAK;
#endif
retval = pm_max_left;
#if defined(HAVE_RECORDING_HISTOGRAM) || defined(HAVE_AGC)
/* store max peak value for peak_meter_get_peakhold_x readout */
pm_peakhold_left = MAX(pm_max_left, pm_peakhold_left);
#endif
@ -812,11 +819,6 @@ static int peak_meter_read_l(void)
get fooled by an old maximum value */
pm_max_left = pm_cur_left;
#if defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC)
srand(current_tick);
retval = rand()%MAX_PEAK;
#endif
return retval;
}
@ -830,9 +832,16 @@ 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;
int retval;
#ifdef HAVE_AGC
#if defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC)
srand(current_tick);
pm_max_right = rand()%MAX_PEAK;
#endif
retval = pm_max_right;
#if defined(HAVE_RECORDING_HISTOGRAM) || defined(HAVE_AGC)
/* store max peak value for peak_meter_get_peakhold_x readout */
pm_peakhold_right = MAX(pm_max_right, pm_peakhold_right);
#endif
@ -843,15 +852,10 @@ static int peak_meter_read_r(void)
get fooled by an old maximum value */
pm_max_right = pm_cur_right;
#if defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC)
srand(current_tick);
retval = rand()%MAX_PEAK;
#endif
return retval;
}
#ifdef HAVE_AGC
#if defined(HAVE_AGC) || defined(HAVE_RECORDING_HISTOGRAM)
/**
* Reads out the current peak-hold values since the last call.
* This is used by the histogram feature in the recording screen.

View File

@ -219,7 +219,6 @@ static char path_buffer[MAX_PATH];
* overflow every 13 years 8-)
*/
static long peak_time = 0;
static long hist_time = 0;
static short peak_valid_mem[4];
#define BAL_MEM_SIZE 24
@ -269,6 +268,38 @@ static short agc_baltime = 0;
/* AGC maximum gain */
static short agc_maxgain;
#endif /* HAVE_AGC */
#if defined(HAVE_AGC) || defined(HAVE_RECORDING_HISTOGRAM)
static long hist_time = 0;
#endif /* HAVE_AGC or HAVE_RECORDING_HISTOGRAM */
/* Histogram data */
/* TO DO: move some of this stuff inside the recording function? */
#ifdef HAVE_RECORDING_HISTOGRAM
static int hist_l = 0;
static int hist_r = 0;
#define HIST_Y (hist_pos_y+hist_size_h-1)
#define HIST_W (LCD_WIDTH / 2 - 4)
#if LCD_DEPTH > 1
#ifdef HAVE_LCD_COLOR
#define LCD_BAL_L LCD_RGBPACK(0, 0, 255)
#define LCD_BAL_R LCD_RGBPACK(204, 0, 0)
#define LCD_HIST_OVER LCD_RGBPACK(204, 0, 0)
#define LCD_HIST_HI LCD_RGBPACK(255, 204, 0)
#define LCD_HIST_OK LCD_RGBPACK(51, 153, 0)
#else /* HAVE_LCD_COLOR */
#define LCD_BATT_OK LCD_BLACK
#define LCD_BATT_LO LCD_DARKGRAY
#define LCD_DISK_OK LCD_BLACK
#define LCD_DISK_LO LCD_DARKGRAY
#define LCD_HIST_OVER LCD_BLACK
#define LCD_HIST_OK LCD_DARKGRAY
#define LCD_BAL LCD_DARKGRAY
#endif /* HAVE_LCD_COLOR */
#else /* LCD_DEPTH > 1 */
#define LCD_HIST_OVER LCD_DEFAULT_FG
#define LCD_HIST_OK LCD_DEFAULT_FG
#define LCD_BAL LCD_DEFAULT_FG
#endif /* LCD_DEPTH > 1 */
#endif /* HAVE_RECORDING_HISTOGRAM */
static void set_gain(void)
{
@ -317,6 +348,13 @@ static bool read_peak_levels(int *peak_l, int *peak_r, int *balance)
*balance += balance_mem[i];
*balance = *balance / BAL_MEM_SIZE;
#ifdef HAVE_RECORDING_HISTOGRAM
if (*peak_l > hist_l)
hist_l = *peak_l;
if (*peak_r > hist_r)
hist_r = *peak_r;
#endif
return true;
}
@ -1015,7 +1053,6 @@ bool recording_screen(bool no_source)
#endif
#ifdef HAVE_AGC
bool peak_read = false;
bool peak_valid = false;
int peak_l, peak_r;
int balance = 0;
#endif
@ -1025,9 +1062,21 @@ bool recording_screen(bool no_source)
int pm_h[NB_SCREENS]; /* peakmeter height */
int trig_ypos[NB_SCREENS]; /* trigger bar y pos */
int trig_width[NB_SCREENS]; /* trigger bar width */
int top_height_req[NB_SCREENS]; /* required height for top half */
bool compact_view[NB_SCREENS]; /* tweak layout tiny screens / big fonts */
struct gui_synclist lists; /* the list in the bottom vp */
#if defined(HAVE_AGC) || defined(HAVE_RECORDING_HISTOGRAM)
bool peak_valid = false;
#endif
#if defined(HAVE_RECORDING_HISTOGRAM)
unsigned short hist_pos_y = 0;
unsigned short hist_size_h = 0;
int history_pos = 0;
short hist_time_interval = 1; /* 1, 2, 4, 8 */
unsigned char history_l[HIST_W];
unsigned char history_r[HIST_W];
const char hist_level_marks[6] = { 29, 26, 23, 17, 9, 2};
#endif
#ifdef HAVE_FMRADIO_REC
int prev_rec_source = global_settings.rec_source; /* detect source change */
#endif
@ -1084,49 +1133,6 @@ bool recording_screen(bool no_source)
rec_init_filename();
#endif
/* viewport init and calculations that only needs to be done once */
FOR_NB_SCREENS(i)
{
struct viewport *v;
/* top vp, 4 lines, force sys font if total screen < 6 lines
NOTE: one could limit the list to 1 line and get away with 5 lines */
v = &vp_top[i];
viewport_set_defaults(v, i);
if (viewport_get_nb_lines(v) < 4)
{
/* compact needs 4 lines total */
v->font = FONT_SYSFIXED;
compact_view[i] = false;
}
else
{
if (viewport_get_nb_lines(v) < (4+2)) /*top=4,list=2*/
compact_view[i] = true;
else
compact_view[i] = false;
}
vp_list[i] = *v; /* get a copy now so it can be sized more easily */
v->height = (font_get(v->font)->height)*(compact_view[i] ? 3 : 4);
/* list section, rest of the screen */
vp_list[i].y += vp_top[i].height;
vp_list[i].height -= vp_top[i].height;
screens[i].set_viewport(&vp_top[i]); /* req for next calls */
screens[i].getstringsize("W", &w, &h);
pm_y[i] = font_get(vp_top[i].font)->height * 2;
trig_ypos[i] = font_get(vp_top[i].font)->height * 3;
if(compact_view[i])
trig_ypos[i] -= (font_get(vp_top[i].font)->height)/2;
}
/* init the bottom list */
gui_synclist_init(&lists, reclist_get_name, NULL, false, 1, vp_list);
gui_synclist_set_title(&lists, NULL, Icon_NOICON);
send_event(GUI_EVENT_ACTIONUPDATE, (void*)1); /* force a redraw */
/* start of the loop: we stay in this loop until user quits recscreen */
while(done <= 0)
{
@ -1143,6 +1149,65 @@ bool recording_screen(bool no_source)
prev_rec_source = global_settings.rec_source;
#endif
/* viewport init and calculations that only needs to be done once */
FOR_NB_SCREENS(i)
{
struct viewport *v;
/* top vp, 4 lines, force sys font if total screen < 6 lines
NOTE: one could limit the list to 1 line and get away with 5 lines */
top_height_req[i] = 4;
#if defined(HAVE_RECORDING_HISTOGRAM)
if((global_settings.rec_histogram_interval) && (!i))
top_height_req[i] += 1; /* use one line for histogram */
hist_time_interval = 1 << global_settings.rec_histogram_interval;
#endif
v = &vp_top[i];
viewport_set_defaults(v, i);
if (viewport_get_nb_lines(v) < top_height_req[i])
{
/* compact needs 4 lines total */
v->font = FONT_SYSFIXED;
compact_view[i] = false;
}
else
{
/*top=4,list=2*/
if (viewport_get_nb_lines(v) < (top_height_req[i]+2))
compact_view[i] = true;
else
compact_view[i] = false;
}
vp_list[i] = *v; /* get a copy now so it can be sized more easily */
v->height = (font_get(v->font)->height)*(compact_view[i] ? 3 :
top_height_req[i]);
/* list section, rest of the screen */
vp_list[i].y += vp_top[i].height;
vp_list[i].height -= vp_top[i].height;
screens[i].set_viewport(&vp_top[i]); /* req for next calls */
screens[i].getstringsize("W", &w, &h);
pm_y[i] = font_get(vp_top[i].font)->height * 2;
trig_ypos[i] = font_get(vp_top[i].font)->height * 3;
if(compact_view[i])
trig_ypos[i] -= (font_get(vp_top[i].font)->height)/2;
}
/* init the bottom list */
gui_synclist_init(&lists, reclist_get_name, NULL, false, 1, vp_list);
gui_synclist_set_title(&lists, NULL, Icon_NOICON);
send_event(GUI_EVENT_ACTIONUPDATE, (void*)1); /* force a redraw */
#if defined(HAVE_RECORDING_HISTOGRAM)
history_pos = 0;
hist_pos_y = (compact_view[0] ? 3 : 4) * (font_get(vp_top[0].font)->height)
+ 1;
hist_size_h = font_get(vp_top[0].font)->height - 2;
memset(history_l, 0, sizeof(unsigned char)*HIST_W);
memset(history_r, 0, sizeof(unsigned char)*HIST_W);
#endif
FOR_NB_SCREENS(i)
{
pm_x[i] = 0;
@ -1673,12 +1738,11 @@ bool recording_screen(bool no_source)
unsigned int dseconds, dhours, dminutes;
unsigned long num_recorded_bytes, dsize, dmb;
FOR_NB_SCREENS(i)
{
screens[i].set_viewport(&vp_top[i]);
screens[i].clear_viewport();
}
}
update_countdown = 5;
last_seconds = seconds;
@ -1796,6 +1860,83 @@ bool recording_screen(bool no_source)
}
}
#ifdef HAVE_RECORDING_HISTOGRAM
if(global_settings.rec_histogram_interval)
{
if (peak_valid && !(hist_time % hist_time_interval) && hist_l)
{
history_l[history_pos] = hist_l * hist_size_h / 32767;
history_r[history_pos] = hist_r * hist_size_h / 32767;
history_pos = (history_pos + 1) % HIST_W;
history_l[history_pos] = history_r[history_pos] = 0;
history_l[(history_pos + 1) % HIST_W] = 0;
history_r[(history_pos + 1) % HIST_W] = 0;
hist_l = 0;
hist_r = 0;
}
lcd_set_drawmode(DRMODE_SOLID);
lcd_drawrect(0, hist_pos_y - 1,
HIST_W + 2, hist_size_h + 1);
lcd_drawrect(HIST_W + 6, hist_pos_y - 1,
HIST_W + 2, hist_size_h + 1);
lcd_set_drawmode(DRMODE_FG);
#ifdef HAVE_LCD_COLOR
for (i = 0; i < HIST_W; i++)
{
if (history_l[i])
{
if (history_l[i] == hist_size_h)
lcd_set_foreground(LCD_HIST_OVER);
else if (history_l[i] > hist_level_marks[1])
lcd_set_foreground(LCD_HIST_HI);
else
lcd_set_foreground(LCD_HIST_OK);
lcd_vline(1 + i, HIST_Y-1, HIST_Y - history_l[i]);
}
if (history_r[i])
{
if (history_r[i] == hist_size_h)
lcd_set_foreground(LCD_HIST_OVER);
else if (history_r[i] > hist_level_marks[1])
lcd_set_foreground(LCD_HIST_HI);
else
lcd_set_foreground(LCD_HIST_OK);
lcd_vline(HIST_W+7 + i, HIST_Y-1, HIST_Y - history_r[i]);
}
}
#else
for (i = 0; i < HIST_W; i++)
{
if (history_l[i])
{
if (history_l[i] == hist_size_h)
lcd_set_foreground(LCD_HIST_OVER);
else
lcd_set_foreground(LCD_HIST_OK);
lcd_vline(1 + i, HIST_Y-1, HIST_Y - history_l[i]);
}
if (history_r[i])
{
if (history_r[i] == hist_size_h)
lcd_set_foreground(LCD_HIST_OVER);
else
lcd_set_foreground(LCD_HIST_OK);
lcd_vline(HIST_W+7 + i, HIST_Y-1, HIST_Y - history_r[i]);
}
}
#endif /* HAVE_LCD_COLOR */
lcd_set_foreground(
#ifdef HAVE_LCD_COLOR
global_settings.fg_color);
#else
LCD_DEFAULT_FG);
#endif
for (i = 0; i < 6; i++)
lcd_hline(HIST_W + 3, HIST_W + 4,
HIST_Y - hist_level_marks[i]);
}
#endif /* HAVE_RECORDING_HISTOGRAM */
#ifdef HAVE_AGC
hist_time++;
#endif
@ -1922,7 +2063,6 @@ rec_abort:
FOR_NB_SCREENS(i)
screens[i].setfont(FONT_UI);
/* if the directory was created or recording happened, make sure the
browser is updated */

View File

@ -469,6 +469,9 @@ struct user_settings
int rec_stop_gap; /* index of trig_durations */
int rec_trigger_mode; /* see TRIG_MODE_XXX constants */
int rec_trigger_type; /* what to do when trigger released */
#ifdef HAVE_RECORDING_HISTOGRAM
int rec_histogram_interval; /* recording peakmeter histogram */
#endif
#ifdef HAVE_AGC
int rec_agc_preset_mic; /* AGC mic preset modes:

View File

@ -1135,6 +1135,13 @@ const struct settings_list settings[] = {
CHOICE_SETTING(F_RECSETTING, rec_trigger_type, LANG_RECORD_TRIGGER_TYPE, TRIG_TYPE_STOP,
"trigger type","stop,pause,nf stp", NULL ,3,
ID2P(LANG_RECORD_TRIGGER_STOP), ID2P(LANG_PAUSE), ID2P(LANG_RECORD_TRIGGER_NEWFILESTP)),
#ifdef HAVE_RECORDING_HISTOGRAM
/* TO DO: additional restictions of following REP items? */
TABLE_SETTING(F_RECSETTING, rec_histogram_interval, LANG_RECORDING_HISTOGRAM_INTERVAL, 0,
"histogram interval","0s,1s,2s,4s",
UNIT_SEC, NULL, NULL, NULL, 4, 0,1,2,4),
#endif /* HAVE_RECORDING_HISTOGRAM */
#endif /* HAVE_RECORDING */
#ifdef HAVE_SPDIF_POWER

View File

@ -111,6 +111,8 @@
/* define this if you have recording possibility */
#define HAVE_RECORDING
#define HAVE_RECORDING_HISTOGRAM
/* Define bitmask of input sources - recordable bitmask can be defined
explicitly if different */
#define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_LINEIN | \

View File

@ -107,6 +107,8 @@
/* define this if you have recording possibility */
#define HAVE_RECORDING
#define HAVE_RECORDING_HISTOGRAM
/* Define bitmask of input sources - recordable bitmask can be defined
explicitly if different */
#define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_LINEIN | SRC_CAP_FMRADIO)