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"
60 #include "buttonbar.h"
65 #include "menus/exported_menus.h"
66 #include "root_menu.h"
71 #if CONFIG_KEYPAD == RECORDER_PAD
74 #define FM_PRESET_ACTION
78 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
81 #define FM_NEXT_PRESET
82 #define FM_PREV_PRESET
84 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
88 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
91 /* This should be removeable if the whole tuning thing is sorted out since
92 proper tuning quiets the screen almost entirely in that extreme measures
93 have to be taken to hear any interference. */
94 #define HAVE_NOISY_IDLE_MODE
96 #elif CONFIG_KEYPAD == ONDIO_PAD
97 #define FM_RECORD_DBLPRE
99 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD)
107 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
111 #elif (CONFIG_KEYPAD == COWOND2_PAD)
120 #define RADIO_SCAN_MODE 0
121 #define RADIO_PRESET_MODE 1
123 static int curr_preset
= -1;
124 static int curr_freq
; /* current frequency in Hz */
125 static int radio_mode
= RADIO_SCAN_MODE
;
126 static int search_dir
= 0;
128 static int radio_status
= FMRADIO_OFF
;
129 static bool in_screen
= false;
131 #define MAX_PRESETS 64
132 static bool presets_loaded
= false, presets_changed
= false;
133 static struct fmstation presets
[MAX_PRESETS
];
135 static char filepreset
[MAX_PATH
]; /* preset filename variable */
137 static int num_presets
= 0; /* The number of presets in the preset list */
139 static void radio_save_presets(void);
140 static int handle_radio_presets(void);
141 static bool radio_menu(void);
142 static int radio_add_preset(void);
143 static int save_preset_list(void);
144 static int load_preset_list(void);
145 static int clear_preset_list(void);
147 static int scan_presets(void *viewports
);
149 /* Function to manipulate all yesno dialogues.
150 This function needs the output text as an argument. */
151 static bool yesno_pop(const char* text
)
154 const char *lines
[]={text
};
155 const struct text_message message
={lines
, 1};
156 bool ret
= (gui_syncyesno_run(&message
,NULL
,NULL
)== YESNO_YES
);
158 screens
[i
].clear_viewport();
162 void radio_init(void)
168 int get_radio_status(void)
173 bool in_radio_screen(void)
178 /* TODO: Move some more of the control functionality to firmware
179 and clean up the mess */
181 /* secret flag for starting paused - prevents unmute */
182 #define FMRADIO_START_PAUSED 0x8000
183 void radio_start(void)
185 const struct fm_region_data
*fmr
;
188 if(radio_status
== FMRADIO_PLAYING
)
191 fmr
= &fm_region_data
[global_settings
.fm_region
];
193 start_paused
= radio_status
& FMRADIO_START_PAUSED
;
194 /* clear flag before any yielding */
195 radio_status
&= ~FMRADIO_START_PAUSED
;
197 if(radio_status
== FMRADIO_OFF
)
200 curr_freq
= global_status
.last_frequency
* fmr
->freq_step
+ fmr
->freq_min
;
202 tuner_set(RADIO_SLEEP
, 0); /* wake up the tuner */
204 if(radio_status
== FMRADIO_OFF
)
206 #ifdef HAVE_RADIO_REGION
207 tuner_set(RADIO_REGION
, global_settings
.fm_region
);
209 tuner_set(RADIO_FORCE_MONO
, global_settings
.fm_force_mono
);
212 tuner_set(RADIO_FREQUENCY
, curr_freq
);
214 #ifdef HAVE_RADIO_MUTE_TIMEOUT
216 unsigned long mute_timeout
= current_tick
+ HZ
;
217 if (radio_status
!= FMRADIO_OFF
)
223 while(!tuner_get(RADIO_STEREO
) && !tuner_get(RADIO_TUNED
))
225 if(TIME_AFTER(current_tick
, mute_timeout
))
232 /* keep radio from sounding initially */
234 tuner_set(RADIO_MUTE
, 0);
236 radio_status
= FMRADIO_PLAYING
;
239 void radio_pause(void)
241 if(radio_status
== FMRADIO_PAUSED
)
244 if(radio_status
== FMRADIO_OFF
)
246 radio_status
|= FMRADIO_START_PAUSED
;
250 tuner_set(RADIO_MUTE
, 1);
251 tuner_set(RADIO_SLEEP
, 1);
253 radio_status
= FMRADIO_PAUSED
;
256 void radio_stop(void)
258 if(radio_status
== FMRADIO_OFF
)
261 tuner_set(RADIO_MUTE
, 1);
262 tuner_set(RADIO_SLEEP
, 1); /* low power mode, if available */
263 radio_status
= FMRADIO_OFF
;
264 tuner_power(false); /* status update, power off if avail. */
267 bool radio_hardware_present(void)
269 return tuner_get(RADIO_PRESENT
);
272 /* Keep freq on the grid for the current region */
273 static int snap_freq_to_grid(int freq
)
275 const struct fm_region_data
* const fmr
=
276 &fm_region_data
[global_settings
.fm_region
];
278 /* Range clamp if out of range or just round to nearest */
279 if (freq
< fmr
->freq_min
)
280 freq
= fmr
->freq_min
;
281 else if (freq
> fmr
->freq_max
)
282 freq
= fmr
->freq_max
;
284 freq
= (freq
- fmr
->freq_min
+ fmr
->freq_step
/2) /
285 fmr
->freq_step
* fmr
->freq_step
+ fmr
->freq_min
;
290 /* Find a matching preset to freq */
291 static int find_preset(int freq
)
296 for(i
= 0;i
< MAX_PRESETS
;i
++)
298 if(freq
== presets
[i
].frequency
)
305 /* Return the closest preset encountered in the search direction with
307 static int find_closest_preset(int freq
, int direction
)
314 if (direction
== 0) /* direction == 0 isn't really used */
317 for (i
= 0; i
< num_presets
; i
++)
319 int f
= presets
[i
].frequency
;
321 return i
; /* Exact match = stop */
323 /* remember the highest and lowest presets for wraparound */
324 if (f
< presets
[lowpreset
].frequency
)
326 if (f
> presets
[highpreset
].frequency
)
329 /* find the closest preset in the given direction */
330 if (direction
> 0 && f
> freq
)
332 if (closest
< 0 || f
< presets
[closest
].frequency
)
335 else if (direction
< 0 && f
< freq
)
337 if (closest
< 0 || f
> presets
[closest
].frequency
)
344 /* no presets in the given direction */
345 /* wrap around depending on direction */
347 closest
= highpreset
;
355 static void remember_frequency(void)
357 const struct fm_region_data
* const fmr
=
358 &fm_region_data
[global_settings
.fm_region
];
359 global_status
.last_frequency
= (curr_freq
- fmr
->freq_min
)
364 static void next_preset(int direction
)
369 if (curr_preset
== -1)
370 curr_preset
= find_closest_preset(curr_freq
, direction
);
372 curr_preset
= (curr_preset
+ direction
+ num_presets
) % num_presets
;
374 /* Must stay on the current grid for the region */
375 curr_freq
= snap_freq_to_grid(presets
[curr_preset
].frequency
);
377 tuner_set(RADIO_FREQUENCY
, curr_freq
);
378 remember_frequency();
381 /* Step to the next or previous frequency */
382 static int step_freq(int freq
, int direction
)
384 const struct fm_region_data
* const fmr
=
385 &fm_region_data
[global_settings
.fm_region
];
387 freq
+= direction
*fmr
->freq_step
;
389 /* Wrap first or snapping to grid will not let us on the band extremes */
390 if (freq
> fmr
->freq_max
)
391 freq
= direction
> 0 ? fmr
->freq_min
: fmr
->freq_max
;
392 else if (freq
< fmr
->freq_min
)
393 freq
= direction
< 0 ? fmr
->freq_max
: fmr
->freq_min
;
395 freq
= snap_freq_to_grid(freq
);
400 /* Step to the next or previous station */
401 static void next_station(int direction
)
403 if (direction
!= 0 && radio_mode
!= RADIO_SCAN_MODE
)
405 next_preset(direction
);
409 curr_freq
= step_freq(curr_freq
, direction
);
411 if (radio_status
== FMRADIO_PLAYING
)
412 tuner_set(RADIO_MUTE
, 1);
414 tuner_set(RADIO_FREQUENCY
, curr_freq
);
416 if (radio_status
== FMRADIO_PLAYING
)
417 tuner_set(RADIO_MUTE
, 0);
419 curr_preset
= find_preset(curr_freq
);
420 remember_frequency();
423 /* Ends an in-progress search */
424 static void end_search(void)
426 if (search_dir
!= 0 && radio_status
== FMRADIO_PLAYING
)
427 tuner_set(RADIO_MUTE
, 0);
431 /* Speak a frequency. */
432 static void talk_freq(int freq
, bool enqueue
)
435 talk_number(freq
/ 100, enqueue
);
436 talk_id(LANG_POINT
, true);
437 talk_number(freq
% 100 / 10, true);
439 talk_number(freq
% 10, true);
442 /* Speak a preset by number or by spelling its name, depending on settings. */
443 static void talk_preset(int preset
, bool fallback
, bool enqueue
)
445 if (global_settings
.talk_file
== 1) /* number */
446 talk_number(preset
+ 1, enqueue
);
449 if(presets
[preset
].name
[0])
450 talk_spell(presets
[preset
].name
, enqueue
);
452 talk_freq(presets
[preset
].frequency
, enqueue
);
456 int radio_screen(void)
460 int ret_val
= GO_TO_ROOT
;
463 bool stereo
= false, last_stereo
= false;
465 int top_of_screen
= 0;
466 bool update_screen
= true;
467 bool screen_freeze
= false;
468 bool keep_playing
= false;
470 #ifdef FM_RECORD_DBLPRE
471 int lastbutton
= BUTTON_NONE
;
472 unsigned long rec_lastclick
= 0;
474 #if CONFIG_CODEC != SWCODEC
475 bool have_recorded
= false;
476 int timeout
= current_tick
+ HZ
/10;
477 unsigned int seconds
= 0;
478 unsigned int last_seconds
= 0;
480 struct audio_recording_options rec_options
;
481 #endif /* CONFIG_CODEC != SWCODEC */
482 #ifndef HAVE_NOISY_IDLE_MODE
483 int button_timeout
= current_tick
+ (2*HZ
);
485 struct viewport vp
[NB_SCREENS
];
486 int oldbars
= 0, fmbars
= VP_SB_ALLSCREENS
;
487 #ifdef HAVE_BUTTONBAR
488 struct gui_buttonbar buttonbar
;
489 gui_buttonbar_init(&buttonbar
);
490 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
493 /* change status to "in screen" */
496 /* always display status bar in radio screen for now */
498 fmbars
|= VP_SB_IGNORE_SETTING(i
);
499 oldbars
= viewportmanager_set_statusbar(fmbars
);
502 viewport_set_defaults(&vp
[i
], i
);
503 #ifdef HAVE_BUTTONBAR
504 if (global_settings
.buttonbar
)
505 vp
[i
].height
-= BUTTONBAR_HEIGHT
;
507 screens
[i
].set_viewport(&vp
[i
]);
508 screens
[i
].stop_scroll();
509 screens
[i
].clear_viewport();
510 screens
[i
].update_viewport();
513 fh
= font_get(FONT_UI
)->height
;
515 /* Adjust for font size, trying to center the information vertically */
521 radio_load_presets(global_settings
.fmr_file
);
524 if(radio_status
== FMRADIO_OFF
)
528 #if CONFIG_CODEC != SWCODEC
529 if(rec_create_directory() > 0)
530 have_recorded
= true;
532 audio_init_recording(talk_get_bufsize());
534 sound_settings_apply();
535 /* Yes, we use the D/A for monitoring */
536 peak_meter_playback(true);
538 peak_meter_enabled
= true;
540 rec_init_recording_options(&rec_options
);
541 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
542 rec_set_recording_options(&rec_options
);
544 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
545 sound_default(SOUND_RIGHT_GAIN
), AUDIO_GAIN_LINEIN
);
547 #endif /* CONFIG_CODEC != SWCODEC */
548 #endif /* ndef SIMULATOR */
551 #if CONFIG_CODEC == SWCODEC
552 audio_set_input_source(AUDIO_SRC_FMRADIO
,
553 (radio_status
== FMRADIO_PAUSED
) ?
554 SRCF_FMRADIO_PAUSED
: SRCF_FMRADIO_PLAYING
);
556 if (radio_status
== FMRADIO_OFF
)
560 if(num_presets
< 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN
)))
563 curr_preset
= find_preset(curr_freq
);
564 if(curr_preset
!= -1)
565 radio_mode
= RADIO_PRESET_MODE
;
567 #ifdef HAVE_BUTTONBAR
568 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
569 str(LANG_PRESET
), str(LANG_FM_BUTTONBAR_RECORD
));
572 #ifndef HAVE_NOISY_IDLE_MODE
580 curr_freq
= step_freq(curr_freq
, search_dir
);
581 update_screen
= true;
583 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
585 curr_preset
= find_preset(curr_freq
);
586 remember_frequency();
599 #if CONFIG_CODEC != SWCODEC
600 /* TODO: Can we timeout at HZ when recording since peaks aren't
601 displayed? This should quiet recordings too. */
602 button
= get_action(CONTEXT_FM
,
603 update_screen
? TIMEOUT_NOBLOCK
: HZ
/ PEAK_METER_FPS
);
605 button
= get_action(CONTEXT_FM
,
606 update_screen
? TIMEOUT_NOBLOCK
: HZ
);
609 #ifndef HAVE_NOISY_IDLE_MODE
610 if (button
!= ACTION_NONE
)
612 cpu_idle_mode(false);
613 button_timeout
= current_tick
+ (2*HZ
);
619 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
620 if(audio_status() == AUDIO_STATUS_RECORD
)
630 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
632 if(filepreset
[0] == '\0')
635 radio_save_presets();
638 /* Clear the preset list on exit. */
641 update_screen
= true;
645 case ACTION_FM_RECORD
:
646 #ifdef FM_RECORD_DBLPRE
647 if (lastbutton
!= ACTION_FM_RECORD_DBLPRE
)
652 if (current_tick
- rec_lastclick
> HZ
/2)
654 rec_lastclick
= current_tick
;
657 #endif /* FM_RECORD_DBLPRE */
659 if(audio_status() == AUDIO_STATUS_RECORD
)
661 rec_command(RECORDING_CMD_START_NEWFILE
);
662 update_screen
= true;
666 have_recorded
= true;
667 rec_command(RECORDING_CMD_START
);
668 update_screen
= true;
670 #endif /* SIMULATOR */
673 #endif /* #ifdef FM_RECORD */
676 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
677 if(audio_status() == AUDIO_STATUS_RECORD
)
682 ret_val
= GO_TO_ROOT
;
685 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
687 if(filepreset
[0] == '\0')
690 radio_save_presets();
694 /* Clear the preset list on exit. */
699 case ACTION_STD_PREV
:
700 case ACTION_STD_NEXT
:
701 next_station(button
== ACTION_STD_PREV
? -1 : 1);
703 update_screen
= true;
707 case ACTION_STD_PREVREPEAT
:
708 case ACTION_STD_NEXTREPEAT
:
710 int dir
= search_dir
;
711 search_dir
= button
== ACTION_STD_PREVREPEAT
? -1 : 1;
712 if (radio_mode
!= RADIO_SCAN_MODE
)
714 next_preset(search_dir
);
716 update_screen
= true;
721 /* Starting auto scan */
722 tuner_set(RADIO_MUTE
, 1);
723 update_screen
= true;
728 case ACTION_SETTINGS_INC
:
729 case ACTION_SETTINGS_INCREPEAT
:
730 global_settings
.volume
++;
732 update_screen
= true;
735 case ACTION_SETTINGS_DEC
:
736 case ACTION_SETTINGS_DECREPEAT
:
737 global_settings
.volume
--;
739 update_screen
= true;
743 if (radio_status
== FMRADIO_PLAYING
)
748 update_screen
= true;
754 viewportmanager_set_statusbar(oldbars
);
756 curr_preset
= find_preset(curr_freq
);
757 viewportmanager_set_statusbar(fmbars
);
760 screens
[i
].set_viewport(&vp
[i
]);
761 screens
[i
].clear_viewport();
762 screens
[i
].update_viewport();
763 screens
[i
].set_viewport(NULL
);
765 #ifdef HAVE_BUTTONBAR
766 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
768 str(LANG_FM_BUTTONBAR_RECORD
));
770 update_screen
= true;
774 case ACTION_FM_PRESET
:
777 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
778 update_screen
= true;
781 screens
[i
].set_viewport(&vp
[i
]);
782 screens
[i
].clear_viewport();
783 screens
[i
].update_viewport();
784 screens
[i
].set_viewport(NULL
);
789 viewportmanager_set_statusbar(oldbars
);
790 handle_radio_presets();
791 viewportmanager_set_statusbar(fmbars
);
794 screens
[i
].set_viewport(&vp
[i
]);
795 screens
[i
].stop_scroll();
796 screens
[i
].clear_viewport();
797 screens
[i
].update_viewport();
798 screens
[i
].set_viewport(NULL
);
800 #ifdef HAVE_BUTTONBAR
801 gui_buttonbar_set(&buttonbar
,
802 str(LANG_BUTTONBAR_MENU
),
804 str(LANG_FM_BUTTONBAR_RECORD
));
806 update_screen
= true;
808 #endif /* FM_PRESET */
811 case ACTION_FM_FREEZE
:
814 splash(HZ
, str(LANG_FM_FREEZE
));
815 screen_freeze
= true;
819 update_screen
= true;
820 screen_freeze
= false;
823 #endif /* FM_FREEZE */
825 case SYS_USB_CONNECTED
:
826 #if CONFIG_CODEC != SWCODEC
827 /* Only accept USB connection when not recording */
828 if(audio_status() != AUDIO_STATUS_RECORD
)
831 default_event_handler(SYS_USB_CONNECTED
);
832 screen_freeze
= true; /* Cosmetic: makes sure the
833 radio screen doesn't redraw */
840 if(radio_mode
== RADIO_SCAN_MODE
)
842 /* Force scan mode if there are no presets. */
844 radio_mode
= RADIO_PRESET_MODE
;
847 radio_mode
= RADIO_SCAN_MODE
;
848 update_screen
= true;
849 cond_talk_ids_fq(radio_mode
?
850 LANG_PRESET
: LANG_RADIO_SCAN_MODE
);
855 #ifdef FM_NEXT_PRESET
856 case ACTION_FM_NEXT_PRESET
:
859 update_screen
= true;
864 #ifdef FM_PREV_PRESET
865 case ACTION_FM_PREV_PRESET
:
868 update_screen
= true;
874 default_event_handler(button
);
878 #ifdef FM_RECORD_DBLPRE
879 if (button
!= ACTION_NONE
)
883 #if CONFIG_CODEC != SWCODEC
889 /* Only display the peak meter when not recording */
890 #if CONFIG_CODEC != SWCODEC
895 screens
[i
].set_viewport(&vp
[i
]);
896 peak_meter_screen(&screens
[i
],0,
897 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
899 screens
[i
].update_rect(0,
900 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
901 screens
[i
].getwidth(), fh
);
902 screens
[i
].set_viewport(NULL
);
906 if(TIME_AFTER(current_tick
, timeout
))
908 timeout
= current_tick
+ HZ
;
911 #endif /* CONFIG_CODEC == SWCODEC */
913 /* keep "mono" from always being displayed when paused */
914 if (radio_status
!= FMRADIO_PAUSED
)
916 stereo
= tuner_get(RADIO_STEREO
) &&
917 !global_settings
.fm_force_mono
;
919 if(stereo
!= last_stereo
)
921 update_screen
= true;
922 last_stereo
= stereo
;
927 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
928 seconds
= audio_recorded_time() / HZ
;
929 if (update_screen
|| seconds
> last_seconds
)
931 last_seconds
= seconds
;
940 screens
[i
].set_viewport(&vp
[i
]);
943 snprintf(buf
, 128, curr_preset
>= 0 ? "%d. %s" : " ",
944 curr_preset
+ 1, presets
[curr_preset
].name
);
947 screens
[i
].puts_scroll(0, top_of_screen
, buf
);
949 freq
= curr_freq
/ 10000;
950 snprintf(buf
, 128, str(LANG_FM_STATION
),
951 freq
/ 100, freq
% 100);
953 screens
[i
].puts_scroll(0, top_of_screen
+ 1, buf
);
955 snprintf(buf
, 128, "%s", stereo
?str(LANG_CHANNEL_STEREO
):
956 str(LANG_CHANNEL_MONO
));
958 screens
[i
].puts_scroll(0, top_of_screen
+ 2, buf
);
960 snprintf(buf
, 128, "%s %s", str(LANG_MODE
),
961 radio_mode
? str(LANG_PRESET
) :
962 str(LANG_RADIO_SCAN_MODE
));
964 screens
[i
].puts_scroll(0, top_of_screen
+ 3, buf
);
966 #if CONFIG_CODEC != SWCODEC
967 if(audio_status() == AUDIO_STATUS_RECORD
)
969 hours
= seconds
/ 3600;
970 minutes
= (seconds
- (hours
* 3600)) / 60;
971 snprintf(buf
, 32, "%s %02d:%02d:%02d",
972 str(LANG_RECORDING_TIME
),
973 hours
, minutes
, seconds
%60);
975 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
979 if(rec_options
.rec_prerecord_time
)
981 snprintf(buf
, 32, "%s %02d",
982 str(LANG_RECORD_PRERECORD
), seconds
%60);
984 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
987 #endif /* CONFIG_CODEC != SWCODEC */
991 screens
[i
].update_viewport();
992 screens
[i
].set_viewport(NULL
);
995 #ifdef HAVE_BUTTONBAR
996 gui_buttonbar_draw(&buttonbar
);
1001 update_screen
= false;
1003 if (global_settings
.talk_file
&& talk
1004 && radio_status
== FMRADIO_PAUSED
)
1007 bool enqueue
= false;
1008 if (radio_mode
== RADIO_SCAN_MODE
)
1010 talk_freq(curr_freq
, enqueue
);
1013 if (curr_preset
>= 0)
1014 talk_preset(curr_preset
, radio_mode
== RADIO_PRESET_MODE
,
1018 #if CONFIG_CODEC != SWCODEC
1019 if(audio_status() & AUDIO_STATUS_ERROR
)
1025 #ifndef HAVE_NOISY_IDLE_MODE
1026 if (TIME_AFTER(current_tick
, button_timeout
))
1028 cpu_idle_mode(true);
1034 #if CONFIG_CODEC != SWCODEC
1035 if(audio_status() & AUDIO_STATUS_ERROR
)
1037 splash(0, str(LANG_DISK_FULL
));
1040 screens
[i
].set_viewport(&vp
[i
]);
1041 screens
[i
].update_viewport();
1042 screens
[i
].set_viewport(NULL
);
1044 audio_error_clear();
1048 button
= get_action(CONTEXT_FM
, TIMEOUT_BLOCK
);
1049 if(button
== ACTION_FM_STOP
)
1054 audio_init_playback();
1055 #endif /* CONFIG_CODEC != SWCODEC */
1057 sound_settings_apply();
1058 #endif /* SIMULATOR */
1062 /* Catch FMRADIO_PLAYING status for the sim. */
1064 #if CONFIG_CODEC != SWCODEC
1065 /* Enable the Left and right A/D Converter */
1066 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
1067 sound_default(SOUND_RIGHT_GAIN
),
1069 mas_codec_writereg(6, 0x4000);
1072 #endif /* SIMULATOR */
1076 #if CONFIG_CODEC == SWCODEC
1077 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
1083 #ifndef HAVE_NOISY_IDLE_MODE
1084 cpu_idle_mode(false);
1087 viewportmanager_set_statusbar(oldbars
);
1089 #if CONFIG_CODEC != SWCODEC
1090 return have_recorded
;
1094 } /* radio_screen */
1096 static void radio_save_presets(void)
1101 fd
= creat(filepreset
);
1104 for(i
= 0;i
< num_presets
;i
++)
1106 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
1110 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
1111 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
1112 presets_changed
= false;
1116 splash(HZ
, ID2P(LANG_FM_PRESET_SAVE_FAILED
));
1120 void radio_load_presets(char *filename
)
1130 memset(presets
, 0, sizeof(presets
));
1133 /* No Preset in configuration. */
1134 if(filename
[0] == '\0')
1136 filepreset
[0] = '\0';
1139 /* Temporary preset, loaded until player shuts down. */
1140 else if(filename
[0] == '/')
1141 strlcpy(filepreset
, filename
, sizeof(filepreset
));
1142 /* Preset from default directory. */
1144 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
1145 FMPRESET_PATH
, filename
);
1147 fd
= open_utf8(filepreset
, O_RDONLY
);
1150 while(!done
&& num_presets
< MAX_PRESETS
)
1152 rc
= read_line(fd
, buf
, 128);
1155 if(settings_parseline(buf
, &freq
, &name
))
1158 if(f
) /* For backwards compatibility */
1160 struct fmstation
* const fms
= &presets
[num_presets
];
1162 strlcpy(fms
->name
, name
, MAX_FMPRESET_LEN
+1);
1172 else /* invalid file name? */
1173 filepreset
[0] = '\0';
1175 presets_loaded
= num_presets
> 0;
1176 presets_changed
= false;
1180 static int radio_add_preset(void)
1182 char buf
[MAX_FMPRESET_LEN
+ 1];
1184 if(num_presets
< MAX_PRESETS
)
1188 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1190 struct fmstation
* const fms
= &presets
[num_presets
];
1191 strcpy(fms
->name
, buf
);
1192 fms
->frequency
= curr_freq
;
1194 presets_changed
= true;
1195 presets_loaded
= num_presets
> 0;
1201 splash(HZ
, ID2P(LANG_FM_NO_FREE_PRESETS
));
1206 /* needed to know which preset we are edit/delete-ing */
1207 static int selected_preset
= -1;
1208 static int radio_edit_preset(void)
1210 char buf
[MAX_FMPRESET_LEN
+ 1];
1212 if (num_presets
> 0)
1214 struct fmstation
* const fms
= &presets
[selected_preset
];
1216 strcpy(buf
, fms
->name
);
1218 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1220 strcpy(fms
->name
, buf
);
1221 presets_changed
= true;
1228 static int radio_delete_preset(void)
1230 if (num_presets
> 0)
1232 struct fmstation
* const fms
= &presets
[selected_preset
];
1234 if (selected_preset
>= --num_presets
)
1235 selected_preset
= num_presets
- 1;
1237 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
1240 if (curr_preset
>= num_presets
)
1244 /* Don't ask to save when all presets are deleted. */
1245 presets_changed
= num_presets
> 0;
1247 if (!presets_changed
)
1249 /* The preset list will be cleared, switch to Scan Mode. */
1250 radio_mode
= RADIO_SCAN_MODE
;
1252 presets_loaded
= false;
1258 static int load_preset_list(void)
1260 return !rockbox_browse(FMPRESET_PATH
, SHOW_FMR
);
1263 static int save_preset_list(void)
1267 bool bad_file_name
= true;
1269 if(!dir_exists(FMPRESET_PATH
)) /* Check if there is preset folder */
1270 mkdir(FMPRESET_PATH
);
1272 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
1273 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
1275 while(bad_file_name
)
1277 if(!kbd_input(filepreset
, sizeof(filepreset
)))
1279 /* check the name: max MAX_FILENAME (20) chars */
1283 p1
= strrchr(filepreset
, '/');
1285 while((p1
) && (*p2
) && (*p2
!= '.'))
1287 len
= (int)(p2
-p1
) - 1;
1288 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
1290 /* no slash, too long or too short */
1291 splash(HZ
, ID2P(LANG_INVALID_FILENAME
));
1295 /* add correct extension (easier to always write)
1296 at this point, p2 points to 0 or the extension dot */
1298 strcat(filepreset
,".fmr");
1299 bad_file_name
= false;
1300 radio_save_presets();
1311 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
1316 static int clear_preset_list(void)
1318 /* Clear all the preset entries */
1319 memset(presets
, 0, sizeof (presets
));
1322 presets_loaded
= false;
1323 /* The preset list will be cleared switch to Scan Mode. */
1324 radio_mode
= RADIO_SCAN_MODE
;
1327 presets_changed
= false; /* Don't ask to save when clearing the list. */
1332 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1333 ID2P(LANG_FM_EDIT_PRESET
),
1334 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
1335 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1336 ID2P(LANG_FM_DELETE_PRESET
),
1337 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
1338 static int radio_preset_callback(int action
,
1339 const struct menu_item_ex
*this_item
)
1341 if (action
== ACTION_STD_OK
)
1342 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
1346 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_PRESET
),
1347 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
1348 &radio_delete_preset_item
);
1349 /* present a list of preset stations */
1350 static const char* presets_get_name(int selected_item
, void *data
,
1351 char *buffer
, size_t buffer_len
)
1354 struct fmstation
*p
= &presets
[selected_item
];
1357 int freq
= p
->frequency
/ 10000;
1358 int frac
= freq
% 100;
1360 snprintf(buffer
, buffer_len
,
1361 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
1365 static int presets_speak_name(int selected_item
, void * data
)
1368 talk_preset(selected_item
, true, false);
1372 static int handle_radio_presets(void)
1374 struct gui_synclist lists
;
1376 int action
= ACTION_NONE
;
1377 #ifdef HAVE_BUTTONBAR
1378 struct gui_buttonbar buttonbar
;
1381 if(presets_loaded
== false)
1384 #ifdef HAVE_BUTTONBAR
1385 gui_buttonbar_init(&buttonbar
);
1386 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
1387 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
1388 str(LANG_FM_BUTTONBAR_EXIT
),
1389 str(LANG_FM_BUTTONBAR_ACTION
));
1390 gui_buttonbar_draw(&buttonbar
);
1392 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1, NULL
);
1393 gui_synclist_set_title(&lists
, str(LANG_PRESET
), NOICON
);
1394 gui_synclist_set_icon_callback(&lists
, NULL
);
1395 if(global_settings
.talk_file
)
1396 gui_synclist_set_voice_callback(&lists
, presets_speak_name
);
1397 gui_synclist_set_nb_items(&lists
, num_presets
);
1398 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
1399 gui_synclist_speak_item(&lists
);
1403 gui_synclist_draw(&lists
);
1404 list_do_action(CONTEXT_STD
, TIMEOUT_BLOCK
,
1405 &lists
, &action
, LIST_WRAP_UNLESS_HELD
);
1408 case ACTION_STD_MENU
:
1409 if (radio_add_preset())
1411 gui_synclist_set_nb_items(&lists
, num_presets
);
1412 gui_synclist_select_item(&lists
, num_presets
- 1);
1415 case ACTION_STD_CANCEL
:
1419 curr_preset
= gui_synclist_get_sel_pos(&lists
);
1420 curr_freq
= presets
[curr_preset
].frequency
;
1422 remember_frequency();
1426 case ACTION_STD_CONTEXT
:
1427 selected_preset
= gui_synclist_get_sel_pos(&lists
);
1428 do_menu(&handle_radio_preset_menu
, NULL
, NULL
, false);
1429 gui_synclist_set_nb_items(&lists
, num_presets
);
1430 gui_synclist_select_item(&lists
, selected_preset
);
1431 gui_synclist_speak_item(&lists
);
1434 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
1441 void toggle_mono_mode(bool mono
)
1443 tuner_set(RADIO_FORCE_MONO
, mono
);
1446 void set_radio_region(int region
)
1448 #ifdef HAVE_RADIO_REGION
1449 tuner_set(RADIO_REGION
, region
);
1452 remember_frequency();
1456 MENUITEM_SETTING(set_region
, &global_settings
.fm_region
, NULL
);
1457 MENUITEM_SETTING(force_mono
, &global_settings
.fm_force_mono
, NULL
);
1460 static char* get_mode_text(int selected_item
, void * data
, char *buffer
)
1462 (void)selected_item
;
1464 snprintf(buffer
, MAX_PATH
, "%s %s", str(LANG_MODE
),
1465 radio_mode
? str(LANG_PRESET
) :
1466 str(LANG_RADIO_SCAN_MODE
));
1469 static int toggle_radio_mode(void)
1471 radio_mode
= (radio_mode
== RADIO_SCAN_MODE
) ?
1472 RADIO_PRESET_MODE
: RADIO_SCAN_MODE
;
1475 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item
, 0,
1476 toggle_radio_mode
, NULL
,
1477 get_mode_text
, NULL
, NULL
, NULL
, Icon_NOICON
);
1480 static int scan_presets(void *viewports
)
1482 bool do_scan
= true;
1484 struct viewport
*vp
= (struct viewport
*)viewports
;
1487 screens
[i
].set_viewport(vp
?&vp
[i
]:NULL
);
1488 if(num_presets
> 0) /* Do that to avoid 2 questions. */
1489 do_scan
= yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS
));
1493 const struct fm_region_data
* const fmr
=
1494 &fm_region_data
[global_settings
.fm_region
];
1496 curr_freq
= fmr
->freq_min
;
1498 memset(presets
, 0, sizeof(presets
));
1499 tuner_set(RADIO_MUTE
, 1);
1501 while(curr_freq
<= fmr
->freq_max
)
1504 if(num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
1507 freq
= curr_freq
/ 10000;
1511 splashf(0, str(LANG_FM_SCANNING
), freq
, frac
);
1513 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
1516 presets
[num_presets
].name
[0] = '\0';
1517 presets
[num_presets
].frequency
= curr_freq
;
1521 curr_freq
+= fmr
->freq_step
;
1524 if (radio_status
== FMRADIO_PLAYING
)
1525 tuner_set(RADIO_MUTE
, 0);
1527 presets_changed
= true;
1531 screens
[i
].clear_viewport();
1532 screens
[i
].update_viewport();
1537 curr_freq
= presets
[0].frequency
;
1538 radio_mode
= RADIO_PRESET_MODE
;
1539 presets_loaded
= true;
1544 /* Wrap it to beginning or we'll be past end of band */
1545 presets_loaded
= false;
1553 #ifdef HAVE_RECORDING
1555 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1556 #define FM_RECORDING_SCREEN
1557 static int fm_recording_screen(void)
1561 /* switch recording source to FMRADIO for the duration */
1562 int rec_source
= global_settings
.rec_source
;
1563 global_settings
.rec_source
= AUDIO_SRC_FMRADIO
;
1565 ret
= recording_screen(true);
1567 /* safe to reset as changing sources is prohibited here */
1568 global_settings
.rec_source
= rec_source
;
1573 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1575 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1576 #define FM_RECORDING_SETTINGS
1577 static int fm_recording_settings(void)
1579 bool ret
= recording_menu(true);
1581 #if CONFIG_CODEC != SWCODEC
1584 struct audio_recording_options rec_options
;
1585 rec_init_recording_options(&rec_options
);
1586 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
1587 rec_set_recording_options(&rec_options
);
1594 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1595 #endif /* HAVE_RECORDING */
1597 #ifdef FM_RECORDING_SCREEN
1598 MENUITEM_FUNCTION(recscreen_item
, 0, ID2P(LANG_RECORDING
),
1599 fm_recording_screen
, NULL
, NULL
, Icon_Recording
);
1601 #ifdef FM_RECORDING_SETTINGS
1602 MENUITEM_FUNCTION(recsettings_item
, 0, ID2P(LANG_RECORDING_SETTINGS
),
1603 fm_recording_settings
, NULL
, NULL
, Icon_Recording
);
1606 MENUITEM_FUNCTION(radio_presets_item
, 0, ID2P(LANG_PRESET
),
1607 handle_radio_presets
, NULL
, NULL
, Icon_NOICON
);
1609 #ifndef FM_PRESET_ADD
1610 MENUITEM_FUNCTION(radio_addpreset_item
, 0, ID2P(LANG_FM_ADD_PRESET
),
1611 radio_add_preset
, NULL
, NULL
, Icon_NOICON
);
1615 MENUITEM_FUNCTION(presetload_item
, 0, ID2P(LANG_FM_PRESET_LOAD
),
1616 load_preset_list
, NULL
, NULL
, Icon_NOICON
);
1617 MENUITEM_FUNCTION(presetsave_item
, 0, ID2P(LANG_FM_PRESET_SAVE
),
1618 save_preset_list
, NULL
, NULL
, Icon_NOICON
);
1619 MENUITEM_FUNCTION(presetclear_item
, 0, ID2P(LANG_FM_PRESET_CLEAR
),
1620 clear_preset_list
, NULL
, NULL
, Icon_NOICON
);
1621 MENUITEM_FUNCTION(scan_presets_item
, MENU_FUNC_USEPARAM
,
1622 ID2P(LANG_FM_SCAN_PRESETS
),
1623 scan_presets
, NULL
, NULL
, Icon_NOICON
);
1625 MAKE_MENU(radio_settings_menu
, ID2P(LANG_FM_MENU
), NULL
,
1628 &radio_presets_item
,
1630 #ifndef FM_PRESET_ADD
1631 &radio_addpreset_item
,
1633 &presetload_item
, &presetsave_item
, &presetclear_item
,
1638 &set_region
, &sound_settings
,
1639 #ifdef FM_RECORDING_SCREEN
1642 #ifdef FM_RECORDING_SETTINGS
1645 &scan_presets_item
);
1646 /* main menu of the radio screen */
1647 static bool radio_menu(void)
1649 return do_menu(&radio_settings_menu
, NULL
, NULL
, false) ==