rockbox/apps/menus/recording_menu.c
Jonathan Gordon efbcece07b New setting to control the file browser start location.
Set using the menu item in folder context menus, clear in the filebrowser settings.
    
    Can be abused to start selecting a *file* (or have a folder selected) instead of a starting inside a folder by removing the trailing / in the .cfg
    
    This only affects the file browser when it would open in / before (on boot, or when entereing after backing out of the browser before (*not* when exited with the menu action)



git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28206 a1c6a512-1295-4272-9138-f99709370657
2010-10-04 10:34:38 +00:00

689 lines
24 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2007 Jonathan Gordon
*
* 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 <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "string.h"
#include "system.h"
#include "kernel.h"
#include "lcd.h"
#include "menu.h"
#include "button.h"
#include "mp3_playback.h"
#include "settings.h"
#include "screens.h"
#include "icons.h"
#ifdef HAVE_LCD_BITMAP
#include "font.h"
#include "scrollbar.h"
#endif
#include "lang.h"
#include "talk.h"
#include "misc.h"
#include "sound.h"
#ifdef HAVE_RECORDING
#include "audio.h"
#if CONFIG_TUNER
#include "radio.h"
#endif
#endif
#ifdef HAVE_RECORDING
#include "peakmeter.h"
#include "mas.h"
#endif
#include "splash.h"
#if CONFIG_CODEC == SWCODEC
#include "metadata.h"
#include "dsp.h"
#include "menus/eq_menu.h"
#ifdef HAVE_RECORDING
#include "enc_config.h"
#endif
#include "general.h"
#endif
#include "action.h"
#include "recording.h"
#include "sound_menu.h"
#include "option_select.h"
#include "settings_list.h"
#include "list.h"
#include "viewport.h"
#include "exported_menus.h"
static bool no_source_in_menu = false;
static int recmenu_callback(int action,const struct menu_item_ex *this_item);
static int recsource_func(void)
{
int n_opts = REC_NUM_SOURCES;
static const struct opt_items names[AUDIO_NUM_SOURCES] = {
HAVE_MIC_REC_([AUDIO_SRC_MIC]
= { STR(LANG_RECORDING_SRC_MIC) },)
HAVE_LINE_REC_([AUDIO_SRC_LINEIN]
= { STR(LANG_LINE_IN) },)
HAVE_SPDIF_REC_([AUDIO_SRC_SPDIF]
= { STR(LANG_RECORDING_SRC_DIGITAL) },)
HAVE_FMRADIO_REC_([AUDIO_SRC_FMRADIO]
= { STR(LANG_FM_RADIO) },)
};
/* caveat: assumes it's the last item! */
#ifdef HAVE_FMRADIO_REC
if (!radio_hardware_present())
n_opts--;
#endif
return set_option(str(LANG_RECORDING_SOURCE),
&global_settings.rec_source, INT, names,
n_opts, NULL );
}
MENUITEM_FUNCTION(recsource, 0, ID2P(LANG_RECORDING_SOURCE),
recsource_func, NULL, recmenu_callback, Icon_Menu_setting);
#if CONFIG_CODEC == SWCODEC
/* Makes an options list from a source list of options and indexes */
static void make_options_from_indexes(const struct opt_items *src_names,
const long *src_indexes,
int n_indexes,
struct opt_items *dst_names)
{
while (--n_indexes >= 0)
dst_names[n_indexes] = src_names[src_indexes[n_indexes]];
} /* make_options_from_indexes */
#endif /* CONFIG_CODEC == SWCODEC */
static int recfrequency_func(void)
{
#if CONFIG_CODEC == MAS3587F
static const struct opt_items names[6] = {
{ "44.1kHz", TALK_ID(44, UNIT_KHZ) },
{ "48kHz", TALK_ID(48, UNIT_KHZ) },
{ "32kHz", TALK_ID(32, UNIT_KHZ) },
{ "22.05kHz", TALK_ID(22, UNIT_KHZ) },
{ "24kHz", TALK_ID(24, UNIT_KHZ) },
{ "16kHz", TALK_ID(16, UNIT_KHZ) }
};
return set_option(str(LANG_RECORDING_FREQUENCY),
&global_settings.rec_frequency, INT,
names, 6, NULL );
#endif /* CONFIG_CODEC == MAS3587F */
#if CONFIG_CODEC == SWCODEC
static const struct opt_items names[REC_NUM_FREQ] = {
REC_HAVE_96_([REC_FREQ_96] = { "96kHz", TALK_ID(96, UNIT_KHZ) },)
REC_HAVE_88_([REC_FREQ_88] = { "88.2kHz", TALK_ID(88, UNIT_KHZ) },)
REC_HAVE_64_([REC_FREQ_64] = { "64kHz", TALK_ID(64, UNIT_KHZ) },)
REC_HAVE_48_([REC_FREQ_48] = { "48kHz", TALK_ID(48, UNIT_KHZ) },)
REC_HAVE_44_([REC_FREQ_44] = { "44.1kHz", TALK_ID(44, UNIT_KHZ) },)
REC_HAVE_32_([REC_FREQ_32] = { "32kHz", TALK_ID(32, UNIT_KHZ) },)
REC_HAVE_24_([REC_FREQ_24] = { "24kHz", TALK_ID(24, UNIT_KHZ) },)
REC_HAVE_22_([REC_FREQ_22] = { "22.05kHz", TALK_ID(22, UNIT_KHZ) },)
REC_HAVE_16_([REC_FREQ_16] = { "16kHz", TALK_ID(16, UNIT_KHZ) },)
REC_HAVE_12_([REC_FREQ_12] = { "12kHz", TALK_ID(12, UNIT_KHZ) },)
REC_HAVE_11_([REC_FREQ_11] = { "11.025kHz", TALK_ID(11, UNIT_KHZ) },)
REC_HAVE_8_( [REC_FREQ_8 ] = { "8kHz", TALK_ID( 8, UNIT_KHZ) },)
};
struct opt_items opts[REC_NUM_FREQ];
unsigned long table[REC_NUM_FREQ];
int n_opts;
int rec_frequency;
bool ret;
#ifdef HAVE_SPDIF_REC
if (global_settings.rec_source == REC_SRC_SPDIF)
{
/* Inform user that frequency follows the source's frequency */
opts[0].string = ID2P(LANG_SOURCE_FREQUENCY);
opts[0].voice_id = LANG_SOURCE_FREQUENCY;
n_opts = 1;
rec_frequency = 0;
}
else
#endif
{
struct encoder_caps caps;
struct encoder_config cfg;
cfg.rec_format = global_settings.rec_format;
global_to_encoder_config(&cfg);
if (!enc_get_caps(&cfg, &caps, true))
return false;
/* Construct samplerate menu based upon encoder settings */
n_opts = make_list_from_caps32(REC_SAMPR_CAPS, NULL,
caps.samplerate_caps, table);
if (n_opts == 0)
return false; /* No common flags...?? */
make_options_from_indexes(names, table, n_opts, opts);
/* Find closest rate that the potentially restricted list
comes to */
make_list_from_caps32(REC_SAMPR_CAPS, rec_freq_sampr,
caps.samplerate_caps, table);
rec_frequency = round_value_to_list32(
rec_freq_sampr[global_settings.rec_frequency],
table, n_opts, false);
}
ret = set_option(str(LANG_RECORDING_FREQUENCY),
&rec_frequency, INT, opts, n_opts, NULL );
if (!ret
HAVE_SPDIF_REC_( && global_settings.rec_source != REC_SRC_SPDIF)
)
{
/* Translate back to full index */
global_settings.rec_frequency =
round_value_to_list32(table[rec_frequency],
rec_freq_sampr,
REC_NUM_FREQ,
false);
}
return ret;
#endif /* CONFIG_CODEC == SWCODEC */
} /* recfrequency */
MENUITEM_FUNCTION(recfrequency, 0, ID2P(LANG_RECORDING_FREQUENCY),
recfrequency_func, NULL, NULL, Icon_Menu_setting);
static int recchannels_func(void)
{
static const struct opt_items names[CHN_NUM_MODES] = {
[CHN_MODE_STEREO] = { STR(LANG_CHANNEL_STEREO) },
[CHN_MODE_MONO] = { STR(LANG_CHANNEL_MONO) }
};
#if CONFIG_CODEC == MAS3587F
return set_option(str(LANG_CHANNELS),
&global_settings.rec_channels, INT,
names, CHN_NUM_MODES, NULL );
#endif /* CONFIG_CODEC == MAS3587F */
#if CONFIG_CODEC == SWCODEC
struct opt_items opts[CHN_NUM_MODES];
long table[CHN_NUM_MODES];
struct encoder_caps caps;
struct encoder_config cfg;
int n_opts;
int rec_channels;
bool ret;
cfg.rec_format = global_settings.rec_format;
global_to_encoder_config(&cfg);
if (!enc_get_caps(&cfg, &caps, true))
return false;
n_opts = make_list_from_caps32(CHN_CAP_ALL, NULL,
caps.channel_caps, table);
rec_channels = round_value_to_list32(global_settings.rec_channels,
table, n_opts, false);
make_options_from_indexes(names, table, n_opts, opts);
ret = set_option(str(LANG_CHANNELS), &rec_channels,
INT, opts, n_opts, NULL );
if (!ret)
global_settings.rec_channels = table[rec_channels];
return ret;
#endif /* CONFIG_CODEC == SWCODEC */
}
MENUITEM_FUNCTION(recchannels, 0, ID2P(LANG_CHANNELS),
recchannels_func, NULL, NULL, Icon_Menu_setting);
#if CONFIG_CODEC == SWCODEC
static int recmonomode_func(void)
{
static const struct opt_items names[3] = {
[0] = { STR(LANG_CHANNEL_LEFTRIGHT) },
[1] = { STR(LANG_CHANNEL_LEFT) },
[2] = { STR(LANG_CHANNEL_RIGHT) },
};
int rec_mono_mode = global_settings.rec_mono_mode;
bool ret = set_option(str(LANG_RECORDING_MONO_MODE), &rec_mono_mode,
INT, names, 3, NULL );
if (rec_mono_mode != global_settings.rec_mono_mode)
global_settings.rec_mono_mode = rec_mono_mode;
return ret;
}
MENUITEM_FUNCTION(recmonomode, 0, ID2P(LANG_RECORDING_MONO_MODE),
recmonomode_func, NULL, NULL, Icon_Menu_setting);
static int recformat_func(void)
{
static const struct opt_items names[REC_NUM_FORMATS] = {
[REC_FORMAT_AIFF] = { STR(LANG_AFMT_AIFF) },
[REC_FORMAT_MPA_L3] = { STR(LANG_AFMT_MPA_L3) },
[REC_FORMAT_WAVPACK] = { STR(LANG_AFMT_WAVPACK) },
[REC_FORMAT_PCM_WAV] = { STR(LANG_AFMT_PCM_WAV) },
};
int rec_format = global_settings.rec_format;
bool res = set_option(str(LANG_RECORDING_FORMAT), &rec_format, INT,
names, REC_NUM_FORMATS, NULL );
if (rec_format != global_settings.rec_format)
{
global_settings.rec_format = rec_format;
enc_global_settings_apply();
}
return res;
} /* recformat */
MENUITEM_FUNCTION(recformat, 0, ID2P(LANG_RECORDING_FORMAT),
recformat_func, NULL, NULL, Icon_Menu_setting);
MENUITEM_FUNCTION(enc_global_config_menu_item, 0, ID2P(LANG_ENCODER_SETTINGS),
(int(*)(void))enc_global_config_menu,
NULL, NULL, Icon_Submenu);
#endif /* CONFIG_CODEC == SWCODEC */
static int recmenu_callback(int action,const struct menu_item_ex *this_item)
{
switch (action)
{
case ACTION_REQUEST_MENUITEM:
if (this_item == &recsource && no_source_in_menu)
return ACTION_EXIT_MENUITEM;
break;
}
return action;
}
#if CONFIG_CODEC == MAS3587F
MENUITEM_SETTING(rec_quality, &global_settings.rec_quality, NULL);
MENUITEM_SETTING(rec_editable, &global_settings.rec_editable, NULL);
#endif
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);
MENUITEM_SETTING(rec_prerecord_time, &global_settings.rec_prerecord_time, NULL);
static int clear_rec_directory(void)
{
strcpy(global_settings.rec_directory, REC_BASE_DIR);
settings_save();
splash(HZ, ID2P(LANG_RESET_DONE_CLEAR));
return false;
}
MENUITEM_FUNCTION(clear_rec_directory_item, 0, ID2P(LANG_CLEAR_REC_DIR),
clear_rec_directory, NULL, NULL, Icon_Folder);
MENUITEM_SETTING(cliplight, &global_settings.cliplight, NULL);
#ifdef HAVE_AGC
static int agc_preset_func(void)
{
static const struct opt_items names[] = {
{ STR(LANG_OFF) },
{ STR(LANG_AGC_SAFETY) },
{ STR(LANG_AGC_LIVE) },
{ STR(LANG_AGC_DJSET) },
{ STR(LANG_AGC_MEDIUM) },
{ STR(LANG_AGC_VOICE) },
};
if (global_settings.rec_source)
return set_option(str(LANG_RECORDING_AGC_PRESET),
&global_settings.rec_agc_preset_line,
INT, names, 6, NULL );
else
return set_option(str(LANG_RECORDING_AGC_PRESET),
&global_settings.rec_agc_preset_mic,
INT, names, 6, NULL );
}
static int agc_cliptime_func(void)
{
static const struct opt_items names[] = {
{ "200ms", TALK_ID(200, UNIT_MS) },
{ "400ms", TALK_ID(400, UNIT_MS) },
{ "600ms", TALK_ID(600, UNIT_MS) },
{ "800ms", TALK_ID(800, UNIT_MS) },
{ "1s", TALK_ID(1, UNIT_SEC) }
};
return set_option(str(LANG_RECORDING_AGC_CLIPTIME),
&global_settings.rec_agc_cliptime,
INT, names, 5, NULL );
}
MENUITEM_FUNCTION(agc_preset, 0, ID2P(LANG_RECORDING_AGC_PRESET),
agc_preset_func, NULL, NULL, Icon_Menu_setting);
MENUITEM_FUNCTION(agc_cliptime, 0, ID2P(LANG_RECORDING_AGC_CLIPTIME),
agc_cliptime_func, NULL, NULL, Icon_Menu_setting);
#endif /* HAVE_AGC */
#if defined(HAVE_RECORDING_HISTOGRAM)
static bool history_interval(void)
{
static const struct opt_items names[] = {
{ "0s", TALK_ID(0, UNIT_SEC) },
{ "1s", TALK_ID(1, UNIT_SEC) },
{ "2s", TALK_ID(2, UNIT_SEC) },
{ "4s", TALK_ID(4, UNIT_SEC) }
};
return set_option(str(LANG_RECORDING_HISTOGRAM_INTERVAL),
&global_settings.rec_histogram_interval,
INT, names, 4, NULL );
}
MENUITEM_FUNCTION(recording_histogram, 0,
ID2P(LANG_RECORDING_HISTOGRAM_INTERVAL),
history_interval, NULL, NULL, Icon_Menu_setting);
#endif
/** Rec trigger **/
enum trigger_menu_option
{
TRIGGER_MODE,
TRIGGER_TYPE,
PRERECORD_TIME,
START_THRESHOLD,
START_DURATION,
STOP_THRESHOLD,
STOP_POSTREC,
STOP_GAP,
TRIG_OPTION_COUNT,
};
static enum themable_icons trigger_get_icon(int selected_item, void * data)
{
(void)data;
if ((selected_item % 2) == 0) /* header */
return Icon_Menu_setting;
return Icon_NOICON;
}
static const char * trigger_get_name(int selected_item, void * data,
char * buffer, size_t buffer_len)
{
const struct settings_list **settings =
(const struct settings_list **)data;
const struct settings_list *s = settings[selected_item / 2];
if ((selected_item % 2) == 0) /* header */
return P2STR(ID2P(s->lang_id));
else
{
int temp;
temp = option_value_as_int(s);
if ((selected_item / 2 == START_THRESHOLD ||
selected_item / 2 == STOP_THRESHOLD) &&
temp == 0)
{
return str(LANG_OFF);
}
return option_get_valuestring(s, buffer, buffer_len, temp);
}
}
static void trigger_speak_item(const struct settings_list **settings,
int selected_setting, bool title)
{
const struct settings_list *s = settings[selected_setting];
int temp;
if (!global_settings.talk_menu)
return;
if (title)
talk_id(s->lang_id, false);
temp = option_value_as_int(s);
if ((selected_setting == START_THRESHOLD ||
selected_setting == STOP_THRESHOLD) &&
temp == 0)
{
talk_id(LANG_OFF, title);
} else {
option_talk_value(s, temp, title);
}
}
int rectrigger(void)
{
struct viewport vp[NB_SCREENS], triggervp[NB_SCREENS];
struct gui_synclist lists;
int i, action = ACTION_REDRAW;
bool done = false, changed = true;
const struct settings_list *settings[TRIG_OPTION_COUNT];
int pm_x[NB_SCREENS];
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];
int old_start_thres_db = global_settings.rec_start_thres_db;
int old_start_thres_linear = global_settings.rec_start_thres_linear;
int old_start_duration = global_settings.rec_start_duration;
int old_prerecord_time = global_settings.rec_prerecord_time;
int old_stop_thres_db = global_settings.rec_stop_thres_db;
int old_stop_thres_linear = global_settings.rec_stop_thres_linear;
int old_stop_postrec = global_settings.rec_stop_postrec;
int old_stop_gap = global_settings.rec_stop_gap;
int old_trigger_mode = global_settings.rec_trigger_mode;
int old_trigger_type = global_settings.rec_trigger_type;
FOR_NB_SCREENS(i)
{
screens[i].clear_display();
screens[i].update();
viewport_set_defaults(&vp[i], i);
vp[i].height -= SYSFONT_HEIGHT*2;
triggervp[i] = vp[i];
triggervp[i].y = vp[i].y + vp[i].height;
triggervp[i].height = SYSFONT_HEIGHT*2;
trig_xpos[i] = 0;
trig_ypos[i] = 0;
pm_x[i] = 0;
pm_y[i] = SYSFONT_HEIGHT;
pm_h[i] = SYSFONT_HEIGHT;
trig_width[i] = triggervp[i].width;
}
/* TODO: what to do if there is < 4 lines on the screen? */
settings[TRIGGER_MODE] =
find_setting(&global_settings.rec_trigger_mode, NULL);
settings[TRIGGER_TYPE] =
find_setting(&global_settings.rec_trigger_type, NULL);
settings[PRERECORD_TIME] =
find_setting(&global_settings.rec_prerecord_time, NULL);
settings[START_DURATION] =
find_setting(&global_settings.rec_start_duration, NULL);
settings[STOP_POSTREC] =
find_setting(&global_settings.rec_stop_postrec, NULL);
settings[STOP_GAP] =
find_setting(&global_settings.rec_stop_gap, NULL);
if (global_settings.peak_meter_dbfs) /* show the dB settings */
{
settings[START_THRESHOLD] =
find_setting(&global_settings.rec_start_thres_db, NULL);
settings[STOP_THRESHOLD] =
find_setting(&global_settings.rec_stop_thres_db, NULL);
}
else
{
settings[START_THRESHOLD] =
find_setting(&global_settings.rec_start_thres_linear, NULL);
settings[STOP_THRESHOLD] =
find_setting(&global_settings.rec_stop_thres_linear, NULL);
}
gui_synclist_init(&lists, trigger_get_name, settings, false, 2, vp);
gui_synclist_set_nb_items(&lists, TRIG_OPTION_COUNT*2);
gui_synclist_set_icon_callback(&lists, global_settings.show_icons?trigger_get_icon:NULL);
/* restart trigger with new values */
settings_apply_trigger();
peak_meter_trigger (global_settings.rec_trigger_mode != TRIG_MODE_OFF);
trigger_speak_item(settings, 0, true);
while (!done)
{
if (changed)
{
gui_synclist_draw(&lists);
peak_meter_trigger(global_settings.rec_trigger_mode!=TRIG_OFF);
settings_apply_trigger();
changed = false;
}
FOR_NB_SCREENS(i)
screens[i].set_viewport(&triggervp[i]);
peak_meter_draw_trig(trig_xpos, trig_ypos, trig_width, NB_SCREENS);
action = peak_meter_draw_get_btn(CONTEXT_SETTINGS_RECTRIGGER,
pm_x, pm_y, pm_h, NB_SCREENS, triggervp);
FOR_NB_SCREENS(i)
screens[i].update();
i = gui_synclist_get_sel_pos(&lists);
switch (action)
{
case ACTION_STD_CANCEL:
splash(HZ/2, ID2P(LANG_CANCEL));
global_settings.rec_start_thres_db = old_start_thres_db;
global_settings.rec_start_thres_linear = old_start_thres_linear;
global_settings.rec_start_duration = old_start_duration;
global_settings.rec_prerecord_time = old_prerecord_time;
global_settings.rec_stop_thres_db = old_stop_thres_db;
global_settings.rec_stop_thres_linear = old_stop_thres_linear;
global_settings.rec_stop_postrec = old_stop_postrec;
global_settings.rec_stop_gap = old_stop_gap;
global_settings.rec_trigger_mode = old_trigger_mode;
global_settings.rec_trigger_type = old_trigger_type;
peak_meter_trigger(global_settings.rec_trigger_mode!=TRIG_OFF);
settings_apply_trigger();
done = true;
break;
case ACTION_STD_OK:
done = true;
break;
case ACTION_SETTINGS_DEC:
case ACTION_SETTINGS_DECREPEAT:
option_select_next_val(settings[i/2], true, false);
trigger_speak_item(settings, i/2, false);
changed = true;
break;
case ACTION_SETTINGS_INC:
case ACTION_SETTINGS_INCREPEAT:
option_select_next_val(settings[i/2], false, false);
trigger_speak_item(settings, i/2, false);
changed = true;
break;
case ACTION_STD_PREV:
case ACTION_STD_PREVREPEAT:
i -= 2;
if (i<0)
i = (TRIG_OPTION_COUNT*2) - 2;
gui_synclist_select_item(&lists, i);
i = gui_synclist_get_sel_pos(&lists);
trigger_speak_item(settings, i/2, true);
changed = true;
break;
case ACTION_STD_NEXT:
case ACTION_STD_NEXTREPEAT:
gui_synclist_select_item(&lists, (i+2) % (TRIG_OPTION_COUNT*2));
i = gui_synclist_get_sel_pos(&lists);
trigger_speak_item(settings, i/2, true);
changed = true;
break;
}
}
peak_meter_trigger(false);
settings_save();
return 0;
}
MENUITEM_FUNCTION(rectrigger_item, 0, ID2P(LANG_RECORD_TRIGGER),
rectrigger, NULL, NULL, Icon_Menu_setting);
static struct browse_folder_info rec_config_browse = {RECPRESETS_DIR, SHOW_CFG};
MENUITEM_FUNCTION(browse_recconfigs, MENU_FUNC_USEPARAM, ID2P(LANG_CUSTOM_CFG),
browse_folder, (void*)&rec_config_browse, NULL, Icon_Config);
static int write_settings_file(void)
{
return settings_save_config(SETTINGS_SAVE_RECPRESETS);
}
MENUITEM_FUNCTION(save_recpresets_item, 0, ID2P(LANG_SAVE_SETTINGS),
write_settings_file, NULL, NULL, Icon_Config);
MAKE_MENU(recording_settings_menu, ID2P(LANG_RECORDING_SETTINGS),
NULL, Icon_Recording,
#if CONFIG_CODEC == MAS3587F
&rec_quality,
#endif
#if CONFIG_CODEC == SWCODEC
&recformat, &enc_global_config_menu_item,
#endif
&recfrequency, &recsource, /* recsource not shown if no_source */
&recchannels,
#if CONFIG_CODEC == SWCODEC
&recmonomode,
#endif
#if CONFIG_CODEC == MAS3587F
&rec_editable,
#endif
&filesplitoptionsmenu,
&rec_prerecord_time,
&clear_rec_directory_item,
#ifdef HAVE_BACKLIGHT
&cliplight,
#endif
&rectrigger_item,
#ifdef HAVE_AGC
&agc_preset, &agc_cliptime,
#endif
#if defined(HAVE_RECORDING_HISTOGRAM)
&recording_histogram,
#endif
#ifdef HAVE_LCD_BITMAP
&peak_meter_menu,
#endif
&browse_recconfigs, &save_recpresets_item
);
bool recording_menu(bool no_source)
{
bool retval;
no_source_in_menu = no_source;
retval = do_menu(&recording_settings_menu, NULL, NULL, false) == MENU_ATTACHED_USB;
no_source_in_menu = false; /* always fall back to the default */
return retval;
};
MENUITEM_FUNCTION(recording_settings, MENU_FUNC_USEPARAM, ID2P(LANG_RECORDING_SETTINGS),
(int (*)(void*))recording_menu, 0, NULL, Icon_Recording);