1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
34 #include "mp3_playback.h"
45 #include "peakmeter.h"
48 #include "sound_menu.h"
50 #include "recording.h"
56 #include "screen_access.h"
57 #include "statusbar.h"
60 #include "buttonbar.h"
66 #include "menus/exported_menus.h"
67 #include "root_menu.h"
72 #if CONFIG_KEYPAD == RECORDER_PAD
75 #define FM_PRESET_ACTION
79 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
82 #define FM_NEXT_PRESET
83 #define FM_PREV_PRESET
85 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
89 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
92 /* This should be removeable if the whole tuning thing is sorted out since
93 proper tuning quiets the screen almost entirely in that extreme measures
94 have to be taken to hear any interference. */
95 #define HAVE_NOISY_IDLE_MODE
97 #elif CONFIG_KEYPAD == ONDIO_PAD
98 #define FM_RECORD_DBLPRE
100 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD)
109 #define RADIO_SCAN_MODE 0
110 #define RADIO_PRESET_MODE 1
112 static int curr_preset
= -1;
113 static int curr_freq
;
114 static int radio_mode
= RADIO_SCAN_MODE
;
115 static int search_dir
= 0;
117 static int radio_status
= FMRADIO_OFF
;
118 static bool in_screen
= false;
120 #define MAX_PRESETS 64
121 static bool presets_loaded
= false, presets_changed
= false;
122 static struct fmstation presets
[MAX_PRESETS
];
124 static char filepreset
[MAX_PATH
]; /* preset filename variable */
126 static int num_presets
= 0; /* The number of presets in the preset list */
128 static void radio_save_presets(void);
129 static int handle_radio_presets(void);
130 static bool radio_menu(void);
131 static int radio_add_preset(void);
132 static int save_preset_list(void);
133 static int load_preset_list(void);
134 static int clear_preset_list(void);
136 static int scan_presets(void *viewports
);
138 /* Function to manipulate all yesno dialogues.
139 This function needs the output text as an argument. */
140 static bool yesno_pop(const char* text
)
143 const char *lines
[]={text
};
144 const struct text_message message
={lines
, 1};
145 bool ret
= (gui_syncyesno_run(&message
,NULL
,NULL
)== YESNO_YES
);
147 screens
[i
].clear_viewport();
151 void radio_init(void)
157 int get_radio_status(void)
162 bool in_radio_screen(void)
167 /* TODO: Move some more of the control functionality to an HAL and clean up the
170 /* secret flag for starting paused - prevents unmute */
171 #define FMRADIO_START_PAUSED 0x8000
172 void radio_start(void)
174 const struct fm_region_data
*fmr
;
177 if(radio_status
== FMRADIO_PLAYING
)
180 fmr
= &fm_region_data
[global_settings
.fm_region
];
182 start_paused
= radio_status
& FMRADIO_START_PAUSED
;
183 /* clear flag before any yielding */
184 radio_status
&= ~FMRADIO_START_PAUSED
;
186 if(radio_status
== FMRADIO_OFF
)
189 curr_freq
= global_status
.last_frequency
190 * fmr
->freq_step
+ fmr
->freq_min
;
192 tuner_set(RADIO_SLEEP
, 0); /* wake up the tuner */
194 if(radio_status
== FMRADIO_OFF
)
196 #ifdef HAVE_RADIO_REGION
197 tuner_set(RADIO_REGION
, global_settings
.fm_region
);
199 tuner_set(RADIO_FORCE_MONO
, global_settings
.fm_force_mono
);
202 tuner_set(RADIO_FREQUENCY
, curr_freq
);
204 #ifdef HAVE_RADIO_MUTE_TIMEOUT
206 unsigned long mute_timeout
= current_tick
+ HZ
;
207 if (radio_status
!= FMRADIO_OFF
)
213 while(!tuner_get(RADIO_STEREO
) && !tuner_get(RADIO_TUNED
))
215 if(TIME_AFTER(current_tick
, mute_timeout
))
222 /* keep radio from sounding initially */
224 tuner_set(RADIO_MUTE
, 0);
226 radio_status
= FMRADIO_PLAYING
;
229 void radio_pause(void)
231 if(radio_status
== FMRADIO_PAUSED
)
234 if(radio_status
== FMRADIO_OFF
)
236 radio_status
|= FMRADIO_START_PAUSED
;
240 tuner_set(RADIO_MUTE
, 1);
241 tuner_set(RADIO_SLEEP
, 1);
243 radio_status
= FMRADIO_PAUSED
;
246 void radio_stop(void)
248 if(radio_status
== FMRADIO_OFF
)
251 tuner_set(RADIO_MUTE
, 1);
252 tuner_set(RADIO_SLEEP
, 1); /* low power mode, if available */
253 radio_status
= FMRADIO_OFF
;
254 tuner_power(false); /* status update, power off if avail. */
257 bool radio_hardware_present(void)
259 return tuner_get(RADIO_PRESENT
);
262 /* Keep freq on the grid for the current region */
263 static int snap_freq_to_grid(int freq
)
265 const struct fm_region_data
* const fmr
=
266 &fm_region_data
[global_settings
.fm_region
];
268 /* Range clamp if out of range or just round to nearest */
269 if (freq
< fmr
->freq_min
)
270 freq
= fmr
->freq_min
;
271 else if (freq
> fmr
->freq_max
)
272 freq
= fmr
->freq_max
;
274 freq
= (freq
- fmr
->freq_min
+ fmr
->freq_step
/2) /
275 fmr
->freq_step
* fmr
->freq_step
+ fmr
->freq_min
;
280 /* Find a matching preset to freq */
281 static int find_preset(int freq
)
286 for(i
= 0;i
< MAX_PRESETS
;i
++)
288 if(freq
== presets
[i
].frequency
)
295 /* Return the first preset encountered in the search direction with
297 static int find_closest_preset(int freq
, int direction
)
301 if (direction
== 0) /* direction == 0 isn't really used */
304 for (i
= 0; i
< MAX_PRESETS
; i
++)
306 int preset_frequency
= presets
[i
].frequency
;
308 if (preset_frequency
== freq
)
309 return i
; /* Exact match = stop */
310 /* Stop when the preset frequency exeeds freq so that we can
311 pick the correct one based on direction */
312 if (preset_frequency
> freq
)
316 /* wrap around depending on direction */
317 if (i
== 0 || i
>= num_presets
- 1)
318 i
= direction
< 0 ? num_presets
- 1 : 0;
319 else if (direction
< 0)
320 i
--; /* use previous */
325 static void remember_frequency(void)
327 const struct fm_region_data
* const fmr
=
328 &fm_region_data
[global_settings
.fm_region
];
329 global_status
.last_frequency
= (curr_freq
- fmr
->freq_min
)
334 static void next_preset(int direction
)
339 if (curr_preset
== -1)
340 curr_preset
= find_closest_preset(curr_freq
, direction
);
342 curr_preset
= (curr_preset
+ direction
+ num_presets
) % num_presets
;
344 /* Must stay on the current grid for the region */
345 curr_freq
= snap_freq_to_grid(presets
[curr_preset
].frequency
);
347 tuner_set(RADIO_FREQUENCY
, curr_freq
);
348 remember_frequency();
351 /* Step to the next or previous frequency */
352 static int step_freq(int freq
, int direction
)
354 const struct fm_region_data
* const fmr
=
355 &fm_region_data
[global_settings
.fm_region
];
357 freq
+= direction
*fmr
->freq_step
;
359 /* Wrap first or snapping to grid will not let us on the band extremes */
360 if (freq
> fmr
->freq_max
)
361 freq
= direction
> 0 ? fmr
->freq_min
: fmr
->freq_max
;
362 else if (freq
< fmr
->freq_min
)
363 freq
= direction
< 0 ? fmr
->freq_max
: fmr
->freq_min
;
365 freq
= snap_freq_to_grid(freq
);
370 /* Step to the next or previous station */
371 static void next_station(int direction
)
373 if (direction
!= 0 && radio_mode
!= RADIO_SCAN_MODE
)
375 next_preset(direction
);
379 curr_freq
= step_freq(curr_freq
, direction
);
381 if (radio_status
== FMRADIO_PLAYING
)
382 tuner_set(RADIO_MUTE
, 1);
384 tuner_set(RADIO_FREQUENCY
, curr_freq
);
386 if (radio_status
== FMRADIO_PLAYING
)
387 tuner_set(RADIO_MUTE
, 0);
389 curr_preset
= find_preset(curr_freq
);
390 remember_frequency();
393 /* Ends an in-progress search */
394 static void end_search(void)
396 if (search_dir
!= 0 && radio_status
== FMRADIO_PLAYING
)
397 tuner_set(RADIO_MUTE
, 0);
401 /* Speak a frequency. */
402 static void talk_freq(int freq
, bool enqueue
)
405 talk_number(freq
/ 100, enqueue
);
406 talk_id(LANG_POINT
, true);
407 talk_number(freq
% 100 / 10, true);
409 talk_number(freq
% 10, true);
412 /* Speak a preset by number or by spelling its name, depending on settings. */
413 static void talk_preset(int preset
, bool fallback
, bool enqueue
)
415 if (global_settings
.talk_file
== 1) /* number */
416 talk_number(preset
+ 1, enqueue
);
419 if(presets
[preset
].name
[0])
420 talk_spell(presets
[preset
].name
, enqueue
);
422 talk_freq(presets
[preset
].frequency
, enqueue
);
426 int radio_screen(void)
430 int ret_val
= GO_TO_ROOT
;
433 bool stereo
= false, last_stereo
= false;
435 int top_of_screen
= 0;
436 bool update_screen
= true;
437 bool screen_freeze
= false;
438 bool keep_playing
= false;
439 bool statusbar
= global_settings
.statusbar
;
441 #ifdef FM_RECORD_DBLPRE
442 int lastbutton
= BUTTON_NONE
;
443 unsigned long rec_lastclick
= 0;
445 #if CONFIG_CODEC != SWCODEC
446 bool have_recorded
= false;
447 int timeout
= current_tick
+ HZ
/10;
448 unsigned int seconds
= 0;
449 unsigned int last_seconds
= 0;
451 struct audio_recording_options rec_options
;
452 #endif /* CONFIG_CODEC != SWCODEC */
453 #ifndef HAVE_NOISY_IDLE_MODE
454 int button_timeout
= current_tick
+ (2*HZ
);
456 struct viewport vp
[NB_SCREENS
];
457 #ifdef HAVE_BUTTONBAR
458 struct gui_buttonbar buttonbar
;
459 gui_buttonbar_init(&buttonbar
);
460 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
463 /* change status to "in screen" */
466 /* always display status bar in radio screen for now */
467 global_status
.statusbar_forced
= statusbar
?0:1;
468 global_settings
.statusbar
= true;
469 gui_syncstatusbar_draw(&statusbars
,true);
472 viewport_set_defaults(&vp
[i
], i
);
473 #ifdef HAVE_BUTTONBAR
474 if (global_settings
.buttonbar
)
475 vp
[i
].height
-= BUTTONBAR_HEIGHT
;
477 screens
[i
].set_viewport(&vp
[i
]);
478 screens
[i
].clear_viewport();
479 screens
[i
].update_viewport();
482 fh
= font_get(FONT_UI
)->height
;
484 /* Adjust for font size, trying to center the information vertically */
490 memset(presets
, 0, sizeof(presets
));
491 radio_load_presets(global_settings
.fmr_file
);
494 if(radio_status
== FMRADIO_OFF
)
498 #if CONFIG_CODEC != SWCODEC
499 if(rec_create_directory() > 0)
500 have_recorded
= true;
502 audio_init_recording(talk_get_bufsize());
504 sound_settings_apply();
505 /* Yes, we use the D/A for monitoring */
506 peak_meter_playback(true);
508 peak_meter_enabled
= true;
510 rec_init_recording_options(&rec_options
);
511 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
512 rec_set_recording_options(&rec_options
);
514 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
515 sound_default(SOUND_RIGHT_GAIN
), AUDIO_GAIN_LINEIN
);
517 #endif /* CONFIG_CODEC != SWCODEC */
518 #endif /* ndef SIMULATOR */
521 #if CONFIG_CODEC == SWCODEC
522 audio_set_input_source(AUDIO_SRC_FMRADIO
,
523 (radio_status
== FMRADIO_PAUSED
) ?
524 SRCF_FMRADIO_PAUSED
: SRCF_FMRADIO_PLAYING
);
526 if (radio_status
== FMRADIO_OFF
)
530 if(num_presets
< 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN
)))
533 curr_preset
= find_preset(curr_freq
);
534 if(curr_preset
!= -1)
535 radio_mode
= RADIO_PRESET_MODE
;
537 #ifdef HAVE_BUTTONBAR
538 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
539 str(LANG_PRESET
), str(LANG_FM_BUTTONBAR_RECORD
));
542 #ifndef HAVE_NOISY_IDLE_MODE
550 curr_freq
= step_freq(curr_freq
, search_dir
);
551 update_screen
= true;
553 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
555 curr_preset
= find_preset(curr_freq
);
556 remember_frequency();
569 #if CONFIG_CODEC != SWCODEC
570 /* TODO: Can we timeout at HZ when recording since peaks aren't
571 displayed? This should quiet recordings too. */
572 button
= get_action(CONTEXT_FM
,
573 update_screen
? TIMEOUT_NOBLOCK
: HZ
/ PEAK_METER_FPS
);
575 button
= get_action(CONTEXT_FM
,
576 update_screen
? TIMEOUT_NOBLOCK
: HZ
);
579 #ifndef HAVE_NOISY_IDLE_MODE
580 if (button
!= ACTION_NONE
)
582 cpu_idle_mode(false);
583 button_timeout
= current_tick
+ (2*HZ
);
589 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
590 if(audio_status() == AUDIO_STATUS_RECORD
)
600 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
602 if(filepreset
[0] == '\0')
605 radio_save_presets();
608 /* Clear the preset list on exit. */
611 update_screen
= true;
615 case ACTION_FM_RECORD
:
616 #ifdef FM_RECORD_DBLPRE
617 if (lastbutton
!= ACTION_FM_RECORD_DBLPRE
)
622 if (current_tick
- rec_lastclick
> HZ
/2)
624 rec_lastclick
= current_tick
;
627 #endif /* FM_RECORD_DBLPRE */
629 if(audio_status() == AUDIO_STATUS_RECORD
)
631 rec_command(RECORDING_CMD_START_NEWFILE
);
632 update_screen
= true;
636 have_recorded
= true;
637 rec_command(RECORDING_CMD_START
);
638 update_screen
= true;
640 #endif /* SIMULATOR */
643 #endif /* #ifdef FM_RECORD */
646 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
647 if(audio_status() == AUDIO_STATUS_RECORD
)
652 ret_val
= GO_TO_ROOT
;
655 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
657 if(filepreset
[0] == '\0')
660 radio_save_presets();
664 /* Clear the preset list on exit. */
669 case ACTION_STD_PREV
:
670 case ACTION_STD_NEXT
:
671 next_station(button
== ACTION_STD_PREV
? -1 : 1);
673 update_screen
= true;
677 case ACTION_STD_PREVREPEAT
:
678 case ACTION_STD_NEXTREPEAT
:
680 int dir
= search_dir
;
681 search_dir
= button
== ACTION_STD_PREVREPEAT
? -1 : 1;
682 if (radio_mode
!= RADIO_SCAN_MODE
)
684 next_preset(search_dir
);
686 update_screen
= true;
691 /* Starting auto scan */
692 tuner_set(RADIO_MUTE
, 1);
693 update_screen
= true;
698 case ACTION_SETTINGS_INC
:
699 case ACTION_SETTINGS_INCREPEAT
:
700 global_settings
.volume
++;
702 update_screen
= true;
705 case ACTION_SETTINGS_DEC
:
706 case ACTION_SETTINGS_DECREPEAT
:
707 global_settings
.volume
--;
709 update_screen
= true;
713 if (radio_status
== FMRADIO_PLAYING
)
718 update_screen
= true;
725 curr_preset
= find_preset(curr_freq
);
728 screens
[i
].set_viewport(&vp
[i
]);
729 screens
[i
].clear_viewport();
730 screens
[i
].update_viewport();
731 screens
[i
].set_viewport(NULL
);
733 #ifdef HAVE_BUTTONBAR
734 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
736 str(LANG_FM_BUTTONBAR_RECORD
));
738 update_screen
= true;
742 case ACTION_FM_PRESET
:
745 gui_syncsplash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
746 update_screen
= true;
749 screens
[i
].set_viewport(&vp
[i
]);
750 screens
[i
].clear_viewport();
751 screens
[i
].update_viewport();
752 screens
[i
].set_viewport(NULL
);
757 handle_radio_presets();
760 screens
[i
].set_viewport(&vp
[i
]);
761 screens
[i
].clear_viewport();
762 screens
[i
].update_viewport();
763 screens
[i
].set_viewport(NULL
);
765 #ifdef HAVE_BUTTONBAR
766 gui_buttonbar_set(&buttonbar
,
767 str(LANG_BUTTONBAR_MENU
),
769 str(LANG_FM_BUTTONBAR_RECORD
));
771 update_screen
= true;
773 #endif /* FM_PRESET */
776 case ACTION_FM_FREEZE
:
779 gui_syncsplash(HZ
, str(LANG_FM_FREEZE
));
780 screen_freeze
= true;
784 update_screen
= true;
785 screen_freeze
= false;
788 #endif /* FM_FREEZE */
790 case SYS_USB_CONNECTED
:
791 #if CONFIG_CODEC != SWCODEC
792 /* Only accept USB connection when not recording */
793 if(audio_status() != AUDIO_STATUS_RECORD
)
796 default_event_handler(SYS_USB_CONNECTED
);
797 screen_freeze
= true; /* Cosmetic: makes sure the
798 radio screen doesn't redraw */
805 if(radio_mode
== RADIO_SCAN_MODE
)
807 /* Force scan mode if there are no presets. */
809 radio_mode
= RADIO_PRESET_MODE
;
812 radio_mode
= RADIO_SCAN_MODE
;
813 update_screen
= true;
814 cond_talk_ids_fq(radio_mode
?
815 LANG_PRESET
: LANG_RADIO_SCAN_MODE
);
820 #ifdef FM_NEXT_PRESET
821 case ACTION_FM_NEXT_PRESET
:
824 update_screen
= true;
829 #ifdef FM_PREV_PRESET
830 case ACTION_FM_PREV_PRESET
:
833 update_screen
= true;
839 default_event_handler(button
);
843 #ifdef FM_RECORD_DBLPRE
844 if (button
!= ACTION_NONE
)
848 #if CONFIG_CODEC != SWCODEC
854 /* Only display the peak meter when not recording */
855 #if CONFIG_CODEC != SWCODEC
860 screens
[i
].set_viewport(&vp
[i
]);
861 peak_meter_screen(&screens
[i
],0,
862 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4), fh
);
863 screens
[i
].update_rect(0, STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
864 screens
[i
].getwidth(), fh
);
865 screens
[i
].set_viewport(NULL
);
869 if(TIME_AFTER(current_tick
, timeout
))
871 timeout
= current_tick
+ HZ
;
874 #endif /* CONFIG_CODEC == SWCODEC */
876 /* keep "mono" from always being displayed when paused */
877 if (radio_status
!= FMRADIO_PAUSED
)
879 stereo
= tuner_get(RADIO_STEREO
) &&
880 !global_settings
.fm_force_mono
;
882 if(stereo
!= last_stereo
)
884 update_screen
= true;
885 last_stereo
= stereo
;
890 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
891 seconds
= audio_recorded_time() / HZ
;
892 if (update_screen
|| seconds
> last_seconds
)
894 last_seconds
= seconds
;
903 screens
[i
].set_viewport(&vp
[i
]);
906 snprintf(buf
, 128, curr_preset
>= 0 ? "%d. %s" : " ",
907 curr_preset
+ 1, presets
[curr_preset
].name
);
910 screens
[i
].puts_scroll(0, top_of_screen
, buf
);
912 freq
= curr_freq
/ 10000;
913 snprintf(buf
, 128, str(LANG_FM_STATION
), freq
/ 100, freq
% 100);
915 screens
[i
].puts_scroll(0, top_of_screen
+ 1, buf
);
917 snprintf(buf
, 128, stereo
?str(LANG_CHANNEL_STEREO
):
918 str(LANG_CHANNEL_MONO
));
920 screens
[i
].puts_scroll(0, top_of_screen
+ 2, buf
);
922 snprintf(buf
, 128, "%s %s", str(LANG_MODE
),
923 radio_mode
? str(LANG_PRESET
) :
924 str(LANG_RADIO_SCAN_MODE
));
926 screens
[i
].puts_scroll(0, top_of_screen
+ 3, buf
);
928 #if CONFIG_CODEC != SWCODEC
929 if(audio_status() == AUDIO_STATUS_RECORD
)
931 hours
= seconds
/ 3600;
932 minutes
= (seconds
- (hours
* 3600)) / 60;
933 snprintf(buf
, 32, "%s %02d:%02d:%02d",
934 str(LANG_RECORDING_TIME
),
935 hours
, minutes
, seconds
%60);
937 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
941 if(rec_options
.rec_prerecord_time
)
943 snprintf(buf
, 32, "%s %02d",
944 str(LANG_RECORD_PRERECORD
), seconds
%60);
946 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
949 #endif /* CONFIG_CODEC != SWCODEC */
953 screens
[i
].update_viewport();
954 screens
[i
].set_viewport(NULL
);
957 #ifdef HAVE_BUTTONBAR
958 gui_buttonbar_draw(&buttonbar
);
961 /* Only force the redraw if update_screen is true */
962 gui_syncstatusbar_draw(&statusbars
,true);
965 update_screen
= false;
967 if (global_settings
.talk_file
&& talk
968 && radio_status
== FMRADIO_PAUSED
)
971 bool enqueue
= false;
972 if (radio_mode
== RADIO_SCAN_MODE
)
974 talk_freq(curr_freq
, enqueue
);
977 if (curr_preset
>= 0)
978 talk_preset(curr_preset
, radio_mode
== RADIO_PRESET_MODE
,
982 #if CONFIG_CODEC != SWCODEC
983 if(audio_status() & AUDIO_STATUS_ERROR
)
989 #ifndef HAVE_NOISY_IDLE_MODE
990 if (TIME_AFTER(current_tick
, button_timeout
))
998 #if CONFIG_CODEC != SWCODEC
999 if(audio_status() & AUDIO_STATUS_ERROR
)
1001 gui_syncsplash(0, str(LANG_DISK_FULL
));
1002 gui_syncstatusbar_draw(&statusbars
,true);
1005 screens
[i
].set_viewport(&vp
[i
]);
1006 screens
[i
].update_viewport();
1007 screens
[i
].set_viewport(NULL
);
1009 audio_error_clear();
1013 button
= get_action(CONTEXT_FM
, TIMEOUT_BLOCK
);
1014 if(button
== ACTION_FM_STOP
)
1019 audio_init_playback();
1020 #endif /* CONFIG_CODEC != SWCODEC */
1022 sound_settings_apply();
1023 #endif /* SIMULATOR */
1027 /* Catch FMRADIO_PLAYING status for the sim. */
1029 #if CONFIG_CODEC != SWCODEC
1030 /* Enable the Left and right A/D Converter */
1031 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
1032 sound_default(SOUND_RIGHT_GAIN
),
1034 mas_codec_writereg(6, 0x4000);
1037 #endif /* SIMULATOR */
1041 #if CONFIG_CODEC == SWCODEC
1042 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
1048 #ifndef HAVE_NOISY_IDLE_MODE
1049 cpu_idle_mode(false);
1052 /* restore status bar settings */
1053 global_settings
.statusbar
= statusbar
;
1054 global_status
.statusbar_forced
= 0;
1056 #if CONFIG_CODEC != SWCODEC
1057 return have_recorded
;
1061 } /* radio_screen */
1063 static void radio_save_presets(void)
1068 fd
= creat(filepreset
);
1071 for(i
= 0;i
< num_presets
;i
++)
1073 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
1077 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
1078 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
1079 presets_changed
= false;
1083 gui_syncsplash(HZ
, ID2P(LANG_FM_PRESET_SAVE_FAILED
));
1087 void radio_load_presets(char *filename
)
1097 memset(presets
, 0, sizeof(presets
));
1100 /* No Preset in configuration. */
1101 if(filename
[0] == '\0')
1103 filepreset
[0] = '\0';
1106 /* Temporary preset, loaded until player shuts down. */
1107 else if(filename
[0] == '/')
1108 strncpy(filepreset
, filename
, sizeof(filepreset
));
1109 /* Preset from default directory. */
1111 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
1112 FMPRESET_PATH
, filename
);
1114 fd
= open(filepreset
, O_RDONLY
);
1117 while(!done
&& num_presets
< MAX_PRESETS
)
1119 rc
= read_line(fd
, buf
, 128);
1122 if(settings_parseline(buf
, &freq
, &name
))
1125 if(f
) /* For backwards compatibility */
1127 struct fmstation
* const fms
= &presets
[num_presets
];
1129 strncpy(fms
->name
, name
, MAX_FMPRESET_LEN
);
1130 fms
->name
[MAX_FMPRESET_LEN
] = '\0';
1140 else /* invalid file name? */
1141 filepreset
[0] = '\0';
1143 presets_loaded
= num_presets
> 0;
1144 presets_changed
= false;
1148 static int radio_add_preset(void)
1150 char buf
[MAX_FMPRESET_LEN
+ 1];
1152 if(num_presets
< MAX_PRESETS
)
1154 memset(buf
, 0, MAX_FMPRESET_LEN
);
1156 if (!kbd_input(buf
, MAX_FMPRESET_LEN
))
1158 struct fmstation
* const fms
= &presets
[num_presets
];
1159 buf
[MAX_FMPRESET_LEN
] = '\0';
1160 strcpy(fms
->name
, buf
);
1161 fms
->frequency
= curr_freq
;
1163 presets_changed
= true;
1164 presets_loaded
= num_presets
> 0;
1169 gui_syncsplash(HZ
, ID2P(LANG_FM_NO_FREE_PRESETS
));
1174 /* needed to know which preset we are edit/delete-ing */
1175 static int selected_preset
= -1;
1176 static int radio_edit_preset(void)
1178 char buf
[MAX_FMPRESET_LEN
+ 1];
1180 if (num_presets
> 0)
1182 struct fmstation
* const fms
= &presets
[selected_preset
];
1184 strncpy(buf
, fms
->name
, MAX_FMPRESET_LEN
);
1186 if (!kbd_input(buf
, MAX_FMPRESET_LEN
))
1188 buf
[MAX_FMPRESET_LEN
] = '\0';
1189 strcpy(fms
->name
, buf
);
1190 presets_changed
= true;
1197 static int radio_delete_preset(void)
1199 if (num_presets
> 0)
1201 struct fmstation
* const fms
= &presets
[selected_preset
];
1203 if (selected_preset
>= --num_presets
)
1204 selected_preset
= num_presets
- 1;
1206 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
1211 /* Don't ask to save when all presets are deleted. */
1212 presets_changed
= num_presets
> 0;
1214 if (!presets_changed
)
1216 /* The preset list will be cleared, switch to Scan Mode. */
1217 radio_mode
= RADIO_SCAN_MODE
;
1218 presets_loaded
= false;
1224 static int load_preset_list(void)
1226 return !rockbox_browse(FMPRESET_PATH
, SHOW_FMR
);
1229 static int save_preset_list(void)
1233 bool bad_file_name
= true;
1235 if(!dir_exists(FMPRESET_PATH
)) /* Check if there is preset folder */
1236 mkdir(FMPRESET_PATH
);
1238 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
1239 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
1241 while(bad_file_name
)
1243 if(!kbd_input(filepreset
, sizeof(filepreset
)))
1245 /* check the name: max MAX_FILENAME (20) chars */
1249 p1
= strrchr(filepreset
, '/');
1251 while((p1
) && (*p2
) && (*p2
!= '.'))
1253 len
= (int)(p2
-p1
) - 1;
1254 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
1256 /* no slash, too long or too short */
1257 gui_syncsplash(HZ
, ID2P(LANG_INVALID_FILENAME
));
1261 /* add correct extension (easier to always write)
1262 at this point, p2 points to 0 or the extension dot */
1264 strcat(filepreset
,".fmr");
1265 bad_file_name
= false;
1266 radio_save_presets();
1277 gui_syncsplash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
1282 static int clear_preset_list(void)
1284 /* Clear all the preset entries */
1285 memset(presets
, 0, sizeof (presets
));
1288 presets_loaded
= false;
1289 /* The preset list will be cleared switch to Scan Mode. */
1290 radio_mode
= RADIO_SCAN_MODE
;
1292 presets_changed
= false; /* Don't ask to save when clearing the list. */
1297 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1298 ID2P(LANG_FM_EDIT_PRESET
),
1299 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
1300 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1301 ID2P(LANG_FM_DELETE_PRESET
),
1302 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
1303 static int radio_preset_callback(int action
,
1304 const struct menu_item_ex
*this_item
)
1306 if (action
== ACTION_STD_OK
)
1307 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
1311 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_PRESET
),
1312 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
1313 &radio_delete_preset_item
);
1314 /* present a list of preset stations */
1315 static char * presets_get_name(int selected_item
, void *data
,
1316 char *buffer
, size_t buffer_len
)
1319 struct fmstation
*p
= &presets
[selected_item
];
1322 int freq
= p
->frequency
/ 10000;
1323 int frac
= freq
% 100;
1325 snprintf(buffer
, buffer_len
,
1326 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
1330 static int presets_speak_name(int selected_item
, void * data
)
1333 talk_preset(selected_item
, true, false);
1337 static int handle_radio_presets(void)
1339 struct gui_synclist lists
;
1341 int action
= ACTION_NONE
;
1342 #ifdef HAVE_BUTTONBAR
1343 struct gui_buttonbar buttonbar
;
1346 if(presets_loaded
== false)
1349 #ifdef HAVE_BUTTONBAR
1350 gui_buttonbar_init(&buttonbar
);
1351 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
1352 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
1353 str(LANG_FM_BUTTONBAR_EXIT
),
1354 str(LANG_FM_BUTTONBAR_ACTION
));
1355 gui_buttonbar_draw(&buttonbar
);
1357 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1, NULL
);
1358 gui_synclist_set_title(&lists
, str(LANG_PRESET
), NOICON
);
1359 gui_synclist_set_icon_callback(&lists
, NULL
);
1360 if(global_settings
.talk_file
)
1361 gui_synclist_set_voice_callback(&lists
, presets_speak_name
);
1362 gui_synclist_set_nb_items(&lists
, num_presets
);
1363 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
1364 gui_synclist_speak_item(&lists
);
1368 gui_synclist_draw(&lists
);
1369 gui_syncstatusbar_draw(&statusbars
, true);
1370 list_do_action(CONTEXT_STD
, HZ
,
1371 &lists
, &action
, LIST_WRAP_UNLESS_HELD
);
1374 case ACTION_STD_MENU
:
1377 case ACTION_STD_CANCEL
:
1381 curr_preset
= gui_synclist_get_sel_pos(&lists
);
1382 curr_freq
= presets
[curr_preset
].frequency
;
1384 remember_frequency();
1388 case ACTION_STD_CONTEXT
:
1389 selected_preset
= gui_synclist_get_sel_pos(&lists
);
1390 do_menu(&handle_radio_preset_menu
, NULL
, NULL
, false);
1391 gui_synclist_speak_item(&lists
);
1394 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
1401 void toggle_mono_mode(bool mono
)
1403 tuner_set(RADIO_FORCE_MONO
, mono
);
1406 void set_radio_region(int region
)
1408 #ifdef HAVE_RADIO_REGION
1409 tuner_set(RADIO_REGION
, region
);
1412 remember_frequency();
1416 MENUITEM_SETTING(set_region
, &global_settings
.fm_region
, NULL
);
1417 MENUITEM_SETTING(force_mono
, &global_settings
.fm_force_mono
, NULL
);
1420 static char* get_mode_text(int selected_item
, void * data
, char *buffer
)
1422 (void)selected_item
;
1424 snprintf(buffer
, MAX_PATH
, "%s %s", str(LANG_MODE
),
1425 radio_mode
? str(LANG_PRESET
) :
1426 str(LANG_RADIO_SCAN_MODE
));
1429 static int toggle_radio_mode(void)
1431 radio_mode
= (radio_mode
== RADIO_SCAN_MODE
) ?
1432 RADIO_PRESET_MODE
: RADIO_SCAN_MODE
;
1435 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item
, 0,
1436 toggle_radio_mode
, NULL
,
1437 get_mode_text
, NULL
, NULL
, NULL
, Icon_NOICON
);
1440 static int scan_presets(void *viewports
)
1442 bool do_scan
= true;
1444 struct viewport
*vp
= (struct viewport
*)viewports
;
1447 screens
[i
].set_viewport(vp
?&vp
[i
]:NULL
);
1448 if(num_presets
> 0) /* Do that to avoid 2 questions. */
1449 do_scan
= yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS
));
1453 const struct fm_region_data
* const fmr
=
1454 &fm_region_data
[global_settings
.fm_region
];
1456 char buf
[MAX_FMPRESET_LEN
+ 1];
1458 curr_freq
= fmr
->freq_min
;
1460 memset(presets
, 0, sizeof(presets
));
1461 tuner_set(RADIO_MUTE
, 1);
1463 while(curr_freq
<= fmr
->freq_max
)
1466 if (num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
1469 freq
= curr_freq
/ 10000;
1473 snprintf(buf
, MAX_FMPRESET_LEN
, str(LANG_FM_SCANNING
), freq
, frac
);
1474 gui_syncsplash(0, buf
);
1476 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
1479 presets
[num_presets
].name
[0] = '\0';
1480 presets
[num_presets
].frequency
= curr_freq
;
1484 curr_freq
+= fmr
->freq_step
;
1487 if (radio_status
== FMRADIO_PLAYING
)
1488 tuner_set(RADIO_MUTE
, 0);
1490 presets_changed
= true;
1494 screens
[i
].clear_viewport();
1495 screens
[i
].update_viewport();
1500 curr_freq
= presets
[0].frequency
;
1501 radio_mode
= RADIO_PRESET_MODE
;
1502 presets_loaded
= true;
1507 /* Wrap it to beginning or we'll be past end of band */
1508 presets_loaded
= false;
1516 #ifdef HAVE_RECORDING
1518 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1519 #define FM_RECORDING_SCREEN
1520 static int fm_recording_screen(void)
1524 /* switch recording source to FMRADIO for the duration */
1525 int rec_source
= global_settings
.rec_source
;
1526 global_settings
.rec_source
= AUDIO_SRC_FMRADIO
;
1528 ret
= recording_screen(true);
1530 /* safe to reset as changing sources is prohibited here */
1531 global_settings
.rec_source
= rec_source
;
1536 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1538 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1539 #define FM_RECORDING_SETTINGS
1540 static int fm_recording_settings(void)
1542 bool ret
= recording_menu(true);
1544 #if CONFIG_CODEC != SWCODEC
1547 struct audio_recording_options rec_options
;
1548 rec_init_recording_options(&rec_options
);
1549 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
1550 rec_set_recording_options(&rec_options
);
1557 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1558 #endif /* HAVE_RECORDING */
1560 #ifdef FM_RECORDING_SCREEN
1561 MENUITEM_FUNCTION(recscreen_item
, 0, ID2P(LANG_RECORDING
),
1562 fm_recording_screen
, NULL
, NULL
, Icon_Recording
);
1564 #ifdef FM_RECORDING_SETTINGS
1565 MENUITEM_FUNCTION(recsettings_item
, 0, ID2P(LANG_RECORDING_SETTINGS
),
1566 fm_recording_settings
, NULL
, NULL
, Icon_Recording
);
1569 MENUITEM_FUNCTION(radio_presets_item
, 0, ID2P(LANG_PRESET
),
1570 handle_radio_presets
, NULL
, NULL
, Icon_NOICON
);
1572 #ifndef FM_PRESET_ADD
1573 MENUITEM_FUNCTION(radio_addpreset_item
, 0, ID2P(LANG_FM_ADD_PRESET
),
1574 radio_add_preset
, NULL
, NULL
, Icon_NOICON
);
1578 MENUITEM_FUNCTION(presetload_item
, 0, ID2P(LANG_FM_PRESET_LOAD
),
1579 load_preset_list
, NULL
, NULL
, Icon_NOICON
);
1580 MENUITEM_FUNCTION(presetsave_item
, 0, ID2P(LANG_FM_PRESET_SAVE
),
1581 save_preset_list
, NULL
, NULL
, Icon_NOICON
);
1582 MENUITEM_FUNCTION(presetclear_item
, 0, ID2P(LANG_FM_PRESET_CLEAR
),
1583 clear_preset_list
, NULL
, NULL
, Icon_NOICON
);
1584 MENUITEM_FUNCTION(scan_presets_item
, MENU_FUNC_USEPARAM
,
1585 ID2P(LANG_FM_SCAN_PRESETS
),
1586 scan_presets
, NULL
, NULL
, Icon_NOICON
);
1588 MAKE_MENU(radio_settings_menu
, ID2P(LANG_FM_MENU
), NULL
,
1591 &radio_presets_item
,
1593 #ifndef FM_PRESET_ADD
1594 &radio_addpreset_item
,
1596 &presetload_item
, &presetsave_item
, &presetclear_item
,
1601 &set_region
, &sound_settings
,
1602 #ifdef FM_RECORDING_SCREEN
1605 #ifdef FM_RECORDING_SETTINGS
1608 &scan_presets_item
);
1609 /* main menu of the radio screen */
1610 static bool radio_menu(void)
1612 return do_menu(&radio_settings_menu
, NULL
, NULL
, false) == MENU_ATTACHED_USB
;