1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2003 Linus Nielsen Feltzing
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
34 #include "mp3_playback.h"
45 #include "peakmeter.h"
48 #include "sound_menu.h"
50 #include "recording.h"
56 #include "screen_access.h"
57 #include "statusbar.h"
60 #include "buttonbar.h"
66 #include "menus/exported_menus.h"
67 #include "root_menu.h"
72 #if CONFIG_KEYPAD == RECORDER_PAD
75 #define FM_PRESET_ACTION
79 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
82 #define FM_NEXT_PRESET
83 #define FM_PREV_PRESET
85 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
89 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
92 /* This should be removeable if the whole tuning thing is sorted out since
93 proper tuning quiets the screen almost entirely in that extreme measures
94 have to be taken to hear any interference. */
95 #define HAVE_NOISY_IDLE_MODE
97 #elif CONFIG_KEYPAD == ONDIO_PAD
98 #define FM_RECORD_DBLPRE
100 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD)
108 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
113 #define RADIO_SCAN_MODE 0
114 #define RADIO_PRESET_MODE 1
116 static int curr_preset
= -1;
117 static int curr_freq
; /* current frequency in Hz */
118 static int radio_mode
= RADIO_SCAN_MODE
;
119 static int search_dir
= 0;
121 static int radio_status
= FMRADIO_OFF
;
122 static bool in_screen
= false;
124 #define MAX_PRESETS 64
125 static bool presets_loaded
= false, presets_changed
= false;
126 static struct fmstation presets
[MAX_PRESETS
];
128 static char filepreset
[MAX_PATH
]; /* preset filename variable */
130 static int num_presets
= 0; /* The number of presets in the preset list */
132 static void radio_save_presets(void);
133 static int handle_radio_presets(void);
134 static bool radio_menu(void);
135 static int radio_add_preset(void);
136 static int save_preset_list(void);
137 static int load_preset_list(void);
138 static int clear_preset_list(void);
140 static int scan_presets(void *viewports
);
142 /* Function to manipulate all yesno dialogues.
143 This function needs the output text as an argument. */
144 static bool yesno_pop(const char* text
)
147 const char *lines
[]={text
};
148 const struct text_message message
={lines
, 1};
149 bool ret
= (gui_syncyesno_run(&message
,NULL
,NULL
)== YESNO_YES
);
151 screens
[i
].clear_viewport();
155 void radio_init(void)
161 int get_radio_status(void)
166 bool in_radio_screen(void)
171 /* TODO: Move some more of the control functionality to firmware
172 and clean up the mess */
174 /* secret flag for starting paused - prevents unmute */
175 #define FMRADIO_START_PAUSED 0x8000
176 void radio_start(void)
178 const struct fm_region_data
*fmr
;
181 if(radio_status
== FMRADIO_PLAYING
)
184 fmr
= &fm_region_data
[global_settings
.fm_region
];
186 start_paused
= radio_status
& FMRADIO_START_PAUSED
;
187 /* clear flag before any yielding */
188 radio_status
&= ~FMRADIO_START_PAUSED
;
190 if(radio_status
== FMRADIO_OFF
)
193 curr_freq
= global_status
.last_frequency
* fmr
->freq_step
+ fmr
->freq_min
;
195 tuner_set(RADIO_SLEEP
, 0); /* wake up the tuner */
197 if(radio_status
== FMRADIO_OFF
)
199 #ifdef HAVE_RADIO_REGION
200 tuner_set(RADIO_REGION
, global_settings
.fm_region
);
202 tuner_set(RADIO_FORCE_MONO
, global_settings
.fm_force_mono
);
205 tuner_set(RADIO_FREQUENCY
, curr_freq
);
207 #ifdef HAVE_RADIO_MUTE_TIMEOUT
209 unsigned long mute_timeout
= current_tick
+ HZ
;
210 if (radio_status
!= FMRADIO_OFF
)
216 while(!tuner_get(RADIO_STEREO
) && !tuner_get(RADIO_TUNED
))
218 if(TIME_AFTER(current_tick
, mute_timeout
))
225 /* keep radio from sounding initially */
227 tuner_set(RADIO_MUTE
, 0);
229 radio_status
= FMRADIO_PLAYING
;
232 void radio_pause(void)
234 if(radio_status
== FMRADIO_PAUSED
)
237 if(radio_status
== FMRADIO_OFF
)
239 radio_status
|= FMRADIO_START_PAUSED
;
243 tuner_set(RADIO_MUTE
, 1);
244 tuner_set(RADIO_SLEEP
, 1);
246 radio_status
= FMRADIO_PAUSED
;
249 void radio_stop(void)
251 if(radio_status
== FMRADIO_OFF
)
254 tuner_set(RADIO_MUTE
, 1);
255 tuner_set(RADIO_SLEEP
, 1); /* low power mode, if available */
256 radio_status
= FMRADIO_OFF
;
257 tuner_power(false); /* status update, power off if avail. */
260 bool radio_hardware_present(void)
262 return tuner_get(RADIO_PRESENT
);
265 /* Keep freq on the grid for the current region */
266 static int snap_freq_to_grid(int freq
)
268 const struct fm_region_data
* const fmr
=
269 &fm_region_data
[global_settings
.fm_region
];
271 /* Range clamp if out of range or just round to nearest */
272 if (freq
< fmr
->freq_min
)
273 freq
= fmr
->freq_min
;
274 else if (freq
> fmr
->freq_max
)
275 freq
= fmr
->freq_max
;
277 freq
= (freq
- fmr
->freq_min
+ fmr
->freq_step
/2) /
278 fmr
->freq_step
* fmr
->freq_step
+ fmr
->freq_min
;
283 /* Find a matching preset to freq */
284 static int find_preset(int freq
)
289 for(i
= 0;i
< MAX_PRESETS
;i
++)
291 if(freq
== presets
[i
].frequency
)
298 /* Return the closest preset encountered in the search direction with
300 static int find_closest_preset(int freq
, int direction
)
307 if (direction
== 0) /* direction == 0 isn't really used */
310 for (i
= 0; i
< num_presets
; i
++)
312 int f
= presets
[i
].frequency
;
314 return i
; /* Exact match = stop */
316 /* remember the highest and lowest presets for wraparound */
317 if (f
< presets
[lowpreset
].frequency
)
319 if (f
> presets
[highpreset
].frequency
)
322 /* find the closest preset in the given direction */
323 if (direction
> 0 && f
> freq
)
325 if (closest
< 0 || f
< presets
[closest
].frequency
)
328 else if (direction
< 0 && f
< freq
)
330 if (closest
< 0 || f
> presets
[closest
].frequency
)
337 /* no presets in the given direction */
338 /* wrap around depending on direction */
340 closest
= highpreset
;
348 static void remember_frequency(void)
350 const struct fm_region_data
* const fmr
=
351 &fm_region_data
[global_settings
.fm_region
];
352 global_status
.last_frequency
= (curr_freq
- fmr
->freq_min
)
357 static void next_preset(int direction
)
362 if (curr_preset
== -1)
363 curr_preset
= find_closest_preset(curr_freq
, direction
);
365 curr_preset
= (curr_preset
+ direction
+ num_presets
) % num_presets
;
367 /* Must stay on the current grid for the region */
368 curr_freq
= snap_freq_to_grid(presets
[curr_preset
].frequency
);
370 tuner_set(RADIO_FREQUENCY
, curr_freq
);
371 remember_frequency();
374 /* Step to the next or previous frequency */
375 static int step_freq(int freq
, int direction
)
377 const struct fm_region_data
* const fmr
=
378 &fm_region_data
[global_settings
.fm_region
];
380 freq
+= direction
*fmr
->freq_step
;
382 /* Wrap first or snapping to grid will not let us on the band extremes */
383 if (freq
> fmr
->freq_max
)
384 freq
= direction
> 0 ? fmr
->freq_min
: fmr
->freq_max
;
385 else if (freq
< fmr
->freq_min
)
386 freq
= direction
< 0 ? fmr
->freq_max
: fmr
->freq_min
;
388 freq
= snap_freq_to_grid(freq
);
393 /* Step to the next or previous station */
394 static void next_station(int direction
)
396 if (direction
!= 0 && radio_mode
!= RADIO_SCAN_MODE
)
398 next_preset(direction
);
402 curr_freq
= step_freq(curr_freq
, direction
);
404 if (radio_status
== FMRADIO_PLAYING
)
405 tuner_set(RADIO_MUTE
, 1);
407 tuner_set(RADIO_FREQUENCY
, curr_freq
);
409 if (radio_status
== FMRADIO_PLAYING
)
410 tuner_set(RADIO_MUTE
, 0);
412 curr_preset
= find_preset(curr_freq
);
413 remember_frequency();
416 /* Ends an in-progress search */
417 static void end_search(void)
419 if (search_dir
!= 0 && radio_status
== FMRADIO_PLAYING
)
420 tuner_set(RADIO_MUTE
, 0);
424 /* Speak a frequency. */
425 static void talk_freq(int freq
, bool enqueue
)
428 talk_number(freq
/ 100, enqueue
);
429 talk_id(LANG_POINT
, true);
430 talk_number(freq
% 100 / 10, true);
432 talk_number(freq
% 10, true);
435 /* Speak a preset by number or by spelling its name, depending on settings. */
436 static void talk_preset(int preset
, bool fallback
, bool enqueue
)
438 if (global_settings
.talk_file
== 1) /* number */
439 talk_number(preset
+ 1, enqueue
);
442 if(presets
[preset
].name
[0])
443 talk_spell(presets
[preset
].name
, enqueue
);
445 talk_freq(presets
[preset
].frequency
, enqueue
);
449 int radio_screen(void)
453 int ret_val
= GO_TO_ROOT
;
456 bool stereo
= false, last_stereo
= false;
458 int top_of_screen
= 0;
459 bool update_screen
= true;
460 bool screen_freeze
= false;
461 bool keep_playing
= false;
463 #ifdef FM_RECORD_DBLPRE
464 int lastbutton
= BUTTON_NONE
;
465 unsigned long rec_lastclick
= 0;
467 #if CONFIG_CODEC != SWCODEC
468 bool have_recorded
= false;
469 int timeout
= current_tick
+ HZ
/10;
470 unsigned int seconds
= 0;
471 unsigned int last_seconds
= 0;
473 struct audio_recording_options rec_options
;
474 #endif /* CONFIG_CODEC != SWCODEC */
475 #ifndef HAVE_NOISY_IDLE_MODE
476 int button_timeout
= current_tick
+ (2*HZ
);
478 struct viewport vp
[NB_SCREENS
];
479 int oldbars
= 0, fmbars
= VP_SB_ALLSCREENS
;
480 #ifdef HAVE_BUTTONBAR
481 struct gui_buttonbar buttonbar
;
482 gui_buttonbar_init(&buttonbar
);
483 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
486 /* change status to "in screen" */
489 /* always display status bar in radio screen for now */
491 fmbars
|= VP_SB_IGNORE_SETTING(i
);
492 oldbars
= viewportmanager_set_statusbar(fmbars
);
495 viewport_set_defaults(&vp
[i
], i
);
496 #ifdef HAVE_BUTTONBAR
497 if (global_settings
.buttonbar
)
498 vp
[i
].height
-= BUTTONBAR_HEIGHT
;
500 screens
[i
].set_viewport(&vp
[i
]);
501 screens
[i
].stop_scroll();
502 screens
[i
].clear_viewport();
503 screens
[i
].update_viewport();
506 fh
= font_get(FONT_UI
)->height
;
508 /* Adjust for font size, trying to center the information vertically */
514 memset(presets
, 0, sizeof(presets
));
515 radio_load_presets(global_settings
.fmr_file
);
518 if(radio_status
== FMRADIO_OFF
)
522 #if CONFIG_CODEC != SWCODEC
523 if(rec_create_directory() > 0)
524 have_recorded
= true;
526 audio_init_recording(talk_get_bufsize());
528 sound_settings_apply();
529 /* Yes, we use the D/A for monitoring */
530 peak_meter_playback(true);
532 peak_meter_enabled
= true;
534 rec_init_recording_options(&rec_options
);
535 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
536 rec_set_recording_options(&rec_options
);
538 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
539 sound_default(SOUND_RIGHT_GAIN
), AUDIO_GAIN_LINEIN
);
541 #endif /* CONFIG_CODEC != SWCODEC */
542 #endif /* ndef SIMULATOR */
545 #if CONFIG_CODEC == SWCODEC
546 audio_set_input_source(AUDIO_SRC_FMRADIO
,
547 (radio_status
== FMRADIO_PAUSED
) ?
548 SRCF_FMRADIO_PAUSED
: SRCF_FMRADIO_PLAYING
);
550 if (radio_status
== FMRADIO_OFF
)
554 if(num_presets
< 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN
)))
557 curr_preset
= find_preset(curr_freq
);
558 if(curr_preset
!= -1)
559 radio_mode
= RADIO_PRESET_MODE
;
561 #ifdef HAVE_BUTTONBAR
562 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
563 str(LANG_PRESET
), str(LANG_FM_BUTTONBAR_RECORD
));
566 #ifndef HAVE_NOISY_IDLE_MODE
574 curr_freq
= step_freq(curr_freq
, search_dir
);
575 update_screen
= true;
577 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
579 curr_preset
= find_preset(curr_freq
);
580 remember_frequency();
593 #if CONFIG_CODEC != SWCODEC
594 /* TODO: Can we timeout at HZ when recording since peaks aren't
595 displayed? This should quiet recordings too. */
596 button
= get_action(CONTEXT_FM
,
597 update_screen
? TIMEOUT_NOBLOCK
: HZ
/ PEAK_METER_FPS
);
599 button
= get_action(CONTEXT_FM
,
600 update_screen
? TIMEOUT_NOBLOCK
: HZ
);
603 #ifndef HAVE_NOISY_IDLE_MODE
604 if (button
!= ACTION_NONE
)
606 cpu_idle_mode(false);
607 button_timeout
= current_tick
+ (2*HZ
);
613 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
614 if(audio_status() == AUDIO_STATUS_RECORD
)
624 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
626 if(filepreset
[0] == '\0')
629 radio_save_presets();
632 /* Clear the preset list on exit. */
635 update_screen
= true;
639 case ACTION_FM_RECORD
:
640 #ifdef FM_RECORD_DBLPRE
641 if (lastbutton
!= ACTION_FM_RECORD_DBLPRE
)
646 if (current_tick
- rec_lastclick
> HZ
/2)
648 rec_lastclick
= current_tick
;
651 #endif /* FM_RECORD_DBLPRE */
653 if(audio_status() == AUDIO_STATUS_RECORD
)
655 rec_command(RECORDING_CMD_START_NEWFILE
);
656 update_screen
= true;
660 have_recorded
= true;
661 rec_command(RECORDING_CMD_START
);
662 update_screen
= true;
664 #endif /* SIMULATOR */
667 #endif /* #ifdef FM_RECORD */
670 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
671 if(audio_status() == AUDIO_STATUS_RECORD
)
676 ret_val
= GO_TO_ROOT
;
679 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
681 if(filepreset
[0] == '\0')
684 radio_save_presets();
688 /* Clear the preset list on exit. */
693 case ACTION_STD_PREV
:
694 case ACTION_STD_NEXT
:
695 next_station(button
== ACTION_STD_PREV
? -1 : 1);
697 update_screen
= true;
701 case ACTION_STD_PREVREPEAT
:
702 case ACTION_STD_NEXTREPEAT
:
704 int dir
= search_dir
;
705 search_dir
= button
== ACTION_STD_PREVREPEAT
? -1 : 1;
706 if (radio_mode
!= RADIO_SCAN_MODE
)
708 next_preset(search_dir
);
710 update_screen
= true;
715 /* Starting auto scan */
716 tuner_set(RADIO_MUTE
, 1);
717 update_screen
= true;
722 case ACTION_SETTINGS_INC
:
723 case ACTION_SETTINGS_INCREPEAT
:
724 global_settings
.volume
++;
726 update_screen
= true;
729 case ACTION_SETTINGS_DEC
:
730 case ACTION_SETTINGS_DECREPEAT
:
731 global_settings
.volume
--;
733 update_screen
= true;
737 if (radio_status
== FMRADIO_PLAYING
)
742 update_screen
= true;
748 viewportmanager_set_statusbar(oldbars
);
750 curr_preset
= find_preset(curr_freq
);
751 viewportmanager_set_statusbar(fmbars
);
754 screens
[i
].set_viewport(&vp
[i
]);
755 screens
[i
].clear_viewport();
756 screens
[i
].update_viewport();
757 screens
[i
].set_viewport(NULL
);
759 #ifdef HAVE_BUTTONBAR
760 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
762 str(LANG_FM_BUTTONBAR_RECORD
));
764 update_screen
= true;
768 case ACTION_FM_PRESET
:
771 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
772 update_screen
= true;
775 screens
[i
].set_viewport(&vp
[i
]);
776 screens
[i
].clear_viewport();
777 screens
[i
].update_viewport();
778 screens
[i
].set_viewport(NULL
);
783 viewportmanager_set_statusbar(oldbars
);
784 handle_radio_presets();
785 viewportmanager_set_statusbar(fmbars
);
788 screens
[i
].set_viewport(&vp
[i
]);
789 screens
[i
].stop_scroll();
790 screens
[i
].clear_viewport();
791 screens
[i
].update_viewport();
792 screens
[i
].set_viewport(NULL
);
794 #ifdef HAVE_BUTTONBAR
795 gui_buttonbar_set(&buttonbar
,
796 str(LANG_BUTTONBAR_MENU
),
798 str(LANG_FM_BUTTONBAR_RECORD
));
800 update_screen
= true;
802 #endif /* FM_PRESET */
805 case ACTION_FM_FREEZE
:
808 splash(HZ
, str(LANG_FM_FREEZE
));
809 screen_freeze
= true;
813 update_screen
= true;
814 screen_freeze
= false;
817 #endif /* FM_FREEZE */
819 case SYS_USB_CONNECTED
:
820 #if CONFIG_CODEC != SWCODEC
821 /* Only accept USB connection when not recording */
822 if(audio_status() != AUDIO_STATUS_RECORD
)
825 default_event_handler(SYS_USB_CONNECTED
);
826 screen_freeze
= true; /* Cosmetic: makes sure the
827 radio screen doesn't redraw */
834 if(radio_mode
== RADIO_SCAN_MODE
)
836 /* Force scan mode if there are no presets. */
838 radio_mode
= RADIO_PRESET_MODE
;
841 radio_mode
= RADIO_SCAN_MODE
;
842 update_screen
= true;
843 cond_talk_ids_fq(radio_mode
?
844 LANG_PRESET
: LANG_RADIO_SCAN_MODE
);
849 #ifdef FM_NEXT_PRESET
850 case ACTION_FM_NEXT_PRESET
:
853 update_screen
= true;
858 #ifdef FM_PREV_PRESET
859 case ACTION_FM_PREV_PRESET
:
862 update_screen
= true;
868 default_event_handler(button
);
872 #ifdef FM_RECORD_DBLPRE
873 if (button
!= ACTION_NONE
)
877 #if CONFIG_CODEC != SWCODEC
883 /* Only display the peak meter when not recording */
884 #if CONFIG_CODEC != SWCODEC
889 screens
[i
].set_viewport(&vp
[i
]);
890 peak_meter_screen(&screens
[i
],0,
891 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
893 screens
[i
].update_rect(0,
894 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
895 screens
[i
].getwidth(), fh
);
896 screens
[i
].set_viewport(NULL
);
900 if(TIME_AFTER(current_tick
, timeout
))
902 timeout
= current_tick
+ HZ
;
905 #endif /* CONFIG_CODEC == SWCODEC */
907 /* keep "mono" from always being displayed when paused */
908 if (radio_status
!= FMRADIO_PAUSED
)
910 stereo
= tuner_get(RADIO_STEREO
) &&
911 !global_settings
.fm_force_mono
;
913 if(stereo
!= last_stereo
)
915 update_screen
= true;
916 last_stereo
= stereo
;
921 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
922 seconds
= audio_recorded_time() / HZ
;
923 if (update_screen
|| seconds
> last_seconds
)
925 last_seconds
= seconds
;
934 screens
[i
].set_viewport(&vp
[i
]);
937 snprintf(buf
, 128, curr_preset
>= 0 ? "%d. %s" : " ",
938 curr_preset
+ 1, presets
[curr_preset
].name
);
941 screens
[i
].puts_scroll(0, top_of_screen
, buf
);
943 freq
= curr_freq
/ 10000;
944 snprintf(buf
, 128, str(LANG_FM_STATION
),
945 freq
/ 100, freq
% 100);
947 screens
[i
].puts_scroll(0, top_of_screen
+ 1, buf
);
949 snprintf(buf
, 128, "%s", stereo
?str(LANG_CHANNEL_STEREO
):
950 str(LANG_CHANNEL_MONO
));
952 screens
[i
].puts_scroll(0, top_of_screen
+ 2, buf
);
954 snprintf(buf
, 128, "%s %s", str(LANG_MODE
),
955 radio_mode
? str(LANG_PRESET
) :
956 str(LANG_RADIO_SCAN_MODE
));
958 screens
[i
].puts_scroll(0, top_of_screen
+ 3, buf
);
960 #if CONFIG_CODEC != SWCODEC
961 if(audio_status() == AUDIO_STATUS_RECORD
)
963 hours
= seconds
/ 3600;
964 minutes
= (seconds
- (hours
* 3600)) / 60;
965 snprintf(buf
, 32, "%s %02d:%02d:%02d",
966 str(LANG_RECORDING_TIME
),
967 hours
, minutes
, seconds
%60);
969 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
973 if(rec_options
.rec_prerecord_time
)
975 snprintf(buf
, 32, "%s %02d",
976 str(LANG_RECORD_PRERECORD
), seconds
%60);
978 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
981 #endif /* CONFIG_CODEC != SWCODEC */
985 screens
[i
].update_viewport();
986 screens
[i
].set_viewport(NULL
);
989 #ifdef HAVE_BUTTONBAR
990 gui_buttonbar_draw(&buttonbar
);
995 update_screen
= false;
997 if (global_settings
.talk_file
&& talk
998 && radio_status
== FMRADIO_PAUSED
)
1001 bool enqueue
= false;
1002 if (radio_mode
== RADIO_SCAN_MODE
)
1004 talk_freq(curr_freq
, enqueue
);
1007 if (curr_preset
>= 0)
1008 talk_preset(curr_preset
, radio_mode
== RADIO_PRESET_MODE
,
1012 #if CONFIG_CODEC != SWCODEC
1013 if(audio_status() & AUDIO_STATUS_ERROR
)
1019 #ifndef HAVE_NOISY_IDLE_MODE
1020 if (TIME_AFTER(current_tick
, button_timeout
))
1022 cpu_idle_mode(true);
1028 #if CONFIG_CODEC != SWCODEC
1029 if(audio_status() & AUDIO_STATUS_ERROR
)
1031 splash(0, str(LANG_DISK_FULL
));
1034 screens
[i
].set_viewport(&vp
[i
]);
1035 screens
[i
].update_viewport();
1036 screens
[i
].set_viewport(NULL
);
1038 audio_error_clear();
1042 button
= get_action(CONTEXT_FM
, TIMEOUT_BLOCK
);
1043 if(button
== ACTION_FM_STOP
)
1048 audio_init_playback();
1049 #endif /* CONFIG_CODEC != SWCODEC */
1051 sound_settings_apply();
1052 #endif /* SIMULATOR */
1056 /* Catch FMRADIO_PLAYING status for the sim. */
1058 #if CONFIG_CODEC != SWCODEC
1059 /* Enable the Left and right A/D Converter */
1060 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
1061 sound_default(SOUND_RIGHT_GAIN
),
1063 mas_codec_writereg(6, 0x4000);
1066 #endif /* SIMULATOR */
1070 #if CONFIG_CODEC == SWCODEC
1071 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
1077 #ifndef HAVE_NOISY_IDLE_MODE
1078 cpu_idle_mode(false);
1081 viewportmanager_set_statusbar(oldbars
);
1083 #if CONFIG_CODEC != SWCODEC
1084 return have_recorded
;
1088 } /* radio_screen */
1090 static void radio_save_presets(void)
1095 fd
= creat(filepreset
);
1098 for(i
= 0;i
< num_presets
;i
++)
1100 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
1104 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
1105 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
1106 presets_changed
= false;
1110 splash(HZ
, ID2P(LANG_FM_PRESET_SAVE_FAILED
));
1114 void radio_load_presets(char *filename
)
1124 memset(presets
, 0, sizeof(presets
));
1127 /* No Preset in configuration. */
1128 if(filename
[0] == '\0')
1130 filepreset
[0] = '\0';
1133 /* Temporary preset, loaded until player shuts down. */
1134 else if(filename
[0] == '/')
1135 strncpy(filepreset
, filename
, sizeof(filepreset
));
1136 /* Preset from default directory. */
1138 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
1139 FMPRESET_PATH
, filename
);
1141 fd
= open_utf8(filepreset
, O_RDONLY
);
1144 while(!done
&& num_presets
< MAX_PRESETS
)
1146 rc
= read_line(fd
, buf
, 128);
1149 if(settings_parseline(buf
, &freq
, &name
))
1152 if(f
) /* For backwards compatibility */
1154 struct fmstation
* const fms
= &presets
[num_presets
];
1156 strncpy(fms
->name
, name
, MAX_FMPRESET_LEN
);
1157 fms
->name
[MAX_FMPRESET_LEN
] = '\0';
1167 else /* invalid file name? */
1168 filepreset
[0] = '\0';
1170 presets_loaded
= num_presets
> 0;
1171 presets_changed
= false;
1175 static int radio_add_preset(void)
1177 char buf
[MAX_FMPRESET_LEN
+ 1];
1179 if(num_presets
< MAX_PRESETS
)
1183 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1185 struct fmstation
* const fms
= &presets
[num_presets
];
1186 strcpy(fms
->name
, buf
);
1187 fms
->frequency
= curr_freq
;
1189 presets_changed
= true;
1190 presets_loaded
= num_presets
> 0;
1196 splash(HZ
, ID2P(LANG_FM_NO_FREE_PRESETS
));
1201 /* needed to know which preset we are edit/delete-ing */
1202 static int selected_preset
= -1;
1203 static int radio_edit_preset(void)
1205 char buf
[MAX_FMPRESET_LEN
+ 1];
1207 if (num_presets
> 0)
1209 struct fmstation
* const fms
= &presets
[selected_preset
];
1211 strcpy(buf
, fms
->name
);
1213 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1215 strcpy(fms
->name
, buf
);
1216 presets_changed
= true;
1223 static int radio_delete_preset(void)
1225 if (num_presets
> 0)
1227 struct fmstation
* const fms
= &presets
[selected_preset
];
1229 if (selected_preset
>= --num_presets
)
1230 selected_preset
= num_presets
- 1;
1232 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
1235 if (curr_preset
>= num_presets
)
1239 /* Don't ask to save when all presets are deleted. */
1240 presets_changed
= num_presets
> 0;
1242 if (!presets_changed
)
1244 /* The preset list will be cleared, switch to Scan Mode. */
1245 radio_mode
= RADIO_SCAN_MODE
;
1247 presets_loaded
= false;
1253 static int load_preset_list(void)
1255 return !rockbox_browse(FMPRESET_PATH
, SHOW_FMR
);
1258 static int save_preset_list(void)
1262 bool bad_file_name
= true;
1264 if(!dir_exists(FMPRESET_PATH
)) /* Check if there is preset folder */
1265 mkdir(FMPRESET_PATH
);
1267 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
1268 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
1270 while(bad_file_name
)
1272 if(!kbd_input(filepreset
, sizeof(filepreset
)))
1274 /* check the name: max MAX_FILENAME (20) chars */
1278 p1
= strrchr(filepreset
, '/');
1280 while((p1
) && (*p2
) && (*p2
!= '.'))
1282 len
= (int)(p2
-p1
) - 1;
1283 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
1285 /* no slash, too long or too short */
1286 splash(HZ
, ID2P(LANG_INVALID_FILENAME
));
1290 /* add correct extension (easier to always write)
1291 at this point, p2 points to 0 or the extension dot */
1293 strcat(filepreset
,".fmr");
1294 bad_file_name
= false;
1295 radio_save_presets();
1306 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
1311 static int clear_preset_list(void)
1313 /* Clear all the preset entries */
1314 memset(presets
, 0, sizeof (presets
));
1317 presets_loaded
= false;
1318 /* The preset list will be cleared switch to Scan Mode. */
1319 radio_mode
= RADIO_SCAN_MODE
;
1322 presets_changed
= false; /* Don't ask to save when clearing the list. */
1327 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1328 ID2P(LANG_FM_EDIT_PRESET
),
1329 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
1330 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1331 ID2P(LANG_FM_DELETE_PRESET
),
1332 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
1333 static int radio_preset_callback(int action
,
1334 const struct menu_item_ex
*this_item
)
1336 if (action
== ACTION_STD_OK
)
1337 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
1341 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_PRESET
),
1342 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
1343 &radio_delete_preset_item
);
1344 /* present a list of preset stations */
1345 static char * presets_get_name(int selected_item
, void *data
,
1346 char *buffer
, size_t buffer_len
)
1349 struct fmstation
*p
= &presets
[selected_item
];
1352 int freq
= p
->frequency
/ 10000;
1353 int frac
= freq
% 100;
1355 snprintf(buffer
, buffer_len
,
1356 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
1360 static int presets_speak_name(int selected_item
, void * data
)
1363 talk_preset(selected_item
, true, false);
1367 static int handle_radio_presets(void)
1369 struct gui_synclist lists
;
1371 int action
= ACTION_NONE
;
1372 #ifdef HAVE_BUTTONBAR
1373 struct gui_buttonbar buttonbar
;
1376 if(presets_loaded
== false)
1379 #ifdef HAVE_BUTTONBAR
1380 gui_buttonbar_init(&buttonbar
);
1381 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
1382 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
1383 str(LANG_FM_BUTTONBAR_EXIT
),
1384 str(LANG_FM_BUTTONBAR_ACTION
));
1385 gui_buttonbar_draw(&buttonbar
);
1387 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1, NULL
);
1388 gui_synclist_set_title(&lists
, str(LANG_PRESET
), NOICON
);
1389 gui_synclist_set_icon_callback(&lists
, NULL
);
1390 if(global_settings
.talk_file
)
1391 gui_synclist_set_voice_callback(&lists
, presets_speak_name
);
1392 gui_synclist_set_nb_items(&lists
, num_presets
);
1393 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
1394 gui_synclist_speak_item(&lists
);
1398 gui_synclist_draw(&lists
);
1399 list_do_action(CONTEXT_STD
, TIMEOUT_BLOCK
,
1400 &lists
, &action
, LIST_WRAP_UNLESS_HELD
);
1403 case ACTION_STD_MENU
:
1404 if (radio_add_preset())
1406 gui_synclist_set_nb_items(&lists
, num_presets
);
1407 gui_synclist_select_item(&lists
, num_presets
- 1);
1410 case ACTION_STD_CANCEL
:
1414 curr_preset
= gui_synclist_get_sel_pos(&lists
);
1415 curr_freq
= presets
[curr_preset
].frequency
;
1417 remember_frequency();
1421 case ACTION_STD_CONTEXT
:
1422 selected_preset
= gui_synclist_get_sel_pos(&lists
);
1423 do_menu(&handle_radio_preset_menu
, NULL
, NULL
, false);
1424 gui_synclist_set_nb_items(&lists
, num_presets
);
1425 gui_synclist_select_item(&lists
, selected_preset
);
1426 gui_synclist_speak_item(&lists
);
1429 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
1436 void toggle_mono_mode(bool mono
)
1438 tuner_set(RADIO_FORCE_MONO
, mono
);
1441 void set_radio_region(int region
)
1443 #ifdef HAVE_RADIO_REGION
1444 tuner_set(RADIO_REGION
, region
);
1447 remember_frequency();
1451 MENUITEM_SETTING(set_region
, &global_settings
.fm_region
, NULL
);
1452 MENUITEM_SETTING(force_mono
, &global_settings
.fm_force_mono
, NULL
);
1455 static char* get_mode_text(int selected_item
, void * data
, char *buffer
)
1457 (void)selected_item
;
1459 snprintf(buffer
, MAX_PATH
, "%s %s", str(LANG_MODE
),
1460 radio_mode
? str(LANG_PRESET
) :
1461 str(LANG_RADIO_SCAN_MODE
));
1464 static int toggle_radio_mode(void)
1466 radio_mode
= (radio_mode
== RADIO_SCAN_MODE
) ?
1467 RADIO_PRESET_MODE
: RADIO_SCAN_MODE
;
1470 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item
, 0,
1471 toggle_radio_mode
, NULL
,
1472 get_mode_text
, NULL
, NULL
, NULL
, Icon_NOICON
);
1475 static int scan_presets(void *viewports
)
1477 bool do_scan
= true;
1479 struct viewport
*vp
= (struct viewport
*)viewports
;
1482 screens
[i
].set_viewport(vp
?&vp
[i
]:NULL
);
1483 if(num_presets
> 0) /* Do that to avoid 2 questions. */
1484 do_scan
= yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS
));
1488 const struct fm_region_data
* const fmr
=
1489 &fm_region_data
[global_settings
.fm_region
];
1491 curr_freq
= fmr
->freq_min
;
1493 memset(presets
, 0, sizeof(presets
));
1494 tuner_set(RADIO_MUTE
, 1);
1496 while(curr_freq
<= fmr
->freq_max
)
1499 if(num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
1502 freq
= curr_freq
/ 10000;
1506 splashf(0, str(LANG_FM_SCANNING
), freq
, frac
);
1508 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
1511 presets
[num_presets
].name
[0] = '\0';
1512 presets
[num_presets
].frequency
= curr_freq
;
1516 curr_freq
+= fmr
->freq_step
;
1519 if (radio_status
== FMRADIO_PLAYING
)
1520 tuner_set(RADIO_MUTE
, 0);
1522 presets_changed
= true;
1526 screens
[i
].clear_viewport();
1527 screens
[i
].update_viewport();
1532 curr_freq
= presets
[0].frequency
;
1533 radio_mode
= RADIO_PRESET_MODE
;
1534 presets_loaded
= true;
1539 /* Wrap it to beginning or we'll be past end of band */
1540 presets_loaded
= false;
1548 #ifdef HAVE_RECORDING
1550 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1551 #define FM_RECORDING_SCREEN
1552 static int fm_recording_screen(void)
1556 /* switch recording source to FMRADIO for the duration */
1557 int rec_source
= global_settings
.rec_source
;
1558 global_settings
.rec_source
= AUDIO_SRC_FMRADIO
;
1560 ret
= recording_screen(true);
1562 /* safe to reset as changing sources is prohibited here */
1563 global_settings
.rec_source
= rec_source
;
1568 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1570 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1571 #define FM_RECORDING_SETTINGS
1572 static int fm_recording_settings(void)
1574 bool ret
= recording_menu(true);
1576 #if CONFIG_CODEC != SWCODEC
1579 struct audio_recording_options rec_options
;
1580 rec_init_recording_options(&rec_options
);
1581 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
1582 rec_set_recording_options(&rec_options
);
1589 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1590 #endif /* HAVE_RECORDING */
1592 #ifdef FM_RECORDING_SCREEN
1593 MENUITEM_FUNCTION(recscreen_item
, 0, ID2P(LANG_RECORDING
),
1594 fm_recording_screen
, NULL
, NULL
, Icon_Recording
);
1596 #ifdef FM_RECORDING_SETTINGS
1597 MENUITEM_FUNCTION(recsettings_item
, 0, ID2P(LANG_RECORDING_SETTINGS
),
1598 fm_recording_settings
, NULL
, NULL
, Icon_Recording
);
1601 MENUITEM_FUNCTION(radio_presets_item
, 0, ID2P(LANG_PRESET
),
1602 handle_radio_presets
, NULL
, NULL
, Icon_NOICON
);
1604 #ifndef FM_PRESET_ADD
1605 MENUITEM_FUNCTION(radio_addpreset_item
, 0, ID2P(LANG_FM_ADD_PRESET
),
1606 radio_add_preset
, NULL
, NULL
, Icon_NOICON
);
1610 MENUITEM_FUNCTION(presetload_item
, 0, ID2P(LANG_FM_PRESET_LOAD
),
1611 load_preset_list
, NULL
, NULL
, Icon_NOICON
);
1612 MENUITEM_FUNCTION(presetsave_item
, 0, ID2P(LANG_FM_PRESET_SAVE
),
1613 save_preset_list
, NULL
, NULL
, Icon_NOICON
);
1614 MENUITEM_FUNCTION(presetclear_item
, 0, ID2P(LANG_FM_PRESET_CLEAR
),
1615 clear_preset_list
, NULL
, NULL
, Icon_NOICON
);
1616 MENUITEM_FUNCTION(scan_presets_item
, MENU_FUNC_USEPARAM
,
1617 ID2P(LANG_FM_SCAN_PRESETS
),
1618 scan_presets
, NULL
, NULL
, Icon_NOICON
);
1620 MAKE_MENU(radio_settings_menu
, ID2P(LANG_FM_MENU
), NULL
,
1623 &radio_presets_item
,
1625 #ifndef FM_PRESET_ADD
1626 &radio_addpreset_item
,
1628 &presetload_item
, &presetsave_item
, &presetclear_item
,
1633 &set_region
, &sound_settings
,
1634 #ifdef FM_RECORDING_SCREEN
1637 #ifdef FM_RECORDING_SETTINGS
1640 &scan_presets_item
);
1641 /* main menu of the radio screen */
1642 static bool radio_menu(void)
1644 return do_menu(&radio_settings_menu
, NULL
, NULL
, false) ==