1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2003 Linus Nielsen Feltzing
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
32 #include "mp3_playback.h"
43 #include "peakmeter.h"
46 #include "sound_menu.h"
48 #include "recording.h"
54 #include "screen_access.h"
55 #include "statusbar.h"
58 #include "buttonbar.h"
64 #include "menus/exported_menus.h"
65 #include "root_menu.h"
70 #if CONFIG_KEYPAD == RECORDER_PAD
73 #define FM_PRESET_ACTION
77 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
80 #define FM_NEXT_PRESET
81 #define FM_PREV_PRESET
83 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
87 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
90 /* This should be removeable if the whole tuning thing is sorted out since
91 proper tuning quiets the screen almost entirely in that extreme measures
92 have to be taken to hear any interference. */
93 #define HAVE_NOISY_IDLE_MODE
95 #elif CONFIG_KEYPAD == ONDIO_PAD
96 #define FM_RECORD_DBLPRE
98 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD)
107 #define RADIO_SCAN_MODE 0
108 #define RADIO_PRESET_MODE 1
110 static int curr_preset
= -1;
111 static int curr_freq
;
112 static int radio_mode
= RADIO_SCAN_MODE
;
113 static int search_dir
= 0;
115 static int radio_status
= FMRADIO_OFF
;
116 static bool in_screen
= false;
118 #define MAX_PRESETS 64
119 static bool presets_loaded
= false, presets_changed
= false;
120 static struct fmstation presets
[MAX_PRESETS
];
122 static char filepreset
[MAX_PATH
]; /* preset filename variable */
124 static int num_presets
= 0; /* The number of presets in the preset list */
126 static void radio_save_presets(void);
127 static int handle_radio_presets(void);
128 static bool radio_menu(void);
129 static int radio_add_preset(void);
130 static int save_preset_list(void);
131 static int load_preset_list(void);
132 static int clear_preset_list(void);
134 static int scan_presets(void *viewports
);
136 /* Function to manipulate all yesno dialogues.
137 This function needs the output text as an argument. */
138 static bool yesno_pop(const char* text
)
141 const char *lines
[]={text
};
142 const struct text_message message
={lines
, 1};
143 bool ret
= (gui_syncyesno_run(&message
,NULL
,NULL
)== YESNO_YES
);
145 screens
[i
].clear_viewport();
149 void radio_init(void)
155 int get_radio_status(void)
160 bool in_radio_screen(void)
165 /* TODO: Move some more of the control functionality to an HAL and clean up the
168 /* secret flag for starting paused - prevents unmute */
169 #define FMRADIO_START_PAUSED 0x8000
170 void radio_start(void)
172 const struct fm_region_data
*fmr
;
175 if(radio_status
== FMRADIO_PLAYING
)
178 fmr
= &fm_region_data
[global_settings
.fm_region
];
180 start_paused
= radio_status
& FMRADIO_START_PAUSED
;
181 /* clear flag before any yielding */
182 radio_status
&= ~FMRADIO_START_PAUSED
;
184 if(radio_status
== FMRADIO_OFF
)
187 curr_freq
= global_status
.last_frequency
188 * fmr
->freq_step
+ fmr
->freq_min
;
190 tuner_set(RADIO_SLEEP
, 0); /* wake up the tuner */
192 if(radio_status
== FMRADIO_OFF
)
194 #ifdef HAVE_RADIO_REGION
195 tuner_set(RADIO_REGION
, global_settings
.fm_region
);
197 tuner_set(RADIO_FORCE_MONO
, global_settings
.fm_force_mono
);
200 tuner_set(RADIO_FREQUENCY
, curr_freq
);
202 #ifdef HAVE_RADIO_MUTE_TIMEOUT
204 unsigned long mute_timeout
= current_tick
+ HZ
;
205 if (radio_status
!= FMRADIO_OFF
)
211 while(!tuner_get(RADIO_STEREO
) && !tuner_get(RADIO_TUNED
))
213 if(TIME_AFTER(current_tick
, mute_timeout
))
220 /* keep radio from sounding initially */
222 tuner_set(RADIO_MUTE
, 0);
224 radio_status
= FMRADIO_PLAYING
;
227 void radio_pause(void)
229 if(radio_status
== FMRADIO_PAUSED
)
232 if(radio_status
== FMRADIO_OFF
)
234 radio_status
|= FMRADIO_START_PAUSED
;
238 tuner_set(RADIO_MUTE
, 1);
239 tuner_set(RADIO_SLEEP
, 1);
241 radio_status
= FMRADIO_PAUSED
;
244 void radio_stop(void)
246 if(radio_status
== FMRADIO_OFF
)
249 tuner_set(RADIO_MUTE
, 1);
250 tuner_set(RADIO_SLEEP
, 1); /* low power mode, if available */
251 radio_status
= FMRADIO_OFF
;
252 tuner_power(false); /* status update, power off if avail. */
255 bool radio_hardware_present(void)
257 return tuner_get(RADIO_PRESENT
);
260 /* Keep freq on the grid for the current region */
261 static int snap_freq_to_grid(int freq
)
263 const struct fm_region_data
* const fmr
=
264 &fm_region_data
[global_settings
.fm_region
];
266 /* Range clamp if out of range or just round to nearest */
267 if (freq
< fmr
->freq_min
)
268 freq
= fmr
->freq_min
;
269 else if (freq
> fmr
->freq_max
)
270 freq
= fmr
->freq_max
;
272 freq
= (freq
- fmr
->freq_min
+ fmr
->freq_step
/2) /
273 fmr
->freq_step
* fmr
->freq_step
+ fmr
->freq_min
;
278 /* Find a matching preset to freq */
279 static int find_preset(int freq
)
284 for(i
= 0;i
< MAX_PRESETS
;i
++)
286 if(freq
== presets
[i
].frequency
)
293 /* Return the first preset encountered in the search direction with
295 static int find_closest_preset(int freq
, int direction
)
299 if (direction
== 0) /* direction == 0 isn't really used */
302 for (i
= 0; i
< MAX_PRESETS
; i
++)
304 int preset_frequency
= presets
[i
].frequency
;
306 if (preset_frequency
== freq
)
307 return i
; /* Exact match = stop */
308 /* Stop when the preset frequency exeeds freq so that we can
309 pick the correct one based on direction */
310 if (preset_frequency
> freq
)
314 /* wrap around depending on direction */
315 if (i
== 0 || i
>= num_presets
- 1)
316 i
= direction
< 0 ? num_presets
- 1 : 0;
317 else if (direction
< 0)
318 i
--; /* use previous */
323 static void remember_frequency(void)
325 const struct fm_region_data
* const fmr
=
326 &fm_region_data
[global_settings
.fm_region
];
327 global_status
.last_frequency
= (curr_freq
- fmr
->freq_min
)
332 static void next_preset(int direction
)
337 if (curr_preset
== -1)
338 curr_preset
= find_closest_preset(curr_freq
, direction
);
340 curr_preset
= (curr_preset
+ direction
+ num_presets
) % num_presets
;
342 /* Must stay on the current grid for the region */
343 curr_freq
= snap_freq_to_grid(presets
[curr_preset
].frequency
);
345 tuner_set(RADIO_FREQUENCY
, curr_freq
);
346 remember_frequency();
349 /* Step to the next or previous frequency */
350 static int step_freq(int freq
, int direction
)
352 const struct fm_region_data
* const fmr
=
353 &fm_region_data
[global_settings
.fm_region
];
355 freq
+= direction
*fmr
->freq_step
;
357 /* Wrap first or snapping to grid will not let us on the band extremes */
358 if (freq
> fmr
->freq_max
)
359 freq
= direction
> 0 ? fmr
->freq_min
: fmr
->freq_max
;
360 else if (freq
< fmr
->freq_min
)
361 freq
= direction
< 0 ? fmr
->freq_max
: fmr
->freq_min
;
363 freq
= snap_freq_to_grid(freq
);
368 /* Step to the next or previous station */
369 static void next_station(int direction
)
371 if (direction
!= 0 && radio_mode
!= RADIO_SCAN_MODE
)
373 next_preset(direction
);
377 curr_freq
= step_freq(curr_freq
, direction
);
379 if (radio_status
== FMRADIO_PLAYING
)
380 tuner_set(RADIO_MUTE
, 1);
382 tuner_set(RADIO_FREQUENCY
, curr_freq
);
384 if (radio_status
== FMRADIO_PLAYING
)
385 tuner_set(RADIO_MUTE
, 0);
387 curr_preset
= find_preset(curr_freq
);
388 remember_frequency();
391 /* Ends an in-progress search */
392 static void end_search(void)
394 if (search_dir
!= 0 && radio_status
== FMRADIO_PLAYING
)
395 tuner_set(RADIO_MUTE
, 0);
399 /* Speak a frequency. */
400 static void talk_freq(int freq
, bool enqueue
)
403 talk_number(freq
/ 100, enqueue
);
404 talk_id(LANG_POINT
, true);
405 talk_number(freq
% 100 / 10, true);
407 talk_number(freq
% 10, true);
410 /* Speak a preset by number or by spelling its name, depending on settings. */
411 static void talk_preset(int preset
, bool fallback
, bool enqueue
)
413 if (global_settings
.talk_file
== 1) /* number */
414 talk_number(preset
+ 1, enqueue
);
417 if(presets
[preset
].name
[0])
418 talk_spell(presets
[preset
].name
, enqueue
);
420 talk_freq(presets
[preset
].frequency
, enqueue
);
424 int radio_screen(void)
428 int ret_val
= GO_TO_ROOT
;
431 bool stereo
= false, last_stereo
= false;
433 int top_of_screen
= 0;
434 bool update_screen
= true;
435 bool screen_freeze
= false;
436 bool keep_playing
= false;
437 bool statusbar
= global_settings
.statusbar
;
439 #ifdef FM_RECORD_DBLPRE
440 int lastbutton
= BUTTON_NONE
;
441 unsigned long rec_lastclick
= 0;
443 #if CONFIG_CODEC != SWCODEC
444 bool have_recorded
= false;
445 int timeout
= current_tick
+ HZ
/10;
446 unsigned int seconds
= 0;
447 unsigned int last_seconds
= 0;
449 struct audio_recording_options rec_options
;
450 #endif /* CONFIG_CODEC != SWCODEC */
451 #ifndef HAVE_NOISY_IDLE_MODE
452 int button_timeout
= current_tick
+ (2*HZ
);
454 struct viewport vp
[NB_SCREENS
];
455 #ifdef HAVE_BUTTONBAR
456 struct gui_buttonbar buttonbar
;
457 gui_buttonbar_init(&buttonbar
);
458 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
461 /* change status to "in screen" */
464 /* always display status bar in radio screen for now */
465 global_status
.statusbar_forced
= statusbar
?0:1;
466 global_settings
.statusbar
= true;
467 gui_syncstatusbar_draw(&statusbars
,true);
470 viewport_set_defaults(&vp
[i
], i
);
471 #ifdef HAVE_BUTTONBAR
472 if (global_settings
.buttonbar
)
473 vp
[i
].height
-= BUTTONBAR_HEIGHT
;
475 screens
[i
].set_viewport(&vp
[i
]);
476 screens
[i
].clear_viewport();
477 screens
[i
].update_viewport();
480 fh
= font_get(FONT_UI
)->height
;
482 /* Adjust for font size, trying to center the information vertically */
488 memset(presets
, 0, sizeof(presets
));
489 radio_load_presets(global_settings
.fmr_file
);
492 if(radio_status
== FMRADIO_OFF
)
496 #if CONFIG_CODEC != SWCODEC
497 if(rec_create_directory() > 0)
498 have_recorded
= true;
500 audio_init_recording(talk_get_bufsize());
502 sound_settings_apply();
503 /* Yes, we use the D/A for monitoring */
504 peak_meter_playback(true);
506 peak_meter_enabled
= true;
508 rec_init_recording_options(&rec_options
);
509 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
510 rec_set_recording_options(&rec_options
);
512 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
513 sound_default(SOUND_RIGHT_GAIN
), AUDIO_GAIN_LINEIN
);
515 #endif /* CONFIG_CODEC != SWCODEC */
516 #endif /* ndef SIMULATOR */
519 #if CONFIG_CODEC == SWCODEC
520 audio_set_input_source(AUDIO_SRC_FMRADIO
,
521 (radio_status
== FMRADIO_PAUSED
) ?
522 SRCF_FMRADIO_PAUSED
: SRCF_FMRADIO_PLAYING
);
524 if (radio_status
== FMRADIO_OFF
)
528 if(num_presets
< 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN
)))
531 curr_preset
= find_preset(curr_freq
);
532 if(curr_preset
!= -1)
533 radio_mode
= RADIO_PRESET_MODE
;
535 #ifdef HAVE_BUTTONBAR
536 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
537 str(LANG_PRESET
), str(LANG_FM_BUTTONBAR_RECORD
));
540 #ifndef HAVE_NOISY_IDLE_MODE
548 curr_freq
= step_freq(curr_freq
, search_dir
);
549 update_screen
= true;
551 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
553 curr_preset
= find_preset(curr_freq
);
554 remember_frequency();
567 #if CONFIG_CODEC != SWCODEC
568 /* TODO: Can we timeout at HZ when recording since peaks aren't
569 displayed? This should quiet recordings too. */
570 button
= get_action(CONTEXT_FM
,
571 update_screen
? TIMEOUT_NOBLOCK
: HZ
/ PEAK_METER_FPS
);
573 button
= get_action(CONTEXT_FM
,
574 update_screen
? TIMEOUT_NOBLOCK
: HZ
);
577 #ifndef HAVE_NOISY_IDLE_MODE
578 if (button
!= ACTION_NONE
)
580 cpu_idle_mode(false);
581 button_timeout
= current_tick
+ (2*HZ
);
587 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
588 if(audio_status() == AUDIO_STATUS_RECORD
)
598 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
600 if(filepreset
[0] == '\0')
603 radio_save_presets();
606 /* Clear the preset list on exit. */
609 update_screen
= true;
613 case ACTION_FM_RECORD
:
614 #ifdef FM_RECORD_DBLPRE
615 if (lastbutton
!= ACTION_FM_RECORD_DBLPRE
)
620 if (current_tick
- rec_lastclick
> HZ
/2)
622 rec_lastclick
= current_tick
;
625 #endif /* FM_RECORD_DBLPRE */
627 if(audio_status() == AUDIO_STATUS_RECORD
)
629 rec_command(RECORDING_CMD_START_NEWFILE
);
630 update_screen
= true;
634 have_recorded
= true;
635 rec_command(RECORDING_CMD_START
);
636 update_screen
= true;
638 #endif /* SIMULATOR */
641 #endif /* #ifdef FM_RECORD */
644 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
645 if(audio_status() == AUDIO_STATUS_RECORD
)
650 ret_val
= GO_TO_ROOT
;
653 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
655 if(filepreset
[0] == '\0')
658 radio_save_presets();
662 /* Clear the preset list on exit. */
667 case ACTION_STD_PREV
:
668 case ACTION_STD_NEXT
:
669 next_station(button
== ACTION_STD_PREV
? -1 : 1);
671 update_screen
= true;
675 case ACTION_STD_PREVREPEAT
:
676 case ACTION_STD_NEXTREPEAT
:
678 int dir
= search_dir
;
679 search_dir
= button
== ACTION_STD_PREVREPEAT
? -1 : 1;
680 if (radio_mode
!= RADIO_SCAN_MODE
)
682 next_preset(search_dir
);
684 update_screen
= true;
689 /* Starting auto scan */
690 tuner_set(RADIO_MUTE
, 1);
691 update_screen
= true;
696 case ACTION_SETTINGS_INC
:
697 case ACTION_SETTINGS_INCREPEAT
:
698 global_settings
.volume
++;
700 update_screen
= true;
703 case ACTION_SETTINGS_DEC
:
704 case ACTION_SETTINGS_DECREPEAT
:
705 global_settings
.volume
--;
707 update_screen
= true;
711 if (radio_status
== FMRADIO_PLAYING
)
716 update_screen
= true;
723 curr_preset
= find_preset(curr_freq
);
726 screens
[i
].set_viewport(&vp
[i
]);
727 screens
[i
].clear_viewport();
728 screens
[i
].update_viewport();
729 screens
[i
].set_viewport(NULL
);
731 #ifdef HAVE_BUTTONBAR
732 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
734 str(LANG_FM_BUTTONBAR_RECORD
));
736 update_screen
= true;
740 case ACTION_FM_PRESET
:
743 gui_syncsplash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
744 update_screen
= true;
747 screens
[i
].set_viewport(&vp
[i
]);
748 screens
[i
].clear_viewport();
749 screens
[i
].update_viewport();
750 screens
[i
].set_viewport(NULL
);
755 handle_radio_presets();
758 screens
[i
].set_viewport(&vp
[i
]);
759 screens
[i
].clear_viewport();
760 screens
[i
].update_viewport();
761 screens
[i
].set_viewport(NULL
);
763 #ifdef HAVE_BUTTONBAR
764 gui_buttonbar_set(&buttonbar
,
765 str(LANG_BUTTONBAR_MENU
),
767 str(LANG_FM_BUTTONBAR_RECORD
));
769 update_screen
= true;
771 #endif /* FM_PRESET */
774 case ACTION_FM_FREEZE
:
777 gui_syncsplash(HZ
, str(LANG_FM_FREEZE
));
778 screen_freeze
= true;
782 update_screen
= true;
783 screen_freeze
= false;
786 #endif /* FM_FREEZE */
788 case SYS_USB_CONNECTED
:
789 #if CONFIG_CODEC != SWCODEC
790 /* Only accept USB connection when not recording */
791 if(audio_status() != AUDIO_STATUS_RECORD
)
794 default_event_handler(SYS_USB_CONNECTED
);
795 screen_freeze
= true; /* Cosmetic: makes sure the
796 radio screen doesn't redraw */
803 if(radio_mode
== RADIO_SCAN_MODE
)
805 /* Force scan mode if there are no presets. */
807 radio_mode
= RADIO_PRESET_MODE
;
810 radio_mode
= RADIO_SCAN_MODE
;
811 update_screen
= true;
812 cond_talk_ids_fq(radio_mode
?
813 LANG_PRESET
: LANG_RADIO_SCAN_MODE
);
818 #ifdef FM_NEXT_PRESET
819 case ACTION_FM_NEXT_PRESET
:
822 update_screen
= true;
827 #ifdef FM_PREV_PRESET
828 case ACTION_FM_PREV_PRESET
:
831 update_screen
= true;
837 default_event_handler(button
);
841 #ifdef FM_RECORD_DBLPRE
842 if (button
!= ACTION_NONE
)
846 #if CONFIG_CODEC != SWCODEC
852 /* Only display the peak meter when not recording */
853 #if CONFIG_CODEC != SWCODEC
858 screens
[i
].set_viewport(&vp
[i
]);
859 peak_meter_screen(&screens
[i
],0,
860 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4), fh
);
861 screens
[i
].update_rect(0, STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
862 screens
[i
].width
, fh
);
863 screens
[i
].set_viewport(NULL
);
867 if(TIME_AFTER(current_tick
, timeout
))
869 timeout
= current_tick
+ HZ
;
872 #endif /* CONFIG_CODEC == SWCODEC */
874 /* keep "mono" from always being displayed when paused */
875 if (radio_status
!= FMRADIO_PAUSED
)
877 stereo
= tuner_get(RADIO_STEREO
) &&
878 !global_settings
.fm_force_mono
;
880 if(stereo
!= last_stereo
)
882 update_screen
= true;
883 last_stereo
= stereo
;
888 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
889 seconds
= audio_recorded_time() / HZ
;
890 if (update_screen
|| seconds
> last_seconds
)
892 last_seconds
= seconds
;
901 screens
[i
].set_viewport(&vp
[i
]);
904 snprintf(buf
, 128, curr_preset
>= 0 ? "%d. %s" : " ",
905 curr_preset
+ 1, presets
[curr_preset
].name
);
908 screens
[i
].puts_scroll(0, top_of_screen
, buf
);
910 freq
= curr_freq
/ 10000;
911 snprintf(buf
, 128, str(LANG_FM_STATION
), freq
/ 100, freq
% 100);
913 screens
[i
].puts_scroll(0, top_of_screen
+ 1, buf
);
915 snprintf(buf
, 128, stereo
?str(LANG_CHANNEL_STEREO
):
916 str(LANG_CHANNEL_MONO
));
918 screens
[i
].puts_scroll(0, top_of_screen
+ 2, buf
);
920 snprintf(buf
, 128, "%s %s", str(LANG_MODE
),
921 radio_mode
? str(LANG_PRESET
) :
922 str(LANG_RADIO_SCAN_MODE
));
924 screens
[i
].puts_scroll(0, top_of_screen
+ 3, buf
);
926 #if CONFIG_CODEC != SWCODEC
927 if(audio_status() == AUDIO_STATUS_RECORD
)
929 hours
= seconds
/ 3600;
930 minutes
= (seconds
- (hours
* 3600)) / 60;
931 snprintf(buf
, 32, "%s %02d:%02d:%02d",
932 str(LANG_RECORDING_TIME
),
933 hours
, minutes
, seconds
%60);
935 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
939 if(rec_options
.rec_prerecord_time
)
941 snprintf(buf
, 32, "%s %02d",
942 str(LANG_RECORD_PRERECORD
), seconds
%60);
944 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
947 #endif /* CONFIG_CODEC != SWCODEC */
951 screens
[i
].update_viewport();
952 screens
[i
].set_viewport(NULL
);
955 #ifdef HAVE_BUTTONBAR
956 gui_buttonbar_draw(&buttonbar
);
959 /* Only force the redraw if update_screen is true */
960 gui_syncstatusbar_draw(&statusbars
,true);
963 update_screen
= false;
965 if (global_settings
.talk_file
&& talk
966 && radio_status
== FMRADIO_PAUSED
)
969 bool enqueue
= false;
970 if (radio_mode
== RADIO_SCAN_MODE
)
972 talk_freq(curr_freq
, enqueue
);
975 if (curr_preset
>= 0)
976 talk_preset(curr_preset
, radio_mode
== RADIO_PRESET_MODE
,
980 #if CONFIG_CODEC != SWCODEC
981 if(audio_status() & AUDIO_STATUS_ERROR
)
987 #ifndef HAVE_NOISY_IDLE_MODE
988 if (TIME_AFTER(current_tick
, button_timeout
))
996 #if CONFIG_CODEC != SWCODEC
997 if(audio_status() & AUDIO_STATUS_ERROR
)
999 gui_syncsplash(0, str(LANG_DISK_FULL
));
1000 gui_syncstatusbar_draw(&statusbars
,true);
1003 screens
[i
].set_viewport(&vp
[i
]);
1004 screens
[i
].update_viewport();
1005 screens
[i
].set_viewport(NULL
);
1007 audio_error_clear();
1011 button
= get_action(CONTEXT_FM
, TIMEOUT_BLOCK
);
1012 if(button
== ACTION_FM_STOP
)
1017 audio_init_playback();
1018 #endif /* CONFIG_CODEC != SWCODEC */
1020 sound_settings_apply();
1021 #endif /* SIMULATOR */
1025 /* Catch FMRADIO_PLAYING status for the sim. */
1027 #if CONFIG_CODEC != SWCODEC
1028 /* Enable the Left and right A/D Converter */
1029 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
1030 sound_default(SOUND_RIGHT_GAIN
),
1032 mas_codec_writereg(6, 0x4000);
1035 #endif /* SIMULATOR */
1039 #if CONFIG_CODEC == SWCODEC
1040 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
1046 #ifndef HAVE_NOISY_IDLE_MODE
1047 cpu_idle_mode(false);
1050 /* restore status bar settings */
1051 global_settings
.statusbar
= statusbar
;
1052 global_status
.statusbar_forced
= 0;
1054 #if CONFIG_CODEC != SWCODEC
1055 return have_recorded
;
1059 } /* radio_screen */
1061 static void radio_save_presets(void)
1066 fd
= creat(filepreset
);
1069 for(i
= 0;i
< num_presets
;i
++)
1071 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
1075 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
1076 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
1077 presets_changed
= false;
1081 gui_syncsplash(HZ
, ID2P(LANG_FM_PRESET_SAVE_FAILED
));
1085 void radio_load_presets(char *filename
)
1095 memset(presets
, 0, sizeof(presets
));
1098 /* No Preset in configuration. */
1099 if(filename
[0] == '\0')
1101 filepreset
[0] = '\0';
1104 /* Temporary preset, loaded until player shuts down. */
1105 else if(filename
[0] == '/')
1106 strncpy(filepreset
, filename
, sizeof(filepreset
));
1107 /* Preset from default directory. */
1109 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
1110 FMPRESET_PATH
, filename
);
1112 fd
= open(filepreset
, O_RDONLY
);
1115 while(!done
&& num_presets
< MAX_PRESETS
)
1117 rc
= read_line(fd
, buf
, 128);
1120 if(settings_parseline(buf
, &freq
, &name
))
1123 if(f
) /* For backwards compatibility */
1125 struct fmstation
* const fms
= &presets
[num_presets
];
1127 strncpy(fms
->name
, name
, MAX_FMPRESET_LEN
);
1128 fms
->name
[MAX_FMPRESET_LEN
] = '\0';
1138 else /* invalid file name? */
1139 filepreset
[0] = '\0';
1141 presets_loaded
= num_presets
> 0;
1142 presets_changed
= false;
1146 static int radio_add_preset(void)
1148 char buf
[MAX_FMPRESET_LEN
+ 1];
1150 if(num_presets
< MAX_PRESETS
)
1152 memset(buf
, 0, MAX_FMPRESET_LEN
);
1154 if (!kbd_input(buf
, MAX_FMPRESET_LEN
))
1156 struct fmstation
* const fms
= &presets
[num_presets
];
1157 buf
[MAX_FMPRESET_LEN
] = '\0';
1158 strcpy(fms
->name
, buf
);
1159 fms
->frequency
= curr_freq
;
1161 presets_changed
= true;
1162 presets_loaded
= num_presets
> 0;
1167 gui_syncsplash(HZ
, ID2P(LANG_FM_NO_FREE_PRESETS
));
1172 /* needed to know which preset we are edit/delete-ing */
1173 static int selected_preset
= -1;
1174 static int radio_edit_preset(void)
1176 char buf
[MAX_FMPRESET_LEN
+ 1];
1178 if (num_presets
> 0)
1180 struct fmstation
* const fms
= &presets
[selected_preset
];
1182 strncpy(buf
, fms
->name
, MAX_FMPRESET_LEN
);
1184 if (!kbd_input(buf
, MAX_FMPRESET_LEN
))
1186 buf
[MAX_FMPRESET_LEN
] = '\0';
1187 strcpy(fms
->name
, buf
);
1188 presets_changed
= true;
1195 static int radio_delete_preset(void)
1197 if (num_presets
> 0)
1199 struct fmstation
* const fms
= &presets
[selected_preset
];
1201 if (selected_preset
>= --num_presets
)
1202 selected_preset
= num_presets
- 1;
1204 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
1209 /* Don't ask to save when all presets are deleted. */
1210 presets_changed
= num_presets
> 0;
1212 if (!presets_changed
)
1214 /* The preset list will be cleared, switch to Scan Mode. */
1215 radio_mode
= RADIO_SCAN_MODE
;
1216 presets_loaded
= false;
1222 static int load_preset_list(void)
1224 return !rockbox_browse(FMPRESET_PATH
, SHOW_FMR
);
1227 static int save_preset_list(void)
1231 bool bad_file_name
= true;
1233 if(!dir_exists(FMPRESET_PATH
)) /* Check if there is preset folder */
1234 mkdir(FMPRESET_PATH
);
1236 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
1237 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
1239 while(bad_file_name
)
1241 if(!kbd_input(filepreset
, sizeof(filepreset
)))
1243 /* check the name: max MAX_FILENAME (20) chars */
1247 p1
= strrchr(filepreset
, '/');
1249 while((p1
) && (*p2
) && (*p2
!= '.'))
1251 len
= (int)(p2
-p1
) - 1;
1252 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
1254 /* no slash, too long or too short */
1255 gui_syncsplash(HZ
, ID2P(LANG_INVALID_FILENAME
));
1259 /* add correct extension (easier to always write)
1260 at this point, p2 points to 0 or the extension dot */
1262 strcat(filepreset
,".fmr");
1263 bad_file_name
= false;
1264 radio_save_presets();
1275 gui_syncsplash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
1280 static int clear_preset_list(void)
1282 /* Clear all the preset entries */
1283 memset(presets
, 0, sizeof (presets
));
1286 presets_loaded
= false;
1287 /* The preset list will be cleared switch to Scan Mode. */
1288 radio_mode
= RADIO_SCAN_MODE
;
1290 presets_changed
= false; /* Don't ask to save when clearing the list. */
1295 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1296 ID2P(LANG_FM_EDIT_PRESET
),
1297 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
1298 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1299 ID2P(LANG_FM_DELETE_PRESET
),
1300 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
1301 static int radio_preset_callback(int action
,
1302 const struct menu_item_ex
*this_item
)
1304 if (action
== ACTION_STD_OK
)
1305 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
1309 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_PRESET
),
1310 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
1311 &radio_delete_preset_item
);
1312 /* present a list of preset stations */
1313 static char * presets_get_name(int selected_item
, void *data
,
1314 char *buffer
, size_t buffer_len
)
1317 struct fmstation
*p
= &presets
[selected_item
];
1320 int freq
= p
->frequency
/ 10000;
1321 int frac
= freq
% 100;
1323 snprintf(buffer
, buffer_len
,
1324 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
1328 static int presets_speak_name(int selected_item
, void * data
)
1331 talk_preset(selected_item
, true, false);
1335 static int handle_radio_presets(void)
1337 struct gui_synclist lists
;
1339 int action
= ACTION_NONE
;
1340 #ifdef HAVE_BUTTONBAR
1341 struct gui_buttonbar buttonbar
;
1344 if(presets_loaded
== false)
1347 #ifdef HAVE_BUTTONBAR
1348 gui_buttonbar_init(&buttonbar
);
1349 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
1350 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
1351 str(LANG_FM_BUTTONBAR_EXIT
),
1352 str(LANG_FM_BUTTONBAR_ACTION
));
1353 gui_buttonbar_draw(&buttonbar
);
1355 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1, NULL
);
1356 gui_synclist_set_title(&lists
, str(LANG_PRESET
), NOICON
);
1357 gui_synclist_set_icon_callback(&lists
, NULL
);
1358 if(global_settings
.talk_file
)
1359 gui_synclist_set_voice_callback(&lists
, presets_speak_name
);
1360 gui_synclist_set_nb_items(&lists
, num_presets
);
1361 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
1362 gui_synclist_speak_item(&lists
);
1366 gui_synclist_draw(&lists
);
1367 gui_syncstatusbar_draw(&statusbars
, true);
1368 list_do_action(CONTEXT_STD
, HZ
,
1369 &lists
, &action
, LIST_WRAP_UNLESS_HELD
);
1372 case ACTION_STD_MENU
:
1375 case ACTION_STD_CANCEL
:
1379 curr_preset
= gui_synclist_get_sel_pos(&lists
);
1380 curr_freq
= presets
[curr_preset
].frequency
;
1382 remember_frequency();
1386 case ACTION_STD_CONTEXT
:
1387 selected_preset
= gui_synclist_get_sel_pos(&lists
);
1388 do_menu(&handle_radio_preset_menu
, NULL
, NULL
, false);
1389 gui_synclist_speak_item(&lists
);
1392 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
1399 void toggle_mono_mode(bool mono
)
1401 tuner_set(RADIO_FORCE_MONO
, mono
);
1404 void set_radio_region(int region
)
1406 #ifdef HAVE_RADIO_REGION
1407 tuner_set(RADIO_REGION
, region
);
1410 remember_frequency();
1414 MENUITEM_SETTING(set_region
, &global_settings
.fm_region
, NULL
);
1415 MENUITEM_SETTING(force_mono
, &global_settings
.fm_force_mono
, NULL
);
1418 static char* get_mode_text(int selected_item
, void * data
, char *buffer
)
1420 (void)selected_item
;
1422 snprintf(buffer
, MAX_PATH
, "%s %s", str(LANG_MODE
),
1423 radio_mode
? str(LANG_PRESET
) :
1424 str(LANG_RADIO_SCAN_MODE
));
1427 static int toggle_radio_mode(void)
1429 radio_mode
= (radio_mode
== RADIO_SCAN_MODE
) ?
1430 RADIO_PRESET_MODE
: RADIO_SCAN_MODE
;
1433 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item
, 0,
1434 toggle_radio_mode
, NULL
,
1435 get_mode_text
, NULL
, NULL
, NULL
, Icon_NOICON
);
1438 static int scan_presets(void *viewports
)
1440 bool do_scan
= true;
1442 struct viewport
*vp
= (struct viewport
*)viewports
;
1445 screens
[i
].set_viewport(vp
?&vp
[i
]:NULL
);
1446 if(num_presets
> 0) /* Do that to avoid 2 questions. */
1447 do_scan
= yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS
));
1451 const struct fm_region_data
* const fmr
=
1452 &fm_region_data
[global_settings
.fm_region
];
1454 char buf
[MAX_FMPRESET_LEN
+ 1];
1456 curr_freq
= fmr
->freq_min
;
1458 memset(presets
, 0, sizeof(presets
));
1459 tuner_set(RADIO_MUTE
, 1);
1461 while(curr_freq
<= fmr
->freq_max
)
1464 if (num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
1467 freq
= curr_freq
/ 10000;
1471 snprintf(buf
, MAX_FMPRESET_LEN
, str(LANG_FM_SCANNING
), freq
, frac
);
1472 gui_syncsplash(0, buf
);
1474 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
1477 presets
[num_presets
].name
[0] = '\0';
1478 presets
[num_presets
].frequency
= curr_freq
;
1482 curr_freq
+= fmr
->freq_step
;
1485 if (radio_status
== FMRADIO_PLAYING
)
1486 tuner_set(RADIO_MUTE
, 0);
1488 presets_changed
= true;
1492 screens
[i
].clear_viewport();
1493 screens
[i
].update_viewport();
1498 curr_freq
= presets
[0].frequency
;
1499 radio_mode
= RADIO_PRESET_MODE
;
1500 presets_loaded
= true;
1505 /* Wrap it to beginning or we'll be past end of band */
1506 presets_loaded
= false;
1514 #ifdef HAVE_RECORDING
1516 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1517 #define FM_RECORDING_SCREEN
1518 static int fm_recording_screen(void)
1522 /* switch recording source to FMRADIO for the duration */
1523 int rec_source
= global_settings
.rec_source
;
1524 global_settings
.rec_source
= AUDIO_SRC_FMRADIO
;
1526 ret
= recording_screen(true);
1528 /* safe to reset as changing sources is prohibited here */
1529 global_settings
.rec_source
= rec_source
;
1534 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1536 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1537 #define FM_RECORDING_SETTINGS
1538 static int fm_recording_settings(void)
1540 bool ret
= recording_menu(true);
1542 #if CONFIG_CODEC != SWCODEC
1545 struct audio_recording_options rec_options
;
1546 rec_init_recording_options(&rec_options
);
1547 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
1548 rec_set_recording_options(&rec_options
);
1555 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1556 #endif /* HAVE_RECORDING */
1558 #ifdef FM_RECORDING_SCREEN
1559 MENUITEM_FUNCTION(recscreen_item
, 0, ID2P(LANG_RECORDING
),
1560 fm_recording_screen
, NULL
, NULL
, Icon_Recording
);
1562 #ifdef FM_RECORDING_SETTINGS
1563 MENUITEM_FUNCTION(recsettings_item
, 0, ID2P(LANG_RECORDING_SETTINGS
),
1564 fm_recording_settings
, NULL
, NULL
, Icon_Recording
);
1567 MENUITEM_FUNCTION(radio_presets_item
, 0, ID2P(LANG_PRESET
),
1568 handle_radio_presets
, NULL
, NULL
, Icon_NOICON
);
1570 #ifndef FM_PRESET_ADD
1571 MENUITEM_FUNCTION(radio_addpreset_item
, 0, ID2P(LANG_FM_ADD_PRESET
),
1572 radio_add_preset
, NULL
, NULL
, Icon_NOICON
);
1576 MENUITEM_FUNCTION(presetload_item
, 0, ID2P(LANG_FM_PRESET_LOAD
),
1577 load_preset_list
, NULL
, NULL
, Icon_NOICON
);
1578 MENUITEM_FUNCTION(presetsave_item
, 0, ID2P(LANG_FM_PRESET_SAVE
),
1579 save_preset_list
, NULL
, NULL
, Icon_NOICON
);
1580 MENUITEM_FUNCTION(presetclear_item
, 0, ID2P(LANG_FM_PRESET_CLEAR
),
1581 clear_preset_list
, NULL
, NULL
, Icon_NOICON
);
1582 MENUITEM_FUNCTION(scan_presets_item
, MENU_FUNC_USEPARAM
,
1583 ID2P(LANG_FM_SCAN_PRESETS
),
1584 scan_presets
, NULL
, NULL
, Icon_NOICON
);
1586 MAKE_MENU(radio_settings_menu
, ID2P(LANG_FM_MENU
), NULL
,
1589 &radio_presets_item
,
1591 #ifndef FM_PRESET_ADD
1592 &radio_addpreset_item
,
1594 &presetload_item
, &presetsave_item
, &presetclear_item
,
1599 &set_region
, &sound_settings
,
1600 #ifdef FM_RECORDING_SCREEN
1603 #ifdef FM_RECORDING_SETTINGS
1606 &scan_presets_item
);
1607 /* main menu of the radio screen */
1608 static bool radio_menu(void)
1610 return do_menu(&radio_settings_menu
, NULL
, NULL
, false) == MENU_ATTACHED_USB
;