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"
70 #ifdef HAVE_QUICKSCREEN
71 #include "quickscreen.h"
76 #if CONFIG_KEYPAD == RECORDER_PAD
79 #define FM_PRESET_ACTION
83 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
86 #define FM_NEXT_PRESET
87 #define FM_PREV_PRESET
89 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
93 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
96 /* This should be removeable if the whole tuning thing is sorted out since
97 proper tuning quiets the screen almost entirely in that extreme measures
98 have to be taken to hear any interference. */
99 #define HAVE_NOISY_IDLE_MODE
101 #elif CONFIG_KEYPAD == ONDIO_PAD
102 #define FM_RECORD_DBLPRE
104 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD) \
105 || (CONFIG_KEYPAD == SANSA_FUZE_PAD)
109 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
113 #elif (CONFIG_KEYPAD == COWON_D2_PAD)
116 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
117 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
122 #define RADIO_SCAN_MODE 0
123 #define RADIO_PRESET_MODE 1
125 static int curr_preset
= -1;
126 static int curr_freq
; /* current frequency in Hz */
127 static int radio_mode
= RADIO_SCAN_MODE
;
128 static int search_dir
= 0;
130 static int radio_status
= FMRADIO_OFF
;
131 static bool in_screen
= false;
133 #define MAX_PRESETS 64
134 static bool presets_loaded
= false, presets_changed
= false;
135 static struct fmstation presets
[MAX_PRESETS
];
137 static char filepreset
[MAX_PATH
]; /* preset filename variable */
139 static int num_presets
= 0; /* The number of presets in the preset list */
141 static void radio_save_presets(void);
142 static int handle_radio_presets(void);
143 static bool radio_menu(void);
144 static int radio_add_preset(void);
145 static int save_preset_list(void);
146 static int load_preset_list(void);
147 static int clear_preset_list(void);
149 static int scan_presets(void *viewports
);
151 /* Function to manipulate all yesno dialogues.
152 This function needs the output text as an argument. */
153 static bool yesno_pop(const char* text
)
156 const char *lines
[]={text
};
157 const struct text_message message
={lines
, 1};
158 bool ret
= (gui_syncyesno_run(&message
,NULL
,NULL
)== YESNO_YES
);
160 screens
[i
].clear_viewport();
164 void radio_init(void)
170 int get_radio_status(void)
175 bool in_radio_screen(void)
180 /* TODO: Move some more of the control functionality to firmware
181 and clean up the mess */
183 /* secret flag for starting paused - prevents unmute */
184 #define FMRADIO_START_PAUSED 0x8000
185 void radio_start(void)
187 const struct fm_region_data
*fmr
;
190 if(radio_status
== FMRADIO_PLAYING
)
193 fmr
= &fm_region_data
[global_settings
.fm_region
];
195 start_paused
= radio_status
& FMRADIO_START_PAUSED
;
196 /* clear flag before any yielding */
197 radio_status
&= ~FMRADIO_START_PAUSED
;
199 if(radio_status
== FMRADIO_OFF
)
202 curr_freq
= global_status
.last_frequency
* fmr
->freq_step
+ fmr
->freq_min
;
204 tuner_set(RADIO_SLEEP
, 0); /* wake up the tuner */
206 if(radio_status
== FMRADIO_OFF
)
208 #ifdef HAVE_RADIO_REGION
209 tuner_set(RADIO_REGION
, global_settings
.fm_region
);
211 tuner_set(RADIO_FORCE_MONO
, global_settings
.fm_force_mono
);
214 tuner_set(RADIO_FREQUENCY
, curr_freq
);
216 #ifdef HAVE_RADIO_MUTE_TIMEOUT
218 unsigned long mute_timeout
= current_tick
+ HZ
;
219 if (radio_status
!= FMRADIO_OFF
)
225 while(!tuner_get(RADIO_STEREO
) && !tuner_get(RADIO_TUNED
))
227 if(TIME_AFTER(current_tick
, mute_timeout
))
234 /* keep radio from sounding initially */
236 tuner_set(RADIO_MUTE
, 0);
238 radio_status
= FMRADIO_PLAYING
;
241 void radio_pause(void)
243 if(radio_status
== FMRADIO_PAUSED
)
246 if(radio_status
== FMRADIO_OFF
)
248 radio_status
|= FMRADIO_START_PAUSED
;
252 tuner_set(RADIO_MUTE
, 1);
253 tuner_set(RADIO_SLEEP
, 1);
255 radio_status
= FMRADIO_PAUSED
;
258 void radio_stop(void)
260 if(radio_status
== FMRADIO_OFF
)
263 tuner_set(RADIO_MUTE
, 1);
264 tuner_set(RADIO_SLEEP
, 1); /* low power mode, if available */
265 radio_status
= FMRADIO_OFF
;
266 tuner_power(false); /* status update, power off if avail. */
269 bool radio_hardware_present(void)
271 return tuner_get(RADIO_PRESENT
);
274 /* Keep freq on the grid for the current region */
275 static int snap_freq_to_grid(int freq
)
277 const struct fm_region_data
* const fmr
=
278 &fm_region_data
[global_settings
.fm_region
];
280 /* Range clamp if out of range or just round to nearest */
281 if (freq
< fmr
->freq_min
)
282 freq
= fmr
->freq_min
;
283 else if (freq
> fmr
->freq_max
)
284 freq
= fmr
->freq_max
;
286 freq
= (freq
- fmr
->freq_min
+ fmr
->freq_step
/2) /
287 fmr
->freq_step
* fmr
->freq_step
+ fmr
->freq_min
;
292 /* Find a matching preset to freq */
293 static int find_preset(int freq
)
298 for(i
= 0;i
< MAX_PRESETS
;i
++)
300 if(freq
== presets
[i
].frequency
)
307 /* Return the closest preset encountered in the search direction with
309 static int find_closest_preset(int freq
, int direction
)
316 if (direction
== 0) /* direction == 0 isn't really used */
319 for (i
= 0; i
< num_presets
; i
++)
321 int f
= presets
[i
].frequency
;
323 return i
; /* Exact match = stop */
325 /* remember the highest and lowest presets for wraparound */
326 if (f
< presets
[lowpreset
].frequency
)
328 if (f
> presets
[highpreset
].frequency
)
331 /* find the closest preset in the given direction */
332 if (direction
> 0 && f
> freq
)
334 if (closest
< 0 || f
< presets
[closest
].frequency
)
337 else if (direction
< 0 && f
< freq
)
339 if (closest
< 0 || f
> presets
[closest
].frequency
)
346 /* no presets in the given direction */
347 /* wrap around depending on direction */
349 closest
= highpreset
;
357 static void remember_frequency(void)
359 const struct fm_region_data
* const fmr
=
360 &fm_region_data
[global_settings
.fm_region
];
361 global_status
.last_frequency
= (curr_freq
- fmr
->freq_min
)
366 static void next_preset(int direction
)
371 if (curr_preset
== -1)
372 curr_preset
= find_closest_preset(curr_freq
, direction
);
374 curr_preset
= (curr_preset
+ direction
+ num_presets
) % num_presets
;
376 /* Must stay on the current grid for the region */
377 curr_freq
= snap_freq_to_grid(presets
[curr_preset
].frequency
);
379 tuner_set(RADIO_FREQUENCY
, curr_freq
);
380 remember_frequency();
383 /* Step to the next or previous frequency */
384 static int step_freq(int freq
, int direction
)
386 const struct fm_region_data
* const fmr
=
387 &fm_region_data
[global_settings
.fm_region
];
389 freq
+= direction
*fmr
->freq_step
;
391 /* Wrap first or snapping to grid will not let us on the band extremes */
392 if (freq
> fmr
->freq_max
)
393 freq
= direction
> 0 ? fmr
->freq_min
: fmr
->freq_max
;
394 else if (freq
< fmr
->freq_min
)
395 freq
= direction
< 0 ? fmr
->freq_max
: fmr
->freq_min
;
397 freq
= snap_freq_to_grid(freq
);
402 /* Step to the next or previous station */
403 static void next_station(int direction
)
405 if (direction
!= 0 && radio_mode
!= RADIO_SCAN_MODE
)
407 next_preset(direction
);
411 curr_freq
= step_freq(curr_freq
, direction
);
413 if (radio_status
== FMRADIO_PLAYING
)
414 tuner_set(RADIO_MUTE
, 1);
416 tuner_set(RADIO_FREQUENCY
, curr_freq
);
418 if (radio_status
== FMRADIO_PLAYING
)
419 tuner_set(RADIO_MUTE
, 0);
421 curr_preset
= find_preset(curr_freq
);
422 remember_frequency();
425 /* Ends an in-progress search */
426 static void end_search(void)
428 if (search_dir
!= 0 && radio_status
== FMRADIO_PLAYING
)
429 tuner_set(RADIO_MUTE
, 0);
433 /* Speak a frequency. */
434 static void talk_freq(int freq
, bool enqueue
)
437 talk_number(freq
/ 100, enqueue
);
438 talk_id(LANG_POINT
, true);
439 talk_number(freq
% 100 / 10, true);
441 talk_number(freq
% 10, true);
444 /* Speak a preset by number or by spelling its name, depending on settings. */
445 static void talk_preset(int preset
, bool fallback
, bool enqueue
)
447 if (global_settings
.talk_file
== 1) /* number */
448 talk_number(preset
+ 1, enqueue
);
451 if(presets
[preset
].name
[0])
452 talk_spell(presets
[preset
].name
, enqueue
);
454 talk_freq(presets
[preset
].frequency
, enqueue
);
458 static void fms_restore(struct viewport vp
[NB_SCREENS
])
460 struct screen
*display
;
464 display
= &screens
[i
];
465 display
->set_viewport(&vp
[i
]);
466 display
->clear_viewport();
467 display
->update_viewport();
471 int radio_screen(void)
475 int ret_val
= GO_TO_ROOT
;
478 bool stereo
= false, last_stereo
= false;
480 int top_of_screen
= 0;
481 bool update_screen
= true;
482 bool screen_freeze
= false;
483 bool keep_playing
= false;
485 #ifdef FM_RECORD_DBLPRE
486 int lastbutton
= BUTTON_NONE
;
487 unsigned long rec_lastclick
= 0;
489 #if CONFIG_CODEC != SWCODEC
490 bool have_recorded
= false;
491 int timeout
= current_tick
+ HZ
/10;
492 unsigned int seconds
= 0;
493 unsigned int last_seconds
= 0;
495 struct audio_recording_options rec_options
;
496 #endif /* CONFIG_CODEC != SWCODEC */
497 #ifndef HAVE_NOISY_IDLE_MODE
498 int button_timeout
= current_tick
+ (2*HZ
);
500 struct viewport vp
[NB_SCREENS
];
501 #ifdef HAVE_BUTTONBAR
502 struct gui_buttonbar buttonbar
;
503 gui_buttonbar_init(&buttonbar
);
504 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
507 /* change status to "in screen" */
510 /* always display status bar in radio screen for now */
513 viewport_set_defaults(&vp
[i
], i
);
514 #ifdef HAVE_BUTTONBAR
515 if (global_settings
.buttonbar
)
516 vp
[i
].height
-= BUTTONBAR_HEIGHT
;
521 fh
= font_get(FONT_UI
)->height
;
523 /* Adjust for font size, trying to center the information vertically */
529 radio_load_presets(global_settings
.fmr_file
);
532 if(radio_status
== FMRADIO_OFF
)
536 #if CONFIG_CODEC != SWCODEC
537 if(rec_create_directory() > 0)
538 have_recorded
= true;
540 audio_init_recording(talk_get_bufsize());
542 sound_settings_apply();
543 /* Yes, we use the D/A for monitoring */
544 peak_meter_playback(true);
546 peak_meter_enabled
= true;
548 rec_init_recording_options(&rec_options
);
549 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
550 rec_set_recording_options(&rec_options
);
552 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
553 sound_default(SOUND_RIGHT_GAIN
), AUDIO_GAIN_LINEIN
);
555 #endif /* CONFIG_CODEC != SWCODEC */
556 #endif /* ndef SIMULATOR */
559 #if CONFIG_CODEC == SWCODEC
560 audio_set_input_source(AUDIO_SRC_FMRADIO
,
561 (radio_status
== FMRADIO_PAUSED
) ?
562 SRCF_FMRADIO_PAUSED
: SRCF_FMRADIO_PLAYING
);
564 if (radio_status
== FMRADIO_OFF
)
568 if(num_presets
< 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN
)))
571 curr_preset
= find_preset(curr_freq
);
572 if(curr_preset
!= -1)
573 radio_mode
= RADIO_PRESET_MODE
;
575 #ifdef HAVE_BUTTONBAR
576 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
577 str(LANG_PRESET
), str(LANG_FM_BUTTONBAR_RECORD
));
580 #ifndef HAVE_NOISY_IDLE_MODE
588 curr_freq
= step_freq(curr_freq
, search_dir
);
589 update_screen
= true;
591 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
593 curr_preset
= find_preset(curr_freq
);
594 remember_frequency();
606 #if CONFIG_CODEC != SWCODEC
607 /* TODO: Can we timeout at HZ when recording since peaks aren't
608 displayed? This should quiet recordings too. */
609 button
= get_action(CONTEXT_FM
,
610 update_screen
? TIMEOUT_NOBLOCK
: HZ
/ PEAK_METER_FPS
);
612 button
= get_action(CONTEXT_FM
,
613 update_screen
? TIMEOUT_NOBLOCK
: HZ
);
616 #ifndef HAVE_NOISY_IDLE_MODE
617 if (button
!= ACTION_NONE
)
619 cpu_idle_mode(false);
620 button_timeout
= current_tick
+ (2*HZ
);
626 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
627 if(audio_status() == AUDIO_STATUS_RECORD
)
637 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
639 if(filepreset
[0] == '\0')
642 radio_save_presets();
645 /* Clear the preset list on exit. */
648 update_screen
= true;
652 case ACTION_FM_RECORD
:
653 #ifdef FM_RECORD_DBLPRE
654 if (lastbutton
!= ACTION_FM_RECORD_DBLPRE
)
659 if (current_tick
- rec_lastclick
> HZ
/2)
661 rec_lastclick
= current_tick
;
664 #endif /* FM_RECORD_DBLPRE */
666 if(audio_status() == AUDIO_STATUS_RECORD
)
668 rec_command(RECORDING_CMD_START_NEWFILE
);
669 update_screen
= true;
673 have_recorded
= true;
674 rec_command(RECORDING_CMD_START
);
675 update_screen
= true;
677 #endif /* SIMULATOR */
680 #endif /* #ifdef FM_RECORD */
683 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
684 if(audio_status() == AUDIO_STATUS_RECORD
)
689 ret_val
= GO_TO_ROOT
;
692 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
694 if(filepreset
[0] == '\0')
697 radio_save_presets();
701 /* Clear the preset list on exit. */
706 case ACTION_STD_PREV
:
707 case ACTION_STD_NEXT
:
708 next_station(button
== ACTION_STD_PREV
? -1 : 1);
710 update_screen
= true;
714 case ACTION_STD_PREVREPEAT
:
715 case ACTION_STD_NEXTREPEAT
:
717 int dir
= search_dir
;
718 search_dir
= button
== ACTION_STD_PREVREPEAT
? -1 : 1;
719 if (radio_mode
!= RADIO_SCAN_MODE
)
721 next_preset(search_dir
);
723 update_screen
= true;
728 /* Starting auto scan */
729 tuner_set(RADIO_MUTE
, 1);
730 update_screen
= true;
735 case ACTION_SETTINGS_INC
:
736 case ACTION_SETTINGS_INCREPEAT
:
737 global_settings
.volume
++;
739 update_screen
= true;
742 case ACTION_SETTINGS_DEC
:
743 case ACTION_SETTINGS_DECREPEAT
:
744 global_settings
.volume
--;
746 update_screen
= true;
750 if (radio_status
== FMRADIO_PLAYING
)
755 update_screen
= true;
763 screens
[i
].scroll_stop(&vp
[i
]);
766 curr_preset
= find_preset(curr_freq
);
768 #ifdef HAVE_BUTTONBAR
769 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
771 str(LANG_FM_BUTTONBAR_RECORD
));
773 update_screen
= true;
777 case ACTION_FM_PRESET
:
780 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
781 update_screen
= true;
787 screens
[i
].scroll_stop(&vp
[i
]);
788 handle_radio_presets();
790 #ifdef HAVE_BUTTONBAR
791 gui_buttonbar_set(&buttonbar
,
792 str(LANG_BUTTONBAR_MENU
),
794 str(LANG_FM_BUTTONBAR_RECORD
));
796 update_screen
= true;
798 #endif /* FM_PRESET */
800 #ifdef HAVE_QUICKSCREEN
801 case ACTION_FM_QUICKSCREEN
:
803 if (quick_screen_quick(button
))
809 update_screen
= true;
814 case ACTION_FM_FREEZE
:
817 splash(HZ
, str(LANG_FM_FREEZE
));
818 screen_freeze
= true;
822 update_screen
= true;
823 screen_freeze
= false;
826 #endif /* FM_FREEZE */
828 case SYS_USB_CONNECTED
:
829 #if CONFIG_CODEC != SWCODEC
830 /* Only accept USB connection when not recording */
831 if(audio_status() != AUDIO_STATUS_RECORD
)
834 default_event_handler(SYS_USB_CONNECTED
);
835 screen_freeze
= true; /* Cosmetic: makes sure the
836 radio screen doesn't redraw */
843 if(radio_mode
== RADIO_SCAN_MODE
)
845 /* Force scan mode if there are no presets. */
847 radio_mode
= RADIO_PRESET_MODE
;
850 radio_mode
= RADIO_SCAN_MODE
;
851 update_screen
= true;
852 cond_talk_ids_fq(radio_mode
?
853 LANG_PRESET
: LANG_RADIO_SCAN_MODE
);
858 #ifdef FM_NEXT_PRESET
859 case ACTION_FM_NEXT_PRESET
:
862 update_screen
= true;
867 #ifdef FM_PREV_PRESET
868 case ACTION_FM_PREV_PRESET
:
871 update_screen
= true;
877 default_event_handler(button
);
879 if (tuner_get(RADIO_EVENT
))
880 update_screen
= true;
882 if (!tuner_get(RADIO_PRESENT
))
884 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
885 if(audio_status() == AUDIO_STATUS_RECORD
)
888 keep_playing
= false;
890 ret_val
= GO_TO_ROOT
;
893 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
895 if(filepreset
[0] == '\0')
898 radio_save_presets();
902 /* Clear the preset list on exit. */
908 #ifdef FM_RECORD_DBLPRE
909 if (button
!= ACTION_NONE
)
913 #if CONFIG_CODEC != SWCODEC
919 /* Only display the peak meter when not recording */
920 #if CONFIG_CODEC != SWCODEC
925 screens
[i
].set_viewport(&vp
[i
]);
926 peak_meter_screen(&screens
[i
],0, fh
*(top_of_screen
+ 4),fh
);
927 screens
[i
].update_rect(0, fh
*(top_of_screen
+ 4),
928 screens
[i
].getwidth(), fh
);
932 if(TIME_AFTER(current_tick
, timeout
))
934 timeout
= current_tick
+ HZ
;
937 #endif /* CONFIG_CODEC == SWCODEC */
939 /* keep "mono" from always being displayed when paused */
940 if (radio_status
!= FMRADIO_PAUSED
)
942 stereo
= tuner_get(RADIO_STEREO
) &&
943 !global_settings
.fm_force_mono
;
945 if(stereo
!= last_stereo
)
947 update_screen
= true;
948 last_stereo
= stereo
;
953 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
954 seconds
= audio_recorded_time() / HZ
;
955 if (update_screen
|| seconds
> last_seconds
)
957 last_seconds
= seconds
;
966 screens
[i
].set_viewport(&vp
[i
]);
969 snprintf(buf
, 128, curr_preset
>= 0 ? "%d. %s" : " ",
970 curr_preset
+ 1, presets
[curr_preset
].name
);
973 screens
[i
].puts_scroll(0, top_of_screen
, buf
);
975 freq
= curr_freq
/ 10000;
976 snprintf(buf
, 128, str(LANG_FM_STATION
),
977 freq
/ 100, freq
% 100);
979 screens
[i
].puts_scroll(0, top_of_screen
+ 1, buf
);
982 screens
[i
].puts_scroll(0, top_of_screen
+ 2,
983 stereo
? str(LANG_CHANNEL_STEREO
) :
984 str(LANG_CHANNEL_MONO
));
986 snprintf(buf
, 128, "%s %s", str(LANG_MODE
),
987 radio_mode
? str(LANG_PRESET
) :
988 str(LANG_RADIO_SCAN_MODE
));
990 screens
[i
].puts_scroll(0, top_of_screen
+ 3, buf
);
993 snprintf(buf
, 128, "%s",tuner_get_rds_info(RADIO_RDS_NAME
));
995 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
997 snprintf(buf
, 128, "%s",tuner_get_rds_info(RADIO_RDS_TEXT
));
999 screens
[i
].puts_scroll(0, top_of_screen
+ 5, buf
);
1001 #endif /* SIMULATOR */
1003 #if CONFIG_CODEC != SWCODEC
1004 if(audio_status() == AUDIO_STATUS_RECORD
)
1006 hours
= seconds
/ 3600;
1007 minutes
= (seconds
- (hours
* 3600)) / 60;
1008 snprintf(buf
, 32, "%s %02d:%02d:%02d",
1009 str(LANG_RECORDING_TIME
),
1010 hours
, minutes
, seconds
%60);
1012 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
1016 if(rec_options
.rec_prerecord_time
)
1018 snprintf(buf
, 32, "%s %02d",
1019 str(LANG_RECORD_PRERECORD
), seconds
%60);
1021 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
1024 #endif /* CONFIG_CODEC != SWCODEC */
1027 screens
[i
].update_viewport();
1028 #ifdef HAVE_BUTTONBAR
1029 gui_buttonbar_draw(&buttonbar
);
1034 update_screen
= false;
1036 if (global_settings
.talk_file
&& talk
1037 && radio_status
== FMRADIO_PAUSED
)
1040 bool enqueue
= false;
1041 if (radio_mode
== RADIO_SCAN_MODE
)
1043 talk_freq(curr_freq
, enqueue
);
1046 if (curr_preset
>= 0)
1047 talk_preset(curr_preset
, radio_mode
== RADIO_PRESET_MODE
,
1051 #if CONFIG_CODEC != SWCODEC
1052 if(audio_status() & AUDIO_STATUS_ERROR
)
1058 #ifndef HAVE_NOISY_IDLE_MODE
1059 if (TIME_AFTER(current_tick
, button_timeout
))
1061 cpu_idle_mode(true);
1067 #if CONFIG_CODEC != SWCODEC
1068 if(audio_status() & AUDIO_STATUS_ERROR
)
1070 splash(0, str(LANG_DISK_FULL
));
1072 audio_error_clear();
1076 button
= get_action(CONTEXT_FM
, TIMEOUT_BLOCK
);
1077 if(button
== ACTION_FM_STOP
)
1082 audio_init_playback();
1083 #endif /* CONFIG_CODEC != SWCODEC */
1085 sound_settings_apply();
1086 #endif /* SIMULATOR */
1090 /* Catch FMRADIO_PLAYING status for the sim. */
1092 #if CONFIG_CODEC != SWCODEC
1093 /* Enable the Left and right A/D Converter */
1094 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
1095 sound_default(SOUND_RIGHT_GAIN
),
1097 mas_codec_writereg(6, 0x4000);
1100 #endif /* SIMULATOR */
1104 #if CONFIG_CODEC == SWCODEC
1105 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
1111 #ifndef HAVE_NOISY_IDLE_MODE
1112 cpu_idle_mode(false);
1116 screens
[i
].scroll_stop(&vp
[i
]);
1117 screens
[i
].set_viewport(NULL
);
1120 #if CONFIG_CODEC != SWCODEC
1121 return have_recorded
;
1125 } /* radio_screen */
1127 static void radio_save_presets(void)
1132 fd
= creat(filepreset
);
1135 for(i
= 0;i
< num_presets
;i
++)
1137 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
1141 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
1142 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
1143 presets_changed
= false;
1147 splash(HZ
, ID2P(LANG_FM_PRESET_SAVE_FAILED
));
1151 void radio_load_presets(char *filename
)
1161 memset(presets
, 0, sizeof(presets
));
1164 /* No Preset in configuration. */
1165 if(filename
[0] == '\0')
1167 filepreset
[0] = '\0';
1170 /* Temporary preset, loaded until player shuts down. */
1171 else if(filename
[0] == '/')
1172 strlcpy(filepreset
, filename
, sizeof(filepreset
));
1173 /* Preset from default directory. */
1175 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
1176 FMPRESET_PATH
, filename
);
1178 fd
= open_utf8(filepreset
, O_RDONLY
);
1181 while(!done
&& num_presets
< MAX_PRESETS
)
1183 rc
= read_line(fd
, buf
, 128);
1186 if(settings_parseline(buf
, &freq
, &name
))
1189 if(f
) /* For backwards compatibility */
1191 struct fmstation
* const fms
= &presets
[num_presets
];
1193 strlcpy(fms
->name
, name
, MAX_FMPRESET_LEN
+1);
1203 else /* invalid file name? */
1204 filepreset
[0] = '\0';
1206 presets_loaded
= num_presets
> 0;
1207 presets_changed
= false;
1211 static int radio_add_preset(void)
1213 char buf
[MAX_FMPRESET_LEN
+ 1];
1215 if(num_presets
< MAX_PRESETS
)
1219 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1221 struct fmstation
* const fms
= &presets
[num_presets
];
1222 strcpy(fms
->name
, buf
);
1223 fms
->frequency
= curr_freq
;
1225 presets_changed
= true;
1226 presets_loaded
= num_presets
> 0;
1232 splash(HZ
, ID2P(LANG_FM_NO_FREE_PRESETS
));
1237 /* needed to know which preset we are edit/delete-ing */
1238 static int selected_preset
= -1;
1239 static int radio_edit_preset(void)
1241 char buf
[MAX_FMPRESET_LEN
+ 1];
1243 if (num_presets
> 0)
1245 struct fmstation
* const fms
= &presets
[selected_preset
];
1247 strcpy(buf
, fms
->name
);
1249 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1251 strcpy(fms
->name
, buf
);
1252 presets_changed
= true;
1259 static int radio_delete_preset(void)
1261 if (num_presets
> 0)
1263 struct fmstation
* const fms
= &presets
[selected_preset
];
1265 if (selected_preset
>= --num_presets
)
1266 selected_preset
= num_presets
- 1;
1268 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
1271 if (curr_preset
>= num_presets
)
1275 /* Don't ask to save when all presets are deleted. */
1276 presets_changed
= num_presets
> 0;
1278 if (!presets_changed
)
1280 /* The preset list will be cleared, switch to Scan Mode. */
1281 radio_mode
= RADIO_SCAN_MODE
;
1283 presets_loaded
= false;
1289 static int load_preset_list(void)
1291 return !rockbox_browse(FMPRESET_PATH
, SHOW_FMR
);
1294 static int save_preset_list(void)
1298 bool bad_file_name
= true;
1300 if(!dir_exists(FMPRESET_PATH
)) /* Check if there is preset folder */
1301 mkdir(FMPRESET_PATH
);
1303 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
1304 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
1306 while(bad_file_name
)
1308 if(!kbd_input(filepreset
, sizeof(filepreset
)))
1310 /* check the name: max MAX_FILENAME (20) chars */
1314 p1
= strrchr(filepreset
, '/');
1316 while((p1
) && (*p2
) && (*p2
!= '.'))
1318 len
= (int)(p2
-p1
) - 1;
1319 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
1321 /* no slash, too long or too short */
1322 splash(HZ
, ID2P(LANG_INVALID_FILENAME
));
1326 /* add correct extension (easier to always write)
1327 at this point, p2 points to 0 or the extension dot */
1329 strcat(filepreset
,".fmr");
1330 bad_file_name
= false;
1331 radio_save_presets();
1342 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
1347 static int clear_preset_list(void)
1349 /* Clear all the preset entries */
1350 memset(presets
, 0, sizeof (presets
));
1353 presets_loaded
= false;
1354 /* The preset list will be cleared switch to Scan Mode. */
1355 radio_mode
= RADIO_SCAN_MODE
;
1358 presets_changed
= false; /* Don't ask to save when clearing the list. */
1363 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1364 ID2P(LANG_FM_EDIT_PRESET
),
1365 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
1366 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1367 ID2P(LANG_FM_DELETE_PRESET
),
1368 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
1369 static int radio_preset_callback(int action
,
1370 const struct menu_item_ex
*this_item
)
1372 if (action
== ACTION_STD_OK
)
1373 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
1377 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_PRESET
),
1378 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
1379 &radio_delete_preset_item
);
1380 /* present a list of preset stations */
1381 static const char* presets_get_name(int selected_item
, void *data
,
1382 char *buffer
, size_t buffer_len
)
1385 struct fmstation
*p
= &presets
[selected_item
];
1388 int freq
= p
->frequency
/ 10000;
1389 int frac
= freq
% 100;
1391 snprintf(buffer
, buffer_len
,
1392 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
1396 static int presets_speak_name(int selected_item
, void * data
)
1399 talk_preset(selected_item
, true, false);
1403 static int handle_radio_presets(void)
1405 struct gui_synclist lists
;
1407 int action
= ACTION_NONE
;
1408 #ifdef HAVE_BUTTONBAR
1409 struct gui_buttonbar buttonbar
;
1412 if(presets_loaded
== false)
1415 #ifdef HAVE_BUTTONBAR
1416 gui_buttonbar_init(&buttonbar
);
1417 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
1418 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
1419 str(LANG_FM_BUTTONBAR_EXIT
),
1420 str(LANG_FM_BUTTONBAR_ACTION
));
1421 gui_buttonbar_draw(&buttonbar
);
1423 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1, NULL
);
1424 gui_synclist_set_title(&lists
, str(LANG_PRESET
), NOICON
);
1425 gui_synclist_set_icon_callback(&lists
, NULL
);
1426 if(global_settings
.talk_file
)
1427 gui_synclist_set_voice_callback(&lists
, presets_speak_name
);
1428 gui_synclist_set_nb_items(&lists
, num_presets
);
1429 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
1430 gui_synclist_speak_item(&lists
);
1434 gui_synclist_draw(&lists
);
1435 list_do_action(CONTEXT_STD
, TIMEOUT_BLOCK
,
1436 &lists
, &action
, LIST_WRAP_UNLESS_HELD
);
1439 case ACTION_STD_MENU
:
1440 if (radio_add_preset())
1442 gui_synclist_set_nb_items(&lists
, num_presets
);
1443 gui_synclist_select_item(&lists
, num_presets
- 1);
1446 case ACTION_STD_CANCEL
:
1450 curr_preset
= gui_synclist_get_sel_pos(&lists
);
1451 curr_freq
= presets
[curr_preset
].frequency
;
1453 remember_frequency();
1457 case ACTION_STD_CONTEXT
:
1458 selected_preset
= gui_synclist_get_sel_pos(&lists
);
1459 do_menu(&handle_radio_preset_menu
, NULL
, NULL
, false);
1460 gui_synclist_set_nb_items(&lists
, num_presets
);
1461 gui_synclist_select_item(&lists
, selected_preset
);
1462 gui_synclist_speak_item(&lists
);
1465 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
1469 gui_synclist_scroll_stop(&lists
);
1473 void toggle_mono_mode(bool mono
)
1475 tuner_set(RADIO_FORCE_MONO
, mono
);
1478 void set_radio_region(int region
)
1480 #ifdef HAVE_RADIO_REGION
1481 tuner_set(RADIO_REGION
, region
);
1484 remember_frequency();
1488 MENUITEM_SETTING(set_region
, &global_settings
.fm_region
, NULL
);
1489 MENUITEM_SETTING(force_mono
, &global_settings
.fm_force_mono
, NULL
);
1492 static char* get_mode_text(int selected_item
, void * data
, char *buffer
)
1494 (void)selected_item
;
1496 snprintf(buffer
, MAX_PATH
, "%s %s", str(LANG_MODE
),
1497 radio_mode
? str(LANG_PRESET
) :
1498 str(LANG_RADIO_SCAN_MODE
));
1501 static int toggle_radio_mode(void)
1503 radio_mode
= (radio_mode
== RADIO_SCAN_MODE
) ?
1504 RADIO_PRESET_MODE
: RADIO_SCAN_MODE
;
1507 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item
, 0,
1508 toggle_radio_mode
, NULL
,
1509 get_mode_text
, NULL
, NULL
, NULL
, Icon_NOICON
);
1512 static int scan_presets(void *viewports
)
1514 bool do_scan
= true;
1516 struct viewport
*vp
= (struct viewport
*)viewports
;
1519 screens
[i
].set_viewport(vp
?&vp
[i
]:NULL
);
1520 if(num_presets
> 0) /* Do that to avoid 2 questions. */
1521 do_scan
= yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS
));
1525 const struct fm_region_data
* const fmr
=
1526 &fm_region_data
[global_settings
.fm_region
];
1528 curr_freq
= fmr
->freq_min
;
1530 memset(presets
, 0, sizeof(presets
));
1532 tuner_set(RADIO_MUTE
, 1);
1534 while(curr_freq
<= fmr
->freq_max
)
1537 if(num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
1540 freq
= curr_freq
/ 10000;
1544 splashf(0, str(LANG_FM_SCANNING
), freq
, frac
);
1546 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
1549 presets
[num_presets
].name
[0] = '\0';
1550 presets
[num_presets
].frequency
= curr_freq
;
1554 curr_freq
+= fmr
->freq_step
;
1557 if (radio_status
== FMRADIO_PLAYING
)
1558 tuner_set(RADIO_MUTE
, 0);
1560 presets_changed
= true;
1564 screens
[i
].clear_viewport();
1565 screens
[i
].update_viewport();
1570 curr_freq
= presets
[0].frequency
;
1571 radio_mode
= RADIO_PRESET_MODE
;
1572 presets_loaded
= true;
1577 /* Wrap it to beginning or we'll be past end of band */
1578 presets_loaded
= false;
1586 #ifdef HAVE_RECORDING
1588 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1589 #define FM_RECORDING_SCREEN
1590 static int fm_recording_screen(void)
1594 /* switch recording source to FMRADIO for the duration */
1595 int rec_source
= global_settings
.rec_source
;
1596 global_settings
.rec_source
= AUDIO_SRC_FMRADIO
;
1597 ret
= recording_screen(true);
1599 /* safe to reset as changing sources is prohibited here */
1600 global_settings
.rec_source
= rec_source
;
1605 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1607 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1608 #define FM_RECORDING_SETTINGS
1609 static int fm_recording_settings(void)
1611 bool ret
= recording_menu(true);
1613 #if CONFIG_CODEC != SWCODEC
1616 struct audio_recording_options rec_options
;
1617 rec_init_recording_options(&rec_options
);
1618 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
1619 rec_set_recording_options(&rec_options
);
1626 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1627 #endif /* HAVE_RECORDING */
1629 #ifdef FM_RECORDING_SCREEN
1630 MENUITEM_FUNCTION(recscreen_item
, 0, ID2P(LANG_RECORDING
),
1631 fm_recording_screen
, NULL
, NULL
, Icon_Recording
);
1633 #ifdef FM_RECORDING_SETTINGS
1634 MENUITEM_FUNCTION(recsettings_item
, 0, ID2P(LANG_RECORDING_SETTINGS
),
1635 fm_recording_settings
, NULL
, NULL
, Icon_Recording
);
1638 MENUITEM_FUNCTION(radio_presets_item
, 0, ID2P(LANG_PRESET
),
1639 handle_radio_presets
, NULL
, NULL
, Icon_NOICON
);
1641 #ifndef FM_PRESET_ADD
1642 MENUITEM_FUNCTION(radio_addpreset_item
, 0, ID2P(LANG_FM_ADD_PRESET
),
1643 radio_add_preset
, NULL
, NULL
, Icon_NOICON
);
1647 MENUITEM_FUNCTION(presetload_item
, 0, ID2P(LANG_FM_PRESET_LOAD
),
1648 load_preset_list
, NULL
, NULL
, Icon_NOICON
);
1649 MENUITEM_FUNCTION(presetsave_item
, 0, ID2P(LANG_FM_PRESET_SAVE
),
1650 save_preset_list
, NULL
, NULL
, Icon_NOICON
);
1651 MENUITEM_FUNCTION(presetclear_item
, 0, ID2P(LANG_FM_PRESET_CLEAR
),
1652 clear_preset_list
, NULL
, NULL
, Icon_NOICON
);
1653 MENUITEM_FUNCTION(scan_presets_item
, MENU_FUNC_USEPARAM
,
1654 ID2P(LANG_FM_SCAN_PRESETS
),
1655 scan_presets
, NULL
, NULL
, Icon_NOICON
);
1657 MAKE_MENU(radio_settings_menu
, ID2P(LANG_FM_MENU
), NULL
,
1660 &radio_presets_item
,
1662 #ifndef FM_PRESET_ADD
1663 &radio_addpreset_item
,
1665 &presetload_item
, &presetsave_item
, &presetclear_item
,
1670 &set_region
, &sound_settings
,
1671 #ifdef FM_RECORDING_SCREEN
1674 #ifdef FM_RECORDING_SETTINGS
1677 &scan_presets_item
);
1678 /* main menu of the radio screen */
1679 static bool radio_menu(void)
1681 return do_menu(&radio_settings_menu
, NULL
, NULL
, false) ==