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"
46 #include "peakmeter.h"
49 #include "sound_menu.h"
51 #include "recording.h"
57 #include "screen_access.h"
58 #include "statusbar.h"
61 #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)
114 #define RADIO_SCAN_MODE 0
115 #define RADIO_PRESET_MODE 1
117 static int curr_preset
= -1;
118 static int curr_freq
; /* current frequency in Hz */
119 static int radio_mode
= RADIO_SCAN_MODE
;
120 static int search_dir
= 0;
122 static int radio_status
= FMRADIO_OFF
;
123 static bool in_screen
= false;
125 #define MAX_PRESETS 64
126 static bool presets_loaded
= false, presets_changed
= false;
127 static struct fmstation presets
[MAX_PRESETS
];
129 static char filepreset
[MAX_PATH
]; /* preset filename variable */
131 static int num_presets
= 0; /* The number of presets in the preset list */
133 static void radio_save_presets(void);
134 static int handle_radio_presets(void);
135 static bool radio_menu(void);
136 static int radio_add_preset(void);
137 static int save_preset_list(void);
138 static int load_preset_list(void);
139 static int clear_preset_list(void);
141 static int scan_presets(void *viewports
);
143 /* Function to manipulate all yesno dialogues.
144 This function needs the output text as an argument. */
145 static bool yesno_pop(const char* text
)
148 const char *lines
[]={text
};
149 const struct text_message message
={lines
, 1};
150 bool ret
= (gui_syncyesno_run(&message
,NULL
,NULL
)== YESNO_YES
);
152 screens
[i
].clear_viewport();
156 void radio_init(void)
162 int get_radio_status(void)
167 bool in_radio_screen(void)
172 /* TODO: Move some more of the control functionality to firmware
173 and clean up the mess */
175 /* secret flag for starting paused - prevents unmute */
176 #define FMRADIO_START_PAUSED 0x8000
177 void radio_start(void)
179 const struct fm_region_data
*fmr
;
182 if(radio_status
== FMRADIO_PLAYING
)
185 fmr
= &fm_region_data
[global_settings
.fm_region
];
187 start_paused
= radio_status
& FMRADIO_START_PAUSED
;
188 /* clear flag before any yielding */
189 radio_status
&= ~FMRADIO_START_PAUSED
;
191 if(radio_status
== FMRADIO_OFF
)
194 curr_freq
= global_status
.last_frequency
* fmr
->freq_step
+ fmr
->freq_min
;
196 tuner_set(RADIO_SLEEP
, 0); /* wake up the tuner */
198 if(radio_status
== FMRADIO_OFF
)
200 #ifdef HAVE_RADIO_REGION
201 tuner_set(RADIO_REGION
, global_settings
.fm_region
);
203 tuner_set(RADIO_FORCE_MONO
, global_settings
.fm_force_mono
);
206 tuner_set(RADIO_FREQUENCY
, curr_freq
);
208 #ifdef HAVE_RADIO_MUTE_TIMEOUT
210 unsigned long mute_timeout
= current_tick
+ HZ
;
211 if (radio_status
!= FMRADIO_OFF
)
217 while(!tuner_get(RADIO_STEREO
) && !tuner_get(RADIO_TUNED
))
219 if(TIME_AFTER(current_tick
, mute_timeout
))
226 /* keep radio from sounding initially */
228 tuner_set(RADIO_MUTE
, 0);
230 radio_status
= FMRADIO_PLAYING
;
233 void radio_pause(void)
235 if(radio_status
== FMRADIO_PAUSED
)
238 if(radio_status
== FMRADIO_OFF
)
240 radio_status
|= FMRADIO_START_PAUSED
;
244 tuner_set(RADIO_MUTE
, 1);
245 tuner_set(RADIO_SLEEP
, 1);
247 radio_status
= FMRADIO_PAUSED
;
250 void radio_stop(void)
252 if(radio_status
== FMRADIO_OFF
)
255 tuner_set(RADIO_MUTE
, 1);
256 tuner_set(RADIO_SLEEP
, 1); /* low power mode, if available */
257 radio_status
= FMRADIO_OFF
;
258 tuner_power(false); /* status update, power off if avail. */
261 bool radio_hardware_present(void)
263 return tuner_get(RADIO_PRESENT
);
266 /* Keep freq on the grid for the current region */
267 static int snap_freq_to_grid(int freq
)
269 const struct fm_region_data
* const fmr
=
270 &fm_region_data
[global_settings
.fm_region
];
272 /* Range clamp if out of range or just round to nearest */
273 if (freq
< fmr
->freq_min
)
274 freq
= fmr
->freq_min
;
275 else if (freq
> fmr
->freq_max
)
276 freq
= fmr
->freq_max
;
278 freq
= (freq
- fmr
->freq_min
+ fmr
->freq_step
/2) /
279 fmr
->freq_step
* fmr
->freq_step
+ fmr
->freq_min
;
284 /* Find a matching preset to freq */
285 static int find_preset(int freq
)
290 for(i
= 0;i
< MAX_PRESETS
;i
++)
292 if(freq
== presets
[i
].frequency
)
299 /* Return the closest preset encountered in the search direction with
301 static int find_closest_preset(int freq
, int direction
)
308 if (direction
== 0) /* direction == 0 isn't really used */
311 for (i
= 0; i
< num_presets
; i
++)
313 int f
= presets
[i
].frequency
;
315 return i
; /* Exact match = stop */
317 /* remember the highest and lowest presets for wraparound */
318 if (f
< presets
[lowpreset
].frequency
)
320 if (f
> presets
[highpreset
].frequency
)
323 /* find the closest preset in the given direction */
324 if (direction
> 0 && f
> freq
)
326 if (closest
< 0 || f
< presets
[closest
].frequency
)
329 else if (direction
< 0 && f
< freq
)
331 if (closest
< 0 || f
> presets
[closest
].frequency
)
338 /* no presets in the given direction */
339 /* wrap around depending on direction */
341 closest
= highpreset
;
349 static void remember_frequency(void)
351 const struct fm_region_data
* const fmr
=
352 &fm_region_data
[global_settings
.fm_region
];
353 global_status
.last_frequency
= (curr_freq
- fmr
->freq_min
)
358 static void next_preset(int direction
)
363 if (curr_preset
== -1)
364 curr_preset
= find_closest_preset(curr_freq
, direction
);
366 curr_preset
= (curr_preset
+ direction
+ num_presets
) % num_presets
;
368 /* Must stay on the current grid for the region */
369 curr_freq
= snap_freq_to_grid(presets
[curr_preset
].frequency
);
371 tuner_set(RADIO_FREQUENCY
, curr_freq
);
372 remember_frequency();
375 /* Step to the next or previous frequency */
376 static int step_freq(int freq
, int direction
)
378 const struct fm_region_data
* const fmr
=
379 &fm_region_data
[global_settings
.fm_region
];
381 freq
+= direction
*fmr
->freq_step
;
383 /* Wrap first or snapping to grid will not let us on the band extremes */
384 if (freq
> fmr
->freq_max
)
385 freq
= direction
> 0 ? fmr
->freq_min
: fmr
->freq_max
;
386 else if (freq
< fmr
->freq_min
)
387 freq
= direction
< 0 ? fmr
->freq_max
: fmr
->freq_min
;
389 freq
= snap_freq_to_grid(freq
);
394 /* Step to the next or previous station */
395 static void next_station(int direction
)
397 if (direction
!= 0 && radio_mode
!= RADIO_SCAN_MODE
)
399 next_preset(direction
);
403 curr_freq
= step_freq(curr_freq
, direction
);
405 if (radio_status
== FMRADIO_PLAYING
)
406 tuner_set(RADIO_MUTE
, 1);
408 tuner_set(RADIO_FREQUENCY
, curr_freq
);
410 if (radio_status
== FMRADIO_PLAYING
)
411 tuner_set(RADIO_MUTE
, 0);
413 curr_preset
= find_preset(curr_freq
);
414 remember_frequency();
417 /* Ends an in-progress search */
418 static void end_search(void)
420 if (search_dir
!= 0 && radio_status
== FMRADIO_PLAYING
)
421 tuner_set(RADIO_MUTE
, 0);
425 /* Speak a frequency. */
426 static void talk_freq(int freq
, bool enqueue
)
429 talk_number(freq
/ 100, enqueue
);
430 talk_id(LANG_POINT
, true);
431 talk_number(freq
% 100 / 10, true);
433 talk_number(freq
% 10, true);
436 /* Speak a preset by number or by spelling its name, depending on settings. */
437 static void talk_preset(int preset
, bool fallback
, bool enqueue
)
439 if (global_settings
.talk_file
== 1) /* number */
440 talk_number(preset
+ 1, enqueue
);
443 if(presets
[preset
].name
[0])
444 talk_spell(presets
[preset
].name
, enqueue
);
446 talk_freq(presets
[preset
].frequency
, enqueue
);
450 int radio_screen(void)
454 int ret_val
= GO_TO_ROOT
;
457 bool stereo
= false, last_stereo
= false;
459 int top_of_screen
= 0;
460 bool update_screen
= true;
461 bool screen_freeze
= false;
462 bool keep_playing
= false;
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 int oldbars
= 0, fmbars
= VP_SB_ALLSCREENS
;
481 #ifdef HAVE_BUTTONBAR
482 struct gui_buttonbar buttonbar
;
483 gui_buttonbar_init(&buttonbar
);
484 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
487 /* change status to "in screen" */
490 /* always display status bar in radio screen for now */
492 fmbars
|= VP_SB_IGNORE_SETTING(i
);
493 oldbars
= viewportmanager_set_statusbar(fmbars
);
496 viewport_set_defaults(&vp
[i
], i
);
497 #ifdef HAVE_BUTTONBAR
498 if (global_settings
.buttonbar
)
499 vp
[i
].height
-= BUTTONBAR_HEIGHT
;
501 screens
[i
].set_viewport(&vp
[i
]);
502 screens
[i
].stop_scroll();
503 screens
[i
].clear_viewport();
504 screens
[i
].update_viewport();
507 fh
= font_get(FONT_UI
)->height
;
509 /* Adjust for font size, trying to center the information vertically */
515 memset(presets
, 0, sizeof(presets
));
516 radio_load_presets(global_settings
.fmr_file
);
519 if(radio_status
== FMRADIO_OFF
)
523 #if CONFIG_CODEC != SWCODEC
524 if(rec_create_directory() > 0)
525 have_recorded
= true;
527 audio_init_recording(talk_get_bufsize());
529 sound_settings_apply();
530 /* Yes, we use the D/A for monitoring */
531 peak_meter_playback(true);
533 peak_meter_enabled
= true;
535 rec_init_recording_options(&rec_options
);
536 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
537 rec_set_recording_options(&rec_options
);
539 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
540 sound_default(SOUND_RIGHT_GAIN
), AUDIO_GAIN_LINEIN
);
542 #endif /* CONFIG_CODEC != SWCODEC */
543 #endif /* ndef SIMULATOR */
546 #if CONFIG_CODEC == SWCODEC
547 audio_set_input_source(AUDIO_SRC_FMRADIO
,
548 (radio_status
== FMRADIO_PAUSED
) ?
549 SRCF_FMRADIO_PAUSED
: SRCF_FMRADIO_PLAYING
);
551 if (radio_status
== FMRADIO_OFF
)
555 if(num_presets
< 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN
)))
558 curr_preset
= find_preset(curr_freq
);
559 if(curr_preset
!= -1)
560 radio_mode
= RADIO_PRESET_MODE
;
562 #ifdef HAVE_BUTTONBAR
563 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
564 str(LANG_PRESET
), str(LANG_FM_BUTTONBAR_RECORD
));
567 #ifndef HAVE_NOISY_IDLE_MODE
575 curr_freq
= step_freq(curr_freq
, search_dir
);
576 update_screen
= true;
578 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
580 curr_preset
= find_preset(curr_freq
);
581 remember_frequency();
594 #if CONFIG_CODEC != SWCODEC
595 /* TODO: Can we timeout at HZ when recording since peaks aren't
596 displayed? This should quiet recordings too. */
597 button
= get_action(CONTEXT_FM
,
598 update_screen
? TIMEOUT_NOBLOCK
: HZ
/ PEAK_METER_FPS
);
600 button
= get_action(CONTEXT_FM
,
601 update_screen
? TIMEOUT_NOBLOCK
: HZ
);
604 #ifndef HAVE_NOISY_IDLE_MODE
605 if (button
!= ACTION_NONE
)
607 cpu_idle_mode(false);
608 button_timeout
= current_tick
+ (2*HZ
);
614 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
615 if(audio_status() == AUDIO_STATUS_RECORD
)
625 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
627 if(filepreset
[0] == '\0')
630 radio_save_presets();
633 /* Clear the preset list on exit. */
636 update_screen
= true;
640 case ACTION_FM_RECORD
:
641 #ifdef FM_RECORD_DBLPRE
642 if (lastbutton
!= ACTION_FM_RECORD_DBLPRE
)
647 if (current_tick
- rec_lastclick
> HZ
/2)
649 rec_lastclick
= current_tick
;
652 #endif /* FM_RECORD_DBLPRE */
654 if(audio_status() == AUDIO_STATUS_RECORD
)
656 rec_command(RECORDING_CMD_START_NEWFILE
);
657 update_screen
= true;
661 have_recorded
= true;
662 rec_command(RECORDING_CMD_START
);
663 update_screen
= true;
665 #endif /* SIMULATOR */
668 #endif /* #ifdef FM_RECORD */
671 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
672 if(audio_status() == AUDIO_STATUS_RECORD
)
677 ret_val
= GO_TO_ROOT
;
680 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
682 if(filepreset
[0] == '\0')
685 radio_save_presets();
689 /* Clear the preset list on exit. */
694 case ACTION_STD_PREV
:
695 case ACTION_STD_NEXT
:
696 next_station(button
== ACTION_STD_PREV
? -1 : 1);
698 update_screen
= true;
702 case ACTION_STD_PREVREPEAT
:
703 case ACTION_STD_NEXTREPEAT
:
705 int dir
= search_dir
;
706 search_dir
= button
== ACTION_STD_PREVREPEAT
? -1 : 1;
707 if (radio_mode
!= RADIO_SCAN_MODE
)
709 next_preset(search_dir
);
711 update_screen
= true;
716 /* Starting auto scan */
717 tuner_set(RADIO_MUTE
, 1);
718 update_screen
= true;
723 case ACTION_SETTINGS_INC
:
724 case ACTION_SETTINGS_INCREPEAT
:
725 global_settings
.volume
++;
727 update_screen
= true;
730 case ACTION_SETTINGS_DEC
:
731 case ACTION_SETTINGS_DECREPEAT
:
732 global_settings
.volume
--;
734 update_screen
= true;
738 if (radio_status
== FMRADIO_PLAYING
)
743 update_screen
= true;
749 viewportmanager_set_statusbar(oldbars
);
751 curr_preset
= find_preset(curr_freq
);
752 viewportmanager_set_statusbar(fmbars
);
755 screens
[i
].set_viewport(&vp
[i
]);
756 screens
[i
].clear_viewport();
757 screens
[i
].update_viewport();
758 screens
[i
].set_viewport(NULL
);
760 #ifdef HAVE_BUTTONBAR
761 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
763 str(LANG_FM_BUTTONBAR_RECORD
));
765 update_screen
= true;
769 case ACTION_FM_PRESET
:
772 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
773 update_screen
= true;
776 screens
[i
].set_viewport(&vp
[i
]);
777 screens
[i
].clear_viewport();
778 screens
[i
].update_viewport();
779 screens
[i
].set_viewport(NULL
);
784 viewportmanager_set_statusbar(oldbars
);
785 handle_radio_presets();
786 viewportmanager_set_statusbar(fmbars
);
789 screens
[i
].set_viewport(&vp
[i
]);
790 screens
[i
].stop_scroll();
791 screens
[i
].clear_viewport();
792 screens
[i
].update_viewport();
793 screens
[i
].set_viewport(NULL
);
795 #ifdef HAVE_BUTTONBAR
796 gui_buttonbar_set(&buttonbar
,
797 str(LANG_BUTTONBAR_MENU
),
799 str(LANG_FM_BUTTONBAR_RECORD
));
801 update_screen
= true;
803 #endif /* FM_PRESET */
806 case ACTION_FM_FREEZE
:
809 splash(HZ
, str(LANG_FM_FREEZE
));
810 screen_freeze
= true;
814 update_screen
= true;
815 screen_freeze
= false;
818 #endif /* FM_FREEZE */
820 case SYS_USB_CONNECTED
:
821 #if CONFIG_CODEC != SWCODEC
822 /* Only accept USB connection when not recording */
823 if(audio_status() != AUDIO_STATUS_RECORD
)
826 default_event_handler(SYS_USB_CONNECTED
);
827 screen_freeze
= true; /* Cosmetic: makes sure the
828 radio screen doesn't redraw */
835 if(radio_mode
== RADIO_SCAN_MODE
)
837 /* Force scan mode if there are no presets. */
839 radio_mode
= RADIO_PRESET_MODE
;
842 radio_mode
= RADIO_SCAN_MODE
;
843 update_screen
= true;
844 cond_talk_ids_fq(radio_mode
?
845 LANG_PRESET
: LANG_RADIO_SCAN_MODE
);
850 #ifdef FM_NEXT_PRESET
851 case ACTION_FM_NEXT_PRESET
:
854 update_screen
= true;
859 #ifdef FM_PREV_PRESET
860 case ACTION_FM_PREV_PRESET
:
863 update_screen
= true;
869 default_event_handler(button
);
873 #ifdef FM_RECORD_DBLPRE
874 if (button
!= ACTION_NONE
)
878 #if CONFIG_CODEC != SWCODEC
884 /* Only display the peak meter when not recording */
885 #if CONFIG_CODEC != SWCODEC
890 screens
[i
].set_viewport(&vp
[i
]);
891 peak_meter_screen(&screens
[i
],0,
892 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
894 screens
[i
].update_rect(0,
895 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
896 screens
[i
].getwidth(), fh
);
897 screens
[i
].set_viewport(NULL
);
901 if(TIME_AFTER(current_tick
, timeout
))
903 timeout
= current_tick
+ HZ
;
906 #endif /* CONFIG_CODEC == SWCODEC */
908 /* keep "mono" from always being displayed when paused */
909 if (radio_status
!= FMRADIO_PAUSED
)
911 stereo
= tuner_get(RADIO_STEREO
) &&
912 !global_settings
.fm_force_mono
;
914 if(stereo
!= last_stereo
)
916 update_screen
= true;
917 last_stereo
= stereo
;
922 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
923 seconds
= audio_recorded_time() / HZ
;
924 if (update_screen
|| seconds
> last_seconds
)
926 last_seconds
= seconds
;
935 screens
[i
].set_viewport(&vp
[i
]);
938 snprintf(buf
, 128, curr_preset
>= 0 ? "%d. %s" : " ",
939 curr_preset
+ 1, presets
[curr_preset
].name
);
942 screens
[i
].puts_scroll(0, top_of_screen
, buf
);
944 freq
= curr_freq
/ 10000;
945 snprintf(buf
, 128, str(LANG_FM_STATION
),
946 freq
/ 100, freq
% 100);
948 screens
[i
].puts_scroll(0, top_of_screen
+ 1, buf
);
950 snprintf(buf
, 128, "%s", stereo
?str(LANG_CHANNEL_STEREO
):
951 str(LANG_CHANNEL_MONO
));
953 screens
[i
].puts_scroll(0, top_of_screen
+ 2, buf
);
955 snprintf(buf
, 128, "%s %s", str(LANG_MODE
),
956 radio_mode
? str(LANG_PRESET
) :
957 str(LANG_RADIO_SCAN_MODE
));
959 screens
[i
].puts_scroll(0, top_of_screen
+ 3, buf
);
961 #if CONFIG_CODEC != SWCODEC
962 if(audio_status() == AUDIO_STATUS_RECORD
)
964 hours
= seconds
/ 3600;
965 minutes
= (seconds
- (hours
* 3600)) / 60;
966 snprintf(buf
, 32, "%s %02d:%02d:%02d",
967 str(LANG_RECORDING_TIME
),
968 hours
, minutes
, seconds
%60);
970 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
974 if(rec_options
.rec_prerecord_time
)
976 snprintf(buf
, 32, "%s %02d",
977 str(LANG_RECORD_PRERECORD
), seconds
%60);
979 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
982 #endif /* CONFIG_CODEC != SWCODEC */
986 screens
[i
].update_viewport();
987 screens
[i
].set_viewport(NULL
);
990 #ifdef HAVE_BUTTONBAR
991 gui_buttonbar_draw(&buttonbar
);
996 update_screen
= false;
998 if (global_settings
.talk_file
&& talk
999 && radio_status
== FMRADIO_PAUSED
)
1002 bool enqueue
= false;
1003 if (radio_mode
== RADIO_SCAN_MODE
)
1005 talk_freq(curr_freq
, enqueue
);
1008 if (curr_preset
>= 0)
1009 talk_preset(curr_preset
, radio_mode
== RADIO_PRESET_MODE
,
1013 #if CONFIG_CODEC != SWCODEC
1014 if(audio_status() & AUDIO_STATUS_ERROR
)
1020 #ifndef HAVE_NOISY_IDLE_MODE
1021 if (TIME_AFTER(current_tick
, button_timeout
))
1023 cpu_idle_mode(true);
1029 #if CONFIG_CODEC != SWCODEC
1030 if(audio_status() & AUDIO_STATUS_ERROR
)
1032 splash(0, str(LANG_DISK_FULL
));
1035 screens
[i
].set_viewport(&vp
[i
]);
1036 screens
[i
].update_viewport();
1037 screens
[i
].set_viewport(NULL
);
1039 audio_error_clear();
1043 button
= get_action(CONTEXT_FM
, TIMEOUT_BLOCK
);
1044 if(button
== ACTION_FM_STOP
)
1049 audio_init_playback();
1050 #endif /* CONFIG_CODEC != SWCODEC */
1052 sound_settings_apply();
1053 #endif /* SIMULATOR */
1057 /* Catch FMRADIO_PLAYING status for the sim. */
1059 #if CONFIG_CODEC != SWCODEC
1060 /* Enable the Left and right A/D Converter */
1061 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
1062 sound_default(SOUND_RIGHT_GAIN
),
1064 mas_codec_writereg(6, 0x4000);
1067 #endif /* SIMULATOR */
1071 #if CONFIG_CODEC == SWCODEC
1072 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
1078 #ifndef HAVE_NOISY_IDLE_MODE
1079 cpu_idle_mode(false);
1082 viewportmanager_set_statusbar(oldbars
);
1084 #if CONFIG_CODEC != SWCODEC
1085 return have_recorded
;
1089 } /* radio_screen */
1091 static void radio_save_presets(void)
1096 fd
= creat(filepreset
);
1099 for(i
= 0;i
< num_presets
;i
++)
1101 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
1105 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
1106 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
1107 presets_changed
= false;
1111 splash(HZ
, ID2P(LANG_FM_PRESET_SAVE_FAILED
));
1115 void radio_load_presets(char *filename
)
1125 memset(presets
, 0, sizeof(presets
));
1128 /* No Preset in configuration. */
1129 if(filename
[0] == '\0')
1131 filepreset
[0] = '\0';
1134 /* Temporary preset, loaded until player shuts down. */
1135 else if(filename
[0] == '/')
1136 strncpy(filepreset
, filename
, sizeof(filepreset
));
1137 /* Preset from default directory. */
1139 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
1140 FMPRESET_PATH
, filename
);
1142 fd
= open_utf8(filepreset
, O_RDONLY
);
1145 while(!done
&& num_presets
< MAX_PRESETS
)
1147 rc
= read_line(fd
, buf
, 128);
1150 if(settings_parseline(buf
, &freq
, &name
))
1153 if(f
) /* For backwards compatibility */
1155 struct fmstation
* const fms
= &presets
[num_presets
];
1157 strncpy(fms
->name
, name
, MAX_FMPRESET_LEN
);
1158 fms
->name
[MAX_FMPRESET_LEN
] = '\0';
1168 else /* invalid file name? */
1169 filepreset
[0] = '\0';
1171 presets_loaded
= num_presets
> 0;
1172 presets_changed
= false;
1176 static int radio_add_preset(void)
1178 char buf
[MAX_FMPRESET_LEN
+ 1];
1180 if(num_presets
< MAX_PRESETS
)
1184 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1186 struct fmstation
* const fms
= &presets
[num_presets
];
1187 strcpy(fms
->name
, buf
);
1188 fms
->frequency
= curr_freq
;
1190 presets_changed
= true;
1191 presets_loaded
= num_presets
> 0;
1197 splash(HZ
, ID2P(LANG_FM_NO_FREE_PRESETS
));
1202 /* needed to know which preset we are edit/delete-ing */
1203 static int selected_preset
= -1;
1204 static int radio_edit_preset(void)
1206 char buf
[MAX_FMPRESET_LEN
+ 1];
1208 if (num_presets
> 0)
1210 struct fmstation
* const fms
= &presets
[selected_preset
];
1212 strcpy(buf
, fms
->name
);
1214 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1216 strcpy(fms
->name
, buf
);
1217 presets_changed
= true;
1224 static int radio_delete_preset(void)
1226 if (num_presets
> 0)
1228 struct fmstation
* const fms
= &presets
[selected_preset
];
1230 if (selected_preset
>= --num_presets
)
1231 selected_preset
= num_presets
- 1;
1233 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
1236 if (curr_preset
>= num_presets
)
1240 /* Don't ask to save when all presets are deleted. */
1241 presets_changed
= num_presets
> 0;
1243 if (!presets_changed
)
1245 /* The preset list will be cleared, switch to Scan Mode. */
1246 radio_mode
= RADIO_SCAN_MODE
;
1248 presets_loaded
= false;
1254 static int load_preset_list(void)
1256 return !rockbox_browse(FMPRESET_PATH
, SHOW_FMR
);
1259 static int save_preset_list(void)
1263 bool bad_file_name
= true;
1265 if(!dir_exists(FMPRESET_PATH
)) /* Check if there is preset folder */
1266 mkdir(FMPRESET_PATH
);
1268 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
1269 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
1271 while(bad_file_name
)
1273 if(!kbd_input(filepreset
, sizeof(filepreset
)))
1275 /* check the name: max MAX_FILENAME (20) chars */
1279 p1
= strrchr(filepreset
, '/');
1281 while((p1
) && (*p2
) && (*p2
!= '.'))
1283 len
= (int)(p2
-p1
) - 1;
1284 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
1286 /* no slash, too long or too short */
1287 splash(HZ
, ID2P(LANG_INVALID_FILENAME
));
1291 /* add correct extension (easier to always write)
1292 at this point, p2 points to 0 or the extension dot */
1294 strcat(filepreset
,".fmr");
1295 bad_file_name
= false;
1296 radio_save_presets();
1307 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
1312 static int clear_preset_list(void)
1314 /* Clear all the preset entries */
1315 memset(presets
, 0, sizeof (presets
));
1318 presets_loaded
= false;
1319 /* The preset list will be cleared switch to Scan Mode. */
1320 radio_mode
= RADIO_SCAN_MODE
;
1323 presets_changed
= false; /* Don't ask to save when clearing the list. */
1328 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1329 ID2P(LANG_FM_EDIT_PRESET
),
1330 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
1331 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1332 ID2P(LANG_FM_DELETE_PRESET
),
1333 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
1334 static int radio_preset_callback(int action
,
1335 const struct menu_item_ex
*this_item
)
1337 if (action
== ACTION_STD_OK
)
1338 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
1342 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_PRESET
),
1343 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
1344 &radio_delete_preset_item
);
1345 /* present a list of preset stations */
1346 static char * presets_get_name(int selected_item
, void *data
,
1347 char *buffer
, size_t buffer_len
)
1350 struct fmstation
*p
= &presets
[selected_item
];
1353 int freq
= p
->frequency
/ 10000;
1354 int frac
= freq
% 100;
1356 snprintf(buffer
, buffer_len
,
1357 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
1361 static int presets_speak_name(int selected_item
, void * data
)
1364 talk_preset(selected_item
, true, false);
1368 static int handle_radio_presets(void)
1370 struct gui_synclist lists
;
1372 int action
= ACTION_NONE
;
1373 #ifdef HAVE_BUTTONBAR
1374 struct gui_buttonbar buttonbar
;
1377 if(presets_loaded
== false)
1380 #ifdef HAVE_BUTTONBAR
1381 gui_buttonbar_init(&buttonbar
);
1382 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
1383 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
1384 str(LANG_FM_BUTTONBAR_EXIT
),
1385 str(LANG_FM_BUTTONBAR_ACTION
));
1386 gui_buttonbar_draw(&buttonbar
);
1388 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1, NULL
);
1389 gui_synclist_set_title(&lists
, str(LANG_PRESET
), NOICON
);
1390 gui_synclist_set_icon_callback(&lists
, NULL
);
1391 if(global_settings
.talk_file
)
1392 gui_synclist_set_voice_callback(&lists
, presets_speak_name
);
1393 gui_synclist_set_nb_items(&lists
, num_presets
);
1394 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
1395 gui_synclist_speak_item(&lists
);
1399 gui_synclist_draw(&lists
);
1400 list_do_action(CONTEXT_STD
, TIMEOUT_BLOCK
,
1401 &lists
, &action
, LIST_WRAP_UNLESS_HELD
);
1404 case ACTION_STD_MENU
:
1405 if (radio_add_preset())
1407 gui_synclist_set_nb_items(&lists
, num_presets
);
1408 gui_synclist_select_item(&lists
, num_presets
- 1);
1411 case ACTION_STD_CANCEL
:
1415 curr_preset
= gui_synclist_get_sel_pos(&lists
);
1416 curr_freq
= presets
[curr_preset
].frequency
;
1418 remember_frequency();
1422 case ACTION_STD_CONTEXT
:
1423 selected_preset
= gui_synclist_get_sel_pos(&lists
);
1424 do_menu(&handle_radio_preset_menu
, NULL
, NULL
, false);
1425 gui_synclist_set_nb_items(&lists
, num_presets
);
1426 gui_synclist_select_item(&lists
, selected_preset
);
1427 gui_synclist_speak_item(&lists
);
1430 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
1437 void toggle_mono_mode(bool mono
)
1439 tuner_set(RADIO_FORCE_MONO
, mono
);
1442 void set_radio_region(int region
)
1444 #ifdef HAVE_RADIO_REGION
1445 tuner_set(RADIO_REGION
, region
);
1448 remember_frequency();
1452 MENUITEM_SETTING(set_region
, &global_settings
.fm_region
, NULL
);
1453 MENUITEM_SETTING(force_mono
, &global_settings
.fm_force_mono
, NULL
);
1456 static char* get_mode_text(int selected_item
, void * data
, char *buffer
)
1458 (void)selected_item
;
1460 snprintf(buffer
, MAX_PATH
, "%s %s", str(LANG_MODE
),
1461 radio_mode
? str(LANG_PRESET
) :
1462 str(LANG_RADIO_SCAN_MODE
));
1465 static int toggle_radio_mode(void)
1467 radio_mode
= (radio_mode
== RADIO_SCAN_MODE
) ?
1468 RADIO_PRESET_MODE
: RADIO_SCAN_MODE
;
1471 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item
, 0,
1472 toggle_radio_mode
, NULL
,
1473 get_mode_text
, NULL
, NULL
, NULL
, Icon_NOICON
);
1476 static int scan_presets(void *viewports
)
1478 bool do_scan
= true;
1480 struct viewport
*vp
= (struct viewport
*)viewports
;
1483 screens
[i
].set_viewport(vp
?&vp
[i
]:NULL
);
1484 if(num_presets
> 0) /* Do that to avoid 2 questions. */
1485 do_scan
= yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS
));
1489 const struct fm_region_data
* const fmr
=
1490 &fm_region_data
[global_settings
.fm_region
];
1492 curr_freq
= fmr
->freq_min
;
1494 memset(presets
, 0, sizeof(presets
));
1495 tuner_set(RADIO_MUTE
, 1);
1497 while(curr_freq
<= fmr
->freq_max
)
1500 if(num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
1503 freq
= curr_freq
/ 10000;
1507 splashf(0, str(LANG_FM_SCANNING
), freq
, frac
);
1509 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
1512 presets
[num_presets
].name
[0] = '\0';
1513 presets
[num_presets
].frequency
= curr_freq
;
1517 curr_freq
+= fmr
->freq_step
;
1520 if (radio_status
== FMRADIO_PLAYING
)
1521 tuner_set(RADIO_MUTE
, 0);
1523 presets_changed
= true;
1527 screens
[i
].clear_viewport();
1528 screens
[i
].update_viewport();
1533 curr_freq
= presets
[0].frequency
;
1534 radio_mode
= RADIO_PRESET_MODE
;
1535 presets_loaded
= true;
1540 /* Wrap it to beginning or we'll be past end of band */
1541 presets_loaded
= false;
1549 #ifdef HAVE_RECORDING
1551 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1552 #define FM_RECORDING_SCREEN
1553 static int fm_recording_screen(void)
1557 /* switch recording source to FMRADIO for the duration */
1558 int rec_source
= global_settings
.rec_source
;
1559 global_settings
.rec_source
= AUDIO_SRC_FMRADIO
;
1561 ret
= recording_screen(true);
1563 /* safe to reset as changing sources is prohibited here */
1564 global_settings
.rec_source
= rec_source
;
1569 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1571 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1572 #define FM_RECORDING_SETTINGS
1573 static int fm_recording_settings(void)
1575 bool ret
= recording_menu(true);
1577 #if CONFIG_CODEC != SWCODEC
1580 struct audio_recording_options rec_options
;
1581 rec_init_recording_options(&rec_options
);
1582 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
1583 rec_set_recording_options(&rec_options
);
1590 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1591 #endif /* HAVE_RECORDING */
1593 #ifdef FM_RECORDING_SCREEN
1594 MENUITEM_FUNCTION(recscreen_item
, 0, ID2P(LANG_RECORDING
),
1595 fm_recording_screen
, NULL
, NULL
, Icon_Recording
);
1597 #ifdef FM_RECORDING_SETTINGS
1598 MENUITEM_FUNCTION(recsettings_item
, 0, ID2P(LANG_RECORDING_SETTINGS
),
1599 fm_recording_settings
, NULL
, NULL
, Icon_Recording
);
1602 MENUITEM_FUNCTION(radio_presets_item
, 0, ID2P(LANG_PRESET
),
1603 handle_radio_presets
, NULL
, NULL
, Icon_NOICON
);
1605 #ifndef FM_PRESET_ADD
1606 MENUITEM_FUNCTION(radio_addpreset_item
, 0, ID2P(LANG_FM_ADD_PRESET
),
1607 radio_add_preset
, NULL
, NULL
, Icon_NOICON
);
1611 MENUITEM_FUNCTION(presetload_item
, 0, ID2P(LANG_FM_PRESET_LOAD
),
1612 load_preset_list
, NULL
, NULL
, Icon_NOICON
);
1613 MENUITEM_FUNCTION(presetsave_item
, 0, ID2P(LANG_FM_PRESET_SAVE
),
1614 save_preset_list
, NULL
, NULL
, Icon_NOICON
);
1615 MENUITEM_FUNCTION(presetclear_item
, 0, ID2P(LANG_FM_PRESET_CLEAR
),
1616 clear_preset_list
, NULL
, NULL
, Icon_NOICON
);
1617 MENUITEM_FUNCTION(scan_presets_item
, MENU_FUNC_USEPARAM
,
1618 ID2P(LANG_FM_SCAN_PRESETS
),
1619 scan_presets
, NULL
, NULL
, Icon_NOICON
);
1621 MAKE_MENU(radio_settings_menu
, ID2P(LANG_FM_MENU
), NULL
,
1624 &radio_presets_item
,
1626 #ifndef FM_PRESET_ADD
1627 &radio_addpreset_item
,
1629 &presetload_item
, &presetsave_item
, &presetclear_item
,
1634 &set_region
, &sound_settings
,
1635 #ifdef FM_RECORDING_SCREEN
1638 #ifdef FM_RECORDING_SETTINGS
1641 &scan_presets_item
);
1642 /* main menu of the radio screen */
1643 static bool radio_menu(void)
1645 return do_menu(&radio_settings_menu
, NULL
, NULL
, false) ==