1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2003 Linus Nielsen Feltzing
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
34 #include "mp3_playback.h"
45 #include "peakmeter.h"
48 #include "sound_menu.h"
50 #include "recording.h"
56 #include "screen_access.h"
57 #include "statusbar.h"
60 #include "buttonbar.h"
66 #include "menus/exported_menus.h"
67 #include "root_menu.h"
72 #if CONFIG_KEYPAD == RECORDER_PAD
75 #define FM_PRESET_ACTION
79 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
82 #define FM_NEXT_PRESET
83 #define FM_PREV_PRESET
85 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
89 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
92 /* This should be removeable if the whole tuning thing is sorted out since
93 proper tuning quiets the screen almost entirely in that extreme measures
94 have to be taken to hear any interference. */
95 #define HAVE_NOISY_IDLE_MODE
97 #elif CONFIG_KEYPAD == ONDIO_PAD
98 #define FM_RECORD_DBLPRE
100 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD)
109 #define RADIO_SCAN_MODE 0
110 #define RADIO_PRESET_MODE 1
112 static int curr_preset
= -1;
113 static int curr_freq
;
114 static int radio_mode
= RADIO_SCAN_MODE
;
115 static int search_dir
= 0;
117 static int radio_status
= FMRADIO_OFF
;
118 static bool in_screen
= false;
120 #define MAX_PRESETS 64
121 static bool presets_loaded
= false, presets_changed
= false;
122 static struct fmstation presets
[MAX_PRESETS
];
124 static char filepreset
[MAX_PATH
]; /* preset filename variable */
126 static int num_presets
= 0; /* The number of presets in the preset list */
128 static void radio_save_presets(void);
129 static int handle_radio_presets(void);
130 static bool radio_menu(void);
131 static int radio_add_preset(void);
132 static int save_preset_list(void);
133 static int load_preset_list(void);
134 static int clear_preset_list(void);
136 static int scan_presets(void *viewports
);
138 /* Function to manipulate all yesno dialogues.
139 This function needs the output text as an argument. */
140 static bool yesno_pop(const char* text
)
143 const char *lines
[]={text
};
144 const struct text_message message
={lines
, 1};
145 bool ret
= (gui_syncyesno_run(&message
,NULL
,NULL
)== YESNO_YES
);
147 screens
[i
].clear_viewport();
151 void radio_init(void)
157 int get_radio_status(void)
162 bool in_radio_screen(void)
167 /* TODO: Move some more of the control functionality to firmware
168 and clean up the mess */
170 /* secret flag for starting paused - prevents unmute */
171 #define FMRADIO_START_PAUSED 0x8000
172 void radio_start(void)
174 const struct fm_region_data
*fmr
;
177 if(radio_status
== FMRADIO_PLAYING
)
180 fmr
= &fm_region_data
[global_settings
.fm_region
];
182 start_paused
= radio_status
& FMRADIO_START_PAUSED
;
183 /* clear flag before any yielding */
184 radio_status
&= ~FMRADIO_START_PAUSED
;
186 if(radio_status
== FMRADIO_OFF
)
189 curr_freq
= global_status
.last_frequency
* fmr
->freq_step
+ fmr
->freq_min
;
191 tuner_set(RADIO_SLEEP
, 0); /* wake up the tuner */
193 if(radio_status
== FMRADIO_OFF
)
195 #ifdef HAVE_RADIO_REGION
196 tuner_set(RADIO_REGION
, global_settings
.fm_region
);
198 tuner_set(RADIO_FORCE_MONO
, global_settings
.fm_force_mono
);
201 tuner_set(RADIO_FREQUENCY
, curr_freq
);
203 #ifdef HAVE_RADIO_MUTE_TIMEOUT
205 unsigned long mute_timeout
= current_tick
+ HZ
;
206 if (radio_status
!= FMRADIO_OFF
)
212 while(!tuner_get(RADIO_STEREO
) && !tuner_get(RADIO_TUNED
))
214 if(TIME_AFTER(current_tick
, mute_timeout
))
221 /* keep radio from sounding initially */
223 tuner_set(RADIO_MUTE
, 0);
225 radio_status
= FMRADIO_PLAYING
;
228 void radio_pause(void)
230 if(radio_status
== FMRADIO_PAUSED
)
233 if(radio_status
== FMRADIO_OFF
)
235 radio_status
|= FMRADIO_START_PAUSED
;
239 tuner_set(RADIO_MUTE
, 1);
240 tuner_set(RADIO_SLEEP
, 1);
242 radio_status
= FMRADIO_PAUSED
;
245 void radio_stop(void)
247 if(radio_status
== FMRADIO_OFF
)
250 tuner_set(RADIO_MUTE
, 1);
251 tuner_set(RADIO_SLEEP
, 1); /* low power mode, if available */
252 radio_status
= FMRADIO_OFF
;
253 tuner_power(false); /* status update, power off if avail. */
256 bool radio_hardware_present(void)
258 return tuner_get(RADIO_PRESENT
);
261 /* Keep freq on the grid for the current region */
262 static int snap_freq_to_grid(int freq
)
264 const struct fm_region_data
* const fmr
=
265 &fm_region_data
[global_settings
.fm_region
];
267 /* Range clamp if out of range or just round to nearest */
268 if (freq
< fmr
->freq_min
)
269 freq
= fmr
->freq_min
;
270 else if (freq
> fmr
->freq_max
)
271 freq
= fmr
->freq_max
;
273 freq
= (freq
- fmr
->freq_min
+ fmr
->freq_step
/2) /
274 fmr
->freq_step
* fmr
->freq_step
+ fmr
->freq_min
;
279 /* Find a matching preset to freq */
280 static int find_preset(int freq
)
285 for(i
= 0;i
< MAX_PRESETS
;i
++)
287 if(freq
== presets
[i
].frequency
)
294 /* Return the first preset encountered in the search direction with
296 static int find_closest_preset(int freq
, int direction
)
300 if (direction
== 0) /* direction == 0 isn't really used */
303 for (i
= 0; i
< MAX_PRESETS
; i
++)
305 int preset_frequency
= presets
[i
].frequency
;
307 if (preset_frequency
== freq
)
308 return i
; /* Exact match = stop */
309 /* Stop when the preset frequency exeeds freq so that we can
310 pick the correct one based on direction */
311 if (preset_frequency
> freq
)
315 /* wrap around depending on direction */
316 if (i
== 0 || i
>= num_presets
- 1)
317 i
= direction
< 0 ? num_presets
- 1 : 0;
318 else if (direction
< 0)
319 i
--; /* use previous */
324 static void remember_frequency(void)
326 const struct fm_region_data
* const fmr
=
327 &fm_region_data
[global_settings
.fm_region
];
328 global_status
.last_frequency
= (curr_freq
- fmr
->freq_min
)
333 static void next_preset(int direction
)
338 if (curr_preset
== -1)
339 curr_preset
= find_closest_preset(curr_freq
, direction
);
341 curr_preset
= (curr_preset
+ direction
+ num_presets
) % num_presets
;
343 /* Must stay on the current grid for the region */
344 curr_freq
= snap_freq_to_grid(presets
[curr_preset
].frequency
);
346 tuner_set(RADIO_FREQUENCY
, curr_freq
);
347 remember_frequency();
350 /* Step to the next or previous frequency */
351 static int step_freq(int freq
, int direction
)
353 const struct fm_region_data
* const fmr
=
354 &fm_region_data
[global_settings
.fm_region
];
356 freq
+= direction
*fmr
->freq_step
;
358 /* Wrap first or snapping to grid will not let us on the band extremes */
359 if (freq
> fmr
->freq_max
)
360 freq
= direction
> 0 ? fmr
->freq_min
: fmr
->freq_max
;
361 else if (freq
< fmr
->freq_min
)
362 freq
= direction
< 0 ? fmr
->freq_max
: fmr
->freq_min
;
364 freq
= snap_freq_to_grid(freq
);
369 /* Step to the next or previous station */
370 static void next_station(int direction
)
372 if (direction
!= 0 && radio_mode
!= RADIO_SCAN_MODE
)
374 next_preset(direction
);
378 curr_freq
= step_freq(curr_freq
, direction
);
380 if (radio_status
== FMRADIO_PLAYING
)
381 tuner_set(RADIO_MUTE
, 1);
383 tuner_set(RADIO_FREQUENCY
, curr_freq
);
385 if (radio_status
== FMRADIO_PLAYING
)
386 tuner_set(RADIO_MUTE
, 0);
388 curr_preset
= find_preset(curr_freq
);
389 remember_frequency();
392 /* Ends an in-progress search */
393 static void end_search(void)
395 if (search_dir
!= 0 && radio_status
== FMRADIO_PLAYING
)
396 tuner_set(RADIO_MUTE
, 0);
400 /* Speak a frequency. */
401 static void talk_freq(int freq
, bool enqueue
)
404 talk_number(freq
/ 100, enqueue
);
405 talk_id(LANG_POINT
, true);
406 talk_number(freq
% 100 / 10, true);
408 talk_number(freq
% 10, true);
411 /* Speak a preset by number or by spelling its name, depending on settings. */
412 static void talk_preset(int preset
, bool fallback
, bool enqueue
)
414 if (global_settings
.talk_file
== 1) /* number */
415 talk_number(preset
+ 1, enqueue
);
418 if(presets
[preset
].name
[0])
419 talk_spell(presets
[preset
].name
, enqueue
);
421 talk_freq(presets
[preset
].frequency
, enqueue
);
425 int radio_screen(void)
429 int ret_val
= GO_TO_ROOT
;
432 bool stereo
= false, last_stereo
= false;
434 int top_of_screen
= 0;
435 bool update_screen
= true;
436 bool screen_freeze
= false;
437 bool keep_playing
= false;
438 bool statusbar
= global_settings
.statusbar
;
440 #ifdef FM_RECORD_DBLPRE
441 int lastbutton
= BUTTON_NONE
;
442 unsigned long rec_lastclick
= 0;
444 #if CONFIG_CODEC != SWCODEC
445 bool have_recorded
= false;
446 int timeout
= current_tick
+ HZ
/10;
447 unsigned int seconds
= 0;
448 unsigned int last_seconds
= 0;
450 struct audio_recording_options rec_options
;
451 #endif /* CONFIG_CODEC != SWCODEC */
452 #ifndef HAVE_NOISY_IDLE_MODE
453 int button_timeout
= current_tick
+ (2*HZ
);
455 struct viewport vp
[NB_SCREENS
];
456 #ifdef HAVE_BUTTONBAR
457 struct gui_buttonbar buttonbar
;
458 gui_buttonbar_init(&buttonbar
);
459 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
462 /* change status to "in screen" */
465 /* always display status bar in radio screen for now */
466 global_status
.statusbar_forced
= statusbar
?0:1;
467 global_settings
.statusbar
= true;
468 gui_syncstatusbar_draw(&statusbars
,true);
471 viewport_set_defaults(&vp
[i
], i
);
472 #ifdef HAVE_BUTTONBAR
473 if (global_settings
.buttonbar
)
474 vp
[i
].height
-= BUTTONBAR_HEIGHT
;
476 screens
[i
].set_viewport(&vp
[i
]);
477 screens
[i
].stop_scroll();
478 screens
[i
].clear_viewport();
479 screens
[i
].update_viewport();
482 fh
= font_get(FONT_UI
)->height
;
484 /* Adjust for font size, trying to center the information vertically */
490 memset(presets
, 0, sizeof(presets
));
491 radio_load_presets(global_settings
.fmr_file
);
494 if(radio_status
== FMRADIO_OFF
)
498 #if CONFIG_CODEC != SWCODEC
499 if(rec_create_directory() > 0)
500 have_recorded
= true;
502 audio_init_recording(talk_get_bufsize());
504 sound_settings_apply();
505 /* Yes, we use the D/A for monitoring */
506 peak_meter_playback(true);
508 peak_meter_enabled
= true;
510 rec_init_recording_options(&rec_options
);
511 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
512 rec_set_recording_options(&rec_options
);
514 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
515 sound_default(SOUND_RIGHT_GAIN
), AUDIO_GAIN_LINEIN
);
517 #endif /* CONFIG_CODEC != SWCODEC */
518 #endif /* ndef SIMULATOR */
521 #if CONFIG_CODEC == SWCODEC
522 audio_set_input_source(AUDIO_SRC_FMRADIO
,
523 (radio_status
== FMRADIO_PAUSED
) ?
524 SRCF_FMRADIO_PAUSED
: SRCF_FMRADIO_PLAYING
);
526 if (radio_status
== FMRADIO_OFF
)
530 if(num_presets
< 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN
)))
533 curr_preset
= find_preset(curr_freq
);
534 if(curr_preset
!= -1)
535 radio_mode
= RADIO_PRESET_MODE
;
537 #ifdef HAVE_BUTTONBAR
538 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
539 str(LANG_PRESET
), str(LANG_FM_BUTTONBAR_RECORD
));
542 #ifndef HAVE_NOISY_IDLE_MODE
550 curr_freq
= step_freq(curr_freq
, search_dir
);
551 update_screen
= true;
553 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
555 curr_preset
= find_preset(curr_freq
);
556 remember_frequency();
569 #if CONFIG_CODEC != SWCODEC
570 /* TODO: Can we timeout at HZ when recording since peaks aren't
571 displayed? This should quiet recordings too. */
572 button
= get_action(CONTEXT_FM
,
573 update_screen
? TIMEOUT_NOBLOCK
: HZ
/ PEAK_METER_FPS
);
575 button
= get_action(CONTEXT_FM
,
576 update_screen
? TIMEOUT_NOBLOCK
: HZ
);
579 #ifndef HAVE_NOISY_IDLE_MODE
580 if (button
!= ACTION_NONE
)
582 cpu_idle_mode(false);
583 button_timeout
= current_tick
+ (2*HZ
);
589 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
590 if(audio_status() == AUDIO_STATUS_RECORD
)
600 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
602 if(filepreset
[0] == '\0')
605 radio_save_presets();
608 /* Clear the preset list on exit. */
611 update_screen
= true;
615 case ACTION_FM_RECORD
:
616 #ifdef FM_RECORD_DBLPRE
617 if (lastbutton
!= ACTION_FM_RECORD_DBLPRE
)
622 if (current_tick
- rec_lastclick
> HZ
/2)
624 rec_lastclick
= current_tick
;
627 #endif /* FM_RECORD_DBLPRE */
629 if(audio_status() == AUDIO_STATUS_RECORD
)
631 rec_command(RECORDING_CMD_START_NEWFILE
);
632 update_screen
= true;
636 have_recorded
= true;
637 rec_command(RECORDING_CMD_START
);
638 update_screen
= true;
640 #endif /* SIMULATOR */
643 #endif /* #ifdef FM_RECORD */
646 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
647 if(audio_status() == AUDIO_STATUS_RECORD
)
652 ret_val
= GO_TO_ROOT
;
655 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
657 if(filepreset
[0] == '\0')
660 radio_save_presets();
664 /* Clear the preset list on exit. */
669 case ACTION_STD_PREV
:
670 case ACTION_STD_NEXT
:
671 next_station(button
== ACTION_STD_PREV
? -1 : 1);
673 update_screen
= true;
677 case ACTION_STD_PREVREPEAT
:
678 case ACTION_STD_NEXTREPEAT
:
680 int dir
= search_dir
;
681 search_dir
= button
== ACTION_STD_PREVREPEAT
? -1 : 1;
682 if (radio_mode
!= RADIO_SCAN_MODE
)
684 next_preset(search_dir
);
686 update_screen
= true;
691 /* Starting auto scan */
692 tuner_set(RADIO_MUTE
, 1);
693 update_screen
= true;
698 case ACTION_SETTINGS_INC
:
699 case ACTION_SETTINGS_INCREPEAT
:
700 global_settings
.volume
++;
702 update_screen
= true;
705 case ACTION_SETTINGS_DEC
:
706 case ACTION_SETTINGS_DECREPEAT
:
707 global_settings
.volume
--;
709 update_screen
= true;
713 if (radio_status
== FMRADIO_PLAYING
)
718 update_screen
= true;
725 curr_preset
= find_preset(curr_freq
);
728 screens
[i
].set_viewport(&vp
[i
]);
729 screens
[i
].clear_viewport();
730 screens
[i
].update_viewport();
731 screens
[i
].set_viewport(NULL
);
733 #ifdef HAVE_BUTTONBAR
734 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
736 str(LANG_FM_BUTTONBAR_RECORD
));
738 update_screen
= true;
742 case ACTION_FM_PRESET
:
745 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
746 update_screen
= true;
749 screens
[i
].set_viewport(&vp
[i
]);
750 screens
[i
].clear_viewport();
751 screens
[i
].update_viewport();
752 screens
[i
].set_viewport(NULL
);
757 handle_radio_presets();
760 screens
[i
].set_viewport(&vp
[i
]);
761 screens
[i
].clear_viewport();
762 screens
[i
].update_viewport();
763 screens
[i
].set_viewport(NULL
);
765 #ifdef HAVE_BUTTONBAR
766 gui_buttonbar_set(&buttonbar
,
767 str(LANG_BUTTONBAR_MENU
),
769 str(LANG_FM_BUTTONBAR_RECORD
));
771 update_screen
= true;
773 #endif /* FM_PRESET */
776 case ACTION_FM_FREEZE
:
779 splash(HZ
, str(LANG_FM_FREEZE
));
780 screen_freeze
= true;
784 update_screen
= true;
785 screen_freeze
= false;
788 #endif /* FM_FREEZE */
790 case SYS_USB_CONNECTED
:
791 #if CONFIG_CODEC != SWCODEC
792 /* Only accept USB connection when not recording */
793 if(audio_status() != AUDIO_STATUS_RECORD
)
796 default_event_handler(SYS_USB_CONNECTED
);
797 screen_freeze
= true; /* Cosmetic: makes sure the
798 radio screen doesn't redraw */
805 if(radio_mode
== RADIO_SCAN_MODE
)
807 /* Force scan mode if there are no presets. */
809 radio_mode
= RADIO_PRESET_MODE
;
812 radio_mode
= RADIO_SCAN_MODE
;
813 update_screen
= true;
814 cond_talk_ids_fq(radio_mode
?
815 LANG_PRESET
: LANG_RADIO_SCAN_MODE
);
820 #ifdef FM_NEXT_PRESET
821 case ACTION_FM_NEXT_PRESET
:
824 update_screen
= true;
829 #ifdef FM_PREV_PRESET
830 case ACTION_FM_PREV_PRESET
:
833 update_screen
= true;
839 default_event_handler(button
);
843 #ifdef FM_RECORD_DBLPRE
844 if (button
!= ACTION_NONE
)
848 #if CONFIG_CODEC != SWCODEC
854 /* Only display the peak meter when not recording */
855 #if CONFIG_CODEC != SWCODEC
860 screens
[i
].set_viewport(&vp
[i
]);
861 peak_meter_screen(&screens
[i
],0,
862 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
864 screens
[i
].update_rect(0,
865 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
866 screens
[i
].getwidth(), fh
);
867 screens
[i
].set_viewport(NULL
);
871 if(TIME_AFTER(current_tick
, timeout
))
873 timeout
= current_tick
+ HZ
;
876 #endif /* CONFIG_CODEC == SWCODEC */
878 /* keep "mono" from always being displayed when paused */
879 if (radio_status
!= FMRADIO_PAUSED
)
881 stereo
= tuner_get(RADIO_STEREO
) &&
882 !global_settings
.fm_force_mono
;
884 if(stereo
!= last_stereo
)
886 update_screen
= true;
887 last_stereo
= stereo
;
892 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
893 seconds
= audio_recorded_time() / HZ
;
894 if (update_screen
|| seconds
> last_seconds
)
896 last_seconds
= seconds
;
905 screens
[i
].set_viewport(&vp
[i
]);
908 snprintf(buf
, 128, curr_preset
>= 0 ? "%d. %s" : " ",
909 curr_preset
+ 1, presets
[curr_preset
].name
);
912 screens
[i
].puts_scroll(0, top_of_screen
, buf
);
914 freq
= curr_freq
/ 10000;
915 snprintf(buf
, 128, str(LANG_FM_STATION
),
916 freq
/ 100, freq
% 100);
918 screens
[i
].puts_scroll(0, top_of_screen
+ 1, buf
);
920 snprintf(buf
, 128, "%s", stereo
?str(LANG_CHANNEL_STEREO
):
921 str(LANG_CHANNEL_MONO
));
923 screens
[i
].puts_scroll(0, top_of_screen
+ 2, buf
);
925 snprintf(buf
, 128, "%s %s", str(LANG_MODE
),
926 radio_mode
? str(LANG_PRESET
) :
927 str(LANG_RADIO_SCAN_MODE
));
929 screens
[i
].puts_scroll(0, top_of_screen
+ 3, buf
);
931 #if CONFIG_CODEC != SWCODEC
932 if(audio_status() == AUDIO_STATUS_RECORD
)
934 hours
= seconds
/ 3600;
935 minutes
= (seconds
- (hours
* 3600)) / 60;
936 snprintf(buf
, 32, "%s %02d:%02d:%02d",
937 str(LANG_RECORDING_TIME
),
938 hours
, minutes
, seconds
%60);
940 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
944 if(rec_options
.rec_prerecord_time
)
946 snprintf(buf
, 32, "%s %02d",
947 str(LANG_RECORD_PRERECORD
), seconds
%60);
949 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
952 #endif /* CONFIG_CODEC != SWCODEC */
956 screens
[i
].update_viewport();
957 screens
[i
].set_viewport(NULL
);
960 #ifdef HAVE_BUTTONBAR
961 gui_buttonbar_draw(&buttonbar
);
964 /* Only force the redraw if update_screen is true */
965 gui_syncstatusbar_draw(&statusbars
,true);
968 update_screen
= false;
970 if (global_settings
.talk_file
&& talk
971 && radio_status
== FMRADIO_PAUSED
)
974 bool enqueue
= false;
975 if (radio_mode
== RADIO_SCAN_MODE
)
977 talk_freq(curr_freq
, enqueue
);
980 if (curr_preset
>= 0)
981 talk_preset(curr_preset
, radio_mode
== RADIO_PRESET_MODE
,
985 #if CONFIG_CODEC != SWCODEC
986 if(audio_status() & AUDIO_STATUS_ERROR
)
992 #ifndef HAVE_NOISY_IDLE_MODE
993 if (TIME_AFTER(current_tick
, button_timeout
))
1001 #if CONFIG_CODEC != SWCODEC
1002 if(audio_status() & AUDIO_STATUS_ERROR
)
1004 splash(0, str(LANG_DISK_FULL
));
1005 gui_syncstatusbar_draw(&statusbars
,true);
1008 screens
[i
].set_viewport(&vp
[i
]);
1009 screens
[i
].update_viewport();
1010 screens
[i
].set_viewport(NULL
);
1012 audio_error_clear();
1016 button
= get_action(CONTEXT_FM
, TIMEOUT_BLOCK
);
1017 if(button
== ACTION_FM_STOP
)
1022 audio_init_playback();
1023 #endif /* CONFIG_CODEC != SWCODEC */
1025 sound_settings_apply();
1026 #endif /* SIMULATOR */
1030 /* Catch FMRADIO_PLAYING status for the sim. */
1032 #if CONFIG_CODEC != SWCODEC
1033 /* Enable the Left and right A/D Converter */
1034 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
1035 sound_default(SOUND_RIGHT_GAIN
),
1037 mas_codec_writereg(6, 0x4000);
1040 #endif /* SIMULATOR */
1044 #if CONFIG_CODEC == SWCODEC
1045 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
1051 #ifndef HAVE_NOISY_IDLE_MODE
1052 cpu_idle_mode(false);
1055 /* restore status bar settings */
1056 global_settings
.statusbar
= statusbar
;
1057 global_status
.statusbar_forced
= 0;
1059 #if CONFIG_CODEC != SWCODEC
1060 return have_recorded
;
1064 } /* radio_screen */
1066 static void radio_save_presets(void)
1071 fd
= creat(filepreset
);
1074 for(i
= 0;i
< num_presets
;i
++)
1076 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
1080 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
1081 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
1082 presets_changed
= false;
1086 splash(HZ
, ID2P(LANG_FM_PRESET_SAVE_FAILED
));
1090 void radio_load_presets(char *filename
)
1100 memset(presets
, 0, sizeof(presets
));
1103 /* No Preset in configuration. */
1104 if(filename
[0] == '\0')
1106 filepreset
[0] = '\0';
1109 /* Temporary preset, loaded until player shuts down. */
1110 else if(filename
[0] == '/')
1111 strncpy(filepreset
, filename
, sizeof(filepreset
));
1112 /* Preset from default directory. */
1114 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
1115 FMPRESET_PATH
, filename
);
1117 fd
= open_utf8(filepreset
, O_RDONLY
);
1120 while(!done
&& num_presets
< MAX_PRESETS
)
1122 rc
= read_line(fd
, buf
, 128);
1125 if(settings_parseline(buf
, &freq
, &name
))
1128 if(f
) /* For backwards compatibility */
1130 struct fmstation
* const fms
= &presets
[num_presets
];
1132 strncpy(fms
->name
, name
, MAX_FMPRESET_LEN
);
1133 fms
->name
[MAX_FMPRESET_LEN
] = '\0';
1143 else /* invalid file name? */
1144 filepreset
[0] = '\0';
1146 presets_loaded
= num_presets
> 0;
1147 presets_changed
= false;
1151 static int radio_add_preset(void)
1153 char buf
[MAX_FMPRESET_LEN
+ 1];
1155 if(num_presets
< MAX_PRESETS
)
1157 memset(buf
, 0, MAX_FMPRESET_LEN
);
1159 if (!kbd_input(buf
, MAX_FMPRESET_LEN
))
1161 struct fmstation
* const fms
= &presets
[num_presets
];
1162 buf
[MAX_FMPRESET_LEN
] = '\0';
1163 strcpy(fms
->name
, buf
);
1164 fms
->frequency
= curr_freq
;
1166 presets_changed
= true;
1167 presets_loaded
= num_presets
> 0;
1172 splash(HZ
, ID2P(LANG_FM_NO_FREE_PRESETS
));
1177 /* needed to know which preset we are edit/delete-ing */
1178 static int selected_preset
= -1;
1179 static int radio_edit_preset(void)
1181 char buf
[MAX_FMPRESET_LEN
+ 1];
1183 if (num_presets
> 0)
1185 struct fmstation
* const fms
= &presets
[selected_preset
];
1187 strncpy(buf
, fms
->name
, MAX_FMPRESET_LEN
);
1189 if (!kbd_input(buf
, MAX_FMPRESET_LEN
))
1191 buf
[MAX_FMPRESET_LEN
] = '\0';
1192 strcpy(fms
->name
, buf
);
1193 presets_changed
= true;
1200 static int radio_delete_preset(void)
1202 if (num_presets
> 0)
1204 struct fmstation
* const fms
= &presets
[selected_preset
];
1206 if (selected_preset
>= --num_presets
)
1207 selected_preset
= num_presets
- 1;
1209 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
1214 /* Don't ask to save when all presets are deleted. */
1215 presets_changed
= num_presets
> 0;
1217 if (!presets_changed
)
1219 /* The preset list will be cleared, switch to Scan Mode. */
1220 radio_mode
= RADIO_SCAN_MODE
;
1221 presets_loaded
= false;
1227 static int load_preset_list(void)
1229 return !rockbox_browse(FMPRESET_PATH
, SHOW_FMR
);
1232 static int save_preset_list(void)
1236 bool bad_file_name
= true;
1238 if(!dir_exists(FMPRESET_PATH
)) /* Check if there is preset folder */
1239 mkdir(FMPRESET_PATH
);
1241 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
1242 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
1244 while(bad_file_name
)
1246 if(!kbd_input(filepreset
, sizeof(filepreset
)))
1248 /* check the name: max MAX_FILENAME (20) chars */
1252 p1
= strrchr(filepreset
, '/');
1254 while((p1
) && (*p2
) && (*p2
!= '.'))
1256 len
= (int)(p2
-p1
) - 1;
1257 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
1259 /* no slash, too long or too short */
1260 splash(HZ
, ID2P(LANG_INVALID_FILENAME
));
1264 /* add correct extension (easier to always write)
1265 at this point, p2 points to 0 or the extension dot */
1267 strcat(filepreset
,".fmr");
1268 bad_file_name
= false;
1269 radio_save_presets();
1280 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
1285 static int clear_preset_list(void)
1287 /* Clear all the preset entries */
1288 memset(presets
, 0, sizeof (presets
));
1291 presets_loaded
= false;
1292 /* The preset list will be cleared switch to Scan Mode. */
1293 radio_mode
= RADIO_SCAN_MODE
;
1295 presets_changed
= false; /* Don't ask to save when clearing the list. */
1300 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1301 ID2P(LANG_FM_EDIT_PRESET
),
1302 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
1303 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1304 ID2P(LANG_FM_DELETE_PRESET
),
1305 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
1306 static int radio_preset_callback(int action
,
1307 const struct menu_item_ex
*this_item
)
1309 if (action
== ACTION_STD_OK
)
1310 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
1314 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_PRESET
),
1315 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
1316 &radio_delete_preset_item
);
1317 /* present a list of preset stations */
1318 static char * presets_get_name(int selected_item
, void *data
,
1319 char *buffer
, size_t buffer_len
)
1322 struct fmstation
*p
= &presets
[selected_item
];
1325 int freq
= p
->frequency
/ 10000;
1326 int frac
= freq
% 100;
1328 snprintf(buffer
, buffer_len
,
1329 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
1333 static int presets_speak_name(int selected_item
, void * data
)
1336 talk_preset(selected_item
, true, false);
1340 static int handle_radio_presets(void)
1342 struct gui_synclist lists
;
1344 int action
= ACTION_NONE
;
1345 #ifdef HAVE_BUTTONBAR
1346 struct gui_buttonbar buttonbar
;
1349 if(presets_loaded
== false)
1352 #ifdef HAVE_BUTTONBAR
1353 gui_buttonbar_init(&buttonbar
);
1354 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
1355 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
1356 str(LANG_FM_BUTTONBAR_EXIT
),
1357 str(LANG_FM_BUTTONBAR_ACTION
));
1358 gui_buttonbar_draw(&buttonbar
);
1360 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1, NULL
);
1361 gui_synclist_set_title(&lists
, str(LANG_PRESET
), NOICON
);
1362 gui_synclist_set_icon_callback(&lists
, NULL
);
1363 if(global_settings
.talk_file
)
1364 gui_synclist_set_voice_callback(&lists
, presets_speak_name
);
1365 gui_synclist_set_nb_items(&lists
, num_presets
);
1366 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
1367 gui_synclist_speak_item(&lists
);
1371 gui_synclist_draw(&lists
);
1372 gui_syncstatusbar_draw(&statusbars
, true);
1373 list_do_action(CONTEXT_STD
, HZ
,
1374 &lists
, &action
, LIST_WRAP_UNLESS_HELD
);
1377 case ACTION_STD_MENU
:
1380 case ACTION_STD_CANCEL
:
1384 curr_preset
= gui_synclist_get_sel_pos(&lists
);
1385 curr_freq
= presets
[curr_preset
].frequency
;
1387 remember_frequency();
1391 case ACTION_STD_CONTEXT
:
1392 selected_preset
= gui_synclist_get_sel_pos(&lists
);
1393 do_menu(&handle_radio_preset_menu
, NULL
, NULL
, false);
1394 gui_synclist_set_nb_items(&lists
, num_presets
);
1395 gui_synclist_select_item(&lists
, selected_preset
);
1396 gui_synclist_speak_item(&lists
);
1399 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
1406 void toggle_mono_mode(bool mono
)
1408 tuner_set(RADIO_FORCE_MONO
, mono
);
1411 void set_radio_region(int region
)
1413 #ifdef HAVE_RADIO_REGION
1414 tuner_set(RADIO_REGION
, region
);
1417 remember_frequency();
1421 MENUITEM_SETTING(set_region
, &global_settings
.fm_region
, NULL
);
1422 MENUITEM_SETTING(force_mono
, &global_settings
.fm_force_mono
, NULL
);
1425 static char* get_mode_text(int selected_item
, void * data
, char *buffer
)
1427 (void)selected_item
;
1429 snprintf(buffer
, MAX_PATH
, "%s %s", str(LANG_MODE
),
1430 radio_mode
? str(LANG_PRESET
) :
1431 str(LANG_RADIO_SCAN_MODE
));
1434 static int toggle_radio_mode(void)
1436 radio_mode
= (radio_mode
== RADIO_SCAN_MODE
) ?
1437 RADIO_PRESET_MODE
: RADIO_SCAN_MODE
;
1440 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item
, 0,
1441 toggle_radio_mode
, NULL
,
1442 get_mode_text
, NULL
, NULL
, NULL
, Icon_NOICON
);
1445 static int scan_presets(void *viewports
)
1447 bool do_scan
= true;
1449 struct viewport
*vp
= (struct viewport
*)viewports
;
1452 screens
[i
].set_viewport(vp
?&vp
[i
]:NULL
);
1453 if(num_presets
> 0) /* Do that to avoid 2 questions. */
1454 do_scan
= yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS
));
1458 const struct fm_region_data
* const fmr
=
1459 &fm_region_data
[global_settings
.fm_region
];
1461 curr_freq
= fmr
->freq_min
;
1463 memset(presets
, 0, sizeof(presets
));
1464 tuner_set(RADIO_MUTE
, 1);
1466 while(curr_freq
<= fmr
->freq_max
)
1469 if(num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
1472 freq
= curr_freq
/ 10000;
1476 splashf(0, str(LANG_FM_SCANNING
), freq
, frac
);
1478 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
1481 presets
[num_presets
].name
[0] = '\0';
1482 presets
[num_presets
].frequency
= curr_freq
;
1486 curr_freq
+= fmr
->freq_step
;
1489 if (radio_status
== FMRADIO_PLAYING
)
1490 tuner_set(RADIO_MUTE
, 0);
1492 presets_changed
= true;
1496 screens
[i
].clear_viewport();
1497 screens
[i
].update_viewport();
1502 curr_freq
= presets
[0].frequency
;
1503 radio_mode
= RADIO_PRESET_MODE
;
1504 presets_loaded
= true;
1509 /* Wrap it to beginning or we'll be past end of band */
1510 presets_loaded
= false;
1518 #ifdef HAVE_RECORDING
1520 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1521 #define FM_RECORDING_SCREEN
1522 static int fm_recording_screen(void)
1526 /* switch recording source to FMRADIO for the duration */
1527 int rec_source
= global_settings
.rec_source
;
1528 global_settings
.rec_source
= AUDIO_SRC_FMRADIO
;
1530 ret
= recording_screen(true);
1532 /* safe to reset as changing sources is prohibited here */
1533 global_settings
.rec_source
= rec_source
;
1538 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1540 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1541 #define FM_RECORDING_SETTINGS
1542 static int fm_recording_settings(void)
1544 bool ret
= recording_menu(true);
1546 #if CONFIG_CODEC != SWCODEC
1549 struct audio_recording_options rec_options
;
1550 rec_init_recording_options(&rec_options
);
1551 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
1552 rec_set_recording_options(&rec_options
);
1559 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1560 #endif /* HAVE_RECORDING */
1562 #ifdef FM_RECORDING_SCREEN
1563 MENUITEM_FUNCTION(recscreen_item
, 0, ID2P(LANG_RECORDING
),
1564 fm_recording_screen
, NULL
, NULL
, Icon_Recording
);
1566 #ifdef FM_RECORDING_SETTINGS
1567 MENUITEM_FUNCTION(recsettings_item
, 0, ID2P(LANG_RECORDING_SETTINGS
),
1568 fm_recording_settings
, NULL
, NULL
, Icon_Recording
);
1571 MENUITEM_FUNCTION(radio_presets_item
, 0, ID2P(LANG_PRESET
),
1572 handle_radio_presets
, NULL
, NULL
, Icon_NOICON
);
1574 #ifndef FM_PRESET_ADD
1575 MENUITEM_FUNCTION(radio_addpreset_item
, 0, ID2P(LANG_FM_ADD_PRESET
),
1576 radio_add_preset
, NULL
, NULL
, Icon_NOICON
);
1580 MENUITEM_FUNCTION(presetload_item
, 0, ID2P(LANG_FM_PRESET_LOAD
),
1581 load_preset_list
, NULL
, NULL
, Icon_NOICON
);
1582 MENUITEM_FUNCTION(presetsave_item
, 0, ID2P(LANG_FM_PRESET_SAVE
),
1583 save_preset_list
, NULL
, NULL
, Icon_NOICON
);
1584 MENUITEM_FUNCTION(presetclear_item
, 0, ID2P(LANG_FM_PRESET_CLEAR
),
1585 clear_preset_list
, NULL
, NULL
, Icon_NOICON
);
1586 MENUITEM_FUNCTION(scan_presets_item
, MENU_FUNC_USEPARAM
,
1587 ID2P(LANG_FM_SCAN_PRESETS
),
1588 scan_presets
, NULL
, NULL
, Icon_NOICON
);
1590 MAKE_MENU(radio_settings_menu
, ID2P(LANG_FM_MENU
), NULL
,
1593 &radio_presets_item
,
1595 #ifndef FM_PRESET_ADD
1596 &radio_addpreset_item
,
1598 &presetload_item
, &presetsave_item
, &presetclear_item
,
1603 &set_region
, &sound_settings
,
1604 #ifdef FM_RECORDING_SCREEN
1607 #ifdef FM_RECORDING_SETTINGS
1610 &scan_presets_item
);
1611 /* main menu of the radio screen */
1612 static bool radio_menu(void)
1614 return do_menu(&radio_settings_menu
, NULL
, NULL
, false) ==