1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2003 Linus Nielsen Feltzing
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
32 #include "mp3_playback.h"
44 #include "peakmeter.h"
47 #include "sound_menu.h"
48 #include "recording.h"
53 #include "screen_access.h"
54 #include "statusbar.h"
58 #include "buttonbar.h"
64 #include "menus/exported_menus.h"
65 #include "root_menu.h"
69 #if CONFIG_KEYPAD == RECORDER_PAD
72 #define FM_PRESET_ACTION
76 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
79 #define FM_NEXT_PRESET
80 #define FM_PREV_PRESET
82 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
85 /* This should be removeable if the whole tuning thing is sorted out since
86 proper tuning quiets the screen almost entirely in that extreme measures
87 have to be taken to hear any interference. */
88 #define HAVE_NOISY_IDLE_MODE
90 #elif CONFIG_KEYPAD == ONDIO_PAD
91 #define FM_RECORD_DBLPRE
95 #define RADIO_SCAN_MODE 0
96 #define RADIO_PRESET_MODE 1
98 static const struct fm_region_setting fm_region
[] = {
99 /* Note: Desriptive strings are just for display atm and are not compiled. */
100 FM_REGION_ENTRY("Europe", 87500000, 108000000, 50000, 0, 0),
101 FM_REGION_ENTRY("US/Canada", 87900000, 107900000, 200000, 1, 0),
102 FM_REGION_ENTRY("Japan", 76000000, 90000000, 100000, 0, 1),
103 FM_REGION_ENTRY("Korea", 87500000, 108000000, 100000, 0, 0),
106 static int curr_preset
= -1;
107 static int curr_freq
;
108 static int radio_mode
= RADIO_SCAN_MODE
;
110 static int radio_status
= FMRADIO_OFF
;
111 static bool in_screen
= false;
113 #define MAX_PRESETS 64
114 static bool presets_loaded
= false, presets_changed
= false;
115 static struct fmstation presets
[MAX_PRESETS
];
117 static char filepreset
[MAX_PATH
]; /* preset filename variable */
119 static int num_presets
= 0; /* The number of presets in the preset list */
121 static void radio_save_presets(void);
122 static int handle_radio_presets(void);
123 static bool radio_menu(void);
124 static int radio_add_preset(void);
125 static int save_preset_list(void);
126 static int load_preset_list(void);
127 static int clear_preset_list(void);
129 static int scan_presets(void);
131 /* Function to manipulate all yesno dialogues.
132 This function needs the output text as an argument. */
133 static bool yesno_pop(char* text
)
136 char *lines
[]={text
};
137 struct text_message message
={lines
, 1};
138 bool ret
= (gui_syncyesno_run(&message
,NULL
,NULL
)== YESNO_YES
);
140 gui_textarea_clear(&screens
[i
]);
144 void radio_init(void)
150 int get_radio_status(void)
155 bool in_radio_screen(void)
160 /* secret flag for starting paused - prevents unmute */
161 #define FMRADIO_START_PAUSED 0x8000
162 void radio_start(void)
164 const struct fm_region_setting
*fmr
;
168 if(radio_status
== FMRADIO_PLAYING
)
171 fmr
= &fm_region
[global_settings
.fm_region
];
173 start_paused
= radio_status
& FMRADIO_START_PAUSED
;
174 /* clear flag before any yielding */
175 radio_status
&= ~FMRADIO_START_PAUSED
;
177 if(radio_status
== FMRADIO_OFF
)
180 curr_freq
= global_status
.last_frequency
181 * fmr
->freq_step
+ fmr
->freq_min
;
183 radio_set(RADIO_SLEEP
, 0); /* wake up the tuner */
184 radio_set(RADIO_FREQUENCY
, curr_freq
);
186 if(radio_status
== FMRADIO_OFF
)
188 #if (CONFIG_TUNER & S1A0903X01)
189 radio_set(RADIO_IF_MEASUREMENT
, 0);
190 radio_set(RADIO_SENSITIVITY
, 0);
192 radio_set(RADIO_FORCE_MONO
, global_settings
.fm_force_mono
);
193 #if (CONFIG_TUNER & TEA5767)
194 radio_set(RADIO_SET_DEEMPHASIS
, fmr
->deemphasis
);
195 radio_set(RADIO_SET_BAND
, fmr
->band
);
197 mute_timeout
= current_tick
+ 1*HZ
;
202 mute_timeout
= current_tick
+ 2*HZ
;
205 while(!radio_get(RADIO_STEREO
) && !radio_get(RADIO_TUNED
))
207 if(TIME_AFTER(current_tick
, mute_timeout
))
212 /* keep radio from sounding initially */
214 radio_set(RADIO_MUTE
, 0);
216 radio_status
= FMRADIO_PLAYING
;
219 void radio_pause(void)
221 if(radio_status
== FMRADIO_PAUSED
)
224 if(radio_status
== FMRADIO_OFF
)
226 radio_status
|= FMRADIO_START_PAUSED
;
230 radio_set(RADIO_MUTE
, 1);
231 radio_set(RADIO_SLEEP
, 1);
233 radio_status
= FMRADIO_PAUSED
;
236 void radio_stop(void)
238 if(radio_status
== FMRADIO_OFF
)
241 radio_set(RADIO_MUTE
, 1);
242 radio_set(RADIO_SLEEP
, 1); /* low power mode, if available */
243 radio_status
= FMRADIO_OFF
;
244 radio_power(false); /* status update, power off if avail. */
247 bool radio_hardware_present(void)
249 #ifdef HAVE_TUNER_PWR_CTRL
251 bool fmstatus
= radio_power(true); /* power it up */
252 ret
= radio_get(RADIO_PRESENT
);
253 radio_power(fmstatus
); /* restore previous state */
256 return radio_get(RADIO_PRESENT
);
260 /* Keep freq on the grid for the current region */
261 static int snap_freq_to_grid(int freq
)
263 const struct fm_region_setting
* const fmr
=
264 &fm_region
[global_settings
.fm_region
];
266 /* Range clamp if out of range or just round to nearest */
267 if (freq
< fmr
->freq_min
)
268 freq
= fmr
->freq_min
;
269 else if (freq
> fmr
->freq_max
)
270 freq
= fmr
->freq_max
;
272 freq
= (freq
- fmr
->freq_min
+ fmr
->freq_step
/2) /
273 fmr
->freq_step
* fmr
->freq_step
+ fmr
->freq_min
;
278 /* Find a matching preset to freq */
279 static int find_preset(int freq
)
284 for(i
= 0;i
< MAX_PRESETS
;i
++)
286 if(freq
== presets
[i
].frequency
)
293 /* Return the first preset encountered in the search direction with
295 static int find_closest_preset(int freq
, int direction
)
299 if (direction
== 0) /* direction == 0 isn't really used */
302 for (i
= 0; i
< MAX_PRESETS
; i
++)
304 int preset_frequency
= presets
[i
].frequency
;
306 if (preset_frequency
== freq
)
307 return i
; /* Exact match = stop */
308 /* Stop when the preset frequency exeeds freq so that we can
309 pick the correct one based on direction */
310 if (preset_frequency
> freq
)
314 /* wrap around depending on direction */
315 if (i
== 0 || i
>= num_presets
- 1)
316 i
= direction
< 0 ? num_presets
- 1 : 0;
317 else if (direction
< 0)
318 i
--; /* use previous */
323 static void remember_frequency(void)
325 const struct fm_region_setting
* const fmr
=
326 &fm_region
[global_settings
.fm_region
];
328 global_status
.last_frequency
= (curr_freq
- fmr
->freq_min
)
333 static void next_preset(int direction
)
338 if (curr_preset
== -1)
339 curr_preset
= find_closest_preset(curr_freq
, direction
);
341 curr_preset
= (curr_preset
+ direction
+ num_presets
) % num_presets
;
343 /* Must stay on the current grid for the region */
344 curr_freq
= snap_freq_to_grid(presets
[curr_preset
].frequency
);
346 radio_set(RADIO_FREQUENCY
, curr_freq
);
347 remember_frequency();
350 /* Step to the next or previous frequency */
351 static int step_freq(int freq
, int direction
)
353 const struct fm_region_setting
* const fmr
=
354 &fm_region
[global_settings
.fm_region
];
356 freq
+= direction
*fmr
->freq_step
;
358 /* Wrap first or snapping to grid will not let us on the band extremes */
359 if (freq
> fmr
->freq_max
)
360 freq
= direction
> 0 ? fmr
->freq_min
: fmr
->freq_max
;
361 else if (freq
< fmr
->freq_min
)
362 freq
= direction
< 0 ? fmr
->freq_max
: fmr
->freq_min
;
364 freq
= snap_freq_to_grid(freq
);
369 /* Step to the next or previous station */
370 static void next_station(int direction
)
372 if (direction
!= 0 && radio_mode
!= RADIO_SCAN_MODE
)
374 next_preset(direction
);
378 curr_freq
= step_freq(curr_freq
, direction
);
380 if (radio_status
== FMRADIO_PLAYING
)
381 radio_set(RADIO_MUTE
, 1);
383 radio_set(RADIO_FREQUENCY
, curr_freq
);
385 if (radio_status
== FMRADIO_PLAYING
)
386 radio_set(RADIO_MUTE
, 0);
388 curr_preset
= find_preset(curr_freq
);
389 remember_frequency();
392 int radio_screen(void)
396 int ret_val
= GO_TO_ROOT
;
400 bool stereo
= false, last_stereo
= false;
402 int top_of_screen
= 0;
403 bool update_screen
= true;
404 bool screen_freeze
= false;
405 bool keep_playing
= false;
406 bool statusbar
= global_settings
.statusbar
;
407 #ifdef FM_RECORD_DBLPRE
408 int lastbutton
= BUTTON_NONE
;
409 unsigned long rec_lastclick
= 0;
411 #if CONFIG_CODEC != SWCODEC
412 bool have_recorded
= false;
413 int timeout
= current_tick
+ HZ
/10;
414 unsigned int seconds
= 0;
415 unsigned int last_seconds
= 0;
417 struct audio_recording_options rec_options
;
418 #endif /* CONFIG_CODEC != SWCODEC */
419 #ifndef HAVE_NOISY_IDLE_MODE
420 int button_timeout
= current_tick
+ (2*HZ
);
423 struct gui_buttonbar buttonbar
;
424 gui_buttonbar_init(&buttonbar
);
425 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
428 /* Ends an in-progress search - needs access to search_dir */
429 void end_search(void)
431 if (search_dir
!= 0 && radio_status
== FMRADIO_PLAYING
)
432 radio_set(RADIO_MUTE
, 0);
436 /* change status to "in screen" */
439 /* always display status bar in radio screen for now */
440 global_settings
.statusbar
= true;
443 gui_textarea_clear(&screens
[i
]);
444 screen_set_xmargin(&screens
[i
],0);
447 gui_syncstatusbar_draw(&statusbars
,true);
449 fh
= font_get(FONT_UI
)->height
;
451 /* Adjust for font size, trying to center the information vertically */
457 memset(presets
, 0, sizeof(presets
));
458 radio_load_presets(global_settings
.fmr_file
);
461 if(radio_status
== FMRADIO_OFF
)
465 #if CONFIG_CODEC != SWCODEC
466 if(rec_create_directory() > 0)
467 have_recorded
= true;
469 audio_init_recording(talk_get_bufsize());
471 sound_settings_apply();
472 /* Yes, we use the D/A for monitoring */
473 peak_meter_playback(true);
475 peak_meter_enabled
= true;
477 rec_init_recording_options(&rec_options
);
478 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
479 rec_set_recording_options(&rec_options
);
481 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
482 sound_default(SOUND_RIGHT_GAIN
), AUDIO_GAIN_LINEIN
);
484 #endif /* CONFIG_CODEC != SWCODEC */
485 #endif /* ndef SIMULATOR */
488 #if CONFIG_CODEC == SWCODEC
489 rec_set_source(AUDIO_SRC_FMRADIO
,
490 (radio_status
== FMRADIO_PAUSED
) ?
491 SRCF_FMRADIO_PAUSED
: SRCF_FMRADIO_PLAYING
);
493 if (radio_status
== FMRADIO_OFF
)
497 if(num_presets
< 1 && yesno_pop(str(LANG_FM_FIRST_AUTOSCAN
)))
500 curr_preset
= find_preset(curr_freq
);
501 if(curr_preset
!= -1)
502 radio_mode
= RADIO_PRESET_MODE
;
505 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
506 str(LANG_FM_BUTTONBAR_PRESETS
), str(LANG_FM_BUTTONBAR_RECORD
));
509 #ifndef HAVE_NOISY_IDLE_MODE
517 curr_freq
= step_freq(curr_freq
, search_dir
);
518 update_screen
= true;
520 if(radio_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
522 curr_preset
= find_preset(curr_freq
);
523 remember_frequency();
530 #if CONFIG_CODEC != SWCODEC
531 /* TODO: Can we timeout at HZ when recording since peaks aren't
532 displayed? This should quiet recordings too. */
533 button
= get_action(CONTEXT_FM
,
534 update_screen
? TIMEOUT_NOBLOCK
: HZ
/ PEAK_METER_FPS
);
536 button
= get_action(CONTEXT_FM
,
537 update_screen
? TIMEOUT_NOBLOCK
: HZ
);
540 #ifndef HAVE_NOISY_IDLE_MODE
541 if (button
!= ACTION_NONE
)
543 cpu_idle_mode(false);
544 button_timeout
= current_tick
+ (2*HZ
);
550 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
551 if(audio_status() == AUDIO_STATUS_RECORD
)
561 if(yesno_pop(str(LANG_FM_SAVE_CHANGES
)))
563 if(filepreset
[0] == '\0')
566 radio_save_presets();
569 /* Clear the preset list on exit. */
572 update_screen
= true;
576 case ACTION_FM_RECORD
:
577 #ifdef FM_RECORD_DBLPRE
578 if (lastbutton
!= ACTION_FM_RECORD_DBLPRE
)
583 if (current_tick
- rec_lastclick
> HZ
/2)
585 rec_lastclick
= current_tick
;
588 #endif /* FM_RECORD_DBLPRE */
590 if(audio_status() == AUDIO_STATUS_RECORD
)
593 update_screen
= true;
597 have_recorded
= true;
599 update_screen
= true;
601 #endif /* SIMULATOR */
604 #endif /* #ifdef FM_RECORD */
607 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
608 if(audio_status() == AUDIO_STATUS_RECORD
)
613 ret_val
= GO_TO_ROOT
;
616 if(yesno_pop(str(LANG_FM_SAVE_CHANGES
)))
618 if(filepreset
[0] == '\0')
621 radio_save_presets();
625 /* Clear the preset list on exit. */
630 case ACTION_STD_PREV
:
631 case ACTION_STD_NEXT
:
632 next_station(button
== ACTION_STD_PREV
? -1 : 1);
634 update_screen
= true;
637 case ACTION_STD_PREVREPEAT
:
638 case ACTION_STD_NEXTREPEAT
:
640 int dir
= search_dir
;
641 search_dir
= button
== ACTION_STD_PREVREPEAT
? -1 : 1;
642 if (radio_mode
!= RADIO_SCAN_MODE
)
644 next_preset(search_dir
);
646 update_screen
= true;
650 /* Starting auto scan */
651 radio_set(RADIO_MUTE
, 1);
652 update_screen
= true;
657 case ACTION_SETTINGS_INC
:
658 case ACTION_SETTINGS_INCREPEAT
:
659 global_settings
.volume
++;
660 if(global_settings
.volume
> sound_max(SOUND_VOLUME
))
661 global_settings
.volume
= sound_max(SOUND_VOLUME
);
662 sound_set_volume(global_settings
.volume
);
663 update_screen
= true;
667 case ACTION_SETTINGS_DEC
:
668 case ACTION_SETTINGS_DECREPEAT
:
669 global_settings
.volume
--;
670 if(global_settings
.volume
< sound_min(SOUND_VOLUME
))
671 global_settings
.volume
= sound_min(SOUND_VOLUME
);
672 sound_set_volume(global_settings
.volume
);
673 update_screen
= true;
678 if (radio_status
== FMRADIO_PLAYING
)
683 update_screen
= true;
688 curr_preset
= find_preset(curr_freq
);
690 struct screen
*sc
= &screens
[i
];
691 gui_textarea_clear(sc
);
692 screen_set_xmargin(sc
, 0);
695 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
696 str(LANG_FM_BUTTONBAR_PRESETS
),
697 str(LANG_FM_BUTTONBAR_RECORD
));
699 update_screen
= true;
703 case ACTION_FM_PRESET
:
706 gui_syncsplash(HZ
, str(LANG_FM_NO_PRESETS
));
707 update_screen
= true;
710 struct screen
*sc
= &screens
[i
];
711 gui_textarea_clear(sc
);
712 screen_set_xmargin(sc
, 0);
713 gui_textarea_update(sc
);
718 handle_radio_presets();
721 struct screen
*sc
= &screens
[i
];
722 gui_textarea_clear(sc
);
723 screen_set_xmargin(sc
, 0);
724 gui_textarea_update(sc
);
727 gui_buttonbar_set(&buttonbar
,
728 str(LANG_BUTTONBAR_MENU
),
729 str(LANG_FM_BUTTONBAR_PRESETS
),
730 str(LANG_FM_BUTTONBAR_RECORD
));
732 update_screen
= true;
734 #endif /* FM_PRESET */
737 case ACTION_FM_FREEZE
:
740 gui_syncsplash(HZ
, str(LANG_FM_FREEZE
));
741 screen_freeze
= true;
745 update_screen
= true;
746 screen_freeze
= false;
749 #endif /* FM_FREEZE */
751 case SYS_USB_CONNECTED
:
752 #if CONFIG_CODEC != SWCODEC
753 /* Only accept USB connection when not recording */
754 if(audio_status() != AUDIO_STATUS_RECORD
)
757 default_event_handler(SYS_USB_CONNECTED
);
758 screen_freeze
= true; /* Cosmetic: makes sure the
759 radio screen doesn't redraw */
766 if(radio_mode
== RADIO_SCAN_MODE
)
768 /* Force scan mode if there are no presets. */
770 radio_mode
= RADIO_PRESET_MODE
;
773 radio_mode
= RADIO_SCAN_MODE
;
774 update_screen
= true;
778 #ifdef FM_NEXT_PRESET
779 case ACTION_FM_NEXT_PRESET
:
782 update_screen
= true;
786 #ifdef FM_PREV_PRESET
787 case ACTION_FM_PREV_PRESET
:
790 update_screen
= true;
795 default_event_handler(button
);
799 #ifdef FM_RECORD_DBLPRE
800 if (button
!= ACTION_NONE
)
804 #if CONFIG_CODEC != SWCODEC
810 /* Only display the peak meter when not recording */
811 #if CONFIG_CODEC != SWCODEC
816 peak_meter_screen(&screens
[i
],0,
817 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4), fh
);
818 screens
[i
].update_rect(0, STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
819 screens
[i
].width
, fh
);
823 if(TIME_AFTER(current_tick
, timeout
))
825 timeout
= current_tick
+ HZ
;
828 #endif /* CONFIG_CODEC == SWCODEC */
830 /* keep "mono" from always being displayed when paused */
831 if (radio_status
!= FMRADIO_PAUSED
)
833 stereo
= radio_get(RADIO_STEREO
) &&
834 !global_settings
.fm_force_mono
;
836 if(stereo
!= last_stereo
)
838 update_screen
= true;
839 last_stereo
= stereo
;
844 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
845 seconds
= audio_recorded_time() / HZ
;
846 if (update_screen
|| seconds
> last_seconds
)
848 last_seconds
= seconds
;
856 screens
[i
].setfont(FONT_UI
);
858 snprintf(buf
, 128, curr_preset
>= 0 ? "%d. %s" : " ",
859 curr_preset
+ 1, presets
[curr_preset
].name
);
862 screens
[i
].puts_scroll(0, top_of_screen
, buf
);
864 freq
= curr_freq
/ 10000;
865 snprintf(buf
, 128, str(LANG_FM_STATION
), freq
/ 100, freq
% 100);
867 screens
[i
].puts_scroll(0, top_of_screen
+ 1, buf
);
869 snprintf(buf
, 128, stereo
?str(LANG_CHANNEL_STEREO
):
870 str(LANG_CHANNEL_MONO
));
872 screens
[i
].puts_scroll(0, top_of_screen
+ 2, buf
);
874 snprintf(buf
, 128, "%s %s", str(LANG_FM_TUNE_MODE
),
875 radio_mode
? str(LANG_RADIO_PRESET_MODE
) :
876 str(LANG_RADIO_SCAN_MODE
));
878 screens
[i
].puts_scroll(0, top_of_screen
+ 3, buf
);
880 #if CONFIG_CODEC != SWCODEC
881 if(audio_status() == AUDIO_STATUS_RECORD
)
883 hours
= seconds
/ 3600;
884 minutes
= (seconds
- (hours
* 3600)) / 60;
885 snprintf(buf
, 32, "%s %02d:%02d:%02d",
886 str(LANG_RECORDING_TIME
),
887 hours
, minutes
, seconds
%60);
889 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
893 if(rec_options
.rec_prerecord_time
)
895 snprintf(buf
, 32, "%s %02d",
896 str(LANG_RECORD_PRERECORD
), seconds
%60);
898 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
901 #endif /* CONFIG_CODEC != SWCODEC */
904 gui_buttonbar_draw(&buttonbar
);
907 gui_textarea_update(&screens
[i
]);
909 /* Only force the redraw if update_screen is true */
910 gui_syncstatusbar_draw(&statusbars
,true);
913 update_screen
= false;
915 #if CONFIG_CODEC != SWCODEC
916 if(audio_status() & AUDIO_STATUS_ERROR
)
922 #ifndef HAVE_NOISY_IDLE_MODE
923 if (TIME_AFTER(current_tick
, button_timeout
))
931 #if CONFIG_CODEC != SWCODEC
932 if(audio_status() & AUDIO_STATUS_ERROR
)
934 gui_syncsplash(0, str(LANG_DISK_FULL
));
935 gui_syncstatusbar_draw(&statusbars
,true);
937 gui_textarea_update(&screens
[i
]);
942 button
= get_action(CONTEXT_FM
, TIMEOUT_BLOCK
);
943 if(button
== ACTION_FM_STOP
)
948 audio_init_playback();
949 #endif /* CONFIG_CODEC != SWCODEC */
951 sound_settings_apply();
952 #endif /* SIMULATOR */
956 /* Catch FMRADIO_PLAYING status for the sim. */
958 #if CONFIG_CODEC != SWCODEC
959 /* Enable the Left and right A/D Converter */
960 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
961 sound_default(SOUND_RIGHT_GAIN
),
963 mas_codec_writereg(6, 0x4000);
966 #endif /* SIMULATOR */
970 #if CONFIG_CODEC == SWCODEC
971 rec_set_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
977 #ifndef HAVE_NOISY_IDLE_MODE
978 cpu_idle_mode(false);
981 /* restore status bar settings */
982 global_settings
.statusbar
= statusbar
;
985 #if CONFIG_CODEC != SWCODEC
986 return have_recorded
;
992 static void radio_save_presets(void)
997 fd
= creat(filepreset
);
1000 for(i
= 0;i
< num_presets
;i
++)
1002 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
1006 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
1007 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
1008 presets_changed
= false;
1012 gui_syncsplash(HZ
, str(LANG_FM_PRESET_SAVE_FAILED
));
1016 void radio_load_presets(char *filename
)
1026 memset(presets
, 0, sizeof(presets
));
1029 /* No Preset in configuration. */
1030 if(filename
[0] == '\0')
1032 filepreset
[0] = '\0';
1035 /* Temporary preset, loaded until player shuts down. */
1036 else if(filename
[0] == '/')
1037 strncpy(filepreset
, filename
, sizeof(filepreset
));
1038 /* Preset from default directory. */
1040 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
1041 FMPRESET_PATH
, filename
);
1043 fd
= open(filepreset
, O_RDONLY
);
1046 while(!done
&& num_presets
< MAX_PRESETS
)
1048 rc
= read_line(fd
, buf
, 128);
1051 if(settings_parseline(buf
, &freq
, &name
))
1054 if(f
) /* For backwards compatibility */
1056 struct fmstation
* const fms
= &presets
[num_presets
];
1058 strncpy(fms
->name
, name
, MAX_FMPRESET_LEN
);
1059 fms
->name
[MAX_FMPRESET_LEN
] = '\0';
1069 else /* invalid file name? */
1070 filepreset
[0] = '\0';
1072 presets_loaded
= num_presets
> 0;
1073 presets_changed
= false;
1077 static int radio_add_preset(void)
1079 char buf
[MAX_FMPRESET_LEN
];
1081 if(num_presets
< MAX_PRESETS
)
1083 memset(buf
, 0, MAX_FMPRESET_LEN
);
1085 if (!kbd_input(buf
, MAX_FMPRESET_LEN
))
1087 struct fmstation
* const fms
= &presets
[num_presets
];
1088 buf
[MAX_FMPRESET_LEN
] = '\0';
1089 strcpy(fms
->name
, buf
);
1090 fms
->frequency
= curr_freq
;
1092 presets_changed
= true;
1093 presets_loaded
= num_presets
> 0;
1098 gui_syncsplash(HZ
, str(LANG_FM_NO_FREE_PRESETS
));
1103 /* needed to know which preset we are edit/delete-ing */
1104 static int selected_preset
= -1;
1105 static int radio_edit_preset(void)
1107 char buf
[MAX_FMPRESET_LEN
];
1109 if (num_presets
> 0)
1111 struct fmstation
* const fms
= &presets
[selected_preset
];
1113 strncpy(buf
, fms
->name
, MAX_FMPRESET_LEN
);
1115 if (!kbd_input(buf
, MAX_FMPRESET_LEN
))
1117 buf
[MAX_FMPRESET_LEN
] = '\0';
1118 strcpy(fms
->name
, buf
);
1119 presets_changed
= true;
1126 static int radio_delete_preset(void)
1128 if (num_presets
> 0)
1130 struct fmstation
* const fms
= &presets
[selected_preset
];
1132 if (selected_preset
>= --num_presets
)
1133 selected_preset
= num_presets
- 1;
1135 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
1140 /* Don't ask to save when all presets are deleted. */
1141 presets_changed
= num_presets
> 0;
1143 if (!presets_changed
)
1145 /* The preset list will be cleared, switch to Scan Mode. */
1146 radio_mode
= RADIO_SCAN_MODE
;
1147 presets_loaded
= false;
1153 static int load_preset_list(void)
1155 return !rockbox_browse(FMPRESET_PATH
, SHOW_FMR
);
1158 static int save_preset_list(void)
1162 bool bad_file_name
= true;
1164 if(!opendir(FMPRESET_PATH
)) /* Check if there is preset folder */
1165 mkdir(FMPRESET_PATH
);
1167 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
1168 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
1170 while(bad_file_name
)
1172 if(!kbd_input(filepreset
, sizeof(filepreset
)))
1174 /* check the name: max MAX_FILENAME (20) chars */
1178 p1
= strrchr(filepreset
, '/');
1180 while((p1
) && (*p2
) && (*p2
!= '.'))
1182 len
= (int)(p2
-p1
) - 1;
1183 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
1185 /* no slash, too long or too short */
1186 gui_syncsplash(HZ
, str(LANG_INVALID_FILENAME
));
1190 /* add correct extension (easier to always write)
1191 at this point, p2 points to 0 or the extension dot */
1193 strcat(filepreset
,".fmr");
1194 bad_file_name
= false;
1195 radio_save_presets();
1206 gui_syncsplash(HZ
, str(LANG_FM_NO_PRESETS
));
1211 static int clear_preset_list(void)
1213 /* Clear all the preset entries */
1214 memset(presets
, 0, sizeof (presets
));
1217 presets_loaded
= false;
1218 /* The preset list will be cleared switch to Scan Mode. */
1219 radio_mode
= RADIO_SCAN_MODE
;
1221 presets_changed
= false; /* Don't ask to save when clearing the list. */
1226 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1227 ID2P(LANG_FM_EDIT_PRESET
),
1228 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
1229 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1230 ID2P(LANG_FM_DELETE_PRESET
),
1231 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
1232 int radio_preset_callback(int action
, const struct menu_item_ex
*this_item
)
1234 if (action
== ACTION_STD_OK
)
1235 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
1239 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_FM_BUTTONBAR_PRESETS
),
1240 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
1241 &radio_delete_preset_item
);
1242 /* present a list of preset stations */
1243 char * presets_get_name(int selected_item
, void * data
, char *buffer
)
1247 return presets
[selected_item
].name
;
1250 static int handle_radio_presets(void)
1252 struct gui_synclist lists
;
1254 int action
= ACTION_NONE
;
1255 #ifdef HAS_BUTTONBAR
1256 struct gui_buttonbar buttonbar
;
1259 if(presets_loaded
== false)
1262 #ifdef HAS_BUTTONBAR
1263 gui_buttonbar_init(&buttonbar
);
1264 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
1265 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
1266 str(LANG_FM_BUTTONBAR_EXIT
),
1267 str(LANG_FM_BUTTONBAR_ACTION
));
1268 gui_buttonbar_draw(&buttonbar
);
1270 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1);
1271 gui_synclist_set_title(&lists
, str(LANG_FM_BUTTONBAR_PRESETS
), NOICON
);
1272 gui_synclist_set_icon_callback(&lists
, NULL
);
1273 gui_synclist_set_nb_items(&lists
, num_presets
);
1274 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
1276 action_signalscreenchange();
1279 gui_synclist_draw(&lists
);
1280 gui_syncstatusbar_draw(&statusbars
, true);
1281 action
= get_action(CONTEXT_STD
, HZ
);
1283 gui_synclist_do_button(&lists
, action
, LIST_WRAP_UNLESS_HELD
);
1286 case ACTION_STD_MENU
:
1289 case ACTION_STD_CANCEL
:
1293 curr_preset
= gui_synclist_get_sel_pos(&lists
);
1294 curr_freq
= presets
[curr_preset
].frequency
;
1296 remember_frequency();
1300 case ACTION_STD_CONTEXT
:
1301 selected_preset
= gui_synclist_get_sel_pos(&lists
);
1302 do_menu(&handle_radio_preset_menu
, NULL
);
1305 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
1309 action_signalscreenchange();
1313 void toggle_mono_mode(bool mono
)
1315 radio_set(RADIO_FORCE_MONO
, mono
);
1318 void set_radio_region(int region
)
1320 #if (CONFIG_TUNER & TEA5767)
1321 radio_set(RADIO_SET_DEEMPHASIS
,
1322 fm_region
[region
].deemphasis
);
1323 radio_set(RADIO_SET_BAND
, fm_region
[region
].band
);
1328 remember_frequency();
1331 MENUITEM_SETTING(set_region
, &global_settings
.fm_region
, NULL
);
1332 MENUITEM_SETTING(force_mono
, &global_settings
.fm_force_mono
, NULL
);
1335 char* get_mode_text(int selected_item
, void * data
, char *buffer
)
1337 (void)selected_item
;
1339 snprintf(buffer
, MAX_PATH
, "%s %s", str(LANG_FM_TUNE_MODE
),
1340 radio_mode
? str(LANG_RADIO_PRESET_MODE
) :
1341 str(LANG_RADIO_SCAN_MODE
));
1344 static int toggle_radio_mode(void)
1346 radio_mode
= (radio_mode
== RADIO_SCAN_MODE
) ?
1347 RADIO_PRESET_MODE
: RADIO_SCAN_MODE
;
1350 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item
, 0,
1351 toggle_radio_mode
, NULL
,
1352 get_mode_text
, NULL
, NULL
, Icon_NOICON
);
1355 static int scan_presets(void)
1357 bool do_scan
= true;
1359 if(num_presets
> 0) /* Do that to avoid 2 questions. */
1360 do_scan
= yesno_pop(str(LANG_FM_CLEAR_PRESETS
));
1364 const struct fm_region_setting
* const fmr
=
1365 &fm_region
[global_settings
.fm_region
];
1366 char buf
[MAX_FMPRESET_LEN
];
1369 curr_freq
= fmr
->freq_min
;
1371 memset(presets
, 0, sizeof(presets
));
1372 radio_set(RADIO_MUTE
, 1);
1374 while(curr_freq
<= fmr
->freq_max
)
1377 if (num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
1380 freq
= curr_freq
/ 10000;
1384 snprintf(buf
, MAX_FMPRESET_LEN
, str(LANG_FM_SCANNING
), freq
, frac
);
1385 gui_syncsplash(0, buf
);
1387 if(radio_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
1390 snprintf(buf
, MAX_FMPRESET_LEN
,
1391 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
1392 strcpy(presets
[num_presets
].name
,buf
);
1393 presets
[num_presets
].frequency
= curr_freq
;
1397 curr_freq
+= fmr
->freq_step
;
1400 if (radio_status
== FMRADIO_PLAYING
)
1401 radio_set(RADIO_MUTE
, 0);
1403 presets_changed
= true;
1407 gui_textarea_clear(&screens
[i
]);
1408 screen_set_xmargin(&screens
[i
],0);
1409 gui_textarea_update(&screens
[i
]);
1414 curr_freq
= presets
[0].frequency
;
1415 radio_mode
= RADIO_PRESET_MODE
;
1416 presets_loaded
= true;
1421 /* Wrap it to beginning or we'll be past end of band */
1422 presets_loaded
= false;
1430 #ifdef HAVE_RECORDING
1432 #if defined(HAVE_FMRADIO_IN) && CONFIG_CODEC == SWCODEC
1433 #define FM_RECORDING_SCREEN
1434 static int fm_recording_screen(void)
1438 /* switch recording source to FMRADIO for the duration */
1439 int rec_source
= global_settings
.rec_source
;
1440 global_settings
.rec_source
= AUDIO_SRC_FMRADIO
;
1442 /* clearing queue seems to cure a spontaneous abort during record */
1443 action_signalscreenchange();
1445 ret
= recording_screen(true);
1447 /* safe to reset as changing sources is prohibited here */
1448 global_settings
.rec_source
= rec_source
;
1453 #endif /* defined(HAVE_FMRADIO_IN) && CONFIG_CODEC == SWCODEC */
1455 #if defined(HAVE_FMRADIO_IN) || CONFIG_CODEC != SWCODEC
1456 #define FM_RECORDING_SETTINGS
1457 static int fm_recording_settings(void)
1459 bool ret
= recording_menu(true);
1461 #if CONFIG_CODEC != SWCODEC
1464 struct audio_recording_options rec_options
;
1465 rec_init_recording_options(&rec_options
);
1466 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
1467 rec_set_recording_options(&rec_options
);
1474 #endif /* defined(HAVE_FMRADIO_IN) || CONFIG_CODEC != SWCODEC */
1475 #endif /* HAVE_RECORDING */
1477 #ifdef FM_RECORDING_SCREEN
1478 MENUITEM_FUNCTION(recscreen_item
, 0, ID2P(LANG_RECORDING_MENU
),
1479 fm_recording_screen
, NULL
, NULL
, Icon_NOICON
);
1481 #ifdef FM_RECORDING_SETTINGS
1482 MENUITEM_FUNCTION(recsettings_item
, 0, ID2P(LANG_RECORDING_SETTINGS
),
1483 fm_recording_settings
, NULL
, NULL
, Icon_NOICON
);
1486 MENUITEM_FUNCTION(radio_presets_item
, 0, ID2P(LANG_FM_BUTTONBAR_PRESETS
),
1487 handle_radio_presets
, NULL
, NULL
, Icon_NOICON
);
1489 #ifndef FM_PRESET_ADD
1490 MENUITEM_FUNCTION(radio_addpreset_item
, 0, ID2P(LANG_FM_ADD_PRESET
),
1491 radio_add_preset
, NULL
, NULL
, Icon_NOICON
);
1495 MENUITEM_FUNCTION(presetload_item
, 0, ID2P(LANG_FM_PRESET_LOAD
),
1496 load_preset_list
, NULL
, NULL
, Icon_NOICON
);
1497 MENUITEM_FUNCTION(presetsave_item
, 0, ID2P(LANG_FM_PRESET_SAVE
),
1498 save_preset_list
, NULL
, NULL
, Icon_NOICON
);
1499 MENUITEM_FUNCTION(presetclear_item
, 0, ID2P(LANG_FM_PRESET_CLEAR
),
1500 clear_preset_list
, NULL
, NULL
, Icon_NOICON
);
1501 MENUITEM_FUNCTION(scan_presets_item
, 0, ID2P(LANG_FM_SCAN_PRESETS
),
1502 scan_presets
, NULL
, NULL
, Icon_NOICON
);
1504 MAKE_MENU(radio_menu_items
, ID2P(LANG_FM_MENU
), NULL
,
1507 &radio_presets_item
,
1509 #ifndef FM_PRESET_ADD
1510 &radio_addpreset_item
,
1512 &presetload_item
, &presetsave_item
, &presetclear_item
,
1517 &set_region
, &sound_settings
,
1518 #ifdef FM_RECORDING_SCREEN
1521 #ifdef FM_RECORDING_SETTINGS
1524 &scan_presets_item
);
1525 /* main menu of the radio screen */
1526 static bool radio_menu(void)
1528 return do_menu(&radio_menu_items
, NULL
) == MENU_ATTACHED_USB
;