diff options
Diffstat (limited to 'apps/menus')
-rw-r--r-- | apps/menus/recording_menu.c | 826 |
1 files changed, 815 insertions, 11 deletions
diff --git a/apps/menus/recording_menu.c b/apps/menus/recording_menu.c index 248cf1655a..3d1bfcaf03 100644 --- a/apps/menus/recording_menu.c +++ b/apps/menus/recording_menu.c | |||
@@ -1,4 +1,3 @@ | |||
1 | |||
2 | /*************************************************************************** | 1 | /*************************************************************************** |
3 | * __________ __ ___. | 2 | * __________ __ ___. |
4 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
@@ -18,19 +17,824 @@ | |||
18 | * | 17 | * |
19 | ****************************************************************************/ | 18 | ****************************************************************************/ |
20 | 19 | ||
21 | #include <stdbool.h> | ||
22 | #include <stddef.h> | ||
23 | #include <limits.h> | ||
24 | #include "config.h" | 20 | #include "config.h" |
21 | #include <stdio.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <stdbool.h> | ||
24 | #include "system.h" | ||
25 | #include "kernel.h" | ||
26 | #include "lcd.h" | ||
27 | #include "menu.h" | ||
28 | #include "button.h" | ||
29 | #include "mp3_playback.h" | ||
30 | #include "settings.h" | ||
31 | #include "statusbar.h" | ||
32 | #include "screens.h" | ||
33 | #include "icons.h" | ||
34 | #ifdef HAVE_LCD_BITMAP | ||
35 | #include "font.h" | ||
36 | #include "scrollbar.h" | ||
37 | #endif | ||
25 | #include "lang.h" | 38 | #include "lang.h" |
39 | #include "sprintf.h" | ||
40 | #include "talk.h" | ||
41 | #include "misc.h" | ||
42 | #include "sound.h" | ||
43 | #ifdef HAVE_RECORDING | ||
44 | #include "audio.h" | ||
45 | #if CONFIG_TUNER | ||
46 | #include "radio.h" | ||
47 | #endif | ||
48 | #endif | ||
49 | #ifdef HAVE_RECORDING | ||
50 | #include "peakmeter.h" | ||
51 | #include "mas.h" | ||
52 | #endif | ||
53 | #include "splash.h" | ||
54 | #if CONFIG_CODEC == SWCODEC | ||
55 | #include "dsp.h" | ||
56 | #include "menus/eq_menu.h" | ||
57 | #include "pcmbuf.h" | ||
58 | #ifdef HAVE_RECORDING | ||
59 | #include "enc_config.h" | ||
60 | #endif | ||
61 | #include "general.h" | ||
62 | #endif | ||
26 | #include "action.h" | 63 | #include "action.h" |
27 | #include "settings.h" | ||
28 | #include "menu.h" | ||
29 | #include "recording.h" | ||
30 | 64 | ||
31 | #ifdef HAVE_RECORDING | 65 | static bool no_source_in_menu = true; |
32 | /* TEMP */ | 66 | int recmenu_callback(int action,const struct menu_item_ex *this_item); |
33 | bool recording_menu(bool no_source); /* from apps/sound_menu.h */ | 67 | |
68 | static int recsource_func(void) | ||
69 | { | ||
70 | int n_opts = AUDIO_NUM_SOURCES; | ||
71 | |||
72 | static const struct opt_items names[AUDIO_NUM_SOURCES] = { | ||
73 | [AUDIO_SRC_MIC] = { STR(LANG_RECORDING_SRC_MIC) }, | ||
74 | [AUDIO_SRC_LINEIN] = { STR(LANG_RECORDING_SRC_LINE) }, | ||
75 | #ifdef HAVE_SPDIF_IN | ||
76 | [AUDIO_SRC_SPDIF] = { STR(LANG_RECORDING_SRC_DIGITAL) }, | ||
77 | #endif | ||
78 | #ifdef HAVE_FMRADIO_IN | ||
79 | [AUDIO_SRC_FMRADIO] = { STR(LANG_FM_RADIO) } | ||
80 | #endif | ||
81 | }; | ||
82 | |||
83 | /* caveat: assumes it's the last item! */ | ||
84 | #ifdef HAVE_FMRADIO_IN | ||
85 | if (!radio_hardware_present()) | ||
86 | n_opts--; | ||
87 | #endif | ||
88 | |||
89 | return set_option(str(LANG_RECORDING_SOURCE), | ||
90 | &global_settings.rec_source, INT, names, | ||
91 | n_opts, NULL ); | ||
92 | } | ||
93 | MENUITEM_FUNCTION(recsource, ID2P(LANG_RECORDING_SOURCE), | ||
94 | recsource_func, recmenu_callback, Icon_Menu_setting); | ||
95 | |||
96 | #if CONFIG_CODEC == SWCODEC | ||
97 | /* Makes an options list from a source list of options and indexes */ | ||
98 | static void make_options_from_indexes(const struct opt_items *src_names, | ||
99 | const long *src_indexes, | ||
100 | int n_indexes, | ||
101 | struct opt_items *dst_names) | ||
102 | { | ||
103 | while (--n_indexes >= 0) | ||
104 | dst_names[n_indexes] = src_names[src_indexes[n_indexes]]; | ||
105 | } /* make_options_from_indexes */ | ||
106 | |||
107 | |||
108 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
109 | |||
110 | static int recfrequency_func(void) | ||
111 | { | ||
112 | #if CONFIG_CODEC == MAS3587F | ||
113 | static const struct opt_items names[6] = { | ||
114 | { "44.1kHz", TALK_ID(44, UNIT_KHZ) }, | ||
115 | { "48kHz", TALK_ID(48, UNIT_KHZ) }, | ||
116 | { "32kHz", TALK_ID(32, UNIT_KHZ) }, | ||
117 | { "22.05kHz", TALK_ID(22, UNIT_KHZ) }, | ||
118 | { "24kHz", TALK_ID(24, UNIT_KHZ) }, | ||
119 | { "16kHz", TALK_ID(16, UNIT_KHZ) } | ||
120 | }; | ||
121 | return set_option(str(LANG_RECORDING_FREQUENCY), | ||
122 | &global_settings.rec_frequency, INT, | ||
123 | names, 6, NULL ); | ||
124 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
125 | |||
126 | #if CONFIG_CODEC == SWCODEC | ||
127 | static const struct opt_items names[REC_NUM_FREQ] = { | ||
128 | REC_HAVE_96_([REC_FREQ_96] = { "96kHz", TALK_ID(96, UNIT_KHZ) },) | ||
129 | REC_HAVE_88_([REC_FREQ_88] = { "88.2kHz", TALK_ID(88, UNIT_KHZ) },) | ||
130 | REC_HAVE_64_([REC_FREQ_64] = { "64kHz", TALK_ID(64, UNIT_KHZ) },) | ||
131 | REC_HAVE_48_([REC_FREQ_48] = { "48kHz", TALK_ID(48, UNIT_KHZ) },) | ||
132 | REC_HAVE_44_([REC_FREQ_44] = { "44.1kHz", TALK_ID(44, UNIT_KHZ) },) | ||
133 | REC_HAVE_32_([REC_FREQ_32] = { "32kHz", TALK_ID(32, UNIT_KHZ) },) | ||
134 | REC_HAVE_24_([REC_FREQ_24] = { "24kHz", TALK_ID(24, UNIT_KHZ) },) | ||
135 | REC_HAVE_22_([REC_FREQ_22] = { "22.05kHz", TALK_ID(22, UNIT_KHZ) },) | ||
136 | REC_HAVE_16_([REC_FREQ_16] = { "16kHz", TALK_ID(16, UNIT_KHZ) },) | ||
137 | REC_HAVE_12_([REC_FREQ_12] = { "12kHz", TALK_ID(12, UNIT_KHZ) },) | ||
138 | REC_HAVE_11_([REC_FREQ_11] = { "11.025kHz", TALK_ID(11, UNIT_KHZ) },) | ||
139 | REC_HAVE_8_( [REC_FREQ_8 ] = { "8kHz", TALK_ID( 8, UNIT_KHZ) },) | ||
140 | }; | ||
141 | |||
142 | struct opt_items opts[REC_NUM_FREQ]; | ||
143 | unsigned long table[REC_NUM_FREQ]; | ||
144 | int n_opts; | ||
145 | int rec_frequency; | ||
146 | bool ret; | ||
147 | |||
148 | #ifdef HAVE_SPDIF_IN | ||
149 | if (global_settings.rec_source == AUDIO_SRC_SPDIF) | ||
150 | { | ||
151 | /* Inform user that frequency follows the source's frequency */ | ||
152 | opts[0].string = ID2P(LANG_SOURCE_FREQUENCY); | ||
153 | opts[0].voice_id = LANG_SOURCE_FREQUENCY; | ||
154 | n_opts = 1; | ||
155 | rec_frequency = 0; | ||
156 | } | ||
157 | else | ||
158 | #endif | ||
159 | { | ||
160 | struct encoder_caps caps; | ||
161 | struct encoder_config cfg; | ||
162 | |||
163 | cfg.rec_format = global_settings.rec_format; | ||
164 | global_to_encoder_config(&cfg); | ||
165 | |||
166 | if (!enc_get_caps(&cfg, &caps, true)) | ||
167 | return false; | ||
168 | |||
169 | /* Construct samplerate menu based upon encoder settings */ | ||
170 | n_opts = make_list_from_caps32(REC_SAMPR_CAPS, NULL, | ||
171 | caps.samplerate_caps, table); | ||
172 | |||
173 | if (n_opts == 0) | ||
174 | return false; /* No common flags...?? */ | ||
175 | |||
176 | make_options_from_indexes(names, table, n_opts, opts); | ||
177 | |||
178 | /* Find closest rate that the potentially restricted list | ||
179 | comes to */ | ||
180 | make_list_from_caps32(REC_SAMPR_CAPS, rec_freq_sampr, | ||
181 | caps.samplerate_caps, table); | ||
182 | |||
183 | rec_frequency = round_value_to_list32( | ||
184 | rec_freq_sampr[global_settings.rec_frequency], | ||
185 | table, n_opts, false); | ||
186 | } | ||
187 | |||
188 | ret = set_option(str(LANG_RECORDING_FREQUENCY), | ||
189 | &rec_frequency, INT, opts, n_opts, NULL ); | ||
190 | |||
191 | if (!ret | ||
192 | #ifdef HAVE_SPDIF_IN | ||
193 | && global_settings.rec_source != AUDIO_SRC_SPDIF | ||
194 | #endif | ||
195 | ) | ||
196 | { | ||
197 | /* Translate back to full index */ | ||
198 | global_settings.rec_frequency = | ||
199 | round_value_to_list32(table[rec_frequency], | ||
200 | rec_freq_sampr, | ||
201 | REC_NUM_FREQ, | ||
202 | false); | ||
203 | } | ||
204 | |||
205 | return ret; | ||
206 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
207 | } /* recfrequency */ | ||
208 | MENUITEM_FUNCTION(recfrequency, ID2P(LANG_RECORDING_FREQUENCY), | ||
209 | recfrequency_func, NULL, Icon_Menu_setting); | ||
210 | |||
211 | |||
212 | static int recchannels_func(void) | ||
213 | { | ||
214 | static const struct opt_items names[CHN_NUM_MODES] = { | ||
215 | [CHN_MODE_STEREO] = { STR(LANG_CHANNEL_STEREO) }, | ||
216 | [CHN_MODE_MONO] = { STR(LANG_CHANNEL_MONO) } | ||
217 | }; | ||
218 | #if CONFIG_CODEC == MAS3587F | ||
219 | return set_option(str(LANG_RECORDING_CHANNELS), | ||
220 | &global_settings.rec_channels, INT, | ||
221 | names, CHN_NUM_MODES, NULL ); | ||
222 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
223 | |||
224 | #if CONFIG_CODEC == SWCODEC | ||
225 | struct opt_items opts[CHN_NUM_MODES]; | ||
226 | long table[CHN_NUM_MODES]; | ||
227 | struct encoder_caps caps; | ||
228 | struct encoder_config cfg; | ||
229 | int n_opts; | ||
230 | int rec_channels; | ||
231 | bool ret; | ||
232 | |||
233 | cfg.rec_format = global_settings.rec_format; | ||
234 | global_to_encoder_config(&cfg); | ||
235 | |||
236 | if (!enc_get_caps(&cfg, &caps, true)) | ||
237 | return false; | ||
238 | |||
239 | n_opts = make_list_from_caps32(CHN_CAP_ALL, NULL, | ||
240 | caps.channel_caps, table); | ||
241 | |||
242 | rec_channels = round_value_to_list32(global_settings.rec_channels, | ||
243 | table, n_opts, false); | ||
244 | |||
245 | make_options_from_indexes(names, table, n_opts, opts); | ||
246 | |||
247 | ret = set_option(str(LANG_RECORDING_CHANNELS), &rec_channels, | ||
248 | INT, opts, n_opts, NULL ); | ||
249 | |||
250 | if (!ret) | ||
251 | global_settings.rec_channels = table[rec_channels]; | ||
252 | |||
253 | return ret; | ||
254 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
255 | } | ||
256 | MENUITEM_FUNCTION(recchannels, ID2P(LANG_RECORDING_CHANNELS), | ||
257 | recchannels_func, NULL, Icon_Menu_setting); | ||
258 | |||
259 | #if CONFIG_CODEC == SWCODEC | ||
260 | |||
261 | static int recformat_func(void) | ||
262 | { | ||
263 | static const struct opt_items names[REC_NUM_FORMATS] = { | ||
264 | [REC_FORMAT_AIFF] = { STR(LANG_AFMT_AIFF) }, | ||
265 | [REC_FORMAT_MPA_L3] = { STR(LANG_AFMT_MPA_L3) }, | ||
266 | [REC_FORMAT_WAVPACK] = { STR(LANG_AFMT_WAVPACK) }, | ||
267 | [REC_FORMAT_PCM_WAV] = { STR(LANG_AFMT_PCM_WAV) }, | ||
268 | }; | ||
269 | |||
270 | int rec_format = global_settings.rec_format; | ||
271 | bool res = set_option(str(LANG_RECORDING_FORMAT), &rec_format, INT, | ||
272 | names, REC_NUM_FORMATS, NULL ); | ||
273 | |||
274 | if (rec_format != global_settings.rec_format) | ||
275 | { | ||
276 | global_settings.rec_format = rec_format; | ||
277 | enc_global_settings_apply(); | ||
278 | } | ||
279 | |||
280 | return res; | ||
281 | } /* recformat */ | ||
282 | MENUITEM_FUNCTION(recformat, ID2P(LANG_RECORDING_FORMAT), | ||
283 | recformat_func, NULL, Icon_Menu_setting); | ||
284 | |||
285 | MENUITEM_FUNCTION(enc_global_config_menu_item, ID2P(LANG_ENCODER_SETTINGS), | ||
286 | (int(*)(void))enc_global_config_menu, NULL, Icon_Submenu); | ||
287 | |||
288 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
289 | |||
290 | |||
291 | int recmenu_callback(int action,const struct menu_item_ex *this_item) | ||
292 | { | ||
293 | switch (action) | ||
294 | { | ||
295 | case ACTION_REQUEST_MENUITEM: | ||
296 | if (this_item == &recsource && no_source_in_menu) | ||
297 | return ACTION_EXIT_MENUITEM; | ||
298 | break; | ||
299 | } | ||
300 | return action; | ||
301 | } | ||
302 | #if CONFIG_CODEC == MAS3587F | ||
303 | MENUITEM_SETTING(rec_quality, &global_settings.rec_quality, NULL); | ||
304 | MENUITEM_SETTING(rec_editable, &global_settings.rec_editable, NULL); | ||
305 | #endif | ||
306 | |||
307 | MENUITEM_SETTING(rec_split_type, &global_settings.rec_split_type, NULL); | ||
308 | MENUITEM_SETTING(rec_split_method, &global_settings.rec_split_method, NULL); | ||
309 | MENUITEM_SETTING(rec_timesplit, &global_settings.rec_timesplit, NULL); | ||
310 | MENUITEM_SETTING(rec_sizesplit, &global_settings.rec_sizesplit, NULL); | ||
311 | MAKE_MENU(filesplitoptionsmenu, ID2P(LANG_RECORD_TIMESPLIT), NULL, Icon_NOICON, | ||
312 | &rec_split_method, &rec_split_type, &rec_timesplit, &rec_sizesplit); | ||
313 | |||
314 | |||
315 | MENUITEM_SETTING(rec_prerecord_time, &global_settings.rec_prerecord_time, NULL); | ||
316 | static int recdirectory_func(void) | ||
317 | { | ||
318 | static const struct opt_items names[] = { | ||
319 | { rec_base_directory, -1 }, | ||
320 | { STR(LANG_RECORD_CURRENT_DIR) } | ||
321 | }; | ||
322 | return set_option(str(LANG_RECORD_DIRECTORY), | ||
323 | &global_settings.rec_directory, INT, | ||
324 | names, 2, NULL ); | ||
325 | } | ||
326 | MENUITEM_FUNCTION(recdirectory, ID2P(LANG_RECORD_DIRECTORY), | ||
327 | recdirectory_func, NULL, Icon_Menu_setting); | ||
328 | |||
329 | MENUITEM_SETTING(cliplight, &global_settings.cliplight, NULL); | ||
330 | |||
331 | #ifdef HAVE_AGC | ||
332 | static int agc_preset_func(void) | ||
333 | { | ||
334 | static const struct opt_items names[] = { | ||
335 | { STR(LANG_OFF) }, | ||
336 | { STR(LANG_AGC_SAFETY) }, | ||
337 | { STR(LANG_AGC_LIVE) }, | ||
338 | { STR(LANG_AGC_DJSET) }, | ||
339 | { STR(LANG_AGC_MEDIUM) }, | ||
340 | { STR(LANG_AGC_VOICE) }, | ||
341 | }; | ||
342 | if (global_settings.rec_source) | ||
343 | return set_option(str(LANG_RECORD_AGC_PRESET), | ||
344 | &global_settings.rec_agc_preset_line, | ||
345 | INT, names, 6, NULL ); | ||
346 | else | ||
347 | return set_option(str(LANG_RECORD_AGC_PRESET), | ||
348 | &global_settings.rec_agc_preset_mic, | ||
349 | INT, names, 6, NULL ); | ||
350 | } | ||
351 | |||
352 | static int agc_cliptime_func(void) | ||
353 | { | ||
354 | static const struct opt_items names[] = { | ||
355 | { "200ms", TALK_ID(200, UNIT_MS) }, | ||
356 | { "400ms", TALK_ID(400, UNIT_MS) }, | ||
357 | { "600ms", TALK_ID(600, UNIT_MS) }, | ||
358 | { "800ms", TALK_ID(800, UNIT_MS) }, | ||
359 | { "1s", TALK_ID(1, UNIT_SEC) } | ||
360 | }; | ||
361 | return set_option(str(LANG_RECORD_AGC_CLIPTIME), | ||
362 | &global_settings.rec_agc_cliptime, | ||
363 | INT, names, 5, NULL ); | ||
364 | } | ||
365 | MENUITEM_FUNCTION(agc_preset, ID2P(LANG_RECORD_AGC_PRESET), | ||
366 | agc_preset_func, NULL, Icon_Menu_setting); | ||
367 | MENUITEM_FUNCTION(agc_cliptime, ID2P(LANG_RECORD_AGC_CLIPTIME), | ||
368 | agc_cliptime_func, NULL, Icon_Menu_setting); | ||
369 | #endif /* HAVE_AGC */ | ||
370 | |||
371 | /** Rec trigger **/ | ||
372 | enum trigger_menu_option | ||
373 | { | ||
374 | TRIGGER_MODE, | ||
375 | TRIGGER_TYPE, | ||
376 | PRERECORD_TIME, | ||
377 | START_THRESHOLD, | ||
378 | START_DURATION, | ||
379 | STOP_THRESHOLD, | ||
380 | STOP_POSTREC, | ||
381 | STOP_GAP, | ||
382 | TRIG_OPTION_COUNT, | ||
383 | }; | ||
384 | |||
385 | static char* create_thres_str(int threshold) | ||
386 | { | ||
387 | static char retval[6]; | ||
388 | if (threshold < 0) { | ||
389 | if (threshold < -88) { | ||
390 | snprintf (retval, sizeof retval, "%s", str(LANG_DB_INF)); | ||
391 | } else { | ||
392 | snprintf (retval, sizeof retval, "%ddb", threshold + 1); | ||
393 | } | ||
394 | } else { | ||
395 | snprintf (retval, sizeof retval, "%d%%", threshold); | ||
396 | } | ||
397 | return retval; | ||
398 | } | ||
399 | |||
400 | #define INF_DB (-89) | ||
401 | static void change_threshold(int *threshold, int change) | ||
402 | { | ||
403 | if (global_settings.peak_meter_dbfs) { | ||
404 | if (*threshold >= 0) { | ||
405 | int db = (calc_db(*threshold * MAX_PEAK / 100) - 9000) / 100; | ||
406 | *threshold = db; | ||
407 | } | ||
408 | *threshold += change; | ||
409 | if (*threshold > -1) { | ||
410 | *threshold = INF_DB; | ||
411 | } else if (*threshold < INF_DB) { | ||
412 | *threshold = -1; | ||
413 | } | ||
414 | } else { | ||
415 | if (*threshold < 0) { | ||
416 | *threshold = peak_meter_db2sample(*threshold * 100) * 100 / MAX_PEAK; | ||
417 | } | ||
418 | *threshold += change; | ||
419 | if (*threshold > 100) { | ||
420 | *threshold = 0; | ||
421 | } else if (*threshold < 0) { | ||
422 | *threshold = 100; | ||
423 | } | ||
424 | } | ||
425 | } | ||
426 | |||
427 | /** | ||
428 | * Displays a menu for editing the trigger settings. | ||
429 | */ | ||
430 | bool rectrigger(void) | ||
431 | { | ||
432 | int exit_request = false; | ||
433 | enum trigger_menu_option selected = TRIGGER_MODE; | ||
434 | bool retval = false; | ||
435 | int old_x_margin[NB_SCREENS]; | ||
436 | int old_y_margin[NB_SCREENS]; | ||
437 | |||
438 | #define TRIGGER_MODE_COUNT 3 | ||
439 | static const unsigned char *trigger_modes[] = { | ||
440 | ID2P(LANG_OFF), | ||
441 | ID2P(LANG_RECORD_TRIG_NOREARM), | ||
442 | ID2P(LANG_RECORD_TRIG_REARM) | ||
443 | }; | ||
444 | |||
445 | #define PRERECORD_TIMES_COUNT 31 | ||
446 | static const unsigned char *prerecord_times[] = { | ||
447 | ID2P(LANG_OFF),"1s","2s", "3s", "4s", "5s", "6s", "7s", "8s", "9s", | ||
448 | "10s", "11s", "12s", "13s", "14s", "15s", "16s", "17s", "18s", "19s", | ||
449 | "20s", "21s", "22s", "23s", "24s", "25s", "26s", "27s", "28s", "29s", | ||
450 | "30s" | ||
451 | }; | ||
452 | |||
453 | #define TRIGGER_TYPE_COUNT 3 | ||
454 | static const unsigned char *trigger_types[] = { | ||
455 | ID2P(LANG_RECORD_TRIGGER_STOP), | ||
456 | ID2P(LANG_RECORD_TRIGGER_PAUSE), | ||
457 | ID2P(LANG_RECORD_TRIGGER_NEWFILESTP), | ||
458 | }; | ||
459 | |||
460 | static const unsigned char *option_name[] = { | ||
461 | [TRIGGER_MODE] = ID2P(LANG_RECORD_TRIGGER_MODE), | ||
462 | [TRIGGER_TYPE] = ID2P(LANG_RECORD_TRIGGER_TYPE), | ||
463 | [PRERECORD_TIME] = ID2P(LANG_RECORD_PRERECORD_TIME), | ||
464 | [START_THRESHOLD] = ID2P(LANG_RECORD_START_THRESHOLD), | ||
465 | [START_DURATION] = ID2P(LANG_RECORD_MIN_DURATION), | ||
466 | [STOP_THRESHOLD] = ID2P(LANG_RECORD_STOP_THRESHOLD), | ||
467 | [STOP_POSTREC] = ID2P(LANG_RECORD_STOP_POSTREC), | ||
468 | [STOP_GAP] = ID2P(LANG_RECORD_STOP_GAP) | ||
469 | }; | ||
470 | |||
471 | int old_start_thres = global_settings.rec_start_thres; | ||
472 | int old_start_duration = global_settings.rec_start_duration; | ||
473 | int old_prerecord_time = global_settings.rec_prerecord_time; | ||
474 | int old_stop_thres = global_settings.rec_stop_thres; | ||
475 | int old_stop_postrec = global_settings.rec_stop_postrec; | ||
476 | int old_stop_gap = global_settings.rec_stop_gap; | ||
477 | int old_trigger_mode = global_settings.rec_trigger_mode; | ||
478 | int old_trigger_type = global_settings.rec_trigger_type; | ||
479 | |||
480 | int offset[NB_SCREENS]; | ||
481 | int option_lines[NB_SCREENS]; | ||
482 | int w, h, i; | ||
483 | int stat_height = global_settings.statusbar ? STATUSBAR_HEIGHT : 0; | ||
484 | int pm_y[NB_SCREENS]; | ||
485 | |||
486 | int trig_xpos[NB_SCREENS]; | ||
487 | int trig_ypos[NB_SCREENS]; | ||
488 | int trig_width[NB_SCREENS]; | ||
489 | |||
490 | FOR_NB_SCREENS(i) | ||
491 | { | ||
492 | offset[i] = 0; | ||
493 | trig_xpos[i] = 0; | ||
494 | trig_ypos[i] = screens[i].height - stat_height - TRIG_HEIGHT; | ||
495 | pm_y[i] = screens[i].height - stat_height; | ||
496 | trig_width[i] = screens[i].width; | ||
497 | } | ||
498 | |||
499 | /* restart trigger with new values */ | ||
500 | settings_apply_trigger(); | ||
501 | peak_meter_trigger (global_settings.rec_trigger_mode != TRIG_MODE_OFF); | ||
502 | |||
503 | FOR_NB_SCREENS(i) | ||
504 | { | ||
505 | screens[i].clear_display(); | ||
506 | |||
507 | old_x_margin[i] = screens[i].getxmargin(); | ||
508 | old_y_margin[i] = screens[i].getymargin(); | ||
509 | if(global_settings.statusbar) | ||
510 | screens[i].setmargins(0, STATUSBAR_HEIGHT); | ||
511 | else | ||
512 | screens[i].setmargins(0, 0); | ||
513 | |||
514 | screens[i].getstringsize("M", &w, &h); | ||
515 | |||
516 | // 16 pixels are reserved for peak meter and trigger status | ||
517 | option_lines[i] = MIN(((screens[i].height) - | ||
518 | stat_height - 16)/h, | ||
519 | TRIG_OPTION_COUNT); | ||
520 | } | ||
521 | |||
522 | while (!exit_request) { | ||
523 | int button, k; | ||
524 | const char *str; | ||
525 | char option_value[TRIG_OPTION_COUNT][9]; | ||
526 | |||
527 | snprintf( | ||
528 | option_value[TRIGGER_MODE], | ||
529 | sizeof option_value[TRIGGER_MODE], | ||
530 | "%s", | ||
531 | P2STR(trigger_modes[global_settings.rec_trigger_mode])); | ||
532 | |||
533 | snprintf( | ||
534 | option_value[TRIGGER_TYPE], | ||
535 | sizeof option_value[TRIGGER_TYPE], | ||
536 | "%s", | ||
537 | P2STR(trigger_types[global_settings.rec_trigger_type])); | ||
538 | |||
539 | snprintf( | ||
540 | option_value[TRIGGER_TYPE], | ||
541 | sizeof option_value[TRIGGER_TYPE], | ||
542 | "%s", | ||
543 | P2STR(trigger_types[global_settings.rec_trigger_type])); | ||
544 | |||
545 | snprintf ( | ||
546 | option_value[PRERECORD_TIME], | ||
547 | sizeof option_value[PRERECORD_TIME], | ||
548 | "%s", | ||
549 | P2STR(prerecord_times[global_settings.rec_prerecord_time])); | ||
550 | |||
551 | /* due to value range shift (peak_meter_define_trigger) -1 is 0db */ | ||
552 | if (global_settings.rec_start_thres == -1) { | ||
553 | str = str(LANG_OFF); | ||
554 | } else { | ||
555 | str = create_thres_str(global_settings.rec_start_thres); | ||
556 | } | ||
557 | snprintf( | ||
558 | option_value[START_THRESHOLD], | ||
559 | sizeof option_value[START_THRESHOLD], | ||
560 | "%s", | ||
561 | str); | ||
562 | |||
563 | snprintf( | ||
564 | option_value[START_DURATION], | ||
565 | sizeof option_value[START_DURATION], | ||
566 | "%s", | ||
567 | trig_durations[global_settings.rec_start_duration]); | ||
568 | |||
569 | |||
570 | if (global_settings.rec_stop_thres <= INF_DB) { | ||
571 | str = str(LANG_OFF); | ||
572 | } else { | ||
573 | str = create_thres_str(global_settings.rec_stop_thres); | ||
574 | } | ||
575 | snprintf( | ||
576 | option_value[STOP_THRESHOLD], | ||
577 | sizeof option_value[STOP_THRESHOLD], | ||
578 | "%s", | ||
579 | str); | ||
580 | |||
581 | snprintf( | ||
582 | option_value[STOP_POSTREC], | ||
583 | sizeof option_value[STOP_POSTREC], | ||
584 | "%s", | ||
585 | trig_durations[global_settings.rec_stop_postrec]); | ||
586 | |||
587 | snprintf( | ||
588 | option_value[STOP_GAP], | ||
589 | sizeof option_value[STOP_GAP], | ||
590 | "%s", | ||
591 | trig_durations[global_settings.rec_stop_gap]); | ||
592 | |||
593 | FOR_NB_SCREENS(i) | ||
594 | { | ||
595 | screens[i].set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); | ||
596 | screens[i].fillrect(0, stat_height, screens[i].width, | ||
597 | screens[i].height - stat_height); | ||
598 | screens[i].set_drawmode(DRMODE_SOLID); | ||
599 | } | ||
600 | |||
601 | gui_syncstatusbar_draw(&statusbars, true); | ||
602 | |||
603 | /* reselect FONT_SYSFONT as status_draw has changed the font */ | ||
604 | /*lcd_setfont(FONT_SYSFIXED);*/ | ||
605 | |||
606 | FOR_NB_SCREENS(i) | ||
607 | { | ||
608 | for (k = 0; k < option_lines[i]; k++) { | ||
609 | int x, y; | ||
610 | |||
611 | str = P2STR(option_name[k + offset[i]]); | ||
612 | screens[i].putsxy((option_lines[i] < TRIG_OPTION_COUNT) ? 5 : 0, | ||
613 | stat_height + k * h, str); | ||
614 | |||
615 | str = option_value[k + offset[i]]; | ||
616 | screens[i].getstringsize(str, &w, &h); | ||
617 | y = stat_height + k * h; | ||
618 | x = screens[i].width - w; | ||
619 | screens[i].putsxy(x, y, str); | ||
620 | if ((int)selected == (k + offset[i])) { | ||
621 | screens[i].set_drawmode(DRMODE_COMPLEMENT); | ||
622 | screens[i].fillrect(x, y, w, h); | ||
623 | screens[i].set_drawmode(DRMODE_SOLID); | ||
624 | } | ||
625 | } | ||
626 | if (option_lines[i] < TRIG_OPTION_COUNT) | ||
627 | gui_scrollbar_draw(&screens[i], 0, stat_height, | ||
628 | 4, screens[i].height - 16 - stat_height, | ||
629 | TRIG_OPTION_COUNT, offset[i], offset[i] + option_lines[i], | ||
630 | VERTICAL); | ||
631 | } | ||
632 | |||
633 | peak_meter_draw_trig(trig_xpos, trig_ypos, trig_width, NB_SCREENS); | ||
634 | button = peak_meter_draw_get_btn(0, pm_y, 8, NB_SCREENS); | ||
635 | |||
636 | FOR_NB_SCREENS(i) | ||
637 | screens[i].update(); | ||
638 | |||
639 | switch (button) { | ||
640 | case ACTION_STD_CANCEL: | ||
641 | gui_syncsplash(50, true, str(LANG_MENU_SETTING_CANCEL)); | ||
642 | global_settings.rec_start_thres = old_start_thres; | ||
643 | global_settings.rec_start_duration = old_start_duration; | ||
644 | global_settings.rec_prerecord_time = old_prerecord_time; | ||
645 | global_settings.rec_stop_thres = old_stop_thres; | ||
646 | global_settings.rec_stop_postrec = old_stop_postrec; | ||
647 | global_settings.rec_stop_gap = old_stop_gap; | ||
648 | global_settings.rec_trigger_mode = old_trigger_mode; | ||
649 | global_settings.rec_trigger_type = old_trigger_type; | ||
650 | exit_request = true; | ||
651 | break; | ||
652 | |||
653 | case ACTION_REC_PAUSE: | ||
654 | exit_request = true; | ||
655 | break; | ||
656 | |||
657 | case ACTION_STD_PREV: | ||
658 | selected += TRIG_OPTION_COUNT - 1; | ||
659 | selected %= TRIG_OPTION_COUNT; | ||
660 | FOR_NB_SCREENS(i) | ||
661 | { | ||
662 | offset[i] = MIN(offset[i], (int)selected); | ||
663 | offset[i] = MAX(offset[i], (int)selected - option_lines[i] + 1); | ||
664 | } | ||
665 | break; | ||
666 | |||
667 | case ACTION_STD_NEXT: | ||
668 | selected ++; | ||
669 | selected %= TRIG_OPTION_COUNT; | ||
670 | FOR_NB_SCREENS(i) | ||
671 | { | ||
672 | offset[i] = MIN(offset[i], (int)selected); | ||
673 | offset[i] = MAX(offset[i], (int)selected - option_lines[i] + 1); | ||
674 | } | ||
675 | break; | ||
676 | |||
677 | case ACTION_SETTINGS_INC: | ||
678 | switch (selected) { | ||
679 | case TRIGGER_MODE: | ||
680 | global_settings.rec_trigger_mode ++; | ||
681 | global_settings.rec_trigger_mode %= TRIGGER_MODE_COUNT; | ||
682 | break; | ||
683 | |||
684 | case TRIGGER_TYPE: | ||
685 | global_settings.rec_trigger_type ++; | ||
686 | global_settings.rec_trigger_type %= TRIGGER_TYPE_COUNT; | ||
687 | break; | ||
688 | |||
689 | case PRERECORD_TIME: | ||
690 | global_settings.rec_prerecord_time ++; | ||
691 | global_settings.rec_prerecord_time %= PRERECORD_TIMES_COUNT; | ||
692 | break; | ||
693 | |||
694 | case START_THRESHOLD: | ||
695 | change_threshold(&global_settings.rec_start_thres, 1); | ||
696 | break; | ||
697 | |||
698 | case START_DURATION: | ||
699 | global_settings.rec_start_duration ++; | ||
700 | global_settings.rec_start_duration %= TRIG_DURATION_COUNT; | ||
701 | break; | ||
702 | |||
703 | case STOP_THRESHOLD: | ||
704 | change_threshold(&global_settings.rec_stop_thres, 1); | ||
705 | break; | ||
706 | |||
707 | case STOP_POSTREC: | ||
708 | global_settings.rec_stop_postrec ++; | ||
709 | global_settings.rec_stop_postrec %= TRIG_DURATION_COUNT; | ||
710 | break; | ||
711 | |||
712 | case STOP_GAP: | ||
713 | global_settings.rec_stop_gap ++; | ||
714 | global_settings.rec_stop_gap %= TRIG_DURATION_COUNT; | ||
715 | break; | ||
716 | |||
717 | case TRIG_OPTION_COUNT: | ||
718 | // avoid compiler warnings | ||
719 | break; | ||
720 | } | ||
721 | peak_meter_trigger(global_settings.rec_trigger_mode!=TRIG_OFF); | ||
722 | settings_apply_trigger(); | ||
723 | break; | ||
724 | |||
725 | case ACTION_SETTINGS_DEC: | ||
726 | switch (selected) { | ||
727 | case TRIGGER_MODE: | ||
728 | global_settings.rec_trigger_mode+=TRIGGER_MODE_COUNT-1; | ||
729 | global_settings.rec_trigger_mode %= TRIGGER_MODE_COUNT; | ||
730 | break; | ||
731 | |||
732 | case TRIGGER_TYPE: | ||
733 | global_settings.rec_trigger_type+=TRIGGER_TYPE_COUNT-1; | ||
734 | global_settings.rec_trigger_type %= TRIGGER_TYPE_COUNT; | ||
735 | break; | ||
736 | |||
737 | case PRERECORD_TIME: | ||
738 | global_settings.rec_prerecord_time += PRERECORD_TIMES_COUNT - 1; | ||
739 | global_settings.rec_prerecord_time %= PRERECORD_TIMES_COUNT; | ||
740 | break; | ||
741 | |||
742 | case START_THRESHOLD: | ||
743 | change_threshold(&global_settings.rec_start_thres, -1); | ||
744 | break; | ||
745 | |||
746 | case START_DURATION: | ||
747 | global_settings.rec_start_duration += TRIG_DURATION_COUNT-1; | ||
748 | global_settings.rec_start_duration %= TRIG_DURATION_COUNT; | ||
749 | break; | ||
750 | |||
751 | case STOP_THRESHOLD: | ||
752 | change_threshold(&global_settings.rec_stop_thres, -1); | ||
753 | break; | ||
754 | |||
755 | case STOP_POSTREC: | ||
756 | global_settings.rec_stop_postrec += | ||
757 | TRIG_DURATION_COUNT - 1; | ||
758 | global_settings.rec_stop_postrec %= | ||
759 | TRIG_DURATION_COUNT; | ||
760 | break; | ||
761 | |||
762 | case STOP_GAP: | ||
763 | global_settings.rec_stop_gap += | ||
764 | TRIG_DURATION_COUNT - 1; | ||
765 | global_settings.rec_stop_gap %= TRIG_DURATION_COUNT; | ||
766 | break; | ||
767 | |||
768 | case TRIG_OPTION_COUNT: | ||
769 | // avoid compiler warnings | ||
770 | break; | ||
771 | } | ||
772 | peak_meter_trigger(global_settings.rec_trigger_mode!=TRIG_OFF); | ||
773 | settings_apply_trigger(); | ||
774 | break; | ||
775 | |||
776 | case ACTION_REC_F2: | ||
777 | peak_meter_trigger(true); | ||
778 | break; | ||
779 | |||
780 | case SYS_USB_CONNECTED: | ||
781 | if(default_event_handler(button) == SYS_USB_CONNECTED) { | ||
782 | retval = true; | ||
783 | exit_request = true; | ||
784 | } | ||
785 | break; | ||
786 | } | ||
787 | } | ||
788 | |||
789 | peak_meter_trigger(false); | ||
790 | FOR_NB_SCREENS(i) | ||
791 | { | ||
792 | screens[i].setfont(FONT_UI); | ||
793 | screens[i].setmargins(old_x_margin[i], old_y_margin[i]); | ||
794 | } | ||
795 | action_signalscreenchange(); | ||
796 | return retval; | ||
797 | } | ||
798 | |||
799 | MENUITEM_FUNCTION(rectrigger_item, ID2P(LANG_RECORD_TRIGGER), | ||
800 | (int(*)(void))rectrigger, NULL, Icon_Menu_setting); | ||
801 | |||
802 | |||
803 | |||
804 | |||
805 | |||
806 | |||
807 | |||
808 | |||
809 | MAKE_MENU(recording_setting_menu, ID2P(LANG_RECORDING_SETTINGS), NULL, Icon_Recording, | ||
810 | #if CONFIG_CODEC == MAS3587F | ||
811 | &rec_quality, | ||
812 | #endif | ||
813 | #if CONFIG_CODEC == SWCODEC | ||
814 | &recformat, &enc_global_config_menu_item, | ||
815 | #endif | ||
816 | &recfrequency, &recsource, /* recsource not shown if no_source */ | ||
817 | &recchannels, | ||
818 | #if CONFIG_CODEC == MAS3587F | ||
819 | &rec_editable, | ||
820 | #endif | ||
821 | &filesplitoptionsmenu, | ||
822 | &rec_prerecord_time, | ||
823 | &recdirectory, | ||
824 | #if CONFIG_BACKLIGHT | ||
825 | &cliplight, | ||
826 | #endif | ||
827 | &rectrigger_item, | ||
828 | #ifdef HAVE_AGC | ||
829 | &agc_preset, &agc_cliptime, | ||
830 | #endif | ||
831 | ); | ||
832 | |||
833 | bool recording_menu(bool no_source) | ||
834 | { | ||
835 | no_source_in_menu = no_source; | ||
836 | return do_menu(&recording_setting_menu, NULL); | ||
837 | }; | ||
838 | |||
34 | MENUITEM_FUNCTION_WPARAM(recording_settings, ID2P(LANG_RECORDING_SETTINGS), | 839 | MENUITEM_FUNCTION_WPARAM(recording_settings, ID2P(LANG_RECORDING_SETTINGS), |
35 | (int (*)(void*))recording_menu,0, NULL, Icon_NOICON); | 840 | (int (*)(void*))recording_menu,0, NULL, Icon_NOICON); |
36 | #endif | ||