Index: apps/recorder/recording.c =================================================================== --- apps/recorder/recording.c (revision 24629) +++ apps/recorder/recording.c (working copy) @@ -30,6 +30,7 @@ #include "powermgmt.h" #include "lcd.h" #include "led.h" +#include "mpeg.h" #include "audio.h" #if CONFIG_CODEC == SWCODEC #include "thread.h" @@ -270,6 +271,59 @@ static short agc_maxgain; #endif /* HAVE_AGC */ +/* Histogram data */ +/* TO DO: move some of this stuff inside the recording function? */ +#ifdef HAVE_RECORDING_HISTOGRAM +#define HIST_Y (hist_pos_y+hist_size_h-1) +#define HIST_W (LCD_WIDTH / 2 - 4) +static short hist_time_interval = 1; /* 1, 2, 4, 8 */ +static int hist_l = 0; +static int hist_r = 0; +static unsigned char history_l[HIST_W]; +static unsigned char history_r[HIST_W]; +const short hist_balance_marks[12] = + /* -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6 */ + {-4988, -4377, -3690, -2920, -2057, -1087, + 1087, 2057, 2920, 3690, 4377, 4988}; +const short hist_peak_lin2dB[31] = +#if 0 + /* Clip, 0, -2, -4, -6, -8, -10 */ + { 32767, 28539, 23197, 18427, 14637, 11627, 9236, + /* -12, -14, -16, -18, -20, -24, -30, -36, -48, -inf */ + 7336, 5828, 4629, 3677, 2602, 1642, 734, 328, 104, 0 }; +#endif + /* Clip, 0, -1, -2, -3, -4, -5, -6, -7, -8 */ + { 32767, 30579, 27569, 24573, 21901, 19519, 17397, 15505, 13819, 12316, + /* -9, -10, -11, -12, -13, -14, -15, -16, -18, -20, -22 */ + 10977, 9783, 8719, 7771, 6926, 6173, 5502, 4629, 3677, 2921, 2320, + /* -24, -27, -30, -33, -36, -39, -42, -48, -60, -inf */ + 1842, 1232, 872, 618, 437, 310, 207, 124, 33, 0 }; +const char hist_level_marks[6] = + /* logarithmic: 0, -3, -6, -12, -24, -48 [dB] */ + { 29, 26, 23, 17, 9, 2}; +#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) { #ifdef HAVE_MIC_REC @@ -317,6 +371,13 @@ *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; } @@ -1025,9 +1086,14 @@ 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_RECORDING_HISTOGRAM) + unsigned short hist_pos_y = 0; + unsigned short hist_size_h = 0; + int history_pos = 0; +#endif #ifdef HAVE_FMRADIO_REC int prev_rec_source = global_settings.rec_source; /* detect source change */ #endif @@ -1084,49 +1150,6 @@ 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,8 +1166,67 @@ 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; if(global_settings.peak_meter_clipcounter) { @@ -1673,12 +1755,11 @@ 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 +1877,103 @@ } } +/*--------------------------------------------------------------------------------------*/ +#ifdef HAVE_RECORDING_HISTOGRAM + /* Draw histogram graphs (on main unit only). + * 4 modes: low size linear or logarithmic histogram with + * disk space usage, battery level and balance meter or + * high size linear or logarithmic peak histogram. + */ +#define HIST_BAL_X (LCD_WIDTH/2 + 4) +#define HIST_BAL_W (LCD_WIDTH/2 - 5) +#define BAL_MAX_R 4988 +#define BAL_MAX_L (-BAL_MAX_R * (HIST_BAL_W/2 + 1) / (HIST_BAL_W/2)) + 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]); + } + } +#if 0 + lcd_set_foreground(LCD_WHITE); + for (i = 0; i < HIST_W; i++) + { + if (history_l[i] == hist_size_h) + lcd_drawpixel(1 + i, HIST_Y - 1); + if (history_r[i] == hist_size_h) + lcd_drawpixel(HIST_W + 7 + i, HIST_Y - 1); + } +#endif +#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 +2100,6 @@ FOR_NB_SCREENS(i) screens[i].setfont(FONT_UI); - /* if the directory was created or recording happened, make sure the browser is updated */ Index: apps/recorder/peakmeter.c =================================================================== --- apps/recorder/peakmeter.c (revision 24629) +++ apps/recorder/peakmeter.c (working copy) @@ -66,7 +66,7 @@ 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 @@ { /* 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 @@ 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 @@ { /* 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 @@ 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. Index: apps/lang/english.lang =================================================================== --- apps/lang/english.lang (revision 24629) +++ apps/lang/english.lang (working copy) @@ -13315,3 +13315,38 @@ lcd_bitmap: "Remote Base Skin" + + id: LANG_RECORDING_HISTOGRAM_MODE + desc: in record settings menu + user: core + + *: none + recording_histogram: "Histogram mode" + + + *: none + recording_histogram: "Histogram mode" + + + *: none + recording_histogram: "Histogram mode" + + + + id: LANG_RECORDING_HISTOGRAM_INTERVAL + desc: in record settings menu + user: core + + *: none + recording_histogram: "Histogram interval" + + + *: none + recording_histogram: "Histogram interval" + + + *: none + recording_histogram: "Histogram interval" + + + Index: apps/settings.h =================================================================== --- apps/settings.h (revision 24629) +++ apps/settings.h (working copy) @@ -469,6 +469,10 @@ 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_mode; /* recording peakmeter histogram + balance */ + int rec_histogram_interval; /* recording peakmeter histogram + balance */ +#endif #ifdef HAVE_AGC int rec_agc_preset_mic; /* AGC mic preset modes: Index: apps/menus/recording_menu.c =================================================================== --- apps/menus/recording_menu.c (revision 24629) +++ apps/menus/recording_menu.c (working copy) @@ -393,6 +393,26 @@ 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) }, + { "5s", 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,7 +667,8 @@ #ifdef HAVE_AGC &agc_preset, &agc_cliptime, #endif -#ifdef HAVE_LCD_BITMAP +#if defined(HAVE_RECORDING_HISTOGRAM) + &recording_histogram, &peak_meter_menu, #endif &browse_recconfigs, &save_recpresets_item Index: apps/settings_list.c =================================================================== --- apps/settings_list.c (revision 24629) +++ apps/settings_list.c (working copy) @@ -1135,6 +1135,13 @@ 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,5s", + UNIT_SEC, NULL, NULL, NULL, 4, 0,1,2,5), +#endif /* HAVE_RECORDING_HISTOGRAM */ + #endif /* HAVE_RECORDING */ #ifdef HAVE_SPDIF_POWER Index: apps/features.txt =================================================================== --- apps/features.txt (revision 24629) +++ apps/features.txt (working copy) @@ -148,6 +148,10 @@ #endif #endif +#if defined(HAVE_RECORDING_HISTOGRAM) +recording_histogram +#endif + #if defined(HAVE_REMOTE_LCD) remote remote_lcd_invert Index: firmware/export/config/iriverh120.h =================================================================== --- firmware/export/config/iriverh120.h (revision 24629) +++ firmware/export/config/iriverh120.h (working copy) @@ -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 | \ Index: firmware/export/config/iriverh300.h =================================================================== --- firmware/export/config/iriverh300.h (revision 24629) +++ firmware/export/config/iriverh300.h (working copy) @@ -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)