diff -Naur _008/apps/action.h _009_rep/apps/action.h --- _008/apps/action.h 2008-07-22 17:19:26.599382400 +0900 +++ _009_rep/apps/action.h 2008-07-23 23:09:36.000000000 +0900 @@ -170,6 +170,7 @@ ACTION_REC_NEWFILE, ACTION_REC_F2, ACTION_REC_F3, + ACTION_REC_HIST_TOGGLE, /* main menu */ /* These are not strictly actions, but must be here diff -Naur _008/apps/gui/statusbar.c _009_rep/apps/gui/statusbar.c --- _008/apps/gui/statusbar.c 2008-07-24 05:21:19.254148800 +0900 +++ _009_rep/apps/gui/statusbar.c 2008-07-24 00:58:05.087750400 +0900 @@ -35,6 +35,7 @@ #include "action.h" /* for keys_locked */ #include "statusbar.h" #ifdef HAVE_RECORDING +#include "recording.h" #include "audio.h" #include "recording.h" #endif @@ -115,7 +116,11 @@ #define STATUSBAR_LOCKR_WIDTH 5 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) +#ifdef HAVE_MMC #define STATUSBAR_DISK_WIDTH 12 +#else +#define STATUSBAR_DISK_WIDTH 7 +#endif #define STATUSBAR_DISK_X_POS(statusbar_width) statusbar_width - \ STATUSBAR_DISK_WIDTH #else @@ -123,6 +128,15 @@ #endif #define STATUSBAR_TIME_X_END(statusbar_width) statusbar_width - 1 - \ STATUSBAR_DISK_WIDTH +#if defined(HAVE_RECORDING) +#define TIMER_ICON_WIDTH 7 +#if CONFIG_RTC +#define CLOCK_WIDTH 35 +#else +#define CLOCK_WIDTH 0 +#endif +#endif + struct gui_syncstatusbar statusbars; /* Prototypes */ @@ -142,9 +156,11 @@ #endif #ifdef HAVE_RECORDING static void gui_statusbar_icon_recording_info(struct screen * display); +static void gui_statusbar_timer(struct screen * display, int dy, int hr, int mn, int sc, bool recscreen); +static void gui_statusbar_timer_rep(struct screen * display); #endif #if CONFIG_RTC -static void gui_statusbar_time(struct screen * display, struct tm *time); +static void gui_statusbar_time(struct screen * display, struct tm *time, bool timer_display); #endif #endif @@ -247,6 +263,21 @@ #if CONFIG_RTC bar->time = get_time(); #endif /* CONFIG_RTC */ +#ifdef HAVE_RECORDING + struct timer* timer = get_timerstat(); + bar->info.timer_day = timer->days; + bar->info.timer_hour = timer->hrs; + bar->info.timer_min = timer->mins; + /* avoid an update every second unless less than one + minute remains on the timer */ + if (!bar->info.timer_day && !bar->info.timer_hour && !bar->info.timer_min) + bar->info.timer_sec = timer->secs; + else + bar->info.timer_sec = 0; + + bar->info.timer_display = timer->timer_display; + bar->info.timer_repeat = timer->repeater; +#endif /* only redraw if forced to, or info has changed */ if (force_redraw || bar->redraw_volume || @@ -265,9 +296,9 @@ #ifdef HAVE_USB_POWER if (bar->info.usb_inserted) display->mono_bitmap(bitmap_icons_7x8[Icon_USBPlug], - STATUSBAR_PLUG_X_POS, - STATUSBAR_Y_POS, STATUSBAR_PLUG_WIDTH, - STATUSBAR_HEIGHT); + STATUSBAR_PLUG_X_POS, + STATUSBAR_Y_POS, STATUSBAR_PLUG_WIDTH, + STATUSBAR_HEIGHT); #endif /* HAVE_USB_POWER */ #if CONFIG_CHARGING #ifdef HAVE_USB_POWER @@ -276,9 +307,9 @@ /* draw power plug if charging */ if (bar->info.inserted) display->mono_bitmap(bitmap_icons_7x8[Icon_Plug], - STATUSBAR_PLUG_X_POS, - STATUSBAR_Y_POS, STATUSBAR_PLUG_WIDTH, - STATUSBAR_HEIGHT); + STATUSBAR_PLUG_X_POS, + STATUSBAR_Y_POS, STATUSBAR_PLUG_WIDTH, + STATUSBAR_HEIGHT); #endif /* CONFIG_CHARGING */ #ifdef HAVE_RECORDING /* turn off volume display in recording screen */ @@ -321,8 +352,16 @@ if (bar->info.keylockremote) gui_statusbar_icon_lock_remote(display); #endif +#ifdef HAVE_RECORDING + if (bar->info.timer_display) + gui_statusbar_timer(display, bar->info.timer_day, bar->info.timer_hour, + bar->info.timer_min, bar->info.timer_sec, recscreen_on); + else if ((bar->info.timer_repeat) && (recscreen_on)) + gui_statusbar_timer_rep(display); +#endif #if CONFIG_RTC - gui_statusbar_time(display, bar->time); + gui_statusbar_time(display, bar->time, + bar->info.timer_display); bar->last_tm_min = bar->time->tm_min; #endif /* CONFIG_RTC */ #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) @@ -583,10 +622,11 @@ /* * Print time to status bar */ -static void gui_statusbar_time(struct screen * display, struct tm *time) + +static void gui_statusbar_time(struct screen * display, struct tm *time, bool timer_display) { unsigned char buffer[6]; - unsigned int width, height; + int width, height; int hour, minute; if ( valid_time(time) ) { hour = time->tm_hour; @@ -605,15 +645,73 @@ display->setfont(FONT_SYSFIXED); display->getstringsize(buffer, &width, &height); if (height <= STATUSBAR_HEIGHT) { +#ifdef HAVE_RECORDING + if (timer_display) + display->set_drawmode(DRMODE_INVERSEVID); +#else + (void)timer_display; +#endif display->putsxy(STATUSBAR_TIME_X_END(display->getwidth()) - width, STATUSBAR_Y_POS, buffer); } + display->set_drawmode(DRMODE_SOLID); display->setfont(FONT_UI); } #endif #ifdef HAVE_RECORDING +static void gui_statusbar_timer(struct screen * display, int dy, int hr, int mn, + int sc, bool recscreen) +{ + unsigned char buffer[8]; + int width, height; + + /* vary the display depending on the remaining time to save space */ + if (dy) + snprintf(buffer, sizeof(buffer), " %dd%02dh", hr > 58 ? dy + 1 : dy, + hr > 58 ? 0 : hr + 1); + else if (!hr && !mn) + snprintf(buffer, sizeof(buffer), "%02ds", sc); + else + snprintf(buffer, sizeof(buffer), "%02dh%02dm", mn > 58 ? hr + 1: hr, + mn > 58 ? 0 : mn + 1); + + display->setfont(FONT_SYSFIXED); + display->getstringsize(buffer, &width, &height); + + if (height <= STATUSBAR_HEIGHT) + { + if(((display->getwidth()) >= (STATUSBAR_LOCKR_X_POS + STATUSBAR_LOCKR_WIDTH + + STATUSBAR_DISK_WIDTH + width + CLOCK_WIDTH + 1)) + && !recscreen) + display->putsxy(STATUSBAR_TIME_X_END(display->getwidth()) - width - + CLOCK_WIDTH, STATUSBAR_Y_POS, buffer); + /* display only an icon for small screens or when in recording screen*/ + else if ((display->getwidth()) >= (STATUSBAR_LOCKR_X_POS + + STATUSBAR_LOCKR_WIDTH + + STATUSBAR_DISK_WIDTH + + TIMER_ICON_WIDTH + CLOCK_WIDTH + 1)) + display->mono_bitmap(bitmap_icons_7x7[Icon_Timer], + STATUSBAR_TIME_X_END(display->getwidth()) - + TIMER_ICON_WIDTH - CLOCK_WIDTH, + STATUSBAR_Y_POS, + TIMER_ICON_WIDTH, STATUSBAR_HEIGHT); + } + + display->setfont(FONT_UI); + +} + +static void gui_statusbar_timer_rep(struct screen * display) +{ + display->mono_bitmap(bitmap_icons_7x7[Icon_Timer_rep], + STATUSBAR_TIME_X_END(display->getwidth()) - + TIMER_ICON_WIDTH - CLOCK_WIDTH, + STATUSBAR_Y_POS, + TIMER_ICON_WIDTH, STATUSBAR_HEIGHT); +} + #if CONFIG_CODEC == SWCODEC /** * Write a number to the display using bitmaps and return new position diff -Naur _008/apps/gui/statusbar.h _009_rep/apps/gui/statusbar.h --- _008/apps/gui/statusbar.h 2008-07-24 05:18:30.000000000 +0900 +++ _009_rep/apps/gui/statusbar.h 2008-07-23 23:09:44.000000000 +0900 @@ -40,6 +40,15 @@ int volume; int playmode; int repeat; +#ifdef HAVE_RECORDING + int timer_day; + int timer_hour; + int timer_min; + int timer_sec; + int timer_repeat; +#endif + int timer_display; + #if CONFIG_CHARGING bool inserted; #endif diff -Naur _008/apps/keymaps/keymap-h1x0_h3x0.c _009_rep/apps/keymaps/keymap-h1x0_h3x0.c --- _008/apps/keymaps/keymap-h1x0_h3x0.c 2008-07-22 17:19:26.949886400 +0900 +++ _009_rep/apps/keymaps/keymap-h1x0_h3x0.c 2008-07-24 00:18:28.860904000 +0900 @@ -251,6 +251,7 @@ { ACTION_SETTINGS_DEC, BUTTON_LEFT, BUTTON_NONE }, { ACTION_SETTINGS_DECREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_STD_SHORTCUTS, BUTTON_ON|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_REC_HIST_TOGGLE, BUTTON_MODE|BUTTON_REPEAT, BUTTON_MODE }, LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) }; /* button_context_recscreen */ @@ -457,6 +458,10 @@ { ACTION_SETTINGS_INCREPEAT, BUTTON_RC_REW|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_SETTINGS_DEC, BUTTON_RC_FF, BUTTON_NONE }, { ACTION_SETTINGS_DECREPEAT, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_STD_PREV, BUTTON_RC_SOURCE, BUTTON_NONE }, + { ACTION_STD_PREVREPEAT, BUTTON_RC_SOURCE|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_STD_NEXT, BUTTON_RC_BITRATE, BUTTON_NONE }, + { ACTION_STD_NEXTREPEAT, BUTTON_RC_BITRATE|BUTTON_REPEAT, BUTTON_NONE }, /* { ACTION_NONE, BUTTON_RC_ON, BUTTON_NONE }, { ACTION_NONE, BUTTON_RC_STOP, BUTTON_NONE }, { ACTION_NONE, BUTTON_RC_MENU|BUTTON_REL, BUTTON_NONE }, @@ -469,8 +474,13 @@ { ACTION_SETTINGS_INCREPEAT, BUTTON_RC_VOL_UP|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_SETTINGS_DEC, BUTTON_RC_VOL_DOWN, BUTTON_NONE }, { ACTION_SETTINGS_DECREPEAT, BUTTON_RC_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE }, - { ACTION_NONE, BUTTON_RC_REW, BUTTON_NONE }, - { ACTION_NONE, BUTTON_RC_FF, BUTTON_NONE }, + // { ACTION_NONE, BUTTON_RC_REW, BUTTON_NONE }, + // { ACTION_NONE, BUTTON_RC_FF, BUTTON_NONE }, + { ACTION_STD_PREV, BUTTON_RC_REW, BUTTON_NONE }, + { ACTION_STD_PREVREPEAT, BUTTON_RC_REW|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_STD_NEXT, BUTTON_RC_FF, BUTTON_NONE }, + { ACTION_STD_NEXTREPEAT, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_SETTINGS_RESET, BUTTON_RC_ON, BUTTON_NONE }, LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) }; /* button_context_settings */ @@ -622,6 +632,7 @@ { ACTION_SETTINGS_DEC, BUTTON_RC_SOURCE, BUTTON_NONE }, { ACTION_SETTINGS_DECREPEAT, BUTTON_RC_SOURCE|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_STD_SHORTCUTS, BUTTON_RC_ON|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_REC_HIST_TOGGLE, BUTTON_RC_MODE|BUTTON_REPEAT, BUTTON_RC_MODE }, LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) }; /* button_context_recscreen_h100remote */ @@ -635,6 +646,7 @@ { ACTION_SETTINGS_DEC, BUTTON_RC_REW, BUTTON_NONE }, { ACTION_SETTINGS_DEC, BUTTON_RC_REW|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_STD_SHORTCUTS, BUTTON_RC_ON|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_REC_HIST_TOGGLE, BUTTON_RC_MODE|BUTTON_REPEAT, BUTTON_RC_MODE }, LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) }; /* button_context_recscreen_h300lcdremote */ diff -Naur _008/apps/keymaps/keymap-ondio.c _009_rep/apps/keymaps/keymap-ondio.c --- _008/apps/keymaps/keymap-ondio.c 2008-07-21 19:59:05.000000000 +0900 +++ _009_rep/apps/keymaps/keymap-ondio.c 2008-07-23 23:09:48.000000000 +0900 @@ -76,9 +76,10 @@ { ACTION_SETTINGS_INCREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_SETTINGS_DEC, BUTTON_DOWN, BUTTON_NONE }, { ACTION_SETTINGS_DECREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE }, - { ACTION_STD_OK, BUTTON_RIGHT, BUTTON_NONE }, - { ACTION_STD_OK, BUTTON_LEFT, BUTTON_NONE }, - { ACTION_STD_CANCEL, BUTTON_MENU, BUTTON_NONE }, + { ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE }, + { ACTION_NONE, BUTTON_RIGHT|BUTTON_REL, BUTTON_RIGHT }, + { ACTION_STD_PREV, BUTTON_LEFT, BUTTON_NONE }, + { ACTION_STD_OK, BUTTON_MENU, BUTTON_NONE }, LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) }; diff -Naur _008/apps/keymaps/keymap-x5.c _009_rep/apps/keymaps/keymap-x5.c --- _008/apps/keymaps/keymap-x5.c 2008-07-21 19:59:05.000000000 +0900 +++ _009_rep/apps/keymaps/keymap-x5.c 2008-07-23 23:09:48.000000000 +0900 @@ -219,6 +219,9 @@ { ACTION_SETTINGS_DEC, BUTTON_DOWN, BUTTON_NONE }, { ACTION_SETTINGS_DECREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_STD_PREV, BUTTON_LEFT, BUTTON_NONE }, + { ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE }, + { ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_STD_CANCEL, BUTTON_REC, BUTTON_NONE }, LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) diff -Naur _008/apps/lang/english.lang _009_rep/apps/lang/english.lang --- _008/apps/lang/english.lang 2008-07-22 17:19:27.009972800 +0900 +++ _009_rep/apps/lang/english.lang 2008-07-24 00:46:26.663465600 +0900 @@ -2613,6 +2613,62 @@ + id: LANG_RECORDING_HISTOGRAM_INTERVAL + desc: in record settings menu + user: + + *: "Histogram interval" + + + *: "Histogram interval" + + + *: "" + + + + id: LANG_WARNING_DISKSPACE_LOW + desc: in recording screen + user: + + *: "WARNING! Low Disk-Space!" + + + *: "WARNING! Low Disk-Space!" + + + *: "" + + + + id: LANG_WARNING_DISK_FULL + desc: in recording screen + user: + + *: "Disk is full!" + + + *: "Disk is full!" + + + *: "" + + + + id: LANG_WARNING_STOP_RECORDING + desc: in recording screen + user: + + *: "Stopping Recording..." + + + *: "Stopping Recording..." + + + *: "" + + + id: LANG_TAGCACHE_UPDATE desc: in tag cache settings user: @@ -9978,6 +10034,45 @@ + id: LANG_RECORD_HIST_OPTIONS + desc: histogram on/off + + *: "Histogram options" + + + *: "Histogram options" + + + *: "Histogram options" + + + + id: LANG_RECORD_PEAKMETER_SIZE + desc: Size of peakmeter + + *: "Size of peakmeter" + + + *: "Size of peakmeter" + + + *: "Size of peakmeter" + + + + id: LANG_RECORD_HIST_DRAW + desc: Draw histogram default + + *: "Draw histogram default" + + + *: "Draw histogram default" + + + *: "Draw histogram default" + + + id: VOICE_KBIT_PER_SEC desc: spoken only, a unit postfix user: @@ -12701,3 +12796,126 @@ *: "Show Recordings Folder in Main Menu" + + id: LANG_MULTIINT_CONFIRM + desc: Confirm string for multi_int settings + user: + + *: "Press PLAY to confirm" + + + *: "Press PLAY to confirm" + h100,h120,h300: "Press NAVI to confirm" + ipod*,x5,gigabeat: "Press SELECT to confirm" + ondio*: "Press MODE to confirm" + + + *: "" + + + + id: LANG_RECORD_TIMER + desc: Record timer menu + user: + + *: "Timer Options" + + + *: "Timer Options" + + + *: "Timer Options" + + + + id: LANG_TIMER_SET + desc: Recording timer menu + + *: "Set countdown timer" + + + *: "Set countdown timer" + + + *: "Set countdown timer" + + + + id: LANG_TIMER_REPEAT + desc: Recording timer menu + + *: "Record repeat timer" + + + *: "Record repeat timer" + + + *: "Record repeat timer" + + + + id: LANG_TIMER_DAYS + desc: recording timer settings string + + *: "Days" + + + *: "Days" + + + *: "Days" + + + + id: LANG_TIMER_HRS + desc: recording timer settings string + + *: "Hrs" + + + *: "Hrs" + + + *: "Hrs" + + + + id: LANG_TIMER_MINS + desc: recording timer settings string + + *: "Mins" + + + *: "Mins" + + + *: "Mins" + + + + id: LANG_REC_TIMER + desc: recording screen timer string + + *: "Timer" + + + *: "Timer" + + + *: "Timer" + + + + id: LANG_MENU_SETTING_CANCEL + desc: Visual confirmation of canceling a changed setting + user: + + *: "Canceled" + + + *: "Annulé" + + + *: "" + + diff -Naur _008/apps/menus/recording_menu.c _009_rep/apps/menus/recording_menu.c --- _008/apps/menus/recording_menu.c 2008-07-21 19:59:07.000000000 +0900 +++ _009_rep/apps/menus/recording_menu.c 2008-07-24 00:11:41.895716800 +0900 @@ -45,6 +45,7 @@ #include "sound.h" #ifdef HAVE_RECORDING #include "audio.h" +#include "recording.h" #if CONFIG_TUNER #include "radio.h" #endif @@ -311,12 +312,78 @@ MENUITEM_SETTING(rec_editable, &global_settings.rec_editable, NULL); #endif +/* Displays a menu for changing the countdown timer settings */ +static int countdown_timer_func(void) +{ + bool retval; + bool changed = false; + struct timer* timer = get_timerstat(); + + static const struct opt_items names[] = { + { STR(LANG_TIMER_DAYS) }, + { STR(LANG_TIMER_HRS) }, + { STR(LANG_TIMER_MINS) } + }; + + struct opt_settings settings[] = { + { &timer->days, 6 }, + { &timer->hrs, 23 }, + { &timer->mins, 59 } + }; + + retval = set_multi_int(str(LANG_TIMER_SET), names, settings, 3, &changed); + + if (changed) + { + timer->countdown = false; + timer->secs = 0; + timer->timer_display = false; + } + + return retval; +} + +static int countdown_timer_repeat_func(void) +{ + struct timer* timer = get_timerstat(); + bool retval; + + static const struct opt_items names[] = { + { STR(LANG_TIMER_DAYS) }, + { STR(LANG_TIMER_HRS) }, + { STR(LANG_TIMER_MINS) } + }; + + struct opt_settings settings[] = { + { &timer->days_rpt, 6 }, + { &timer->hrs_rpt, 23 }, + { &timer->mins_rpt, 59 } + }; + retval = set_multi_int(str(LANG_TIMER_REPEAT), names, settings, 3, NULL); + + /* automatically select settings necessary for repeated recording */ + if (timer->days_rpt || timer->hrs_rpt || timer->mins_rpt) + { + global_settings.rec_split_type = 1; /* Stop */ + global_settings.rec_split_method = 0; /* Time */ + global_settings.rec_trigger_mode = 0; /* The repeat timer isn't + compatible with the trigger */ + } + + return retval; +} + +MENUITEM_FUNCTION(countdown_timer, 0, ID2P(LANG_TIMER_SET), + countdown_timer_func, NULL, NULL, Icon_Menu_setting); +MENUITEM_FUNCTION(countdown_timer_repeat, 0, ID2P(LANG_TIMER_REPEAT), + countdown_timer_repeat_func, NULL, NULL, Icon_Menu_setting); MENUITEM_SETTING(rec_split_type, &global_settings.rec_split_type, NULL); MENUITEM_SETTING(rec_split_method, &global_settings.rec_split_method, NULL); MENUITEM_SETTING(rec_timesplit, &global_settings.rec_timesplit, NULL); MENUITEM_SETTING(rec_sizesplit, &global_settings.rec_sizesplit, NULL); -MAKE_MENU(filesplitoptionsmenu, ID2P(LANG_RECORD_TIMESPLIT), NULL, Icon_NOICON, - &rec_split_method, &rec_split_type, &rec_timesplit, &rec_sizesplit); +MAKE_MENU(timermenu, ID2P(LANG_RECORD_TIMER), NULL, Icon_NOICON, + &countdown_timer, &countdown_timer_repeat, &rec_split_method, + &rec_split_type, &rec_timesplit, &rec_sizesplit); MENUITEM_SETTING(rec_prerecord_time, &global_settings.rec_prerecord_time, NULL); @@ -370,6 +437,9 @@ agc_preset_func, NULL, NULL, Icon_Menu_setting); MENUITEM_FUNCTION(agc_cliptime, 0, ID2P(LANG_RECORD_AGC_CLIPTIME), agc_cliptime_func, NULL, NULL, Icon_Menu_setting); +MAKE_MENU(agc_menu, ID2P(LANG_RECORD_AGC_PRESET), NULL, Icon_NOICON, + &agc_preset, &agc_cliptime); + #endif /* HAVE_AGC */ /** Rec trigger **/ @@ -443,6 +513,8 @@ const struct settings_list *settings[TRIG_OPTION_COUNT]; int pm_y[NB_SCREENS]; + int pm_h[NB_SCREENS]; + int trig_xpos[NB_SCREENS]; int trig_ypos[NB_SCREENS]; int trig_width[NB_SCREENS]; @@ -467,6 +539,8 @@ trig_xpos[i] = 0; trig_ypos[i] = vp[i].y + vp[i].height; pm_y[i] = screens[i].getheight() - SYSFONT_HEIGHT; +//check + pm_h[i] = 8; trig_width[i] = screens[i].getwidth(); } /* TODO: what to do if there is < 4 lines on the screen? */ @@ -519,7 +593,9 @@ peak_meter_draw_trig(trig_xpos, trig_ypos, trig_width, NB_SCREENS); action = peak_meter_draw_get_btn(CONTEXT_SETTINGS_RECTRIGGER, 0, pm_y, - SYSFONT_HEIGHT, NB_SCREENS); + pm_h, NB_SCREENS); +//- button = peak_meter_draw_get_btn(0, pm_y, 8, NB_SCREENS); +//+ button = peak_meter_draw_get_btn(0, pm_y, pm_h, NB_SCREENS); FOR_NB_SCREENS(i) screens[i].update(); i = gui_synclist_get_sel_pos(&lists); @@ -583,6 +659,43 @@ rectrigger, NULL, NULL, Icon_Menu_setting); +#if LCD_HEIGHT > 111 +static int history_int_func(void) +{ + static const struct opt_items names[] = { + { "0.5s", TALK_ID(500, UNIT_MS) }, + { "1s", TALK_ID(1, UNIT_SEC) }, + { "2s", TALK_ID(2, UNIT_SEC) }, + { "4s", TALK_ID(4, UNIT_SEC) } + }; + return set_option(str(LANG_RECORDING_HISTOGRAM_INTERVAL), + &global_settings.rec_histogram_interval, + INT, names, 4, NULL ); +} +MENUITEM_FUNCTION(history_interval, 0, ID2P(LANG_RECORDING_HISTOGRAM_INTERVAL), + history_int_func, NULL, NULL, Icon_Menu_setting); +MENUITEM_SETTING(hist_def, &global_settings.hist_def, NULL); +MAKE_MENU(hist_menu, ID2P(LANG_RECORD_HIST_OPTIONS), NULL, Icon_NOICON, + &history_interval, &hist_def); +#endif +static int peak_size_func(void) +{ + static const struct opt_items names[] = { + { "1x", TALK_ID(1, UNIT_INT) }, + { "2x", TALK_ID(2, UNIT_INT) }, + { "3x", TALK_ID(3, UNIT_INT) }, + { "4x", TALK_ID(4, UNIT_INT) }, + { "5x", TALK_ID(5, UNIT_INT) }, + { "6x", TALK_ID(6, UNIT_INT) }, + { "7x", TALK_ID(7, UNIT_INT) }, + { "8x", TALK_ID(8, UNIT_INT) } + }; + return set_option(str(LANG_RECORD_PEAKMETER_SIZE), + &global_settings.peak_size, + INT, names, 8, NULL ); +} +MENUITEM_FUNCTION(peak_size, 0, ID2P(LANG_RECORD_PEAKMETER_SIZE), + peak_size_func, NULL, NULL, Icon_Menu_setting); /* from main_menu.c */ struct browse_folder_info { @@ -613,7 +726,7 @@ #if CONFIG_CODEC == MAS3587F &rec_editable, #endif - &filesplitoptionsmenu, + &timermenu, &rec_prerecord_time, &clear_rec_directory_item, #ifdef HAVE_BACKLIGHT @@ -621,8 +734,12 @@ #endif &rectrigger_item, #ifdef HAVE_AGC - &agc_preset, &agc_cliptime, + &agc_menu, +#endif +#if LCD_HEIGHT > 111 + &hist_menu, #endif + &peak_size, &browse_recconfigs, &save_recpresets_item ); diff -Naur _008/apps/recorder/icons.c _009_rep/apps/recorder/icons.c --- _008/apps/recorder/icons.c 2008-07-21 19:59:13.000000000 +0900 +++ _009_rep/apps/recorder/icons.c 2008-07-23 23:09:36.000000000 +0900 @@ -46,6 +46,14 @@ #endif }; +const unsigned char bitmap_icons_7x7[][7] = +{ + [Icon_Timer] = + {0x1c, 0x22, 0x41, 0x4f, 0x49, 0x22, 0x1d}, /* Recording timer icon */ + [Icon_Timer_rep]= + {0x17, 0x26, 0x45, 0x41, 0x51, 0x32, 0x74} /* Recording repeat timer icon */ +}; + const unsigned char bitmap_icons_7x8[][7] = { {0x08,0x1c,0x3e,0x3e,0x3e,0x14,0x14}, /* Power plug */ @@ -123,7 +131,7 @@ #ifdef HAVE_FLASH_STORAGE {0x15,0x3f,0x7d,0x7B,0x77,0x67,0x79,0x7b,0x57,0x4f,0x47,0x7f}; #else - {0x00,0x00,0x00,0x1c,0x2e,0x4f,0x77,0x79,0x3a,0x1c,0x00,0x00}; + {0x1c,0x2e,0x4f,0x77,0x79,0x3a,0x1c,0x00,0x00,0x00,0x00,0x00}; #endif /* diff -Naur _008/apps/recorder/icons.h _009_rep/apps/recorder/icons.h --- _008/apps/recorder/icons.h 2008-07-24 05:18:30.000000000 +0900 +++ _009_rep/apps/recorder/icons.h 2008-07-23 23:09:36.000000000 +0900 @@ -47,6 +47,12 @@ Icon5x8Last }; +enum icons_7x7 { + Icon_Timer, + Icon_Timer_rep, + Icon7x7Last +}; + enum icons_7x8 { Icon_Plug, Icon_USBPlug, @@ -102,6 +108,7 @@ #endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */ extern const unsigned char bitmap_icons_5x8[Icon5x8Last][5]; +extern const unsigned char bitmap_icons_7x7[Icon7x7Last][7]; extern const unsigned char bitmap_icons_7x8[Icon7x8Last][7]; extern const unsigned char bitmap_icon_disk[]; diff -Naur _008/apps/recorder/peakmeter.c _009_rep/apps/recorder/peakmeter.c --- _008/apps/recorder/peakmeter.c 2008-07-21 19:59:13.000000000 +0900 +++ _009_rep/apps/recorder/peakmeter.c 2008-07-23 23:52:09.740240000 +0900 @@ -155,17 +155,17 @@ /* precalculated peak values that represent magical dBfs values. Used to draw the scale */ static const short db_scale_src_values[DB_SCALE_SRC_VALUES_SIZE] = { - 32736, /* 0 db */ - 22752, /* - 3 db */ - 16640, /* - 6 db */ - 11648, /* - 9 db */ - 8320, /* -12 db */ - 4364, /* -18 db */ - 2064, /* -24 db */ - 1194, /* -30 db */ - 363, /* -40 db */ - 101, /* -50 db */ - 34, /* -60 db */ + 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 */ 0, /* -inf */ }; @@ -198,69 +198,81 @@ long m; int istart; - if (isample < 2308) { /* Range 1-5 */ + /* Range 1-4 */ + if (isample < 119) { - if (isample < 115) { /* Range 1-3 */ + /* Range 1-2 */ + if (isample < 5) { - if (isample < 24) { + /* Range 1 */ + if (isample < 1) { + istart = 0; + n = 0; + m = 5900; + } - if (isample < 5) { - istart = 1; /* Range 1 */ - n = 98; + /* Range 2 */ + else { + istart = 1; + n = 59; m = 34950; } + } + + /* Range 3-4 */ else { - istart = 5; /* Range 2 */ - n = 1496; + + /* Range 3 */ + if (isample < 24) { + istart = 5; + n = 1457; m = 7168; } - } - else { - istart = 24; /* Range 3 */ - n = 2858; - m = 1498; - } - } - else { /* Range 4-5 */ - if (isample < 534) { - istart = 114; /* Range 4 */ - n = 4207; - m = 319; - } + /* Range 4 */ else { - istart = 588; /* Range 5 */ - n = 5583; - m = 69; + istart = 24; + n = 2819; + m = 1464; } } } - else { /* Range 6-9 */ + /* Range 5-8 */ + else { - if (isample < 12932) { + /* Range 5-6 */ + if (isample < 2918) { - if (isample < 6394) { - istart = 2608; /* Range 6 */ - n = 6832; - m = 21; + /* Range 5 */ + if (isample < 592) { + istart = 119; + n = 4210; + m = 295; } + + /* Range 6 */ else { - istart = 7000; /* Range 7 */ - n = 7682; - m = 9; + istart = 592; + n = 5605; + m = 60; } } + + /* Range 7-8 */ else { - if (isample < 22450) { - istart = 13000; /* Range 8 */ - n = 8219; - m = 5; + /* Range 7 */ + if (isample < 15352) { + istart = 2918; + n = 7001; + m = 12; } + + /* Range 8 */ else { - istart = 22636; /* Range 9 */ - n = 8697; + istart = 15352; + n = 8439; m = 3; } } @@ -1329,7 +1341,7 @@ #endif int peak_meter_draw_get_btn(int action_context, int x, int y[], - int height, int nb_screens) + int height[], int nb_screens) { int button = BUTTON_NONE; long next_refresh = current_tick; @@ -1362,10 +1374,10 @@ if (TIME_AFTER(current_tick, next_refresh)) { for(i = 0; i < nb_screens; i++) { - peak_meter_screen(&screens[i], x, y[i], height); + peak_meter_screen(&screens[i], x, y[i], height[i]); screens[i].update_viewport_rect(x, y[i], screens[i].getwidth() - x, - height); + height[i]); } next_refresh += HZ / PEAK_METER_FPS; dopeek = true; diff -Naur _008/apps/recorder/peakmeter.h _009_rep/apps/recorder/peakmeter.h --- _008/apps/recorder/peakmeter.h 2008-07-21 19:59:13.000000000 +0900 +++ _009_rep/apps/recorder/peakmeter.h 2008-07-23 23:11:26.737374400 +0900 @@ -36,7 +36,7 @@ extern void peak_meter_playback(bool playback); extern int peak_meter_draw_get_btn(int action_context, int x, int y[], - int height, int nb_screens); + int height[], int nb_screens); 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); diff -Naur _008/apps/recorder/recording.c _009_rep/apps/recorder/recording.c --- _008/apps/recorder/recording.c 2008-07-22 17:19:28.201686400 +0900 +++ _009_rep/apps/recorder/recording.c 2008-07-24 05:12:00.560787200 +0900 @@ -71,6 +71,8 @@ #include "radio.h" #include "sound_menu.h" #include "viewport.h" +#include "fat.h" +#include "backlight.h" #ifdef HAVE_RECORDING /* This array holds the record timer interval lengths, in seconds */ @@ -164,14 +166,20 @@ return (rec_status & RCSTAT_IN_RECSCREEN) != 0; } -#define PM_HEIGHT ((LCD_HEIGHT >= 72) ? 2 : 1) +static struct timer timer; #if CONFIG_KEYPAD == RECORDER_PAD static bool f2_rec_screen(void); static bool f3_rec_screen(void); #endif +#if defined(HAVE_LCD_BITMAP) && (LCD_HEIGHT > 111) && defined(HAVE_AGC) +#define HAVE_HISTOGRAM /* only for bigger screens */ +#endif + #define MAX_FILE_SIZE 0x7F800000 /* 2 GB - 4 MB */ +#define MIN_DISK_SPACE 48 /* minimum remaining disk space */ +unsigned long disk_space = 0; #ifndef HAVE_REMOTE_LCD static const int screen_update = NB_SCREENS; @@ -211,10 +219,11 @@ * peak_time is the counter of the peak hold read and agc process, * overflow every 13 years 8-) */ + static long peak_time = 0; +static short peak_valid_mem[4]; static long hist_time = 0; -static short peak_valid_mem[4]; #define BAL_MEM_SIZE 24 static short balance_mem[BAL_MEM_SIZE]; @@ -263,6 +272,43 @@ static short agc_maxgain; #endif /* HAVE_AGC */ +/* Histogram data, only for bigger screens */ +#ifdef HAVE_HISTOGRAM +#define HIST_Y (LCD_HEIGHT - 1) +#define HIST_W (LCD_WIDTH / 2 - 4) +static short history_mode; +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]; +#if LCD_DEPTH > 1 +#ifdef HAVE_LCD_COLOR +#define LCD_BATT_OK LCD_RGBPACK(63, 63, 63) +#define LCD_BATT_LO LCD_RGBPACK(159, 0, 0) +#define LCD_DISK_OK LCD_RGBPACK(0, 0, 143) +#define LCD_DISK_LO LCD_RGBPACK(127, 0, 0) +#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 +#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 +#else +#define LCD_HIST_OVER LCD_DEFAULT_FG +#define LCD_HIST_OK LCD_DEFAULT_FG +#define LCD_BAL LCD_DEFAULT_FG +#endif +#endif /* HAVE_HISTOGRAM */ + static void set_gain(void) { if(global_settings.rec_source == AUDIO_SRC_MIC) @@ -306,6 +352,12 @@ for (i = 0; i < BAL_MEM_SIZE; i++) *balance += balance_mem[i]; *balance = *balance / BAL_MEM_SIZE; +#ifdef HAVE_HISTOGRAM + if (*peak_l > hist_l) + hist_l = *peak_l; + if (*peak_r > hist_r) + hist_r = *peak_r; +#endif return true; } @@ -547,8 +599,25 @@ { int max_cursor; - if(cursor < 0) - cursor = 0; + if(cursor < 0) { + cursor = 0; +#ifdef HAVE_HISTOGRAM + int i; + history_mode++; + if (history_mode == 2) { + for (i=0; i < HIST_W; i++) { + history_l[i] = history_l[i] * 2; + history_r[i] = history_r[i] * 2; + } + } else if (history_mode == 4) { + for (i=0; i < HIST_W; i++) { + history_l[i] = history_l[i] / 2; + history_r[i] = history_r[i] / 2; + } + history_mode = 0; + } +#endif + } #ifdef HAVE_AGC switch(global_settings.rec_source) @@ -823,6 +892,37 @@ } } +/* countdown timer tick task */ +void timer_tick_task(void) +{ + static int mini_tick = 0; + + mini_tick ++; + /* the countdown */ + if ((mini_tick >= HZ) && (timer.countdown)) + { + mini_tick = 0; + if (timer.secs) timer.secs -= 1; + else{ + timer.secs = 59; + if (timer.mins) timer.mins -= 1; + else{ + timer.mins = 59; + if (timer.hrs) timer.hrs -= 1; + else{ + timer.hrs = 23; + if (timer.days) timer.days -= 1; + else{ + timer.days = timer.hrs = timer.mins = timer.secs = 0; + /* switch timer display on/off when countdown finished */ + timer.timer_display = !timer.timer_display; + } + } + } + } + } +} + bool recording_start_automatic = false; bool recording_screen(bool no_source) @@ -831,9 +931,18 @@ bool done = false; char buf[32]; char buf2[32]; - int w, h; + int w[NB_SCREENS], h[NB_SCREENS]; + int font[NB_SCREENS]; + int pm_h[NB_SCREENS]; int update_countdown = 1; - unsigned int seconds; +#ifndef SIMULATOR + bool disk_was_active = false; + bool warn_message = true; +#endif + unsigned long disk_free; + int bitrate; + int disk_time = 0; + unsigned int seconds, prerec = 0; int hours, minutes; char filename[13]; int last_audio_stat = -1; @@ -855,10 +964,10 @@ int led_countdown = 2; #endif #ifdef HAVE_AGC - bool peak_read = false; bool peak_valid = false; - int peak_l, peak_r; int balance = 0; + bool peak_read = false; + int peak_l, peak_r; bool display_agc[NB_SCREENS]; #endif int line[NB_SCREENS]; @@ -871,6 +980,13 @@ /* pm_x = offset pm to put clipcount in front. Use lcd_getstringsize() when not using SYSFONT */ int pm_x = global_settings.peak_meter_clipcounter ? 30 : 0; + int agc_line = 0; + bool histogram_on = global_settings.hist_def; + bool font_check = true; + int pm_height[NB_SCREENS]; + int countdown_offset = 0; + bool repeat_timer_start = false; + unsigned int repeat_timer; static const unsigned char *byte_units[] = { ID2P(LANG_BYTE), @@ -901,6 +1017,66 @@ return false; } + /* Stop countdown if countdown settings changed */ + if (!timer.countdown) + tick_remove_task(timer_tick_task); + +#ifdef HAVE_AGC + memset(balance_mem, 0x00, BAL_MEM_SIZE); +#endif + +#ifdef HAVE_HISTOGRAM + int history_pos = 0; + int hist_height; + const short hist_size_h[2] = {17, 31}; + /* + * Peak histogram linear to logarithmic [dB] table. + * The thresholds are scaled between the corresponding + * dispayed values, e.g. -6dB is -5.5dB < level <= 6.5dB + */ + const short hist_peak_lin2dB[2][31] = + { + /* 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 }, + /* 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[4][6] = + { + /* linear: 0, -6, -12, -24, -inf [dB] */ + { 15, 8, 4, 1, 0, 0}, + /* logarithmic: 0, -6, -12, -24, -48 [dB] */ + { 15, 12, 9, 4, 1, 1}, + /* linear: 0, -3, -6, -12, -24, -inf [dB] */ + { 29, 21, 15, 7, 2, 0}, + /* logarithmic: 0, -3, -6, -12, -24, -48 [dB] */ + { 29, 26, 23, 17, 9, 2} + }; + 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 unsigned char rec_icons_6x8[][6] = + { + {0x00,0x1c,0x3e,0x36,0x3e,0x1c} + }; + enum icons_6x8 + { + Icon_Disk, + Icon_6x8end + }; + + memset(history_l, 0x00, sizeof(history_l)); + memset(history_r, 0x00, sizeof(history_r)); +#endif /* HAVE_HISTOGRAM */ + cursor = 0; #if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR) ata_set_led_enabled(false); @@ -916,7 +1092,7 @@ peak_meter_enabled = true; peak_meter_playback(true); #endif - + gui_syncsplash(1, "%s...", str(LANG_RECORDING)); audio_init_recording(0); sound_set_volume(global_settings.volume); @@ -954,32 +1130,133 @@ agc_maxgain = global_settings.rec_agc_maxgain_line; } #endif /* HAVE_AGC */ - +//check +/* FOR_NB_SCREENS(i) { viewport_set_defaults(&vp[i], i); vp[i].font = FONT_SYSFIXED; screens[i].set_viewport(&vp[i]); screens[i].setfont(FONT_SYSFIXED); - screens[i].getstringsize("M", &w, &h); filename_offset[i] = ((vp[i].height >= 7*h) ? 1 : 0); pm_y[i] = h * (2 + filename_offset[i]); } +*/ + + FOR_NB_SCREENS(i) + { + viewport_set_defaults(&vp[i], i); + vp[i].font = FONT_SYSFIXED; + screens[i].set_viewport(&vp[i]); + } #ifdef HAVE_REMOTE_LCD if (!remote_display_on) { screens[1].clear_display(); snprintf(buf, sizeof(buf), str(LANG_REMOTE_LCD_ON)); - screens[1].puts((vp[1].width/w - strlen(buf))/2 + 1, - vp[1].height/(h*2) + 1, buf); +// screens[1].puts((vp[1].width/w - strlen(buf))/2 + 1, +// vp[1].height/(h*2) + 1, buf); + screens[1].puts((vp[1].width/w[1] - strlen(buf))/2 + 1, + vp[1].height/(h[1]*2) + 1, buf); screens[1].update(); gui_syncsplash(0, str(LANG_REMOTE_LCD_OFF)); } #endif + /* store the free disk space for this session [MBytes] */ + fat_size(IF_MV2(0,) NULL, &disk_free); /* free KBytes */ + disk_free = disk_free / 1024; + if (disk_free > disk_space) + disk_space = disk_free; + bitrate = 1411; /* [kbps] default for 44kHz stereo 16bit WAV */ + +#ifdef HAVE_HISTOGRAM + history_mode = global_settings.rec_histogram_mode; + hist_time_interval = 1 << global_settings.rec_histogram_interval; +#endif + while(!done) { + switch(global_settings.rec_source) + { + case AUDIO_SRC_LINEIN: +#ifdef HAVE_FMRADIO_IN + case AUDIO_SRC_FMRADIO: +#endif + FOR_NB_SCREENS(i) + line[i] = 5; + agc_line = 1; + break; + case AUDIO_SRC_MIC: + FOR_NB_SCREENS(i) + line[i] = 4; + agc_line = 1; + break; +#ifdef HAVE_SPDIF_IN + case AUDIO_SRC_SPDIF: + FOR_NB_SCREENS(i) + line[i] = 3; + agc_line = 0; /* no agc line for Spdif in */ + break; +#endif + default: + FOR_NB_SCREENS(i) + line[i] = 5; + break; + } + /* check and change font only if source has been changed */ + if (font_check) + { + FOR_NB_SCREENS(i) + pm_height[i] = global_settings.peak_size + 1; + + FOR_NB_SCREENS(i) + { +//check +// filename_offset[i] = ((vp[i].height >= 80) ? 1 : 0); + filename_offset[i] = ((vp[i].height >= 7*h[i]) ? 1 : 0); + + while(vp[i].height < (line[i] + 1 + filename_offset[i] + pm_height[i]) * 8) + { + pm_height[i] -= 1; + if (pm_height[i] < 1) + { pm_height[i] = 1; + break; + } + } + + screens[i].setfont(FONT_UI); + screens[i].getstringsize("M", &w[i], &h[i]); + + if (i == SCREEN_MAIN) { + if (h[i] <= ((LCD_HEIGHT - (histogram_on ? 25 : 8)) / (line[i] + + filename_offset[0] + pm_height[i] + agc_line))) + font[i] = FONT_UI; + else + font[i] = FONT_SYSFIXED; + } + else if (h[i] <= ((vp[i].height) / (line[i] + filename_offset[i] + pm_height[i]))) + font[i] = FONT_UI; + else + font[i] = FONT_SYSFIXED; + + screens[i].setfont(font[i]); + screens[i].getstringsize("M", &w[i], &h[i]); +// screens[i].setmargins(global_settings.invert_cursor ? 0 : w[i], 8); + if (h[i] > 8) { + pm_y[i] = 1 + h[i] * (2 + filename_offset[i]); + pm_h[i] = (h[i] - 1) * pm_height[i]; + } + else { + pm_y[i] = h[i] * (2 + filename_offset[i]); + pm_h[i] = h[i] * pm_height[i]; + } + } + font_check = false; + } + + audio_stat = audio_status(); #if (CONFIG_LED == LED_REAL) @@ -1031,10 +1308,10 @@ /* Wait for a button a while (HZ/10) drawing the peak meter */ button = peak_meter_draw_get_btn(CONTEXT_RECSCREEN, - pm_x, pm_y, h * PM_HEIGHT, + pm_x, pm_y, pm_h, // pm_x, pm_y, 8, screen_update); - +// button = peak_meter_draw_get_btn(0, pm_y, pm_h, h[i] * pm_height[i], screen_update); if (last_audio_stat != audio_stat) { if (audio_stat & AUDIO_STATUS_RECORD) @@ -1044,7 +1321,6 @@ last_audio_stat = audio_stat; } - if (recording_start_automatic) { /* simulate a button press */ @@ -1052,9 +1328,33 @@ recording_start_automatic = false; } + /* repeat_timer is the repeat time in seconds */ + repeat_timer = (timer.mins_rpt * 60 + timer.hrs_rpt * + 3600 + timer.days_rpt * 3600 * 24); + + /* decide on repeat timer status */ + if ((repeat_timer > rec_timesplit_seconds()) && + global_settings.rec_timesplit) + timer.repeater = true; + else + timer.repeater = false; + + /* When countdown timer reaches zero fake a new file button press */ + if (timer.countdown && !timer.days && !timer.hrs && !timer.mins && + !timer.secs) + { + tick_remove_task(timer_tick_task); + button = ACTION_REC_NEWFILE; + timer.countdown = false; + } + switch(button) { #ifdef HAVE_REMOTE_LCD + case ACTION_REC_HIST_TOGGLE: + histogram_on = !histogram_on; + font_check = true; + break; case ACTION_REC_LCD: if (remote_display_on) { @@ -1062,9 +1362,11 @@ screen_update = 1; screens[1].clear_display(); snprintf(buf, sizeof(buf), str(LANG_REMOTE_LCD_ON)); - screens[1].puts((screens[1].getwidth()/w - strlen(buf))/2 + - 1, - screens[1].getheight()/(h*2) + 1, buf); +// screens[1].puts((screens[1].getwidth()/w - strlen(buf))/2 + +// 1, +// screens[1].getheight()/(h*2) + 1, buf); + screens[1].puts((screens[1].getwidth()/w[1] - strlen(buf))/2 + 1, + screens[1].getheight()/(h[1]*2) + 1, buf); screens[1].update(); gui_syncsplash(0, str(LANG_REMOTE_LCD_OFF)); } @@ -1099,7 +1401,27 @@ case ACTION_REC_NEWFILE: /* Only act if the mpeg is stopped */ if(!(audio_stat & AUDIO_STATUS_RECORD)) - { + { /* if countdown timer is set, start countdown */ + if (timer.days || timer.hrs || timer.mins || timer.secs) + { + if (button == ACTION_REC_PAUSE) + { + timer.countdown = !timer.countdown; + if (timer.countdown) + tick_add_task(timer_tick_task); + else + tick_remove_task(timer_tick_task); + break; + } + else + { + /* if newfile button pressed and countdown timer is on, + start new file and reset timer */ + tick_remove_task(timer_tick_task); + timer.days = timer.hrs = timer.mins = timer.secs = 0; + timer.countdown = false; + } + } /* is this manual or triggered recording? */ if ((global_settings.rec_trigger_mode == TRIG_MODE_OFF) || (peak_meter_trigger_status() != TRIG_OFF)) @@ -1107,6 +1429,11 @@ /* manual recording */ rec_status |= RCSTAT_HAVE_RECORDED; rec_command(RECORDING_CMD_START); + repeat_timer_start = true; /* allow access to repeat timer + code */ + /* amount of file that has been prerecorded - needed for + syncing repeat timer */ + prerec = audio_recorded_time() / HZ; last_seconds = 0; if (global_settings.talk_menu) { @@ -1309,7 +1636,6 @@ #ifdef HAVE_FMRADIO_REC const int prev_rec_source = global_settings.rec_source; #endif - #if (CONFIG_LED == LED_REAL) /* led is restored at begin of loop / end of function */ led(false); @@ -1331,6 +1657,10 @@ && prev_rec_source == AUDIO_SRC_FMRADIO) radio_status = FMRADIO_OFF; #endif + /* if countdown timer settings changed in menu, + stop counting and reset */ + if (!timer.countdown) + tick_remove_task(timer_tick_task); #if CONFIG_CODEC == SWCODEC /* reinit after submenu exit */ @@ -1365,13 +1695,20 @@ adjust_cursor(); set_gain(); update_countdown = 1; /* Update immediately */ +#ifdef HAVE_HISTOGRAM + hist_time_interval = 1 << global_settings.rec_histogram_interval; +#endif FOR_NB_SCREENS(i) { +//check screens[i].set_viewport(&vp[i]); - screens[i].setfont(FONT_SYSFIXED); +// screens[i].setfont(FONT_SYSFIXED); + screens[i].setfont(font[i]); +// screens[i].setmargins(global_settings.invert_cursor ? 0 : w[i], 8); } } + font_check = true; } break; @@ -1439,6 +1776,9 @@ break; } /* end switch */ + /* display timer status in status bar if countdown enabled */ + timer.timer_display = timer.countdown; + #ifdef HAVE_AGC peak_read = !peak_read; if (peak_read) { /* every 2nd run of loop */ @@ -1452,7 +1792,8 @@ #endif FOR_NB_SCREENS(i) - screens[i].setfont(FONT_SYSFIXED); +// screens[i].setfont(FONT_SYSFIXED); + screens[i].setfont(font[i]); seconds = audio_recorded_time() / HZ; @@ -1466,12 +1807,23 @@ update_countdown = 5; last_seconds = seconds; + /* Get free disk space and calculate remain time */ + fat_size( IF_MV2(0,) NULL, &disk_free ); /* [KBytes] */ + disk_free = disk_free / 1024; + if (disk_free < MIN_DISK_SPACE) + disk_free = MIN_DISK_SPACE; + disk_free -= MIN_DISK_SPACE; + disk_time = 140 * (int)disk_free / bitrate; /* rough estimation */ + dseconds = rec_timesplit_seconds(); dsize = rec_sizesplit_bytes(); num_recorded_bytes = audio_num_recorded_bytes(); for(i = 0; i < screen_update; i++) + { screens[i].clear_display(); + screens[i].setfont(font[i]); + } style = base_style; @@ -1498,11 +1850,13 @@ if ((global_settings.rec_sizesplit) && (global_settings.rec_split_method)) { + countdown_offset = 1; dmb = dsize/1024/1024; snprintf(buf, sizeof(buf), "%s %dMB", str(LANG_SYSFONT_SPLIT_SIZE), dmb); } - else + /* only display recording time if countdown timer is off */ + else if (!timer.days && !timer.hrs && !timer.mins && !timer.secs) { hours = seconds / 3600; minutes = (seconds - (hours * 3600)) / 60; @@ -1510,6 +1864,11 @@ str(LANG_SYSFONT_RECORDING_TIME), hours, minutes, seconds%60); } + else + { + countdown_offset = 0; + snprintf(buf, 32, ""); + } for(i = 0; i < screen_update; i++) screens[i].puts(0, 0, buf); @@ -1535,7 +1894,8 @@ str(LANG_SYSFONT_RECORD_TIMESPLIT_REC), dhours, dminutes); } - else + /* only display recording size if countdown timer is off */ + else if (!timer.days && !timer.hrs && !timer.mins && !timer.secs) { output_dyn_value(buf2, sizeof buf2, num_recorded_bytes, @@ -1547,6 +1907,16 @@ for(i = 0; i < screen_update; i++) screens[i].puts(0, 1, buf); + /* display countdown timer if set */ + if (timer.days || timer.hrs || timer.mins || timer.secs) + { + snprintf(buf, 32, "%s %d:%02d:%02d:%02d", str(LANG_REC_TIMER), + timer.days, timer.hrs, timer.mins, timer.secs); + + for(i = 0; i < screen_update; i++) + screens[i].puts(0, countdown_offset, buf); + } + for(i = 0; i < screen_update; i++) { if (filename_offset[i] > 0) @@ -1581,7 +1951,8 @@ rec_command(RECORDING_CMD_START_NEWFILE); last_seconds = 0; } - else +// else + else if (repeat_timer_start) { peak_meter_trigger(false); peak_meter_set_trigger_listener(NULL); @@ -1589,6 +1960,31 @@ rec_command(RECORDING_CMD_STOP); else rec_command(RECORDING_CMD_STOP_SHUTDOWN); + + /* stop any more attempts to access this code until a new + recording is started */ + repeat_timer_start = false; + + /* start repeat countdown if set and only if + stop time < repeat time */ + if (timer.repeater) + { + repeat_timer -= dseconds; + timer.days = repeat_timer / (3600 * 24); + timer.hrs = (repeat_timer - (timer.days * 3600 * 24)) / + 3600; + timer.mins = (repeat_timer - (timer.hrs * 3600)) / 60; + timer.secs = prerec; /* add prerecorded time to timer */ + + /* This is not really a toggle so much as a safety feature + so that it is impossible to start the timer more than + once */ + timer.countdown = !timer.countdown; + if (timer.countdown) + tick_add_task(timer_tick_task); + else + tick_remove_task(timer_tick_task); + } } update_countdown = 1; } @@ -1600,10 +1996,10 @@ snprintf(clpstr, 32, "%4d", pm_get_clipcount()); for(i = 0; i < screen_update; i++) { - if(PM_HEIGHT > 1) + if(pm_height[i] > 1) screens[i].puts(0, 2 + filename_offset[i], str(LANG_SYSFONT_PM_CLIPCOUNT)); - screens[i].puts(0, 1 + PM_HEIGHT + filename_offset[i], + screens[i].puts(0, 1 + pm_height[i] + filename_offset[i], clpstr); } } @@ -1617,14 +2013,18 @@ { for(i = 0; i < screen_update; i++) screens[i].puts_style_offset(0, filename_offset[i] + - PM_HEIGHT + 2, buf, style,0); + pm_height[i] + 2, buf, style,0); +//- PM_HEIGHT + 2, buf, STYLE_INVERT,0); +//+ pm_height[i] + 2, buf, STYLE_INVERT,0); } else { for(i = 0; i < screen_update; i++) screens[i].putsxy(ymargin, - h*(filename_offset[i]+ - PM_HEIGHT + 2), buf); + h[i]*(filename_offset[i]+ + pm_height[i] + 2), buf); +//- screens[i].puts(0, filename_offset[i] + PM_HEIGHT + 2, buf); +//+ screens[i].puts(0, filename_offset[i] + pm_height[i] + 2, buf); } if(global_settings.rec_source == AUDIO_SRC_MIC) @@ -1638,14 +2038,18 @@ { for(i = 0; i < screen_update; i++) screens[i].puts_style_offset(0, filename_offset[i] + - PM_HEIGHT + 3, buf, style,0); + pm_height[i] + 3, buf, style,0); +//- PM_HEIGHT + 3, buf, STYLE_INVERT,0); +//+ pm_height[i] + 3, buf, STYLE_INVERT,0); } else { for(i = 0; i < screen_update; i++) screens[i].putsxy(ymargin, - h*(filename_offset[i] + - PM_HEIGHT + 3), buf); + h[i]*(filename_offset[i] + + pm_height[i] + 3), buf); +//- PM_HEIGHT + 3, buf); +//+ pm_height[i] + 3, buf); } } else if(0 @@ -1671,14 +2075,18 @@ { for(i = 0; i < screen_update; i++) screens[i].puts_style_offset(0, filename_offset[i] + - PM_HEIGHT + 3, buf, style,0); + pm_height[i] + 3, buf, style,0); +//- PM_HEIGHT + 3, buf, STYLE_INVERT,0); +//+ pm_height[i] + 3, buf, STYLE_INVERT,0); } else { for(i = 0; i < screen_update; i++) screens[i].putsxy(ymargin, - h*(filename_offset[i] + - PM_HEIGHT + 3), buf); + h[i]*(filename_offset[i] + + pm_height[i] + 3), buf); +//- PM_HEIGHT + 3, buf); +//+ pm_height[i] + 3, buf); } snprintf(buf, sizeof(buf), "%s:%s", @@ -1696,22 +2104,27 @@ { for(i = 0; i < screen_update; i++) screens[i].puts_style_offset(0, filename_offset[i] + - PM_HEIGHT + 4, buf, style,0); + pm_height[i] + 4, buf, style,0); +//- PM_HEIGHT + 4, buf, STYLE_INVERT,0); +//+ pm_height[i] + 4, buf, STYLE_INVERT,0); } else { for(i = 0; i < screen_update; i++) screens[i].putsxy(ymargin, - h*(filename_offset[i] + - PM_HEIGHT + 4), buf); + h[i]*(filename_offset[i] + + pm_height[i] + 4), buf); +//- PM_HEIGHT + 4, buf); +//+ pm_height[i] + 4, buf); } } + yield(); + #ifdef HAVE_LCD_COLOR /* special action for gradient - back to single line gradient */ if(global_settings.cursor_style == 3) style = base_style | CURLN_PACK(0) | NUMLN_PACK(1); #endif /* HAVE_LCD_COLOR */ - FOR_NB_SCREENS(i) { switch (global_settings.rec_source) @@ -1735,15 +2148,18 @@ break; } /* end switch */ #ifdef HAVE_AGC - if (vp[i].height < h * (2 + filename_offset[i] + - PM_HEIGHT + line[i])) +// if (vp[i].height < h * (2 + filename_offset[i] + +// PM_HEIGHT + line[i])) +//- if (screens[i].height < h * (2 + filename_offset[i] + PM_HEIGHT + line[i])) +// if (vp[i].height < 8 + h[i] * (1 + filename_offset[i] + pm_height[i] + line[i])) + if (vp[i].height < h[i] * (1 + filename_offset[i] + pm_height[i] + line[i])) { line[i] -= 1; display_agc[i] = false; } else display_agc[i] = true; - +//check if ((cursor==4) || (cursor==5)) display_agc[i] = true; } @@ -1788,7 +2204,9 @@ { for(i = 0; i < screen_update; i++) screens[i].puts_style_offset(0, filename_offset[i] + - PM_HEIGHT + line[i], buf, style,0); + pm_height[i] + line[i], buf, style,0); +//- PM_HEIGHT + line[i], buf, STYLE_INVERT,0); +//+ pm_height[i] + line[i], buf, STYLE_INVERT,0); } else if (global_settings.rec_source == AUDIO_SRC_MIC HAVE_LINE_REC_(|| global_settings.rec_source == @@ -1800,8 +2218,12 @@ for(i = 0; i < screen_update; i++) { if (display_agc[i]) { screens[i].putsxy(ymargin, - h*(filename_offset[i] + - PM_HEIGHT + line[i]), buf); + h[i]*(filename_offset[i] + + pm_height[i] + line[i]), buf); +//- screens[i].puts(0, filename_offset[i] + +//- PM_HEIGHT + line[i], buf); +//+ screens[i].puts(0, filename_offset[i] + +//+ pm_height[i] + line[i], buf); } } } @@ -1829,27 +2251,27 @@ for(i = 0; i < screen_update; i++) screen_put_cursorxy(&screens[i], 0, filename_offset[i] + - PM_HEIGHT + 3, true); + pm_height[i] + 3, true); if(global_settings.rec_source != AUDIO_SRC_MIC) { for(i = 0; i < screen_update; i++) screen_put_cursorxy(&screens[i], 0, filename_offset[i] + - PM_HEIGHT + 4, true); + pm_height[i] + 4, true); } break; case 2: for(i = 0; i < screen_update; i++) screen_put_cursorxy(&screens[i], 0, filename_offset[i] + - PM_HEIGHT + 3, true); + pm_height[i] + 3, true); break; case 3: for(i = 0; i < screen_update; i++) screen_put_cursorxy(&screens[i], 0, filename_offset[i] + - PM_HEIGHT + 4, true); + pm_height[i] + 4, true); break; #ifdef HAVE_AGC case 4: @@ -1857,16 +2279,256 @@ for(i = 0; i < screen_update; i++) screen_put_cursorxy(&screens[i], 0, filename_offset[i] + - PM_HEIGHT + line[i], true); + pm_height[i] + line[i], true); break; #endif /* HAVE_AGC */ default: for(i = 0; i < screen_update; i++) screen_put_cursorxy(&screens[i], 0, filename_offset[i] + - PM_HEIGHT + 2, true); + pm_height[i] + 2, true); + } + } + +#ifdef HAVE_AGC + hist_time++; +#endif + +#ifdef HAVE_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)) + int hist_bal_y; + if (histogram_on) + hist_bal_y = HIST_Y - hist_size_h[history_mode/2] - 11; + else + hist_bal_y = HIST_Y - 11; + + if((global_settings.rec_source == AUDIO_SRC_MIC)|| + (global_settings.rec_source == AUDIO_SRC_LINEIN)|| + (global_settings.rec_source == AUDIO_SRC_FMRADIO)) + agc_line = 1; + else + agc_line = 0; /* no agc line for Spdif in */ + + if ((hist_bal_y) > (8 + ((line[0] + filename_offset[0] + + pm_height[0] + agc_line + (global_settings.rec_trigger_mode > + 0 ? 1 : 0)) * h[0]))) + { + lcd_setfont(FONT_SYSFIXED); + lcd_set_drawmode(DRMODE_FG); +#if LCD_DEPTH > 1 + if (battery_level() > 10) + lcd_set_foreground(LCD_BATT_OK); + else + lcd_set_foreground(LCD_BATT_LO); +#else + lcd_set_foreground( +#ifdef HAVE_LCD_COLOR + global_settings.fg_color); +#else + LCD_DEFAULT_FG); +#endif +#endif /* LCD_DEPTH > 1 */ + lcd_fillrect(0, hist_bal_y, + (30 * battery_level() + 60) / 100, 9); +#if LCD_DEPTH > 1 + if (disk_time > 59) + lcd_set_foreground(LCD_DISK_OK); + else + lcd_set_foreground(LCD_DISK_LO); +#endif /* LCD_DEPTH > 1 */ + if ((LCD_WIDTH/2 - 36)*(disk_space-disk_free-3) / disk_space) + lcd_fillrect(35, hist_bal_y, (LCD_WIDTH/2 - 37) * + (disk_space - disk_free - 1) / disk_space, 9); + lcd_set_drawmode(DRMODE_COMPLEMENT); + lcd_set_foreground( +#ifdef HAVE_LCD_COLOR + global_settings.fg_color); +#else + LCD_DEFAULT_FG); +#endif +#ifndef SIMULATOR + if (charger_inserted()) + lcd_mono_bitmap(bitmap_icons_7x8[Icon_Plug], + 2 + 19*(battery_level() > 48), + hist_bal_y + 1, 7, 8); +#endif + if (battery_time() > 90) + snprintf(buf, 32, "%dh", (battery_time() + 10) / 60); + else + snprintf(buf,32, "%dm", battery_time()); + if (battery_level() > 48) + i = 1; + else if ((battery_time() < 590) && (battery_time() > 90)) + i = 15; + else + i = 10; + lcd_putsxy(i, hist_bal_y + 1, buf); + if (disk_time > 90) + snprintf(buf, 32, "%dh", (disk_time + 10) / 60); + else + snprintf(buf, 32, "%dm", disk_time); + i = ((disk_time < 91) || (disk_time > 589))? 30:26; + + if ((hist_time % 2) +#ifndef SIMULATOR + || !ata_disk_is_active() +#endif + ) + lcd_mono_bitmap(rec_icons_6x8[Icon_Disk], + LCD_WIDTH/2 - 11, + hist_bal_y + 1, 6, 8); + lcd_putsxy((5*disk_free > 3*disk_space) ? + (LCD_WIDTH/2 - i) : 37, + hist_bal_y + 1, buf); + lcd_drawrect(34, hist_bal_y - 1, LCD_WIDTH/2 - 36, 11); + lcd_set_drawmode(DRMODE_SOLID); + lcd_drawrect(0, hist_bal_y - 1, 30, 11); + lcd_vline(30, hist_bal_y + 2, hist_bal_y + 6); + lcd_vline(31, hist_bal_y + 2, hist_bal_y + 6); + + int bal; + lcd_drawrect(HIST_BAL_X-2, hist_bal_y-1, HIST_BAL_W+3, 11); + lcd_hline(HIST_BAL_X + HIST_BAL_W/2 - 1, + HIST_BAL_X + HIST_BAL_W/2 + 1, + hist_bal_y - 2); + lcd_hline(HIST_BAL_X + HIST_BAL_W/2 - 1, + HIST_BAL_X + HIST_BAL_W/2 + 1, + hist_bal_y + 10); + lcd_set_drawmode(DRMODE_FG); +#ifndef HAVE_LCD_COLOR + lcd_set_foreground(LCD_BAL); +#endif + for (i = 0; i < BAL_MEM_SIZE; i++) { + bal = MIN(balance_mem[i], BAL_MAX_R); + bal = MAX(bal, BAL_MAX_L); +#ifdef HAVE_LCD_COLOR + if (bal > 142) + lcd_set_foreground(LCD_BAL_L); + else if (bal < 142) + lcd_set_foreground(LCD_BAL_R); + else + lcd_set_foreground(LCD_DARKGRAY); +#endif + /* every 0.2 seconds a balance measure is taken, + draw a vline for each */ + lcd_vline(HIST_BAL_X + HIST_BAL_W/2 + + HIST_BAL_W * bal / 9976, + hist_bal_y + 1, hist_bal_y + 7); + } + lcd_set_foreground(LCD_BLACK); + bal = MAX(balance, BAL_MAX_L); + bal = MIN(bal, BAL_MAX_R); + /* draw the 3 pixel wide balance measure, + average measure of the last 24 measures (5 seconds) */ + lcd_fillrect(HIST_BAL_X-1 + HIST_BAL_W/2 + + HIST_BAL_W * bal / 9976, + hist_bal_y, 3, 9); + lcd_drawpixel(HIST_BAL_X + HIST_BAL_W/2, hist_bal_y + 4); + lcd_set_drawmode(DRMODE_COMPLEMENT); + lcd_drawpixel(HIST_BAL_X + HIST_BAL_W/2, hist_bal_y - 1); + lcd_drawpixel(HIST_BAL_X + HIST_BAL_W/2, hist_bal_y + 9); + for (i = 0; i < 12; i++) + lcd_drawpixel(HIST_BAL_X + HIST_BAL_W/2 + + HIST_BAL_W * hist_balance_marks[i] / 9976, + hist_bal_y + 4); + } + + if (histogram_on) + { + hist_height = hist_size_h[history_mode/2] - 1; + if (peak_valid && !(hist_time % hist_time_interval) && hist_l) + { + if (history_mode % 2) { + i = 0; + while (hist_l < hist_peak_lin2dB[history_mode / 2][i]) + i++; + history_l[history_pos] = hist_height - i; + i = 0; + while (hist_r < hist_peak_lin2dB[history_mode / 2][i]) + i++; + history_r[history_pos] = hist_height - i; + } else { + history_l[history_pos] = hist_l * hist_height / 32767; + history_r[history_pos] = hist_r * hist_height / 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_Y - hist_height, + HIST_W + 2, hist_height + 1); + lcd_drawrect(HIST_W + 6, HIST_Y - hist_height, + HIST_W + 2, hist_height + 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_height) + lcd_set_foreground(LCD_HIST_OVER); + else if (history_l[i] > hist_level_marks[history_mode][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_height) + lcd_set_foreground(LCD_HIST_OVER); + else if (history_r[i] > hist_level_marks[history_mode][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_height) + 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_height) + 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]); + } + } + lcd_set_foreground(LCD_WHITE); + for (i = 0; i < HIST_W; i++) { + if (history_l[i] == hist_height) + lcd_drawpixel(1 + i, HIST_Y - 1); + if (history_r[i] == hist_height) + lcd_drawpixel(HIST_W + 7 + i, HIST_Y - 1); } +#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[history_mode][i]); } +#endif /* HAVE_HISTOGRAM */ #ifdef HAVE_AGC hist_time++; @@ -1877,7 +2539,9 @@ screens[i].set_viewport(NULL); gui_statusbar_draw(&(statusbars.statusbars[i]), true); screens[i].set_viewport(&vp[i]); - peak_meter_screen(&screens[i], pm_x, pm_y[i], h*PM_HEIGHT); + peak_meter_screen(&screens[i], pm_x, pm_y[i], pm_h[i]); +//- peak_meter_screen(&screens[i], 0, pm_y[i], h*PM_HEIGHT); +//+ peak_meter_screen(&screens[i], 0, pm_y[i], pm_h[i]); screens[i].update(); } @@ -1885,15 +2549,31 @@ FOR_NB_SCREENS(i) { /* NOTE: UGLY width setting based on height! To be fixed! */ - trig_width[i] = ((vp[i].height < 64) || - ((vp[i].height < 72) && (PM_HEIGHT > 1))) ? - screens[i].getwidth() - 14 * w : - screens[i].getwidth(); +// trig_width[i] = ((vp[i].height < 64) || +// ((vp[i].height < 72) && (PM_HEIGHT > 1))) ? +// screens[i].getwidth() - 14 * w : +// screens[i].getwidth(); +//- trig_width[i] = ((screens[i].height < 64) || +//- ((screens[i].height < 72) && (PM_HEIGHT > 1))) ? +//- screens[i].width - 14 * w : screens[i].width; + trig_width[i] = (vp[i].height < (h[i] * (2 + + filename_offset[i] + pm_height[i] + + line[i]) + (histogram_on ? 25 : 8))) ? + screens[i].getwidth() - + 14 * w[i] : screens[i].getwidth(); trig_xpos[i] = screens[i].getwidth() - trig_width[i]; - trig_ypos[i] = ((vp[i].height < 72) && (PM_HEIGHT > 1)) ? - h*2 : - h*(1 + filename_offset[i] + PM_HEIGHT + - line[i] +// trig_ypos[i] = ((vp[i].height < 72) && (PM_HEIGHT > 1)) ? +// h*2 : +// h*(1 + filename_offset[i] + PM_HEIGHT + +// line[i] +//- trig_ypos[i] = ((screens[i].height < 72) && (PM_HEIGHT > 1)) ? +//- h*2 : +//- h*(1 + filename_offset[i] + PM_HEIGHT + line[i] + trig_ypos[i] = (vp[i].height < (h[i] * (2 + + filename_offset[i] + pm_height[i] + + line[i]) + (histogram_on ? 25 : 8))) ? h[i]*2 + : h[i]*(1 + filename_offset[i] + + pm_height[i] + line[i] #ifdef HAVE_AGC + 1 #endif @@ -1911,6 +2591,51 @@ } } + /* check battery level & free disk space */ +#ifndef SIMULATOR + if (ata_disk_is_active()) + disk_was_active = true; + else if (disk_was_active) + { + lcd_setfont(FONT_UI); + if (disk_time == 0) { + backlight_on(); +#ifdef HAVE_REMOTE_LCD + remote_backlight_on(); +#endif + if (audio_stat & AUDIO_STATUS_RECORD) { + gui_syncsplash(HZ, "%s %s", + str(LANG_WARNING_DISK_FULL), + str(LANG_WARNING_STOP_RECORDING)); + audio_stop_recording(); + } + else { + gui_syncsplash(2*HZ, + str(LANG_WARNING_DISK_FULL)); + } + } + else if (warn_message && (battery_level() < 10)) { + backlight_on(); +#ifdef HAVE_REMOTE_LCD + remote_backlight_on(); +#endif + gui_syncsplash(3*HZ, + str(LANG_WARNING_BATTERY_LOW)); + } + else if (!warn_message && (disk_free < 512)) { + backlight_on(); +#ifdef HAVE_REMOTE_LCD + remote_backlight_on(); +#endif + gui_syncsplash(3*HZ, + str(LANG_WARNING_DISKSPACE_LOW)); + } + lcd_setfont(FONT_SYSFIXED); + warn_message = !warn_message; + disk_was_active = false; + } +#endif + if(audio_stat & AUDIO_STATUS_ERROR) { done = true; @@ -1980,6 +2705,10 @@ if (rec_status & (RCSTAT_CREATED_DIRECTORY | RCSTAT_HAVE_RECORDED)) reload_directory(); +#ifdef HAVE_HISTOGRAM + global_settings.rec_histogram_mode = history_mode; +#endif + #if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR) ata_set_led_enabled(true); #endif @@ -2228,6 +2957,12 @@ } #endif /* CONFIG_KEYPAD == RECORDER_PAD */ +struct timer *get_timerstat(void) +{ + return &timer; +} + + #if CONFIG_CODEC == SWCODEC void audio_beep(int duration) { diff -Naur _008/apps/recorder/recording.c.orig1 _009_rep/apps/recorder/recording.c.orig1 --- _008/apps/recorder/recording.c.orig1 1970-01-01 09:00:00.000000000 +0900 +++ _009_rep/apps/recorder/recording.c.orig1 2008-07-24 02:51:43.107083200 +0900 @@ -0,0 +1,3034 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: recording.c 17945 2008-07-05 12:47:34Z jdgordon $ + * + * Copyright (C) 2002 by Linus Nielsen Feltzing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" + +#include +#include +#include + +#include "system.h" +#include "power.h" +#include "powermgmt.h" +#include "lcd.h" +#include "led.h" +#include "mpeg.h" +#include "audio.h" +#if CONFIG_CODEC == SWCODEC +#include "thread.h" +#include "playback.h" +#include "enc_config.h" +#if defined(HAVE_SPDIF_IN) || defined(HAVE_SPDIF_OUT) +#include "spdif.h" +#endif +#endif /* CONFIG_CODEC == SWCODEC */ +#include "recording.h" +#include "mp3_playback.h" +#include "mas.h" +#include "button.h" +#include "kernel.h" +#include "settings.h" +#include "lang.h" +#include "font.h" +#include "icons.h" +#include "icon.h" +#include "screens.h" +#include "peakmeter.h" +#include "statusbar.h" +#include "menu.h" +#include "sound_menu.h" +#include "timefuncs.h" +#include "debug.h" +#include "misc.h" +#include "tree.h" +#include "string.h" +#include "dir.h" +#include "errno.h" +#include "talk.h" +#include "sound.h" +#include "ata.h" +#include "splash.h" +#include "screen_access.h" +#include "action.h" +#include "radio.h" +#include "sound_menu.h" +#include "viewport.h" +#include "fat.h" +#include "backlight.h" + +#ifdef HAVE_RECORDING +/* This array holds the record timer interval lengths, in seconds */ +static const unsigned long rec_timer_seconds[] = +{ + 0, /* 0 means OFF */ + 5*60, /* 00:05 */ + 10*60, /* 00:10 */ + 15*60, /* 00:15 */ + 30*60, /* 00:30 */ + 60*60, /* 01:00 */ + 74*60, /* 74:00 */ + 80*60, /* 80:00 */ + 2*60*60, /* 02:00 */ + 4*60*60, /* 04:00 */ + 6*60*60, /* 06:00 */ + 8*60*60, /* 08:00 */ + 10L*60*60, /* 10:00 */ + 12L*60*60, /* 12:00 */ + 18L*60*60, /* 18:00 */ + 24L*60*60 /* 24:00 */ +}; + +static unsigned int rec_timesplit_seconds(void) +{ + return rec_timer_seconds[global_settings.rec_timesplit]; +} + +/* This array holds the record size interval lengths, in bytes */ +static const unsigned long rec_size_bytes[] = +{ + 0, /* 0 means OFF */ + 5*1024*1024, /* 5MB */ + 10*1024*1024, /* 10MB */ + 15*1024*1024, /* 15MB */ + 32*1024*1024, /* 32MB */ + 64*1024*1024, /* 64MB */ + 75*1024*1024, /* 75MB */ + 100*1024*1024, /* 100MB */ + 128*1024*1024, /* 128MB */ + 256*1024*1024, /* 256MB */ + 512*1024*1024, /* 512MB */ + 650*1024*1024, /* 650MB */ + 700*1024*1024, /* 700MB */ + 1024*1024*1024, /* 1GB */ + 1536*1024*1024, /* 1.5GB */ + 1792*1024*1024, /* 1.75GB */ +}; + +static unsigned long rec_sizesplit_bytes(void) +{ + return rec_size_bytes[global_settings.rec_sizesplit]; +} + +void settings_apply_trigger(void) +{ + int start_thres, stop_thres; + if (global_settings.peak_meter_dbfs) + { + start_thres = global_settings.rec_start_thres_db - 1; + stop_thres = global_settings.rec_stop_thres_db - 1; + } + else + { + start_thres = global_settings.rec_start_thres_linear; + stop_thres = global_settings.rec_stop_thres_linear; + } + + peak_meter_define_trigger( + start_thres, + global_settings.rec_start_duration*HZ, + MIN(global_settings.rec_start_duration*HZ / 2, 2*HZ), + stop_thres, + global_settings.rec_stop_postrec*HZ, + global_settings.rec_stop_gap*HZ + ); +} +/* recording screen status flags */ +enum rec_status_flags +{ + RCSTAT_IN_RECSCREEN = 0x00000001, + RCSTAT_BEEN_IN_USB_MODE = 0x00000002, + RCSTAT_CREATED_DIRECTORY = 0x00000004, + RCSTAT_HAVE_RECORDED = 0x00000008, +}; + +static int rec_status = 0; + +bool in_recording_screen(void) +{ + return (rec_status & RCSTAT_IN_RECSCREEN) != 0; +} + +static struct timer timer; + +#if CONFIG_KEYPAD == RECORDER_PAD +static bool f2_rec_screen(void); +static bool f3_rec_screen(void); +#endif + +#if defined(HAVE_LCD_BITMAP) && (LCD_HEIGHT > 111) && defined(HAVE_AGC) +#define HAVE_HISTOGRAM /* only for bigger screens */ +#endif + +#define MAX_FILE_SIZE 0x7F800000 /* 2 GB - 4 MB */ +#define MIN_DISK_SPACE 48 /* minimum remaining disk space */ +unsigned long disk_space = 0; + +#ifndef HAVE_REMOTE_LCD +static const int screen_update = NB_SCREENS; +#else +static int screen_update = NB_SCREENS; +static bool remote_display_on = true; +#endif + +/** File name creation **/ +#if CONFIG_RTC == 0 +/* current file number to assist in creating unique numbered filenames + without actually having to create the file on disk */ +static int file_number = -1; +#endif /* CONFIG_RTC */ + +#if CONFIG_CODEC == SWCODEC + +#define REC_FILE_ENDING(rec_format) \ + (audio_formats[rec_format_afmt[rec_format]].ext_list) + +#else /* CONFIG_CODEC != SWCODEC */ + +/* default record file extension for HWCODEC */ +#define REC_FILE_ENDING(rec_format) \ + (audio_formats[AFMT_MPA_L3].ext_list) + +#endif /* CONFIG_CODEC == SWCODEC */ + +/* path for current file */ +static char path_buffer[MAX_PATH]; + +/** Automatic Gain Control (AGC) **/ +#ifdef HAVE_AGC +/* Timing counters: + * peak_time is incremented every 0.2s, every 2nd run of record screen loop. + * hist_time is incremented every 0.5s, display update. + * peak_time is the counter of the peak hold read and agc process, + * overflow every 13 years 8-) + */ + +static long peak_time = 0; +static short peak_valid_mem[4]; +static long hist_time = 0; + +#define BAL_MEM_SIZE 24 +static short balance_mem[BAL_MEM_SIZE]; + +/* Automatic Gain Control */ +#define AGC_MODE_SIZE 5 +#define AGC_SAFETY_MODE 0 + +static const char* agc_preset_str[] = +{ "Off", "S", "L", "D", "M", "V" }; +/* "Off", + "Safety (clip)", + "Live (slow)", + "DJ-Set (slow)", + "Medium", + "Voice (fast)" */ +#define AGC_CLIP 32766 +#define AGC_PEAK 29883 /* fast gain reduction threshold -0.8dB */ +#define AGC_HIGH 27254 /* accelerated gain reduction threshold -1.6dB */ +#define AGC_IMG 823 /* threshold for balance control -32dB */ +/* autogain high level thresholds (-3dB, -7dB, -4dB, -5dB, -5dB) */ +static const short agc_th_hi[AGC_MODE_SIZE] = +{ 23197, 14637, 21156, 18428, 18426 }; +/* autogain low level thresholds (-14dB, -11dB, -6dB, -7dB, -8dB) */ +static const short agc_th_lo[AGC_MODE_SIZE] = +{ 6538, 9235, 16422, 14636, 13045 }; +/* autogain threshold times [1/5s] or [200ms] */ +static const short agc_tdrop[AGC_MODE_SIZE] = +{ 900, 225, 150, 60, 8 }; +static const short agc_trise[AGC_MODE_SIZE] = +{ 9000, 750, 400, 150, 20 }; +static const short agc_tbal[AGC_MODE_SIZE] = +{ 4500, 500, 300, 100, 15 }; +/* AGC operation */ +static bool agc_enable = true; +static short agc_preset; +/* AGC levels */ +static int agc_left = 0; +static int agc_right = 0; +/* AGC time since high target volume was exceeded */ +static short agc_droptime = 0; +/* AGC time since volume fallen below low target */ +static short agc_risetime = 0; +/* AGC balance time exceeding +/- 0.7dB */ +static short agc_baltime = 0; +/* AGC maximum gain */ +static short agc_maxgain; +#endif /* HAVE_AGC */ + +/* Histogram data, only for bigger screens */ +#ifdef HAVE_HISTOGRAM +#define HIST_Y (LCD_HEIGHT - 1) +#define HIST_W (LCD_WIDTH / 2 - 4) +static short history_mode; +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]; +#if LCD_DEPTH > 1 +#ifdef HAVE_LCD_COLOR +#define LCD_BATT_OK LCD_RGBPACK(63, 63, 63) +#define LCD_BATT_LO LCD_RGBPACK(159, 0, 0) +#define LCD_DISK_OK LCD_RGBPACK(0, 0, 143) +#define LCD_DISK_LO LCD_RGBPACK(127, 0, 0) +#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 +#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 +#else +#define LCD_HIST_OVER LCD_DEFAULT_FG +#define LCD_HIST_OK LCD_DEFAULT_FG +#define LCD_BAL LCD_DEFAULT_FG +#endif +#endif /* HAVE_HISTOGRAM */ + +static void set_gain(void) +{ + if(global_settings.rec_source == AUDIO_SRC_MIC) + { + audio_set_recording_gain(global_settings.rec_mic_gain, + 0, AUDIO_GAIN_MIC); + } + else + { + /* AUDIO_SRC_LINEIN, AUDIO_SRC_FMRADIO, AUDIO_SRC_SPDIF */ + audio_set_recording_gain(global_settings.rec_left_gain, + global_settings.rec_right_gain, + AUDIO_GAIN_LINEIN); + } + /* reset the clipping indicators */ + peak_meter_set_clip_hold(global_settings.peak_meter_clip_hold); +} + +#ifdef HAVE_AGC +/* Read peak meter values & calculate balance. + * Returns validity of peak values. + * Used for automatic gain control and history diagram. + */ +static bool read_peak_levels(int *peak_l, int *peak_r, int *balance) +{ + peak_meter_get_peakhold(peak_l, peak_r); + peak_valid_mem[peak_time % 3] = *peak_l; + if (((peak_valid_mem[0] == peak_valid_mem[1]) && + (peak_valid_mem[1] == peak_valid_mem[2])) && + ((*peak_l < 32767) || ata_disk_is_active())) + return false; + + if (*peak_r > *peak_l) + balance_mem[peak_time % BAL_MEM_SIZE] = (*peak_l ? + MIN((10000 * *peak_r) / *peak_l - 10000, 15118) : 15118); + else + balance_mem[peak_time % BAL_MEM_SIZE] = (*peak_r ? + MAX(10000 - (10000 * *peak_l) / *peak_r, -15118) : -15118); + *balance = 0; + int i; + for (i = 0; i < BAL_MEM_SIZE; i++) + *balance += balance_mem[i]; + *balance = *balance / BAL_MEM_SIZE; +#ifdef HAVE_HISTOGRAM + if (*peak_l > hist_l) + hist_l = *peak_l; + if (*peak_r > hist_r) + hist_r = *peak_r; +#endif + + return true; +} + +/* AGC helper function to check if maximum gain is reached */ +static bool agc_gain_is_max(bool left, bool right) +{ + /* range -128...+108 [0.5dB] */ + short gain_current_l; + short gain_current_r; + + if (agc_preset == 0) + return false; + + switch (global_settings.rec_source) + { + HAVE_LINE_REC_(case AUDIO_SRC_LINEIN:) + HAVE_FMRADIO_REC_(case AUDIO_SRC_FMRADIO:) + gain_current_l = global_settings.rec_left_gain; + gain_current_r = global_settings.rec_right_gain; + break; + case AUDIO_SRC_MIC: + default: + gain_current_l = global_settings.rec_mic_gain; + gain_current_r = global_settings.rec_mic_gain; + } + + return ((left && (gain_current_l >= agc_maxgain)) || + (right && (gain_current_r >= agc_maxgain))); +} + +static void change_recording_gain(bool increment, bool left, bool right) +{ + int factor = (increment ? 1 : -1); + + switch (global_settings.rec_source) + { + HAVE_LINE_REC_(case AUDIO_SRC_LINEIN:) + HAVE_FMRADIO_REC_(case AUDIO_SRC_FMRADIO:) + if (left) global_settings.rec_left_gain += factor; + if (right) global_settings.rec_right_gain += factor; + break; + case AUDIO_SRC_MIC: + global_settings.rec_mic_gain += factor; + } +} + +/* + * Handle automatic gain control (AGC). + * Change recording gain if peak_x levels are above or below + * target volume for specified timeouts. + */ +static void auto_gain_control(int *peak_l, int *peak_r, int *balance) +{ + int agc_mono; + short agc_mode; + bool increment; + + if (*peak_l > agc_left) + agc_left = *peak_l; + else + agc_left -= (agc_left - *peak_l + 3) >> 2; + if (*peak_r > agc_right) + agc_right = *peak_r; + else + agc_right -= (agc_right - *peak_r + 3) >> 2; + agc_mono = (agc_left + agc_right) / 2; + + agc_mode = abs(agc_preset) - 1; + if (agc_mode < 0) { + agc_enable = false; + return; + } + + if (agc_mode != AGC_SAFETY_MODE) { + /* Automatic balance control - only if not in safety mode */ + if ((agc_left > AGC_IMG) && (agc_right > AGC_IMG)) + { + if (*balance < -556) + { + if (*balance > -900) + agc_baltime -= !(peak_time % 4); /* 0.47 - 0.75dB */ + else if (*balance > -4125) + agc_baltime--; /* 0.75 - 3.00dB */ + else if (*balance > -7579) + agc_baltime -= 2; /* 3.00 - 4.90dB */ + else + agc_baltime -= !(peak_time % 8); /* 4.90 - inf dB */ + if (agc_baltime > 0) + agc_baltime -= (peak_time % 2); + } + else if (*balance > 556) + { + if (*balance < 900) + agc_baltime += !(peak_time % 4); + else if (*balance < 4125) + agc_baltime++; + else if (*balance < 7579) + agc_baltime += 2; + else + agc_baltime += !(peak_time % 8); + if (agc_baltime < 0) + agc_baltime += (peak_time % 2); + } + + if ((*balance * agc_baltime) < 0) + { + if (*balance < 0) + agc_baltime -= peak_time % 2; + else + agc_baltime += peak_time % 2; + } + + increment = ((agc_risetime / 2) > agc_droptime); + + if (agc_baltime < -agc_tbal[agc_mode]) + { + if (!increment || !agc_gain_is_max(!increment, increment)) { + change_recording_gain(increment, !increment, increment); + set_gain(); + } + agc_baltime = 0; + } + else if (agc_baltime > +agc_tbal[agc_mode]) + { + if (!increment || !agc_gain_is_max(increment, !increment)) { + change_recording_gain(increment, increment, !increment); + set_gain(); + } + agc_baltime = 0; + } + } + else if (!(hist_time % 4)) + { + if (agc_baltime < 0) + agc_baltime++; + else + agc_baltime--; + } + } + + /* Automatic gain control */ + if ((agc_left > agc_th_hi[agc_mode]) || (agc_right > agc_th_hi[agc_mode])) + { + if ((agc_left > AGC_CLIP) || (agc_right > AGC_CLIP)) + agc_droptime += agc_tdrop[agc_mode] / + (global_settings.rec_agc_cliptime + 1); + if (agc_left > AGC_HIGH) { + agc_droptime++; + agc_risetime=0; + if (agc_left > AGC_PEAK) + agc_droptime += 2; + } + if (agc_right > AGC_HIGH) { + agc_droptime++; + agc_risetime=0; + if (agc_right > AGC_PEAK) + agc_droptime += 2; + } + if (agc_mono > agc_th_hi[agc_mode]) + agc_droptime++; + else + agc_droptime += !(peak_time % 2); + + if (agc_droptime >= agc_tdrop[agc_mode]) + { + change_recording_gain(false, true, true); + agc_droptime = 0; + agc_risetime = 0; + set_gain(); + } + agc_risetime = MAX(agc_risetime - 1, 0); + } + else if (agc_mono < agc_th_lo[agc_mode]) + { + if (agc_mono < (agc_th_lo[agc_mode] / 8)) + agc_risetime += !(peak_time % 5); + else if (agc_mono < (agc_th_lo[agc_mode] / 2)) + agc_risetime += 2; + else + agc_risetime++; + + if (agc_risetime >= agc_trise[agc_mode]) { + if ((agc_mode != AGC_SAFETY_MODE) && + (!agc_gain_is_max(true, true))) { + change_recording_gain(true, true, true); + set_gain(); + } + agc_risetime = 0; + agc_droptime = 0; + } + agc_droptime = MAX(agc_droptime - 1, 0); + } + else if (!(peak_time % 6)) /* on target level every 1.2 sec */ + { + agc_risetime = MAX(agc_risetime - 1, 0); + agc_droptime = MAX(agc_droptime - 1, 0); + } +} +#endif /* HAVE_AGC */ + +static const char* const fmtstr[] = +{ + "%c%d %s", /* no decimals */ + "%c%d.%d %s ", /* 1 decimal */ + "%c%d.%02d %s " /* 2 decimals */ +}; + +static char *fmt_gain(int snd, int val, char *str, int len) +{ + int i, d, numdec; + const char *unit; + char sign = ' '; + + val = sound_val2phys(snd, val); + if(val < 0) + { + sign = '-'; + val = -val; + } + numdec = sound_numdecimals(snd); + unit = sound_unit(snd); + + if(numdec) + { + i = val / (10*numdec); + d = val % (10*numdec); + snprintf(str, len, fmtstr[numdec], sign, i, d, unit); + } + else + snprintf(str, len, fmtstr[numdec], sign, val, unit); + + return str; +} + +static int cursor; + +static void adjust_cursor(void) +{ + int max_cursor; + + if(cursor < 0) { + cursor = 0; +#ifdef HAVE_HISTOGRAM + int i; + history_mode++; + if (history_mode == 2) { + for (i=0; i < HIST_W; i++) { + history_l[i] = history_l[i] * 2; + history_r[i] = history_r[i] * 2; + } + } else if (history_mode == 4) { + for (i=0; i < HIST_W; i++) { + history_l[i] = history_l[i] / 2; + history_r[i] = history_r[i] / 2; + } + history_mode = 0; + } +#endif + } + +#ifdef HAVE_AGC + switch(global_settings.rec_source) + { + case REC_SRC_MIC: + if(cursor == 2) + cursor = 4; + else if(cursor == 3) + cursor = 1; + HAVE_LINE_REC_(case AUDIO_SRC_LINEIN:) + HAVE_FMRADIO_REC_(case AUDIO_SRC_FMRADIO:) + max_cursor = 5; + break; + default: + max_cursor = 0; + break; + } +#else /* !HAVE_AGC */ + switch(global_settings.rec_source) + { + case AUDIO_SRC_MIC: + max_cursor = 1; + break; + HAVE_LINE_REC_(case AUDIO_SRC_LINEIN:) + HAVE_FMRADIO_REC_(case AUDIO_SRC_FMRADIO:) + max_cursor = 3; + break; + default: + max_cursor = 0; + break; + } +#endif /* HAVE_AGC */ + + if(cursor > max_cursor) + cursor = max_cursor; +} + +/* the list below must match enum audio_sources in audio.h */ +static const char* const prestr[] = +{ + HAVE_MIC_IN_([AUDIO_SRC_MIC] = "R_MIC_",) + HAVE_LINE_REC_([AUDIO_SRC_LINEIN] = "R_LINE_",) + HAVE_SPDIF_IN_([AUDIO_SRC_SPDIF] = "R_SPDIF_",) + HAVE_FMRADIO_REC_([AUDIO_SRC_FMRADIO] = "R_FM_",) +}; + +char *rec_create_filename(char *buffer) +{ + char ext[16]; + const char *pref = "R_"; + + /* Directory existence and writeablility should have already been + * verified - do not pass NULL pointers to pcmrec */ + + if((unsigned)global_settings.rec_source < AUDIO_NUM_SOURCES) + { + pref = prestr[global_settings.rec_source]; + } + + strcpy(buffer, global_settings.rec_directory); + + snprintf(ext, sizeof(ext), ".%s", + REC_FILE_ENDING(global_settings.rec_format)); + +#if CONFIG_RTC == 0 + return create_numbered_filename(buffer, buffer, pref, ext, 4, + &file_number); +#else + /* We'll wait at least up to the start of the next second so no duplicate + names are created */ + return create_datetime_filename(buffer, buffer, pref, ext, true); +#endif +} + +#if CONFIG_RTC == 0 +/* Hit disk to get a starting filename for the type */ +static void rec_init_filename(void) +{ + file_number = -1; + rec_create_filename(path_buffer); + file_number--; +} +#endif + +int rec_create_directory(void) +{ + int rc = 0; + const char * const folder = global_settings.rec_directory; + + if (strcmp(folder, "/") && !dir_exists(folder)) + { + rc = mkdir(folder); + + if(rc < 0) + { + while (action_userabort(HZ) == false) + { + gui_syncsplash(0, "%s %s", + str(LANG_REC_DIR_NOT_WRITABLE), + str(LANG_OFF_ABORT)); + } + } + else + { + rec_status |= RCSTAT_CREATED_DIRECTORY; + rc = 1; + } + } + + return rc; +} + +void rec_init_recording_options(struct audio_recording_options *options) +{ + options->rec_source = global_settings.rec_source; + options->rec_frequency = global_settings.rec_frequency; + options->rec_channels = global_settings.rec_channels; + options->rec_prerecord_time = global_settings.rec_prerecord_time; +#if CONFIG_CODEC == SWCODEC + options->rec_source_flags = 0; + options->enc_config.rec_format = global_settings.rec_format; + global_to_encoder_config(&options->enc_config); +#else + options->rec_quality = global_settings.rec_quality; + options->rec_editable = global_settings.rec_editable; +#endif +} + +#if CONFIG_CODEC == SWCODEC && !defined (SIMULATOR) +void rec_set_source(int source, unsigned flags) +{ + /* Set audio input source, power up/down devices */ + audio_set_input_source(source, flags); + + /* Set peakmeters for recording or reset to playback */ + peak_meter_playback((flags & SRCF_RECORDING) == 0); + peak_meter_enabled = true; +} +#endif /* CONFIG_CODEC == SWCODEC && !defined (SIMULATOR) */ + +void rec_set_recording_options(struct audio_recording_options *options) +{ +#if CONFIG_CODEC != SWCODEC + if (global_settings.rec_prerecord_time) + { + talk_buffer_steal(); /* will use the mp3 buffer */ + } +#else /* == SWCODEC */ + rec_set_source(options->rec_source, + options->rec_source_flags | SRCF_RECORDING); +#endif /* CONFIG_CODEC != SWCODEC */ + + audio_set_recording_options(options); +} + +void rec_command(enum recording_command cmd) +{ + switch(cmd) + { + case RECORDING_CMD_STOP_SHUTDOWN: + pm_activate_clipcount(false); + audio_stop_recording(); +#if CONFIG_CODEC == SWCODEC + audio_close_recording(); +#endif + sys_poweroff(); + break; + case RECORDING_CMD_STOP: + pm_activate_clipcount(false); + audio_stop_recording(); + break; + case RECORDING_CMD_START: + /* steal mp3 buffer, create unique filename and start recording */ + pm_reset_clipcount(); + pm_activate_clipcount(true); +#if CONFIG_CODEC != SWCODEC + talk_buffer_steal(); /* we use the mp3 buffer */ +#endif + audio_record(rec_create_filename(path_buffer)); + break; + case RECORDING_CMD_START_NEWFILE: + /* create unique filename and start recording*/ + pm_reset_clipcount(); + pm_activate_clipcount(true); /* just to be sure */ + audio_new_file(rec_create_filename(path_buffer)); + break; + case RECORDING_CMD_PAUSE: + pm_activate_clipcount(false); + audio_pause_recording(); + break; + case RECORDING_CMD_RESUME: + pm_activate_clipcount(true); + audio_resume_recording(); + break; + } +} + +/* used in trigger_listerner and recording_screen */ +static unsigned int last_seconds = 0; + +/** + * Callback function so that the peak meter code can send an event + * to this application. This function can be passed to + * peak_meter_set_trigger_listener in order to activate the trigger. + */ +static void trigger_listener(int trigger_status) +{ + switch (trigger_status) + { + case TRIG_GO: + if(!(audio_status() & AUDIO_STATUS_RECORD)) + { + rec_status |= RCSTAT_HAVE_RECORDED; + rec_command(RECORDING_CMD_START); +#if CONFIG_CODEC != SWCODEC + /* give control to mpeg thread so that it can start + recording */ + yield(); yield(); yield(); +#endif + } + + /* if we're already recording this is a retrigger */ + else + { + if((audio_status() & AUDIO_STATUS_PAUSE) && + (global_settings.rec_trigger_type == TRIG_TYPE_PAUSE)) + { + rec_command(RECORDING_CMD_RESUME); + } + /* New file on trig start*/ + else if (global_settings.rec_trigger_type != TRIG_TYPE_NEW_FILE) + { + rec_command(RECORDING_CMD_START_NEWFILE); + /* tell recording_screen to reset the time */ + last_seconds = 0; + } + } + break; + + /* A _change_ to TRIG_READY means the current recording has stopped */ + case TRIG_READY: + if(audio_status() & AUDIO_STATUS_RECORD) + { + switch(global_settings.rec_trigger_type) + { + case TRIG_TYPE_STOP: /* Stop */ + rec_command(RECORDING_CMD_STOP); + break; + + case TRIG_TYPE_PAUSE: /* Pause */ + rec_command(RECORDING_CMD_PAUSE); + break; + + case TRIG_TYPE_NEW_FILE: /* New file on trig stop*/ + rec_command(RECORDING_CMD_START_NEWFILE); + /* tell recording_screen to reset the time */ + last_seconds = 0; + break; + + case 3: /* Stop and shutdown */ + rec_command(RECORDING_CMD_STOP_SHUTDOWN); + break; + } + + if (global_settings.rec_trigger_mode != TRIG_MODE_REARM) + { + peak_meter_set_trigger_listener(NULL); + peak_meter_trigger(false); + } + } + break; + } +} + +/* countdown timer tick task */ +void timer_tick_task(void) +{ + static int mini_tick = 0; + + mini_tick ++; + /* the countdown */ + if ((mini_tick >= HZ) && (timer.countdown)) + { + mini_tick = 0; + if (timer.secs) timer.secs -= 1; + else{ + timer.secs = 59; + if (timer.mins) timer.mins -= 1; + else{ + timer.mins = 59; + if (timer.hrs) timer.hrs -= 1; + else{ + timer.hrs = 23; + if (timer.days) timer.days -= 1; + else{ + timer.days = timer.hrs = timer.mins = timer.secs = 0; + /* switch timer display on/off when countdown finished */ + timer.timer_display = !timer.timer_display; + } + } + } + } + } +} + +bool recording_start_automatic = false; + +bool recording_screen(bool no_source) +{ + long button; + bool done = false; + char buf[32]; + char buf2[32]; + int w[NB_SCREENS], h[NB_SCREENS]; + int font[NB_SCREENS]; + int pm_h[NB_SCREENS]; + int update_countdown = 1; +#ifndef SIMULATOR + bool disk_was_active = false; + bool warn_message = true; +#endif + unsigned long disk_free; + int bitrate; + int disk_time = 0; + unsigned int seconds, prerec = 0; + int hours, minutes; + char filename[13]; + int last_audio_stat = -1; + int audio_stat; +#if CONFIG_CODEC == SWCODEC + int warning_counter = 0; + #define WARNING_PERIOD 7 +#endif +#ifdef HAVE_FMRADIO_REC + /* Radio is left on if: + * 1) Is was on at the start and the initial source is FM Radio + * 2) 1) and the source was never changed to something else + */ + int radio_status = (global_settings.rec_source != AUDIO_SRC_FMRADIO) ? + FMRADIO_OFF : get_radio_status(); +#endif +#if (CONFIG_LED == LED_REAL) + bool led_state = false; + int led_countdown = 2; +#endif +#ifdef HAVE_AGC + bool peak_valid = false; + int balance = 0; + bool peak_read = false; + int peak_l, peak_r; + bool display_agc[NB_SCREENS]; +#endif + int line[NB_SCREENS]; + int i; + int filename_offset[NB_SCREENS]; + int pm_y[NB_SCREENS]; + int trig_xpos[NB_SCREENS]; + int trig_ypos[NB_SCREENS]; + int trig_width[NB_SCREENS]; + /* pm_x = offset pm to put clipcount in front. + Use lcd_getstringsize() when not using SYSFONT */ + int pm_x = global_settings.peak_meter_clipcounter ? 30 : 0; + int agc_line = 0; + bool histogram_on = global_settings.hist_def; + bool font_check = true; + int pm_height[NB_SCREENS]; + int countdown_offset = 0; + bool repeat_timer_start = false; + unsigned int repeat_timer; + + static const unsigned char *byte_units[] = { + ID2P(LANG_BYTE), + ID2P(LANG_KILOBYTE), + ID2P(LANG_MEGABYTE), + ID2P(LANG_GIGABYTE) + }; + + int base_style = STYLE_INVERT; + int style; + struct viewport vp[NB_SCREENS]; + int ymargin = global_settings.cursor_style?0:10; +#ifdef HAVE_LCD_COLOR + if (global_settings.cursor_style == 2) { + base_style |= STYLE_COLORBAR; + } + else if (global_settings.cursor_style == 3) { + base_style |= STYLE_GRADIENT; + } +#endif + + struct audio_recording_options rec_options; + rec_status = RCSTAT_IN_RECSCREEN; + + if (rec_create_directory() < 0) + { + rec_status = 0; + return false; + } + + /* Stop countdown if countdown settings changed */ + if (!timer.countdown) + tick_remove_task(timer_tick_task); + +#ifdef HAVE_AGC + memset(balance_mem, 0x00, BAL_MEM_SIZE); +#endif + +#ifdef HAVE_HISTOGRAM + int history_pos = 0; + int hist_height; + const short hist_size_h[2] = {17, 31}; + /* + * Peak histogram linear to logarithmic [dB] table. + * The thresholds are scaled between the corresponding + * dispayed values, e.g. -6dB is -5.5dB < level <= 6.5dB + */ + const short hist_peak_lin2dB[2][31] = + { + /* 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 }, + /* 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[4][6] = + { + /* linear: 0, -6, -12, -24, -inf [dB] */ + { 15, 8, 4, 1, 0, 0}, + /* logarithmic: 0, -6, -12, -24, -48 [dB] */ + { 15, 12, 9, 4, 1, 1}, + /* linear: 0, -3, -6, -12, -24, -inf [dB] */ + { 29, 21, 15, 7, 2, 0}, + /* logarithmic: 0, -3, -6, -12, -24, -48 [dB] */ + { 29, 26, 23, 17, 9, 2} + }; + 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 unsigned char rec_icons_6x8[][6] = + { + {0x00,0x1c,0x3e,0x36,0x3e,0x1c} + }; + enum icons_6x8 + { + Icon_Disk, + Icon_6x8end + }; + + memset(history_l, 0x00, sizeof(history_l)); + memset(history_r, 0x00, sizeof(history_r)); +#endif /* HAVE_HISTOGRAM */ + + cursor = 0; +#if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR) + ata_set_led_enabled(false); +#endif + +#if CONFIG_CODEC == SWCODEC + /* recording_menu gets messed up: so prevent manus talking */ + talk_disable(true); + /* audio_init_recording stops anything playing when it takes the audio + buffer */ +#else + /* Yes, we use the D/A for monitoring */ + peak_meter_enabled = true; + peak_meter_playback(true); +#endif + gui_syncsplash(1, "%s...", str(LANG_RECORDING)); + audio_init_recording(0); + sound_set_volume(global_settings.volume); + +#ifdef HAVE_AGC + peak_meter_get_peakhold(&peak_l, &peak_r); +#endif + + rec_init_recording_options(&rec_options); + rec_set_recording_options(&rec_options); + + set_gain(); + +#if CONFIG_RTC == 0 + /* Create new filename for recording start */ + rec_init_filename(); +#endif + + pm_reset_clipcount(); + pm_activate_clipcount(false); + settings_apply_trigger(); + +#ifdef HAVE_AGC + agc_preset_str[0] = str(LANG_SYSFONT_OFF); + agc_preset_str[1] = str(LANG_SYSFONT_AGC_SAFETY); + agc_preset_str[2] = str(LANG_SYSFONT_AGC_LIVE); + agc_preset_str[3] = str(LANG_SYSFONT_AGC_DJSET); + agc_preset_str[4] = str(LANG_SYSFONT_AGC_MEDIUM); + agc_preset_str[5] = str(LANG_SYSFONT_AGC_VOICE); + if (global_settings.rec_source == AUDIO_SRC_MIC) { + agc_preset = global_settings.rec_agc_preset_mic; + agc_maxgain = global_settings.rec_agc_maxgain_mic; + } + else { + agc_preset = global_settings.rec_agc_preset_line; + agc_maxgain = global_settings.rec_agc_maxgain_line; + } +#endif /* HAVE_AGC */ +/* + FOR_NB_SCREENS(i) + { + viewport_set_defaults(&vp[i], i); + vp[i].font = FONT_SYSFIXED; + screens[i].set_viewport(&vp[i]); + screens[i].setfont(FONT_SYSFIXED); + screens[i].getstringsize("M", &w, &h); + filename_offset[i] = ((vp[i].height >= 7*h) ? 1 : 0); + pm_y[i] = h * (2 + filename_offset[i]); + } +*/ +#ifdef HAVE_REMOTE_LCD + if (!remote_display_on) + { + screens[1].clear_display(); + snprintf(buf, sizeof(buf), str(LANG_REMOTE_LCD_ON)); +// screens[1].puts((vp[1].width/w - strlen(buf))/2 + 1, +// vp[1].height/(h*2) + 1, buf); + screens[1].puts((vp[1].width/w[1] - strlen(buf))/2 + 1, + vp[1].height/(h[1]*2) + 1, buf); + screens[1].update(); + gui_syncsplash(0, str(LANG_REMOTE_LCD_OFF)); + } +#endif + + /* store the free disk space for this session [MBytes] */ + fat_size(IF_MV2(0,) NULL, &disk_free); /* free KBytes */ + disk_free = disk_free / 1024; + if (disk_free > disk_space) + disk_space = disk_free; + bitrate = 1411; /* [kbps] default for 44kHz stereo 16bit WAV */ + +#ifdef HAVE_HISTOGRAM + history_mode = global_settings.rec_histogram_mode; + hist_time_interval = 1 << global_settings.rec_histogram_interval; +#endif + + while(!done) + { + switch(global_settings.rec_source) + { + case AUDIO_SRC_LINEIN: +#ifdef HAVE_FMRADIO_IN + case AUDIO_SRC_FMRADIO: +#endif + FOR_NB_SCREENS(i) + line[i] = 5; + agc_line = 1; + break; + case AUDIO_SRC_MIC: + FOR_NB_SCREENS(i) + line[i] = 4; + agc_line = 1; + break; +#ifdef HAVE_SPDIF_IN + case AUDIO_SRC_SPDIF: + FOR_NB_SCREENS(i) + line[i] = 3; + agc_line = 0; /* no agc line for Spdif in */ + break; +#endif + default: + FOR_NB_SCREENS(i) + line[i] = 5; + break; + } + /* check and change font only if source has been changed */ + if (font_check) + { + FOR_NB_SCREENS(i) + pm_height[i] = global_settings.peak_size + 1; + + FOR_NB_SCREENS(i) + { +//check +// filename_offset[i] = ((screens[i].height >= 80) ? 1 : 0); + filename_offset[i] = ((vp[i].height >= 80) ? 1 : 0); + + while(vp[i].height < (line[i] + 1 + filename_offset[i] + pm_height[i]) * 8) + { + pm_height[i] -= 1; + if (pm_height[i] < 1) + { pm_height[i] = 1; + break; + } + } + + screens[i].setfont(FONT_UI); + screens[i].getstringsize("M", &w[i], &h[i]); + + if (i == SCREEN_MAIN) { + if (h[i] <= ((LCD_HEIGHT - (histogram_on ? 25 : 8)) / (line[i] + + filename_offset[0] + pm_height[i] + agc_line))) + font[i] = FONT_UI; + else + font[i] = FONT_SYSFIXED; + } + else if (h[i] <= ((vp[i].height - 8) / (line[i] + filename_offset[i] + pm_height[i]))) + font[i] = FONT_UI; + else + font[i] = FONT_SYSFIXED; + + screens[i].setfont(font[i]); + screens[i].getstringsize("M", &w[i], &h[i]); +// screens[i].setmargins(global_settings.invert_cursor ? 0 : w[i], 8); + if (h[i] > 8) { + pm_y[i] = 9 + h[i] * (2 + filename_offset[i]); + pm_h[i] = (h[i] - 1) * pm_height[i]; + } + else { + pm_y[i] = 8 + h[i] * (2 + filename_offset[i]); + pm_h[i] = h[i] * pm_height[i]; + } + } + font_check = false; + } + + + audio_stat = audio_status(); + +#if (CONFIG_LED == LED_REAL) + + /* + * Flash the LED while waiting to record. Turn it on while + * recording. + */ + if(audio_stat & AUDIO_STATUS_RECORD) + { + if (audio_stat & AUDIO_STATUS_PAUSE) + { + if (--led_countdown <= 0) + { + led_state = !led_state; + led(led_state); + led_countdown = 2; + } + } + else + { + /* trigger is on in status TRIG_READY (no check needed) */ + led(true); + } + } + else + { + int trigStat = peak_meter_trigger_status(); + /* + * other trigger stati than trig_off and trig_steady + * already imply that we are recording. + */ + if (trigStat == TRIG_STEADY) + { + if (--led_countdown <= 0) + { + led_state = !led_state; + led(led_state); + led_countdown = 2; + } + } + else + { + /* trigger is on in status TRIG_READY (no check needed) */ + led(false); + } + } +#endif /* CONFIG_LED */ + + /* Wait for a button a while (HZ/10) drawing the peak meter */ + button = peak_meter_draw_get_btn(CONTEXT_RECSCREEN, + pm_x, pm_y, pm_h, +// pm_x, pm_y, 8, + screen_update); +// button = peak_meter_draw_get_btn(0, pm_y, pm_h, h[i] * pm_height[i], screen_update); + if (last_audio_stat != audio_stat) + { + if (audio_stat & AUDIO_STATUS_RECORD) + { + rec_status |= RCSTAT_HAVE_RECORDED; + } + last_audio_stat = audio_stat; + } + + if (recording_start_automatic) + { + /* simulate a button press */ + button = ACTION_REC_PAUSE; + recording_start_automatic = false; + } + + /* repeat_timer is the repeat time in seconds */ + repeat_timer = (timer.mins_rpt * 60 + timer.hrs_rpt * + 3600 + timer.days_rpt * 3600 * 24); + + /* decide on repeat timer status */ + if ((repeat_timer > rec_timesplit_seconds()) && + global_settings.rec_timesplit) + timer.repeater = true; + else + timer.repeater = false; + + /* When countdown timer reaches zero fake a new file button press */ + if (timer.countdown && !timer.days && !timer.hrs && !timer.mins && + !timer.secs) + { + tick_remove_task(timer_tick_task); + button = ACTION_REC_NEWFILE; + timer.countdown = false; + } + + switch(button) + { +#ifdef HAVE_REMOTE_LCD + case ACTION_REC_HIST_TOGGLE: + histogram_on = !histogram_on; + font_check = true; + break; + case ACTION_REC_LCD: + if (remote_display_on) + { + remote_display_on = false; + screen_update = 1; + screens[1].clear_display(); + snprintf(buf, sizeof(buf), str(LANG_REMOTE_LCD_ON)); +// screens[1].puts((screens[1].getwidth()/w - strlen(buf))/2 + +// 1, +// screens[1].getheight()/(h*2) + 1, buf); + screens[1].puts((screens[1].getwidth()/w[1] - strlen(buf))/2 + 1, + screens[1].getheight()/(h[1]*2) + 1, buf); + screens[1].update(); + gui_syncsplash(0, str(LANG_REMOTE_LCD_OFF)); + } + else + { + remote_display_on = true; + screen_update = NB_SCREENS; + } + break; +#endif + case ACTION_STD_CANCEL: + /* turn off the trigger */ + peak_meter_trigger(false); + peak_meter_set_trigger_listener(NULL); + + if(audio_stat & AUDIO_STATUS_RECORD) + { + rec_command(RECORDING_CMD_STOP); + } + else + { +#if CONFIG_CODEC != SWCODEC + peak_meter_playback(true); + peak_meter_enabled = false; +#endif + done = true; + } + update_countdown = 1; /* Update immediately */ + break; + + case ACTION_REC_PAUSE: + case ACTION_REC_NEWFILE: + /* Only act if the mpeg is stopped */ + if(!(audio_stat & AUDIO_STATUS_RECORD)) + { /* if countdown timer is set, start countdown */ + if (timer.days || timer.hrs || timer.mins || timer.secs) + { + if (button == ACTION_REC_PAUSE) + { + timer.countdown = !timer.countdown; + if (timer.countdown) + tick_add_task(timer_tick_task); + else + tick_remove_task(timer_tick_task); + break; + } + else + { + /* if newfile button pressed and countdown timer is on, + start new file and reset timer */ + tick_remove_task(timer_tick_task); + timer.days = timer.hrs = timer.mins = timer.secs = 0; + timer.countdown = false; + } + } + /* is this manual or triggered recording? */ + if ((global_settings.rec_trigger_mode == TRIG_MODE_OFF) || + (peak_meter_trigger_status() != TRIG_OFF)) + { + /* manual recording */ + rec_status |= RCSTAT_HAVE_RECORDED; + rec_command(RECORDING_CMD_START); + repeat_timer_start = true; /* allow access to repeat timer + code */ + /* amount of file that has been prerecorded - needed for + syncing repeat timer */ + prerec = audio_recorded_time() / HZ; + last_seconds = 0; + if (global_settings.talk_menu) + { + /* no voice possible here, but a beep */ + audio_beep(HZ/2); /* longer beep on start */ + } + } + /* this is triggered recording */ + else + { + /* we don't start recording now, but enable the + trigger and let the callback function + trigger_listener control when the recording starts */ + peak_meter_trigger(true); + peak_meter_set_trigger_listener(&trigger_listener); + } + } + else + { + /*if new file button pressed, start new file */ + if (button == ACTION_REC_NEWFILE) + { + rec_command(RECORDING_CMD_START_NEWFILE); + last_seconds = 0; + } + else + /* if pause button pressed, pause or resume */ + { + if(audio_stat & AUDIO_STATUS_PAUSE) + { + rec_command(RECORDING_CMD_RESUME); + if (global_settings.talk_menu) + { + /* no voice possible here, but a beep */ + audio_beep(HZ/4); /* short beep on resume */ + } + } + else + { + rec_command(RECORDING_CMD_PAUSE); + } + } + } + update_countdown = 1; /* Update immediately */ + break; + + case ACTION_STD_PREV: + cursor--; + adjust_cursor(); + update_countdown = 1; /* Update immediately */ + break; + + case ACTION_STD_NEXT: + cursor++; + adjust_cursor(); + update_countdown = 1; /* Update immediately */ + break; + + case ACTION_SETTINGS_INC: + case ACTION_SETTINGS_INCREPEAT: + switch(cursor) + { + case 0: + global_settings.volume++; + setvol(); + break; + case 1: + if(global_settings.rec_source == AUDIO_SRC_MIC) + { + if(global_settings.rec_mic_gain < + sound_max(SOUND_MIC_GAIN)) + global_settings.rec_mic_gain++; + } + else + { + if(global_settings.rec_left_gain < + sound_max(SOUND_LEFT_GAIN)) + global_settings.rec_left_gain++; + if(global_settings.rec_right_gain < + sound_max(SOUND_RIGHT_GAIN)) + global_settings.rec_right_gain++; + } + break; + case 2: + if(global_settings.rec_left_gain < + sound_max(SOUND_LEFT_GAIN)) + global_settings.rec_left_gain++; + break; + case 3: + if(global_settings.rec_right_gain < + sound_max(SOUND_RIGHT_GAIN)) + global_settings.rec_right_gain++; + break; +#ifdef HAVE_AGC + case 4: + agc_preset = MIN(agc_preset + 1, AGC_MODE_SIZE); + agc_enable = (agc_preset != 0); + if (global_settings.rec_source == AUDIO_SRC_MIC) { + global_settings.rec_agc_preset_mic = agc_preset; + agc_maxgain = global_settings.rec_agc_maxgain_mic; + } else { + global_settings.rec_agc_preset_line = agc_preset; + agc_maxgain = global_settings.rec_agc_maxgain_line; + } + break; + case 5: + if (global_settings.rec_source == AUDIO_SRC_MIC) + { + agc_maxgain = MIN(agc_maxgain + 1, + sound_max(SOUND_MIC_GAIN)); + global_settings.rec_agc_maxgain_mic = agc_maxgain; + } + else + { + agc_maxgain = MIN(agc_maxgain + 1, + sound_max(SOUND_LEFT_GAIN)); + global_settings.rec_agc_maxgain_line = agc_maxgain; + } + break; +#endif /* HAVE_AGC */ + } + set_gain(); + update_countdown = 1; /* Update immediately */ + break; + + case ACTION_SETTINGS_DEC: + case ACTION_SETTINGS_DECREPEAT: + switch(cursor) + { + case 0: + global_settings.volume--; + setvol(); + break; + case 1: + if(global_settings.rec_source == AUDIO_SRC_MIC) + { + if(global_settings.rec_mic_gain > + sound_min(SOUND_MIC_GAIN)) + global_settings.rec_mic_gain--; + } + else + { + if(global_settings.rec_left_gain > + sound_min(SOUND_LEFT_GAIN)) + global_settings.rec_left_gain--; + if(global_settings.rec_right_gain > + sound_min(SOUND_RIGHT_GAIN)) + global_settings.rec_right_gain--; + } + break; + case 2: + if(global_settings.rec_left_gain > + sound_min(SOUND_LEFT_GAIN)) + global_settings.rec_left_gain--; + break; + case 3: + if(global_settings.rec_right_gain > + sound_min(SOUND_RIGHT_GAIN)) + global_settings.rec_right_gain--; + break; +#ifdef HAVE_AGC + case 4: + agc_preset = MAX(agc_preset - 1, 0); + agc_enable = (agc_preset != 0); + if (global_settings.rec_source == AUDIO_SRC_MIC) { + global_settings.rec_agc_preset_mic = agc_preset; + agc_maxgain = global_settings.rec_agc_maxgain_mic; + } else { + global_settings.rec_agc_preset_line = agc_preset; + agc_maxgain = global_settings.rec_agc_maxgain_line; + } + break; + case 5: + if (global_settings.rec_source == AUDIO_SRC_MIC) + { + agc_maxgain = MAX(agc_maxgain - 1, + sound_min(SOUND_MIC_GAIN)); + global_settings.rec_agc_maxgain_mic = agc_maxgain; + } + else + { + agc_maxgain = MAX(agc_maxgain - 1, + sound_min(SOUND_LEFT_GAIN)); + global_settings.rec_agc_maxgain_line = agc_maxgain; + } + break; +#endif /* HAVE_AGC */ + } + set_gain(); + update_countdown = 1; /* Update immediately */ + break; + + case ACTION_STD_MENU: +#if CONFIG_CODEC == SWCODEC + if(!(audio_stat & AUDIO_STATUS_RECORD)) +#else + if(audio_stat != AUDIO_STATUS_RECORD) +#endif + { +#ifdef HAVE_FMRADIO_REC + const int prev_rec_source = global_settings.rec_source; +#endif +#if (CONFIG_LED == LED_REAL) + /* led is restored at begin of loop / end of function */ + led(false); +#endif + if (recording_menu(no_source)) + { + done = true; + rec_status |= RCSTAT_BEEN_IN_USB_MODE; +#ifdef HAVE_FMRADIO_REC + radio_status = FMRADIO_OFF; +#endif + } + else + { +#ifdef HAVE_FMRADIO_REC + /* If input changes away from FM Radio, radio will + remain off when recording screen closes. */ + if (global_settings.rec_source != prev_rec_source + && prev_rec_source == AUDIO_SRC_FMRADIO) + radio_status = FMRADIO_OFF; +#endif + /* if countdown timer settings changed in menu, + stop counting and reset */ + if (!timer.countdown) + tick_remove_task(timer_tick_task); + +#if CONFIG_CODEC == SWCODEC + /* reinit after submenu exit */ + audio_close_recording(); + audio_init_recording(0); +#endif + + rec_init_recording_options(&rec_options); + rec_set_recording_options(&rec_options); + + if(rec_create_directory() < 0) + { + goto rec_abort; + } + +#if CONFIG_CODEC == SWCODEC && CONFIG_RTC == 0 + /* If format changed, a new number is required */ + rec_init_filename(); +#endif + +#ifdef HAVE_AGC + if (global_settings.rec_source == AUDIO_SRC_MIC) { + agc_preset = global_settings.rec_agc_preset_mic; + agc_maxgain = global_settings.rec_agc_maxgain_mic; + } + else { + agc_preset = global_settings.rec_agc_preset_line; + agc_maxgain = global_settings.rec_agc_maxgain_line; + } +#endif + + adjust_cursor(); + set_gain(); + update_countdown = 1; /* Update immediately */ +#ifdef HAVE_HISTOGRAM + hist_time_interval = 1 << global_settings.rec_histogram_interval; +#endif + + FOR_NB_SCREENS(i) + { +//check + screens[i].set_viewport(&vp[i]); +// screens[i].setfont(FONT_SYSFIXED); + screens[i].setfont(font[i]); +// screens[i].setmargins(global_settings.invert_cursor ? 0 : w[i], 8); + } + } + font_check = true; + } + break; + + case ACTION_STD_SHORTCUTS: + if(audio_stat != AUDIO_STATUS_RECORD) + rockbox_browse("/_Shortcuts/",SHOW_SUPPORTED); + break; + +#if CONFIG_KEYPAD == RECORDER_PAD + case ACTION_REC_F2: + if(audio_stat != AUDIO_STATUS_RECORD) + { +#if (CONFIG_LED == LED_REAL) + /* led is restored at begin of loop / end of function */ + led(false); +#endif + if (f2_rec_screen()) + { + rec_status |= RCSTAT_HAVE_RECORDED; + done = true; + } + else + update_countdown = 1; /* Update immediately */ + } + break; + + case ACTION_REC_F3: + if(audio_stat & AUDIO_STATUS_RECORD) + { + rec_command(RECORDING_CMD_START_NEWFILE); + last_seconds = 0; + } + else + { +#if (CONFIG_LED == LED_REAL) + /* led is restored at begin of loop / end of function */ + led(false); +#endif + if (f3_rec_screen()) + { + rec_status |= RCSTAT_HAVE_RECORDED; + done = true; + } + else + update_countdown = 1; /* Update immediately */ + } + break; +#endif /* CONFIG_KEYPAD == RECORDER_PAD */ + + case SYS_USB_CONNECTED: + /* Only accept USB connection when not recording */ + if(!(audio_stat & AUDIO_STATUS_RECORD)) + { + default_event_handler(SYS_USB_CONNECTED); + done = true; + rec_status |= RCSTAT_BEEN_IN_USB_MODE; +#ifdef HAVE_FMRADIO_REC + radio_status = FMRADIO_OFF; +#endif + } + break; + + default: + default_event_handler(button); + break; + } /* end switch */ + + /* display timer status in status bar if countdown enabled */ + timer.timer_display = timer.countdown; + +#ifdef HAVE_AGC + peak_read = !peak_read; + if (peak_read) { /* every 2nd run of loop */ + peak_time++; + peak_valid = read_peak_levels(&peak_l, &peak_r, &balance); + } + + /* Handle AGC every 200ms when enabled and peak data is valid */ + if (peak_read && agc_enable && peak_valid) + auto_gain_control(&peak_l, &peak_r, &balance); +#endif + + FOR_NB_SCREENS(i) +// screens[i].setfont(FONT_SYSFIXED); + screens[i].setfont(font[i]); + + seconds = audio_recorded_time() / HZ; + + update_countdown--; + if(update_countdown == 0 || seconds > last_seconds) + { + unsigned int dseconds, dhours, dminutes; + unsigned long num_recorded_bytes, dsize, dmb; + int pos = 0; + + update_countdown = 5; + last_seconds = seconds; + + /* Get free disk space and calculate remain time */ + fat_size( IF_MV2(0,) NULL, &disk_free ); /* [KBytes] */ + disk_free = disk_free / 1024; + if (disk_free < MIN_DISK_SPACE) + disk_free = MIN_DISK_SPACE; + disk_free -= MIN_DISK_SPACE; + disk_time = 140 * (int)disk_free / bitrate; /* rough estimation */ + + dseconds = rec_timesplit_seconds(); + dsize = rec_sizesplit_bytes(); + num_recorded_bytes = audio_num_recorded_bytes(); + + for(i = 0; i < screen_update; i++) + { + screens[i].clear_display(); + screens[i].setfont(font[i]); + } + + style = base_style; + +#ifdef HAVE_LCD_COLOR + /* special action for gradient - set default for 1 line gradient */ + if(global_settings.cursor_style == 3) + style = base_style | CURLN_PACK(0) | NUMLN_PACK(1); +#endif /* HAVE_LCD_COLOR */ + +#if CONFIG_CODEC == SWCODEC + if ((audio_stat & AUDIO_STATUS_WARNING) + && (warning_counter++ % WARNING_PERIOD) < WARNING_PERIOD/2) + { + /* Switch back and forth displaying warning on first available + line to ensure visibility - the motion should also help + draw attention */ + /* Don't use language string unless agreed upon to make this + method permanent - could do something in the statusbar */ + snprintf(buf, sizeof(buf), "Warning: %08X", + pcm_rec_get_warnings()); + } + else +#endif /* CONFIG_CODEC == SWCODEC */ + if ((global_settings.rec_sizesplit) && + (global_settings.rec_split_method)) + { + countdown_offset = 1; + dmb = dsize/1024/1024; + snprintf(buf, sizeof(buf), "%s %dMB", + str(LANG_SYSFONT_SPLIT_SIZE), dmb); + } + /* only display recording time if countdown timer is off */ + else if (!timer.days && !timer.hrs && !timer.mins && !timer.secs) + { + hours = seconds / 3600; + minutes = (seconds - (hours * 3600)) / 60; + snprintf(buf, sizeof(buf), "%s %02d:%02d:%02d", + str(LANG_SYSFONT_RECORDING_TIME), + hours, minutes, seconds%60); + } + else + { + countdown_offset = 0; + snprintf(buf, 32, ""); + } + + for(i = 0; i < screen_update; i++) + screens[i].puts(0, 0, buf); + + if(audio_stat & AUDIO_STATUS_PRERECORD) + { + snprintf(buf, sizeof(buf), "%s...", + str(LANG_SYSFONT_RECORD_PRERECORD)); + } + else + { + /* Display the split interval if the record timesplit + is active */ + if ((global_settings.rec_timesplit) && + !(global_settings.rec_split_method)) + { + /* Display the record timesplit interval rather + than the file size if the record timer is + active */ + dhours = dseconds / 3600; + dminutes = (dseconds - (dhours * 3600)) / 60; + snprintf(buf, sizeof(buf), "%s %02d:%02d", + str(LANG_SYSFONT_RECORD_TIMESPLIT_REC), + dhours, dminutes); + } + /* only display recording size if countdown timer is off */ + else if (!timer.days && !timer.hrs && !timer.mins && !timer.secs) + { + output_dyn_value(buf2, sizeof buf2, + num_recorded_bytes, + byte_units, true); + snprintf(buf, sizeof(buf), "%s %s", + str(LANG_SYSFONT_RECORDING_SIZE), buf2); + } + } + for(i = 0; i < screen_update; i++) + screens[i].puts(0, 1, buf); + + /* display countdown timer if set */ + if (timer.days || timer.hrs || timer.mins || timer.secs) + { + snprintf(buf, 32, "%s %d:%02d:%02d:%02d", str(LANG_REC_TIMER), + timer.days, timer.hrs, timer.mins, timer.secs); + + for(i = 0; i < screen_update; i++) + screens[i].puts(0, countdown_offset, buf); + } + + for(i = 0; i < screen_update; i++) + { + if (filename_offset[i] > 0) + { + *filename = '\0'; + if (audio_stat & AUDIO_STATUS_RECORD) + { + strncpy(filename, path_buffer + + strlen(path_buffer) - 12, 13); + filename[12]='\0'; + } + + snprintf(buf, sizeof(buf), "%s %s", + str(LANG_SYSFONT_RECORDING_FILENAME), filename); + screens[i].puts(0, 2, buf); + } + } + + /* We will do file splitting regardless, either at the end of + a split interval, or when the filesize approaches the 2GB + FAT file size (compatibility) limit. */ + if ((audio_stat && !(global_settings.rec_split_method) + && global_settings.rec_timesplit && (seconds >= dseconds)) + || (audio_stat && global_settings.rec_split_method + && global_settings.rec_sizesplit + && (num_recorded_bytes >= dsize)) + || (num_recorded_bytes >= MAX_FILE_SIZE)) + { + if (!(global_settings.rec_split_type) + || (num_recorded_bytes >= MAX_FILE_SIZE)) + { + rec_command(RECORDING_CMD_START_NEWFILE); + last_seconds = 0; + } +// else + else if (repeat_timer_start) + { + peak_meter_trigger(false); + peak_meter_set_trigger_listener(NULL); + if( global_settings.rec_split_type == 1) + rec_command(RECORDING_CMD_STOP); + else + rec_command(RECORDING_CMD_STOP_SHUTDOWN); + + /* stop any more attempts to access this code until a new + recording is started */ + repeat_timer_start = false; + + /* start repeat countdown if set and only if + stop time < repeat time */ + if (timer.repeater) + { + repeat_timer -= dseconds; + timer.days = repeat_timer / (3600 * 24); + timer.hrs = (repeat_timer - (timer.days * 3600 * 24)) / + 3600; + timer.mins = (repeat_timer - (timer.hrs * 3600)) / 60; + timer.secs = prerec; /* add prerecorded time to timer */ + + /* This is not really a toggle so much as a safety feature + so that it is impossible to start the timer more than + once */ + timer.countdown = !timer.countdown; + if (timer.countdown) + tick_add_task(timer_tick_task); + else + tick_remove_task(timer_tick_task); + } + } + update_countdown = 1; + } + + /* draw the clipcounter just in front of the peakmeter */ + if(global_settings.peak_meter_clipcounter) + { + char clpstr[32]; + snprintf(clpstr, 32, "%4d", pm_get_clipcount()); + for(i = 0; i < screen_update; i++) + { + if(pm_height[i] > 1) + screens[i].puts(0, 2 + filename_offset[i], + str(LANG_SYSFONT_PM_CLIPCOUNT)); + screens[i].puts(0, 1 + pm_height[i] + filename_offset[i], + clpstr); + } + } + + snprintf(buf, sizeof(buf), "%s: %s", str(LANG_SYSFONT_VOLUME), + fmt_gain(SOUND_VOLUME, + global_settings.volume, + buf2, sizeof(buf2))); + + if (global_settings.cursor_style && (pos++ == cursor)) + { + for(i = 0; i < screen_update; i++) + screens[i].puts_style_offset(0, filename_offset[i] + + pm_height[i] + 2, buf, style,0); +//- PM_HEIGHT + 2, buf, STYLE_INVERT,0); +//+ pm_height[i] + 2, buf, STYLE_INVERT,0); + } + else + { + for(i = 0; i < screen_update; i++) + screens[i].putsxy(ymargin, + h[i]*(filename_offset[i]+ + pm_height[i] + 2), buf); +//- screens[i].puts(0, filename_offset[i] + PM_HEIGHT + 2, buf); +//+ screens[i].puts(0, filename_offset[i] + pm_height[i] + 2, buf); + } + + if(global_settings.rec_source == AUDIO_SRC_MIC) + { + /* Draw MIC recording gain */ + snprintf(buf, sizeof(buf), "%s:%s", str(LANG_SYSFONT_GAIN), + fmt_gain(SOUND_MIC_GAIN, + global_settings.rec_mic_gain, + buf2, sizeof(buf2))); + if(global_settings.cursor_style && ((1==cursor)||(2==cursor))) + { + for(i = 0; i < screen_update; i++) + screens[i].puts_style_offset(0, filename_offset[i] + + pm_height[i] + 3, buf, style,0); +//- PM_HEIGHT + 3, buf, STYLE_INVERT,0); +//+ pm_height[i] + 3, buf, STYLE_INVERT,0); + } + else + { + for(i = 0; i < screen_update; i++) + screens[i].putsxy(ymargin, + h[i]*(filename_offset[i] + + pm_height[i] + 3), buf); +//- PM_HEIGHT + 3, buf); +//+ pm_height[i] + 3, buf); + } + } + else if(0 + HAVE_LINE_REC_( || global_settings.rec_source == + AUDIO_SRC_LINEIN) + HAVE_FMRADIO_REC_( || global_settings.rec_source == + AUDIO_SRC_FMRADIO) + ) + { + /* Draw LINE or FMRADIO recording gain */ + snprintf(buf, sizeof(buf), "%s:%s", + str(LANG_SYSFONT_RECORDING_LEFT), + fmt_gain(SOUND_LEFT_GAIN, + global_settings.rec_left_gain, + buf2, sizeof(buf2))); +#ifdef HAVE_LCD_COLOR + /* special action for gradient - double line gradient - line1 */ + if((global_settings.cursor_style == 3) && + (1==cursor)) + style = base_style | CURLN_PACK(0) | NUMLN_PACK(2); +#endif /* HAVE_LCD_COLOR */ + if(global_settings.cursor_style && ((1==cursor)||(2==cursor))) + { + for(i = 0; i < screen_update; i++) + screens[i].puts_style_offset(0, filename_offset[i] + + pm_height[i] + 3, buf, style,0); +//- PM_HEIGHT + 3, buf, STYLE_INVERT,0); +//+ pm_height[i] + 3, buf, STYLE_INVERT,0); + } + else + { + for(i = 0; i < screen_update; i++) + screens[i].putsxy(ymargin, + h[i]*(filename_offset[i] + + pm_height[i] + 3), buf); +//- PM_HEIGHT + 3, buf); +//+ pm_height[i] + 3, buf); + } + + snprintf(buf, sizeof(buf), "%s:%s", + str(LANG_SYSFONT_RECORDING_RIGHT), + fmt_gain(SOUND_RIGHT_GAIN, + global_settings.rec_right_gain, + buf2, sizeof(buf2))); +#ifdef HAVE_LCD_COLOR + /* special action for gradient - double line gradient - line2 */ + if((global_settings.cursor_style == 3) && + (1==cursor)) + style = base_style | CURLN_PACK(1) | NUMLN_PACK(2); +#endif /* HAVE_LCD_COLOR */ + if(global_settings.cursor_style && ((1==cursor)||(3==cursor))) + { + for(i = 0; i < screen_update; i++) + screens[i].puts_style_offset(0, filename_offset[i] + + pm_height[i] + 4, buf, style,0); +//- PM_HEIGHT + 4, buf, STYLE_INVERT,0); +//+ pm_height[i] + 4, buf, STYLE_INVERT,0); + } + else + { + for(i = 0; i < screen_update; i++) + screens[i].putsxy(ymargin, + h[i]*(filename_offset[i] + + pm_height[i] + 4), buf); +//- PM_HEIGHT + 4, buf); +//+ pm_height[i] + 4, buf); + } + } + yield(); + +#ifdef HAVE_LCD_COLOR + /* special action for gradient - back to single line gradient */ + if(global_settings.cursor_style == 3) + style = base_style | CURLN_PACK(0) | NUMLN_PACK(1); +#endif /* HAVE_LCD_COLOR */ + FOR_NB_SCREENS(i) + { + switch (global_settings.rec_source) + { + HAVE_LINE_REC_(case AUDIO_SRC_LINEIN:) + HAVE_FMRADIO_REC_(case AUDIO_SRC_FMRADIO:) + line[i] = 5; + break; + + case AUDIO_SRC_MIC: + line[i] = 4; + break; +#ifdef HAVE_SPDIF_REC + case AUDIO_SRC_SPDIF: + line[i] = 3; + break; +#endif + default: + line[i] = 5; /* to prevent uninitialisation + warnings for line[0] */ + break; + } /* end switch */ +#ifdef HAVE_AGC +// if (vp[i].height < h * (2 + filename_offset[i] + +// PM_HEIGHT + line[i])) +//- if (screens[i].height < h * (2 + filename_offset[i] + PM_HEIGHT + line[i])) + if (vp[i].height < 8 + h[i] * (1 + filename_offset[i] + pm_height[i] + line[i])) + { + line[i] -= 1; + display_agc[i] = false; + } + else + display_agc[i] = true; + + if ((cursor==4) || (cursor==5)) + display_agc[i] = true; + } + + /************** AGC test info ****************** + snprintf(buf, sizeof(buf), "D:%d U:%d", + (agc_droptime+2)/5, (agc_risetime+2)/5); + lcd_putsxy(1, LCD_HEIGHT - 8, buf); + snprintf(buf, sizeof(buf), "B:%d", + (agc_baltime+2)/5); + lcd_putsxy(LCD_WIDTH/2 + 3, LCD_HEIGHT - 8, buf); + ***********************************************/ + + if (cursor == 5) + snprintf(buf, sizeof(buf), "%s: %s", + str(LANG_SYSFONT_RECORDING_AGC_MAXGAIN), + fmt_gain(SOUND_LEFT_GAIN, + agc_maxgain, buf2, sizeof(buf2))); + else if (agc_preset == 0) + snprintf(buf, sizeof(buf), "%s: %s", + str(LANG_SYSFONT_RECORDING_AGC_PRESET), + agc_preset_str[agc_preset]); + else if (global_settings.rec_source == AUDIO_SRC_MIC) + snprintf(buf, sizeof(buf), "%s: %s%s", + str(LANG_SYSFONT_RECORDING_AGC_PRESET), + agc_preset_str[agc_preset], + fmt_gain(SOUND_LEFT_GAIN, + agc_maxgain - + global_settings.rec_mic_gain, + buf2, sizeof(buf2))); + else + snprintf(buf, sizeof(buf), "%s: %s%s", + str(LANG_SYSFONT_RECORDING_AGC_PRESET), + agc_preset_str[agc_preset], + fmt_gain(SOUND_LEFT_GAIN, + agc_maxgain - + (global_settings.rec_left_gain + + global_settings.rec_right_gain)/2, + buf2, sizeof(buf2))); + + if(global_settings.cursor_style && ((cursor==4) || (cursor==5))) + { + for(i = 0; i < screen_update; i++) + screens[i].puts_style_offset(0, filename_offset[i] + + pm_height[i] + line[i], buf, style,0); +//- PM_HEIGHT + line[i], buf, STYLE_INVERT,0); +//+ pm_height[i] + line[i], buf, STYLE_INVERT,0); + } + else if (global_settings.rec_source == AUDIO_SRC_MIC + HAVE_LINE_REC_(|| global_settings.rec_source == + AUDIO_SRC_LINEIN) + HAVE_FMRADIO_REC_(|| global_settings.rec_source == + AUDIO_SRC_FMRADIO) + ) + { + for(i = 0; i < screen_update; i++) { + if (display_agc[i]) { + screens[i].putsxy(ymargin, + h[i]*(filename_offset[i] + + pm_height[i] + line[i]), buf); +//- screens[i].puts(0, filename_offset[i] + +//- PM_HEIGHT + line[i], buf); +//+ screens[i].puts(0, filename_offset[i] + +//+ pm_height[i] + line[i], buf); + } + } + } + + if (global_settings.rec_source == AUDIO_SRC_MIC) + { + if(agc_maxgain < (global_settings.rec_mic_gain)) + change_recording_gain(false, true, true); + } + else + { + if(agc_maxgain < (global_settings.rec_left_gain)) + change_recording_gain(false, true, false); + if(agc_maxgain < (global_settings.rec_right_gain)) + change_recording_gain(false, false, true); + } +#else /* !HAVE_AGC */ + } +#endif /* HAVE_AGC */ + + if(!global_settings.cursor_style) { + switch(cursor) + { + case 1: + for(i = 0; i < screen_update; i++) + screen_put_cursorxy(&screens[i], 0, + filename_offset[i] + + pm_height[i] + 3, true); + + if(global_settings.rec_source != AUDIO_SRC_MIC) + { + for(i = 0; i < screen_update; i++) + screen_put_cursorxy(&screens[i], 0, + filename_offset[i] + + pm_height[i] + 4, true); + } + break; + case 2: + for(i = 0; i < screen_update; i++) + screen_put_cursorxy(&screens[i], 0, + filename_offset[i] + + pm_height[i] + 3, true); + break; + case 3: + for(i = 0; i < screen_update; i++) + screen_put_cursorxy(&screens[i], 0, + filename_offset[i] + + pm_height[i] + 4, true); + break; +#ifdef HAVE_AGC + case 4: + case 5: + for(i = 0; i < screen_update; i++) + screen_put_cursorxy(&screens[i], 0, + filename_offset[i] + + pm_height[i] + line[i], true); + break; +#endif /* HAVE_AGC */ + default: + for(i = 0; i < screen_update; i++) + screen_put_cursorxy(&screens[i], 0, + filename_offset[i] + + pm_height[i] + 2, true); + } + } + +#ifdef HAVE_AGC + hist_time++; +#endif + +#ifdef HAVE_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)) + int hist_bal_y; + if (histogram_on) + hist_bal_y = HIST_Y - hist_size_h[history_mode/2] - 11; + else + hist_bal_y = HIST_Y - 11; + + if((global_settings.rec_source == AUDIO_SRC_MIC)|| + (global_settings.rec_source == AUDIO_SRC_LINEIN)|| + (global_settings.rec_source == AUDIO_SRC_FMRADIO)) + agc_line = 1; + else + agc_line = 0; /* no agc line for Spdif in */ + + if ((hist_bal_y) > (8 + ((line[0] + filename_offset[0] + + pm_height[0] + agc_line + (global_settings.rec_trigger_mode > + 0 ? 1 : 0)) * h[0]))) + { + lcd_setfont(FONT_SYSFIXED); + lcd_set_drawmode(DRMODE_FG); +#if LCD_DEPTH > 1 + if (battery_level() > 10) + lcd_set_foreground(LCD_BATT_OK); + else + lcd_set_foreground(LCD_BATT_LO); +#else + lcd_set_foreground( +#ifdef HAVE_LCD_COLOR + global_settings.fg_color); +#else + LCD_DEFAULT_FG); +#endif +#endif /* LCD_DEPTH > 1 */ + lcd_fillrect(0, hist_bal_y, + (30 * battery_level() + 60) / 100, 9); +#if LCD_DEPTH > 1 + if (disk_time > 59) + lcd_set_foreground(LCD_DISK_OK); + else + lcd_set_foreground(LCD_DISK_LO); +#endif /* LCD_DEPTH > 1 */ + if ((LCD_WIDTH/2 - 36)*(disk_space-disk_free-3) / disk_space) + lcd_fillrect(35, hist_bal_y, (LCD_WIDTH/2 - 37) * + (disk_space - disk_free - 1) / disk_space, 9); + lcd_set_drawmode(DRMODE_COMPLEMENT); + lcd_set_foreground( +#ifdef HAVE_LCD_COLOR + global_settings.fg_color); +#else + LCD_DEFAULT_FG); +#endif +#ifndef SIMULATOR + if (charger_inserted()) + lcd_mono_bitmap(bitmap_icons_7x8[Icon_Plug], + 2 + 19*(battery_level() > 48), + hist_bal_y + 1, 7, 8); +#endif + if (battery_time() > 90) + snprintf(buf, 32, "%dh", (battery_time() + 10) / 60); + else + snprintf(buf,32, "%dm", battery_time()); + if (battery_level() > 48) + i = 1; + else if ((battery_time() < 590) && (battery_time() > 90)) + i = 15; + else + i = 10; + lcd_putsxy(i, hist_bal_y + 1, buf); + if (disk_time > 90) + snprintf(buf, 32, "%dh", (disk_time + 10) / 60); + else + snprintf(buf, 32, "%dm", disk_time); + i = ((disk_time < 91) || (disk_time > 589))? 30:26; + + if ((hist_time % 2) +#ifndef SIMULATOR + || !ata_disk_is_active() +#endif + ) + lcd_mono_bitmap(rec_icons_6x8[Icon_Disk], + LCD_WIDTH/2 - 11, + hist_bal_y + 1, 6, 8); + lcd_putsxy((5*disk_free > 3*disk_space) ? + (LCD_WIDTH/2 - i) : 37, + hist_bal_y + 1, buf); + lcd_drawrect(34, hist_bal_y - 1, LCD_WIDTH/2 - 36, 11); + lcd_set_drawmode(DRMODE_SOLID); + lcd_drawrect(0, hist_bal_y - 1, 30, 11); + lcd_vline(30, hist_bal_y + 2, hist_bal_y + 6); + lcd_vline(31, hist_bal_y + 2, hist_bal_y + 6); + + int bal; + lcd_drawrect(HIST_BAL_X-2, hist_bal_y-1, HIST_BAL_W+3, 11); + lcd_hline(HIST_BAL_X + HIST_BAL_W/2 - 1, + HIST_BAL_X + HIST_BAL_W/2 + 1, + hist_bal_y - 2); + lcd_hline(HIST_BAL_X + HIST_BAL_W/2 - 1, + HIST_BAL_X + HIST_BAL_W/2 + 1, + hist_bal_y + 10); + lcd_set_drawmode(DRMODE_FG); +#ifndef HAVE_LCD_COLOR + lcd_set_foreground(LCD_BAL); +#endif + for (i = 0; i < BAL_MEM_SIZE; i++) { + bal = MIN(balance_mem[i], BAL_MAX_R); + bal = MAX(bal, BAL_MAX_L); +#ifdef HAVE_LCD_COLOR + if (bal > 142) + lcd_set_foreground(LCD_BAL_L); + else if (bal < 142) + lcd_set_foreground(LCD_BAL_R); + else + lcd_set_foreground(LCD_DARKGRAY); +#endif + /* every 0.2 seconds a balance measure is taken, + draw a vline for each */ + lcd_vline(HIST_BAL_X + HIST_BAL_W/2 + + HIST_BAL_W * bal / 9976, + hist_bal_y + 1, hist_bal_y + 7); + } + lcd_set_foreground(LCD_BLACK); + bal = MAX(balance, BAL_MAX_L); + bal = MIN(bal, BAL_MAX_R); + /* draw the 3 pixel wide balance measure, + average measure of the last 24 measures (5 seconds) */ + lcd_fillrect(HIST_BAL_X-1 + HIST_BAL_W/2 + + HIST_BAL_W * bal / 9976, + hist_bal_y, 3, 9); + lcd_drawpixel(HIST_BAL_X + HIST_BAL_W/2, hist_bal_y + 4); + lcd_set_drawmode(DRMODE_COMPLEMENT); + lcd_drawpixel(HIST_BAL_X + HIST_BAL_W/2, hist_bal_y - 1); + lcd_drawpixel(HIST_BAL_X + HIST_BAL_W/2, hist_bal_y + 9); + for (i = 0; i < 12; i++) + lcd_drawpixel(HIST_BAL_X + HIST_BAL_W/2 + + HIST_BAL_W * hist_balance_marks[i] / 9976, + hist_bal_y + 4); + } + + if (histogram_on) + { + hist_height = hist_size_h[history_mode/2] - 1; + if (peak_valid && !(hist_time % hist_time_interval) && hist_l) + { + if (history_mode % 2) { + i = 0; + while (hist_l < hist_peak_lin2dB[history_mode / 2][i]) + i++; + history_l[history_pos] = hist_height - i; + i = 0; + while (hist_r < hist_peak_lin2dB[history_mode / 2][i]) + i++; + history_r[history_pos] = hist_height - i; + } else { + history_l[history_pos] = hist_l * hist_height / 32767; + history_r[history_pos] = hist_r * hist_height / 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_Y - hist_height, + HIST_W + 2, hist_height + 1); + lcd_drawrect(HIST_W + 6, HIST_Y - hist_height, + HIST_W + 2, hist_height + 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_height) + lcd_set_foreground(LCD_HIST_OVER); + else if (history_l[i] > hist_level_marks[history_mode][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_height) + lcd_set_foreground(LCD_HIST_OVER); + else if (history_r[i] > hist_level_marks[history_mode][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_height) + 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_height) + 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]); + } + } + lcd_set_foreground(LCD_WHITE); + for (i = 0; i < HIST_W; i++) { + if (history_l[i] == hist_height) + lcd_drawpixel(1 + i, HIST_Y - 1); + if (history_r[i] == hist_height) + lcd_drawpixel(HIST_W + 7 + i, HIST_Y - 1); + } +#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[history_mode][i]); + } +#endif /* HAVE_HISTOGRAM */ + +#ifdef HAVE_AGC + hist_time++; +#endif + + for(i = 0; i < screen_update; i++) + { + screens[i].set_viewport(NULL); + gui_statusbar_draw(&(statusbars.statusbars[i]), true); + screens[i].set_viewport(&vp[i]); + peak_meter_screen(&screens[i], pm_x, pm_y[i], pm_h[i]); +//- peak_meter_screen(&screens[i], 0, pm_y[i], h*PM_HEIGHT); +//+ peak_meter_screen(&screens[i], 0, pm_y[i], pm_h[i]); + screens[i].update(); + } + + /* draw the trigger status */ + FOR_NB_SCREENS(i) + { + /* NOTE: UGLY width setting based on height! To be fixed! */ +// trig_width[i] = ((vp[i].height < 64) || +// ((vp[i].height < 72) && (PM_HEIGHT > 1))) ? +// screens[i].getwidth() - 14 * w : +// screens[i].getwidth(); +//- trig_width[i] = ((screens[i].height < 64) || +//- ((screens[i].height < 72) && (PM_HEIGHT > 1))) ? +//- screens[i].width - 14 * w : screens[i].width; + trig_width[i] = (vp[i].height < (h[i] * (2 + + filename_offset[i] + pm_height[i] + + line[i]) + (histogram_on ? 25 : 8))) ? + screens[i].getwidth() - + 14 * w[i] : screens[i].getwidth(); + trig_xpos[i] = screens[i].getwidth() - trig_width[i]; +// trig_ypos[i] = ((vp[i].height < 72) && (PM_HEIGHT > 1)) ? +// h*2 : +// h*(1 + filename_offset[i] + PM_HEIGHT + +// line[i] +//- trig_ypos[i] = ((screens[i].height < 72) && (PM_HEIGHT > 1)) ? +//- h*2 : +//- h*(1 + filename_offset[i] + PM_HEIGHT + line[i] + trig_ypos[i] = (vp[i].height < (h[i] * (2 + + filename_offset[i] + pm_height[i] + + line[i]) + (histogram_on ? 25 : 8))) ? h[i]*2 + : h[i]*(1 + filename_offset[i] + + pm_height[i] + line[i] +#ifdef HAVE_AGC + + 1 +#endif + ); + } + + if (peak_meter_trigger_status() != TRIG_OFF) + { + peak_meter_draw_trig(trig_xpos, trig_ypos, trig_width, + screen_update); + for(i = 0; i < screen_update; i++){ + screens[i].update_rect(trig_xpos[i], trig_ypos[i], + trig_width[i] + 2, TRIG_HEIGHT); + } + } + } + + /* check battery level & free disk space */ +#ifndef SIMULATOR + if (ata_disk_is_active()) + disk_was_active = true; + else if (disk_was_active) + { + lcd_setfont(FONT_UI); + if (disk_time == 0) { + backlight_on(); +#ifdef HAVE_REMOTE_LCD + remote_backlight_on(); +#endif + if (audio_stat & AUDIO_STATUS_RECORD) { + gui_syncsplash(HZ, "%s %s", + str(LANG_WARNING_DISK_FULL), + str(LANG_WARNING_STOP_RECORDING)); + audio_stop_recording(); + } + else { + gui_syncsplash(2*HZ, + str(LANG_WARNING_DISK_FULL)); + } + } + else if (warn_message && (battery_level() < 10)) { + backlight_on(); +#ifdef HAVE_REMOTE_LCD + remote_backlight_on(); +#endif + gui_syncsplash(3*HZ, + str(LANG_WARNING_BATTERY_LOW)); + } + else if (!warn_message && (disk_free < 512)) { + backlight_on(); +#ifdef HAVE_REMOTE_LCD + remote_backlight_on(); +#endif + gui_syncsplash(3*HZ, + str(LANG_WARNING_DISKSPACE_LOW)); + } + lcd_setfont(FONT_SYSFIXED); + warn_message = !warn_message; + disk_was_active = false; + } +#endif + + if(audio_stat & AUDIO_STATUS_ERROR) + { + done = true; + } + } /* end while(!done) */ + + audio_stat = audio_status(); + if (audio_stat & AUDIO_STATUS_ERROR) + { + gui_syncsplash(0, str(LANG_SYSFONT_DISK_FULL)); + gui_syncstatusbar_draw(&statusbars, true); + + FOR_NB_SCREENS(i) + screens[i].update(); + +#if CONFIG_CODEC == SWCODEC + /* stop recording - some players like H10 freeze otherwise + TO DO: find out why it freezes and fix properly */ + rec_command(RECORDING_CMD_STOP); + audio_close_recording(); +#endif + + audio_error_clear(); + + while(1) + { + if (action_userabort(TIMEOUT_NOBLOCK)) + break; + } + } + +rec_abort: + +#if CONFIG_CODEC == SWCODEC + rec_command(RECORDING_CMD_STOP); + audio_close_recording(); + +#ifdef HAVE_FMRADIO_REC + if (radio_status != FMRADIO_OFF) + /* Restore radio playback - radio_status should be unchanged if started + through fm radio screen (barring usb connect) */ + rec_set_source(AUDIO_SRC_FMRADIO, (radio_status & FMRADIO_PAUSED) ? + SRCF_FMRADIO_PAUSED : SRCF_FMRADIO_PLAYING); + else +#endif + /* Go back to playback mode */ + rec_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); + + /* restore talking */ + talk_disable(false); +#else /* !SWCODEC */ + audio_init_playback(); +#endif /* CONFIG_CODEC == SWCODEC */ + + /* make sure the trigger is really turned off */ + peak_meter_trigger(false); + peak_meter_set_trigger_listener(NULL); + + rec_status &= ~RCSTAT_IN_RECSCREEN; + sound_settings_apply(); + + FOR_NB_SCREENS(i) + screens[i].setfont(FONT_UI); + + /* if the directory was created or recording happened, make sure the + browser is updated */ + if (rec_status & (RCSTAT_CREATED_DIRECTORY | RCSTAT_HAVE_RECORDED)) + reload_directory(); + +#ifdef HAVE_HISTOGRAM + global_settings.rec_histogram_mode = history_mode; +#endif + +#if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR) + ata_set_led_enabled(true); +#endif + + settings_save(); + + return (rec_status & RCSTAT_BEEN_IN_USB_MODE) != 0; +} /* recording_screen */ + +#if CONFIG_KEYPAD == RECORDER_PAD +static bool f2_rec_screen(void) +{ + static const char* const freq_str[6] = + { + "44.1kHz", + "48kHz", + "32kHz", + "22.05kHz", + "24kHz", + "16kHz" + }; + + bool exit = false; + bool used = false; + int w, h, i; + char buf[32]; + int button; + struct audio_recording_options rec_options; + + FOR_NB_SCREENS(i) + { + screens[i].setfont(FONT_SYSFIXED); + screens[i].getstringsize("A",&w,&h); + } + + while (!exit) { + const char* ptr=NULL; + + FOR_NB_SCREENS(i) + { + screens[i].clear_display(); + + /* Recording quality */ + screens[i].putsxy(0, LCD_HEIGHT/2 - h*2, + str(LANG_SYSFONT_RECORDING_QUALITY)); + } + + snprintf(buf, sizeof(buf), "%d", global_settings.rec_quality); + FOR_NB_SCREENS(i) + { + screens[i].putsxy(0, LCD_HEIGHT/2-h, buf); + screens[i].mono_bitmap(bitmap_icons_7x8[Icon_FastBackward], + LCD_WIDTH/2 - 16, LCD_HEIGHT/2 - 4, 7, 8); + } + + /* Frequency */ + snprintf(buf, sizeof buf, "%s:", str(LANG_SYSFONT_RECORDING_FREQUENCY)); + ptr = freq_str[global_settings.rec_frequency]; + FOR_NB_SCREENS(i) + { + screens[i].getstringsize(buf,&w,&h); + screens[i].putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h*2, buf); + screens[i].getstringsize(ptr, &w, &h); + screens[i].putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h, ptr); + screens[i].mono_bitmap(bitmap_icons_7x8[Icon_DownArrow], + LCD_WIDTH/2 - 3, LCD_HEIGHT - h*3, 7, 8); + } + + /* Channel mode */ + switch ( global_settings.rec_channels ) { + case 0: + ptr = str(LANG_SYSFONT_CHANNEL_STEREO); + break; + + case 1: + ptr = str(LANG_SYSFONT_CHANNEL_MONO); + break; + } + + FOR_NB_SCREENS(i) + { + screens[i].getstringsize(str(LANG_SYSFONT_CHANNELS), &w, &h); + screens[i].putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 - h*2, + str(LANG_SYSFONT_CHANNELS)); + screens[i].getstringsize(str(LANG_SYSFONT_MODE), &w, &h); + screens[i].putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 - h, + str(LANG_SYSFONT_MODE)); + screens[i].getstringsize(ptr, &w, &h); + screens[i].putsxy(LCD_WIDTH - w, LCD_HEIGHT/2, ptr); + screens[i].mono_bitmap(bitmap_icons_7x8[Icon_FastForward], + LCD_WIDTH/2 + 8, LCD_HEIGHT/2 - 4, 7, 8); + + screens[i].update(); + } + + button = button_get(true); + switch (button) { + case BUTTON_LEFT: + case BUTTON_F2 | BUTTON_LEFT: + global_settings.rec_quality++; + if(global_settings.rec_quality > 7) + global_settings.rec_quality = 0; + used = true; + break; + + case BUTTON_DOWN: + case BUTTON_F2 | BUTTON_DOWN: + global_settings.rec_frequency++; + if(global_settings.rec_frequency > 5) + global_settings.rec_frequency = 0; + used = true; + break; + + case BUTTON_RIGHT: + case BUTTON_F2 | BUTTON_RIGHT: + global_settings.rec_channels++; + if(global_settings.rec_channels > 1) + global_settings.rec_channels = 0; + used = true; + break; + + case BUTTON_F2 | BUTTON_REL: + if ( used ) + exit = true; + used = true; + break; + + case BUTTON_F2 | BUTTON_REPEAT: + used = true; + break; + + default: + if(default_event_handler(button) == SYS_USB_CONNECTED) + return true; + break; + } + } + + rec_init_recording_options(&rec_options); + rec_set_recording_options(&rec_options); + + set_gain(); + + settings_save(); + FOR_NB_SCREENS(i) + screens[i].setfont(FONT_UI); + + return false; +} + +static bool f3_rec_screen(void) +{ + bool exit = false; + bool used = false; + int w, h, i; + int button; + char *src_str[] = + { + str(LANG_SYSFONT_RECORDING_SRC_MIC), + str(LANG_SYSFONT_LINE_IN), + str(LANG_SYSFONT_RECORDING_SRC_DIGITAL) + }; + struct audio_recording_options rec_options; + + FOR_NB_SCREENS(i) + { + screens[i].setfont(FONT_SYSFIXED); + screens[i].getstringsize("A",&w,&h); + } + + while (!exit) { + char* ptr=NULL; + ptr = src_str[global_settings.rec_source]; + FOR_NB_SCREENS(i) + { + screens[i].clear_display(); + + /* Recording source */ + screens[i].putsxy(0, LCD_HEIGHT/2 - h*2, + str(LANG_SYSFONT_RECORDING_SOURCE)); + + screens[i].getstringsize(ptr, &w, &h); + screens[i].putsxy(0, LCD_HEIGHT/2-h, ptr); + screens[i].mono_bitmap(bitmap_icons_7x8[Icon_FastBackward], + LCD_WIDTH/2 - 16, LCD_HEIGHT/2 - 4, 7, 8); + } + + /* trigger setup */ + ptr = str(LANG_SYSFONT_RECORD_TRIGGER); + FOR_NB_SCREENS(i) + { + screens[i].getstringsize(ptr,&w,&h); + screens[i].putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h*2, ptr); + screens[i].mono_bitmap(bitmap_icons_7x8[Icon_DownArrow], + LCD_WIDTH/2 - 3, LCD_HEIGHT - h*3, 7, 8); + + screens[i].update(); + } + + button = button_get(true); + switch (button) { + case BUTTON_DOWN: + case BUTTON_F3 | BUTTON_DOWN: +#ifndef SIMULATOR + rectrigger(); + settings_apply_trigger(); +#endif + exit = true; + break; + + case BUTTON_LEFT: + case BUTTON_F3 | BUTTON_LEFT: + global_settings.rec_source++; + if(global_settings.rec_source > AUDIO_SRC_MAX) + global_settings.rec_source = 0; + used = true; + break; + + case BUTTON_F3 | BUTTON_REL: + if ( used ) + exit = true; + used = true; + break; + + case BUTTON_F3 | BUTTON_REPEAT: + used = true; + break; + + default: + if(default_event_handler(button) == SYS_USB_CONNECTED) + return true; + break; + } + } + + rec_init_recording_options(&rec_options); + rec_set_recording_options(&rec_options); + + set_gain(); + + settings_save(); + FOR_NB_SCREENS(i) + screens[i].setfont(FONT_UI); + + return false; +} +#endif /* CONFIG_KEYPAD == RECORDER_PAD */ + +struct timer *get_timerstat(void) +{ + return &timer; +} + + +#if CONFIG_CODEC == SWCODEC +void audio_beep(int duration) +{ + /* dummy */ + (void)duration; +} + +#ifdef SIMULATOR +/* stubs for recording sim */ +void audio_init_recording(unsigned int buffer_offset) +{ + buffer_offset = buffer_offset; +} + +void audio_close_recording(void) +{ +} + +unsigned long pcm_rec_get_warnings(void) +{ + return 0; +} + +unsigned long audio_recorded_time(void) +{ + return 123; +} + +unsigned long audio_num_recorded_bytes(void) +{ + return 5 * 1024 * 1024; +} + +void rec_set_source(int source, unsigned flags) +{ + source = source; + flags = flags; +} + +void audio_set_recording_options(struct audio_recording_options *options) +{ + options = options; +} + +void audio_set_recording_gain(int left, int right, int type) +{ + left = left; + right = right; + type = type; +} + +void audio_record(const char *filename) +{ + filename = filename; +} + +void audio_new_file(const char *filename) +{ + filename = filename; +} + +void audio_stop_recording(void) +{ +} + +void audio_pause_recording(void) +{ +} + +void audio_resume_recording(void) +{ +} + +#endif /* #ifdef SIMULATOR */ +#endif /* #ifdef CONFIG_CODEC == SWCODEC */ + +#endif /* HAVE_RECORDING */ + \ No newline at end of file diff -Naur _008/apps/recorder/recording.c.orig2 _009_rep/apps/recorder/recording.c.orig2 --- _008/apps/recorder/recording.c.orig2 1970-01-01 09:00:00.000000000 +0900 +++ _009_rep/apps/recorder/recording.c.orig2 2008-07-24 03:45:43.136016000 +0900 @@ -0,0 +1,3036 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: recording.c 17945 2008-07-05 12:47:34Z jdgordon $ + * + * Copyright (C) 2002 by Linus Nielsen Feltzing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" + +#include +#include +#include + +#include "system.h" +#include "power.h" +#include "powermgmt.h" +#include "lcd.h" +#include "led.h" +#include "mpeg.h" +#include "audio.h" +#if CONFIG_CODEC == SWCODEC +#include "thread.h" +#include "playback.h" +#include "enc_config.h" +#if defined(HAVE_SPDIF_IN) || defined(HAVE_SPDIF_OUT) +#include "spdif.h" +#endif +#endif /* CONFIG_CODEC == SWCODEC */ +#include "recording.h" +#include "mp3_playback.h" +#include "mas.h" +#include "button.h" +#include "kernel.h" +#include "settings.h" +#include "lang.h" +#include "font.h" +#include "icons.h" +#include "icon.h" +#include "screens.h" +#include "peakmeter.h" +#include "statusbar.h" +#include "menu.h" +#include "sound_menu.h" +#include "timefuncs.h" +#include "debug.h" +#include "misc.h" +#include "tree.h" +#include "string.h" +#include "dir.h" +#include "errno.h" +#include "talk.h" +#include "sound.h" +#include "ata.h" +#include "splash.h" +#include "screen_access.h" +#include "action.h" +#include "radio.h" +#include "sound_menu.h" +#include "viewport.h" +#include "fat.h" +#include "backlight.h" + +#ifdef HAVE_RECORDING +/* This array holds the record timer interval lengths, in seconds */ +static const unsigned long rec_timer_seconds[] = +{ + 0, /* 0 means OFF */ + 5*60, /* 00:05 */ + 10*60, /* 00:10 */ + 15*60, /* 00:15 */ + 30*60, /* 00:30 */ + 60*60, /* 01:00 */ + 74*60, /* 74:00 */ + 80*60, /* 80:00 */ + 2*60*60, /* 02:00 */ + 4*60*60, /* 04:00 */ + 6*60*60, /* 06:00 */ + 8*60*60, /* 08:00 */ + 10L*60*60, /* 10:00 */ + 12L*60*60, /* 12:00 */ + 18L*60*60, /* 18:00 */ + 24L*60*60 /* 24:00 */ +}; + +static unsigned int rec_timesplit_seconds(void) +{ + return rec_timer_seconds[global_settings.rec_timesplit]; +} + +/* This array holds the record size interval lengths, in bytes */ +static const unsigned long rec_size_bytes[] = +{ + 0, /* 0 means OFF */ + 5*1024*1024, /* 5MB */ + 10*1024*1024, /* 10MB */ + 15*1024*1024, /* 15MB */ + 32*1024*1024, /* 32MB */ + 64*1024*1024, /* 64MB */ + 75*1024*1024, /* 75MB */ + 100*1024*1024, /* 100MB */ + 128*1024*1024, /* 128MB */ + 256*1024*1024, /* 256MB */ + 512*1024*1024, /* 512MB */ + 650*1024*1024, /* 650MB */ + 700*1024*1024, /* 700MB */ + 1024*1024*1024, /* 1GB */ + 1536*1024*1024, /* 1.5GB */ + 1792*1024*1024, /* 1.75GB */ +}; + +static unsigned long rec_sizesplit_bytes(void) +{ + return rec_size_bytes[global_settings.rec_sizesplit]; +} + +void settings_apply_trigger(void) +{ + int start_thres, stop_thres; + if (global_settings.peak_meter_dbfs) + { + start_thres = global_settings.rec_start_thres_db - 1; + stop_thres = global_settings.rec_stop_thres_db - 1; + } + else + { + start_thres = global_settings.rec_start_thres_linear; + stop_thres = global_settings.rec_stop_thres_linear; + } + + peak_meter_define_trigger( + start_thres, + global_settings.rec_start_duration*HZ, + MIN(global_settings.rec_start_duration*HZ / 2, 2*HZ), + stop_thres, + global_settings.rec_stop_postrec*HZ, + global_settings.rec_stop_gap*HZ + ); +} +/* recording screen status flags */ +enum rec_status_flags +{ + RCSTAT_IN_RECSCREEN = 0x00000001, + RCSTAT_BEEN_IN_USB_MODE = 0x00000002, + RCSTAT_CREATED_DIRECTORY = 0x00000004, + RCSTAT_HAVE_RECORDED = 0x00000008, +}; + +static int rec_status = 0; + +bool in_recording_screen(void) +{ + return (rec_status & RCSTAT_IN_RECSCREEN) != 0; +} + +static struct timer timer; + +#if CONFIG_KEYPAD == RECORDER_PAD +static bool f2_rec_screen(void); +static bool f3_rec_screen(void); +#endif + +#if defined(HAVE_LCD_BITMAP) && (LCD_HEIGHT > 111) && defined(HAVE_AGC) +#define HAVE_HISTOGRAM /* only for bigger screens */ +#endif + +#define MAX_FILE_SIZE 0x7F800000 /* 2 GB - 4 MB */ +#define MIN_DISK_SPACE 48 /* minimum remaining disk space */ +unsigned long disk_space = 0; + +#ifndef HAVE_REMOTE_LCD +static const int screen_update = NB_SCREENS; +#else +static int screen_update = NB_SCREENS; +static bool remote_display_on = true; +#endif + +/** File name creation **/ +#if CONFIG_RTC == 0 +/* current file number to assist in creating unique numbered filenames + without actually having to create the file on disk */ +static int file_number = -1; +#endif /* CONFIG_RTC */ + +#if CONFIG_CODEC == SWCODEC + +#define REC_FILE_ENDING(rec_format) \ + (audio_formats[rec_format_afmt[rec_format]].ext_list) + +#else /* CONFIG_CODEC != SWCODEC */ + +/* default record file extension for HWCODEC */ +#define REC_FILE_ENDING(rec_format) \ + (audio_formats[AFMT_MPA_L3].ext_list) + +#endif /* CONFIG_CODEC == SWCODEC */ + +/* path for current file */ +static char path_buffer[MAX_PATH]; + +/** Automatic Gain Control (AGC) **/ +#ifdef HAVE_AGC +/* Timing counters: + * peak_time is incremented every 0.2s, every 2nd run of record screen loop. + * hist_time is incremented every 0.5s, display update. + * peak_time is the counter of the peak hold read and agc process, + * overflow every 13 years 8-) + */ + +static long peak_time = 0; +static short peak_valid_mem[4]; +static long hist_time = 0; + +#define BAL_MEM_SIZE 24 +static short balance_mem[BAL_MEM_SIZE]; + +/* Automatic Gain Control */ +#define AGC_MODE_SIZE 5 +#define AGC_SAFETY_MODE 0 + +static const char* agc_preset_str[] = +{ "Off", "S", "L", "D", "M", "V" }; +/* "Off", + "Safety (clip)", + "Live (slow)", + "DJ-Set (slow)", + "Medium", + "Voice (fast)" */ +#define AGC_CLIP 32766 +#define AGC_PEAK 29883 /* fast gain reduction threshold -0.8dB */ +#define AGC_HIGH 27254 /* accelerated gain reduction threshold -1.6dB */ +#define AGC_IMG 823 /* threshold for balance control -32dB */ +/* autogain high level thresholds (-3dB, -7dB, -4dB, -5dB, -5dB) */ +static const short agc_th_hi[AGC_MODE_SIZE] = +{ 23197, 14637, 21156, 18428, 18426 }; +/* autogain low level thresholds (-14dB, -11dB, -6dB, -7dB, -8dB) */ +static const short agc_th_lo[AGC_MODE_SIZE] = +{ 6538, 9235, 16422, 14636, 13045 }; +/* autogain threshold times [1/5s] or [200ms] */ +static const short agc_tdrop[AGC_MODE_SIZE] = +{ 900, 225, 150, 60, 8 }; +static const short agc_trise[AGC_MODE_SIZE] = +{ 9000, 750, 400, 150, 20 }; +static const short agc_tbal[AGC_MODE_SIZE] = +{ 4500, 500, 300, 100, 15 }; +/* AGC operation */ +static bool agc_enable = true; +static short agc_preset; +/* AGC levels */ +static int agc_left = 0; +static int agc_right = 0; +/* AGC time since high target volume was exceeded */ +static short agc_droptime = 0; +/* AGC time since volume fallen below low target */ +static short agc_risetime = 0; +/* AGC balance time exceeding +/- 0.7dB */ +static short agc_baltime = 0; +/* AGC maximum gain */ +static short agc_maxgain; +#endif /* HAVE_AGC */ + +/* Histogram data, only for bigger screens */ +#ifdef HAVE_HISTOGRAM +#define HIST_Y (LCD_HEIGHT - 1) +#define HIST_W (LCD_WIDTH / 2 - 4) +static short history_mode; +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]; +#if LCD_DEPTH > 1 +#ifdef HAVE_LCD_COLOR +#define LCD_BATT_OK LCD_RGBPACK(63, 63, 63) +#define LCD_BATT_LO LCD_RGBPACK(159, 0, 0) +#define LCD_DISK_OK LCD_RGBPACK(0, 0, 143) +#define LCD_DISK_LO LCD_RGBPACK(127, 0, 0) +#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 +#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 +#else +#define LCD_HIST_OVER LCD_DEFAULT_FG +#define LCD_HIST_OK LCD_DEFAULT_FG +#define LCD_BAL LCD_DEFAULT_FG +#endif +#endif /* HAVE_HISTOGRAM */ + +static void set_gain(void) +{ + if(global_settings.rec_source == AUDIO_SRC_MIC) + { + audio_set_recording_gain(global_settings.rec_mic_gain, + 0, AUDIO_GAIN_MIC); + } + else + { + /* AUDIO_SRC_LINEIN, AUDIO_SRC_FMRADIO, AUDIO_SRC_SPDIF */ + audio_set_recording_gain(global_settings.rec_left_gain, + global_settings.rec_right_gain, + AUDIO_GAIN_LINEIN); + } + /* reset the clipping indicators */ + peak_meter_set_clip_hold(global_settings.peak_meter_clip_hold); +} + +#ifdef HAVE_AGC +/* Read peak meter values & calculate balance. + * Returns validity of peak values. + * Used for automatic gain control and history diagram. + */ +static bool read_peak_levels(int *peak_l, int *peak_r, int *balance) +{ + peak_meter_get_peakhold(peak_l, peak_r); + peak_valid_mem[peak_time % 3] = *peak_l; + if (((peak_valid_mem[0] == peak_valid_mem[1]) && + (peak_valid_mem[1] == peak_valid_mem[2])) && + ((*peak_l < 32767) || ata_disk_is_active())) + return false; + + if (*peak_r > *peak_l) + balance_mem[peak_time % BAL_MEM_SIZE] = (*peak_l ? + MIN((10000 * *peak_r) / *peak_l - 10000, 15118) : 15118); + else + balance_mem[peak_time % BAL_MEM_SIZE] = (*peak_r ? + MAX(10000 - (10000 * *peak_l) / *peak_r, -15118) : -15118); + *balance = 0; + int i; + for (i = 0; i < BAL_MEM_SIZE; i++) + *balance += balance_mem[i]; + *balance = *balance / BAL_MEM_SIZE; +#ifdef HAVE_HISTOGRAM + if (*peak_l > hist_l) + hist_l = *peak_l; + if (*peak_r > hist_r) + hist_r = *peak_r; +#endif + + return true; +} + +/* AGC helper function to check if maximum gain is reached */ +static bool agc_gain_is_max(bool left, bool right) +{ + /* range -128...+108 [0.5dB] */ + short gain_current_l; + short gain_current_r; + + if (agc_preset == 0) + return false; + + switch (global_settings.rec_source) + { + HAVE_LINE_REC_(case AUDIO_SRC_LINEIN:) + HAVE_FMRADIO_REC_(case AUDIO_SRC_FMRADIO:) + gain_current_l = global_settings.rec_left_gain; + gain_current_r = global_settings.rec_right_gain; + break; + case AUDIO_SRC_MIC: + default: + gain_current_l = global_settings.rec_mic_gain; + gain_current_r = global_settings.rec_mic_gain; + } + + return ((left && (gain_current_l >= agc_maxgain)) || + (right && (gain_current_r >= agc_maxgain))); +} + +static void change_recording_gain(bool increment, bool left, bool right) +{ + int factor = (increment ? 1 : -1); + + switch (global_settings.rec_source) + { + HAVE_LINE_REC_(case AUDIO_SRC_LINEIN:) + HAVE_FMRADIO_REC_(case AUDIO_SRC_FMRADIO:) + if (left) global_settings.rec_left_gain += factor; + if (right) global_settings.rec_right_gain += factor; + break; + case AUDIO_SRC_MIC: + global_settings.rec_mic_gain += factor; + } +} + +/* + * Handle automatic gain control (AGC). + * Change recording gain if peak_x levels are above or below + * target volume for specified timeouts. + */ +static void auto_gain_control(int *peak_l, int *peak_r, int *balance) +{ + int agc_mono; + short agc_mode; + bool increment; + + if (*peak_l > agc_left) + agc_left = *peak_l; + else + agc_left -= (agc_left - *peak_l + 3) >> 2; + if (*peak_r > agc_right) + agc_right = *peak_r; + else + agc_right -= (agc_right - *peak_r + 3) >> 2; + agc_mono = (agc_left + agc_right) / 2; + + agc_mode = abs(agc_preset) - 1; + if (agc_mode < 0) { + agc_enable = false; + return; + } + + if (agc_mode != AGC_SAFETY_MODE) { + /* Automatic balance control - only if not in safety mode */ + if ((agc_left > AGC_IMG) && (agc_right > AGC_IMG)) + { + if (*balance < -556) + { + if (*balance > -900) + agc_baltime -= !(peak_time % 4); /* 0.47 - 0.75dB */ + else if (*balance > -4125) + agc_baltime--; /* 0.75 - 3.00dB */ + else if (*balance > -7579) + agc_baltime -= 2; /* 3.00 - 4.90dB */ + else + agc_baltime -= !(peak_time % 8); /* 4.90 - inf dB */ + if (agc_baltime > 0) + agc_baltime -= (peak_time % 2); + } + else if (*balance > 556) + { + if (*balance < 900) + agc_baltime += !(peak_time % 4); + else if (*balance < 4125) + agc_baltime++; + else if (*balance < 7579) + agc_baltime += 2; + else + agc_baltime += !(peak_time % 8); + if (agc_baltime < 0) + agc_baltime += (peak_time % 2); + } + + if ((*balance * agc_baltime) < 0) + { + if (*balance < 0) + agc_baltime -= peak_time % 2; + else + agc_baltime += peak_time % 2; + } + + increment = ((agc_risetime / 2) > agc_droptime); + + if (agc_baltime < -agc_tbal[agc_mode]) + { + if (!increment || !agc_gain_is_max(!increment, increment)) { + change_recording_gain(increment, !increment, increment); + set_gain(); + } + agc_baltime = 0; + } + else if (agc_baltime > +agc_tbal[agc_mode]) + { + if (!increment || !agc_gain_is_max(increment, !increment)) { + change_recording_gain(increment, increment, !increment); + set_gain(); + } + agc_baltime = 0; + } + } + else if (!(hist_time % 4)) + { + if (agc_baltime < 0) + agc_baltime++; + else + agc_baltime--; + } + } + + /* Automatic gain control */ + if ((agc_left > agc_th_hi[agc_mode]) || (agc_right > agc_th_hi[agc_mode])) + { + if ((agc_left > AGC_CLIP) || (agc_right > AGC_CLIP)) + agc_droptime += agc_tdrop[agc_mode] / + (global_settings.rec_agc_cliptime + 1); + if (agc_left > AGC_HIGH) { + agc_droptime++; + agc_risetime=0; + if (agc_left > AGC_PEAK) + agc_droptime += 2; + } + if (agc_right > AGC_HIGH) { + agc_droptime++; + agc_risetime=0; + if (agc_right > AGC_PEAK) + agc_droptime += 2; + } + if (agc_mono > agc_th_hi[agc_mode]) + agc_droptime++; + else + agc_droptime += !(peak_time % 2); + + if (agc_droptime >= agc_tdrop[agc_mode]) + { + change_recording_gain(false, true, true); + agc_droptime = 0; + agc_risetime = 0; + set_gain(); + } + agc_risetime = MAX(agc_risetime - 1, 0); + } + else if (agc_mono < agc_th_lo[agc_mode]) + { + if (agc_mono < (agc_th_lo[agc_mode] / 8)) + agc_risetime += !(peak_time % 5); + else if (agc_mono < (agc_th_lo[agc_mode] / 2)) + agc_risetime += 2; + else + agc_risetime++; + + if (agc_risetime >= agc_trise[agc_mode]) { + if ((agc_mode != AGC_SAFETY_MODE) && + (!agc_gain_is_max(true, true))) { + change_recording_gain(true, true, true); + set_gain(); + } + agc_risetime = 0; + agc_droptime = 0; + } + agc_droptime = MAX(agc_droptime - 1, 0); + } + else if (!(peak_time % 6)) /* on target level every 1.2 sec */ + { + agc_risetime = MAX(agc_risetime - 1, 0); + agc_droptime = MAX(agc_droptime - 1, 0); + } +} +#endif /* HAVE_AGC */ + +static const char* const fmtstr[] = +{ + "%c%d %s", /* no decimals */ + "%c%d.%d %s ", /* 1 decimal */ + "%c%d.%02d %s " /* 2 decimals */ +}; + +static char *fmt_gain(int snd, int val, char *str, int len) +{ + int i, d, numdec; + const char *unit; + char sign = ' '; + + val = sound_val2phys(snd, val); + if(val < 0) + { + sign = '-'; + val = -val; + } + numdec = sound_numdecimals(snd); + unit = sound_unit(snd); + + if(numdec) + { + i = val / (10*numdec); + d = val % (10*numdec); + snprintf(str, len, fmtstr[numdec], sign, i, d, unit); + } + else + snprintf(str, len, fmtstr[numdec], sign, val, unit); + + return str; +} + +static int cursor; + +static void adjust_cursor(void) +{ + int max_cursor; + + if(cursor < 0) { + cursor = 0; +#ifdef HAVE_HISTOGRAM + int i; + history_mode++; + if (history_mode == 2) { + for (i=0; i < HIST_W; i++) { + history_l[i] = history_l[i] * 2; + history_r[i] = history_r[i] * 2; + } + } else if (history_mode == 4) { + for (i=0; i < HIST_W; i++) { + history_l[i] = history_l[i] / 2; + history_r[i] = history_r[i] / 2; + } + history_mode = 0; + } +#endif + } + +#ifdef HAVE_AGC + switch(global_settings.rec_source) + { + case REC_SRC_MIC: + if(cursor == 2) + cursor = 4; + else if(cursor == 3) + cursor = 1; + HAVE_LINE_REC_(case AUDIO_SRC_LINEIN:) + HAVE_FMRADIO_REC_(case AUDIO_SRC_FMRADIO:) + max_cursor = 5; + break; + default: + max_cursor = 0; + break; + } +#else /* !HAVE_AGC */ + switch(global_settings.rec_source) + { + case AUDIO_SRC_MIC: + max_cursor = 1; + break; + HAVE_LINE_REC_(case AUDIO_SRC_LINEIN:) + HAVE_FMRADIO_REC_(case AUDIO_SRC_FMRADIO:) + max_cursor = 3; + break; + default: + max_cursor = 0; + break; + } +#endif /* HAVE_AGC */ + + if(cursor > max_cursor) + cursor = max_cursor; +} + +/* the list below must match enum audio_sources in audio.h */ +static const char* const prestr[] = +{ + HAVE_MIC_IN_([AUDIO_SRC_MIC] = "R_MIC_",) + HAVE_LINE_REC_([AUDIO_SRC_LINEIN] = "R_LINE_",) + HAVE_SPDIF_IN_([AUDIO_SRC_SPDIF] = "R_SPDIF_",) + HAVE_FMRADIO_REC_([AUDIO_SRC_FMRADIO] = "R_FM_",) +}; + +char *rec_create_filename(char *buffer) +{ + char ext[16]; + const char *pref = "R_"; + + /* Directory existence and writeablility should have already been + * verified - do not pass NULL pointers to pcmrec */ + + if((unsigned)global_settings.rec_source < AUDIO_NUM_SOURCES) + { + pref = prestr[global_settings.rec_source]; + } + + strcpy(buffer, global_settings.rec_directory); + + snprintf(ext, sizeof(ext), ".%s", + REC_FILE_ENDING(global_settings.rec_format)); + +#if CONFIG_RTC == 0 + return create_numbered_filename(buffer, buffer, pref, ext, 4, + &file_number); +#else + /* We'll wait at least up to the start of the next second so no duplicate + names are created */ + return create_datetime_filename(buffer, buffer, pref, ext, true); +#endif +} + +#if CONFIG_RTC == 0 +/* Hit disk to get a starting filename for the type */ +static void rec_init_filename(void) +{ + file_number = -1; + rec_create_filename(path_buffer); + file_number--; +} +#endif + +int rec_create_directory(void) +{ + int rc = 0; + const char * const folder = global_settings.rec_directory; + + if (strcmp(folder, "/") && !dir_exists(folder)) + { + rc = mkdir(folder); + + if(rc < 0) + { + while (action_userabort(HZ) == false) + { + gui_syncsplash(0, "%s %s", + str(LANG_REC_DIR_NOT_WRITABLE), + str(LANG_OFF_ABORT)); + } + } + else + { + rec_status |= RCSTAT_CREATED_DIRECTORY; + rc = 1; + } + } + + return rc; +} + +void rec_init_recording_options(struct audio_recording_options *options) +{ + options->rec_source = global_settings.rec_source; + options->rec_frequency = global_settings.rec_frequency; + options->rec_channels = global_settings.rec_channels; + options->rec_prerecord_time = global_settings.rec_prerecord_time; +#if CONFIG_CODEC == SWCODEC + options->rec_source_flags = 0; + options->enc_config.rec_format = global_settings.rec_format; + global_to_encoder_config(&options->enc_config); +#else + options->rec_quality = global_settings.rec_quality; + options->rec_editable = global_settings.rec_editable; +#endif +} + +#if CONFIG_CODEC == SWCODEC && !defined (SIMULATOR) +void rec_set_source(int source, unsigned flags) +{ + /* Set audio input source, power up/down devices */ + audio_set_input_source(source, flags); + + /* Set peakmeters for recording or reset to playback */ + peak_meter_playback((flags & SRCF_RECORDING) == 0); + peak_meter_enabled = true; +} +#endif /* CONFIG_CODEC == SWCODEC && !defined (SIMULATOR) */ + +void rec_set_recording_options(struct audio_recording_options *options) +{ +#if CONFIG_CODEC != SWCODEC + if (global_settings.rec_prerecord_time) + { + talk_buffer_steal(); /* will use the mp3 buffer */ + } +#else /* == SWCODEC */ + rec_set_source(options->rec_source, + options->rec_source_flags | SRCF_RECORDING); +#endif /* CONFIG_CODEC != SWCODEC */ + + audio_set_recording_options(options); +} + +void rec_command(enum recording_command cmd) +{ + switch(cmd) + { + case RECORDING_CMD_STOP_SHUTDOWN: + pm_activate_clipcount(false); + audio_stop_recording(); +#if CONFIG_CODEC == SWCODEC + audio_close_recording(); +#endif + sys_poweroff(); + break; + case RECORDING_CMD_STOP: + pm_activate_clipcount(false); + audio_stop_recording(); + break; + case RECORDING_CMD_START: + /* steal mp3 buffer, create unique filename and start recording */ + pm_reset_clipcount(); + pm_activate_clipcount(true); +#if CONFIG_CODEC != SWCODEC + talk_buffer_steal(); /* we use the mp3 buffer */ +#endif + audio_record(rec_create_filename(path_buffer)); + break; + case RECORDING_CMD_START_NEWFILE: + /* create unique filename and start recording*/ + pm_reset_clipcount(); + pm_activate_clipcount(true); /* just to be sure */ + audio_new_file(rec_create_filename(path_buffer)); + break; + case RECORDING_CMD_PAUSE: + pm_activate_clipcount(false); + audio_pause_recording(); + break; + case RECORDING_CMD_RESUME: + pm_activate_clipcount(true); + audio_resume_recording(); + break; + } +} + +/* used in trigger_listerner and recording_screen */ +static unsigned int last_seconds = 0; + +/** + * Callback function so that the peak meter code can send an event + * to this application. This function can be passed to + * peak_meter_set_trigger_listener in order to activate the trigger. + */ +static void trigger_listener(int trigger_status) +{ + switch (trigger_status) + { + case TRIG_GO: + if(!(audio_status() & AUDIO_STATUS_RECORD)) + { + rec_status |= RCSTAT_HAVE_RECORDED; + rec_command(RECORDING_CMD_START); +#if CONFIG_CODEC != SWCODEC + /* give control to mpeg thread so that it can start + recording */ + yield(); yield(); yield(); +#endif + } + + /* if we're already recording this is a retrigger */ + else + { + if((audio_status() & AUDIO_STATUS_PAUSE) && + (global_settings.rec_trigger_type == TRIG_TYPE_PAUSE)) + { + rec_command(RECORDING_CMD_RESUME); + } + /* New file on trig start*/ + else if (global_settings.rec_trigger_type != TRIG_TYPE_NEW_FILE) + { + rec_command(RECORDING_CMD_START_NEWFILE); + /* tell recording_screen to reset the time */ + last_seconds = 0; + } + } + break; + + /* A _change_ to TRIG_READY means the current recording has stopped */ + case TRIG_READY: + if(audio_status() & AUDIO_STATUS_RECORD) + { + switch(global_settings.rec_trigger_type) + { + case TRIG_TYPE_STOP: /* Stop */ + rec_command(RECORDING_CMD_STOP); + break; + + case TRIG_TYPE_PAUSE: /* Pause */ + rec_command(RECORDING_CMD_PAUSE); + break; + + case TRIG_TYPE_NEW_FILE: /* New file on trig stop*/ + rec_command(RECORDING_CMD_START_NEWFILE); + /* tell recording_screen to reset the time */ + last_seconds = 0; + break; + + case 3: /* Stop and shutdown */ + rec_command(RECORDING_CMD_STOP_SHUTDOWN); + break; + } + + if (global_settings.rec_trigger_mode != TRIG_MODE_REARM) + { + peak_meter_set_trigger_listener(NULL); + peak_meter_trigger(false); + } + } + break; + } +} + +/* countdown timer tick task */ +void timer_tick_task(void) +{ + static int mini_tick = 0; + + mini_tick ++; + /* the countdown */ + if ((mini_tick >= HZ) && (timer.countdown)) + { + mini_tick = 0; + if (timer.secs) timer.secs -= 1; + else{ + timer.secs = 59; + if (timer.mins) timer.mins -= 1; + else{ + timer.mins = 59; + if (timer.hrs) timer.hrs -= 1; + else{ + timer.hrs = 23; + if (timer.days) timer.days -= 1; + else{ + timer.days = timer.hrs = timer.mins = timer.secs = 0; + /* switch timer display on/off when countdown finished */ + timer.timer_display = !timer.timer_display; + } + } + } + } + } +} + +bool recording_start_automatic = false; + +bool recording_screen(bool no_source) +{ + long button; + bool done = false; + char buf[32]; + char buf2[32]; + int w[NB_SCREENS], h[NB_SCREENS]; + int font[NB_SCREENS]; + int pm_h[NB_SCREENS]; + int update_countdown = 1; +#ifndef SIMULATOR + bool disk_was_active = false; + bool warn_message = true; +#endif + unsigned long disk_free; + int bitrate; + int disk_time = 0; + unsigned int seconds, prerec = 0; + int hours, minutes; + char filename[13]; + int last_audio_stat = -1; + int audio_stat; +#if CONFIG_CODEC == SWCODEC + int warning_counter = 0; + #define WARNING_PERIOD 7 +#endif +#ifdef HAVE_FMRADIO_REC + /* Radio is left on if: + * 1) Is was on at the start and the initial source is FM Radio + * 2) 1) and the source was never changed to something else + */ + int radio_status = (global_settings.rec_source != AUDIO_SRC_FMRADIO) ? + FMRADIO_OFF : get_radio_status(); +#endif +#if (CONFIG_LED == LED_REAL) + bool led_state = false; + int led_countdown = 2; +#endif +#ifdef HAVE_AGC + bool peak_valid = false; + int balance = 0; + bool peak_read = false; + int peak_l, peak_r; + bool display_agc[NB_SCREENS]; +#endif + int line[NB_SCREENS]; + int i; + int filename_offset[NB_SCREENS]; + int pm_y[NB_SCREENS]; + int trig_xpos[NB_SCREENS]; + int trig_ypos[NB_SCREENS]; + int trig_width[NB_SCREENS]; + /* pm_x = offset pm to put clipcount in front. + Use lcd_getstringsize() when not using SYSFONT */ + int pm_x = global_settings.peak_meter_clipcounter ? 30 : 0; + int agc_line = 0; + bool histogram_on = global_settings.hist_def; + bool font_check = true; + int pm_height[NB_SCREENS]; + int countdown_offset = 0; + bool repeat_timer_start = false; + unsigned int repeat_timer; + + static const unsigned char *byte_units[] = { + ID2P(LANG_BYTE), + ID2P(LANG_KILOBYTE), + ID2P(LANG_MEGABYTE), + ID2P(LANG_GIGABYTE) + }; + + int base_style = STYLE_INVERT; + int style; + struct viewport vp[NB_SCREENS]; + int ymargin = global_settings.cursor_style?0:10; +#ifdef HAVE_LCD_COLOR + if (global_settings.cursor_style == 2) { + base_style |= STYLE_COLORBAR; + } + else if (global_settings.cursor_style == 3) { + base_style |= STYLE_GRADIENT; + } +#endif + + struct audio_recording_options rec_options; + rec_status = RCSTAT_IN_RECSCREEN; + + if (rec_create_directory() < 0) + { + rec_status = 0; + return false; + } + + /* Stop countdown if countdown settings changed */ + if (!timer.countdown) + tick_remove_task(timer_tick_task); + +#ifdef HAVE_AGC + memset(balance_mem, 0x00, BAL_MEM_SIZE); +#endif + +#ifdef HAVE_HISTOGRAM + int history_pos = 0; + int hist_height; + const short hist_size_h[2] = {17, 31}; + /* + * Peak histogram linear to logarithmic [dB] table. + * The thresholds are scaled between the corresponding + * dispayed values, e.g. -6dB is -5.5dB < level <= 6.5dB + */ + const short hist_peak_lin2dB[2][31] = + { + /* 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 }, + /* 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[4][6] = + { + /* linear: 0, -6, -12, -24, -inf [dB] */ + { 15, 8, 4, 1, 0, 0}, + /* logarithmic: 0, -6, -12, -24, -48 [dB] */ + { 15, 12, 9, 4, 1, 1}, + /* linear: 0, -3, -6, -12, -24, -inf [dB] */ + { 29, 21, 15, 7, 2, 0}, + /* logarithmic: 0, -3, -6, -12, -24, -48 [dB] */ + { 29, 26, 23, 17, 9, 2} + }; + 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 unsigned char rec_icons_6x8[][6] = + { + {0x00,0x1c,0x3e,0x36,0x3e,0x1c} + }; + enum icons_6x8 + { + Icon_Disk, + Icon_6x8end + }; + + memset(history_l, 0x00, sizeof(history_l)); + memset(history_r, 0x00, sizeof(history_r)); +#endif /* HAVE_HISTOGRAM */ + + cursor = 0; +#if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR) + ata_set_led_enabled(false); +#endif + +#if CONFIG_CODEC == SWCODEC + /* recording_menu gets messed up: so prevent manus talking */ + talk_disable(true); + /* audio_init_recording stops anything playing when it takes the audio + buffer */ +#else + /* Yes, we use the D/A for monitoring */ + peak_meter_enabled = true; + peak_meter_playback(true); +#endif + gui_syncsplash(1, "%s...", str(LANG_RECORDING)); + audio_init_recording(0); + sound_set_volume(global_settings.volume); + +#ifdef HAVE_AGC + peak_meter_get_peakhold(&peak_l, &peak_r); +#endif + + rec_init_recording_options(&rec_options); + rec_set_recording_options(&rec_options); + + set_gain(); + +#if CONFIG_RTC == 0 + /* Create new filename for recording start */ + rec_init_filename(); +#endif + + pm_reset_clipcount(); + pm_activate_clipcount(false); + settings_apply_trigger(); + +#ifdef HAVE_AGC + agc_preset_str[0] = str(LANG_SYSFONT_OFF); + agc_preset_str[1] = str(LANG_SYSFONT_AGC_SAFETY); + agc_preset_str[2] = str(LANG_SYSFONT_AGC_LIVE); + agc_preset_str[3] = str(LANG_SYSFONT_AGC_DJSET); + agc_preset_str[4] = str(LANG_SYSFONT_AGC_MEDIUM); + agc_preset_str[5] = str(LANG_SYSFONT_AGC_VOICE); + if (global_settings.rec_source == AUDIO_SRC_MIC) { + agc_preset = global_settings.rec_agc_preset_mic; + agc_maxgain = global_settings.rec_agc_maxgain_mic; + } + else { + agc_preset = global_settings.rec_agc_preset_line; + agc_maxgain = global_settings.rec_agc_maxgain_line; + } +#endif /* HAVE_AGC */ +//check + FOR_NB_SCREENS(i) + { + viewport_set_defaults(&vp[i], i); + vp[i].font = FONT_SYSFIXED; + screens[i].set_viewport(&vp[i]); + } + +#ifdef HAVE_REMOTE_LCD + if (!remote_display_on) + { + screens[1].clear_display(); + snprintf(buf, sizeof(buf), str(LANG_REMOTE_LCD_ON)); +// screens[1].puts((vp[1].width/w - strlen(buf))/2 + 1, +// vp[1].height/(h*2) + 1, buf); + screens[1].puts((vp[1].width/w[1] - strlen(buf))/2 + 1, + vp[1].height/(h[1]*2) + 1, buf); + screens[1].update(); + gui_syncsplash(0, str(LANG_REMOTE_LCD_OFF)); + } +#endif + + /* store the free disk space for this session [MBytes] */ + fat_size(IF_MV2(0,) NULL, &disk_free); /* free KBytes */ + disk_free = disk_free / 1024; + if (disk_free > disk_space) + disk_space = disk_free; + bitrate = 1411; /* [kbps] default for 44kHz stereo 16bit WAV */ + +#ifdef HAVE_HISTOGRAM + history_mode = global_settings.rec_histogram_mode; + hist_time_interval = 1 << global_settings.rec_histogram_interval; +#endif + + while(!done) + { + switch(global_settings.rec_source) + { + case AUDIO_SRC_LINEIN: +#ifdef HAVE_FMRADIO_IN + case AUDIO_SRC_FMRADIO: +#endif + FOR_NB_SCREENS(i) + line[i] = 5; + agc_line = 1; + break; + case AUDIO_SRC_MIC: + FOR_NB_SCREENS(i) + line[i] = 4; + agc_line = 1; + break; +#ifdef HAVE_SPDIF_IN + case AUDIO_SRC_SPDIF: + FOR_NB_SCREENS(i) + line[i] = 3; + agc_line = 0; /* no agc line for Spdif in */ + break; +#endif + default: + FOR_NB_SCREENS(i) + line[i] = 5; + break; + } + /* check and change font only if source has been changed */ + if (font_check) + { + FOR_NB_SCREENS(i) + pm_height[i] = global_settings.peak_size + 1; + + FOR_NB_SCREENS(i) + { +//check +// filename_offset[i] = ((screens[i].height >= 80) ? 1 : 0); + filename_offset[i] = ((vp[i].height >= 80) ? 1 : 0); + + while(vp[i].height < (line[i] + 1 + filename_offset[i] + pm_height[i]) * 8) + { + pm_height[i] -= 1; + if (pm_height[i] < 1) + { pm_height[i] = 1; + break; + } + } + + screens[i].setfont(FONT_UI); + screens[i].getstringsize("M", &w[i], &h[i]); + + if (i == SCREEN_MAIN) { + if (h[i] <= ((LCD_HEIGHT - (histogram_on ? 25 : 8)) / (line[i] + + filename_offset[0] + pm_height[i] + agc_line))) + font[i] = FONT_UI; + else + font[i] = FONT_SYSFIXED; + } + else if (h[i] <= ((vp[i].height - 8) / (line[i] + filename_offset[i] + pm_height[i]))) + font[i] = FONT_UI; + else + font[i] = FONT_SYSFIXED; + + screens[i].setfont(font[i]); + screens[i].getstringsize("M", &w[i], &h[i]); +// screens[i].setmargins(global_settings.invert_cursor ? 0 : w[i], 8); + if (h[i] > 8) { + pm_y[i] = 9 + h[i] * (2 + filename_offset[i]); + pm_h[i] = (h[i] - 1) * pm_height[i]; + } + else { + pm_y[i] = 8 + h[i] * (2 + filename_offset[i]); + pm_h[i] = h[i] * pm_height[i]; + } + } + font_check = false; + } + + + audio_stat = audio_status(); + +#if (CONFIG_LED == LED_REAL) + + /* + * Flash the LED while waiting to record. Turn it on while + * recording. + */ + if(audio_stat & AUDIO_STATUS_RECORD) + { + if (audio_stat & AUDIO_STATUS_PAUSE) + { + if (--led_countdown <= 0) + { + led_state = !led_state; + led(led_state); + led_countdown = 2; + } + } + else + { + /* trigger is on in status TRIG_READY (no check needed) */ + led(true); + } + } + else + { + int trigStat = peak_meter_trigger_status(); + /* + * other trigger stati than trig_off and trig_steady + * already imply that we are recording. + */ + if (trigStat == TRIG_STEADY) + { + if (--led_countdown <= 0) + { + led_state = !led_state; + led(led_state); + led_countdown = 2; + } + } + else + { + /* trigger is on in status TRIG_READY (no check needed) */ + led(false); + } + } +#endif /* CONFIG_LED */ + + /* Wait for a button a while (HZ/10) drawing the peak meter */ +// button = peak_meter_draw_get_btn(CONTEXT_RECSCREEN, + button = peak_meter_draw_get_btn(0, + pm_x, pm_y, pm_h, + screen_update); +//- button = peak_meter_draw_get_btn(0, pm_y, h * PM_HEIGHT, screen_update); +//+ button = peak_meter_draw_get_btn(0, pm_y, pm_h, screen_update); + if (last_audio_stat != audio_stat) + { + if (audio_stat & AUDIO_STATUS_RECORD) + { + rec_status |= RCSTAT_HAVE_RECORDED; + } + last_audio_stat = audio_stat; + } + + if (recording_start_automatic) + { + /* simulate a button press */ + button = ACTION_REC_PAUSE; + recording_start_automatic = false; + } + + /* repeat_timer is the repeat time in seconds */ + repeat_timer = (timer.mins_rpt * 60 + timer.hrs_rpt * + 3600 + timer.days_rpt * 3600 * 24); + + /* decide on repeat timer status */ + if ((repeat_timer > rec_timesplit_seconds()) && + global_settings.rec_timesplit) + timer.repeater = true; + else + timer.repeater = false; + + /* When countdown timer reaches zero fake a new file button press */ + if (timer.countdown && !timer.days && !timer.hrs && !timer.mins && + !timer.secs) + { + tick_remove_task(timer_tick_task); + button = ACTION_REC_NEWFILE; + timer.countdown = false; + } + + switch(button) + { +#ifdef HAVE_REMOTE_LCD + case ACTION_REC_HIST_TOGGLE: + histogram_on = !histogram_on; + font_check = true; + break; + case ACTION_REC_LCD: + if (remote_display_on) + { + remote_display_on = false; + screen_update = 1; + screens[1].clear_display(); + snprintf(buf, sizeof(buf), str(LANG_REMOTE_LCD_ON)); +//check +// screens[1].puts((screens[1].getwidth()/w - strlen(buf))/2 + +// 1, +// screens[1].getheight()/(h*2) + 1, buf); + screens[1].puts((screens[1].getwidth()/w[1] - strlen(buf))/2 + 1, + screens[1].getheight()/(h[1]*2) + 1, buf); + screens[1].update(); + gui_syncsplash(0, str(LANG_REMOTE_LCD_OFF)); + } + else + { + remote_display_on = true; + screen_update = NB_SCREENS; + } + break; +#endif + case ACTION_STD_CANCEL: + /* turn off the trigger */ + peak_meter_trigger(false); + peak_meter_set_trigger_listener(NULL); + + if(audio_stat & AUDIO_STATUS_RECORD) + { + rec_command(RECORDING_CMD_STOP); + } + else + { +#if CONFIG_CODEC != SWCODEC + peak_meter_playback(true); + peak_meter_enabled = false; +#endif + done = true; + } + update_countdown = 1; /* Update immediately */ + break; + + case ACTION_REC_PAUSE: + case ACTION_REC_NEWFILE: + /* Only act if the mpeg is stopped */ + if(!(audio_stat & AUDIO_STATUS_RECORD)) + { /* if countdown timer is set, start countdown */ + if (timer.days || timer.hrs || timer.mins || timer.secs) + { + if (button == ACTION_REC_PAUSE) + { + timer.countdown = !timer.countdown; + if (timer.countdown) + tick_add_task(timer_tick_task); + else + tick_remove_task(timer_tick_task); + break; + } + else + { + /* if newfile button pressed and countdown timer is on, + start new file and reset timer */ + tick_remove_task(timer_tick_task); + timer.days = timer.hrs = timer.mins = timer.secs = 0; + timer.countdown = false; + } + } + /* is this manual or triggered recording? */ + if ((global_settings.rec_trigger_mode == TRIG_MODE_OFF) || + (peak_meter_trigger_status() != TRIG_OFF)) + { + /* manual recording */ + rec_status |= RCSTAT_HAVE_RECORDED; + rec_command(RECORDING_CMD_START); + repeat_timer_start = true; /* allow access to repeat timer + code */ + /* amount of file that has been prerecorded - needed for + syncing repeat timer */ + prerec = audio_recorded_time() / HZ; + last_seconds = 0; + if (global_settings.talk_menu) + { + /* no voice possible here, but a beep */ + audio_beep(HZ/2); /* longer beep on start */ + } + } + /* this is triggered recording */ + else + { + /* we don't start recording now, but enable the + trigger and let the callback function + trigger_listener control when the recording starts */ + peak_meter_trigger(true); + peak_meter_set_trigger_listener(&trigger_listener); + } + } + else + { + /*if new file button pressed, start new file */ + if (button == ACTION_REC_NEWFILE) + { + rec_command(RECORDING_CMD_START_NEWFILE); + last_seconds = 0; + } + else + /* if pause button pressed, pause or resume */ + { + if(audio_stat & AUDIO_STATUS_PAUSE) + { + rec_command(RECORDING_CMD_RESUME); + if (global_settings.talk_menu) + { + /* no voice possible here, but a beep */ + audio_beep(HZ/4); /* short beep on resume */ + } + } + else + { + rec_command(RECORDING_CMD_PAUSE); + } + } + } + update_countdown = 1; /* Update immediately */ + break; + + case ACTION_STD_PREV: + cursor--; + adjust_cursor(); + update_countdown = 1; /* Update immediately */ + break; + + case ACTION_STD_NEXT: + cursor++; + adjust_cursor(); + update_countdown = 1; /* Update immediately */ + break; + + case ACTION_SETTINGS_INC: + case ACTION_SETTINGS_INCREPEAT: + switch(cursor) + { + case 0: + global_settings.volume++; + setvol(); + break; + case 1: + if(global_settings.rec_source == AUDIO_SRC_MIC) + { + if(global_settings.rec_mic_gain < + sound_max(SOUND_MIC_GAIN)) + global_settings.rec_mic_gain++; + } + else + { + if(global_settings.rec_left_gain < + sound_max(SOUND_LEFT_GAIN)) + global_settings.rec_left_gain++; + if(global_settings.rec_right_gain < + sound_max(SOUND_RIGHT_GAIN)) + global_settings.rec_right_gain++; + } + break; + case 2: + if(global_settings.rec_left_gain < + sound_max(SOUND_LEFT_GAIN)) + global_settings.rec_left_gain++; + break; + case 3: + if(global_settings.rec_right_gain < + sound_max(SOUND_RIGHT_GAIN)) + global_settings.rec_right_gain++; + break; +#ifdef HAVE_AGC + case 4: + agc_preset = MIN(agc_preset + 1, AGC_MODE_SIZE); + agc_enable = (agc_preset != 0); + if (global_settings.rec_source == AUDIO_SRC_MIC) { + global_settings.rec_agc_preset_mic = agc_preset; + agc_maxgain = global_settings.rec_agc_maxgain_mic; + } else { + global_settings.rec_agc_preset_line = agc_preset; + agc_maxgain = global_settings.rec_agc_maxgain_line; + } + break; + case 5: + if (global_settings.rec_source == AUDIO_SRC_MIC) + { + agc_maxgain = MIN(agc_maxgain + 1, + sound_max(SOUND_MIC_GAIN)); + global_settings.rec_agc_maxgain_mic = agc_maxgain; + } + else + { + agc_maxgain = MIN(agc_maxgain + 1, + sound_max(SOUND_LEFT_GAIN)); + global_settings.rec_agc_maxgain_line = agc_maxgain; + } + break; +#endif /* HAVE_AGC */ + } + set_gain(); + update_countdown = 1; /* Update immediately */ + break; + + case ACTION_SETTINGS_DEC: + case ACTION_SETTINGS_DECREPEAT: + switch(cursor) + { + case 0: + global_settings.volume--; + setvol(); + break; + case 1: + if(global_settings.rec_source == AUDIO_SRC_MIC) + { + if(global_settings.rec_mic_gain > + sound_min(SOUND_MIC_GAIN)) + global_settings.rec_mic_gain--; + } + else + { + if(global_settings.rec_left_gain > + sound_min(SOUND_LEFT_GAIN)) + global_settings.rec_left_gain--; + if(global_settings.rec_right_gain > + sound_min(SOUND_RIGHT_GAIN)) + global_settings.rec_right_gain--; + } + break; + case 2: + if(global_settings.rec_left_gain > + sound_min(SOUND_LEFT_GAIN)) + global_settings.rec_left_gain--; + break; + case 3: + if(global_settings.rec_right_gain > + sound_min(SOUND_RIGHT_GAIN)) + global_settings.rec_right_gain--; + break; +#ifdef HAVE_AGC + case 4: + agc_preset = MAX(agc_preset - 1, 0); + agc_enable = (agc_preset != 0); + if (global_settings.rec_source == AUDIO_SRC_MIC) { + global_settings.rec_agc_preset_mic = agc_preset; + agc_maxgain = global_settings.rec_agc_maxgain_mic; + } else { + global_settings.rec_agc_preset_line = agc_preset; + agc_maxgain = global_settings.rec_agc_maxgain_line; + } + break; + case 5: + if (global_settings.rec_source == AUDIO_SRC_MIC) + { + agc_maxgain = MAX(agc_maxgain - 1, + sound_min(SOUND_MIC_GAIN)); + global_settings.rec_agc_maxgain_mic = agc_maxgain; + } + else + { + agc_maxgain = MAX(agc_maxgain - 1, + sound_min(SOUND_LEFT_GAIN)); + global_settings.rec_agc_maxgain_line = agc_maxgain; + } + break; +#endif /* HAVE_AGC */ + } + set_gain(); + update_countdown = 1; /* Update immediately */ + break; + + case ACTION_STD_MENU: +#if CONFIG_CODEC == SWCODEC + if(!(audio_stat & AUDIO_STATUS_RECORD)) +#else + if(audio_stat != AUDIO_STATUS_RECORD) +#endif + { +#ifdef HAVE_FMRADIO_REC + const int prev_rec_source = global_settings.rec_source; +#endif +#if (CONFIG_LED == LED_REAL) + /* led is restored at begin of loop / end of function */ + led(false); +#endif + if (recording_menu(no_source)) + { + done = true; + rec_status |= RCSTAT_BEEN_IN_USB_MODE; +#ifdef HAVE_FMRADIO_REC + radio_status = FMRADIO_OFF; +#endif + } + else + { +#ifdef HAVE_FMRADIO_REC + /* If input changes away from FM Radio, radio will + remain off when recording screen closes. */ + if (global_settings.rec_source != prev_rec_source + && prev_rec_source == AUDIO_SRC_FMRADIO) + radio_status = FMRADIO_OFF; +#endif + /* if countdown timer settings changed in menu, + stop counting and reset */ + if (!timer.countdown) + tick_remove_task(timer_tick_task); + +#if CONFIG_CODEC == SWCODEC + /* reinit after submenu exit */ + audio_close_recording(); + audio_init_recording(0); +#endif + + rec_init_recording_options(&rec_options); + rec_set_recording_options(&rec_options); + + if(rec_create_directory() < 0) + { + goto rec_abort; + } + +#if CONFIG_CODEC == SWCODEC && CONFIG_RTC == 0 + /* If format changed, a new number is required */ + rec_init_filename(); +#endif + +#ifdef HAVE_AGC + if (global_settings.rec_source == AUDIO_SRC_MIC) { + agc_preset = global_settings.rec_agc_preset_mic; + agc_maxgain = global_settings.rec_agc_maxgain_mic; + } + else { + agc_preset = global_settings.rec_agc_preset_line; + agc_maxgain = global_settings.rec_agc_maxgain_line; + } +#endif + + adjust_cursor(); + set_gain(); + update_countdown = 1; /* Update immediately */ +#ifdef HAVE_HISTOGRAM + hist_time_interval = 1 << global_settings.rec_histogram_interval; +#endif + + FOR_NB_SCREENS(i) + { +//check + screens[i].set_viewport(&vp[i]); +// screens[i].setfont(FONT_SYSFIXED); + screens[i].setfont(font[i]); +// screens[i].setmargins(global_settings.invert_cursor ? 0 : w[i], 8); + } + } + font_check = true; + } + break; + + case ACTION_STD_SHORTCUTS: + if(audio_stat != AUDIO_STATUS_RECORD) + rockbox_browse("/_Shortcuts/",SHOW_SUPPORTED); + break; + +#if CONFIG_KEYPAD == RECORDER_PAD + case ACTION_REC_F2: + if(audio_stat != AUDIO_STATUS_RECORD) + { +#if (CONFIG_LED == LED_REAL) + /* led is restored at begin of loop / end of function */ + led(false); +#endif + if (f2_rec_screen()) + { + rec_status |= RCSTAT_HAVE_RECORDED; + done = true; + } + else + update_countdown = 1; /* Update immediately */ + } + break; + + case ACTION_REC_F3: + if(audio_stat & AUDIO_STATUS_RECORD) + { + rec_command(RECORDING_CMD_START_NEWFILE); + last_seconds = 0; + } + else + { +#if (CONFIG_LED == LED_REAL) + /* led is restored at begin of loop / end of function */ + led(false); +#endif + if (f3_rec_screen()) + { + rec_status |= RCSTAT_HAVE_RECORDED; + done = true; + } + else + update_countdown = 1; /* Update immediately */ + } + break; +#endif /* CONFIG_KEYPAD == RECORDER_PAD */ + + case SYS_USB_CONNECTED: + /* Only accept USB connection when not recording */ + if(!(audio_stat & AUDIO_STATUS_RECORD)) + { + default_event_handler(SYS_USB_CONNECTED); + done = true; + rec_status |= RCSTAT_BEEN_IN_USB_MODE; +#ifdef HAVE_FMRADIO_REC + radio_status = FMRADIO_OFF; +#endif + } + break; + + default: + default_event_handler(button); + break; + } /* end switch */ + + /* display timer status in status bar if countdown enabled */ + timer.timer_display = timer.countdown; + +#ifdef HAVE_AGC + peak_read = !peak_read; + if (peak_read) { /* every 2nd run of loop */ + peak_time++; + peak_valid = read_peak_levels(&peak_l, &peak_r, &balance); + } + + /* Handle AGC every 200ms when enabled and peak data is valid */ + if (peak_read && agc_enable && peak_valid) + auto_gain_control(&peak_l, &peak_r, &balance); +#endif + + FOR_NB_SCREENS(i) +// screens[i].setfont(FONT_SYSFIXED); + screens[i].setfont(font[i]); + + seconds = audio_recorded_time() / HZ; + + update_countdown--; + if(update_countdown == 0 || seconds > last_seconds) + { + unsigned int dseconds, dhours, dminutes; + unsigned long num_recorded_bytes, dsize, dmb; + int pos = 0; + + update_countdown = 5; + last_seconds = seconds; + + /* Get free disk space and calculate remain time */ + fat_size( IF_MV2(0,) NULL, &disk_free ); /* [KBytes] */ + disk_free = disk_free / 1024; + if (disk_free < MIN_DISK_SPACE) + disk_free = MIN_DISK_SPACE; + disk_free -= MIN_DISK_SPACE; + disk_time = 140 * (int)disk_free / bitrate; /* rough estimation */ + + dseconds = rec_timesplit_seconds(); + dsize = rec_sizesplit_bytes(); + num_recorded_bytes = audio_num_recorded_bytes(); + + for(i = 0; i < screen_update; i++) + { + screens[i].clear_display(); + screens[i].setfont(font[i]); + } + + style = base_style; + +#ifdef HAVE_LCD_COLOR + /* special action for gradient - set default for 1 line gradient */ + if(global_settings.cursor_style == 3) + style = base_style | CURLN_PACK(0) | NUMLN_PACK(1); +#endif /* HAVE_LCD_COLOR */ + +#if CONFIG_CODEC == SWCODEC + if ((audio_stat & AUDIO_STATUS_WARNING) + && (warning_counter++ % WARNING_PERIOD) < WARNING_PERIOD/2) + { + /* Switch back and forth displaying warning on first available + line to ensure visibility - the motion should also help + draw attention */ + /* Don't use language string unless agreed upon to make this + method permanent - could do something in the statusbar */ + snprintf(buf, sizeof(buf), "Warning: %08X", + pcm_rec_get_warnings()); + } + else +#endif /* CONFIG_CODEC == SWCODEC */ + if ((global_settings.rec_sizesplit) && + (global_settings.rec_split_method)) + { + countdown_offset = 1; + dmb = dsize/1024/1024; + snprintf(buf, sizeof(buf), "%s %dMB", + str(LANG_SYSFONT_SPLIT_SIZE), dmb); + } + /* only display recording time if countdown timer is off */ + else if (!timer.days && !timer.hrs && !timer.mins && !timer.secs) + { + hours = seconds / 3600; + minutes = (seconds - (hours * 3600)) / 60; + snprintf(buf, sizeof(buf), "%s %02d:%02d:%02d", + str(LANG_SYSFONT_RECORDING_TIME), + hours, minutes, seconds%60); + } + else + { + countdown_offset = 0; + snprintf(buf, 32, ""); + } + + for(i = 0; i < screen_update; i++) + screens[i].puts(0, 0, buf); + + if(audio_stat & AUDIO_STATUS_PRERECORD) + { + snprintf(buf, sizeof(buf), "%s...", + str(LANG_SYSFONT_RECORD_PRERECORD)); + } + else + { + /* Display the split interval if the record timesplit + is active */ + if ((global_settings.rec_timesplit) && + !(global_settings.rec_split_method)) + { + /* Display the record timesplit interval rather + than the file size if the record timer is + active */ + dhours = dseconds / 3600; + dminutes = (dseconds - (dhours * 3600)) / 60; + snprintf(buf, sizeof(buf), "%s %02d:%02d", + str(LANG_SYSFONT_RECORD_TIMESPLIT_REC), + dhours, dminutes); + } + /* only display recording size if countdown timer is off */ + else if (!timer.days && !timer.hrs && !timer.mins && !timer.secs) + { + output_dyn_value(buf2, sizeof buf2, + num_recorded_bytes, + byte_units, true); + snprintf(buf, sizeof(buf), "%s %s", + str(LANG_SYSFONT_RECORDING_SIZE), buf2); + } + } + for(i = 0; i < screen_update; i++) + screens[i].puts(0, 1, buf); + + /* display countdown timer if set */ + if (timer.days || timer.hrs || timer.mins || timer.secs) + { + snprintf(buf, 32, "%s %d:%02d:%02d:%02d", str(LANG_REC_TIMER), + timer.days, timer.hrs, timer.mins, timer.secs); + + for(i = 0; i < screen_update; i++) + screens[i].puts(0, countdown_offset, buf); + } + + for(i = 0; i < screen_update; i++) + { + if (filename_offset[i] > 0) + { + *filename = '\0'; + if (audio_stat & AUDIO_STATUS_RECORD) + { + strncpy(filename, path_buffer + + strlen(path_buffer) - 12, 13); + filename[12]='\0'; + } + + snprintf(buf, sizeof(buf), "%s %s", + str(LANG_SYSFONT_RECORDING_FILENAME), filename); + screens[i].puts(0, 2, buf); + } + } + + /* We will do file splitting regardless, either at the end of + a split interval, or when the filesize approaches the 2GB + FAT file size (compatibility) limit. */ + if ((audio_stat && !(global_settings.rec_split_method) + && global_settings.rec_timesplit && (seconds >= dseconds)) + || (audio_stat && global_settings.rec_split_method + && global_settings.rec_sizesplit + && (num_recorded_bytes >= dsize)) + || (num_recorded_bytes >= MAX_FILE_SIZE)) + { + if (!(global_settings.rec_split_type) + || (num_recorded_bytes >= MAX_FILE_SIZE)) + { + rec_command(RECORDING_CMD_START_NEWFILE); + last_seconds = 0; + } +// else + else if (repeat_timer_start) + { + peak_meter_trigger(false); + peak_meter_set_trigger_listener(NULL); + if( global_settings.rec_split_type == 1) + rec_command(RECORDING_CMD_STOP); + else + rec_command(RECORDING_CMD_STOP_SHUTDOWN); + + /* stop any more attempts to access this code until a new + recording is started */ + repeat_timer_start = false; + + /* start repeat countdown if set and only if + stop time < repeat time */ + if (timer.repeater) + { + repeat_timer -= dseconds; + timer.days = repeat_timer / (3600 * 24); + timer.hrs = (repeat_timer - (timer.days * 3600 * 24)) / + 3600; + timer.mins = (repeat_timer - (timer.hrs * 3600)) / 60; + timer.secs = prerec; /* add prerecorded time to timer */ + + /* This is not really a toggle so much as a safety feature + so that it is impossible to start the timer more than + once */ + timer.countdown = !timer.countdown; + if (timer.countdown) + tick_add_task(timer_tick_task); + else + tick_remove_task(timer_tick_task); + } + } + update_countdown = 1; + } + + /* draw the clipcounter just in front of the peakmeter */ + if(global_settings.peak_meter_clipcounter) + { + char clpstr[32]; + snprintf(clpstr, 32, "%4d", pm_get_clipcount()); + for(i = 0; i < screen_update; i++) + { + if(pm_height[i] > 1) + screens[i].puts(0, 2 + filename_offset[i], + str(LANG_SYSFONT_PM_CLIPCOUNT)); + screens[i].puts(0, 1 + pm_height[i] + filename_offset[i], + clpstr); + } + } + + snprintf(buf, sizeof(buf), "%s: %s", str(LANG_SYSFONT_VOLUME), + fmt_gain(SOUND_VOLUME, + global_settings.volume, + buf2, sizeof(buf2))); + + if (global_settings.cursor_style && (pos++ == cursor)) + { + for(i = 0; i < screen_update; i++) + screens[i].puts_style_offset(0, filename_offset[i] + + pm_height[i] + 2, buf, style,0); +//- PM_HEIGHT + 2, buf, STYLE_INVERT,0); +//+ pm_height[i] + 2, buf, STYLE_INVERT,0); + } + else + { + for(i = 0; i < screen_update; i++) +// screens[i].putsxy(ymargin, +// h[i]*(filename_offset[i]+ +// pm_height[i] + 2), buf); +//- screens[i].puts(0, filename_offset[i] + PM_HEIGHT + 2, buf); + screens[i].puts(0, filename_offset[i] + pm_height[i] + 2, buf); + } + + if(global_settings.rec_source == AUDIO_SRC_MIC) + { + /* Draw MIC recording gain */ + snprintf(buf, sizeof(buf), "%s:%s", str(LANG_SYSFONT_GAIN), + fmt_gain(SOUND_MIC_GAIN, + global_settings.rec_mic_gain, + buf2, sizeof(buf2))); + if(global_settings.cursor_style && ((1==cursor)||(2==cursor))) + { + for(i = 0; i < screen_update; i++) + screens[i].puts_style_offset(0, filename_offset[i] + + pm_height[i] + 3, buf, style,0); +//- PM_HEIGHT + 3, buf, STYLE_INVERT,0); +//+ pm_height[i] + 3, buf, STYLE_INVERT,0); + } + else + { + for(i = 0; i < screen_update; i++) +// screens[i].putsxy(ymargin, +// h[i]*(filename_offset[i] + +// pm_height[i] + 3), buf); +//- PM_HEIGHT + 3, buf); + screens[i].puts(0, filename_offset[i] + + pm_height[i] + 3, buf); + } + } + else if(0 + HAVE_LINE_REC_( || global_settings.rec_source == + AUDIO_SRC_LINEIN) + HAVE_FMRADIO_REC_( || global_settings.rec_source == + AUDIO_SRC_FMRADIO) + ) + { + /* Draw LINE or FMRADIO recording gain */ + snprintf(buf, sizeof(buf), "%s:%s", + str(LANG_SYSFONT_RECORDING_LEFT), + fmt_gain(SOUND_LEFT_GAIN, + global_settings.rec_left_gain, + buf2, sizeof(buf2))); +#ifdef HAVE_LCD_COLOR + /* special action for gradient - double line gradient - line1 */ + if((global_settings.cursor_style == 3) && + (1==cursor)) + style = base_style | CURLN_PACK(0) | NUMLN_PACK(2); +#endif /* HAVE_LCD_COLOR */ + if(global_settings.cursor_style && ((1==cursor)||(2==cursor))) + { + for(i = 0; i < screen_update; i++) + screens[i].puts_style_offset(0, filename_offset[i] + + pm_height[i] + 3, buf, style,0); +//- PM_HEIGHT + 3, buf, STYLE_INVERT,0); +//+ pm_height[i] + 3, buf, STYLE_INVERT,0); + } + else + { + for(i = 0; i < screen_update; i++) +// screens[i].putsxy(ymargin, +// h[i]*(filename_offset[i] + +// pm_height[i] + 3), buf); +//- PM_HEIGHT + 3, buf); +//+ pm_height[i] + 3, buf); + screens[i].puts(0, filename_offset[i] + + pm_height[i] + 3, buf); + } + + snprintf(buf, sizeof(buf), "%s:%s", + str(LANG_SYSFONT_RECORDING_RIGHT), + fmt_gain(SOUND_RIGHT_GAIN, + global_settings.rec_right_gain, + buf2, sizeof(buf2))); +#ifdef HAVE_LCD_COLOR + /* special action for gradient - double line gradient - line2 */ + if((global_settings.cursor_style == 3) && + (1==cursor)) + style = base_style | CURLN_PACK(1) | NUMLN_PACK(2); +#endif /* HAVE_LCD_COLOR */ + if(global_settings.cursor_style && ((1==cursor)||(3==cursor))) + { + for(i = 0; i < screen_update; i++) + screens[i].puts_style_offset(0, filename_offset[i] + + pm_height[i] + 4, buf, style,0); +//- PM_HEIGHT + 4, buf, STYLE_INVERT,0); +//+ pm_height[i] + 4, buf, STYLE_INVERT,0); + } + else + { + for(i = 0; i < screen_update; i++) +// screens[i].putsxy(ymargin, +// h[i]*(filename_offset[i] + +// pm_height[i] + 4), buf); +//- PM_HEIGHT + 4, buf); +//+ pm_height[i] + 4, buf); + screens[i].puts(0, filename_offset[i] + + pm_height[i] + 4, buf); + } + } + yield(); + +#ifdef HAVE_LCD_COLOR + /* special action for gradient - back to single line gradient */ + if(global_settings.cursor_style == 3) + style = base_style | CURLN_PACK(0) | NUMLN_PACK(1); +#endif /* HAVE_LCD_COLOR */ + FOR_NB_SCREENS(i) + { + switch (global_settings.rec_source) + { + HAVE_LINE_REC_(case AUDIO_SRC_LINEIN:) + HAVE_FMRADIO_REC_(case AUDIO_SRC_FMRADIO:) + line[i] = 5; + break; + + case AUDIO_SRC_MIC: + line[i] = 4; + break; +#ifdef HAVE_SPDIF_REC + case AUDIO_SRC_SPDIF: + line[i] = 3; + break; +#endif + default: + line[i] = 5; /* to prevent uninitialisation + warnings for line[0] */ + break; + } /* end switch */ +#ifdef HAVE_AGC +// if (vp[i].height < h * (2 + filename_offset[i] + +// PM_HEIGHT + line[i])) +//- if (screens[i].height < h * (2 + filename_offset[i] + PM_HEIGHT + line[i])) + if (vp[i].height < 8 + h[i] * (1 + filename_offset[i] + pm_height[i] + line[i])) + { + line[i] -= 1; + display_agc[i] = false; + } + else + display_agc[i] = true; + + if ((cursor==4) || (cursor==5)) + display_agc[i] = true; + } + + /************** AGC test info ****************** + snprintf(buf, sizeof(buf), "D:%d U:%d", + (agc_droptime+2)/5, (agc_risetime+2)/5); + lcd_putsxy(1, LCD_HEIGHT - 8, buf); + snprintf(buf, sizeof(buf), "B:%d", + (agc_baltime+2)/5); + lcd_putsxy(LCD_WIDTH/2 + 3, LCD_HEIGHT - 8, buf); + ***********************************************/ + + if (cursor == 5) + snprintf(buf, sizeof(buf), "%s: %s", + str(LANG_SYSFONT_RECORDING_AGC_MAXGAIN), + fmt_gain(SOUND_LEFT_GAIN, + agc_maxgain, buf2, sizeof(buf2))); + else if (agc_preset == 0) + snprintf(buf, sizeof(buf), "%s: %s", + str(LANG_SYSFONT_RECORDING_AGC_PRESET), + agc_preset_str[agc_preset]); + else if (global_settings.rec_source == AUDIO_SRC_MIC) + snprintf(buf, sizeof(buf), "%s: %s%s", + str(LANG_SYSFONT_RECORDING_AGC_PRESET), + agc_preset_str[agc_preset], + fmt_gain(SOUND_LEFT_GAIN, + agc_maxgain - + global_settings.rec_mic_gain, + buf2, sizeof(buf2))); + else + snprintf(buf, sizeof(buf), "%s: %s%s", + str(LANG_SYSFONT_RECORDING_AGC_PRESET), + agc_preset_str[agc_preset], + fmt_gain(SOUND_LEFT_GAIN, + agc_maxgain - + (global_settings.rec_left_gain + + global_settings.rec_right_gain)/2, + buf2, sizeof(buf2))); + + if(global_settings.cursor_style && ((cursor==4) || (cursor==5))) + { + for(i = 0; i < screen_update; i++) + screens[i].puts_style_offset(0, filename_offset[i] + + pm_height[i] + line[i], buf, style,0); +//- PM_HEIGHT + line[i], buf, STYLE_INVERT,0); +//+ pm_height[i] + line[i], buf, STYLE_INVERT,0); + } + else if (global_settings.rec_source == AUDIO_SRC_MIC + HAVE_LINE_REC_(|| global_settings.rec_source == + AUDIO_SRC_LINEIN) + HAVE_FMRADIO_REC_(|| global_settings.rec_source == + AUDIO_SRC_FMRADIO) + ) + { + for(i = 0; i < screen_update; i++) { + if (display_agc[i]) { +// screens[i].putsxy(ymargin, +// h[i]*(filename_offset[i] + +// pm_height[i] + line[i]), buf); +//- screens[i].puts(0, filename_offset[i] + +//- PM_HEIGHT + line[i], buf); + screens[i].puts(0, filename_offset[i] + + pm_height[i] + line[i], buf); + } + } + } + + if (global_settings.rec_source == AUDIO_SRC_MIC) + { + if(agc_maxgain < (global_settings.rec_mic_gain)) + change_recording_gain(false, true, true); + } + else + { + if(agc_maxgain < (global_settings.rec_left_gain)) + change_recording_gain(false, true, false); + if(agc_maxgain < (global_settings.rec_right_gain)) + change_recording_gain(false, false, true); + } +#else /* !HAVE_AGC */ + } +#endif /* HAVE_AGC */ + + if(!global_settings.cursor_style) { + switch(cursor) + { + case 1: + for(i = 0; i < screen_update; i++) + screen_put_cursorxy(&screens[i], 0, + filename_offset[i] + + pm_height[i] + 3, true); + + if(global_settings.rec_source != AUDIO_SRC_MIC) + { + for(i = 0; i < screen_update; i++) + screen_put_cursorxy(&screens[i], 0, + filename_offset[i] + + pm_height[i] + 4, true); + } + break; + case 2: + for(i = 0; i < screen_update; i++) + screen_put_cursorxy(&screens[i], 0, + filename_offset[i] + + pm_height[i] + 3, true); + break; + case 3: + for(i = 0; i < screen_update; i++) + screen_put_cursorxy(&screens[i], 0, + filename_offset[i] + + pm_height[i] + 4, true); + break; +#ifdef HAVE_AGC + case 4: + case 5: + for(i = 0; i < screen_update; i++) + screen_put_cursorxy(&screens[i], 0, + filename_offset[i] + + pm_height[i] + line[i], true); + break; +#endif /* HAVE_AGC */ + default: + for(i = 0; i < screen_update; i++) + screen_put_cursorxy(&screens[i], 0, + filename_offset[i] + + pm_height[i] + 2, true); + } + } + +#ifdef HAVE_AGC + hist_time++; +#endif + +#ifdef HAVE_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)) + int hist_bal_y; + if (histogram_on) + hist_bal_y = HIST_Y - hist_size_h[history_mode/2] - 11; + else + hist_bal_y = HIST_Y - 11; + + if((global_settings.rec_source == AUDIO_SRC_MIC)|| + (global_settings.rec_source == AUDIO_SRC_LINEIN)|| + (global_settings.rec_source == AUDIO_SRC_FMRADIO)) + agc_line = 1; + else + agc_line = 0; /* no agc line for Spdif in */ + + if ((hist_bal_y) > (8 + ((line[0] + filename_offset[0] + + pm_height[0] + agc_line + (global_settings.rec_trigger_mode > + 0 ? 1 : 0)) * h[0]))) + { + lcd_setfont(FONT_SYSFIXED); + lcd_set_drawmode(DRMODE_FG); +#if LCD_DEPTH > 1 + if (battery_level() > 10) + lcd_set_foreground(LCD_BATT_OK); + else + lcd_set_foreground(LCD_BATT_LO); +#else + lcd_set_foreground( +#ifdef HAVE_LCD_COLOR + global_settings.fg_color); +#else + LCD_DEFAULT_FG); +#endif +#endif /* LCD_DEPTH > 1 */ + lcd_fillrect(0, hist_bal_y, + (30 * battery_level() + 60) / 100, 9); +#if LCD_DEPTH > 1 + if (disk_time > 59) + lcd_set_foreground(LCD_DISK_OK); + else + lcd_set_foreground(LCD_DISK_LO); +#endif /* LCD_DEPTH > 1 */ + if ((LCD_WIDTH/2 - 36)*(disk_space-disk_free-3) / disk_space) + lcd_fillrect(35, hist_bal_y, (LCD_WIDTH/2 - 37) * + (disk_space - disk_free - 1) / disk_space, 9); + lcd_set_drawmode(DRMODE_COMPLEMENT); + lcd_set_foreground( +#ifdef HAVE_LCD_COLOR + global_settings.fg_color); +#else + LCD_DEFAULT_FG); +#endif +#ifndef SIMULATOR + if (charger_inserted()) + lcd_mono_bitmap(bitmap_icons_7x8[Icon_Plug], + 2 + 19*(battery_level() > 48), + hist_bal_y + 1, 7, 8); +#endif + if (battery_time() > 90) + snprintf(buf, 32, "%dh", (battery_time() + 10) / 60); + else + snprintf(buf,32, "%dm", battery_time()); + if (battery_level() > 48) + i = 1; + else if ((battery_time() < 590) && (battery_time() > 90)) + i = 15; + else + i = 10; + lcd_putsxy(i, hist_bal_y + 1, buf); + if (disk_time > 90) + snprintf(buf, 32, "%dh", (disk_time + 10) / 60); + else + snprintf(buf, 32, "%dm", disk_time); + i = ((disk_time < 91) || (disk_time > 589))? 30:26; + + if ((hist_time % 2) +#ifndef SIMULATOR + || !ata_disk_is_active() +#endif + ) + lcd_mono_bitmap(rec_icons_6x8[Icon_Disk], + LCD_WIDTH/2 - 11, + hist_bal_y + 1, 6, 8); + lcd_putsxy((5*disk_free > 3*disk_space) ? + (LCD_WIDTH/2 - i) : 37, + hist_bal_y + 1, buf); + lcd_drawrect(34, hist_bal_y - 1, LCD_WIDTH/2 - 36, 11); + lcd_set_drawmode(DRMODE_SOLID); + lcd_drawrect(0, hist_bal_y - 1, 30, 11); + lcd_vline(30, hist_bal_y + 2, hist_bal_y + 6); + lcd_vline(31, hist_bal_y + 2, hist_bal_y + 6); + + int bal; + lcd_drawrect(HIST_BAL_X-2, hist_bal_y-1, HIST_BAL_W+3, 11); + lcd_hline(HIST_BAL_X + HIST_BAL_W/2 - 1, + HIST_BAL_X + HIST_BAL_W/2 + 1, + hist_bal_y - 2); + lcd_hline(HIST_BAL_X + HIST_BAL_W/2 - 1, + HIST_BAL_X + HIST_BAL_W/2 + 1, + hist_bal_y + 10); + lcd_set_drawmode(DRMODE_FG); +#ifndef HAVE_LCD_COLOR + lcd_set_foreground(LCD_BAL); +#endif + for (i = 0; i < BAL_MEM_SIZE; i++) { + bal = MIN(balance_mem[i], BAL_MAX_R); + bal = MAX(bal, BAL_MAX_L); +#ifdef HAVE_LCD_COLOR + if (bal > 142) + lcd_set_foreground(LCD_BAL_L); + else if (bal < 142) + lcd_set_foreground(LCD_BAL_R); + else + lcd_set_foreground(LCD_DARKGRAY); +#endif + /* every 0.2 seconds a balance measure is taken, + draw a vline for each */ + lcd_vline(HIST_BAL_X + HIST_BAL_W/2 + + HIST_BAL_W * bal / 9976, + hist_bal_y + 1, hist_bal_y + 7); + } + lcd_set_foreground(LCD_BLACK); + bal = MAX(balance, BAL_MAX_L); + bal = MIN(bal, BAL_MAX_R); + /* draw the 3 pixel wide balance measure, + average measure of the last 24 measures (5 seconds) */ + lcd_fillrect(HIST_BAL_X-1 + HIST_BAL_W/2 + + HIST_BAL_W * bal / 9976, + hist_bal_y, 3, 9); + lcd_drawpixel(HIST_BAL_X + HIST_BAL_W/2, hist_bal_y + 4); + lcd_set_drawmode(DRMODE_COMPLEMENT); + lcd_drawpixel(HIST_BAL_X + HIST_BAL_W/2, hist_bal_y - 1); + lcd_drawpixel(HIST_BAL_X + HIST_BAL_W/2, hist_bal_y + 9); + for (i = 0; i < 12; i++) + lcd_drawpixel(HIST_BAL_X + HIST_BAL_W/2 + + HIST_BAL_W * hist_balance_marks[i] / 9976, + hist_bal_y + 4); + } + + if (histogram_on) + { + hist_height = hist_size_h[history_mode/2] - 1; + if (peak_valid && !(hist_time % hist_time_interval) && hist_l) + { + if (history_mode % 2) { + i = 0; + while (hist_l < hist_peak_lin2dB[history_mode / 2][i]) + i++; + history_l[history_pos] = hist_height - i; + i = 0; + while (hist_r < hist_peak_lin2dB[history_mode / 2][i]) + i++; + history_r[history_pos] = hist_height - i; + } else { + history_l[history_pos] = hist_l * hist_height / 32767; + history_r[history_pos] = hist_r * hist_height / 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_Y - hist_height, + HIST_W + 2, hist_height + 1); + lcd_drawrect(HIST_W + 6, HIST_Y - hist_height, + HIST_W + 2, hist_height + 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_height) + lcd_set_foreground(LCD_HIST_OVER); + else if (history_l[i] > hist_level_marks[history_mode][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_height) + lcd_set_foreground(LCD_HIST_OVER); + else if (history_r[i] > hist_level_marks[history_mode][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_height) + 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_height) + 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]); + } + } + lcd_set_foreground(LCD_WHITE); + for (i = 0; i < HIST_W; i++) { + if (history_l[i] == hist_height) + lcd_drawpixel(1 + i, HIST_Y - 1); + if (history_r[i] == hist_height) + lcd_drawpixel(HIST_W + 7 + i, HIST_Y - 1); + } +#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[history_mode][i]); + } +#endif /* HAVE_HISTOGRAM */ + +#ifdef HAVE_AGC + hist_time++; +#endif + + for(i = 0; i < screen_update; i++) + { + screens[i].set_viewport(NULL); + gui_statusbar_draw(&(statusbars.statusbars[i]), true); + screens[i].set_viewport(&vp[i]); + peak_meter_screen(&screens[i], pm_x, pm_y[i], pm_h[i]); +//- peak_meter_screen(&screens[i], 0, pm_y[i], h*PM_HEIGHT); +//+ peak_meter_screen(&screens[i], 0, pm_y[i], pm_h[i]); + screens[i].update(); + } + + /* draw the trigger status */ + FOR_NB_SCREENS(i) + { + /* NOTE: UGLY width setting based on height! To be fixed! */ +// trig_width[i] = ((vp[i].height < 64) || +// ((vp[i].height < 72) && (PM_HEIGHT > 1))) ? +// screens[i].getwidth() - 14 * w : +// screens[i].getwidth(); +//- trig_width[i] = ((screens[i].height < 64) || +//- ((screens[i].height < 72) && (PM_HEIGHT > 1))) ? +//- screens[i].width - 14 * w : screens[i].width; + trig_width[i] = (vp[i].height < (h[i] * (2 + + filename_offset[i] + pm_height[i] + + line[i]) + (histogram_on ? 25 : 8))) ? + screens[i].getwidth() - + 14 * w[i] : screens[i].getwidth(); + trig_xpos[i] = screens[i].getwidth() - trig_width[i]; +// trig_ypos[i] = ((vp[i].height < 72) && (PM_HEIGHT > 1)) ? +// h*2 : +// h*(1 + filename_offset[i] + PM_HEIGHT + +// line[i] +//- trig_ypos[i] = ((screens[i].height < 72) && (PM_HEIGHT > 1)) ? +//- h*2 : +//- h*(1 + filename_offset[i] + PM_HEIGHT + line[i] + trig_ypos[i] = (vp[i].height < (h[i] * (2 + + filename_offset[i] + pm_height[i] + + line[i]) + (histogram_on ? 25 : 8))) ? h[i]*2 + : h[i]*(1 + filename_offset[i] + + pm_height[i] + line[i] +#ifdef HAVE_AGC + + 1 +#endif + ); + } + + if (peak_meter_trigger_status() != TRIG_OFF) + { + peak_meter_draw_trig(trig_xpos, trig_ypos, trig_width, + screen_update); + for(i = 0; i < screen_update; i++){ + screens[i].update_rect(trig_xpos[i], trig_ypos[i], + trig_width[i] + 2, TRIG_HEIGHT); + } + } + } + + /* check battery level & free disk space */ +#ifndef SIMULATOR + if (ata_disk_is_active()) + disk_was_active = true; + else if (disk_was_active) + { + lcd_setfont(FONT_UI); + if (disk_time == 0) { + backlight_on(); +#ifdef HAVE_REMOTE_LCD + remote_backlight_on(); +#endif + if (audio_stat & AUDIO_STATUS_RECORD) { + gui_syncsplash(HZ, "%s %s", + str(LANG_WARNING_DISK_FULL), + str(LANG_WARNING_STOP_RECORDING)); + audio_stop_recording(); + } + else { + gui_syncsplash(2*HZ, + str(LANG_WARNING_DISK_FULL)); + } + } + else if (warn_message && (battery_level() < 10)) { + backlight_on(); +#ifdef HAVE_REMOTE_LCD + remote_backlight_on(); +#endif + gui_syncsplash(3*HZ, + str(LANG_WARNING_BATTERY_LOW)); + } + else if (!warn_message && (disk_free < 512)) { + backlight_on(); +#ifdef HAVE_REMOTE_LCD + remote_backlight_on(); +#endif + gui_syncsplash(3*HZ, + str(LANG_WARNING_DISKSPACE_LOW)); + } + lcd_setfont(FONT_SYSFIXED); + warn_message = !warn_message; + disk_was_active = false; + } +#endif + + if(audio_stat & AUDIO_STATUS_ERROR) + { + done = true; + } + } /* end while(!done) */ + + audio_stat = audio_status(); + if (audio_stat & AUDIO_STATUS_ERROR) + { + gui_syncsplash(0, str(LANG_SYSFONT_DISK_FULL)); + gui_syncstatusbar_draw(&statusbars, true); + + FOR_NB_SCREENS(i) + screens[i].update(); + +#if CONFIG_CODEC == SWCODEC + /* stop recording - some players like H10 freeze otherwise + TO DO: find out why it freezes and fix properly */ + rec_command(RECORDING_CMD_STOP); + audio_close_recording(); +#endif + + audio_error_clear(); + + while(1) + { + if (action_userabort(TIMEOUT_NOBLOCK)) + break; + } + } + +rec_abort: + +#if CONFIG_CODEC == SWCODEC + rec_command(RECORDING_CMD_STOP); + audio_close_recording(); + +#ifdef HAVE_FMRADIO_REC + if (radio_status != FMRADIO_OFF) + /* Restore radio playback - radio_status should be unchanged if started + through fm radio screen (barring usb connect) */ + rec_set_source(AUDIO_SRC_FMRADIO, (radio_status & FMRADIO_PAUSED) ? + SRCF_FMRADIO_PAUSED : SRCF_FMRADIO_PLAYING); + else +#endif + /* Go back to playback mode */ + rec_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); + + /* restore talking */ + talk_disable(false); +#else /* !SWCODEC */ + audio_init_playback(); +#endif /* CONFIG_CODEC == SWCODEC */ + + /* make sure the trigger is really turned off */ + peak_meter_trigger(false); + peak_meter_set_trigger_listener(NULL); + + rec_status &= ~RCSTAT_IN_RECSCREEN; + sound_settings_apply(); + + FOR_NB_SCREENS(i) + screens[i].setfont(FONT_UI); + + /* if the directory was created or recording happened, make sure the + browser is updated */ + if (rec_status & (RCSTAT_CREATED_DIRECTORY | RCSTAT_HAVE_RECORDED)) + reload_directory(); + +#ifdef HAVE_HISTOGRAM + global_settings.rec_histogram_mode = history_mode; +#endif + +#if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR) + ata_set_led_enabled(true); +#endif + + settings_save(); + + return (rec_status & RCSTAT_BEEN_IN_USB_MODE) != 0; +} /* recording_screen */ + +#if CONFIG_KEYPAD == RECORDER_PAD +static bool f2_rec_screen(void) +{ + static const char* const freq_str[6] = + { + "44.1kHz", + "48kHz", + "32kHz", + "22.05kHz", + "24kHz", + "16kHz" + }; + + bool exit = false; + bool used = false; + int w, h, i; + char buf[32]; + int button; + struct audio_recording_options rec_options; + + FOR_NB_SCREENS(i) + { + screens[i].setfont(FONT_SYSFIXED); + screens[i].getstringsize("A",&w,&h); + } + + while (!exit) { + const char* ptr=NULL; + + FOR_NB_SCREENS(i) + { + screens[i].clear_display(); + + /* Recording quality */ + screens[i].putsxy(0, LCD_HEIGHT/2 - h*2, + str(LANG_SYSFONT_RECORDING_QUALITY)); + } + + snprintf(buf, sizeof(buf), "%d", global_settings.rec_quality); + FOR_NB_SCREENS(i) + { + screens[i].putsxy(0, LCD_HEIGHT/2-h, buf); + screens[i].mono_bitmap(bitmap_icons_7x8[Icon_FastBackward], + LCD_WIDTH/2 - 16, LCD_HEIGHT/2 - 4, 7, 8); + } + + /* Frequency */ + snprintf(buf, sizeof buf, "%s:", str(LANG_SYSFONT_RECORDING_FREQUENCY)); + ptr = freq_str[global_settings.rec_frequency]; + FOR_NB_SCREENS(i) + { + screens[i].getstringsize(buf,&w,&h); + screens[i].putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h*2, buf); + screens[i].getstringsize(ptr, &w, &h); + screens[i].putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h, ptr); + screens[i].mono_bitmap(bitmap_icons_7x8[Icon_DownArrow], + LCD_WIDTH/2 - 3, LCD_HEIGHT - h*3, 7, 8); + } + + /* Channel mode */ + switch ( global_settings.rec_channels ) { + case 0: + ptr = str(LANG_SYSFONT_CHANNEL_STEREO); + break; + + case 1: + ptr = str(LANG_SYSFONT_CHANNEL_MONO); + break; + } + + FOR_NB_SCREENS(i) + { + screens[i].getstringsize(str(LANG_SYSFONT_CHANNELS), &w, &h); + screens[i].putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 - h*2, + str(LANG_SYSFONT_CHANNELS)); + screens[i].getstringsize(str(LANG_SYSFONT_MODE), &w, &h); + screens[i].putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 - h, + str(LANG_SYSFONT_MODE)); + screens[i].getstringsize(ptr, &w, &h); + screens[i].putsxy(LCD_WIDTH - w, LCD_HEIGHT/2, ptr); + screens[i].mono_bitmap(bitmap_icons_7x8[Icon_FastForward], + LCD_WIDTH/2 + 8, LCD_HEIGHT/2 - 4, 7, 8); + + screens[i].update(); + } + + button = button_get(true); + switch (button) { + case BUTTON_LEFT: + case BUTTON_F2 | BUTTON_LEFT: + global_settings.rec_quality++; + if(global_settings.rec_quality > 7) + global_settings.rec_quality = 0; + used = true; + break; + + case BUTTON_DOWN: + case BUTTON_F2 | BUTTON_DOWN: + global_settings.rec_frequency++; + if(global_settings.rec_frequency > 5) + global_settings.rec_frequency = 0; + used = true; + break; + + case BUTTON_RIGHT: + case BUTTON_F2 | BUTTON_RIGHT: + global_settings.rec_channels++; + if(global_settings.rec_channels > 1) + global_settings.rec_channels = 0; + used = true; + break; + + case BUTTON_F2 | BUTTON_REL: + if ( used ) + exit = true; + used = true; + break; + + case BUTTON_F2 | BUTTON_REPEAT: + used = true; + break; + + default: + if(default_event_handler(button) == SYS_USB_CONNECTED) + return true; + break; + } + } + + rec_init_recording_options(&rec_options); + rec_set_recording_options(&rec_options); + + set_gain(); + + settings_save(); + FOR_NB_SCREENS(i) + screens[i].setfont(FONT_UI); + + return false; +} + +static bool f3_rec_screen(void) +{ + bool exit = false; + bool used = false; + int w, h, i; + int button; + char *src_str[] = + { + str(LANG_SYSFONT_RECORDING_SRC_MIC), + str(LANG_SYSFONT_LINE_IN), + str(LANG_SYSFONT_RECORDING_SRC_DIGITAL) + }; + struct audio_recording_options rec_options; + + FOR_NB_SCREENS(i) + { + screens[i].setfont(FONT_SYSFIXED); + screens[i].getstringsize("A",&w,&h); + } + + while (!exit) { + char* ptr=NULL; + ptr = src_str[global_settings.rec_source]; + FOR_NB_SCREENS(i) + { + screens[i].clear_display(); + + /* Recording source */ + screens[i].putsxy(0, LCD_HEIGHT/2 - h*2, + str(LANG_SYSFONT_RECORDING_SOURCE)); + + screens[i].getstringsize(ptr, &w, &h); + screens[i].putsxy(0, LCD_HEIGHT/2-h, ptr); + screens[i].mono_bitmap(bitmap_icons_7x8[Icon_FastBackward], + LCD_WIDTH/2 - 16, LCD_HEIGHT/2 - 4, 7, 8); + } + + /* trigger setup */ + ptr = str(LANG_SYSFONT_RECORD_TRIGGER); + FOR_NB_SCREENS(i) + { + screens[i].getstringsize(ptr,&w,&h); + screens[i].putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h*2, ptr); + screens[i].mono_bitmap(bitmap_icons_7x8[Icon_DownArrow], + LCD_WIDTH/2 - 3, LCD_HEIGHT - h*3, 7, 8); + + screens[i].update(); + } + + button = button_get(true); + switch (button) { + case BUTTON_DOWN: + case BUTTON_F3 | BUTTON_DOWN: +#ifndef SIMULATOR + rectrigger(); + settings_apply_trigger(); +#endif + exit = true; + break; + + case BUTTON_LEFT: + case BUTTON_F3 | BUTTON_LEFT: + global_settings.rec_source++; + if(global_settings.rec_source > AUDIO_SRC_MAX) + global_settings.rec_source = 0; + used = true; + break; + + case BUTTON_F3 | BUTTON_REL: + if ( used ) + exit = true; + used = true; + break; + + case BUTTON_F3 | BUTTON_REPEAT: + used = true; + break; + + default: + if(default_event_handler(button) == SYS_USB_CONNECTED) + return true; + break; + } + } + + rec_init_recording_options(&rec_options); + rec_set_recording_options(&rec_options); + + set_gain(); + + settings_save(); + FOR_NB_SCREENS(i) + screens[i].setfont(FONT_UI); + + return false; +} +#endif /* CONFIG_KEYPAD == RECORDER_PAD */ + +struct timer *get_timerstat(void) +{ + return &timer; +} + + +#if CONFIG_CODEC == SWCODEC +void audio_beep(int duration) +{ + /* dummy */ + (void)duration; +} + +#ifdef SIMULATOR +/* stubs for recording sim */ +void audio_init_recording(unsigned int buffer_offset) +{ + buffer_offset = buffer_offset; +} + +void audio_close_recording(void) +{ +} + +unsigned long pcm_rec_get_warnings(void) +{ + return 0; +} + +unsigned long audio_recorded_time(void) +{ + return 123; +} + +unsigned long audio_num_recorded_bytes(void) +{ + return 5 * 1024 * 1024; +} + +void rec_set_source(int source, unsigned flags) +{ + source = source; + flags = flags; +} + +void audio_set_recording_options(struct audio_recording_options *options) +{ + options = options; +} + +void audio_set_recording_gain(int left, int right, int type) +{ + left = left; + right = right; + type = type; +} + +void audio_record(const char *filename) +{ + filename = filename; +} + +void audio_new_file(const char *filename) +{ + filename = filename; +} + +void audio_stop_recording(void) +{ +} + +void audio_pause_recording(void) +{ +} + +void audio_resume_recording(void) +{ +} + +#endif /* #ifdef SIMULATOR */ +#endif /* #ifdef CONFIG_CODEC == SWCODEC */ + +#endif /* HAVE_RECORDING */ diff -Naur _008/apps/recorder/recording.h _009_rep/apps/recorder/recording.h --- _008/apps/recorder/recording.h 2008-07-21 19:59:13.000000000 +0900 +++ _009_rep/apps/recorder/recording.h 2008-07-23 23:09:36.000000000 +0900 @@ -28,6 +28,22 @@ int rec_create_directory(void); void settings_apply_trigger(void); +struct timer +{ + bool countdown; + bool timer_display; + unsigned int days; + unsigned int hrs; + unsigned int mins; + unsigned int secs; + unsigned int days_rpt; + unsigned int hrs_rpt; + unsigned int mins_rpt; + bool repeater; +}; + +struct timer *get_timerstat(void); + /* If true, start recording automatically when recording_sreen() is entered */ extern bool recording_start_automatic; @@ -36,6 +52,7 @@ void rec_set_source(int source, unsigned flags); #endif /* CONFIG_CODEC == SW_CODEC */ +struct audio_recording_options; /* Initializes a recording_options structure with global settings. pass returned data to audio_set_recording_options or rec_set_recording_options */ diff -Naur _008/apps/settings.c _009_rep/apps/settings.c --- _008/apps/settings.c 2008-07-22 17:19:28.291816000 +0900 +++ _009_rep/apps/settings.c 2008-07-24 00:45:18.785862400 +0900 @@ -1046,6 +1046,207 @@ step, min, max, formatter, NULL); } + /* The type separation is necessary since int and bool are fundamentally + different and bit-incompatible types and can not share the same access + code. */ + +/* Useful for time and other multi integer settings */ +bool set_multi_int(const char* string, + const struct opt_items * names, + struct opt_settings * variable, + const int varcount, + bool *changes_accepted) +{ + int i, j, w, h, space_width; + char buf[32]; + long button; + int cursor = 0; + bool done = false; + int value[varcount]; + int pos = 0; + bool changed; + + if(changes_accepted) + changed = *changes_accepted; + else + changed = false; + + /* store current values in temp array */ + for(j = 0; j < varcount; j++) + value[j] = *(int*)variable[j].setting; + + /* initialize screen */ + FOR_NB_SCREENS(i) + screens[i].clear_display(); + + gui_syncstatusbar_draw(&statusbars, true); + screens[0].getstringsize(" ", &space_width, &h); + + /* print title */ + snprintf(buf, sizeof(buf), "%s", string); + FOR_NB_SCREENS(i) + screens[i].puts(0, 0, buf); + + /* print variable names */ + for(j = 0; j < varcount ; j++) + { + if (j > 0) + { + snprintf(buf, sizeof(buf), ":"); + screens[0].getstringsize(buf, &w, &h); + FOR_NB_SCREENS(i) + screens[i].putsxy(pos, 8 + h, buf); + pos += w + space_width; + + } + + snprintf(buf, sizeof(buf), "%s", P2STR(names[j].string)); + FOR_NB_SCREENS(i) + screens[i].putsxy(pos, 8 + h, buf); + + screens[0].getstringsize(buf, &w, &h); + pos += w + space_width; + } + + /* print button instructions */ + snprintf(buf, sizeof(buf), "%s", str(LANG_MULTIINT_CONFIRM)); + FOR_NB_SCREENS(i) + screens[i].puts(0, 6, buf); + + while(!done) + { + /* print variables */ + pos = 0; + FOR_NB_SCREENS(i) + { + screens[i].set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); + screens[i].fillrect(0, 8 + 3 * h, screens[i].getwidth(), h + 1); + screens[i].set_drawmode(DRMODE_SOLID); + } + + for(j = 0; j < varcount; j++) + { + if (j > 0) + { + snprintf(buf, sizeof(buf), ":"); + screens[0].getstringsize(buf, &w, &h); + FOR_NB_SCREENS(i) + screens[i].putsxy(pos, 8 + 3 * h, buf); + pos += w + space_width; + } + + snprintf(buf, sizeof(buf), "%d", value[j]); + + FOR_NB_SCREENS(i) + screens[i].putsxy(pos, 8 + 3 * h, buf); + + snprintf(buf, sizeof(buf), "%d", variable[j].setting_max); + screens[0].getstringsize(buf, &w, &h); + + /* highlight currently selected integer */ + if (cursor == j) + { + FOR_NB_SCREENS(i) + { + screens[i].set_drawmode(DRMODE_COMPLEMENT); + screens[i].fillrect(pos, 8 + 3 * h, w + 1, h + 1); + screens[i].set_drawmode(DRMODE_SOLID); + } + } + + pos += w + space_width; + } + +#ifdef HAVE_LCD_BITMAP + FOR_NB_SCREENS(i) + screens[i].update(); +#endif + + button = get_action(CONTEXT_SETTINGS, TIMEOUT_BLOCK); + + switch (button) + { + case ACTION_STD_NEXT: + cursor ++; + + if (cursor >= varcount) + cursor = varcount - 1; + + if (global_settings.talk_menu) + talk_id(names[cursor].voice_id, false); + break; + + case ACTION_STD_PREV: + /* cancel if pressing left when cursor + is already at the far left */ + if (cursor == 0) + { + changed = false; + gui_syncsplash(HZ/2, str(LANG_MENU_SETTING_CANCEL)); + done = true; + } + else + { + cursor --; + + if (cursor < 0) + cursor = 0; + + if (global_settings.talk_menu) + talk_id(names[cursor].voice_id, false); + } + break; + + case ACTION_SETTINGS_INC: + case ACTION_SETTINGS_INCREPEAT: + value[cursor] += 1; + + if (value[cursor] > variable[cursor].setting_max) + value[cursor] = 0; + + if (global_settings.talk_menu) + talk_id(value[cursor], false); + break; + + case ACTION_SETTINGS_DEC: + case ACTION_SETTINGS_DECREPEAT: + value[cursor] -= 1; + + if (value[cursor] < 0) + value[cursor] = variable[cursor].setting_max; + + if (global_settings.talk_menu) + talk_id(value[cursor], false); + break; + + case ACTION_STD_OK: + changed = true; + done = true; + break; + + case ACTION_STD_CANCEL: + changed = false; + gui_syncsplash(HZ/2, str(LANG_MENU_SETTING_CANCEL)); + done = true; + + default: + if (default_event_handler(button) == SYS_USB_CONNECTED) + return true; + } + } + + /* store values if accepted */ + if(changed) + { + for(j = 0; j < varcount; j++) + *(int*)variable[j].setting = value[j]; + } + + if(changes_accepted) + *changes_accepted = changed; + return false; +} + bool set_int_ex(const unsigned char* string, const char* unit, int voice_unit, @@ -1147,3 +1348,102 @@ settings_save(); } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Naur _008/apps/settings.h _009_rep/apps/settings.h --- _008/apps/settings.h 2008-07-22 17:19:28.311844800 +0900 +++ _009_rep/apps/settings.h 2008-07-24 00:35:02.559772800 +0900 @@ -240,6 +240,11 @@ enum optiontype { INT, BOOL }; +struct opt_settings { + int* setting; + int setting_max; +}; + const struct settings_list* find_setting(const void* variable, int *id); bool cfg_int_to_string(int setting_id, int val, char* buf, int buf_len); bool set_bool_options(const char* string, const bool* variable, @@ -252,6 +257,9 @@ const int* variable, void (*function)(int), int step, int min, int max, void (*formatter)(char*, size_t, int, const char*) ); +bool set_multi_int(const char* string, const struct opt_items * names, + struct opt_settings * variable, int varcount, + bool * changes_accepted); /* use this one if you need to create a lang from the value (i.e with TALK_ID()) */ bool set_int_ex(const unsigned char* string, const char* unit, int voice_unit, @@ -361,7 +369,6 @@ 13= 1GB, 14 = 1.5GB 15 = 1.75MB*/ int rec_split_type; /* split/stop */ int rec_split_method; /* time/filesize */ - int rec_prerecord_time; /* In seconds, 0-30, 0 means OFF */ char rec_directory[MAX_FILENAME+1]; int cliplight; /* 0 = off @@ -482,6 +489,14 @@ #endif bool poweroff_on_hold; /* 0=no 1=yes */ +#ifdef HAVE_RECORDING +#if defined(HAVE_LCD_BITMAP) && (LCD_WIDTH > 111) + int rec_histogram_mode; /* small lin/log /w balance, big lin/log */ + int rec_histogram_interval; /* interval: 0.5s, 1s, 2s, 4s */ + bool hist_def; +#endif + int peak_size; +#endif /* show status bar */ bool statusbar; /* 0=hide, 1=show */ diff -Naur _008/apps/settings_list.c _009_rep/apps/settings_list.c --- _008/apps/settings_list.c 2008-07-22 17:19:28.341888000 +0900 +++ _009_rep/apps/settings_list.c 2008-07-24 00:15:21.281177600 +0900 @@ -1023,6 +1023,17 @@ CHOICE_SETTING(F_RECSETTING, rec_trigger_type, LANG_RECORD_TRIGGER_TYPE, TRIG_TYPE_STOP, "trigger mode","off,once,repeat", NULL ,3, ID2P(LANG_RECORD_TRIGGER_STOP), ID2P(LANG_PAUSE), ID2P(LANG_RECORD_TRIGGER_NEWFILESTP)), + +#if defined(HAVE_LCD_BITMAP) && (LCD_WIDTH > 111) + {F_T_INT,&global_settings.rec_histogram_mode,-1,INT(1), + "histogram mode",NULL,UNUSED}, + {F_T_INT,&global_settings.rec_histogram_interval,LANG_RECORDING_HISTOGRAM_INTERVAL,INT(0), + "histogram interval","0.5s,1s,2s,4s",UNUSED}, + OFFON_SETTING(0, hist_def, LANG_RECORD_HIST_DRAW, true, "default histogram status", NULL), +#endif + {F_T_INT,&global_settings.peak_size,LANG_RECORD_PEAKMETER_SIZE,INT(0), + "peakmeter size", "1x,2x,3x,4x,5x,6x,7x,8x",UNUSED}, + #endif /* HAVE_RECORDING */ #ifdef HAVE_SPDIF_POWER diff -Naur _008/apps/tree.c _009_rep/apps/tree.c --- _008/apps/tree.c 2008-07-22 17:19:28.452046400 +0900 +++ _009_rep/apps/tree.c 2008-07-24 00:49:19.722312000 +0900 @@ -742,7 +742,6 @@ restore = true; } break; - case ACTION_TREE_WPS: return GO_TO_PREVIOUS_MUSIC; break;