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"
46 #include "peakmeter.h"
49 #include "sound_menu.h"
51 #include "recording.h"
57 #include "screen_access.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)
108 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
112 #elif (CONFIG_KEYPAD == COWOND2_PAD)
121 #define RADIO_SCAN_MODE 0
122 #define RADIO_PRESET_MODE 1
124 static int curr_preset
= -1;
125 static int curr_freq
; /* current frequency in Hz */
126 static int radio_mode
= RADIO_SCAN_MODE
;
127 static int search_dir
= 0;
129 static int radio_status
= FMRADIO_OFF
;
130 static bool in_screen
= false;
132 #define MAX_PRESETS 64
133 static bool presets_loaded
= false, presets_changed
= false;
134 static struct fmstation presets
[MAX_PRESETS
];
136 static char filepreset
[MAX_PATH
]; /* preset filename variable */
138 static int num_presets
= 0; /* The number of presets in the preset list */
140 static void radio_save_presets(void);
141 static int handle_radio_presets(void);
142 static bool radio_menu(void);
143 static int radio_add_preset(void);
144 static int save_preset_list(void);
145 static int load_preset_list(void);
146 static int clear_preset_list(void);
148 static int scan_presets(void *viewports
);
150 /* Function to manipulate all yesno dialogues.
151 This function needs the output text as an argument. */
152 static bool yesno_pop(const char* text
)
155 const char *lines
[]={text
};
156 const struct text_message message
={lines
, 1};
157 bool ret
= (gui_syncyesno_run(&message
,NULL
,NULL
)== YESNO_YES
);
159 screens
[i
].clear_viewport();
163 void radio_init(void)
169 int get_radio_status(void)
174 bool in_radio_screen(void)
179 /* TODO: Move some more of the control functionality to firmware
180 and clean up the mess */
182 /* secret flag for starting paused - prevents unmute */
183 #define FMRADIO_START_PAUSED 0x8000
184 void radio_start(void)
186 const struct fm_region_data
*fmr
;
189 if(radio_status
== FMRADIO_PLAYING
)
192 fmr
= &fm_region_data
[global_settings
.fm_region
];
194 start_paused
= radio_status
& FMRADIO_START_PAUSED
;
195 /* clear flag before any yielding */
196 radio_status
&= ~FMRADIO_START_PAUSED
;
198 if(radio_status
== FMRADIO_OFF
)
201 curr_freq
= global_status
.last_frequency
* fmr
->freq_step
+ fmr
->freq_min
;
203 tuner_set(RADIO_SLEEP
, 0); /* wake up the tuner */
205 if(radio_status
== FMRADIO_OFF
)
207 #ifdef HAVE_RADIO_REGION
208 tuner_set(RADIO_REGION
, global_settings
.fm_region
);
210 tuner_set(RADIO_FORCE_MONO
, global_settings
.fm_force_mono
);
213 tuner_set(RADIO_FREQUENCY
, curr_freq
);
215 #ifdef HAVE_RADIO_MUTE_TIMEOUT
217 unsigned long mute_timeout
= current_tick
+ HZ
;
218 if (radio_status
!= FMRADIO_OFF
)
224 while(!tuner_get(RADIO_STEREO
) && !tuner_get(RADIO_TUNED
))
226 if(TIME_AFTER(current_tick
, mute_timeout
))
233 /* keep radio from sounding initially */
235 tuner_set(RADIO_MUTE
, 0);
237 radio_status
= FMRADIO_PLAYING
;
240 void radio_pause(void)
242 if(radio_status
== FMRADIO_PAUSED
)
245 if(radio_status
== FMRADIO_OFF
)
247 radio_status
|= FMRADIO_START_PAUSED
;
251 tuner_set(RADIO_MUTE
, 1);
252 tuner_set(RADIO_SLEEP
, 1);
254 radio_status
= FMRADIO_PAUSED
;
257 void radio_stop(void)
259 if(radio_status
== FMRADIO_OFF
)
262 tuner_set(RADIO_MUTE
, 1);
263 tuner_set(RADIO_SLEEP
, 1); /* low power mode, if available */
264 radio_status
= FMRADIO_OFF
;
265 tuner_power(false); /* status update, power off if avail. */
268 bool radio_hardware_present(void)
270 return tuner_get(RADIO_PRESENT
);
273 /* Keep freq on the grid for the current region */
274 static int snap_freq_to_grid(int freq
)
276 const struct fm_region_data
* const fmr
=
277 &fm_region_data
[global_settings
.fm_region
];
279 /* Range clamp if out of range or just round to nearest */
280 if (freq
< fmr
->freq_min
)
281 freq
= fmr
->freq_min
;
282 else if (freq
> fmr
->freq_max
)
283 freq
= fmr
->freq_max
;
285 freq
= (freq
- fmr
->freq_min
+ fmr
->freq_step
/2) /
286 fmr
->freq_step
* fmr
->freq_step
+ fmr
->freq_min
;
291 /* Find a matching preset to freq */
292 static int find_preset(int freq
)
297 for(i
= 0;i
< MAX_PRESETS
;i
++)
299 if(freq
== presets
[i
].frequency
)
306 /* Return the closest preset encountered in the search direction with
308 static int find_closest_preset(int freq
, int direction
)
315 if (direction
== 0) /* direction == 0 isn't really used */
318 for (i
= 0; i
< num_presets
; i
++)
320 int f
= presets
[i
].frequency
;
322 return i
; /* Exact match = stop */
324 /* remember the highest and lowest presets for wraparound */
325 if (f
< presets
[lowpreset
].frequency
)
327 if (f
> presets
[highpreset
].frequency
)
330 /* find the closest preset in the given direction */
331 if (direction
> 0 && f
> freq
)
333 if (closest
< 0 || f
< presets
[closest
].frequency
)
336 else if (direction
< 0 && f
< freq
)
338 if (closest
< 0 || f
> presets
[closest
].frequency
)
345 /* no presets in the given direction */
346 /* wrap around depending on direction */
348 closest
= highpreset
;
356 static void remember_frequency(void)
358 const struct fm_region_data
* const fmr
=
359 &fm_region_data
[global_settings
.fm_region
];
360 global_status
.last_frequency
= (curr_freq
- fmr
->freq_min
)
365 static void next_preset(int direction
)
370 if (curr_preset
== -1)
371 curr_preset
= find_closest_preset(curr_freq
, direction
);
373 curr_preset
= (curr_preset
+ direction
+ num_presets
) % num_presets
;
375 /* Must stay on the current grid for the region */
376 curr_freq
= snap_freq_to_grid(presets
[curr_preset
].frequency
);
378 tuner_set(RADIO_FREQUENCY
, curr_freq
);
379 remember_frequency();
382 /* Step to the next or previous frequency */
383 static int step_freq(int freq
, int direction
)
385 const struct fm_region_data
* const fmr
=
386 &fm_region_data
[global_settings
.fm_region
];
388 freq
+= direction
*fmr
->freq_step
;
390 /* Wrap first or snapping to grid will not let us on the band extremes */
391 if (freq
> fmr
->freq_max
)
392 freq
= direction
> 0 ? fmr
->freq_min
: fmr
->freq_max
;
393 else if (freq
< fmr
->freq_min
)
394 freq
= direction
< 0 ? fmr
->freq_max
: fmr
->freq_min
;
396 freq
= snap_freq_to_grid(freq
);
401 /* Step to the next or previous station */
402 static void next_station(int direction
)
404 if (direction
!= 0 && radio_mode
!= RADIO_SCAN_MODE
)
406 next_preset(direction
);
410 curr_freq
= step_freq(curr_freq
, direction
);
412 if (radio_status
== FMRADIO_PLAYING
)
413 tuner_set(RADIO_MUTE
, 1);
415 tuner_set(RADIO_FREQUENCY
, curr_freq
);
417 if (radio_status
== FMRADIO_PLAYING
)
418 tuner_set(RADIO_MUTE
, 0);
420 curr_preset
= find_preset(curr_freq
);
421 remember_frequency();
424 /* Ends an in-progress search */
425 static void end_search(void)
427 if (search_dir
!= 0 && radio_status
== FMRADIO_PLAYING
)
428 tuner_set(RADIO_MUTE
, 0);
432 /* Speak a frequency. */
433 static void talk_freq(int freq
, bool enqueue
)
436 talk_number(freq
/ 100, enqueue
);
437 talk_id(LANG_POINT
, true);
438 talk_number(freq
% 100 / 10, true);
440 talk_number(freq
% 10, true);
443 /* Speak a preset by number or by spelling its name, depending on settings. */
444 static void talk_preset(int preset
, bool fallback
, bool enqueue
)
446 if (global_settings
.talk_file
== 1) /* number */
447 talk_number(preset
+ 1, enqueue
);
450 if(presets
[preset
].name
[0])
451 talk_spell(presets
[preset
].name
, enqueue
);
453 talk_freq(presets
[preset
].frequency
, enqueue
);
457 int radio_screen(void)
461 int ret_val
= GO_TO_ROOT
;
464 bool stereo
= false, last_stereo
= false;
466 int top_of_screen
= 0;
467 bool update_screen
= true;
468 bool screen_freeze
= false;
469 bool keep_playing
= false;
471 #ifdef FM_RECORD_DBLPRE
472 int lastbutton
= BUTTON_NONE
;
473 unsigned long rec_lastclick
= 0;
475 #if CONFIG_CODEC != SWCODEC
476 bool have_recorded
= false;
477 int timeout
= current_tick
+ HZ
/10;
478 unsigned int seconds
= 0;
479 unsigned int last_seconds
= 0;
481 struct audio_recording_options rec_options
;
482 #endif /* CONFIG_CODEC != SWCODEC */
483 #ifndef HAVE_NOISY_IDLE_MODE
484 int button_timeout
= current_tick
+ (2*HZ
);
486 struct viewport vp
[NB_SCREENS
];
487 int oldbars
= 0, fmbars
= VP_SB_ALLSCREENS
;
488 #ifdef HAVE_BUTTONBAR
489 struct gui_buttonbar buttonbar
;
490 gui_buttonbar_init(&buttonbar
);
491 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
494 /* change status to "in screen" */
497 /* always display status bar in radio screen for now */
499 fmbars
|= VP_SB_IGNORE_SETTING(i
);
500 oldbars
= viewportmanager_set_statusbar(fmbars
);
503 viewport_set_defaults(&vp
[i
], i
);
504 #ifdef HAVE_BUTTONBAR
505 if (global_settings
.buttonbar
)
506 vp
[i
].height
-= BUTTONBAR_HEIGHT
;
508 screens
[i
].set_viewport(&vp
[i
]);
509 screens
[i
].stop_scroll();
510 screens
[i
].clear_viewport();
511 screens
[i
].update_viewport();
514 fh
= font_get(FONT_UI
)->height
;
516 /* Adjust for font size, trying to center the information vertically */
522 radio_load_presets(global_settings
.fmr_file
);
525 if(radio_status
== FMRADIO_OFF
)
529 #if CONFIG_CODEC != SWCODEC
530 if(rec_create_directory() > 0)
531 have_recorded
= true;
533 audio_init_recording(talk_get_bufsize());
535 sound_settings_apply();
536 /* Yes, we use the D/A for monitoring */
537 peak_meter_playback(true);
539 peak_meter_enabled
= true;
541 rec_init_recording_options(&rec_options
);
542 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
543 rec_set_recording_options(&rec_options
);
545 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
546 sound_default(SOUND_RIGHT_GAIN
), AUDIO_GAIN_LINEIN
);
548 #endif /* CONFIG_CODEC != SWCODEC */
549 #endif /* ndef SIMULATOR */
552 #if CONFIG_CODEC == SWCODEC
553 audio_set_input_source(AUDIO_SRC_FMRADIO
,
554 (radio_status
== FMRADIO_PAUSED
) ?
555 SRCF_FMRADIO_PAUSED
: SRCF_FMRADIO_PLAYING
);
557 if (radio_status
== FMRADIO_OFF
)
561 if(num_presets
< 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN
)))
564 curr_preset
= find_preset(curr_freq
);
565 if(curr_preset
!= -1)
566 radio_mode
= RADIO_PRESET_MODE
;
568 #ifdef HAVE_BUTTONBAR
569 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
570 str(LANG_PRESET
), str(LANG_FM_BUTTONBAR_RECORD
));
573 #ifndef HAVE_NOISY_IDLE_MODE
581 curr_freq
= step_freq(curr_freq
, search_dir
);
582 update_screen
= true;
584 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
586 curr_preset
= find_preset(curr_freq
);
587 remember_frequency();
600 #if CONFIG_CODEC != SWCODEC
601 /* TODO: Can we timeout at HZ when recording since peaks aren't
602 displayed? This should quiet recordings too. */
603 button
= get_action(CONTEXT_FM
,
604 update_screen
? TIMEOUT_NOBLOCK
: HZ
/ PEAK_METER_FPS
);
606 button
= get_action(CONTEXT_FM
,
607 update_screen
? TIMEOUT_NOBLOCK
: HZ
);
610 #ifndef HAVE_NOISY_IDLE_MODE
611 if (button
!= ACTION_NONE
)
613 cpu_idle_mode(false);
614 button_timeout
= current_tick
+ (2*HZ
);
620 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
621 if(audio_status() == AUDIO_STATUS_RECORD
)
631 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
633 if(filepreset
[0] == '\0')
636 radio_save_presets();
639 /* Clear the preset list on exit. */
642 update_screen
= true;
646 case ACTION_FM_RECORD
:
647 #ifdef FM_RECORD_DBLPRE
648 if (lastbutton
!= ACTION_FM_RECORD_DBLPRE
)
653 if (current_tick
- rec_lastclick
> HZ
/2)
655 rec_lastclick
= current_tick
;
658 #endif /* FM_RECORD_DBLPRE */
660 if(audio_status() == AUDIO_STATUS_RECORD
)
662 rec_command(RECORDING_CMD_START_NEWFILE
);
663 update_screen
= true;
667 have_recorded
= true;
668 rec_command(RECORDING_CMD_START
);
669 update_screen
= true;
671 #endif /* SIMULATOR */
674 #endif /* #ifdef FM_RECORD */
677 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
678 if(audio_status() == AUDIO_STATUS_RECORD
)
683 ret_val
= GO_TO_ROOT
;
686 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
688 if(filepreset
[0] == '\0')
691 radio_save_presets();
695 /* Clear the preset list on exit. */
700 case ACTION_STD_PREV
:
701 case ACTION_STD_NEXT
:
702 next_station(button
== ACTION_STD_PREV
? -1 : 1);
704 update_screen
= true;
708 case ACTION_STD_PREVREPEAT
:
709 case ACTION_STD_NEXTREPEAT
:
711 int dir
= search_dir
;
712 search_dir
= button
== ACTION_STD_PREVREPEAT
? -1 : 1;
713 if (radio_mode
!= RADIO_SCAN_MODE
)
715 next_preset(search_dir
);
717 update_screen
= true;
722 /* Starting auto scan */
723 tuner_set(RADIO_MUTE
, 1);
724 update_screen
= true;
729 case ACTION_SETTINGS_INC
:
730 case ACTION_SETTINGS_INCREPEAT
:
731 global_settings
.volume
++;
733 update_screen
= true;
736 case ACTION_SETTINGS_DEC
:
737 case ACTION_SETTINGS_DECREPEAT
:
738 global_settings
.volume
--;
740 update_screen
= true;
744 if (radio_status
== FMRADIO_PLAYING
)
749 update_screen
= true;
755 viewportmanager_set_statusbar(oldbars
);
757 curr_preset
= find_preset(curr_freq
);
758 viewportmanager_set_statusbar(fmbars
);
761 screens
[i
].set_viewport(&vp
[i
]);
762 screens
[i
].clear_viewport();
763 screens
[i
].update_viewport();
764 screens
[i
].set_viewport(NULL
);
766 #ifdef HAVE_BUTTONBAR
767 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
769 str(LANG_FM_BUTTONBAR_RECORD
));
771 update_screen
= true;
775 case ACTION_FM_PRESET
:
778 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
779 update_screen
= true;
782 screens
[i
].set_viewport(&vp
[i
]);
783 screens
[i
].clear_viewport();
784 screens
[i
].update_viewport();
785 screens
[i
].set_viewport(NULL
);
790 viewportmanager_set_statusbar(oldbars
);
791 handle_radio_presets();
792 viewportmanager_set_statusbar(fmbars
);
795 screens
[i
].set_viewport(&vp
[i
]);
796 screens
[i
].stop_scroll();
797 screens
[i
].clear_viewport();
798 screens
[i
].update_viewport();
799 screens
[i
].set_viewport(NULL
);
801 #ifdef HAVE_BUTTONBAR
802 gui_buttonbar_set(&buttonbar
,
803 str(LANG_BUTTONBAR_MENU
),
805 str(LANG_FM_BUTTONBAR_RECORD
));
807 update_screen
= true;
809 #endif /* FM_PRESET */
812 case ACTION_FM_FREEZE
:
815 splash(HZ
, str(LANG_FM_FREEZE
));
816 screen_freeze
= true;
820 update_screen
= true;
821 screen_freeze
= false;
824 #endif /* FM_FREEZE */
826 case SYS_USB_CONNECTED
:
827 #if CONFIG_CODEC != SWCODEC
828 /* Only accept USB connection when not recording */
829 if(audio_status() != AUDIO_STATUS_RECORD
)
832 default_event_handler(SYS_USB_CONNECTED
);
833 screen_freeze
= true; /* Cosmetic: makes sure the
834 radio screen doesn't redraw */
841 if(radio_mode
== RADIO_SCAN_MODE
)
843 /* Force scan mode if there are no presets. */
845 radio_mode
= RADIO_PRESET_MODE
;
848 radio_mode
= RADIO_SCAN_MODE
;
849 update_screen
= true;
850 cond_talk_ids_fq(radio_mode
?
851 LANG_PRESET
: LANG_RADIO_SCAN_MODE
);
856 #ifdef FM_NEXT_PRESET
857 case ACTION_FM_NEXT_PRESET
:
860 update_screen
= true;
865 #ifdef FM_PREV_PRESET
866 case ACTION_FM_PREV_PRESET
:
869 update_screen
= true;
875 default_event_handler(button
);
879 #ifdef FM_RECORD_DBLPRE
880 if (button
!= ACTION_NONE
)
884 #if CONFIG_CODEC != SWCODEC
890 /* Only display the peak meter when not recording */
891 #if CONFIG_CODEC != SWCODEC
896 screens
[i
].set_viewport(&vp
[i
]);
897 peak_meter_screen(&screens
[i
],0,
898 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
900 screens
[i
].update_rect(0,
901 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
902 screens
[i
].getwidth(), fh
);
903 screens
[i
].set_viewport(NULL
);
907 if(TIME_AFTER(current_tick
, timeout
))
909 timeout
= current_tick
+ HZ
;
912 #endif /* CONFIG_CODEC == SWCODEC */
914 /* keep "mono" from always being displayed when paused */
915 if (radio_status
!= FMRADIO_PAUSED
)
917 stereo
= tuner_get(RADIO_STEREO
) &&
918 !global_settings
.fm_force_mono
;
920 if(stereo
!= last_stereo
)
922 update_screen
= true;
923 last_stereo
= stereo
;
928 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
929 seconds
= audio_recorded_time() / HZ
;
930 if (update_screen
|| seconds
> last_seconds
)
932 last_seconds
= seconds
;
941 screens
[i
].set_viewport(&vp
[i
]);
944 snprintf(buf
, 128, curr_preset
>= 0 ? "%d. %s" : " ",
945 curr_preset
+ 1, presets
[curr_preset
].name
);
948 screens
[i
].puts_scroll(0, top_of_screen
, buf
);
950 freq
= curr_freq
/ 10000;
951 snprintf(buf
, 128, str(LANG_FM_STATION
),
952 freq
/ 100, freq
% 100);
954 screens
[i
].puts_scroll(0, top_of_screen
+ 1, buf
);
956 snprintf(buf
, 128, "%s", stereo
?str(LANG_CHANNEL_STEREO
):
957 str(LANG_CHANNEL_MONO
));
959 screens
[i
].puts_scroll(0, top_of_screen
+ 2, buf
);
961 snprintf(buf
, 128, "%s %s", str(LANG_MODE
),
962 radio_mode
? str(LANG_PRESET
) :
963 str(LANG_RADIO_SCAN_MODE
));
965 screens
[i
].puts_scroll(0, top_of_screen
+ 3, buf
);
967 #if CONFIG_CODEC != SWCODEC
968 if(audio_status() == AUDIO_STATUS_RECORD
)
970 hours
= seconds
/ 3600;
971 minutes
= (seconds
- (hours
* 3600)) / 60;
972 snprintf(buf
, 32, "%s %02d:%02d:%02d",
973 str(LANG_RECORDING_TIME
),
974 hours
, minutes
, seconds
%60);
976 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
980 if(rec_options
.rec_prerecord_time
)
982 snprintf(buf
, 32, "%s %02d",
983 str(LANG_RECORD_PRERECORD
), seconds
%60);
985 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
988 #endif /* CONFIG_CODEC != SWCODEC */
992 screens
[i
].update_viewport();
993 screens
[i
].set_viewport(NULL
);
996 #ifdef HAVE_BUTTONBAR
997 gui_buttonbar_draw(&buttonbar
);
1002 update_screen
= false;
1004 if (global_settings
.talk_file
&& talk
1005 && radio_status
== FMRADIO_PAUSED
)
1008 bool enqueue
= false;
1009 if (radio_mode
== RADIO_SCAN_MODE
)
1011 talk_freq(curr_freq
, enqueue
);
1014 if (curr_preset
>= 0)
1015 talk_preset(curr_preset
, radio_mode
== RADIO_PRESET_MODE
,
1019 #if CONFIG_CODEC != SWCODEC
1020 if(audio_status() & AUDIO_STATUS_ERROR
)
1026 #ifndef HAVE_NOISY_IDLE_MODE
1027 if (TIME_AFTER(current_tick
, button_timeout
))
1029 cpu_idle_mode(true);
1035 #if CONFIG_CODEC != SWCODEC
1036 if(audio_status() & AUDIO_STATUS_ERROR
)
1038 splash(0, str(LANG_DISK_FULL
));
1041 screens
[i
].set_viewport(&vp
[i
]);
1042 screens
[i
].update_viewport();
1043 screens
[i
].set_viewport(NULL
);
1045 audio_error_clear();
1049 button
= get_action(CONTEXT_FM
, TIMEOUT_BLOCK
);
1050 if(button
== ACTION_FM_STOP
)
1055 audio_init_playback();
1056 #endif /* CONFIG_CODEC != SWCODEC */
1058 sound_settings_apply();
1059 #endif /* SIMULATOR */
1063 /* Catch FMRADIO_PLAYING status for the sim. */
1065 #if CONFIG_CODEC != SWCODEC
1066 /* Enable the Left and right A/D Converter */
1067 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
1068 sound_default(SOUND_RIGHT_GAIN
),
1070 mas_codec_writereg(6, 0x4000);
1073 #endif /* SIMULATOR */
1077 #if CONFIG_CODEC == SWCODEC
1078 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
1084 #ifndef HAVE_NOISY_IDLE_MODE
1085 cpu_idle_mode(false);
1088 viewportmanager_set_statusbar(oldbars
);
1090 #if CONFIG_CODEC != SWCODEC
1091 return have_recorded
;
1095 } /* radio_screen */
1097 static void radio_save_presets(void)
1102 fd
= creat(filepreset
);
1105 for(i
= 0;i
< num_presets
;i
++)
1107 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
1111 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
1112 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
1113 presets_changed
= false;
1117 splash(HZ
, ID2P(LANG_FM_PRESET_SAVE_FAILED
));
1121 void radio_load_presets(char *filename
)
1131 memset(presets
, 0, sizeof(presets
));
1134 /* No Preset in configuration. */
1135 if(filename
[0] == '\0')
1137 filepreset
[0] = '\0';
1140 /* Temporary preset, loaded until player shuts down. */
1141 else if(filename
[0] == '/')
1142 strncpy(filepreset
, filename
, sizeof(filepreset
));
1143 /* Preset from default directory. */
1145 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
1146 FMPRESET_PATH
, filename
);
1148 fd
= open_utf8(filepreset
, O_RDONLY
);
1151 while(!done
&& num_presets
< MAX_PRESETS
)
1153 rc
= read_line(fd
, buf
, 128);
1156 if(settings_parseline(buf
, &freq
, &name
))
1159 if(f
) /* For backwards compatibility */
1161 struct fmstation
* const fms
= &presets
[num_presets
];
1163 strncpy(fms
->name
, name
, MAX_FMPRESET_LEN
);
1164 fms
->name
[MAX_FMPRESET_LEN
] = '\0';
1174 else /* invalid file name? */
1175 filepreset
[0] = '\0';
1177 presets_loaded
= num_presets
> 0;
1178 presets_changed
= false;
1182 static int radio_add_preset(void)
1184 char buf
[MAX_FMPRESET_LEN
+ 1];
1186 if(num_presets
< MAX_PRESETS
)
1190 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1192 struct fmstation
* const fms
= &presets
[num_presets
];
1193 strcpy(fms
->name
, buf
);
1194 fms
->frequency
= curr_freq
;
1196 presets_changed
= true;
1197 presets_loaded
= num_presets
> 0;
1203 splash(HZ
, ID2P(LANG_FM_NO_FREE_PRESETS
));
1208 /* needed to know which preset we are edit/delete-ing */
1209 static int selected_preset
= -1;
1210 static int radio_edit_preset(void)
1212 char buf
[MAX_FMPRESET_LEN
+ 1];
1214 if (num_presets
> 0)
1216 struct fmstation
* const fms
= &presets
[selected_preset
];
1218 strcpy(buf
, fms
->name
);
1220 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1222 strcpy(fms
->name
, buf
);
1223 presets_changed
= true;
1230 static int radio_delete_preset(void)
1232 if (num_presets
> 0)
1234 struct fmstation
* const fms
= &presets
[selected_preset
];
1236 if (selected_preset
>= --num_presets
)
1237 selected_preset
= num_presets
- 1;
1239 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
1242 if (curr_preset
>= num_presets
)
1246 /* Don't ask to save when all presets are deleted. */
1247 presets_changed
= num_presets
> 0;
1249 if (!presets_changed
)
1251 /* The preset list will be cleared, switch to Scan Mode. */
1252 radio_mode
= RADIO_SCAN_MODE
;
1254 presets_loaded
= false;
1260 static int load_preset_list(void)
1262 return !rockbox_browse(FMPRESET_PATH
, SHOW_FMR
);
1265 static int save_preset_list(void)
1269 bool bad_file_name
= true;
1271 if(!dir_exists(FMPRESET_PATH
)) /* Check if there is preset folder */
1272 mkdir(FMPRESET_PATH
);
1274 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
1275 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
1277 while(bad_file_name
)
1279 if(!kbd_input(filepreset
, sizeof(filepreset
)))
1281 /* check the name: max MAX_FILENAME (20) chars */
1285 p1
= strrchr(filepreset
, '/');
1287 while((p1
) && (*p2
) && (*p2
!= '.'))
1289 len
= (int)(p2
-p1
) - 1;
1290 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
1292 /* no slash, too long or too short */
1293 splash(HZ
, ID2P(LANG_INVALID_FILENAME
));
1297 /* add correct extension (easier to always write)
1298 at this point, p2 points to 0 or the extension dot */
1300 strcat(filepreset
,".fmr");
1301 bad_file_name
= false;
1302 radio_save_presets();
1313 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
1318 static int clear_preset_list(void)
1320 /* Clear all the preset entries */
1321 memset(presets
, 0, sizeof (presets
));
1324 presets_loaded
= false;
1325 /* The preset list will be cleared switch to Scan Mode. */
1326 radio_mode
= RADIO_SCAN_MODE
;
1329 presets_changed
= false; /* Don't ask to save when clearing the list. */
1334 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1335 ID2P(LANG_FM_EDIT_PRESET
),
1336 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
1337 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1338 ID2P(LANG_FM_DELETE_PRESET
),
1339 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
1340 static int radio_preset_callback(int action
,
1341 const struct menu_item_ex
*this_item
)
1343 if (action
== ACTION_STD_OK
)
1344 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
1348 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_PRESET
),
1349 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
1350 &radio_delete_preset_item
);
1351 /* present a list of preset stations */
1352 static char * presets_get_name(int selected_item
, void *data
,
1353 char *buffer
, size_t buffer_len
)
1356 struct fmstation
*p
= &presets
[selected_item
];
1359 int freq
= p
->frequency
/ 10000;
1360 int frac
= freq
% 100;
1362 snprintf(buffer
, buffer_len
,
1363 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
1367 static int presets_speak_name(int selected_item
, void * data
)
1370 talk_preset(selected_item
, true, false);
1374 static int handle_radio_presets(void)
1376 struct gui_synclist lists
;
1378 int action
= ACTION_NONE
;
1379 #ifdef HAVE_BUTTONBAR
1380 struct gui_buttonbar buttonbar
;
1383 if(presets_loaded
== false)
1386 #ifdef HAVE_BUTTONBAR
1387 gui_buttonbar_init(&buttonbar
);
1388 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
1389 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
1390 str(LANG_FM_BUTTONBAR_EXIT
),
1391 str(LANG_FM_BUTTONBAR_ACTION
));
1392 gui_buttonbar_draw(&buttonbar
);
1394 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1, NULL
);
1395 gui_synclist_set_title(&lists
, str(LANG_PRESET
), NOICON
);
1396 gui_synclist_set_icon_callback(&lists
, NULL
);
1397 if(global_settings
.talk_file
)
1398 gui_synclist_set_voice_callback(&lists
, presets_speak_name
);
1399 gui_synclist_set_nb_items(&lists
, num_presets
);
1400 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
1401 gui_synclist_speak_item(&lists
);
1405 gui_synclist_draw(&lists
);
1406 list_do_action(CONTEXT_STD
, TIMEOUT_BLOCK
,
1407 &lists
, &action
, LIST_WRAP_UNLESS_HELD
);
1410 case ACTION_STD_MENU
:
1411 if (radio_add_preset())
1413 gui_synclist_set_nb_items(&lists
, num_presets
);
1414 gui_synclist_select_item(&lists
, num_presets
- 1);
1417 case ACTION_STD_CANCEL
:
1421 curr_preset
= gui_synclist_get_sel_pos(&lists
);
1422 curr_freq
= presets
[curr_preset
].frequency
;
1424 remember_frequency();
1428 case ACTION_STD_CONTEXT
:
1429 selected_preset
= gui_synclist_get_sel_pos(&lists
);
1430 do_menu(&handle_radio_preset_menu
, NULL
, NULL
, false);
1431 gui_synclist_set_nb_items(&lists
, num_presets
);
1432 gui_synclist_select_item(&lists
, selected_preset
);
1433 gui_synclist_speak_item(&lists
);
1436 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
1443 void toggle_mono_mode(bool mono
)
1445 tuner_set(RADIO_FORCE_MONO
, mono
);
1448 void set_radio_region(int region
)
1450 #ifdef HAVE_RADIO_REGION
1451 tuner_set(RADIO_REGION
, region
);
1454 remember_frequency();
1458 MENUITEM_SETTING(set_region
, &global_settings
.fm_region
, NULL
);
1459 MENUITEM_SETTING(force_mono
, &global_settings
.fm_force_mono
, NULL
);
1462 static char* get_mode_text(int selected_item
, void * data
, char *buffer
)
1464 (void)selected_item
;
1466 snprintf(buffer
, MAX_PATH
, "%s %s", str(LANG_MODE
),
1467 radio_mode
? str(LANG_PRESET
) :
1468 str(LANG_RADIO_SCAN_MODE
));
1471 static int toggle_radio_mode(void)
1473 radio_mode
= (radio_mode
== RADIO_SCAN_MODE
) ?
1474 RADIO_PRESET_MODE
: RADIO_SCAN_MODE
;
1477 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item
, 0,
1478 toggle_radio_mode
, NULL
,
1479 get_mode_text
, NULL
, NULL
, NULL
, Icon_NOICON
);
1482 static int scan_presets(void *viewports
)
1484 bool do_scan
= true;
1486 struct viewport
*vp
= (struct viewport
*)viewports
;
1489 screens
[i
].set_viewport(vp
?&vp
[i
]:NULL
);
1490 if(num_presets
> 0) /* Do that to avoid 2 questions. */
1491 do_scan
= yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS
));
1495 const struct fm_region_data
* const fmr
=
1496 &fm_region_data
[global_settings
.fm_region
];
1498 curr_freq
= fmr
->freq_min
;
1500 memset(presets
, 0, sizeof(presets
));
1501 tuner_set(RADIO_MUTE
, 1);
1503 while(curr_freq
<= fmr
->freq_max
)
1506 if(num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
1509 freq
= curr_freq
/ 10000;
1513 splashf(0, str(LANG_FM_SCANNING
), freq
, frac
);
1515 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
1518 presets
[num_presets
].name
[0] = '\0';
1519 presets
[num_presets
].frequency
= curr_freq
;
1523 curr_freq
+= fmr
->freq_step
;
1526 if (radio_status
== FMRADIO_PLAYING
)
1527 tuner_set(RADIO_MUTE
, 0);
1529 presets_changed
= true;
1533 screens
[i
].clear_viewport();
1534 screens
[i
].update_viewport();
1539 curr_freq
= presets
[0].frequency
;
1540 radio_mode
= RADIO_PRESET_MODE
;
1541 presets_loaded
= true;
1546 /* Wrap it to beginning or we'll be past end of band */
1547 presets_loaded
= false;
1555 #ifdef HAVE_RECORDING
1557 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1558 #define FM_RECORDING_SCREEN
1559 static int fm_recording_screen(void)
1563 /* switch recording source to FMRADIO for the duration */
1564 int rec_source
= global_settings
.rec_source
;
1565 global_settings
.rec_source
= AUDIO_SRC_FMRADIO
;
1567 ret
= recording_screen(true);
1569 /* safe to reset as changing sources is prohibited here */
1570 global_settings
.rec_source
= rec_source
;
1575 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1577 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1578 #define FM_RECORDING_SETTINGS
1579 static int fm_recording_settings(void)
1581 bool ret
= recording_menu(true);
1583 #if CONFIG_CODEC != SWCODEC
1586 struct audio_recording_options rec_options
;
1587 rec_init_recording_options(&rec_options
);
1588 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
1589 rec_set_recording_options(&rec_options
);
1596 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1597 #endif /* HAVE_RECORDING */
1599 #ifdef FM_RECORDING_SCREEN
1600 MENUITEM_FUNCTION(recscreen_item
, 0, ID2P(LANG_RECORDING
),
1601 fm_recording_screen
, NULL
, NULL
, Icon_Recording
);
1603 #ifdef FM_RECORDING_SETTINGS
1604 MENUITEM_FUNCTION(recsettings_item
, 0, ID2P(LANG_RECORDING_SETTINGS
),
1605 fm_recording_settings
, NULL
, NULL
, Icon_Recording
);
1608 MENUITEM_FUNCTION(radio_presets_item
, 0, ID2P(LANG_PRESET
),
1609 handle_radio_presets
, NULL
, NULL
, Icon_NOICON
);
1611 #ifndef FM_PRESET_ADD
1612 MENUITEM_FUNCTION(radio_addpreset_item
, 0, ID2P(LANG_FM_ADD_PRESET
),
1613 radio_add_preset
, NULL
, NULL
, Icon_NOICON
);
1617 MENUITEM_FUNCTION(presetload_item
, 0, ID2P(LANG_FM_PRESET_LOAD
),
1618 load_preset_list
, NULL
, NULL
, Icon_NOICON
);
1619 MENUITEM_FUNCTION(presetsave_item
, 0, ID2P(LANG_FM_PRESET_SAVE
),
1620 save_preset_list
, NULL
, NULL
, Icon_NOICON
);
1621 MENUITEM_FUNCTION(presetclear_item
, 0, ID2P(LANG_FM_PRESET_CLEAR
),
1622 clear_preset_list
, NULL
, NULL
, Icon_NOICON
);
1623 MENUITEM_FUNCTION(scan_presets_item
, MENU_FUNC_USEPARAM
,
1624 ID2P(LANG_FM_SCAN_PRESETS
),
1625 scan_presets
, NULL
, NULL
, Icon_NOICON
);
1627 MAKE_MENU(radio_settings_menu
, ID2P(LANG_FM_MENU
), NULL
,
1630 &radio_presets_item
,
1632 #ifndef FM_PRESET_ADD
1633 &radio_addpreset_item
,
1635 &presetload_item
, &presetsave_item
, &presetclear_item
,
1640 &set_region
, &sound_settings
,
1641 #ifdef FM_RECORDING_SCREEN
1644 #ifdef FM_RECORDING_SETTINGS
1647 &scan_presets_item
);
1648 /* main menu of the radio screen */
1649 static bool radio_menu(void)
1651 return do_menu(&radio_settings_menu
, NULL
, NULL
, false) ==