Revert "Replace yield_codec() with a call to queue_wait_w_tmo()" and the related...
[Rockbox.git] / apps / menus / recording_menu.c
blob70389045d73d228357c160660acc4c8b4282741b
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 Jonathan Gordon
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "config.h"
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdbool.h>
24 #include "string.h"
25 #include "system.h"
26 #include "kernel.h"
27 #include "lcd.h"
28 #include "menu.h"
29 #include "button.h"
30 #include "mp3_playback.h"
31 #include "settings.h"
32 #include "statusbar.h"
33 #include "screens.h"
34 #include "icons.h"
35 #ifdef HAVE_LCD_BITMAP
36 #include "font.h"
37 #include "scrollbar.h"
38 #endif
39 #include "lang.h"
40 #include "sprintf.h"
41 #include "talk.h"
42 #include "misc.h"
43 #include "sound.h"
44 #ifdef HAVE_RECORDING
45 #include "audio.h"
46 #if CONFIG_TUNER
47 #include "radio.h"
48 #endif
49 #endif
50 #ifdef HAVE_RECORDING
51 #include "peakmeter.h"
52 #include "mas.h"
53 #endif
54 #include "splash.h"
55 #if CONFIG_CODEC == SWCODEC
56 #include "dsp.h"
57 #include "menus/eq_menu.h"
58 #include "pcmbuf.h"
59 #ifdef HAVE_RECORDING
60 #include "enc_config.h"
61 #endif
62 #include "general.h"
63 #endif
64 #include "action.h"
65 #include "recording.h"
68 static bool no_source_in_menu = false;
69 int recmenu_callback(int action,const struct menu_item_ex *this_item);
71 static int recsource_func(void)
73 int n_opts = REC_NUM_SOURCES;
75 static const struct opt_items names[AUDIO_NUM_SOURCES] = {
76 HAVE_MIC_REC_([AUDIO_SRC_MIC]
77 = { STR(LANG_RECORDING_SRC_MIC) },)
78 HAVE_LINE_REC_([AUDIO_SRC_LINEIN]
79 = { STR(LANG_LINE_IN) },)
80 HAVE_SPDIF_REC_([AUDIO_SRC_SPDIF]
81 = { STR(LANG_RECORDING_SRC_DIGITAL) },)
82 HAVE_FMRADIO_REC_([AUDIO_SRC_FMRADIO]
83 = { STR(LANG_FM_RADIO) },)
86 /* caveat: assumes it's the last item! */
87 #ifdef HAVE_FMRADIO_REC
88 if (!radio_hardware_present())
89 n_opts--;
90 #endif
92 return set_option(str(LANG_RECORDING_SOURCE),
93 &global_settings.rec_source, INT, names,
94 n_opts, NULL );
96 MENUITEM_FUNCTION(recsource, 0, ID2P(LANG_RECORDING_SOURCE),
97 recsource_func, NULL, recmenu_callback, Icon_Menu_setting);
99 #if CONFIG_CODEC == SWCODEC
100 /* Makes an options list from a source list of options and indexes */
101 static void make_options_from_indexes(const struct opt_items *src_names,
102 const long *src_indexes,
103 int n_indexes,
104 struct opt_items *dst_names)
106 while (--n_indexes >= 0)
107 dst_names[n_indexes] = src_names[src_indexes[n_indexes]];
108 } /* make_options_from_indexes */
111 #endif /* CONFIG_CODEC == SWCODEC */
113 static int recfrequency_func(void)
115 #if CONFIG_CODEC == MAS3587F
116 static const struct opt_items names[6] = {
117 { "44.1kHz", TALK_ID(44, UNIT_KHZ) },
118 { "48kHz", TALK_ID(48, UNIT_KHZ) },
119 { "32kHz", TALK_ID(32, UNIT_KHZ) },
120 { "22.05kHz", TALK_ID(22, UNIT_KHZ) },
121 { "24kHz", TALK_ID(24, UNIT_KHZ) },
122 { "16kHz", TALK_ID(16, UNIT_KHZ) }
124 return set_option(str(LANG_RECORDING_FREQUENCY),
125 &global_settings.rec_frequency, INT,
126 names, 6, NULL );
127 #endif /* CONFIG_CODEC == MAS3587F */
129 #if CONFIG_CODEC == SWCODEC
130 static const struct opt_items names[REC_NUM_FREQ] = {
131 REC_HAVE_96_([REC_FREQ_96] = { "96kHz", TALK_ID(96, UNIT_KHZ) },)
132 REC_HAVE_88_([REC_FREQ_88] = { "88.2kHz", TALK_ID(88, UNIT_KHZ) },)
133 REC_HAVE_64_([REC_FREQ_64] = { "64kHz", TALK_ID(64, UNIT_KHZ) },)
134 REC_HAVE_48_([REC_FREQ_48] = { "48kHz", TALK_ID(48, UNIT_KHZ) },)
135 REC_HAVE_44_([REC_FREQ_44] = { "44.1kHz", TALK_ID(44, UNIT_KHZ) },)
136 REC_HAVE_32_([REC_FREQ_32] = { "32kHz", TALK_ID(32, UNIT_KHZ) },)
137 REC_HAVE_24_([REC_FREQ_24] = { "24kHz", TALK_ID(24, UNIT_KHZ) },)
138 REC_HAVE_22_([REC_FREQ_22] = { "22.05kHz", TALK_ID(22, UNIT_KHZ) },)
139 REC_HAVE_16_([REC_FREQ_16] = { "16kHz", TALK_ID(16, UNIT_KHZ) },)
140 REC_HAVE_12_([REC_FREQ_12] = { "12kHz", TALK_ID(12, UNIT_KHZ) },)
141 REC_HAVE_11_([REC_FREQ_11] = { "11.025kHz", TALK_ID(11, UNIT_KHZ) },)
142 REC_HAVE_8_( [REC_FREQ_8 ] = { "8kHz", TALK_ID( 8, UNIT_KHZ) },)
145 struct opt_items opts[REC_NUM_FREQ];
146 unsigned long table[REC_NUM_FREQ];
147 int n_opts;
148 int rec_frequency;
149 bool ret;
151 #ifdef HAVE_SPDIF_REC
152 if (global_settings.rec_source == REC_SRC_SPDIF)
154 /* Inform user that frequency follows the source's frequency */
155 opts[0].string = ID2P(LANG_SOURCE_FREQUENCY);
156 opts[0].voice_id = LANG_SOURCE_FREQUENCY;
157 n_opts = 1;
158 rec_frequency = 0;
160 else
161 #endif
163 struct encoder_caps caps;
164 struct encoder_config cfg;
166 cfg.rec_format = global_settings.rec_format;
167 global_to_encoder_config(&cfg);
169 if (!enc_get_caps(&cfg, &caps, true))
170 return false;
172 /* Construct samplerate menu based upon encoder settings */
173 n_opts = make_list_from_caps32(REC_SAMPR_CAPS, NULL,
174 caps.samplerate_caps, table);
176 if (n_opts == 0)
177 return false; /* No common flags...?? */
179 make_options_from_indexes(names, table, n_opts, opts);
181 /* Find closest rate that the potentially restricted list
182 comes to */
183 make_list_from_caps32(REC_SAMPR_CAPS, rec_freq_sampr,
184 caps.samplerate_caps, table);
186 rec_frequency = round_value_to_list32(
187 rec_freq_sampr[global_settings.rec_frequency],
188 table, n_opts, false);
191 ret = set_option(str(LANG_RECORDING_FREQUENCY),
192 &rec_frequency, INT, opts, n_opts, NULL );
194 if (!ret
195 HAVE_SPDIF_REC_( && global_settings.rec_source != REC_SRC_SPDIF)
198 /* Translate back to full index */
199 global_settings.rec_frequency =
200 round_value_to_list32(table[rec_frequency],
201 rec_freq_sampr,
202 REC_NUM_FREQ,
203 false);
206 return ret;
207 #endif /* CONFIG_CODEC == SWCODEC */
208 } /* recfrequency */
209 MENUITEM_FUNCTION(recfrequency, 0, ID2P(LANG_RECORDING_FREQUENCY),
210 recfrequency_func, NULL, NULL, Icon_Menu_setting);
213 static int recchannels_func(void)
215 static const struct opt_items names[CHN_NUM_MODES] = {
216 [CHN_MODE_STEREO] = { STR(LANG_CHANNEL_STEREO) },
217 [CHN_MODE_MONO] = { STR(LANG_CHANNEL_MONO) }
219 #if CONFIG_CODEC == MAS3587F
220 return set_option(str(LANG_CHANNELS),
221 &global_settings.rec_channels, INT,
222 names, CHN_NUM_MODES, NULL );
223 #endif /* CONFIG_CODEC == MAS3587F */
225 #if CONFIG_CODEC == SWCODEC
226 struct opt_items opts[CHN_NUM_MODES];
227 long table[CHN_NUM_MODES];
228 struct encoder_caps caps;
229 struct encoder_config cfg;
230 int n_opts;
231 int rec_channels;
232 bool ret;
234 cfg.rec_format = global_settings.rec_format;
235 global_to_encoder_config(&cfg);
237 if (!enc_get_caps(&cfg, &caps, true))
238 return false;
240 n_opts = make_list_from_caps32(CHN_CAP_ALL, NULL,
241 caps.channel_caps, table);
243 rec_channels = round_value_to_list32(global_settings.rec_channels,
244 table, n_opts, false);
246 make_options_from_indexes(names, table, n_opts, opts);
248 ret = set_option(str(LANG_CHANNELS), &rec_channels,
249 INT, opts, n_opts, NULL );
251 if (!ret)
252 global_settings.rec_channels = table[rec_channels];
254 return ret;
255 #endif /* CONFIG_CODEC == SWCODEC */
257 MENUITEM_FUNCTION(recchannels, 0, ID2P(LANG_CHANNELS),
258 recchannels_func, NULL, NULL, Icon_Menu_setting);
260 #if CONFIG_CODEC == SWCODEC
262 static int recformat_func(void)
264 static const struct opt_items names[REC_NUM_FORMATS] = {
265 [REC_FORMAT_AIFF] = { STR(LANG_AFMT_AIFF) },
266 [REC_FORMAT_MPA_L3] = { STR(LANG_AFMT_MPA_L3) },
267 [REC_FORMAT_WAVPACK] = { STR(LANG_AFMT_WAVPACK) },
268 [REC_FORMAT_PCM_WAV] = { STR(LANG_AFMT_PCM_WAV) },
271 int rec_format = global_settings.rec_format;
272 bool res = set_option(str(LANG_RECORDING_FORMAT), &rec_format, INT,
273 names, REC_NUM_FORMATS, NULL );
275 if (rec_format != global_settings.rec_format)
277 global_settings.rec_format = rec_format;
278 enc_global_settings_apply();
281 return res;
282 } /* recformat */
283 MENUITEM_FUNCTION(recformat, 0, ID2P(LANG_RECORDING_FORMAT),
284 recformat_func, NULL, NULL, Icon_Menu_setting);
286 MENUITEM_FUNCTION(enc_global_config_menu_item, 0, ID2P(LANG_ENCODER_SETTINGS),
287 (int(*)(void))enc_global_config_menu,
288 NULL, NULL, Icon_Submenu);
290 #endif /* CONFIG_CODEC == SWCODEC */
293 int recmenu_callback(int action,const struct menu_item_ex *this_item)
295 switch (action)
297 case ACTION_REQUEST_MENUITEM:
298 if (this_item == &recsource && no_source_in_menu)
299 return ACTION_EXIT_MENUITEM;
300 break;
302 return action;
304 #if CONFIG_CODEC == MAS3587F
305 MENUITEM_SETTING(rec_quality, &global_settings.rec_quality, NULL);
306 MENUITEM_SETTING(rec_editable, &global_settings.rec_editable, NULL);
307 #endif
309 MENUITEM_SETTING(rec_split_type, &global_settings.rec_split_type, NULL);
310 MENUITEM_SETTING(rec_split_method, &global_settings.rec_split_method, NULL);
311 MENUITEM_SETTING(rec_timesplit, &global_settings.rec_timesplit, NULL);
312 MENUITEM_SETTING(rec_sizesplit, &global_settings.rec_sizesplit, NULL);
313 MAKE_MENU(filesplitoptionsmenu, ID2P(LANG_RECORD_TIMESPLIT), NULL, Icon_NOICON,
314 &rec_split_method, &rec_split_type, &rec_timesplit, &rec_sizesplit);
317 MENUITEM_SETTING(rec_prerecord_time, &global_settings.rec_prerecord_time, NULL);
319 static int clear_rec_directory(void)
321 strcpy(global_settings.rec_directory, REC_BASE_DIR);
322 gui_syncsplash(HZ, str(LANG_RESET_DONE_CLEAR));
323 return false;
325 MENUITEM_FUNCTION(clear_rec_directory_item, 0, ID2P(LANG_CLEAR_REC_DIR),
326 clear_rec_directory, NULL, NULL, Icon_Folder);
328 MENUITEM_SETTING(cliplight, &global_settings.cliplight, NULL);
330 #ifdef HAVE_AGC
331 static int agc_preset_func(void)
333 static const struct opt_items names[] = {
334 { STR(LANG_OFF) },
335 { STR(LANG_AGC_SAFETY) },
336 { STR(LANG_AGC_LIVE) },
337 { STR(LANG_AGC_DJSET) },
338 { STR(LANG_AGC_MEDIUM) },
339 { STR(LANG_AGC_VOICE) },
341 if (global_settings.rec_source)
342 return set_option(str(LANG_RECORD_AGC_PRESET),
343 &global_settings.rec_agc_preset_line,
344 INT, names, 6, NULL );
345 else
346 return set_option(str(LANG_RECORD_AGC_PRESET),
347 &global_settings.rec_agc_preset_mic,
348 INT, names, 6, NULL );
351 static int agc_cliptime_func(void)
353 static const struct opt_items names[] = {
354 { "200ms", TALK_ID(200, UNIT_MS) },
355 { "400ms", TALK_ID(400, UNIT_MS) },
356 { "600ms", TALK_ID(600, UNIT_MS) },
357 { "800ms", TALK_ID(800, UNIT_MS) },
358 { "1s", TALK_ID(1, UNIT_SEC) }
360 return set_option(str(LANG_RECORD_AGC_CLIPTIME),
361 &global_settings.rec_agc_cliptime,
362 INT, names, 5, NULL );
364 MENUITEM_FUNCTION(agc_preset, 0, ID2P(LANG_RECORD_AGC_PRESET),
365 agc_preset_func, NULL, NULL, Icon_Menu_setting);
366 MENUITEM_FUNCTION(agc_cliptime, 0, ID2P(LANG_RECORD_AGC_CLIPTIME),
367 agc_cliptime_func, NULL, NULL, Icon_Menu_setting);
368 #endif /* HAVE_AGC */
370 /** Rec trigger **/
371 enum trigger_menu_option
373 TRIGGER_MODE,
374 TRIGGER_TYPE,
375 PRERECORD_TIME,
376 START_THRESHOLD,
377 START_DURATION,
378 STOP_THRESHOLD,
379 STOP_POSTREC,
380 STOP_GAP,
381 TRIG_OPTION_COUNT,
384 static char* create_thres_str(int threshold, long *voice_id)
386 static char retval[6];
387 if (threshold < 0) {
388 if (threshold < -88) {
389 snprintf (retval, sizeof retval, "%s", str(LANG_DB_INF));
390 if(voice_id)
391 *voice_id = LANG_DB_INF;
392 } else {
393 snprintf (retval, sizeof retval, "%ddb", threshold + 1);
394 if(voice_id)
395 *voice_id = TALK_ID(threshold + 1, UNIT_DB);
397 } else {
398 snprintf (retval, sizeof retval, "%d%%", threshold);
399 if(voice_id)
400 *voice_id = TALK_ID(threshold, UNIT_PERCENT);
402 return retval;
405 #define INF_DB (-89)
406 static void change_threshold(int *threshold, int change)
408 if (global_settings.peak_meter_dbfs) {
409 if (*threshold >= 0) {
410 int db = (calc_db(*threshold * MAX_PEAK / 100) - 9000) / 100;
411 *threshold = db;
413 *threshold += change;
414 if (*threshold > -1) {
415 *threshold = INF_DB;
416 } else if (*threshold < INF_DB) {
417 *threshold = -1;
419 } else {
420 if (*threshold < 0) {
421 *threshold = peak_meter_db2sample(*threshold * 100) * 100 / MAX_PEAK;
423 *threshold += change;
424 if (*threshold > 100) {
425 *threshold = 0;
426 } else if (*threshold < 0) {
427 *threshold = 100;
433 * Displays a menu for editing the trigger settings.
435 bool rectrigger(void)
437 int exit_request = false;
438 enum trigger_menu_option selected = TRIGGER_MODE;
439 bool retval = false;
440 int old_x_margin[NB_SCREENS];
441 int old_y_margin[NB_SCREENS];
443 #define TRIGGER_MODE_COUNT 3
444 static const unsigned char *trigger_modes[] = {
445 ID2P(LANG_OFF),
446 ID2P(LANG_RECORD_TRIG_NOREARM),
447 ID2P(LANG_REPEAT)
450 #define PRERECORD_TIMES_COUNT 31
451 static const struct opt_items prerecord_times[] = {
452 { STR(LANG_OFF) },
453 #define T(x) { (unsigned char *)(#x "s"), TALK_ID(x, UNIT_SEC) }
454 T(1), T(2), T(3), T(4), T(5), T(6), T(7), T(8), T(9), T(10),
455 T(11), T(12), T(13), T(14), T(15), T(16), T(17), T(18), T(19), T(20),
456 T(21), T(22), T(23), T(24), T(25), T(26), T(27), T(28), T(29), T(30),
457 #undef T
460 #define TRIGGER_TYPE_COUNT 3
461 static const unsigned char *trigger_types[] = {
462 ID2P(LANG_RECORD_TRIGGER_STOP),
463 ID2P(LANG_PAUSE),
464 ID2P(LANG_RECORD_TRIGGER_NEWFILESTP),
467 static const unsigned char *option_name[] = {
468 [TRIGGER_MODE] = ID2P(LANG_RECORD_TRIGGER),
469 [TRIGGER_TYPE] = ID2P(LANG_RECORD_TRIGGER_TYPE),
470 [PRERECORD_TIME] = ID2P(LANG_RECORD_PRERECORD_TIME),
471 [START_THRESHOLD] = ID2P(LANG_RECORD_START_THRESHOLD),
472 [START_DURATION] = ID2P(LANG_MIN_DURATION),
473 [STOP_THRESHOLD] = ID2P(LANG_RECORD_STOP_THRESHOLD),
474 [STOP_POSTREC] = ID2P(LANG_MIN_DURATION),
475 [STOP_GAP] = ID2P(LANG_RECORD_STOP_GAP)
478 int old_start_thres = global_settings.rec_start_thres;
479 int old_start_duration = global_settings.rec_start_duration;
480 int old_prerecord_time = global_settings.rec_prerecord_time;
481 int old_stop_thres = global_settings.rec_stop_thres;
482 int old_stop_postrec = global_settings.rec_stop_postrec;
483 int old_stop_gap = global_settings.rec_stop_gap;
484 int old_trigger_mode = global_settings.rec_trigger_mode;
485 int old_trigger_type = global_settings.rec_trigger_type;
487 int offset[NB_SCREENS];
488 int option_lines[NB_SCREENS];
489 int w, h, i;
490 int stat_height = global_settings.statusbar ? STATUSBAR_HEIGHT : 0;
491 int pm_y[NB_SCREENS];
493 int trig_xpos[NB_SCREENS];
494 int trig_ypos[NB_SCREENS];
495 int trig_width[NB_SCREENS];
497 bool say_field = true, say_value = true;
499 FOR_NB_SCREENS(i)
501 offset[i] = 0;
502 trig_xpos[i] = 0;
503 trig_ypos[i] = screens[i].height - stat_height - TRIG_HEIGHT;
504 pm_y[i] = screens[i].height - stat_height;
505 trig_width[i] = screens[i].width;
508 /* restart trigger with new values */
509 settings_apply_trigger();
510 peak_meter_trigger (global_settings.rec_trigger_mode != TRIG_MODE_OFF);
512 FOR_NB_SCREENS(i)
514 screens[i].clear_display();
516 old_x_margin[i] = screens[i].getxmargin();
517 old_y_margin[i] = screens[i].getymargin();
518 if(global_settings.statusbar)
519 screens[i].setmargins(0, STATUSBAR_HEIGHT);
520 else
521 screens[i].setmargins(0, 0);
523 screens[i].getstringsize("M", &w, &h);
525 // 16 pixels are reserved for peak meter and trigger status
526 option_lines[i] = MIN(((screens[i].height) -
527 stat_height - 16)/h,
528 TRIG_OPTION_COUNT);
531 while (!exit_request) {
532 int button, k;
533 const char *str;
534 char option_value[TRIG_OPTION_COUNT][16];
536 snprintf(
537 option_value[TRIGGER_MODE],
538 sizeof option_value[TRIGGER_MODE],
539 "%s",
540 P2STR(trigger_modes[global_settings.rec_trigger_mode]));
542 snprintf(
543 option_value[TRIGGER_TYPE],
544 sizeof option_value[TRIGGER_TYPE],
545 "%s",
546 P2STR(trigger_types[global_settings.rec_trigger_type]));
548 snprintf (
549 option_value[PRERECORD_TIME],
550 sizeof option_value[PRERECORD_TIME],
551 "%s",
552 prerecord_times[global_settings.rec_prerecord_time].string);
554 /* due to value range shift (peak_meter_define_trigger) -1 is 0db */
555 if (global_settings.rec_start_thres == -1) {
556 str = str(LANG_OFF);
557 } else {
558 str = create_thres_str(global_settings.rec_start_thres, NULL);
560 snprintf(
561 option_value[START_THRESHOLD],
562 sizeof option_value[START_THRESHOLD],
563 "%s",
564 str);
566 snprintf(
567 option_value[START_DURATION],
568 sizeof option_value[START_DURATION],
569 "%s",
570 trig_durations[global_settings.rec_start_duration].string);
572 if (global_settings.rec_stop_thres <= INF_DB) {
573 str = str(LANG_OFF);
574 } else {
575 str = create_thres_str(global_settings.rec_stop_thres, NULL);
577 snprintf(
578 option_value[STOP_THRESHOLD],
579 sizeof option_value[STOP_THRESHOLD],
580 "%s",
581 str);
583 snprintf(
584 option_value[STOP_POSTREC],
585 sizeof option_value[STOP_POSTREC],
586 "%s",
587 trig_durations[global_settings.rec_stop_postrec].string);
589 snprintf(
590 option_value[STOP_GAP],
591 sizeof option_value[STOP_GAP],
592 "%s",
593 trig_durations[global_settings.rec_stop_gap].string);
595 FOR_NB_SCREENS(i)
597 screens[i].set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
598 screens[i].fillrect(0, stat_height, screens[i].width,
599 screens[i].height - stat_height);
600 screens[i].set_drawmode(DRMODE_SOLID);
603 gui_syncstatusbar_draw(&statusbars, true);
605 /* reselect FONT_SYSFONT as status_draw has changed the font */
606 /*lcd_setfont(FONT_SYSFIXED);*/
608 FOR_NB_SCREENS(i)
610 for (k = 0; k < option_lines[i]; k++) {
611 int x, y;
613 str = P2STR(option_name[k + offset[i]]);
614 screens[i].putsxy((option_lines[i] < TRIG_OPTION_COUNT) ? 5 : 0,
615 stat_height + k * h, str);
617 str = option_value[k + offset[i]];
618 screens[i].getstringsize(str, &w, &h);
619 y = stat_height + k * h;
620 x = screens[i].width - w;
621 screens[i].putsxy(x, y, str);
622 if ((int)selected == (k + offset[i])) {
623 screens[i].set_drawmode(DRMODE_COMPLEMENT);
624 screens[i].fillrect(x, y, w, h);
625 screens[i].set_drawmode(DRMODE_SOLID);
628 if (option_lines[i] < TRIG_OPTION_COUNT)
629 gui_scrollbar_draw(&screens[i], 0, stat_height,
630 4, screens[i].height - 16 - stat_height,
631 TRIG_OPTION_COUNT, offset[i], offset[i] + option_lines[i],
632 VERTICAL);
635 bool enqueue = false;
636 if(say_field) {
637 talk_id(P2ID(option_name[selected]), enqueue);
638 enqueue = true;
640 if(say_value) {
641 long id;
642 switch(selected) {
643 case TRIGGER_MODE:
644 id = P2ID(trigger_modes[global_settings.rec_trigger_mode]);
645 break;
646 case TRIGGER_TYPE:
647 id = P2ID(trigger_types[global_settings.rec_trigger_type]);
648 break;
649 case PRERECORD_TIME:
650 id = prerecord_times[global_settings.rec_prerecord_time]
651 .voice_id;
652 break;
653 case START_THRESHOLD:
654 if (global_settings.rec_start_thres == -1)
655 id = LANG_OFF;
656 else create_thres_str(global_settings.rec_start_thres, &id);
657 break;
658 case START_DURATION:
659 id = trig_durations[global_settings.rec_start_duration]
660 .voice_id;
661 break;
662 case STOP_THRESHOLD:
663 if (global_settings.rec_stop_thres <= INF_DB)
664 id = LANG_OFF;
665 else create_thres_str(global_settings.rec_stop_thres, &id);
666 break;
667 case STOP_POSTREC:
668 id = trig_durations[global_settings.rec_stop_postrec].voice_id;
669 break;
670 case STOP_GAP:
671 id = trig_durations[global_settings.rec_stop_gap].voice_id;
672 break;
673 case TRIG_OPTION_COUNT:
674 // avoid compiler warnings
675 break;
677 talk_id(id, enqueue);
679 say_field = say_value = false;
681 peak_meter_draw_trig(trig_xpos, trig_ypos, trig_width, NB_SCREENS);
682 button = peak_meter_draw_get_btn(0, pm_y, 8, NB_SCREENS);
684 FOR_NB_SCREENS(i)
685 screens[i].update();
687 switch (button) {
688 case ACTION_STD_CANCEL:
689 gui_syncsplash(50, str(LANG_CANCEL));
690 global_settings.rec_start_thres = old_start_thres;
691 global_settings.rec_start_duration = old_start_duration;
692 global_settings.rec_prerecord_time = old_prerecord_time;
693 global_settings.rec_stop_thres = old_stop_thres;
694 global_settings.rec_stop_postrec = old_stop_postrec;
695 global_settings.rec_stop_gap = old_stop_gap;
696 global_settings.rec_trigger_mode = old_trigger_mode;
697 global_settings.rec_trigger_type = old_trigger_type;
698 exit_request = true;
699 break;
701 case ACTION_REC_PAUSE:
702 exit_request = true;
703 break;
705 case ACTION_STD_PREV:
706 selected += TRIG_OPTION_COUNT - 1;
707 selected %= TRIG_OPTION_COUNT;
708 FOR_NB_SCREENS(i)
710 offset[i] = MIN(offset[i], (int)selected);
711 offset[i] = MAX(offset[i], (int)selected - option_lines[i] + 1);
713 say_field = say_value = true;
714 break;
716 case ACTION_STD_NEXT:
717 selected ++;
718 selected %= TRIG_OPTION_COUNT;
719 FOR_NB_SCREENS(i)
721 offset[i] = MIN(offset[i], (int)selected);
722 offset[i] = MAX(offset[i], (int)selected - option_lines[i] + 1);
724 say_field = say_value = true;
725 break;
727 case ACTION_SETTINGS_INC:
728 switch (selected) {
729 case TRIGGER_MODE:
730 global_settings.rec_trigger_mode ++;
731 global_settings.rec_trigger_mode %= TRIGGER_MODE_COUNT;
732 break;
734 case TRIGGER_TYPE:
735 global_settings.rec_trigger_type ++;
736 global_settings.rec_trigger_type %= TRIGGER_TYPE_COUNT;
737 break;
739 case PRERECORD_TIME:
740 global_settings.rec_prerecord_time ++;
741 global_settings.rec_prerecord_time %= PRERECORD_TIMES_COUNT;
742 break;
744 case START_THRESHOLD:
745 change_threshold(&global_settings.rec_start_thres, 1);
746 break;
748 case START_DURATION:
749 global_settings.rec_start_duration ++;
750 global_settings.rec_start_duration %= TRIG_DURATION_COUNT;
751 break;
753 case STOP_THRESHOLD:
754 change_threshold(&global_settings.rec_stop_thres, 1);
755 break;
757 case STOP_POSTREC:
758 global_settings.rec_stop_postrec ++;
759 global_settings.rec_stop_postrec %= TRIG_DURATION_COUNT;
760 break;
762 case STOP_GAP:
763 global_settings.rec_stop_gap ++;
764 global_settings.rec_stop_gap %= TRIG_DURATION_COUNT;
765 break;
767 case TRIG_OPTION_COUNT:
768 // avoid compiler warnings
769 break;
771 peak_meter_trigger(global_settings.rec_trigger_mode!=TRIG_OFF);
772 settings_apply_trigger();
773 say_value = true;
774 break;
776 case ACTION_SETTINGS_DEC:
777 switch (selected) {
778 case TRIGGER_MODE:
779 global_settings.rec_trigger_mode+=TRIGGER_MODE_COUNT-1;
780 global_settings.rec_trigger_mode %= TRIGGER_MODE_COUNT;
781 break;
783 case TRIGGER_TYPE:
784 global_settings.rec_trigger_type+=TRIGGER_TYPE_COUNT-1;
785 global_settings.rec_trigger_type %= TRIGGER_TYPE_COUNT;
786 break;
788 case PRERECORD_TIME:
789 global_settings.rec_prerecord_time += PRERECORD_TIMES_COUNT - 1;
790 global_settings.rec_prerecord_time %= PRERECORD_TIMES_COUNT;
791 break;
793 case START_THRESHOLD:
794 change_threshold(&global_settings.rec_start_thres, -1);
795 break;
797 case START_DURATION:
798 global_settings.rec_start_duration += TRIG_DURATION_COUNT-1;
799 global_settings.rec_start_duration %= TRIG_DURATION_COUNT;
800 break;
802 case STOP_THRESHOLD:
803 change_threshold(&global_settings.rec_stop_thres, -1);
804 break;
806 case STOP_POSTREC:
807 global_settings.rec_stop_postrec +=
808 TRIG_DURATION_COUNT - 1;
809 global_settings.rec_stop_postrec %=
810 TRIG_DURATION_COUNT;
811 break;
813 case STOP_GAP:
814 global_settings.rec_stop_gap +=
815 TRIG_DURATION_COUNT - 1;
816 global_settings.rec_stop_gap %= TRIG_DURATION_COUNT;
817 break;
819 case TRIG_OPTION_COUNT:
820 // avoid compiler warnings
821 break;
823 peak_meter_trigger(global_settings.rec_trigger_mode!=TRIG_OFF);
824 settings_apply_trigger();
825 say_value = true;
826 break;
828 case ACTION_REC_F2:
829 peak_meter_trigger(true);
830 break;
832 case SYS_USB_CONNECTED:
833 if(default_event_handler(button) == SYS_USB_CONNECTED) {
834 retval = true;
835 exit_request = true;
837 break;
841 peak_meter_trigger(false);
842 FOR_NB_SCREENS(i)
844 screens[i].setfont(FONT_UI);
845 screens[i].setmargins(old_x_margin[i], old_y_margin[i]);
847 return retval;
850 MENUITEM_FUNCTION(rectrigger_item, 0, ID2P(LANG_RECORD_TRIGGER),
851 (int(*)(void))rectrigger, NULL, NULL, Icon_Menu_setting);
858 /* from main_menu.c */
859 struct browse_folder_info {
860 const char* dir;
861 int show_options;
863 static struct browse_folder_info rec_config_browse = {RECPRESETS_DIR, SHOW_CFG};
864 int browse_folder(void *param);
865 MENUITEM_FUNCTION(browse_recconfigs, MENU_FUNC_USEPARAM, ID2P(LANG_CUSTOM_CFG),
866 browse_folder, (void*)&rec_config_browse, NULL, Icon_Config);
867 static int write_settings_file(void)
869 return settings_save_config(SETTINGS_SAVE_RECPRESETS);
871 MENUITEM_FUNCTION(save_recpresets_item, 0, ID2P(LANG_SAVE_SETTINGS),
872 write_settings_file, NULL, NULL, Icon_Config);
874 MAKE_MENU(recording_settings_menu, ID2P(LANG_RECORDING_SETTINGS),
875 NULL, Icon_Recording,
876 #if CONFIG_CODEC == MAS3587F
877 &rec_quality,
878 #endif
879 #if CONFIG_CODEC == SWCODEC
880 &recformat, &enc_global_config_menu_item,
881 #endif
882 &recfrequency, &recsource, /* recsource not shown if no_source */
883 &recchannels,
884 #if CONFIG_CODEC == MAS3587F
885 &rec_editable,
886 #endif
887 &filesplitoptionsmenu,
888 &rec_prerecord_time,
889 &clear_rec_directory_item,
890 #ifdef HAVE_BACKLIGHT
891 &cliplight,
892 #endif
893 &rectrigger_item,
894 #ifdef HAVE_AGC
895 &agc_preset, &agc_cliptime,
896 #endif
897 &browse_recconfigs, &save_recpresets_item
900 bool recording_menu(bool no_source)
902 bool retval;
903 no_source_in_menu = no_source;
904 retval = do_menu(&recording_settings_menu, NULL) == MENU_ATTACHED_USB;
905 no_source_in_menu = false; /* always fall back to the default */
906 return retval;
909 MENUITEM_FUNCTION(recording_settings, MENU_FUNC_USEPARAM, ID2P(LANG_RECORDING_SETTINGS),
910 (int (*)(void*))recording_menu, 0, NULL, Icon_Recording);