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"
58 #include "statusbar.h"
61 #include "buttonbar.h"
67 #include "menus/exported_menus.h"
68 #include "root_menu.h"
73 #if CONFIG_KEYPAD == RECORDER_PAD
76 #define FM_PRESET_ACTION
80 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
83 #define FM_NEXT_PRESET
84 #define FM_PREV_PRESET
86 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
90 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
93 /* This should be removeable if the whole tuning thing is sorted out since
94 proper tuning quiets the screen almost entirely in that extreme measures
95 have to be taken to hear any interference. */
96 #define HAVE_NOISY_IDLE_MODE
98 #elif CONFIG_KEYPAD == ONDIO_PAD
99 #define FM_RECORD_DBLPRE
101 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD)
109 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
113 #elif (CONFIG_KEYPAD == COWOND2_PAD)
122 #define RADIO_SCAN_MODE 0
123 #define RADIO_PRESET_MODE 1
125 static int curr_preset
= -1;
126 static int curr_freq
; /* current frequency in Hz */
127 static int radio_mode
= RADIO_SCAN_MODE
;
128 static int search_dir
= 0;
130 static int radio_status
= FMRADIO_OFF
;
131 static bool in_screen
= false;
133 #define MAX_PRESETS 64
134 static bool presets_loaded
= false, presets_changed
= false;
135 static struct fmstation presets
[MAX_PRESETS
];
137 static char filepreset
[MAX_PATH
]; /* preset filename variable */
139 static int num_presets
= 0; /* The number of presets in the preset list */
141 static void radio_save_presets(void);
142 static int handle_radio_presets(void);
143 static bool radio_menu(void);
144 static int radio_add_preset(void);
145 static int save_preset_list(void);
146 static int load_preset_list(void);
147 static int clear_preset_list(void);
149 static int scan_presets(void *viewports
);
151 /* Function to manipulate all yesno dialogues.
152 This function needs the output text as an argument. */
153 static bool yesno_pop(const char* text
)
156 const char *lines
[]={text
};
157 const struct text_message message
={lines
, 1};
158 bool ret
= (gui_syncyesno_run(&message
,NULL
,NULL
)== YESNO_YES
);
160 screens
[i
].clear_viewport();
164 void radio_init(void)
170 int get_radio_status(void)
175 bool in_radio_screen(void)
180 /* TODO: Move some more of the control functionality to firmware
181 and clean up the mess */
183 /* secret flag for starting paused - prevents unmute */
184 #define FMRADIO_START_PAUSED 0x8000
185 void radio_start(void)
187 const struct fm_region_data
*fmr
;
190 if(radio_status
== FMRADIO_PLAYING
)
193 fmr
= &fm_region_data
[global_settings
.fm_region
];
195 start_paused
= radio_status
& FMRADIO_START_PAUSED
;
196 /* clear flag before any yielding */
197 radio_status
&= ~FMRADIO_START_PAUSED
;
199 if(radio_status
== FMRADIO_OFF
)
202 curr_freq
= global_status
.last_frequency
* fmr
->freq_step
+ fmr
->freq_min
;
204 tuner_set(RADIO_SLEEP
, 0); /* wake up the tuner */
206 if(radio_status
== FMRADIO_OFF
)
208 #ifdef HAVE_RADIO_REGION
209 tuner_set(RADIO_REGION
, global_settings
.fm_region
);
211 tuner_set(RADIO_FORCE_MONO
, global_settings
.fm_force_mono
);
214 tuner_set(RADIO_FREQUENCY
, curr_freq
);
216 #ifdef HAVE_RADIO_MUTE_TIMEOUT
218 unsigned long mute_timeout
= current_tick
+ HZ
;
219 if (radio_status
!= FMRADIO_OFF
)
225 while(!tuner_get(RADIO_STEREO
) && !tuner_get(RADIO_TUNED
))
227 if(TIME_AFTER(current_tick
, mute_timeout
))
234 /* keep radio from sounding initially */
236 tuner_set(RADIO_MUTE
, 0);
238 radio_status
= FMRADIO_PLAYING
;
241 void radio_pause(void)
243 if(radio_status
== FMRADIO_PAUSED
)
246 if(radio_status
== FMRADIO_OFF
)
248 radio_status
|= FMRADIO_START_PAUSED
;
252 tuner_set(RADIO_MUTE
, 1);
253 tuner_set(RADIO_SLEEP
, 1);
255 radio_status
= FMRADIO_PAUSED
;
258 void radio_stop(void)
260 if(radio_status
== FMRADIO_OFF
)
263 tuner_set(RADIO_MUTE
, 1);
264 tuner_set(RADIO_SLEEP
, 1); /* low power mode, if available */
265 radio_status
= FMRADIO_OFF
;
266 tuner_power(false); /* status update, power off if avail. */
269 bool radio_hardware_present(void)
271 return tuner_get(RADIO_PRESENT
);
274 /* Keep freq on the grid for the current region */
275 static int snap_freq_to_grid(int freq
)
277 const struct fm_region_data
* const fmr
=
278 &fm_region_data
[global_settings
.fm_region
];
280 /* Range clamp if out of range or just round to nearest */
281 if (freq
< fmr
->freq_min
)
282 freq
= fmr
->freq_min
;
283 else if (freq
> fmr
->freq_max
)
284 freq
= fmr
->freq_max
;
286 freq
= (freq
- fmr
->freq_min
+ fmr
->freq_step
/2) /
287 fmr
->freq_step
* fmr
->freq_step
+ fmr
->freq_min
;
292 /* Find a matching preset to freq */
293 static int find_preset(int freq
)
298 for(i
= 0;i
< MAX_PRESETS
;i
++)
300 if(freq
== presets
[i
].frequency
)
307 /* Return the closest preset encountered in the search direction with
309 static int find_closest_preset(int freq
, int direction
)
316 if (direction
== 0) /* direction == 0 isn't really used */
319 for (i
= 0; i
< num_presets
; i
++)
321 int f
= presets
[i
].frequency
;
323 return i
; /* Exact match = stop */
325 /* remember the highest and lowest presets for wraparound */
326 if (f
< presets
[lowpreset
].frequency
)
328 if (f
> presets
[highpreset
].frequency
)
331 /* find the closest preset in the given direction */
332 if (direction
> 0 && f
> freq
)
334 if (closest
< 0 || f
< presets
[closest
].frequency
)
337 else if (direction
< 0 && f
< freq
)
339 if (closest
< 0 || f
> presets
[closest
].frequency
)
346 /* no presets in the given direction */
347 /* wrap around depending on direction */
349 closest
= highpreset
;
357 static void remember_frequency(void)
359 const struct fm_region_data
* const fmr
=
360 &fm_region_data
[global_settings
.fm_region
];
361 global_status
.last_frequency
= (curr_freq
- fmr
->freq_min
)
366 static void next_preset(int direction
)
371 if (curr_preset
== -1)
372 curr_preset
= find_closest_preset(curr_freq
, direction
);
374 curr_preset
= (curr_preset
+ direction
+ num_presets
) % num_presets
;
376 /* Must stay on the current grid for the region */
377 curr_freq
= snap_freq_to_grid(presets
[curr_preset
].frequency
);
379 tuner_set(RADIO_FREQUENCY
, curr_freq
);
380 remember_frequency();
383 /* Step to the next or previous frequency */
384 static int step_freq(int freq
, int direction
)
386 const struct fm_region_data
* const fmr
=
387 &fm_region_data
[global_settings
.fm_region
];
389 freq
+= direction
*fmr
->freq_step
;
391 /* Wrap first or snapping to grid will not let us on the band extremes */
392 if (freq
> fmr
->freq_max
)
393 freq
= direction
> 0 ? fmr
->freq_min
: fmr
->freq_max
;
394 else if (freq
< fmr
->freq_min
)
395 freq
= direction
< 0 ? fmr
->freq_max
: fmr
->freq_min
;
397 freq
= snap_freq_to_grid(freq
);
402 /* Step to the next or previous station */
403 static void next_station(int direction
)
405 if (direction
!= 0 && radio_mode
!= RADIO_SCAN_MODE
)
407 next_preset(direction
);
411 curr_freq
= step_freq(curr_freq
, direction
);
413 if (radio_status
== FMRADIO_PLAYING
)
414 tuner_set(RADIO_MUTE
, 1);
416 tuner_set(RADIO_FREQUENCY
, curr_freq
);
418 if (radio_status
== FMRADIO_PLAYING
)
419 tuner_set(RADIO_MUTE
, 0);
421 curr_preset
= find_preset(curr_freq
);
422 remember_frequency();
425 /* Ends an in-progress search */
426 static void end_search(void)
428 if (search_dir
!= 0 && radio_status
== FMRADIO_PLAYING
)
429 tuner_set(RADIO_MUTE
, 0);
433 /* Speak a frequency. */
434 static void talk_freq(int freq
, bool enqueue
)
437 talk_number(freq
/ 100, enqueue
);
438 talk_id(LANG_POINT
, true);
439 talk_number(freq
% 100 / 10, true);
441 talk_number(freq
% 10, true);
444 /* Speak a preset by number or by spelling its name, depending on settings. */
445 static void talk_preset(int preset
, bool fallback
, bool enqueue
)
447 if (global_settings
.talk_file
== 1) /* number */
448 talk_number(preset
+ 1, enqueue
);
451 if(presets
[preset
].name
[0])
452 talk_spell(presets
[preset
].name
, enqueue
);
454 talk_freq(presets
[preset
].frequency
, enqueue
);
458 int radio_screen(void)
462 int ret_val
= GO_TO_ROOT
;
465 bool stereo
= false, last_stereo
= false;
467 int top_of_screen
= 0;
468 bool update_screen
= true;
469 bool screen_freeze
= false;
470 bool keep_playing
= false;
472 #ifdef FM_RECORD_DBLPRE
473 int lastbutton
= BUTTON_NONE
;
474 unsigned long rec_lastclick
= 0;
476 #if CONFIG_CODEC != SWCODEC
477 bool have_recorded
= false;
478 int timeout
= current_tick
+ HZ
/10;
479 unsigned int seconds
= 0;
480 unsigned int last_seconds
= 0;
482 struct audio_recording_options rec_options
;
483 #endif /* CONFIG_CODEC != SWCODEC */
484 #ifndef HAVE_NOISY_IDLE_MODE
485 int button_timeout
= current_tick
+ (2*HZ
);
487 struct viewport vp
[NB_SCREENS
];
488 int oldbars
= 0, fmbars
= VP_SB_ALLSCREENS
;
489 #ifdef HAVE_BUTTONBAR
490 struct gui_buttonbar buttonbar
;
491 gui_buttonbar_init(&buttonbar
);
492 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
495 /* change status to "in screen" */
498 /* always display status bar in radio screen for now */
500 fmbars
|= VP_SB_IGNORE_SETTING(i
);
501 oldbars
= viewportmanager_set_statusbar(fmbars
);
504 viewport_set_defaults(&vp
[i
], i
);
505 #ifdef HAVE_BUTTONBAR
506 if (global_settings
.buttonbar
)
507 vp
[i
].height
-= BUTTONBAR_HEIGHT
;
509 screens
[i
].set_viewport(&vp
[i
]);
510 screens
[i
].stop_scroll();
511 screens
[i
].clear_viewport();
512 screens
[i
].update_viewport();
515 fh
= font_get(FONT_UI
)->height
;
517 /* Adjust for font size, trying to center the information vertically */
523 memset(presets
, 0, sizeof(presets
));
524 radio_load_presets(global_settings
.fmr_file
);
527 if(radio_status
== FMRADIO_OFF
)
531 #if CONFIG_CODEC != SWCODEC
532 if(rec_create_directory() > 0)
533 have_recorded
= true;
535 audio_init_recording(talk_get_bufsize());
537 sound_settings_apply();
538 /* Yes, we use the D/A for monitoring */
539 peak_meter_playback(true);
541 peak_meter_enabled
= true;
543 rec_init_recording_options(&rec_options
);
544 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
545 rec_set_recording_options(&rec_options
);
547 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
548 sound_default(SOUND_RIGHT_GAIN
), AUDIO_GAIN_LINEIN
);
550 #endif /* CONFIG_CODEC != SWCODEC */
551 #endif /* ndef SIMULATOR */
554 #if CONFIG_CODEC == SWCODEC
555 audio_set_input_source(AUDIO_SRC_FMRADIO
,
556 (radio_status
== FMRADIO_PAUSED
) ?
557 SRCF_FMRADIO_PAUSED
: SRCF_FMRADIO_PLAYING
);
559 if (radio_status
== FMRADIO_OFF
)
563 if(num_presets
< 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN
)))
566 curr_preset
= find_preset(curr_freq
);
567 if(curr_preset
!= -1)
568 radio_mode
= RADIO_PRESET_MODE
;
570 #ifdef HAVE_BUTTONBAR
571 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
572 str(LANG_PRESET
), str(LANG_FM_BUTTONBAR_RECORD
));
575 #ifndef HAVE_NOISY_IDLE_MODE
583 curr_freq
= step_freq(curr_freq
, search_dir
);
584 update_screen
= true;
586 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
588 curr_preset
= find_preset(curr_freq
);
589 remember_frequency();
602 #if CONFIG_CODEC != SWCODEC
603 /* TODO: Can we timeout at HZ when recording since peaks aren't
604 displayed? This should quiet recordings too. */
605 button
= get_action(CONTEXT_FM
,
606 update_screen
? TIMEOUT_NOBLOCK
: HZ
/ PEAK_METER_FPS
);
608 button
= get_action(CONTEXT_FM
,
609 update_screen
? TIMEOUT_NOBLOCK
: HZ
);
612 #ifndef HAVE_NOISY_IDLE_MODE
613 if (button
!= ACTION_NONE
)
615 cpu_idle_mode(false);
616 button_timeout
= current_tick
+ (2*HZ
);
622 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
623 if(audio_status() == AUDIO_STATUS_RECORD
)
633 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
635 if(filepreset
[0] == '\0')
638 radio_save_presets();
641 /* Clear the preset list on exit. */
644 update_screen
= true;
648 case ACTION_FM_RECORD
:
649 #ifdef FM_RECORD_DBLPRE
650 if (lastbutton
!= ACTION_FM_RECORD_DBLPRE
)
655 if (current_tick
- rec_lastclick
> HZ
/2)
657 rec_lastclick
= current_tick
;
660 #endif /* FM_RECORD_DBLPRE */
662 if(audio_status() == AUDIO_STATUS_RECORD
)
664 rec_command(RECORDING_CMD_START_NEWFILE
);
665 update_screen
= true;
669 have_recorded
= true;
670 rec_command(RECORDING_CMD_START
);
671 update_screen
= true;
673 #endif /* SIMULATOR */
676 #endif /* #ifdef FM_RECORD */
679 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
680 if(audio_status() == AUDIO_STATUS_RECORD
)
685 ret_val
= GO_TO_ROOT
;
688 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
690 if(filepreset
[0] == '\0')
693 radio_save_presets();
697 /* Clear the preset list on exit. */
702 case ACTION_STD_PREV
:
703 case ACTION_STD_NEXT
:
704 next_station(button
== ACTION_STD_PREV
? -1 : 1);
706 update_screen
= true;
710 case ACTION_STD_PREVREPEAT
:
711 case ACTION_STD_NEXTREPEAT
:
713 int dir
= search_dir
;
714 search_dir
= button
== ACTION_STD_PREVREPEAT
? -1 : 1;
715 if (radio_mode
!= RADIO_SCAN_MODE
)
717 next_preset(search_dir
);
719 update_screen
= true;
724 /* Starting auto scan */
725 tuner_set(RADIO_MUTE
, 1);
726 update_screen
= true;
731 case ACTION_SETTINGS_INC
:
732 case ACTION_SETTINGS_INCREPEAT
:
733 global_settings
.volume
++;
735 update_screen
= true;
738 case ACTION_SETTINGS_DEC
:
739 case ACTION_SETTINGS_DECREPEAT
:
740 global_settings
.volume
--;
742 update_screen
= true;
746 if (radio_status
== FMRADIO_PLAYING
)
751 update_screen
= true;
757 viewportmanager_set_statusbar(oldbars
);
759 curr_preset
= find_preset(curr_freq
);
760 viewportmanager_set_statusbar(fmbars
);
763 screens
[i
].set_viewport(&vp
[i
]);
764 screens
[i
].clear_viewport();
765 screens
[i
].update_viewport();
766 screens
[i
].set_viewport(NULL
);
768 #ifdef HAVE_BUTTONBAR
769 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
771 str(LANG_FM_BUTTONBAR_RECORD
));
773 update_screen
= true;
777 case ACTION_FM_PRESET
:
780 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
781 update_screen
= true;
784 screens
[i
].set_viewport(&vp
[i
]);
785 screens
[i
].clear_viewport();
786 screens
[i
].update_viewport();
787 screens
[i
].set_viewport(NULL
);
792 viewportmanager_set_statusbar(oldbars
);
793 handle_radio_presets();
794 viewportmanager_set_statusbar(fmbars
);
797 screens
[i
].set_viewport(&vp
[i
]);
798 screens
[i
].stop_scroll();
799 screens
[i
].clear_viewport();
800 screens
[i
].update_viewport();
801 screens
[i
].set_viewport(NULL
);
803 #ifdef HAVE_BUTTONBAR
804 gui_buttonbar_set(&buttonbar
,
805 str(LANG_BUTTONBAR_MENU
),
807 str(LANG_FM_BUTTONBAR_RECORD
));
809 update_screen
= true;
811 #endif /* FM_PRESET */
814 case ACTION_FM_FREEZE
:
817 splash(HZ
, str(LANG_FM_FREEZE
));
818 screen_freeze
= true;
822 update_screen
= true;
823 screen_freeze
= false;
826 #endif /* FM_FREEZE */
828 case SYS_USB_CONNECTED
:
829 #if CONFIG_CODEC != SWCODEC
830 /* Only accept USB connection when not recording */
831 if(audio_status() != AUDIO_STATUS_RECORD
)
834 default_event_handler(SYS_USB_CONNECTED
);
835 screen_freeze
= true; /* Cosmetic: makes sure the
836 radio screen doesn't redraw */
843 if(radio_mode
== RADIO_SCAN_MODE
)
845 /* Force scan mode if there are no presets. */
847 radio_mode
= RADIO_PRESET_MODE
;
850 radio_mode
= RADIO_SCAN_MODE
;
851 update_screen
= true;
852 cond_talk_ids_fq(radio_mode
?
853 LANG_PRESET
: LANG_RADIO_SCAN_MODE
);
858 #ifdef FM_NEXT_PRESET
859 case ACTION_FM_NEXT_PRESET
:
862 update_screen
= true;
867 #ifdef FM_PREV_PRESET
868 case ACTION_FM_PREV_PRESET
:
871 update_screen
= true;
877 default_event_handler(button
);
881 #ifdef FM_RECORD_DBLPRE
882 if (button
!= ACTION_NONE
)
886 #if CONFIG_CODEC != SWCODEC
892 /* Only display the peak meter when not recording */
893 #if CONFIG_CODEC != SWCODEC
898 screens
[i
].set_viewport(&vp
[i
]);
899 peak_meter_screen(&screens
[i
],0,
900 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
902 screens
[i
].update_rect(0,
903 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
904 screens
[i
].getwidth(), fh
);
905 screens
[i
].set_viewport(NULL
);
909 if(TIME_AFTER(current_tick
, timeout
))
911 timeout
= current_tick
+ HZ
;
914 #endif /* CONFIG_CODEC == SWCODEC */
916 /* keep "mono" from always being displayed when paused */
917 if (radio_status
!= FMRADIO_PAUSED
)
919 stereo
= tuner_get(RADIO_STEREO
) &&
920 !global_settings
.fm_force_mono
;
922 if(stereo
!= last_stereo
)
924 update_screen
= true;
925 last_stereo
= stereo
;
930 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
931 seconds
= audio_recorded_time() / HZ
;
932 if (update_screen
|| seconds
> last_seconds
)
934 last_seconds
= seconds
;
943 screens
[i
].set_viewport(&vp
[i
]);
946 snprintf(buf
, 128, curr_preset
>= 0 ? "%d. %s" : " ",
947 curr_preset
+ 1, presets
[curr_preset
].name
);
950 screens
[i
].puts_scroll(0, top_of_screen
, buf
);
952 freq
= curr_freq
/ 10000;
953 snprintf(buf
, 128, str(LANG_FM_STATION
),
954 freq
/ 100, freq
% 100);
956 screens
[i
].puts_scroll(0, top_of_screen
+ 1, buf
);
958 snprintf(buf
, 128, "%s", stereo
?str(LANG_CHANNEL_STEREO
):
959 str(LANG_CHANNEL_MONO
));
961 screens
[i
].puts_scroll(0, top_of_screen
+ 2, buf
);
963 snprintf(buf
, 128, "%s %s", str(LANG_MODE
),
964 radio_mode
? str(LANG_PRESET
) :
965 str(LANG_RADIO_SCAN_MODE
));
967 screens
[i
].puts_scroll(0, top_of_screen
+ 3, buf
);
969 #if CONFIG_CODEC != SWCODEC
970 if(audio_status() == AUDIO_STATUS_RECORD
)
972 hours
= seconds
/ 3600;
973 minutes
= (seconds
- (hours
* 3600)) / 60;
974 snprintf(buf
, 32, "%s %02d:%02d:%02d",
975 str(LANG_RECORDING_TIME
),
976 hours
, minutes
, seconds
%60);
978 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
982 if(rec_options
.rec_prerecord_time
)
984 snprintf(buf
, 32, "%s %02d",
985 str(LANG_RECORD_PRERECORD
), seconds
%60);
987 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
990 #endif /* CONFIG_CODEC != SWCODEC */
994 screens
[i
].update_viewport();
995 screens
[i
].set_viewport(NULL
);
998 #ifdef HAVE_BUTTONBAR
999 gui_buttonbar_draw(&buttonbar
);
1004 update_screen
= false;
1006 if (global_settings
.talk_file
&& talk
1007 && radio_status
== FMRADIO_PAUSED
)
1010 bool enqueue
= false;
1011 if (radio_mode
== RADIO_SCAN_MODE
)
1013 talk_freq(curr_freq
, enqueue
);
1016 if (curr_preset
>= 0)
1017 talk_preset(curr_preset
, radio_mode
== RADIO_PRESET_MODE
,
1021 #if CONFIG_CODEC != SWCODEC
1022 if(audio_status() & AUDIO_STATUS_ERROR
)
1028 #ifndef HAVE_NOISY_IDLE_MODE
1029 if (TIME_AFTER(current_tick
, button_timeout
))
1031 cpu_idle_mode(true);
1037 #if CONFIG_CODEC != SWCODEC
1038 if(audio_status() & AUDIO_STATUS_ERROR
)
1040 splash(0, str(LANG_DISK_FULL
));
1043 screens
[i
].set_viewport(&vp
[i
]);
1044 screens
[i
].update_viewport();
1045 screens
[i
].set_viewport(NULL
);
1047 audio_error_clear();
1051 button
= get_action(CONTEXT_FM
, TIMEOUT_BLOCK
);
1052 if(button
== ACTION_FM_STOP
)
1057 audio_init_playback();
1058 #endif /* CONFIG_CODEC != SWCODEC */
1060 sound_settings_apply();
1061 #endif /* SIMULATOR */
1065 /* Catch FMRADIO_PLAYING status for the sim. */
1067 #if CONFIG_CODEC != SWCODEC
1068 /* Enable the Left and right A/D Converter */
1069 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
1070 sound_default(SOUND_RIGHT_GAIN
),
1072 mas_codec_writereg(6, 0x4000);
1075 #endif /* SIMULATOR */
1079 #if CONFIG_CODEC == SWCODEC
1080 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
1086 #ifndef HAVE_NOISY_IDLE_MODE
1087 cpu_idle_mode(false);
1090 viewportmanager_set_statusbar(oldbars
);
1092 #if CONFIG_CODEC != SWCODEC
1093 return have_recorded
;
1097 } /* radio_screen */
1099 static void radio_save_presets(void)
1104 fd
= creat(filepreset
);
1107 for(i
= 0;i
< num_presets
;i
++)
1109 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
1113 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
1114 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
1115 presets_changed
= false;
1119 splash(HZ
, ID2P(LANG_FM_PRESET_SAVE_FAILED
));
1123 void radio_load_presets(char *filename
)
1133 memset(presets
, 0, sizeof(presets
));
1136 /* No Preset in configuration. */
1137 if(filename
[0] == '\0')
1139 filepreset
[0] = '\0';
1142 /* Temporary preset, loaded until player shuts down. */
1143 else if(filename
[0] == '/')
1144 strncpy(filepreset
, filename
, sizeof(filepreset
));
1145 /* Preset from default directory. */
1147 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
1148 FMPRESET_PATH
, filename
);
1150 fd
= open_utf8(filepreset
, O_RDONLY
);
1153 while(!done
&& num_presets
< MAX_PRESETS
)
1155 rc
= read_line(fd
, buf
, 128);
1158 if(settings_parseline(buf
, &freq
, &name
))
1161 if(f
) /* For backwards compatibility */
1163 struct fmstation
* const fms
= &presets
[num_presets
];
1165 strncpy(fms
->name
, name
, MAX_FMPRESET_LEN
);
1166 fms
->name
[MAX_FMPRESET_LEN
] = '\0';
1176 else /* invalid file name? */
1177 filepreset
[0] = '\0';
1179 presets_loaded
= num_presets
> 0;
1180 presets_changed
= false;
1184 static int radio_add_preset(void)
1186 char buf
[MAX_FMPRESET_LEN
+ 1];
1188 if(num_presets
< MAX_PRESETS
)
1192 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1194 struct fmstation
* const fms
= &presets
[num_presets
];
1195 strcpy(fms
->name
, buf
);
1196 fms
->frequency
= curr_freq
;
1198 presets_changed
= true;
1199 presets_loaded
= num_presets
> 0;
1205 splash(HZ
, ID2P(LANG_FM_NO_FREE_PRESETS
));
1210 /* needed to know which preset we are edit/delete-ing */
1211 static int selected_preset
= -1;
1212 static int radio_edit_preset(void)
1214 char buf
[MAX_FMPRESET_LEN
+ 1];
1216 if (num_presets
> 0)
1218 struct fmstation
* const fms
= &presets
[selected_preset
];
1220 strcpy(buf
, fms
->name
);
1222 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1224 strcpy(fms
->name
, buf
);
1225 presets_changed
= true;
1232 static int radio_delete_preset(void)
1234 if (num_presets
> 0)
1236 struct fmstation
* const fms
= &presets
[selected_preset
];
1238 if (selected_preset
>= --num_presets
)
1239 selected_preset
= num_presets
- 1;
1241 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
1244 if (curr_preset
>= num_presets
)
1248 /* Don't ask to save when all presets are deleted. */
1249 presets_changed
= num_presets
> 0;
1251 if (!presets_changed
)
1253 /* The preset list will be cleared, switch to Scan Mode. */
1254 radio_mode
= RADIO_SCAN_MODE
;
1256 presets_loaded
= false;
1262 static int load_preset_list(void)
1264 return !rockbox_browse(FMPRESET_PATH
, SHOW_FMR
);
1267 static int save_preset_list(void)
1271 bool bad_file_name
= true;
1273 if(!dir_exists(FMPRESET_PATH
)) /* Check if there is preset folder */
1274 mkdir(FMPRESET_PATH
);
1276 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
1277 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
1279 while(bad_file_name
)
1281 if(!kbd_input(filepreset
, sizeof(filepreset
)))
1283 /* check the name: max MAX_FILENAME (20) chars */
1287 p1
= strrchr(filepreset
, '/');
1289 while((p1
) && (*p2
) && (*p2
!= '.'))
1291 len
= (int)(p2
-p1
) - 1;
1292 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
1294 /* no slash, too long or too short */
1295 splash(HZ
, ID2P(LANG_INVALID_FILENAME
));
1299 /* add correct extension (easier to always write)
1300 at this point, p2 points to 0 or the extension dot */
1302 strcat(filepreset
,".fmr");
1303 bad_file_name
= false;
1304 radio_save_presets();
1315 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
1320 static int clear_preset_list(void)
1322 /* Clear all the preset entries */
1323 memset(presets
, 0, sizeof (presets
));
1326 presets_loaded
= false;
1327 /* The preset list will be cleared switch to Scan Mode. */
1328 radio_mode
= RADIO_SCAN_MODE
;
1331 presets_changed
= false; /* Don't ask to save when clearing the list. */
1336 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1337 ID2P(LANG_FM_EDIT_PRESET
),
1338 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
1339 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1340 ID2P(LANG_FM_DELETE_PRESET
),
1341 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
1342 static int radio_preset_callback(int action
,
1343 const struct menu_item_ex
*this_item
)
1345 if (action
== ACTION_STD_OK
)
1346 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
1350 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_PRESET
),
1351 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
1352 &radio_delete_preset_item
);
1353 /* present a list of preset stations */
1354 static char * presets_get_name(int selected_item
, void *data
,
1355 char *buffer
, size_t buffer_len
)
1358 struct fmstation
*p
= &presets
[selected_item
];
1361 int freq
= p
->frequency
/ 10000;
1362 int frac
= freq
% 100;
1364 snprintf(buffer
, buffer_len
,
1365 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
1369 static int presets_speak_name(int selected_item
, void * data
)
1372 talk_preset(selected_item
, true, false);
1376 static int handle_radio_presets(void)
1378 struct gui_synclist lists
;
1380 int action
= ACTION_NONE
;
1381 #ifdef HAVE_BUTTONBAR
1382 struct gui_buttonbar buttonbar
;
1385 if(presets_loaded
== false)
1388 #ifdef HAVE_BUTTONBAR
1389 gui_buttonbar_init(&buttonbar
);
1390 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
1391 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
1392 str(LANG_FM_BUTTONBAR_EXIT
),
1393 str(LANG_FM_BUTTONBAR_ACTION
));
1394 gui_buttonbar_draw(&buttonbar
);
1396 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1, NULL
);
1397 gui_synclist_set_title(&lists
, str(LANG_PRESET
), NOICON
);
1398 gui_synclist_set_icon_callback(&lists
, NULL
);
1399 if(global_settings
.talk_file
)
1400 gui_synclist_set_voice_callback(&lists
, presets_speak_name
);
1401 gui_synclist_set_nb_items(&lists
, num_presets
);
1402 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
1403 gui_synclist_speak_item(&lists
);
1407 gui_synclist_draw(&lists
);
1408 list_do_action(CONTEXT_STD
, TIMEOUT_BLOCK
,
1409 &lists
, &action
, LIST_WRAP_UNLESS_HELD
);
1412 case ACTION_STD_MENU
:
1413 if (radio_add_preset())
1415 gui_synclist_set_nb_items(&lists
, num_presets
);
1416 gui_synclist_select_item(&lists
, num_presets
- 1);
1419 case ACTION_STD_CANCEL
:
1423 curr_preset
= gui_synclist_get_sel_pos(&lists
);
1424 curr_freq
= presets
[curr_preset
].frequency
;
1426 remember_frequency();
1430 case ACTION_STD_CONTEXT
:
1431 selected_preset
= gui_synclist_get_sel_pos(&lists
);
1432 do_menu(&handle_radio_preset_menu
, NULL
, NULL
, false);
1433 gui_synclist_set_nb_items(&lists
, num_presets
);
1434 gui_synclist_select_item(&lists
, selected_preset
);
1435 gui_synclist_speak_item(&lists
);
1438 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
1445 void toggle_mono_mode(bool mono
)
1447 tuner_set(RADIO_FORCE_MONO
, mono
);
1450 void set_radio_region(int region
)
1452 #ifdef HAVE_RADIO_REGION
1453 tuner_set(RADIO_REGION
, region
);
1456 remember_frequency();
1460 MENUITEM_SETTING(set_region
, &global_settings
.fm_region
, NULL
);
1461 MENUITEM_SETTING(force_mono
, &global_settings
.fm_force_mono
, NULL
);
1464 static char* get_mode_text(int selected_item
, void * data
, char *buffer
)
1466 (void)selected_item
;
1468 snprintf(buffer
, MAX_PATH
, "%s %s", str(LANG_MODE
),
1469 radio_mode
? str(LANG_PRESET
) :
1470 str(LANG_RADIO_SCAN_MODE
));
1473 static int toggle_radio_mode(void)
1475 radio_mode
= (radio_mode
== RADIO_SCAN_MODE
) ?
1476 RADIO_PRESET_MODE
: RADIO_SCAN_MODE
;
1479 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item
, 0,
1480 toggle_radio_mode
, NULL
,
1481 get_mode_text
, NULL
, NULL
, NULL
, Icon_NOICON
);
1484 static int scan_presets(void *viewports
)
1486 bool do_scan
= true;
1488 struct viewport
*vp
= (struct viewport
*)viewports
;
1491 screens
[i
].set_viewport(vp
?&vp
[i
]:NULL
);
1492 if(num_presets
> 0) /* Do that to avoid 2 questions. */
1493 do_scan
= yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS
));
1497 const struct fm_region_data
* const fmr
=
1498 &fm_region_data
[global_settings
.fm_region
];
1500 curr_freq
= fmr
->freq_min
;
1502 memset(presets
, 0, sizeof(presets
));
1503 tuner_set(RADIO_MUTE
, 1);
1505 while(curr_freq
<= fmr
->freq_max
)
1508 if(num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
1511 freq
= curr_freq
/ 10000;
1515 splashf(0, str(LANG_FM_SCANNING
), freq
, frac
);
1517 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
1520 presets
[num_presets
].name
[0] = '\0';
1521 presets
[num_presets
].frequency
= curr_freq
;
1525 curr_freq
+= fmr
->freq_step
;
1528 if (radio_status
== FMRADIO_PLAYING
)
1529 tuner_set(RADIO_MUTE
, 0);
1531 presets_changed
= true;
1535 screens
[i
].clear_viewport();
1536 screens
[i
].update_viewport();
1541 curr_freq
= presets
[0].frequency
;
1542 radio_mode
= RADIO_PRESET_MODE
;
1543 presets_loaded
= true;
1548 /* Wrap it to beginning or we'll be past end of band */
1549 presets_loaded
= false;
1557 #ifdef HAVE_RECORDING
1559 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1560 #define FM_RECORDING_SCREEN
1561 static int fm_recording_screen(void)
1565 /* switch recording source to FMRADIO for the duration */
1566 int rec_source
= global_settings
.rec_source
;
1567 global_settings
.rec_source
= AUDIO_SRC_FMRADIO
;
1569 ret
= recording_screen(true);
1571 /* safe to reset as changing sources is prohibited here */
1572 global_settings
.rec_source
= rec_source
;
1577 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1579 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1580 #define FM_RECORDING_SETTINGS
1581 static int fm_recording_settings(void)
1583 bool ret
= recording_menu(true);
1585 #if CONFIG_CODEC != SWCODEC
1588 struct audio_recording_options rec_options
;
1589 rec_init_recording_options(&rec_options
);
1590 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
1591 rec_set_recording_options(&rec_options
);
1598 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1599 #endif /* HAVE_RECORDING */
1601 #ifdef FM_RECORDING_SCREEN
1602 MENUITEM_FUNCTION(recscreen_item
, 0, ID2P(LANG_RECORDING
),
1603 fm_recording_screen
, NULL
, NULL
, Icon_Recording
);
1605 #ifdef FM_RECORDING_SETTINGS
1606 MENUITEM_FUNCTION(recsettings_item
, 0, ID2P(LANG_RECORDING_SETTINGS
),
1607 fm_recording_settings
, NULL
, NULL
, Icon_Recording
);
1610 MENUITEM_FUNCTION(radio_presets_item
, 0, ID2P(LANG_PRESET
),
1611 handle_radio_presets
, NULL
, NULL
, Icon_NOICON
);
1613 #ifndef FM_PRESET_ADD
1614 MENUITEM_FUNCTION(radio_addpreset_item
, 0, ID2P(LANG_FM_ADD_PRESET
),
1615 radio_add_preset
, NULL
, NULL
, Icon_NOICON
);
1619 MENUITEM_FUNCTION(presetload_item
, 0, ID2P(LANG_FM_PRESET_LOAD
),
1620 load_preset_list
, NULL
, NULL
, Icon_NOICON
);
1621 MENUITEM_FUNCTION(presetsave_item
, 0, ID2P(LANG_FM_PRESET_SAVE
),
1622 save_preset_list
, NULL
, NULL
, Icon_NOICON
);
1623 MENUITEM_FUNCTION(presetclear_item
, 0, ID2P(LANG_FM_PRESET_CLEAR
),
1624 clear_preset_list
, NULL
, NULL
, Icon_NOICON
);
1625 MENUITEM_FUNCTION(scan_presets_item
, MENU_FUNC_USEPARAM
,
1626 ID2P(LANG_FM_SCAN_PRESETS
),
1627 scan_presets
, NULL
, NULL
, Icon_NOICON
);
1629 MAKE_MENU(radio_settings_menu
, ID2P(LANG_FM_MENU
), NULL
,
1632 &radio_presets_item
,
1634 #ifndef FM_PRESET_ADD
1635 &radio_addpreset_item
,
1637 &presetload_item
, &presetsave_item
, &presetclear_item
,
1642 &set_region
, &sound_settings
,
1643 #ifdef FM_RECORDING_SCREEN
1646 #ifdef FM_RECORDING_SETTINGS
1649 &scan_presets_item
);
1650 /* main menu of the radio screen */
1651 static bool radio_menu(void)
1653 return do_menu(&radio_settings_menu
, NULL
, NULL
, false) ==