Update Beast installation instructions to use beastpatcher and remove instructions...
[kugel-rb.git] / apps / recorder / radio.c
blobf3270d1f5d4385ae3005e2a3799bb34c5b931717
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2003 Linus Nielsen Feltzing
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "config.h"
23 #include <stdio.h>
24 #include <stdbool.h>
25 #include <stdlib.h>
26 #include "sprintf.h"
27 #include "mas.h"
28 #include "settings.h"
29 #include "button.h"
30 #include "status.h"
31 #include "thread.h"
32 #include "mpeg.h"
33 #include "audio.h"
34 #include "mp3_playback.h"
35 #include "ctype.h"
36 #include "file.h"
37 #include "general.h"
38 #include "errno.h"
39 #include "string.h"
40 #include "system.h"
41 #include "radio.h"
42 #include "menu.h"
43 #include "misc.h"
44 #include "keyboard.h"
45 #include "screens.h"
46 #include "peakmeter.h"
47 #include "lang.h"
48 #include "font.h"
49 #include "sound_menu.h"
50 #ifdef HAVE_RECORDING
51 #include "recording.h"
52 #endif
53 #include "talk.h"
54 #include "tuner.h"
55 #include "power.h"
56 #include "sound.h"
57 #include "screen_access.h"
58 #include "statusbar.h"
59 #include "splash.h"
60 #include "yesno.h"
61 #include "buttonbar.h"
62 #include "power.h"
63 #include "tree.h"
64 #include "dir.h"
65 #include "action.h"
66 #include "list.h"
67 #include "menus/exported_menus.h"
68 #include "root_menu.h"
69 #include "viewport.h"
71 #if CONFIG_TUNER
73 #if CONFIG_KEYPAD == RECORDER_PAD
74 #define FM_RECORD
75 #define FM_PRESET_ADD
76 #define FM_PRESET_ACTION
77 #define FM_PRESET
78 #define FM_MODE
80 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
81 #define FM_PRESET
82 #define FM_MODE
83 #define FM_NEXT_PRESET
84 #define FM_PREV_PRESET
86 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
87 #define FM_PRESET
88 #define FM_MODE
90 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
91 #define FM_PRESET
92 #define FM_MODE
93 /* This should be removeable if the whole tuning thing is sorted out since
94 proper tuning quiets the screen almost entirely in that extreme measures
95 have to be taken to hear any interference. */
96 #define HAVE_NOISY_IDLE_MODE
98 #elif CONFIG_KEYPAD == ONDIO_PAD
99 #define FM_RECORD_DBLPRE
100 #define FM_RECORD
101 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD)
102 #define FM_MENU
103 #define FM_PRESET
104 #define FM_STOP
105 #define FM_MODE
106 #define FM_EXIT
107 #define FM_PLAY
109 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
110 #define FM_PRESET
111 #define FM_MODE
112 #endif
114 #define RADIO_SCAN_MODE 0
115 #define RADIO_PRESET_MODE 1
117 static int curr_preset = -1;
118 static int curr_freq; /* current frequency in Hz */
119 static int radio_mode = RADIO_SCAN_MODE;
120 static int search_dir = 0;
122 static int radio_status = FMRADIO_OFF;
123 static bool in_screen = false;
125 #define MAX_PRESETS 64
126 static bool presets_loaded = false, presets_changed = false;
127 static struct fmstation presets[MAX_PRESETS];
129 static char filepreset[MAX_PATH]; /* preset filename variable */
131 static int num_presets = 0; /* The number of presets in the preset list */
133 static void radio_save_presets(void);
134 static int handle_radio_presets(void);
135 static bool radio_menu(void);
136 static int radio_add_preset(void);
137 static int save_preset_list(void);
138 static int load_preset_list(void);
139 static int clear_preset_list(void);
141 static int scan_presets(void *viewports);
143 /* Function to manipulate all yesno dialogues.
144 This function needs the output text as an argument. */
145 static bool yesno_pop(const char* text)
147 int i;
148 const char *lines[]={text};
149 const struct text_message message={lines, 1};
150 bool ret = (gui_syncyesno_run(&message,NULL,NULL)== YESNO_YES);
151 FOR_NB_SCREENS(i)
152 screens[i].clear_viewport();
153 return ret;
156 void radio_init(void)
158 tuner_init();
159 radio_stop();
162 int get_radio_status(void)
164 return radio_status;
167 bool in_radio_screen(void)
169 return in_screen;
172 /* TODO: Move some more of the control functionality to firmware
173 and clean up the mess */
175 /* secret flag for starting paused - prevents unmute */
176 #define FMRADIO_START_PAUSED 0x8000
177 void radio_start(void)
179 const struct fm_region_data *fmr;
180 bool start_paused;
182 if(radio_status == FMRADIO_PLAYING)
183 return;
185 fmr = &fm_region_data[global_settings.fm_region];
187 start_paused = radio_status & FMRADIO_START_PAUSED;
188 /* clear flag before any yielding */
189 radio_status &= ~FMRADIO_START_PAUSED;
191 if(radio_status == FMRADIO_OFF)
192 tuner_power(true);
194 curr_freq = global_status.last_frequency * fmr->freq_step + fmr->freq_min;
196 tuner_set(RADIO_SLEEP, 0); /* wake up the tuner */
198 if(radio_status == FMRADIO_OFF)
200 #ifdef HAVE_RADIO_REGION
201 tuner_set(RADIO_REGION, global_settings.fm_region);
202 #endif
203 tuner_set(RADIO_FORCE_MONO, global_settings.fm_force_mono);
206 tuner_set(RADIO_FREQUENCY, curr_freq);
208 #ifdef HAVE_RADIO_MUTE_TIMEOUT
210 unsigned long mute_timeout = current_tick + HZ;
211 if (radio_status != FMRADIO_OFF)
213 /* paused */
214 mute_timeout += HZ;
217 while(!tuner_get(RADIO_STEREO) && !tuner_get(RADIO_TUNED))
219 if(TIME_AFTER(current_tick, mute_timeout))
220 break;
221 yield();
224 #endif
226 /* keep radio from sounding initially */
227 if(!start_paused)
228 tuner_set(RADIO_MUTE, 0);
230 radio_status = FMRADIO_PLAYING;
231 } /* radio_start */
233 void radio_pause(void)
235 if(radio_status == FMRADIO_PAUSED)
236 return;
238 if(radio_status == FMRADIO_OFF)
240 radio_status |= FMRADIO_START_PAUSED;
241 radio_start();
244 tuner_set(RADIO_MUTE, 1);
245 tuner_set(RADIO_SLEEP, 1);
247 radio_status = FMRADIO_PAUSED;
248 } /* radio_pause */
250 void radio_stop(void)
252 if(radio_status == FMRADIO_OFF)
253 return;
255 tuner_set(RADIO_MUTE, 1);
256 tuner_set(RADIO_SLEEP, 1); /* low power mode, if available */
257 radio_status = FMRADIO_OFF;
258 tuner_power(false); /* status update, power off if avail. */
259 } /* radio_stop */
261 bool radio_hardware_present(void)
263 return tuner_get(RADIO_PRESENT);
266 /* Keep freq on the grid for the current region */
267 static int snap_freq_to_grid(int freq)
269 const struct fm_region_data * const fmr =
270 &fm_region_data[global_settings.fm_region];
272 /* Range clamp if out of range or just round to nearest */
273 if (freq < fmr->freq_min)
274 freq = fmr->freq_min;
275 else if (freq > fmr->freq_max)
276 freq = fmr->freq_max;
277 else
278 freq = (freq - fmr->freq_min + fmr->freq_step/2) /
279 fmr->freq_step * fmr->freq_step + fmr->freq_min;
281 return freq;
284 /* Find a matching preset to freq */
285 static int find_preset(int freq)
287 int i;
288 if(num_presets < 1)
289 return -1;
290 for(i = 0;i < MAX_PRESETS;i++)
292 if(freq == presets[i].frequency)
293 return i;
296 return -1;
299 /* Return the closest preset encountered in the search direction with
300 wraparound. */
301 static int find_closest_preset(int freq, int direction)
303 int i;
304 int lowpreset = 0;
305 int highpreset = 0;
306 int closest = -1;
308 if (direction == 0) /* direction == 0 isn't really used */
309 return 0;
311 for (i = 0; i < num_presets; i++)
313 int f = presets[i].frequency;
314 if (f == freq)
315 return i; /* Exact match = stop */
317 /* remember the highest and lowest presets for wraparound */
318 if (f < presets[lowpreset].frequency)
319 lowpreset = i;
320 if (f > presets[highpreset].frequency)
321 highpreset = i;
323 /* find the closest preset in the given direction */
324 if (direction > 0 && f > freq)
326 if (closest < 0 || f < presets[closest].frequency)
327 closest = i;
329 else if (direction < 0 && f < freq)
331 if (closest < 0 || f > presets[closest].frequency)
332 closest = i;
336 if (closest < 0)
338 /* no presets in the given direction */
339 /* wrap around depending on direction */
340 if (direction < 0)
341 closest = highpreset;
342 else
343 closest = lowpreset;
346 return closest;
349 static void remember_frequency(void)
351 const struct fm_region_data * const fmr =
352 &fm_region_data[global_settings.fm_region];
353 global_status.last_frequency = (curr_freq - fmr->freq_min)
354 / fmr->freq_step;
355 status_save();
358 static void next_preset(int direction)
360 if (num_presets < 1)
361 return;
363 if (curr_preset == -1)
364 curr_preset = find_closest_preset(curr_freq, direction);
365 else
366 curr_preset = (curr_preset + direction + num_presets) % num_presets;
368 /* Must stay on the current grid for the region */
369 curr_freq = snap_freq_to_grid(presets[curr_preset].frequency);
371 tuner_set(RADIO_FREQUENCY, curr_freq);
372 remember_frequency();
375 /* Step to the next or previous frequency */
376 static int step_freq(int freq, int direction)
378 const struct fm_region_data * const fmr =
379 &fm_region_data[global_settings.fm_region];
381 freq += direction*fmr->freq_step;
383 /* Wrap first or snapping to grid will not let us on the band extremes */
384 if (freq > fmr->freq_max)
385 freq = direction > 0 ? fmr->freq_min : fmr->freq_max;
386 else if (freq < fmr->freq_min)
387 freq = direction < 0 ? fmr->freq_max : fmr->freq_min;
388 else
389 freq = snap_freq_to_grid(freq);
391 return freq;
394 /* Step to the next or previous station */
395 static void next_station(int direction)
397 if (direction != 0 && radio_mode != RADIO_SCAN_MODE)
399 next_preset(direction);
400 return;
403 curr_freq = step_freq(curr_freq, direction);
405 if (radio_status == FMRADIO_PLAYING)
406 tuner_set(RADIO_MUTE, 1);
408 tuner_set(RADIO_FREQUENCY, curr_freq);
410 if (radio_status == FMRADIO_PLAYING)
411 tuner_set(RADIO_MUTE, 0);
413 curr_preset = find_preset(curr_freq);
414 remember_frequency();
417 /* Ends an in-progress search */
418 static void end_search(void)
420 if (search_dir != 0 && radio_status == FMRADIO_PLAYING)
421 tuner_set(RADIO_MUTE, 0);
422 search_dir = 0;
425 /* Speak a frequency. */
426 static void talk_freq(int freq, bool enqueue)
428 freq /= 10000;
429 talk_number(freq / 100, enqueue);
430 talk_id(LANG_POINT, true);
431 talk_number(freq % 100 / 10, true);
432 if (freq % 10)
433 talk_number(freq % 10, true);
436 /* Speak a preset by number or by spelling its name, depending on settings. */
437 static void talk_preset(int preset, bool fallback, bool enqueue)
439 if (global_settings.talk_file == 1) /* number */
440 talk_number(preset + 1, enqueue);
441 else
442 { /* spell */
443 if(presets[preset].name[0])
444 talk_spell(presets[preset].name, enqueue);
445 else if(fallback)
446 talk_freq(presets[preset].frequency, enqueue);
450 int radio_screen(void)
452 char buf[MAX_PATH];
453 bool done = false;
454 int ret_val = GO_TO_ROOT;
455 int button;
456 int i;
457 bool stereo = false, last_stereo = false;
458 int fh;
459 int top_of_screen = 0;
460 bool update_screen = true;
461 bool screen_freeze = false;
462 bool keep_playing = false;
463 bool talk = false;
464 #ifdef FM_RECORD_DBLPRE
465 int lastbutton = BUTTON_NONE;
466 unsigned long rec_lastclick = 0;
467 #endif
468 #if CONFIG_CODEC != SWCODEC
469 bool have_recorded = false;
470 int timeout = current_tick + HZ/10;
471 unsigned int seconds = 0;
472 unsigned int last_seconds = 0;
473 int hours, minutes;
474 struct audio_recording_options rec_options;
475 #endif /* CONFIG_CODEC != SWCODEC */
476 #ifndef HAVE_NOISY_IDLE_MODE
477 int button_timeout = current_tick + (2*HZ);
478 #endif
479 struct viewport vp[NB_SCREENS];
480 int oldbars = 0, fmbars = VP_SB_ALLSCREENS;
481 #ifdef HAVE_BUTTONBAR
482 struct gui_buttonbar buttonbar;
483 gui_buttonbar_init(&buttonbar);
484 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
485 #endif
487 /* change status to "in screen" */
488 in_screen = true;
490 /* always display status bar in radio screen for now */
491 FOR_NB_SCREENS(i)
492 fmbars |= VP_SB_IGNORE_SETTING(i);
493 oldbars = viewportmanager_set_statusbar(fmbars);
494 FOR_NB_SCREENS(i)
496 viewport_set_defaults(&vp[i], i);
497 #ifdef HAVE_BUTTONBAR
498 if (global_settings.buttonbar)
499 vp[i].height -= BUTTONBAR_HEIGHT;
500 #endif
501 screens[i].set_viewport(&vp[i]);
502 screens[i].stop_scroll();
503 screens[i].clear_viewport();
504 screens[i].update_viewport();
507 fh = font_get(FONT_UI)->height;
509 /* Adjust for font size, trying to center the information vertically */
510 if(fh < 10)
511 top_of_screen = 1;
513 if(num_presets <= 0)
515 memset(presets, 0, sizeof(presets));
516 radio_load_presets(global_settings.fmr_file);
519 if(radio_status == FMRADIO_OFF)
520 audio_stop();
521 #ifndef SIMULATOR
523 #if CONFIG_CODEC != SWCODEC
524 if(rec_create_directory() > 0)
525 have_recorded = true;
527 audio_init_recording(talk_get_bufsize());
529 sound_settings_apply();
530 /* Yes, we use the D/A for monitoring */
531 peak_meter_playback(true);
533 peak_meter_enabled = true;
535 rec_init_recording_options(&rec_options);
536 rec_options.rec_source = AUDIO_SRC_LINEIN;
537 rec_set_recording_options(&rec_options);
539 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
540 sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN);
542 #endif /* CONFIG_CODEC != SWCODEC */
543 #endif /* ndef SIMULATOR */
545 /* turn on radio */
546 #if CONFIG_CODEC == SWCODEC
547 audio_set_input_source(AUDIO_SRC_FMRADIO,
548 (radio_status == FMRADIO_PAUSED) ?
549 SRCF_FMRADIO_PAUSED : SRCF_FMRADIO_PLAYING);
550 #else
551 if (radio_status == FMRADIO_OFF)
552 radio_start();
553 #endif
555 if(num_presets < 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN)))
556 scan_presets(vp);
558 curr_preset = find_preset(curr_freq);
559 if(curr_preset != -1)
560 radio_mode = RADIO_PRESET_MODE;
562 #ifdef HAVE_BUTTONBAR
563 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
564 str(LANG_PRESET), str(LANG_FM_BUTTONBAR_RECORD));
565 #endif
567 #ifndef HAVE_NOISY_IDLE_MODE
568 cpu_idle_mode(true);
569 #endif
571 while(!done)
573 if(search_dir != 0)
575 curr_freq = step_freq(curr_freq, search_dir);
576 update_screen = true;
578 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
580 curr_preset = find_preset(curr_freq);
581 remember_frequency();
582 end_search();
583 talk = true;
586 trigger_cpu_boost();
589 if (!update_screen)
591 cancel_cpu_boost();
594 #if CONFIG_CODEC != SWCODEC
595 /* TODO: Can we timeout at HZ when recording since peaks aren't
596 displayed? This should quiet recordings too. */
597 button = get_action(CONTEXT_FM,
598 update_screen ? TIMEOUT_NOBLOCK : HZ / PEAK_METER_FPS);
599 #else
600 button = get_action(CONTEXT_FM,
601 update_screen ? TIMEOUT_NOBLOCK : HZ);
602 #endif
604 #ifndef HAVE_NOISY_IDLE_MODE
605 if (button != ACTION_NONE)
607 cpu_idle_mode(false);
608 button_timeout = current_tick + (2*HZ);
610 #endif
611 switch(button)
613 case ACTION_FM_STOP:
614 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
615 if(audio_status() == AUDIO_STATUS_RECORD)
617 audio_stop();
619 else
620 #endif
622 done = true;
623 if(presets_changed)
625 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
627 if(filepreset[0] == '\0')
628 save_preset_list();
629 else
630 radio_save_presets();
633 /* Clear the preset list on exit. */
634 clear_preset_list();
636 update_screen = true;
637 break;
639 #ifdef FM_RECORD
640 case ACTION_FM_RECORD:
641 #ifdef FM_RECORD_DBLPRE
642 if (lastbutton != ACTION_FM_RECORD_DBLPRE)
644 rec_lastclick = 0;
645 break;
647 if (current_tick - rec_lastclick > HZ/2)
649 rec_lastclick = current_tick;
650 break;
652 #endif /* FM_RECORD_DBLPRE */
653 #ifndef SIMULATOR
654 if(audio_status() == AUDIO_STATUS_RECORD)
656 rec_command(RECORDING_CMD_START_NEWFILE);
657 update_screen = true;
659 else
661 have_recorded = true;
662 rec_command(RECORDING_CMD_START);
663 update_screen = true;
665 #endif /* SIMULATOR */
666 last_seconds = 0;
667 break;
668 #endif /* #ifdef FM_RECORD */
670 case ACTION_FM_EXIT:
671 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
672 if(audio_status() == AUDIO_STATUS_RECORD)
673 audio_stop();
674 #endif
675 keep_playing = true;
676 done = true;
677 ret_val = GO_TO_ROOT;
678 if(presets_changed)
680 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
682 if(filepreset[0] == '\0')
683 save_preset_list();
684 else
685 radio_save_presets();
689 /* Clear the preset list on exit. */
690 clear_preset_list();
692 break;
694 case ACTION_STD_PREV:
695 case ACTION_STD_NEXT:
696 next_station(button == ACTION_STD_PREV ? -1 : 1);
697 end_search();
698 update_screen = true;
699 talk = true;
700 break;
702 case ACTION_STD_PREVREPEAT:
703 case ACTION_STD_NEXTREPEAT:
705 int dir = search_dir;
706 search_dir = button == ACTION_STD_PREVREPEAT ? -1 : 1;
707 if (radio_mode != RADIO_SCAN_MODE)
709 next_preset(search_dir);
710 end_search();
711 update_screen = true;
712 talk = true;
714 else if (dir == 0)
716 /* Starting auto scan */
717 tuner_set(RADIO_MUTE, 1);
718 update_screen = true;
720 break;
723 case ACTION_SETTINGS_INC:
724 case ACTION_SETTINGS_INCREPEAT:
725 global_settings.volume++;
726 setvol();
727 update_screen = true;
728 break;
730 case ACTION_SETTINGS_DEC:
731 case ACTION_SETTINGS_DECREPEAT:
732 global_settings.volume--;
733 setvol();
734 update_screen = true;
735 break;
737 case ACTION_FM_PLAY:
738 if (radio_status == FMRADIO_PLAYING)
739 radio_pause();
740 else
741 radio_start();
743 update_screen = true;
744 talk = false;
745 talk_shutup();
746 break;
748 case ACTION_FM_MENU:
749 viewportmanager_set_statusbar(oldbars);
750 radio_menu();
751 curr_preset = find_preset(curr_freq);
752 viewportmanager_set_statusbar(fmbars);
753 FOR_NB_SCREENS(i)
755 screens[i].set_viewport(&vp[i]);
756 screens[i].clear_viewport();
757 screens[i].update_viewport();
758 screens[i].set_viewport(NULL);
760 #ifdef HAVE_BUTTONBAR
761 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
762 str(LANG_PRESET),
763 str(LANG_FM_BUTTONBAR_RECORD));
764 #endif
765 update_screen = true;
766 break;
768 #ifdef FM_PRESET
769 case ACTION_FM_PRESET:
770 if(num_presets < 1)
772 splash(HZ, ID2P(LANG_FM_NO_PRESETS));
773 update_screen = true;
774 FOR_NB_SCREENS(i)
776 screens[i].set_viewport(&vp[i]);
777 screens[i].clear_viewport();
778 screens[i].update_viewport();
779 screens[i].set_viewport(NULL);
782 break;
784 viewportmanager_set_statusbar(oldbars);
785 handle_radio_presets();
786 viewportmanager_set_statusbar(fmbars);
787 FOR_NB_SCREENS(i)
789 screens[i].set_viewport(&vp[i]);
790 screens[i].stop_scroll();
791 screens[i].clear_viewport();
792 screens[i].update_viewport();
793 screens[i].set_viewport(NULL);
795 #ifdef HAVE_BUTTONBAR
796 gui_buttonbar_set(&buttonbar,
797 str(LANG_BUTTONBAR_MENU),
798 str(LANG_PRESET),
799 str(LANG_FM_BUTTONBAR_RECORD));
800 #endif
801 update_screen = true;
802 break;
803 #endif /* FM_PRESET */
805 #ifdef FM_FREEZE
806 case ACTION_FM_FREEZE:
807 if(!screen_freeze)
809 splash(HZ, str(LANG_FM_FREEZE));
810 screen_freeze = true;
812 else
814 update_screen = true;
815 screen_freeze = false;
817 break;
818 #endif /* FM_FREEZE */
820 case SYS_USB_CONNECTED:
821 #if CONFIG_CODEC != SWCODEC
822 /* Only accept USB connection when not recording */
823 if(audio_status() != AUDIO_STATUS_RECORD)
824 #endif
826 default_event_handler(SYS_USB_CONNECTED);
827 screen_freeze = true; /* Cosmetic: makes sure the
828 radio screen doesn't redraw */
829 done = true;
831 break;
833 #ifdef FM_MODE
834 case ACTION_FM_MODE:
835 if(radio_mode == RADIO_SCAN_MODE)
837 /* Force scan mode if there are no presets. */
838 if(num_presets > 0)
839 radio_mode = RADIO_PRESET_MODE;
841 else
842 radio_mode = RADIO_SCAN_MODE;
843 update_screen = true;
844 cond_talk_ids_fq(radio_mode ?
845 LANG_PRESET : LANG_RADIO_SCAN_MODE);
846 talk = true;
847 break;
848 #endif /* FM_MODE */
850 #ifdef FM_NEXT_PRESET
851 case ACTION_FM_NEXT_PRESET:
852 next_preset(1);
853 end_search();
854 update_screen = true;
855 talk = true;
856 break;
857 #endif
859 #ifdef FM_PREV_PRESET
860 case ACTION_FM_PREV_PRESET:
861 next_preset(-1);
862 end_search();
863 update_screen = true;
864 talk = true;
865 break;
866 #endif
868 default:
869 default_event_handler(button);
870 break;
871 } /*switch(button)*/
873 #ifdef FM_RECORD_DBLPRE
874 if (button != ACTION_NONE)
875 lastbutton = button;
876 #endif
878 #if CONFIG_CODEC != SWCODEC
879 peak_meter_peek();
880 #endif
882 if(!screen_freeze)
884 /* Only display the peak meter when not recording */
885 #if CONFIG_CODEC != SWCODEC
886 if(!audio_status())
888 FOR_NB_SCREENS(i)
890 screens[i].set_viewport(&vp[i]);
891 peak_meter_screen(&screens[i],0,
892 STATUSBAR_HEIGHT + fh*(top_of_screen + 4),
893 fh);
894 screens[i].update_rect(0,
895 STATUSBAR_HEIGHT + fh*(top_of_screen + 4),
896 screens[i].getwidth(), fh);
897 screens[i].set_viewport(NULL);
901 if(TIME_AFTER(current_tick, timeout))
903 timeout = current_tick + HZ;
904 #else /* SWCODEC */
906 #endif /* CONFIG_CODEC == SWCODEC */
908 /* keep "mono" from always being displayed when paused */
909 if (radio_status != FMRADIO_PAUSED)
911 stereo = tuner_get(RADIO_STEREO) &&
912 !global_settings.fm_force_mono;
914 if(stereo != last_stereo)
916 update_screen = true;
917 last_stereo = stereo;
922 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
923 seconds = audio_recorded_time() / HZ;
924 if (update_screen || seconds > last_seconds)
926 last_seconds = seconds;
927 #else
928 if (update_screen)
930 #endif
931 int freq;
933 FOR_NB_SCREENS(i)
935 screens[i].set_viewport(&vp[i]);
938 snprintf(buf, 128, curr_preset >= 0 ? "%d. %s" : " ",
939 curr_preset + 1, presets[curr_preset].name);
941 FOR_NB_SCREENS(i)
942 screens[i].puts_scroll(0, top_of_screen, buf);
944 freq = curr_freq / 10000;
945 snprintf(buf, 128, str(LANG_FM_STATION),
946 freq / 100, freq % 100);
947 FOR_NB_SCREENS(i)
948 screens[i].puts_scroll(0, top_of_screen + 1, buf);
950 snprintf(buf, 128, "%s", stereo?str(LANG_CHANNEL_STEREO):
951 str(LANG_CHANNEL_MONO));
952 FOR_NB_SCREENS(i)
953 screens[i].puts_scroll(0, top_of_screen + 2, buf);
955 snprintf(buf, 128, "%s %s", str(LANG_MODE),
956 radio_mode ? str(LANG_PRESET) :
957 str(LANG_RADIO_SCAN_MODE));
958 FOR_NB_SCREENS(i)
959 screens[i].puts_scroll(0, top_of_screen + 3, buf);
961 #if CONFIG_CODEC != SWCODEC
962 if(audio_status() == AUDIO_STATUS_RECORD)
964 hours = seconds / 3600;
965 minutes = (seconds - (hours * 3600)) / 60;
966 snprintf(buf, 32, "%s %02d:%02d:%02d",
967 str(LANG_RECORDING_TIME),
968 hours, minutes, seconds%60);
969 FOR_NB_SCREENS(i)
970 screens[i].puts_scroll(0, top_of_screen + 4, buf);
972 else
974 if(rec_options.rec_prerecord_time)
976 snprintf(buf, 32, "%s %02d",
977 str(LANG_RECORD_PRERECORD), seconds%60);
978 FOR_NB_SCREENS(i)
979 screens[i].puts_scroll(0, top_of_screen + 4, buf);
982 #endif /* CONFIG_CODEC != SWCODEC */
984 FOR_NB_SCREENS(i)
986 screens[i].update_viewport();
987 screens[i].set_viewport(NULL);
990 #ifdef HAVE_BUTTONBAR
991 gui_buttonbar_draw(&buttonbar);
992 #endif
996 update_screen = false;
998 if (global_settings.talk_file && talk
999 && radio_status == FMRADIO_PAUSED)
1001 talk = false;
1002 bool enqueue = false;
1003 if (radio_mode == RADIO_SCAN_MODE)
1005 talk_freq(curr_freq, enqueue);
1006 enqueue = true;
1008 if (curr_preset >= 0)
1009 talk_preset(curr_preset, radio_mode == RADIO_PRESET_MODE,
1010 enqueue);
1013 #if CONFIG_CODEC != SWCODEC
1014 if(audio_status() & AUDIO_STATUS_ERROR)
1016 done = true;
1018 #endif
1020 #ifndef HAVE_NOISY_IDLE_MODE
1021 if (TIME_AFTER(current_tick, button_timeout))
1023 cpu_idle_mode(true);
1025 #endif
1026 } /*while(!done)*/
1028 #ifndef SIMULATOR
1029 #if CONFIG_CODEC != SWCODEC
1030 if(audio_status() & AUDIO_STATUS_ERROR)
1032 splash(0, str(LANG_DISK_FULL));
1033 FOR_NB_SCREENS(i)
1035 screens[i].set_viewport(&vp[i]);
1036 screens[i].update_viewport();
1037 screens[i].set_viewport(NULL);
1039 audio_error_clear();
1041 while(1)
1043 button = get_action(CONTEXT_FM, TIMEOUT_BLOCK);
1044 if(button == ACTION_FM_STOP)
1045 break;
1049 audio_init_playback();
1050 #endif /* CONFIG_CODEC != SWCODEC */
1052 sound_settings_apply();
1053 #endif /* SIMULATOR */
1055 if(keep_playing)
1057 /* Catch FMRADIO_PLAYING status for the sim. */
1058 #ifndef SIMULATOR
1059 #if CONFIG_CODEC != SWCODEC
1060 /* Enable the Left and right A/D Converter */
1061 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
1062 sound_default(SOUND_RIGHT_GAIN),
1063 AUDIO_GAIN_LINEIN);
1064 mas_codec_writereg(6, 0x4000);
1065 #endif
1066 end_search();
1067 #endif /* SIMULATOR */
1069 else
1071 #if CONFIG_CODEC == SWCODEC
1072 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
1073 #else
1074 radio_stop();
1075 #endif
1078 #ifndef HAVE_NOISY_IDLE_MODE
1079 cpu_idle_mode(false);
1080 #endif
1082 viewportmanager_set_statusbar(oldbars);
1083 in_screen = false;
1084 #if CONFIG_CODEC != SWCODEC
1085 return have_recorded;
1086 #else
1087 return false;
1088 #endif
1089 } /* radio_screen */
1091 static void radio_save_presets(void)
1093 int fd;
1094 int i;
1096 fd = creat(filepreset);
1097 if(fd >= 0)
1099 for(i = 0;i < num_presets;i++)
1101 fdprintf(fd, "%d:%s\n", presets[i].frequency, presets[i].name);
1103 close(fd);
1105 if(!strncasecmp(FMPRESET_PATH, filepreset, strlen(FMPRESET_PATH)))
1106 set_file(filepreset, global_settings.fmr_file, MAX_FILENAME);
1107 presets_changed = false;
1109 else
1111 splash(HZ, ID2P(LANG_FM_PRESET_SAVE_FAILED));
1115 void radio_load_presets(char *filename)
1117 int fd;
1118 int rc;
1119 char buf[128];
1120 char *freq;
1121 char *name;
1122 bool done = false;
1123 int f;
1125 memset(presets, 0, sizeof(presets));
1126 num_presets = 0;
1128 /* No Preset in configuration. */
1129 if(filename[0] == '\0')
1131 filepreset[0] = '\0';
1132 return;
1134 /* Temporary preset, loaded until player shuts down. */
1135 else if(filename[0] == '/')
1136 strncpy(filepreset, filename, sizeof(filepreset));
1137 /* Preset from default directory. */
1138 else
1139 snprintf(filepreset, sizeof(filepreset), "%s/%s.fmr",
1140 FMPRESET_PATH, filename);
1142 fd = open_utf8(filepreset, O_RDONLY);
1143 if(fd >= 0)
1145 while(!done && num_presets < MAX_PRESETS)
1147 rc = read_line(fd, buf, 128);
1148 if(rc > 0)
1150 if(settings_parseline(buf, &freq, &name))
1152 f = atoi(freq);
1153 if(f) /* For backwards compatibility */
1155 struct fmstation * const fms = &presets[num_presets];
1156 fms->frequency = f;
1157 strncpy(fms->name, name, MAX_FMPRESET_LEN);
1158 fms->name[MAX_FMPRESET_LEN] = '\0';
1159 num_presets++;
1163 else
1164 done = true;
1166 close(fd);
1168 else /* invalid file name? */
1169 filepreset[0] = '\0';
1171 presets_loaded = num_presets > 0;
1172 presets_changed = false;
1176 static int radio_add_preset(void)
1178 char buf[MAX_FMPRESET_LEN + 1];
1180 if(num_presets < MAX_PRESETS)
1182 buf[0] = '\0';
1184 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1186 struct fmstation * const fms = &presets[num_presets];
1187 strcpy(fms->name, buf);
1188 fms->frequency = curr_freq;
1189 num_presets++;
1190 presets_changed = true;
1191 presets_loaded = num_presets > 0;
1192 return true;
1195 else
1197 splash(HZ, ID2P(LANG_FM_NO_FREE_PRESETS));
1199 return false;
1202 /* needed to know which preset we are edit/delete-ing */
1203 static int selected_preset = -1;
1204 static int radio_edit_preset(void)
1206 char buf[MAX_FMPRESET_LEN + 1];
1208 if (num_presets > 0)
1210 struct fmstation * const fms = &presets[selected_preset];
1212 strcpy(buf, fms->name);
1214 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1216 strcpy(fms->name, buf);
1217 presets_changed = true;
1221 return 1;
1224 static int radio_delete_preset(void)
1226 if (num_presets > 0)
1228 struct fmstation * const fms = &presets[selected_preset];
1230 if (selected_preset >= --num_presets)
1231 selected_preset = num_presets - 1;
1233 memmove(fms, fms + 1, (uintptr_t)(fms + num_presets) -
1234 (uintptr_t)fms);
1236 if (curr_preset >= num_presets)
1237 --curr_preset;
1240 /* Don't ask to save when all presets are deleted. */
1241 presets_changed = num_presets > 0;
1243 if (!presets_changed)
1245 /* The preset list will be cleared, switch to Scan Mode. */
1246 radio_mode = RADIO_SCAN_MODE;
1247 curr_preset = -1;
1248 presets_loaded = false;
1251 return 1;
1254 static int load_preset_list(void)
1256 return !rockbox_browse(FMPRESET_PATH, SHOW_FMR);
1259 static int save_preset_list(void)
1261 if(num_presets > 0)
1263 bool bad_file_name = true;
1265 if(!dir_exists(FMPRESET_PATH)) /* Check if there is preset folder */
1266 mkdir(FMPRESET_PATH);
1268 create_numbered_filename(filepreset, FMPRESET_PATH, "preset",
1269 ".fmr", 2 IF_CNFN_NUM_(, NULL));
1271 while(bad_file_name)
1273 if(!kbd_input(filepreset, sizeof(filepreset)))
1275 /* check the name: max MAX_FILENAME (20) chars */
1276 char* p2;
1277 char* p1;
1278 int len;
1279 p1 = strrchr(filepreset, '/');
1280 p2 = p1;
1281 while((p1) && (*p2) && (*p2 != '.'))
1282 p2++;
1283 len = (int)(p2-p1) - 1;
1284 if((!p1) || (len > MAX_FILENAME) || (len == 0))
1286 /* no slash, too long or too short */
1287 splash(HZ, ID2P(LANG_INVALID_FILENAME));
1289 else
1291 /* add correct extension (easier to always write)
1292 at this point, p2 points to 0 or the extension dot */
1293 *p2 = '\0';
1294 strcat(filepreset,".fmr");
1295 bad_file_name = false;
1296 radio_save_presets();
1299 else
1301 /* user aborted */
1302 return false;
1306 else
1307 splash(HZ, ID2P(LANG_FM_NO_PRESETS));
1309 return true;
1312 static int clear_preset_list(void)
1314 /* Clear all the preset entries */
1315 memset(presets, 0, sizeof (presets));
1317 num_presets = 0;
1318 presets_loaded = false;
1319 /* The preset list will be cleared switch to Scan Mode. */
1320 radio_mode = RADIO_SCAN_MODE;
1321 curr_preset = -1;
1323 presets_changed = false; /* Don't ask to save when clearing the list. */
1325 return true;
1328 MENUITEM_FUNCTION(radio_edit_preset_item, MENU_FUNC_CHECK_RETVAL,
1329 ID2P(LANG_FM_EDIT_PRESET),
1330 radio_edit_preset, NULL, NULL, Icon_NOICON);
1331 MENUITEM_FUNCTION(radio_delete_preset_item, MENU_FUNC_CHECK_RETVAL,
1332 ID2P(LANG_FM_DELETE_PRESET),
1333 radio_delete_preset, NULL, NULL, Icon_NOICON);
1334 static int radio_preset_callback(int action,
1335 const struct menu_item_ex *this_item)
1337 if (action == ACTION_STD_OK)
1338 action = ACTION_EXIT_AFTER_THIS_MENUITEM;
1339 return action;
1340 (void)this_item;
1342 MAKE_MENU(handle_radio_preset_menu, ID2P(LANG_PRESET),
1343 radio_preset_callback, Icon_NOICON, &radio_edit_preset_item,
1344 &radio_delete_preset_item);
1345 /* present a list of preset stations */
1346 static char * presets_get_name(int selected_item, void *data,
1347 char *buffer, size_t buffer_len)
1349 (void)data;
1350 struct fmstation *p = &presets[selected_item];
1351 if(p->name[0])
1352 return p->name;
1353 int freq = p->frequency / 10000;
1354 int frac = freq % 100;
1355 freq /= 100;
1356 snprintf(buffer, buffer_len,
1357 str(LANG_FM_DEFAULT_PRESET_NAME), freq, frac);
1358 return buffer;
1361 static int presets_speak_name(int selected_item, void * data)
1363 (void)data;
1364 talk_preset(selected_item, true, false);
1365 return 0;
1368 static int handle_radio_presets(void)
1370 struct gui_synclist lists;
1371 int result = 0;
1372 int action = ACTION_NONE;
1373 #ifdef HAVE_BUTTONBAR
1374 struct gui_buttonbar buttonbar;
1375 #endif
1377 if(presets_loaded == false)
1378 return result;
1380 #ifdef HAVE_BUTTONBAR
1381 gui_buttonbar_init(&buttonbar);
1382 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
1383 gui_buttonbar_set(&buttonbar, str(LANG_FM_BUTTONBAR_ADD),
1384 str(LANG_FM_BUTTONBAR_EXIT),
1385 str(LANG_FM_BUTTONBAR_ACTION));
1386 gui_buttonbar_draw(&buttonbar);
1387 #endif
1388 gui_synclist_init(&lists, presets_get_name, NULL, false, 1, NULL);
1389 gui_synclist_set_title(&lists, str(LANG_PRESET), NOICON);
1390 gui_synclist_set_icon_callback(&lists, NULL);
1391 if(global_settings.talk_file)
1392 gui_synclist_set_voice_callback(&lists, presets_speak_name);
1393 gui_synclist_set_nb_items(&lists, num_presets);
1394 gui_synclist_select_item(&lists, curr_preset<0 ? 0 : curr_preset);
1395 gui_synclist_speak_item(&lists);
1397 while (result == 0)
1399 gui_synclist_draw(&lists);
1400 list_do_action(CONTEXT_STD, TIMEOUT_BLOCK,
1401 &lists, &action, LIST_WRAP_UNLESS_HELD);
1402 switch (action)
1404 case ACTION_STD_MENU:
1405 if (radio_add_preset())
1407 gui_synclist_set_nb_items(&lists, num_presets);
1408 gui_synclist_select_item(&lists, num_presets - 1);
1410 break;
1411 case ACTION_STD_CANCEL:
1412 result = 1;
1413 break;
1414 case ACTION_STD_OK:
1415 curr_preset = gui_synclist_get_sel_pos(&lists);
1416 curr_freq = presets[curr_preset].frequency;
1417 next_station(0);
1418 remember_frequency();
1419 result = 1;
1420 break;
1421 case ACTION_F3:
1422 case ACTION_STD_CONTEXT:
1423 selected_preset = gui_synclist_get_sel_pos(&lists);
1424 do_menu(&handle_radio_preset_menu, NULL, NULL, false);
1425 gui_synclist_set_nb_items(&lists, num_presets);
1426 gui_synclist_select_item(&lists, selected_preset);
1427 gui_synclist_speak_item(&lists);
1428 break;
1429 default:
1430 if(default_event_handler(action) == SYS_USB_CONNECTED)
1431 result = 2;
1434 return result - 1;
1437 void toggle_mono_mode(bool mono)
1439 tuner_set(RADIO_FORCE_MONO, mono);
1442 void set_radio_region(int region)
1444 #ifdef HAVE_RADIO_REGION
1445 tuner_set(RADIO_REGION, region);
1446 #endif
1447 next_station(0);
1448 remember_frequency();
1449 (void)region;
1452 MENUITEM_SETTING(set_region, &global_settings.fm_region, NULL);
1453 MENUITEM_SETTING(force_mono, &global_settings.fm_force_mono, NULL);
1455 #ifndef FM_MODE
1456 static char* get_mode_text(int selected_item, void * data, char *buffer)
1458 (void)selected_item;
1459 (void)data;
1460 snprintf(buffer, MAX_PATH, "%s %s", str(LANG_MODE),
1461 radio_mode ? str(LANG_PRESET) :
1462 str(LANG_RADIO_SCAN_MODE));
1463 return buffer;
1465 static int toggle_radio_mode(void)
1467 radio_mode = (radio_mode == RADIO_SCAN_MODE) ?
1468 RADIO_PRESET_MODE : RADIO_SCAN_MODE;
1469 return 0;
1471 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item, 0,
1472 toggle_radio_mode, NULL,
1473 get_mode_text, NULL, NULL, NULL, Icon_NOICON);
1474 #endif
1476 static int scan_presets(void *viewports)
1478 bool do_scan = true;
1479 int i;
1480 struct viewport *vp = (struct viewport *)viewports;
1482 FOR_NB_SCREENS(i)
1483 screens[i].set_viewport(vp?&vp[i]:NULL);
1484 if(num_presets > 0) /* Do that to avoid 2 questions. */
1485 do_scan = yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS));
1487 if(do_scan)
1489 const struct fm_region_data * const fmr =
1490 &fm_region_data[global_settings.fm_region];
1492 curr_freq = fmr->freq_min;
1493 num_presets = 0;
1494 memset(presets, 0, sizeof(presets));
1495 tuner_set(RADIO_MUTE, 1);
1497 while(curr_freq <= fmr->freq_max)
1499 int freq, frac;
1500 if(num_presets >= MAX_PRESETS || action_userabort(TIMEOUT_NOBLOCK))
1501 break;
1503 freq = curr_freq / 10000;
1504 frac = freq % 100;
1505 freq /= 100;
1507 splashf(0, str(LANG_FM_SCANNING), freq, frac);
1509 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
1511 /* add preset */
1512 presets[num_presets].name[0] = '\0';
1513 presets[num_presets].frequency = curr_freq;
1514 num_presets++;
1517 curr_freq += fmr->freq_step;
1520 if (radio_status == FMRADIO_PLAYING)
1521 tuner_set(RADIO_MUTE, 0);
1523 presets_changed = true;
1525 FOR_NB_SCREENS(i)
1527 screens[i].clear_viewport();
1528 screens[i].update_viewport();
1531 if(num_presets > 0)
1533 curr_freq = presets[0].frequency;
1534 radio_mode = RADIO_PRESET_MODE;
1535 presets_loaded = true;
1536 next_station(0);
1538 else
1540 /* Wrap it to beginning or we'll be past end of band */
1541 presets_loaded = false;
1542 next_station(1);
1545 return true;
1549 #ifdef HAVE_RECORDING
1551 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1552 #define FM_RECORDING_SCREEN
1553 static int fm_recording_screen(void)
1555 bool ret;
1557 /* switch recording source to FMRADIO for the duration */
1558 int rec_source = global_settings.rec_source;
1559 global_settings.rec_source = AUDIO_SRC_FMRADIO;
1561 ret = recording_screen(true);
1563 /* safe to reset as changing sources is prohibited here */
1564 global_settings.rec_source = rec_source;
1566 return ret;
1569 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1571 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1572 #define FM_RECORDING_SETTINGS
1573 static int fm_recording_settings(void)
1575 bool ret = recording_menu(true);
1577 #if CONFIG_CODEC != SWCODEC
1578 if (!ret)
1580 struct audio_recording_options rec_options;
1581 rec_init_recording_options(&rec_options);
1582 rec_options.rec_source = AUDIO_SRC_LINEIN;
1583 rec_set_recording_options(&rec_options);
1585 #endif
1587 return ret;
1590 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1591 #endif /* HAVE_RECORDING */
1593 #ifdef FM_RECORDING_SCREEN
1594 MENUITEM_FUNCTION(recscreen_item, 0, ID2P(LANG_RECORDING),
1595 fm_recording_screen, NULL, NULL, Icon_Recording);
1596 #endif
1597 #ifdef FM_RECORDING_SETTINGS
1598 MENUITEM_FUNCTION(recsettings_item, 0, ID2P(LANG_RECORDING_SETTINGS),
1599 fm_recording_settings, NULL, NULL, Icon_Recording);
1600 #endif
1601 #ifndef FM_PRESET
1602 MENUITEM_FUNCTION(radio_presets_item, 0, ID2P(LANG_PRESET),
1603 handle_radio_presets, NULL, NULL, Icon_NOICON);
1604 #endif
1605 #ifndef FM_PRESET_ADD
1606 MENUITEM_FUNCTION(radio_addpreset_item, 0, ID2P(LANG_FM_ADD_PRESET),
1607 radio_add_preset, NULL, NULL, Icon_NOICON);
1608 #endif
1611 MENUITEM_FUNCTION(presetload_item, 0, ID2P(LANG_FM_PRESET_LOAD),
1612 load_preset_list, NULL, NULL, Icon_NOICON);
1613 MENUITEM_FUNCTION(presetsave_item, 0, ID2P(LANG_FM_PRESET_SAVE),
1614 save_preset_list, NULL, NULL, Icon_NOICON);
1615 MENUITEM_FUNCTION(presetclear_item, 0, ID2P(LANG_FM_PRESET_CLEAR),
1616 clear_preset_list, NULL, NULL, Icon_NOICON);
1617 MENUITEM_FUNCTION(scan_presets_item, MENU_FUNC_USEPARAM,
1618 ID2P(LANG_FM_SCAN_PRESETS),
1619 scan_presets, NULL, NULL, Icon_NOICON);
1621 MAKE_MENU(radio_settings_menu, ID2P(LANG_FM_MENU), NULL,
1622 Icon_Radio_screen,
1623 #ifndef FM_PRESET
1624 &radio_presets_item,
1625 #endif
1626 #ifndef FM_PRESET_ADD
1627 &radio_addpreset_item,
1628 #endif
1629 &presetload_item, &presetsave_item, &presetclear_item,
1630 &force_mono,
1631 #ifndef FM_MODE
1632 &radio_mode_item,
1633 #endif
1634 &set_region, &sound_settings,
1635 #ifdef FM_RECORDING_SCREEN
1636 &recscreen_item,
1637 #endif
1638 #ifdef FM_RECORDING_SETTINGS
1639 &recsettings_item,
1640 #endif
1641 &scan_presets_item);
1642 /* main menu of the radio screen */
1643 static bool radio_menu(void)
1645 return do_menu(&radio_settings_menu, NULL, NULL, false) ==
1646 MENU_ATTACHED_USB;
1649 #endif