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 ****************************************************************************/
33 #include "mp3_playback.h"
45 #include "peakmeter.h"
48 #include "sound_menu.h"
50 #include "recording.h"
52 #ifdef IPOD_ACCESSORY_PROTOCOL
59 #include "screen_access.h"
62 #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 == COWON_D2_PAD)
121 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
122 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
131 #define RADIO_SCAN_MODE 0
132 #define RADIO_PRESET_MODE 1
134 static int curr_preset
= -1;
135 static int curr_freq
; /* current frequency in Hz */
136 static int radio_mode
= RADIO_SCAN_MODE
;
137 static int search_dir
= 0;
139 static int radio_status
= FMRADIO_OFF
;
140 static bool in_screen
= false;
142 #define MAX_PRESETS 64
143 static bool presets_loaded
= false, presets_changed
= false;
144 static struct fmstation presets
[MAX_PRESETS
];
146 static char filepreset
[MAX_PATH
]; /* preset filename variable */
148 static int num_presets
= 0; /* The number of presets in the preset list */
150 static void radio_save_presets(void);
151 static int handle_radio_presets(void);
152 static bool radio_menu(void);
153 static int radio_add_preset(void);
154 static int save_preset_list(void);
155 static int load_preset_list(void);
156 static int clear_preset_list(void);
158 static int scan_presets(void *viewports
);
160 /* Function to manipulate all yesno dialogues.
161 This function needs the output text as an argument. */
162 static bool yesno_pop(const char* text
)
165 const char *lines
[]={text
};
166 const struct text_message message
={lines
, 1};
167 bool ret
= (gui_syncyesno_run(&message
,NULL
,NULL
)== YESNO_YES
);
169 screens
[i
].clear_viewport();
173 void radio_init(void)
179 int get_radio_status(void)
184 bool in_radio_screen(void)
189 /* TODO: Move some more of the control functionality to firmware
190 and clean up the mess */
192 /* secret flag for starting paused - prevents unmute */
193 #define FMRADIO_START_PAUSED 0x8000
194 void radio_start(void)
196 const struct fm_region_data
*fmr
;
199 if(radio_status
== FMRADIO_PLAYING
)
202 fmr
= &fm_region_data
[global_settings
.fm_region
];
204 start_paused
= radio_status
& FMRADIO_START_PAUSED
;
205 /* clear flag before any yielding */
206 radio_status
&= ~FMRADIO_START_PAUSED
;
208 if(radio_status
== FMRADIO_OFF
)
211 curr_freq
= global_status
.last_frequency
* fmr
->freq_step
+ fmr
->freq_min
;
213 tuner_set(RADIO_SLEEP
, 0); /* wake up the tuner */
215 if(radio_status
== FMRADIO_OFF
)
217 #ifdef HAVE_RADIO_REGION
218 tuner_set(RADIO_REGION
, global_settings
.fm_region
);
220 tuner_set(RADIO_FORCE_MONO
, global_settings
.fm_force_mono
);
223 tuner_set(RADIO_FREQUENCY
, curr_freq
);
225 #ifdef HAVE_RADIO_MUTE_TIMEOUT
227 unsigned long mute_timeout
= current_tick
+ HZ
;
228 if (radio_status
!= FMRADIO_OFF
)
234 while(!tuner_get(RADIO_STEREO
) && !tuner_get(RADIO_TUNED
))
236 if(TIME_AFTER(current_tick
, mute_timeout
))
243 /* keep radio from sounding initially */
245 tuner_set(RADIO_MUTE
, 0);
247 radio_status
= FMRADIO_PLAYING
;
250 void radio_pause(void)
252 if(radio_status
== FMRADIO_PAUSED
)
255 if(radio_status
== FMRADIO_OFF
)
257 radio_status
|= FMRADIO_START_PAUSED
;
261 tuner_set(RADIO_MUTE
, 1);
262 tuner_set(RADIO_SLEEP
, 1);
264 radio_status
= FMRADIO_PAUSED
;
267 void radio_stop(void)
269 if(radio_status
== FMRADIO_OFF
)
272 tuner_set(RADIO_MUTE
, 1);
273 tuner_set(RADIO_SLEEP
, 1); /* low power mode, if available */
274 radio_status
= FMRADIO_OFF
;
275 tuner_power(false); /* status update, power off if avail. */
278 bool radio_hardware_present(void)
280 return tuner_get(RADIO_PRESENT
);
283 /* Keep freq on the grid for the current region */
284 static int snap_freq_to_grid(int freq
)
286 const struct fm_region_data
* const fmr
=
287 &fm_region_data
[global_settings
.fm_region
];
289 /* Range clamp if out of range or just round to nearest */
290 if (freq
< fmr
->freq_min
)
291 freq
= fmr
->freq_min
;
292 else if (freq
> fmr
->freq_max
)
293 freq
= fmr
->freq_max
;
295 freq
= (freq
- fmr
->freq_min
+ fmr
->freq_step
/2) /
296 fmr
->freq_step
* fmr
->freq_step
+ fmr
->freq_min
;
301 /* Find a matching preset to freq */
302 static int find_preset(int freq
)
307 for(i
= 0;i
< MAX_PRESETS
;i
++)
309 if(freq
== presets
[i
].frequency
)
316 /* Return the closest preset encountered in the search direction with
318 static int find_closest_preset(int freq
, int direction
)
325 if (direction
== 0) /* direction == 0 isn't really used */
328 for (i
= 0; i
< num_presets
; i
++)
330 int f
= presets
[i
].frequency
;
332 return i
; /* Exact match = stop */
334 /* remember the highest and lowest presets for wraparound */
335 if (f
< presets
[lowpreset
].frequency
)
337 if (f
> presets
[highpreset
].frequency
)
340 /* find the closest preset in the given direction */
341 if (direction
> 0 && f
> freq
)
343 if (closest
< 0 || f
< presets
[closest
].frequency
)
346 else if (direction
< 0 && f
< freq
)
348 if (closest
< 0 || f
> presets
[closest
].frequency
)
355 /* no presets in the given direction */
356 /* wrap around depending on direction */
358 closest
= highpreset
;
366 static void remember_frequency(void)
368 const struct fm_region_data
* const fmr
=
369 &fm_region_data
[global_settings
.fm_region
];
370 global_status
.last_frequency
= (curr_freq
- fmr
->freq_min
)
375 static void next_preset(int direction
)
380 if (curr_preset
== -1)
381 curr_preset
= find_closest_preset(curr_freq
, direction
);
383 curr_preset
= (curr_preset
+ direction
+ num_presets
) % num_presets
;
385 /* Must stay on the current grid for the region */
386 curr_freq
= snap_freq_to_grid(presets
[curr_preset
].frequency
);
388 tuner_set(RADIO_FREQUENCY
, curr_freq
);
389 remember_frequency();
392 /* Step to the next or previous frequency */
393 static int step_freq(int freq
, int direction
)
395 const struct fm_region_data
* const fmr
=
396 &fm_region_data
[global_settings
.fm_region
];
398 freq
+= direction
*fmr
->freq_step
;
400 /* Wrap first or snapping to grid will not let us on the band extremes */
401 if (freq
> fmr
->freq_max
)
402 freq
= direction
> 0 ? fmr
->freq_min
: fmr
->freq_max
;
403 else if (freq
< fmr
->freq_min
)
404 freq
= direction
< 0 ? fmr
->freq_max
: fmr
->freq_min
;
406 freq
= snap_freq_to_grid(freq
);
411 /* Step to the next or previous station */
412 static void next_station(int direction
)
414 if (direction
!= 0 && radio_mode
!= RADIO_SCAN_MODE
)
416 next_preset(direction
);
420 curr_freq
= step_freq(curr_freq
, direction
);
422 if (radio_status
== FMRADIO_PLAYING
)
423 tuner_set(RADIO_MUTE
, 1);
425 tuner_set(RADIO_FREQUENCY
, curr_freq
);
427 if (radio_status
== FMRADIO_PLAYING
)
428 tuner_set(RADIO_MUTE
, 0);
430 curr_preset
= find_preset(curr_freq
);
431 remember_frequency();
434 /* Ends an in-progress search */
435 static void end_search(void)
437 if (search_dir
!= 0 && radio_status
== FMRADIO_PLAYING
)
438 tuner_set(RADIO_MUTE
, 0);
442 /* Speak a frequency. */
443 static void talk_freq(int freq
, bool enqueue
)
446 talk_number(freq
/ 100, enqueue
);
447 talk_id(LANG_POINT
, true);
448 talk_number(freq
% 100 / 10, true);
450 talk_number(freq
% 10, true);
453 /* Speak a preset by number or by spelling its name, depending on settings. */
454 static void talk_preset(int preset
, bool fallback
, bool enqueue
)
456 if (global_settings
.talk_file
== 1) /* number */
457 talk_number(preset
+ 1, enqueue
);
460 if(presets
[preset
].name
[0])
461 talk_spell(presets
[preset
].name
, enqueue
);
463 talk_freq(presets
[preset
].frequency
, enqueue
);
467 int radio_screen(void)
471 int ret_val
= GO_TO_ROOT
;
474 bool stereo
= false, last_stereo
= false;
476 int top_of_screen
= 0;
477 bool update_screen
= true;
478 bool screen_freeze
= false;
479 bool keep_playing
= false;
481 #ifdef FM_RECORD_DBLPRE
482 int lastbutton
= BUTTON_NONE
;
483 unsigned long rec_lastclick
= 0;
485 #if CONFIG_CODEC != SWCODEC
486 bool have_recorded
= false;
487 int timeout
= current_tick
+ HZ
/10;
488 unsigned int seconds
= 0;
489 unsigned int last_seconds
= 0;
491 struct audio_recording_options rec_options
;
492 #endif /* CONFIG_CODEC != SWCODEC */
493 #ifndef HAVE_NOISY_IDLE_MODE
494 int button_timeout
= current_tick
+ (2*HZ
);
496 struct viewport vp
[NB_SCREENS
];
497 #ifdef HAVE_BUTTONBAR
498 struct gui_buttonbar buttonbar
;
499 gui_buttonbar_init(&buttonbar
);
500 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
503 /* change status to "in screen" */
506 /* always display status bar in radio screen for now */
509 viewport_set_defaults(&vp
[i
], i
);
510 #ifdef HAVE_BUTTONBAR
511 if (global_settings
.buttonbar
)
512 vp
[i
].height
-= BUTTONBAR_HEIGHT
;
514 screens
[i
].set_viewport(&vp
[i
]);
515 screens
[i
].stop_scroll();
516 screens
[i
].clear_viewport();
517 screens
[i
].update_viewport();
520 fh
= font_get(FONT_UI
)->height
;
522 /* Adjust for font size, trying to center the information vertically */
528 radio_load_presets(global_settings
.fmr_file
);
531 if(radio_status
== FMRADIO_OFF
)
535 #if CONFIG_CODEC != SWCODEC
536 if(rec_create_directory() > 0)
537 have_recorded
= true;
539 audio_init_recording(talk_get_bufsize());
541 sound_settings_apply();
542 /* Yes, we use the D/A for monitoring */
543 peak_meter_playback(true);
545 peak_meter_enabled
= true;
547 rec_init_recording_options(&rec_options
);
548 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
549 rec_set_recording_options(&rec_options
);
551 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
552 sound_default(SOUND_RIGHT_GAIN
), AUDIO_GAIN_LINEIN
);
554 #endif /* CONFIG_CODEC != SWCODEC */
555 #endif /* ndef SIMULATOR */
558 #if CONFIG_CODEC == SWCODEC
559 audio_set_input_source(AUDIO_SRC_FMRADIO
,
560 (radio_status
== FMRADIO_PAUSED
) ?
561 SRCF_FMRADIO_PAUSED
: SRCF_FMRADIO_PLAYING
);
563 if (radio_status
== FMRADIO_OFF
)
567 if(num_presets
< 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN
)))
570 curr_preset
= find_preset(curr_freq
);
571 if(curr_preset
!= -1)
572 radio_mode
= RADIO_PRESET_MODE
;
574 #ifdef HAVE_BUTTONBAR
575 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
576 str(LANG_PRESET
), str(LANG_FM_BUTTONBAR_RECORD
));
579 #ifndef HAVE_NOISY_IDLE_MODE
587 curr_freq
= step_freq(curr_freq
, search_dir
);
588 update_screen
= true;
590 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
592 curr_preset
= find_preset(curr_freq
);
593 remember_frequency();
605 #if CONFIG_CODEC != SWCODEC
606 /* TODO: Can we timeout at HZ when recording since peaks aren't
607 displayed? This should quiet recordings too. */
608 button
= get_action(CONTEXT_FM
,
609 update_screen
? TIMEOUT_NOBLOCK
: HZ
/ PEAK_METER_FPS
);
611 button
= get_action(CONTEXT_FM
,
612 update_screen
? TIMEOUT_NOBLOCK
: HZ
);
615 #ifndef HAVE_NOISY_IDLE_MODE
616 if (button
!= ACTION_NONE
)
618 cpu_idle_mode(false);
619 button_timeout
= current_tick
+ (2*HZ
);
625 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
626 if(audio_status() == AUDIO_STATUS_RECORD
)
636 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
638 if(filepreset
[0] == '\0')
641 radio_save_presets();
644 /* Clear the preset list on exit. */
647 update_screen
= true;
651 case ACTION_FM_RECORD
:
652 #ifdef FM_RECORD_DBLPRE
653 if (lastbutton
!= ACTION_FM_RECORD_DBLPRE
)
658 if (current_tick
- rec_lastclick
> HZ
/2)
660 rec_lastclick
= current_tick
;
663 #endif /* FM_RECORD_DBLPRE */
665 if(audio_status() == AUDIO_STATUS_RECORD
)
667 rec_command(RECORDING_CMD_START_NEWFILE
);
668 update_screen
= true;
672 have_recorded
= true;
673 rec_command(RECORDING_CMD_START
);
674 update_screen
= true;
676 #endif /* SIMULATOR */
679 #endif /* #ifdef FM_RECORD */
682 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
683 if(audio_status() == AUDIO_STATUS_RECORD
)
688 ret_val
= GO_TO_ROOT
;
691 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
693 if(filepreset
[0] == '\0')
696 radio_save_presets();
700 /* Clear the preset list on exit. */
705 case ACTION_STD_PREV
:
706 case ACTION_STD_NEXT
:
707 next_station(button
== ACTION_STD_PREV
? -1 : 1);
709 update_screen
= true;
713 case ACTION_STD_PREVREPEAT
:
714 case ACTION_STD_NEXTREPEAT
:
716 int dir
= search_dir
;
717 search_dir
= button
== ACTION_STD_PREVREPEAT
? -1 : 1;
718 if (radio_mode
!= RADIO_SCAN_MODE
)
720 next_preset(search_dir
);
722 update_screen
= true;
727 /* Starting auto scan */
728 tuner_set(RADIO_MUTE
, 1);
729 update_screen
= true;
734 case ACTION_SETTINGS_INC
:
735 case ACTION_SETTINGS_INCREPEAT
:
736 global_settings
.volume
++;
738 update_screen
= true;
741 case ACTION_SETTINGS_DEC
:
742 case ACTION_SETTINGS_DECREPEAT
:
743 global_settings
.volume
--;
745 update_screen
= true;
749 if (radio_status
== FMRADIO_PLAYING
)
754 update_screen
= true;
762 screens
[i
].scroll_stop(&vp
[i
]);
765 curr_preset
= find_preset(curr_freq
);
768 screens
[i
].set_viewport(&vp
[i
]);
769 screens
[i
].clear_viewport();
770 screens
[i
].update_viewport();
771 screens
[i
].set_viewport(NULL
);
773 #ifdef HAVE_BUTTONBAR
774 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
776 str(LANG_FM_BUTTONBAR_RECORD
));
778 update_screen
= true;
782 case ACTION_FM_PRESET
:
785 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
786 update_screen
= true;
789 screens
[i
].set_viewport(&vp
[i
]);
790 screens
[i
].clear_viewport();
791 screens
[i
].update_viewport();
792 screens
[i
].set_viewport(NULL
);
797 handle_radio_presets();
800 screens
[i
].set_viewport(&vp
[i
]);
801 screens
[i
].stop_scroll();
802 screens
[i
].clear_viewport();
803 screens
[i
].update_viewport();
804 screens
[i
].set_viewport(NULL
);
806 #ifdef HAVE_BUTTONBAR
807 gui_buttonbar_set(&buttonbar
,
808 str(LANG_BUTTONBAR_MENU
),
810 str(LANG_FM_BUTTONBAR_RECORD
));
812 update_screen
= true;
814 #endif /* FM_PRESET */
817 case ACTION_FM_FREEZE
:
820 splash(HZ
, str(LANG_FM_FREEZE
));
821 screen_freeze
= true;
825 update_screen
= true;
826 screen_freeze
= false;
829 #endif /* FM_FREEZE */
831 case SYS_USB_CONNECTED
:
832 #if CONFIG_CODEC != SWCODEC
833 /* Only accept USB connection when not recording */
834 if(audio_status() != AUDIO_STATUS_RECORD
)
837 default_event_handler(SYS_USB_CONNECTED
);
838 screen_freeze
= true; /* Cosmetic: makes sure the
839 radio screen doesn't redraw */
846 if(radio_mode
== RADIO_SCAN_MODE
)
848 /* Force scan mode if there are no presets. */
850 radio_mode
= RADIO_PRESET_MODE
;
853 radio_mode
= RADIO_SCAN_MODE
;
854 update_screen
= true;
855 cond_talk_ids_fq(radio_mode
?
856 LANG_PRESET
: LANG_RADIO_SCAN_MODE
);
861 #ifdef FM_NEXT_PRESET
862 case ACTION_FM_NEXT_PRESET
:
865 update_screen
= true;
870 #ifdef FM_PREV_PRESET
871 case ACTION_FM_PREV_PRESET
:
874 update_screen
= true;
880 default_event_handler(button
);
882 if (tuner_get(RADIO_EVENT
))
883 update_screen
= true;
885 if (!tuner_get(RADIO_PRESENT
))
887 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
888 if(audio_status() == AUDIO_STATUS_RECORD
)
891 keep_playing
= false;
893 ret_val
= GO_TO_ROOT
;
896 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
898 if(filepreset
[0] == '\0')
901 radio_save_presets();
905 /* Clear the preset list on exit. */
911 #ifdef FM_RECORD_DBLPRE
912 if (button
!= ACTION_NONE
)
916 #if CONFIG_CODEC != SWCODEC
922 /* Only display the peak meter when not recording */
923 #if CONFIG_CODEC != SWCODEC
928 screens
[i
].set_viewport(&vp
[i
]);
929 peak_meter_screen(&screens
[i
],0, fh
*(top_of_screen
+ 4),fh
);
930 screens
[i
].update_rect(0, fh
*(top_of_screen
+ 4),
931 screens
[i
].getwidth(), fh
);
932 screens
[i
].set_viewport(NULL
);
936 if(TIME_AFTER(current_tick
, timeout
))
938 timeout
= current_tick
+ HZ
;
941 #endif /* CONFIG_CODEC == SWCODEC */
943 /* keep "mono" from always being displayed when paused */
944 if (radio_status
!= FMRADIO_PAUSED
)
946 stereo
= tuner_get(RADIO_STEREO
) &&
947 !global_settings
.fm_force_mono
;
949 if(stereo
!= last_stereo
)
951 update_screen
= true;
952 last_stereo
= stereo
;
957 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
958 seconds
= audio_recorded_time() / HZ
;
959 if (update_screen
|| seconds
> last_seconds
)
961 last_seconds
= seconds
;
970 screens
[i
].set_viewport(&vp
[i
]);
973 snprintf(buf
, 128, curr_preset
>= 0 ? "%d. %s" : " ",
974 curr_preset
+ 1, presets
[curr_preset
].name
);
977 screens
[i
].puts_scroll(0, top_of_screen
, buf
);
979 freq
= curr_freq
/ 10000;
980 snprintf(buf
, 128, str(LANG_FM_STATION
),
981 freq
/ 100, freq
% 100);
983 screens
[i
].puts_scroll(0, top_of_screen
+ 1, buf
);
986 screens
[i
].puts_scroll(0, top_of_screen
+ 2,
987 stereo
? str(LANG_CHANNEL_STEREO
) :
988 str(LANG_CHANNEL_MONO
));
990 snprintf(buf
, 128, "%s %s", str(LANG_MODE
),
991 radio_mode
? str(LANG_PRESET
) :
992 str(LANG_RADIO_SCAN_MODE
));
994 screens
[i
].puts_scroll(0, top_of_screen
+ 3, buf
);
997 snprintf(buf
, 128, "%s",tuner_get_rds_info(RADIO_RDS_NAME
));
999 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
1001 snprintf(buf
, 128, "%s",tuner_get_rds_info(RADIO_RDS_TEXT
));
1003 screens
[i
].puts_scroll(0, top_of_screen
+ 5, buf
);
1005 #endif /* SIMULATOR */
1007 #if CONFIG_CODEC != SWCODEC
1008 if(audio_status() == AUDIO_STATUS_RECORD
)
1010 hours
= seconds
/ 3600;
1011 minutes
= (seconds
- (hours
* 3600)) / 60;
1012 snprintf(buf
, 32, "%s %02d:%02d:%02d",
1013 str(LANG_RECORDING_TIME
),
1014 hours
, minutes
, seconds
%60);
1016 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
1020 if(rec_options
.rec_prerecord_time
)
1022 snprintf(buf
, 32, "%s %02d",
1023 str(LANG_RECORD_PRERECORD
), seconds
%60);
1025 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
1028 #endif /* CONFIG_CODEC != SWCODEC */
1032 screens
[i
].update_viewport();
1033 screens
[i
].set_viewport(NULL
);
1036 #ifdef HAVE_BUTTONBAR
1037 gui_buttonbar_draw(&buttonbar
);
1042 update_screen
= false;
1044 if (global_settings
.talk_file
&& talk
1045 && radio_status
== FMRADIO_PAUSED
)
1048 bool enqueue
= false;
1049 if (radio_mode
== RADIO_SCAN_MODE
)
1051 talk_freq(curr_freq
, enqueue
);
1054 if (curr_preset
>= 0)
1055 talk_preset(curr_preset
, radio_mode
== RADIO_PRESET_MODE
,
1059 #if CONFIG_CODEC != SWCODEC
1060 if(audio_status() & AUDIO_STATUS_ERROR
)
1066 #ifndef HAVE_NOISY_IDLE_MODE
1067 if (TIME_AFTER(current_tick
, button_timeout
))
1069 cpu_idle_mode(true);
1075 #if CONFIG_CODEC != SWCODEC
1076 if(audio_status() & AUDIO_STATUS_ERROR
)
1078 splash(0, str(LANG_DISK_FULL
));
1081 screens
[i
].set_viewport(&vp
[i
]);
1082 screens
[i
].update_viewport();
1083 screens
[i
].set_viewport(NULL
);
1085 audio_error_clear();
1089 button
= get_action(CONTEXT_FM
, TIMEOUT_BLOCK
);
1090 if(button
== ACTION_FM_STOP
)
1095 audio_init_playback();
1096 #endif /* CONFIG_CODEC != SWCODEC */
1098 sound_settings_apply();
1099 #endif /* SIMULATOR */
1103 /* Catch FMRADIO_PLAYING status for the sim. */
1105 #if CONFIG_CODEC != SWCODEC
1106 /* Enable the Left and right A/D Converter */
1107 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
1108 sound_default(SOUND_RIGHT_GAIN
),
1110 mas_codec_writereg(6, 0x4000);
1113 #endif /* SIMULATOR */
1117 #if CONFIG_CODEC == SWCODEC
1118 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
1124 #ifndef HAVE_NOISY_IDLE_MODE
1125 cpu_idle_mode(false);
1129 screens
[i
].scroll_stop(&vp
[i
]);
1132 #if CONFIG_CODEC != SWCODEC
1133 return have_recorded
;
1137 } /* radio_screen */
1139 static void radio_save_presets(void)
1144 fd
= creat(filepreset
);
1147 for(i
= 0;i
< num_presets
;i
++)
1149 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
1153 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
1154 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
1155 presets_changed
= false;
1159 splash(HZ
, ID2P(LANG_FM_PRESET_SAVE_FAILED
));
1163 void radio_load_presets(char *filename
)
1173 memset(presets
, 0, sizeof(presets
));
1176 /* No Preset in configuration. */
1177 if(filename
[0] == '\0')
1179 filepreset
[0] = '\0';
1182 /* Temporary preset, loaded until player shuts down. */
1183 else if(filename
[0] == '/')
1184 strlcpy(filepreset
, filename
, sizeof(filepreset
));
1185 /* Preset from default directory. */
1187 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
1188 FMPRESET_PATH
, filename
);
1190 fd
= open_utf8(filepreset
, O_RDONLY
);
1193 while(!done
&& num_presets
< MAX_PRESETS
)
1195 rc
= read_line(fd
, buf
, 128);
1198 if(settings_parseline(buf
, &freq
, &name
))
1201 if(f
) /* For backwards compatibility */
1203 struct fmstation
* const fms
= &presets
[num_presets
];
1205 strlcpy(fms
->name
, name
, MAX_FMPRESET_LEN
+1);
1215 else /* invalid file name? */
1216 filepreset
[0] = '\0';
1218 presets_loaded
= num_presets
> 0;
1219 presets_changed
= false;
1223 static int radio_add_preset(void)
1225 char buf
[MAX_FMPRESET_LEN
+ 1];
1227 if(num_presets
< MAX_PRESETS
)
1231 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1233 struct fmstation
* const fms
= &presets
[num_presets
];
1234 strcpy(fms
->name
, buf
);
1235 fms
->frequency
= curr_freq
;
1237 presets_changed
= true;
1238 presets_loaded
= num_presets
> 0;
1244 splash(HZ
, ID2P(LANG_FM_NO_FREE_PRESETS
));
1249 /* needed to know which preset we are edit/delete-ing */
1250 static int selected_preset
= -1;
1251 static int radio_edit_preset(void)
1253 char buf
[MAX_FMPRESET_LEN
+ 1];
1255 if (num_presets
> 0)
1257 struct fmstation
* const fms
= &presets
[selected_preset
];
1259 strcpy(buf
, fms
->name
);
1261 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1263 strcpy(fms
->name
, buf
);
1264 presets_changed
= true;
1271 static int radio_delete_preset(void)
1273 if (num_presets
> 0)
1275 struct fmstation
* const fms
= &presets
[selected_preset
];
1277 if (selected_preset
>= --num_presets
)
1278 selected_preset
= num_presets
- 1;
1280 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
1283 if (curr_preset
>= num_presets
)
1287 /* Don't ask to save when all presets are deleted. */
1288 presets_changed
= num_presets
> 0;
1290 if (!presets_changed
)
1292 /* The preset list will be cleared, switch to Scan Mode. */
1293 radio_mode
= RADIO_SCAN_MODE
;
1295 presets_loaded
= false;
1301 static int load_preset_list(void)
1303 return !rockbox_browse(FMPRESET_PATH
, SHOW_FMR
);
1306 static int save_preset_list(void)
1310 bool bad_file_name
= true;
1312 if(!dir_exists(FMPRESET_PATH
)) /* Check if there is preset folder */
1313 mkdir(FMPRESET_PATH
);
1315 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
1316 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
1318 while(bad_file_name
)
1320 if(!kbd_input(filepreset
, sizeof(filepreset
)))
1322 /* check the name: max MAX_FILENAME (20) chars */
1326 p1
= strrchr(filepreset
, '/');
1328 while((p1
) && (*p2
) && (*p2
!= '.'))
1330 len
= (int)(p2
-p1
) - 1;
1331 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
1333 /* no slash, too long or too short */
1334 splash(HZ
, ID2P(LANG_INVALID_FILENAME
));
1338 /* add correct extension (easier to always write)
1339 at this point, p2 points to 0 or the extension dot */
1341 strcat(filepreset
,".fmr");
1342 bad_file_name
= false;
1343 radio_save_presets();
1354 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
1359 static int clear_preset_list(void)
1361 /* Clear all the preset entries */
1362 memset(presets
, 0, sizeof (presets
));
1365 presets_loaded
= false;
1366 /* The preset list will be cleared switch to Scan Mode. */
1367 radio_mode
= RADIO_SCAN_MODE
;
1370 presets_changed
= false; /* Don't ask to save when clearing the list. */
1375 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1376 ID2P(LANG_FM_EDIT_PRESET
),
1377 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
1378 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1379 ID2P(LANG_FM_DELETE_PRESET
),
1380 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
1381 static int radio_preset_callback(int action
,
1382 const struct menu_item_ex
*this_item
)
1384 if (action
== ACTION_STD_OK
)
1385 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
1389 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_PRESET
),
1390 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
1391 &radio_delete_preset_item
);
1392 /* present a list of preset stations */
1393 static const char* presets_get_name(int selected_item
, void *data
,
1394 char *buffer
, size_t buffer_len
)
1397 struct fmstation
*p
= &presets
[selected_item
];
1400 int freq
= p
->frequency
/ 10000;
1401 int frac
= freq
% 100;
1403 snprintf(buffer
, buffer_len
,
1404 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
1408 static int presets_speak_name(int selected_item
, void * data
)
1411 talk_preset(selected_item
, true, false);
1415 static int handle_radio_presets(void)
1417 struct gui_synclist lists
;
1419 int action
= ACTION_NONE
;
1420 #ifdef HAVE_BUTTONBAR
1421 struct gui_buttonbar buttonbar
;
1424 if(presets_loaded
== false)
1427 #ifdef HAVE_BUTTONBAR
1428 gui_buttonbar_init(&buttonbar
);
1429 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
1430 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
1431 str(LANG_FM_BUTTONBAR_EXIT
),
1432 str(LANG_FM_BUTTONBAR_ACTION
));
1433 gui_buttonbar_draw(&buttonbar
);
1435 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1, NULL
);
1436 gui_synclist_set_title(&lists
, str(LANG_PRESET
), NOICON
);
1437 gui_synclist_set_icon_callback(&lists
, NULL
);
1438 if(global_settings
.talk_file
)
1439 gui_synclist_set_voice_callback(&lists
, presets_speak_name
);
1440 gui_synclist_set_nb_items(&lists
, num_presets
);
1441 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
1442 gui_synclist_speak_item(&lists
);
1446 gui_synclist_draw(&lists
);
1447 list_do_action(CONTEXT_STD
, TIMEOUT_BLOCK
,
1448 &lists
, &action
, LIST_WRAP_UNLESS_HELD
);
1451 case ACTION_STD_MENU
:
1452 if (radio_add_preset())
1454 gui_synclist_set_nb_items(&lists
, num_presets
);
1455 gui_synclist_select_item(&lists
, num_presets
- 1);
1458 case ACTION_STD_CANCEL
:
1462 curr_preset
= gui_synclist_get_sel_pos(&lists
);
1463 curr_freq
= presets
[curr_preset
].frequency
;
1465 remember_frequency();
1469 case ACTION_STD_CONTEXT
:
1470 selected_preset
= gui_synclist_get_sel_pos(&lists
);
1471 do_menu(&handle_radio_preset_menu
, NULL
, NULL
, false);
1472 gui_synclist_set_nb_items(&lists
, num_presets
);
1473 gui_synclist_select_item(&lists
, selected_preset
);
1474 gui_synclist_speak_item(&lists
);
1477 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
1484 void toggle_mono_mode(bool mono
)
1486 tuner_set(RADIO_FORCE_MONO
, mono
);
1489 void set_radio_region(int region
)
1491 #ifdef HAVE_RADIO_REGION
1492 tuner_set(RADIO_REGION
, region
);
1495 remember_frequency();
1499 MENUITEM_SETTING(set_region
, &global_settings
.fm_region
, NULL
);
1500 MENUITEM_SETTING(force_mono
, &global_settings
.fm_force_mono
, NULL
);
1503 static char* get_mode_text(int selected_item
, void * data
, char *buffer
)
1505 (void)selected_item
;
1507 snprintf(buffer
, MAX_PATH
, "%s %s", str(LANG_MODE
),
1508 radio_mode
? str(LANG_PRESET
) :
1509 str(LANG_RADIO_SCAN_MODE
));
1512 static int toggle_radio_mode(void)
1514 radio_mode
= (radio_mode
== RADIO_SCAN_MODE
) ?
1515 RADIO_PRESET_MODE
: RADIO_SCAN_MODE
;
1518 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item
, 0,
1519 toggle_radio_mode
, NULL
,
1520 get_mode_text
, NULL
, NULL
, NULL
, Icon_NOICON
);
1523 static int scan_presets(void *viewports
)
1525 bool do_scan
= true;
1527 struct viewport
*vp
= (struct viewport
*)viewports
;
1530 screens
[i
].set_viewport(vp
?&vp
[i
]:NULL
);
1531 if(num_presets
> 0) /* Do that to avoid 2 questions. */
1532 do_scan
= yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS
));
1536 const struct fm_region_data
* const fmr
=
1537 &fm_region_data
[global_settings
.fm_region
];
1539 curr_freq
= fmr
->freq_min
;
1541 memset(presets
, 0, sizeof(presets
));
1543 tuner_set(RADIO_MUTE
, 1);
1545 while(curr_freq
<= fmr
->freq_max
)
1548 if(num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
1551 freq
= curr_freq
/ 10000;
1555 splashf(0, str(LANG_FM_SCANNING
), freq
, frac
);
1557 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
1560 presets
[num_presets
].name
[0] = '\0';
1561 presets
[num_presets
].frequency
= curr_freq
;
1565 curr_freq
+= fmr
->freq_step
;
1568 if (radio_status
== FMRADIO_PLAYING
)
1569 tuner_set(RADIO_MUTE
, 0);
1571 presets_changed
= true;
1575 screens
[i
].clear_viewport();
1576 screens
[i
].update_viewport();
1581 curr_freq
= presets
[0].frequency
;
1582 radio_mode
= RADIO_PRESET_MODE
;
1583 presets_loaded
= true;
1588 /* Wrap it to beginning or we'll be past end of band */
1589 presets_loaded
= false;
1597 #ifdef HAVE_RECORDING
1599 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1600 #define FM_RECORDING_SCREEN
1601 static int fm_recording_screen(void)
1605 /* switch recording source to FMRADIO for the duration */
1606 int rec_source
= global_settings
.rec_source
;
1607 global_settings
.rec_source
= AUDIO_SRC_FMRADIO
;
1608 ret
= recording_screen(true);
1610 /* safe to reset as changing sources is prohibited here */
1611 global_settings
.rec_source
= rec_source
;
1616 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1618 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1619 #define FM_RECORDING_SETTINGS
1620 static int fm_recording_settings(void)
1622 bool ret
= recording_menu(true);
1624 #if CONFIG_CODEC != SWCODEC
1627 struct audio_recording_options rec_options
;
1628 rec_init_recording_options(&rec_options
);
1629 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
1630 rec_set_recording_options(&rec_options
);
1637 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1638 #endif /* HAVE_RECORDING */
1640 #ifdef FM_RECORDING_SCREEN
1641 MENUITEM_FUNCTION(recscreen_item
, 0, ID2P(LANG_RECORDING
),
1642 fm_recording_screen
, NULL
, NULL
, Icon_Recording
);
1644 #ifdef FM_RECORDING_SETTINGS
1645 MENUITEM_FUNCTION(recsettings_item
, 0, ID2P(LANG_RECORDING_SETTINGS
),
1646 fm_recording_settings
, NULL
, NULL
, Icon_Recording
);
1649 MENUITEM_FUNCTION(radio_presets_item
, 0, ID2P(LANG_PRESET
),
1650 handle_radio_presets
, NULL
, NULL
, Icon_NOICON
);
1652 #ifndef FM_PRESET_ADD
1653 MENUITEM_FUNCTION(radio_addpreset_item
, 0, ID2P(LANG_FM_ADD_PRESET
),
1654 radio_add_preset
, NULL
, NULL
, Icon_NOICON
);
1658 MENUITEM_FUNCTION(presetload_item
, 0, ID2P(LANG_FM_PRESET_LOAD
),
1659 load_preset_list
, NULL
, NULL
, Icon_NOICON
);
1660 MENUITEM_FUNCTION(presetsave_item
, 0, ID2P(LANG_FM_PRESET_SAVE
),
1661 save_preset_list
, NULL
, NULL
, Icon_NOICON
);
1662 MENUITEM_FUNCTION(presetclear_item
, 0, ID2P(LANG_FM_PRESET_CLEAR
),
1663 clear_preset_list
, NULL
, NULL
, Icon_NOICON
);
1664 MENUITEM_FUNCTION(scan_presets_item
, MENU_FUNC_USEPARAM
,
1665 ID2P(LANG_FM_SCAN_PRESETS
),
1666 scan_presets
, NULL
, NULL
, Icon_NOICON
);
1668 MAKE_MENU(radio_settings_menu
, ID2P(LANG_FM_MENU
), NULL
,
1671 &radio_presets_item
,
1673 #ifndef FM_PRESET_ADD
1674 &radio_addpreset_item
,
1676 &presetload_item
, &presetsave_item
, &presetclear_item
,
1681 &set_region
, &sound_settings
,
1682 #ifdef FM_RECORDING_SCREEN
1685 #ifdef FM_RECORDING_SETTINGS
1688 &scan_presets_item
);
1689 /* main menu of the radio screen */
1690 static bool radio_menu(void)
1692 return do_menu(&radio_settings_menu
, NULL
, NULL
, false) ==