1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2003 Linus Nielsen Feltzing
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
34 #include "mp3_playback.h"
45 #include "peakmeter.h"
48 #include "sound_menu.h"
50 #include "recording.h"
56 #include "screen_access.h"
57 #include "statusbar.h"
60 #include "buttonbar.h"
66 #include "menus/exported_menus.h"
67 #include "root_menu.h"
72 #if CONFIG_KEYPAD == RECORDER_PAD
75 #define FM_PRESET_ACTION
79 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
82 #define FM_NEXT_PRESET
83 #define FM_PREV_PRESET
85 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
89 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
92 /* This should be removeable if the whole tuning thing is sorted out since
93 proper tuning quiets the screen almost entirely in that extreme measures
94 have to be taken to hear any interference. */
95 #define HAVE_NOISY_IDLE_MODE
97 #elif CONFIG_KEYPAD == ONDIO_PAD
98 #define FM_RECORD_DBLPRE
100 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD)
108 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
113 #define RADIO_SCAN_MODE 0
114 #define RADIO_PRESET_MODE 1
116 static int curr_preset
= -1;
117 static int curr_freq
; /* current frequency in Hz */
118 static int radio_mode
= RADIO_SCAN_MODE
;
119 static int search_dir
= 0;
121 static int radio_status
= FMRADIO_OFF
;
122 static bool in_screen
= false;
124 #define MAX_PRESETS 64
125 static bool presets_loaded
= false, presets_changed
= false;
126 static struct fmstation presets
[MAX_PRESETS
];
128 static char filepreset
[MAX_PATH
]; /* preset filename variable */
130 static int num_presets
= 0; /* The number of presets in the preset list */
132 static void radio_save_presets(void);
133 static int handle_radio_presets(void);
134 static bool radio_menu(void);
135 static int radio_add_preset(void);
136 static int save_preset_list(void);
137 static int load_preset_list(void);
138 static int clear_preset_list(void);
140 static int scan_presets(void *viewports
);
142 /* Function to manipulate all yesno dialogues.
143 This function needs the output text as an argument. */
144 static bool yesno_pop(const char* text
)
147 const char *lines
[]={text
};
148 const struct text_message message
={lines
, 1};
149 bool ret
= (gui_syncyesno_run(&message
,NULL
,NULL
)== YESNO_YES
);
151 screens
[i
].clear_viewport();
155 void radio_init(void)
161 int get_radio_status(void)
166 bool in_radio_screen(void)
171 /* TODO: Move some more of the control functionality to firmware
172 and clean up the mess */
174 /* secret flag for starting paused - prevents unmute */
175 #define FMRADIO_START_PAUSED 0x8000
176 void radio_start(void)
178 const struct fm_region_data
*fmr
;
181 if(radio_status
== FMRADIO_PLAYING
)
184 fmr
= &fm_region_data
[global_settings
.fm_region
];
186 start_paused
= radio_status
& FMRADIO_START_PAUSED
;
187 /* clear flag before any yielding */
188 radio_status
&= ~FMRADIO_START_PAUSED
;
190 if(radio_status
== FMRADIO_OFF
)
193 curr_freq
= global_status
.last_frequency
* fmr
->freq_step
+ fmr
->freq_min
;
195 tuner_set(RADIO_SLEEP
, 0); /* wake up the tuner */
197 if(radio_status
== FMRADIO_OFF
)
199 #ifdef HAVE_RADIO_REGION
200 tuner_set(RADIO_REGION
, global_settings
.fm_region
);
202 tuner_set(RADIO_FORCE_MONO
, global_settings
.fm_force_mono
);
205 tuner_set(RADIO_FREQUENCY
, curr_freq
);
207 #ifdef HAVE_RADIO_MUTE_TIMEOUT
209 unsigned long mute_timeout
= current_tick
+ HZ
;
210 if (radio_status
!= FMRADIO_OFF
)
216 while(!tuner_get(RADIO_STEREO
) && !tuner_get(RADIO_TUNED
))
218 if(TIME_AFTER(current_tick
, mute_timeout
))
225 /* keep radio from sounding initially */
227 tuner_set(RADIO_MUTE
, 0);
229 radio_status
= FMRADIO_PLAYING
;
232 void radio_pause(void)
234 if(radio_status
== FMRADIO_PAUSED
)
237 if(radio_status
== FMRADIO_OFF
)
239 radio_status
|= FMRADIO_START_PAUSED
;
243 tuner_set(RADIO_MUTE
, 1);
244 tuner_set(RADIO_SLEEP
, 1);
246 radio_status
= FMRADIO_PAUSED
;
249 void radio_stop(void)
251 if(radio_status
== FMRADIO_OFF
)
254 tuner_set(RADIO_MUTE
, 1);
255 tuner_set(RADIO_SLEEP
, 1); /* low power mode, if available */
256 radio_status
= FMRADIO_OFF
;
257 tuner_power(false); /* status update, power off if avail. */
260 bool radio_hardware_present(void)
262 return tuner_get(RADIO_PRESENT
);
265 /* Keep freq on the grid for the current region */
266 static int snap_freq_to_grid(int freq
)
268 const struct fm_region_data
* const fmr
=
269 &fm_region_data
[global_settings
.fm_region
];
271 /* Range clamp if out of range or just round to nearest */
272 if (freq
< fmr
->freq_min
)
273 freq
= fmr
->freq_min
;
274 else if (freq
> fmr
->freq_max
)
275 freq
= fmr
->freq_max
;
277 freq
= (freq
- fmr
->freq_min
+ fmr
->freq_step
/2) /
278 fmr
->freq_step
* fmr
->freq_step
+ fmr
->freq_min
;
283 /* Find a matching preset to freq */
284 static int find_preset(int freq
)
289 for(i
= 0;i
< MAX_PRESETS
;i
++)
291 if(freq
== presets
[i
].frequency
)
298 /* Return the closest preset encountered in the search direction with
300 static int find_closest_preset(int freq
, int direction
)
307 if (direction
== 0) /* direction == 0 isn't really used */
310 for (i
= 0; i
< num_presets
; i
++)
312 int f
= presets
[i
].frequency
;
314 return i
; /* Exact match = stop */
316 /* remember the highest and lowest presets for wraparound */
317 if (f
< presets
[lowpreset
].frequency
)
319 if (f
> presets
[highpreset
].frequency
)
322 /* find the closest preset in the given direction */
323 if (direction
> 0 && f
> freq
)
325 if (closest
< 0 || f
< presets
[closest
].frequency
)
328 else if (direction
< 0 && f
< freq
)
330 if (closest
< 0 || f
> presets
[closest
].frequency
)
337 /* no presets in the given direction */
338 /* wrap around depending on direction */
340 closest
= highpreset
;
348 static void remember_frequency(void)
350 const struct fm_region_data
* const fmr
=
351 &fm_region_data
[global_settings
.fm_region
];
352 global_status
.last_frequency
= (curr_freq
- fmr
->freq_min
)
357 static void next_preset(int direction
)
362 if (curr_preset
== -1)
363 curr_preset
= find_closest_preset(curr_freq
, direction
);
365 curr_preset
= (curr_preset
+ direction
+ num_presets
) % num_presets
;
367 /* Must stay on the current grid for the region */
368 curr_freq
= snap_freq_to_grid(presets
[curr_preset
].frequency
);
370 tuner_set(RADIO_FREQUENCY
, curr_freq
);
371 remember_frequency();
374 /* Step to the next or previous frequency */
375 static int step_freq(int freq
, int direction
)
377 const struct fm_region_data
* const fmr
=
378 &fm_region_data
[global_settings
.fm_region
];
380 freq
+= direction
*fmr
->freq_step
;
382 /* Wrap first or snapping to grid will not let us on the band extremes */
383 if (freq
> fmr
->freq_max
)
384 freq
= direction
> 0 ? fmr
->freq_min
: fmr
->freq_max
;
385 else if (freq
< fmr
->freq_min
)
386 freq
= direction
< 0 ? fmr
->freq_max
: fmr
->freq_min
;
388 freq
= snap_freq_to_grid(freq
);
393 /* Step to the next or previous station */
394 static void next_station(int direction
)
396 if (direction
!= 0 && radio_mode
!= RADIO_SCAN_MODE
)
398 next_preset(direction
);
402 curr_freq
= step_freq(curr_freq
, direction
);
404 if (radio_status
== FMRADIO_PLAYING
)
405 tuner_set(RADIO_MUTE
, 1);
407 tuner_set(RADIO_FREQUENCY
, curr_freq
);
409 if (radio_status
== FMRADIO_PLAYING
)
410 tuner_set(RADIO_MUTE
, 0);
412 curr_preset
= find_preset(curr_freq
);
413 remember_frequency();
416 /* Ends an in-progress search */
417 static void end_search(void)
419 if (search_dir
!= 0 && radio_status
== FMRADIO_PLAYING
)
420 tuner_set(RADIO_MUTE
, 0);
424 /* Speak a frequency. */
425 static void talk_freq(int freq
, bool enqueue
)
428 talk_number(freq
/ 100, enqueue
);
429 talk_id(LANG_POINT
, true);
430 talk_number(freq
% 100 / 10, true);
432 talk_number(freq
% 10, true);
435 /* Speak a preset by number or by spelling its name, depending on settings. */
436 static void talk_preset(int preset
, bool fallback
, bool enqueue
)
438 if (global_settings
.talk_file
== 1) /* number */
439 talk_number(preset
+ 1, enqueue
);
442 if(presets
[preset
].name
[0])
443 talk_spell(presets
[preset
].name
, enqueue
);
445 talk_freq(presets
[preset
].frequency
, enqueue
);
449 int radio_screen(void)
453 int ret_val
= GO_TO_ROOT
;
456 bool stereo
= false, last_stereo
= false;
458 int top_of_screen
= 0;
459 bool update_screen
= true;
460 bool screen_freeze
= false;
461 bool keep_playing
= false;
462 bool statusbar
= global_settings
.statusbar
;
464 #ifdef FM_RECORD_DBLPRE
465 int lastbutton
= BUTTON_NONE
;
466 unsigned long rec_lastclick
= 0;
468 #if CONFIG_CODEC != SWCODEC
469 bool have_recorded
= false;
470 int timeout
= current_tick
+ HZ
/10;
471 unsigned int seconds
= 0;
472 unsigned int last_seconds
= 0;
474 struct audio_recording_options rec_options
;
475 #endif /* CONFIG_CODEC != SWCODEC */
476 #ifndef HAVE_NOISY_IDLE_MODE
477 int button_timeout
= current_tick
+ (2*HZ
);
479 struct viewport vp
[NB_SCREENS
];
480 #ifdef HAVE_BUTTONBAR
481 struct gui_buttonbar buttonbar
;
482 gui_buttonbar_init(&buttonbar
);
483 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
486 /* change status to "in screen" */
489 /* always display status bar in radio screen for now */
490 global_status
.statusbar_forced
= statusbar
?0:1;
491 global_settings
.statusbar
= true;
494 viewport_set_defaults(&vp
[i
], i
);
495 #ifdef HAVE_BUTTONBAR
496 if (global_settings
.buttonbar
)
497 vp
[i
].height
-= BUTTONBAR_HEIGHT
;
499 screens
[i
].set_viewport(&vp
[i
]);
500 screens
[i
].stop_scroll();
501 screens
[i
].clear_viewport();
502 screens
[i
].update_viewport();
505 fh
= font_get(FONT_UI
)->height
;
507 /* Adjust for font size, trying to center the information vertically */
513 memset(presets
, 0, sizeof(presets
));
514 radio_load_presets(global_settings
.fmr_file
);
517 if(radio_status
== FMRADIO_OFF
)
521 #if CONFIG_CODEC != SWCODEC
522 if(rec_create_directory() > 0)
523 have_recorded
= true;
525 audio_init_recording(talk_get_bufsize());
527 sound_settings_apply();
528 /* Yes, we use the D/A for monitoring */
529 peak_meter_playback(true);
531 peak_meter_enabled
= true;
533 rec_init_recording_options(&rec_options
);
534 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
535 rec_set_recording_options(&rec_options
);
537 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
538 sound_default(SOUND_RIGHT_GAIN
), AUDIO_GAIN_LINEIN
);
540 #endif /* CONFIG_CODEC != SWCODEC */
541 #endif /* ndef SIMULATOR */
544 #if CONFIG_CODEC == SWCODEC
545 audio_set_input_source(AUDIO_SRC_FMRADIO
,
546 (radio_status
== FMRADIO_PAUSED
) ?
547 SRCF_FMRADIO_PAUSED
: SRCF_FMRADIO_PLAYING
);
549 if (radio_status
== FMRADIO_OFF
)
553 if(num_presets
< 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN
)))
556 curr_preset
= find_preset(curr_freq
);
557 if(curr_preset
!= -1)
558 radio_mode
= RADIO_PRESET_MODE
;
560 #ifdef HAVE_BUTTONBAR
561 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
562 str(LANG_PRESET
), str(LANG_FM_BUTTONBAR_RECORD
));
565 #ifndef HAVE_NOISY_IDLE_MODE
573 curr_freq
= step_freq(curr_freq
, search_dir
);
574 update_screen
= true;
576 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
578 curr_preset
= find_preset(curr_freq
);
579 remember_frequency();
592 #if CONFIG_CODEC != SWCODEC
593 /* TODO: Can we timeout at HZ when recording since peaks aren't
594 displayed? This should quiet recordings too. */
595 button
= get_action(CONTEXT_FM
,
596 update_screen
? TIMEOUT_NOBLOCK
: HZ
/ PEAK_METER_FPS
);
598 button
= get_action(CONTEXT_FM
,
599 update_screen
? TIMEOUT_NOBLOCK
: HZ
);
602 #ifndef HAVE_NOISY_IDLE_MODE
603 if (button
!= ACTION_NONE
)
605 cpu_idle_mode(false);
606 button_timeout
= current_tick
+ (2*HZ
);
612 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
613 if(audio_status() == AUDIO_STATUS_RECORD
)
623 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
625 if(filepreset
[0] == '\0')
628 radio_save_presets();
631 /* Clear the preset list on exit. */
634 update_screen
= true;
638 case ACTION_FM_RECORD
:
639 #ifdef FM_RECORD_DBLPRE
640 if (lastbutton
!= ACTION_FM_RECORD_DBLPRE
)
645 if (current_tick
- rec_lastclick
> HZ
/2)
647 rec_lastclick
= current_tick
;
650 #endif /* FM_RECORD_DBLPRE */
652 if(audio_status() == AUDIO_STATUS_RECORD
)
654 rec_command(RECORDING_CMD_START_NEWFILE
);
655 update_screen
= true;
659 have_recorded
= true;
660 rec_command(RECORDING_CMD_START
);
661 update_screen
= true;
663 #endif /* SIMULATOR */
666 #endif /* #ifdef FM_RECORD */
669 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
670 if(audio_status() == AUDIO_STATUS_RECORD
)
675 ret_val
= GO_TO_ROOT
;
678 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
680 if(filepreset
[0] == '\0')
683 radio_save_presets();
687 /* Clear the preset list on exit. */
692 case ACTION_STD_PREV
:
693 case ACTION_STD_NEXT
:
694 next_station(button
== ACTION_STD_PREV
? -1 : 1);
696 update_screen
= true;
700 case ACTION_STD_PREVREPEAT
:
701 case ACTION_STD_NEXTREPEAT
:
703 int dir
= search_dir
;
704 search_dir
= button
== ACTION_STD_PREVREPEAT
? -1 : 1;
705 if (radio_mode
!= RADIO_SCAN_MODE
)
707 next_preset(search_dir
);
709 update_screen
= true;
714 /* Starting auto scan */
715 tuner_set(RADIO_MUTE
, 1);
716 update_screen
= true;
721 case ACTION_SETTINGS_INC
:
722 case ACTION_SETTINGS_INCREPEAT
:
723 global_settings
.volume
++;
725 update_screen
= true;
728 case ACTION_SETTINGS_DEC
:
729 case ACTION_SETTINGS_DECREPEAT
:
730 global_settings
.volume
--;
732 update_screen
= true;
736 if (radio_status
== FMRADIO_PLAYING
)
741 update_screen
= true;
748 curr_preset
= find_preset(curr_freq
);
751 screens
[i
].set_viewport(&vp
[i
]);
752 screens
[i
].clear_viewport();
753 screens
[i
].update_viewport();
754 screens
[i
].set_viewport(NULL
);
756 #ifdef HAVE_BUTTONBAR
757 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
759 str(LANG_FM_BUTTONBAR_RECORD
));
761 update_screen
= true;
765 case ACTION_FM_PRESET
:
768 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
769 update_screen
= true;
772 screens
[i
].set_viewport(&vp
[i
]);
773 screens
[i
].clear_viewport();
774 screens
[i
].update_viewport();
775 screens
[i
].set_viewport(NULL
);
780 handle_radio_presets();
783 screens
[i
].set_viewport(&vp
[i
]);
784 screens
[i
].stop_scroll();
785 screens
[i
].clear_viewport();
786 screens
[i
].update_viewport();
787 screens
[i
].set_viewport(NULL
);
789 #ifdef HAVE_BUTTONBAR
790 gui_buttonbar_set(&buttonbar
,
791 str(LANG_BUTTONBAR_MENU
),
793 str(LANG_FM_BUTTONBAR_RECORD
));
795 update_screen
= true;
797 #endif /* FM_PRESET */
800 case ACTION_FM_FREEZE
:
803 splash(HZ
, str(LANG_FM_FREEZE
));
804 screen_freeze
= true;
808 update_screen
= true;
809 screen_freeze
= false;
812 #endif /* FM_FREEZE */
814 case SYS_USB_CONNECTED
:
815 #if CONFIG_CODEC != SWCODEC
816 /* Only accept USB connection when not recording */
817 if(audio_status() != AUDIO_STATUS_RECORD
)
820 default_event_handler(SYS_USB_CONNECTED
);
821 screen_freeze
= true; /* Cosmetic: makes sure the
822 radio screen doesn't redraw */
829 if(radio_mode
== RADIO_SCAN_MODE
)
831 /* Force scan mode if there are no presets. */
833 radio_mode
= RADIO_PRESET_MODE
;
836 radio_mode
= RADIO_SCAN_MODE
;
837 update_screen
= true;
838 cond_talk_ids_fq(radio_mode
?
839 LANG_PRESET
: LANG_RADIO_SCAN_MODE
);
844 #ifdef FM_NEXT_PRESET
845 case ACTION_FM_NEXT_PRESET
:
848 update_screen
= true;
853 #ifdef FM_PREV_PRESET
854 case ACTION_FM_PREV_PRESET
:
857 update_screen
= true;
863 default_event_handler(button
);
867 #ifdef FM_RECORD_DBLPRE
868 if (button
!= ACTION_NONE
)
872 #if CONFIG_CODEC != SWCODEC
878 /* Only display the peak meter when not recording */
879 #if CONFIG_CODEC != SWCODEC
884 screens
[i
].set_viewport(&vp
[i
]);
885 peak_meter_screen(&screens
[i
],0,
886 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
888 screens
[i
].update_rect(0,
889 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
890 screens
[i
].getwidth(), fh
);
891 screens
[i
].set_viewport(NULL
);
895 if(TIME_AFTER(current_tick
, timeout
))
897 timeout
= current_tick
+ HZ
;
900 #endif /* CONFIG_CODEC == SWCODEC */
902 /* keep "mono" from always being displayed when paused */
903 if (radio_status
!= FMRADIO_PAUSED
)
905 stereo
= tuner_get(RADIO_STEREO
) &&
906 !global_settings
.fm_force_mono
;
908 if(stereo
!= last_stereo
)
910 update_screen
= true;
911 last_stereo
= stereo
;
916 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
917 seconds
= audio_recorded_time() / HZ
;
918 if (update_screen
|| seconds
> last_seconds
)
920 last_seconds
= seconds
;
929 screens
[i
].set_viewport(&vp
[i
]);
932 snprintf(buf
, 128, curr_preset
>= 0 ? "%d. %s" : " ",
933 curr_preset
+ 1, presets
[curr_preset
].name
);
936 screens
[i
].puts_scroll(0, top_of_screen
, buf
);
938 freq
= curr_freq
/ 10000;
939 snprintf(buf
, 128, str(LANG_FM_STATION
),
940 freq
/ 100, freq
% 100);
942 screens
[i
].puts_scroll(0, top_of_screen
+ 1, buf
);
944 snprintf(buf
, 128, "%s", stereo
?str(LANG_CHANNEL_STEREO
):
945 str(LANG_CHANNEL_MONO
));
947 screens
[i
].puts_scroll(0, top_of_screen
+ 2, buf
);
949 snprintf(buf
, 128, "%s %s", str(LANG_MODE
),
950 radio_mode
? str(LANG_PRESET
) :
951 str(LANG_RADIO_SCAN_MODE
));
953 screens
[i
].puts_scroll(0, top_of_screen
+ 3, buf
);
955 #if CONFIG_CODEC != SWCODEC
956 if(audio_status() == AUDIO_STATUS_RECORD
)
958 hours
= seconds
/ 3600;
959 minutes
= (seconds
- (hours
* 3600)) / 60;
960 snprintf(buf
, 32, "%s %02d:%02d:%02d",
961 str(LANG_RECORDING_TIME
),
962 hours
, minutes
, seconds
%60);
964 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
968 if(rec_options
.rec_prerecord_time
)
970 snprintf(buf
, 32, "%s %02d",
971 str(LANG_RECORD_PRERECORD
), seconds
%60);
973 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
976 #endif /* CONFIG_CODEC != SWCODEC */
980 screens
[i
].update_viewport();
981 screens
[i
].set_viewport(NULL
);
984 #ifdef HAVE_BUTTONBAR
985 gui_buttonbar_draw(&buttonbar
);
990 update_screen
= false;
992 if (global_settings
.talk_file
&& talk
993 && radio_status
== FMRADIO_PAUSED
)
996 bool enqueue
= false;
997 if (radio_mode
== RADIO_SCAN_MODE
)
999 talk_freq(curr_freq
, enqueue
);
1002 if (curr_preset
>= 0)
1003 talk_preset(curr_preset
, radio_mode
== RADIO_PRESET_MODE
,
1007 #if CONFIG_CODEC != SWCODEC
1008 if(audio_status() & AUDIO_STATUS_ERROR
)
1014 #ifndef HAVE_NOISY_IDLE_MODE
1015 if (TIME_AFTER(current_tick
, button_timeout
))
1017 cpu_idle_mode(true);
1023 #if CONFIG_CODEC != SWCODEC
1024 if(audio_status() & AUDIO_STATUS_ERROR
)
1026 splash(0, str(LANG_DISK_FULL
));
1029 screens
[i
].set_viewport(&vp
[i
]);
1030 screens
[i
].update_viewport();
1031 screens
[i
].set_viewport(NULL
);
1033 audio_error_clear();
1037 button
= get_action(CONTEXT_FM
, TIMEOUT_BLOCK
);
1038 if(button
== ACTION_FM_STOP
)
1043 audio_init_playback();
1044 #endif /* CONFIG_CODEC != SWCODEC */
1046 sound_settings_apply();
1047 #endif /* SIMULATOR */
1051 /* Catch FMRADIO_PLAYING status for the sim. */
1053 #if CONFIG_CODEC != SWCODEC
1054 /* Enable the Left and right A/D Converter */
1055 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
1056 sound_default(SOUND_RIGHT_GAIN
),
1058 mas_codec_writereg(6, 0x4000);
1061 #endif /* SIMULATOR */
1065 #if CONFIG_CODEC == SWCODEC
1066 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
1072 #ifndef HAVE_NOISY_IDLE_MODE
1073 cpu_idle_mode(false);
1076 /* restore status bar settings */
1077 global_settings
.statusbar
= statusbar
;
1078 global_status
.statusbar_forced
= 0;
1080 #if CONFIG_CODEC != SWCODEC
1081 return have_recorded
;
1085 } /* radio_screen */
1087 static void radio_save_presets(void)
1092 fd
= creat(filepreset
);
1095 for(i
= 0;i
< num_presets
;i
++)
1097 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
1101 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
1102 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
1103 presets_changed
= false;
1107 splash(HZ
, ID2P(LANG_FM_PRESET_SAVE_FAILED
));
1111 void radio_load_presets(char *filename
)
1121 memset(presets
, 0, sizeof(presets
));
1124 /* No Preset in configuration. */
1125 if(filename
[0] == '\0')
1127 filepreset
[0] = '\0';
1130 /* Temporary preset, loaded until player shuts down. */
1131 else if(filename
[0] == '/')
1132 strncpy(filepreset
, filename
, sizeof(filepreset
));
1133 /* Preset from default directory. */
1135 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
1136 FMPRESET_PATH
, filename
);
1138 fd
= open_utf8(filepreset
, O_RDONLY
);
1141 while(!done
&& num_presets
< MAX_PRESETS
)
1143 rc
= read_line(fd
, buf
, 128);
1146 if(settings_parseline(buf
, &freq
, &name
))
1149 if(f
) /* For backwards compatibility */
1151 struct fmstation
* const fms
= &presets
[num_presets
];
1153 strncpy(fms
->name
, name
, MAX_FMPRESET_LEN
);
1154 fms
->name
[MAX_FMPRESET_LEN
] = '\0';
1164 else /* invalid file name? */
1165 filepreset
[0] = '\0';
1167 presets_loaded
= num_presets
> 0;
1168 presets_changed
= false;
1172 static int radio_add_preset(void)
1174 char buf
[MAX_FMPRESET_LEN
+ 1];
1176 if(num_presets
< MAX_PRESETS
)
1180 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1182 struct fmstation
* const fms
= &presets
[num_presets
];
1183 strcpy(fms
->name
, buf
);
1184 fms
->frequency
= curr_freq
;
1186 presets_changed
= true;
1187 presets_loaded
= num_presets
> 0;
1193 splash(HZ
, ID2P(LANG_FM_NO_FREE_PRESETS
));
1198 /* needed to know which preset we are edit/delete-ing */
1199 static int selected_preset
= -1;
1200 static int radio_edit_preset(void)
1202 char buf
[MAX_FMPRESET_LEN
+ 1];
1204 if (num_presets
> 0)
1206 struct fmstation
* const fms
= &presets
[selected_preset
];
1208 strcpy(buf
, fms
->name
);
1210 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1212 strcpy(fms
->name
, buf
);
1213 presets_changed
= true;
1220 static int radio_delete_preset(void)
1222 if (num_presets
> 0)
1224 struct fmstation
* const fms
= &presets
[selected_preset
];
1226 if (selected_preset
>= --num_presets
)
1227 selected_preset
= num_presets
- 1;
1229 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
1232 if (curr_preset
>= num_presets
)
1236 /* Don't ask to save when all presets are deleted. */
1237 presets_changed
= num_presets
> 0;
1239 if (!presets_changed
)
1241 /* The preset list will be cleared, switch to Scan Mode. */
1242 radio_mode
= RADIO_SCAN_MODE
;
1244 presets_loaded
= false;
1250 static int load_preset_list(void)
1252 return !rockbox_browse(FMPRESET_PATH
, SHOW_FMR
);
1255 static int save_preset_list(void)
1259 bool bad_file_name
= true;
1261 if(!dir_exists(FMPRESET_PATH
)) /* Check if there is preset folder */
1262 mkdir(FMPRESET_PATH
);
1264 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
1265 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
1267 while(bad_file_name
)
1269 if(!kbd_input(filepreset
, sizeof(filepreset
)))
1271 /* check the name: max MAX_FILENAME (20) chars */
1275 p1
= strrchr(filepreset
, '/');
1277 while((p1
) && (*p2
) && (*p2
!= '.'))
1279 len
= (int)(p2
-p1
) - 1;
1280 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
1282 /* no slash, too long or too short */
1283 splash(HZ
, ID2P(LANG_INVALID_FILENAME
));
1287 /* add correct extension (easier to always write)
1288 at this point, p2 points to 0 or the extension dot */
1290 strcat(filepreset
,".fmr");
1291 bad_file_name
= false;
1292 radio_save_presets();
1303 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
1308 static int clear_preset_list(void)
1310 /* Clear all the preset entries */
1311 memset(presets
, 0, sizeof (presets
));
1314 presets_loaded
= false;
1315 /* The preset list will be cleared switch to Scan Mode. */
1316 radio_mode
= RADIO_SCAN_MODE
;
1319 presets_changed
= false; /* Don't ask to save when clearing the list. */
1324 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1325 ID2P(LANG_FM_EDIT_PRESET
),
1326 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
1327 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1328 ID2P(LANG_FM_DELETE_PRESET
),
1329 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
1330 static int radio_preset_callback(int action
,
1331 const struct menu_item_ex
*this_item
)
1333 if (action
== ACTION_STD_OK
)
1334 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
1338 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_PRESET
),
1339 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
1340 &radio_delete_preset_item
);
1341 /* present a list of preset stations */
1342 static char * presets_get_name(int selected_item
, void *data
,
1343 char *buffer
, size_t buffer_len
)
1346 struct fmstation
*p
= &presets
[selected_item
];
1349 int freq
= p
->frequency
/ 10000;
1350 int frac
= freq
% 100;
1352 snprintf(buffer
, buffer_len
,
1353 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
1357 static int presets_speak_name(int selected_item
, void * data
)
1360 talk_preset(selected_item
, true, false);
1364 static int handle_radio_presets(void)
1366 struct gui_synclist lists
;
1368 int action
= ACTION_NONE
;
1369 #ifdef HAVE_BUTTONBAR
1370 struct gui_buttonbar buttonbar
;
1373 if(presets_loaded
== false)
1376 #ifdef HAVE_BUTTONBAR
1377 gui_buttonbar_init(&buttonbar
);
1378 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
1379 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
1380 str(LANG_FM_BUTTONBAR_EXIT
),
1381 str(LANG_FM_BUTTONBAR_ACTION
));
1382 gui_buttonbar_draw(&buttonbar
);
1384 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1, NULL
);
1385 gui_synclist_set_title(&lists
, str(LANG_PRESET
), NOICON
);
1386 gui_synclist_set_icon_callback(&lists
, NULL
);
1387 if(global_settings
.talk_file
)
1388 gui_synclist_set_voice_callback(&lists
, presets_speak_name
);
1389 gui_synclist_set_nb_items(&lists
, num_presets
);
1390 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
1391 gui_synclist_speak_item(&lists
);
1395 gui_synclist_draw(&lists
);
1396 list_do_action(CONTEXT_STD
, TIMEOUT_BLOCK
,
1397 &lists
, &action
, LIST_WRAP_UNLESS_HELD
);
1400 case ACTION_STD_MENU
:
1401 if (radio_add_preset())
1403 gui_synclist_set_nb_items(&lists
, num_presets
);
1404 gui_synclist_select_item(&lists
, num_presets
- 1);
1407 case ACTION_STD_CANCEL
:
1411 curr_preset
= gui_synclist_get_sel_pos(&lists
);
1412 curr_freq
= presets
[curr_preset
].frequency
;
1414 remember_frequency();
1418 case ACTION_STD_CONTEXT
:
1419 selected_preset
= gui_synclist_get_sel_pos(&lists
);
1420 do_menu(&handle_radio_preset_menu
, NULL
, NULL
, false);
1421 gui_synclist_set_nb_items(&lists
, num_presets
);
1422 gui_synclist_select_item(&lists
, selected_preset
);
1423 gui_synclist_speak_item(&lists
);
1426 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
1433 void toggle_mono_mode(bool mono
)
1435 tuner_set(RADIO_FORCE_MONO
, mono
);
1438 void set_radio_region(int region
)
1440 #ifdef HAVE_RADIO_REGION
1441 tuner_set(RADIO_REGION
, region
);
1444 remember_frequency();
1448 MENUITEM_SETTING(set_region
, &global_settings
.fm_region
, NULL
);
1449 MENUITEM_SETTING(force_mono
, &global_settings
.fm_force_mono
, NULL
);
1452 static char* get_mode_text(int selected_item
, void * data
, char *buffer
)
1454 (void)selected_item
;
1456 snprintf(buffer
, MAX_PATH
, "%s %s", str(LANG_MODE
),
1457 radio_mode
? str(LANG_PRESET
) :
1458 str(LANG_RADIO_SCAN_MODE
));
1461 static int toggle_radio_mode(void)
1463 radio_mode
= (radio_mode
== RADIO_SCAN_MODE
) ?
1464 RADIO_PRESET_MODE
: RADIO_SCAN_MODE
;
1467 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item
, 0,
1468 toggle_radio_mode
, NULL
,
1469 get_mode_text
, NULL
, NULL
, NULL
, Icon_NOICON
);
1472 static int scan_presets(void *viewports
)
1474 bool do_scan
= true;
1476 struct viewport
*vp
= (struct viewport
*)viewports
;
1479 screens
[i
].set_viewport(vp
?&vp
[i
]:NULL
);
1480 if(num_presets
> 0) /* Do that to avoid 2 questions. */
1481 do_scan
= yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS
));
1485 const struct fm_region_data
* const fmr
=
1486 &fm_region_data
[global_settings
.fm_region
];
1488 curr_freq
= fmr
->freq_min
;
1490 memset(presets
, 0, sizeof(presets
));
1491 tuner_set(RADIO_MUTE
, 1);
1493 while(curr_freq
<= fmr
->freq_max
)
1496 if(num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
1499 freq
= curr_freq
/ 10000;
1503 splashf(0, str(LANG_FM_SCANNING
), freq
, frac
);
1505 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
1508 presets
[num_presets
].name
[0] = '\0';
1509 presets
[num_presets
].frequency
= curr_freq
;
1513 curr_freq
+= fmr
->freq_step
;
1516 if (radio_status
== FMRADIO_PLAYING
)
1517 tuner_set(RADIO_MUTE
, 0);
1519 presets_changed
= true;
1523 screens
[i
].clear_viewport();
1524 screens
[i
].update_viewport();
1529 curr_freq
= presets
[0].frequency
;
1530 radio_mode
= RADIO_PRESET_MODE
;
1531 presets_loaded
= true;
1536 /* Wrap it to beginning or we'll be past end of band */
1537 presets_loaded
= false;
1545 #ifdef HAVE_RECORDING
1547 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1548 #define FM_RECORDING_SCREEN
1549 static int fm_recording_screen(void)
1553 /* switch recording source to FMRADIO for the duration */
1554 int rec_source
= global_settings
.rec_source
;
1555 global_settings
.rec_source
= AUDIO_SRC_FMRADIO
;
1557 ret
= recording_screen(true);
1559 /* safe to reset as changing sources is prohibited here */
1560 global_settings
.rec_source
= rec_source
;
1565 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1567 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1568 #define FM_RECORDING_SETTINGS
1569 static int fm_recording_settings(void)
1571 bool ret
= recording_menu(true);
1573 #if CONFIG_CODEC != SWCODEC
1576 struct audio_recording_options rec_options
;
1577 rec_init_recording_options(&rec_options
);
1578 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
1579 rec_set_recording_options(&rec_options
);
1586 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1587 #endif /* HAVE_RECORDING */
1589 #ifdef FM_RECORDING_SCREEN
1590 MENUITEM_FUNCTION(recscreen_item
, 0, ID2P(LANG_RECORDING
),
1591 fm_recording_screen
, NULL
, NULL
, Icon_Recording
);
1593 #ifdef FM_RECORDING_SETTINGS
1594 MENUITEM_FUNCTION(recsettings_item
, 0, ID2P(LANG_RECORDING_SETTINGS
),
1595 fm_recording_settings
, NULL
, NULL
, Icon_Recording
);
1598 MENUITEM_FUNCTION(radio_presets_item
, 0, ID2P(LANG_PRESET
),
1599 handle_radio_presets
, NULL
, NULL
, Icon_NOICON
);
1601 #ifndef FM_PRESET_ADD
1602 MENUITEM_FUNCTION(radio_addpreset_item
, 0, ID2P(LANG_FM_ADD_PRESET
),
1603 radio_add_preset
, NULL
, NULL
, Icon_NOICON
);
1607 MENUITEM_FUNCTION(presetload_item
, 0, ID2P(LANG_FM_PRESET_LOAD
),
1608 load_preset_list
, NULL
, NULL
, Icon_NOICON
);
1609 MENUITEM_FUNCTION(presetsave_item
, 0, ID2P(LANG_FM_PRESET_SAVE
),
1610 save_preset_list
, NULL
, NULL
, Icon_NOICON
);
1611 MENUITEM_FUNCTION(presetclear_item
, 0, ID2P(LANG_FM_PRESET_CLEAR
),
1612 clear_preset_list
, NULL
, NULL
, Icon_NOICON
);
1613 MENUITEM_FUNCTION(scan_presets_item
, MENU_FUNC_USEPARAM
,
1614 ID2P(LANG_FM_SCAN_PRESETS
),
1615 scan_presets
, NULL
, NULL
, Icon_NOICON
);
1617 MAKE_MENU(radio_settings_menu
, ID2P(LANG_FM_MENU
), NULL
,
1620 &radio_presets_item
,
1622 #ifndef FM_PRESET_ADD
1623 &radio_addpreset_item
,
1625 &presetload_item
, &presetsave_item
, &presetclear_item
,
1630 &set_region
, &sound_settings
,
1631 #ifdef FM_RECORDING_SCREEN
1634 #ifdef FM_RECORDING_SETTINGS
1637 &scan_presets_item
);
1638 /* main menu of the radio screen */
1639 static bool radio_menu(void)
1641 return do_menu(&radio_settings_menu
, NULL
, NULL
, false) ==