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
93 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
102 #define RADIO_SCAN_MODE 0
103 #define RADIO_PRESET_MODE 1
105 static int curr_preset
= -1;
106 static int curr_freq
;
107 static int radio_mode
= RADIO_SCAN_MODE
;
108 static int search_dir
= 0;
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 /* TODO: Move some more of the control functionality to an HAL and clean up the
163 /* secret flag for starting paused - prevents unmute */
164 #define FMRADIO_START_PAUSED 0x8000
165 void radio_start(void)
167 const struct fm_region_data
*fmr
;
170 if(radio_status
== FMRADIO_PLAYING
)
173 fmr
= &fm_region_data
[global_settings
.fm_region
];
175 start_paused
= radio_status
& FMRADIO_START_PAUSED
;
176 /* clear flag before any yielding */
177 radio_status
&= ~FMRADIO_START_PAUSED
;
179 if(radio_status
== FMRADIO_OFF
)
182 curr_freq
= global_status
.last_frequency
183 * fmr
->freq_step
+ fmr
->freq_min
;
185 tuner_set(RADIO_SLEEP
, 0); /* wake up the tuner */
187 if(radio_status
== FMRADIO_OFF
)
189 #ifdef HAVE_RADIO_REGION
190 tuner_set(RADIO_REGION
, global_settings
.fm_region
);
192 tuner_set(RADIO_FORCE_MONO
, global_settings
.fm_force_mono
);
195 tuner_set(RADIO_FREQUENCY
, curr_freq
);
197 #ifdef HAVE_RADIO_MUTE_TIMEOUT
199 unsigned long mute_timeout
= current_tick
+ HZ
;
200 if (radio_status
!= FMRADIO_OFF
)
206 while(!tuner_get(RADIO_STEREO
) && !tuner_get(RADIO_TUNED
))
208 if(TIME_AFTER(current_tick
, mute_timeout
))
215 /* keep radio from sounding initially */
217 tuner_set(RADIO_MUTE
, 0);
219 radio_status
= FMRADIO_PLAYING
;
222 void radio_pause(void)
224 if(radio_status
== FMRADIO_PAUSED
)
227 if(radio_status
== FMRADIO_OFF
)
229 radio_status
|= FMRADIO_START_PAUSED
;
233 tuner_set(RADIO_MUTE
, 1);
234 tuner_set(RADIO_SLEEP
, 1);
236 radio_status
= FMRADIO_PAUSED
;
239 void radio_stop(void)
241 if(radio_status
== FMRADIO_OFF
)
244 tuner_set(RADIO_MUTE
, 1);
245 tuner_set(RADIO_SLEEP
, 1); /* low power mode, if available */
246 radio_status
= FMRADIO_OFF
;
247 tuner_power(false); /* status update, power off if avail. */
250 bool radio_hardware_present(void)
252 return tuner_get(RADIO_PRESENT
);
255 /* Keep freq on the grid for the current region */
256 static int snap_freq_to_grid(int freq
)
258 const struct fm_region_data
* const fmr
=
259 &fm_region_data
[global_settings
.fm_region
];
261 /* Range clamp if out of range or just round to nearest */
262 if (freq
< fmr
->freq_min
)
263 freq
= fmr
->freq_min
;
264 else if (freq
> fmr
->freq_max
)
265 freq
= fmr
->freq_max
;
267 freq
= (freq
- fmr
->freq_min
+ fmr
->freq_step
/2) /
268 fmr
->freq_step
* fmr
->freq_step
+ fmr
->freq_min
;
273 /* Find a matching preset to freq */
274 static int find_preset(int freq
)
279 for(i
= 0;i
< MAX_PRESETS
;i
++)
281 if(freq
== presets
[i
].frequency
)
288 /* Return the first preset encountered in the search direction with
290 static int find_closest_preset(int freq
, int direction
)
294 if (direction
== 0) /* direction == 0 isn't really used */
297 for (i
= 0; i
< MAX_PRESETS
; i
++)
299 int preset_frequency
= presets
[i
].frequency
;
301 if (preset_frequency
== freq
)
302 return i
; /* Exact match = stop */
303 /* Stop when the preset frequency exeeds freq so that we can
304 pick the correct one based on direction */
305 if (preset_frequency
> freq
)
309 /* wrap around depending on direction */
310 if (i
== 0 || i
>= num_presets
- 1)
311 i
= direction
< 0 ? num_presets
- 1 : 0;
312 else if (direction
< 0)
313 i
--; /* use previous */
318 static void remember_frequency(void)
320 const struct fm_region_data
* const fmr
=
321 &fm_region_data
[global_settings
.fm_region
];
322 global_status
.last_frequency
= (curr_freq
- fmr
->freq_min
)
327 static void next_preset(int direction
)
332 if (curr_preset
== -1)
333 curr_preset
= find_closest_preset(curr_freq
, direction
);
335 curr_preset
= (curr_preset
+ direction
+ num_presets
) % num_presets
;
337 /* Must stay on the current grid for the region */
338 curr_freq
= snap_freq_to_grid(presets
[curr_preset
].frequency
);
340 tuner_set(RADIO_FREQUENCY
, curr_freq
);
341 remember_frequency();
344 /* Step to the next or previous frequency */
345 static int step_freq(int freq
, int direction
)
347 const struct fm_region_data
* const fmr
=
348 &fm_region_data
[global_settings
.fm_region
];
350 freq
+= direction
*fmr
->freq_step
;
352 /* Wrap first or snapping to grid will not let us on the band extremes */
353 if (freq
> fmr
->freq_max
)
354 freq
= direction
> 0 ? fmr
->freq_min
: fmr
->freq_max
;
355 else if (freq
< fmr
->freq_min
)
356 freq
= direction
< 0 ? fmr
->freq_max
: fmr
->freq_min
;
358 freq
= snap_freq_to_grid(freq
);
363 /* Step to the next or previous station */
364 static void next_station(int direction
)
366 if (direction
!= 0 && radio_mode
!= RADIO_SCAN_MODE
)
368 next_preset(direction
);
372 curr_freq
= step_freq(curr_freq
, direction
);
374 if (radio_status
== FMRADIO_PLAYING
)
375 tuner_set(RADIO_MUTE
, 1);
377 tuner_set(RADIO_FREQUENCY
, curr_freq
);
379 if (radio_status
== FMRADIO_PLAYING
)
380 tuner_set(RADIO_MUTE
, 0);
382 curr_preset
= find_preset(curr_freq
);
383 remember_frequency();
386 /* Ends an in-progress search */
387 static void end_search(void)
389 if (search_dir
!= 0 && radio_status
== FMRADIO_PLAYING
)
390 tuner_set(RADIO_MUTE
, 0);
394 int radio_screen(void)
398 int ret_val
= GO_TO_ROOT
;
401 bool stereo
= false, last_stereo
= false;
403 int top_of_screen
= 0;
404 bool update_screen
= true;
405 bool screen_freeze
= false;
406 bool keep_playing
= false;
407 bool statusbar
= global_settings
.statusbar
;
408 #ifdef FM_RECORD_DBLPRE
409 int lastbutton
= BUTTON_NONE
;
410 unsigned long rec_lastclick
= 0;
412 #if CONFIG_CODEC != SWCODEC
413 bool have_recorded
= false;
414 int timeout
= current_tick
+ HZ
/10;
415 unsigned int seconds
= 0;
416 unsigned int last_seconds
= 0;
418 struct audio_recording_options rec_options
;
419 #endif /* CONFIG_CODEC != SWCODEC */
420 #ifndef HAVE_NOISY_IDLE_MODE
421 int button_timeout
= current_tick
+ (2*HZ
);
424 struct gui_buttonbar buttonbar
;
425 gui_buttonbar_init(&buttonbar
);
426 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
429 /* change status to "in screen" */
432 /* always display status bar in radio screen for now */
433 global_settings
.statusbar
= true;
436 gui_textarea_clear(&screens
[i
]);
437 screen_set_xmargin(&screens
[i
],0);
440 gui_syncstatusbar_draw(&statusbars
,true);
442 fh
= font_get(FONT_UI
)->height
;
444 /* Adjust for font size, trying to center the information vertically */
450 memset(presets
, 0, sizeof(presets
));
451 radio_load_presets(global_settings
.fmr_file
);
454 if(radio_status
== FMRADIO_OFF
)
458 #if CONFIG_CODEC != SWCODEC
459 if(rec_create_directory() > 0)
460 have_recorded
= true;
462 audio_init_recording(talk_get_bufsize());
464 sound_settings_apply();
465 /* Yes, we use the D/A for monitoring */
466 peak_meter_playback(true);
468 peak_meter_enabled
= true;
470 rec_init_recording_options(&rec_options
);
471 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
472 rec_set_recording_options(&rec_options
);
474 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
475 sound_default(SOUND_RIGHT_GAIN
), AUDIO_GAIN_LINEIN
);
477 #endif /* CONFIG_CODEC != SWCODEC */
478 #endif /* ndef SIMULATOR */
481 #if CONFIG_CODEC == SWCODEC
482 audio_set_input_source(AUDIO_SRC_FMRADIO
,
483 (radio_status
== FMRADIO_PAUSED
) ?
484 SRCF_FMRADIO_PAUSED
: SRCF_FMRADIO_PLAYING
);
486 if (radio_status
== FMRADIO_OFF
)
490 if(num_presets
< 1 && yesno_pop(str(LANG_FM_FIRST_AUTOSCAN
)))
493 curr_preset
= find_preset(curr_freq
);
494 if(curr_preset
!= -1)
495 radio_mode
= RADIO_PRESET_MODE
;
498 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
499 str(LANG_FM_BUTTONBAR_PRESETS
), str(LANG_FM_BUTTONBAR_RECORD
));
502 #ifndef HAVE_NOISY_IDLE_MODE
510 curr_freq
= step_freq(curr_freq
, search_dir
);
511 update_screen
= true;
513 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
515 curr_preset
= find_preset(curr_freq
);
516 remember_frequency();
523 #if CONFIG_CODEC != SWCODEC
524 /* TODO: Can we timeout at HZ when recording since peaks aren't
525 displayed? This should quiet recordings too. */
526 button
= get_action(CONTEXT_FM
,
527 update_screen
? TIMEOUT_NOBLOCK
: HZ
/ PEAK_METER_FPS
);
529 button
= get_action(CONTEXT_FM
,
530 update_screen
? TIMEOUT_NOBLOCK
: HZ
);
533 #ifndef HAVE_NOISY_IDLE_MODE
534 if (button
!= ACTION_NONE
)
536 cpu_idle_mode(false);
537 button_timeout
= current_tick
+ (2*HZ
);
543 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
544 if(audio_status() == AUDIO_STATUS_RECORD
)
554 if(yesno_pop(str(LANG_FM_SAVE_CHANGES
)))
556 if(filepreset
[0] == '\0')
559 radio_save_presets();
562 /* Clear the preset list on exit. */
565 update_screen
= true;
569 case ACTION_FM_RECORD
:
570 #ifdef FM_RECORD_DBLPRE
571 if (lastbutton
!= ACTION_FM_RECORD_DBLPRE
)
576 if (current_tick
- rec_lastclick
> HZ
/2)
578 rec_lastclick
= current_tick
;
581 #endif /* FM_RECORD_DBLPRE */
583 if(audio_status() == AUDIO_STATUS_RECORD
)
586 update_screen
= true;
590 have_recorded
= true;
592 update_screen
= true;
594 #endif /* SIMULATOR */
597 #endif /* #ifdef FM_RECORD */
600 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
601 if(audio_status() == AUDIO_STATUS_RECORD
)
606 ret_val
= GO_TO_ROOT
;
609 if(yesno_pop(str(LANG_FM_SAVE_CHANGES
)))
611 if(filepreset
[0] == '\0')
614 radio_save_presets();
618 /* Clear the preset list on exit. */
623 case ACTION_STD_PREV
:
624 case ACTION_STD_NEXT
:
625 next_station(button
== ACTION_STD_PREV
? -1 : 1);
627 update_screen
= true;
630 case ACTION_STD_PREVREPEAT
:
631 case ACTION_STD_NEXTREPEAT
:
633 int dir
= search_dir
;
634 search_dir
= button
== ACTION_STD_PREVREPEAT
? -1 : 1;
635 if (radio_mode
!= RADIO_SCAN_MODE
)
637 next_preset(search_dir
);
639 update_screen
= true;
643 /* Starting auto scan */
644 tuner_set(RADIO_MUTE
, 1);
645 update_screen
= true;
650 case ACTION_SETTINGS_INC
:
651 case ACTION_SETTINGS_INCREPEAT
:
652 global_settings
.volume
++;
654 update_screen
= true;
657 case ACTION_SETTINGS_DEC
:
658 case ACTION_SETTINGS_DECREPEAT
:
659 global_settings
.volume
--;
661 update_screen
= true;
665 if (radio_status
== FMRADIO_PLAYING
)
670 update_screen
= true;
675 curr_preset
= find_preset(curr_freq
);
677 struct screen
*sc
= &screens
[i
];
678 gui_textarea_clear(sc
);
679 screen_set_xmargin(sc
, 0);
682 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
683 str(LANG_FM_BUTTONBAR_PRESETS
),
684 str(LANG_FM_BUTTONBAR_RECORD
));
686 update_screen
= true;
690 case ACTION_FM_PRESET
:
693 gui_syncsplash(HZ
, str(LANG_FM_NO_PRESETS
));
694 update_screen
= true;
697 struct screen
*sc
= &screens
[i
];
698 gui_textarea_clear(sc
);
699 screen_set_xmargin(sc
, 0);
700 gui_textarea_update(sc
);
705 handle_radio_presets();
708 struct screen
*sc
= &screens
[i
];
709 gui_textarea_clear(sc
);
710 screen_set_xmargin(sc
, 0);
711 gui_textarea_update(sc
);
714 gui_buttonbar_set(&buttonbar
,
715 str(LANG_BUTTONBAR_MENU
),
716 str(LANG_FM_BUTTONBAR_PRESETS
),
717 str(LANG_FM_BUTTONBAR_RECORD
));
719 update_screen
= true;
721 #endif /* FM_PRESET */
724 case ACTION_FM_FREEZE
:
727 gui_syncsplash(HZ
, str(LANG_FM_FREEZE
));
728 screen_freeze
= true;
732 update_screen
= true;
733 screen_freeze
= false;
736 #endif /* FM_FREEZE */
738 case SYS_USB_CONNECTED
:
739 #if CONFIG_CODEC != SWCODEC
740 /* Only accept USB connection when not recording */
741 if(audio_status() != AUDIO_STATUS_RECORD
)
744 default_event_handler(SYS_USB_CONNECTED
);
745 screen_freeze
= true; /* Cosmetic: makes sure the
746 radio screen doesn't redraw */
753 if(radio_mode
== RADIO_SCAN_MODE
)
755 /* Force scan mode if there are no presets. */
757 radio_mode
= RADIO_PRESET_MODE
;
760 radio_mode
= RADIO_SCAN_MODE
;
761 update_screen
= true;
765 #ifdef FM_NEXT_PRESET
766 case ACTION_FM_NEXT_PRESET
:
769 update_screen
= true;
773 #ifdef FM_PREV_PRESET
774 case ACTION_FM_PREV_PRESET
:
777 update_screen
= true;
782 default_event_handler(button
);
786 #ifdef FM_RECORD_DBLPRE
787 if (button
!= ACTION_NONE
)
791 #if CONFIG_CODEC != SWCODEC
797 /* Only display the peak meter when not recording */
798 #if CONFIG_CODEC != SWCODEC
803 peak_meter_screen(&screens
[i
],0,
804 STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4), fh
);
805 screens
[i
].update_rect(0, STATUSBAR_HEIGHT
+ fh
*(top_of_screen
+ 4),
806 screens
[i
].width
, fh
);
810 if(TIME_AFTER(current_tick
, timeout
))
812 timeout
= current_tick
+ HZ
;
815 #endif /* CONFIG_CODEC == SWCODEC */
817 /* keep "mono" from always being displayed when paused */
818 if (radio_status
!= FMRADIO_PAUSED
)
820 stereo
= tuner_get(RADIO_STEREO
) &&
821 !global_settings
.fm_force_mono
;
823 if(stereo
!= last_stereo
)
825 update_screen
= true;
826 last_stereo
= stereo
;
831 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
832 seconds
= audio_recorded_time() / HZ
;
833 if (update_screen
|| seconds
> last_seconds
)
835 last_seconds
= seconds
;
843 screens
[i
].setfont(FONT_UI
);
845 snprintf(buf
, 128, curr_preset
>= 0 ? "%d. %s" : " ",
846 curr_preset
+ 1, presets
[curr_preset
].name
);
849 screens
[i
].puts_scroll(0, top_of_screen
, buf
);
851 freq
= curr_freq
/ 10000;
852 snprintf(buf
, 128, str(LANG_FM_STATION
), freq
/ 100, freq
% 100);
854 screens
[i
].puts_scroll(0, top_of_screen
+ 1, buf
);
856 snprintf(buf
, 128, stereo
?str(LANG_CHANNEL_STEREO
):
857 str(LANG_CHANNEL_MONO
));
859 screens
[i
].puts_scroll(0, top_of_screen
+ 2, buf
);
861 snprintf(buf
, 128, "%s %s", str(LANG_FM_TUNE_MODE
),
862 radio_mode
? str(LANG_RADIO_PRESET_MODE
) :
863 str(LANG_RADIO_SCAN_MODE
));
865 screens
[i
].puts_scroll(0, top_of_screen
+ 3, buf
);
867 #if CONFIG_CODEC != SWCODEC
868 if(audio_status() == AUDIO_STATUS_RECORD
)
870 hours
= seconds
/ 3600;
871 minutes
= (seconds
- (hours
* 3600)) / 60;
872 snprintf(buf
, 32, "%s %02d:%02d:%02d",
873 str(LANG_RECORDING_TIME
),
874 hours
, minutes
, seconds
%60);
876 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
880 if(rec_options
.rec_prerecord_time
)
882 snprintf(buf
, 32, "%s %02d",
883 str(LANG_RECORD_PRERECORD
), seconds
%60);
885 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
888 #endif /* CONFIG_CODEC != SWCODEC */
891 gui_buttonbar_draw(&buttonbar
);
894 gui_textarea_update(&screens
[i
]);
896 /* Only force the redraw if update_screen is true */
897 gui_syncstatusbar_draw(&statusbars
,true);
900 update_screen
= false;
902 #if CONFIG_CODEC != SWCODEC
903 if(audio_status() & AUDIO_STATUS_ERROR
)
909 #ifndef HAVE_NOISY_IDLE_MODE
910 if (TIME_AFTER(current_tick
, button_timeout
))
918 #if CONFIG_CODEC != SWCODEC
919 if(audio_status() & AUDIO_STATUS_ERROR
)
921 gui_syncsplash(0, str(LANG_DISK_FULL
));
922 gui_syncstatusbar_draw(&statusbars
,true);
924 gui_textarea_update(&screens
[i
]);
929 button
= get_action(CONTEXT_FM
, TIMEOUT_BLOCK
);
930 if(button
== ACTION_FM_STOP
)
935 audio_init_playback();
936 #endif /* CONFIG_CODEC != SWCODEC */
938 sound_settings_apply();
939 #endif /* SIMULATOR */
943 /* Catch FMRADIO_PLAYING status for the sim. */
945 #if CONFIG_CODEC != SWCODEC
946 /* Enable the Left and right A/D Converter */
947 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
948 sound_default(SOUND_RIGHT_GAIN
),
950 mas_codec_writereg(6, 0x4000);
953 #endif /* SIMULATOR */
957 #if CONFIG_CODEC == SWCODEC
958 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
964 #ifndef HAVE_NOISY_IDLE_MODE
965 cpu_idle_mode(false);
968 /* restore status bar settings */
969 global_settings
.statusbar
= statusbar
;
972 #if CONFIG_CODEC != SWCODEC
973 return have_recorded
;
979 static void radio_save_presets(void)
984 fd
= creat(filepreset
);
987 for(i
= 0;i
< num_presets
;i
++)
989 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
993 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
994 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
995 presets_changed
= false;
999 gui_syncsplash(HZ
, str(LANG_FM_PRESET_SAVE_FAILED
));
1003 void radio_load_presets(char *filename
)
1013 memset(presets
, 0, sizeof(presets
));
1016 /* No Preset in configuration. */
1017 if(filename
[0] == '\0')
1019 filepreset
[0] = '\0';
1022 /* Temporary preset, loaded until player shuts down. */
1023 else if(filename
[0] == '/')
1024 strncpy(filepreset
, filename
, sizeof(filepreset
));
1025 /* Preset from default directory. */
1027 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
1028 FMPRESET_PATH
, filename
);
1030 fd
= open(filepreset
, O_RDONLY
);
1033 while(!done
&& num_presets
< MAX_PRESETS
)
1035 rc
= read_line(fd
, buf
, 128);
1038 if(settings_parseline(buf
, &freq
, &name
))
1041 if(f
) /* For backwards compatibility */
1043 struct fmstation
* const fms
= &presets
[num_presets
];
1045 strncpy(fms
->name
, name
, MAX_FMPRESET_LEN
);
1046 fms
->name
[MAX_FMPRESET_LEN
] = '\0';
1056 else /* invalid file name? */
1057 filepreset
[0] = '\0';
1059 presets_loaded
= num_presets
> 0;
1060 presets_changed
= false;
1064 static int radio_add_preset(void)
1066 char buf
[MAX_FMPRESET_LEN
+ 1];
1068 if(num_presets
< MAX_PRESETS
)
1070 memset(buf
, 0, MAX_FMPRESET_LEN
);
1072 if (!kbd_input(buf
, MAX_FMPRESET_LEN
))
1074 struct fmstation
* const fms
= &presets
[num_presets
];
1075 buf
[MAX_FMPRESET_LEN
] = '\0';
1076 strcpy(fms
->name
, buf
);
1077 fms
->frequency
= curr_freq
;
1079 presets_changed
= true;
1080 presets_loaded
= num_presets
> 0;
1085 gui_syncsplash(HZ
, str(LANG_FM_NO_FREE_PRESETS
));
1090 /* needed to know which preset we are edit/delete-ing */
1091 static int selected_preset
= -1;
1092 static int radio_edit_preset(void)
1094 char buf
[MAX_FMPRESET_LEN
+ 1];
1096 if (num_presets
> 0)
1098 struct fmstation
* const fms
= &presets
[selected_preset
];
1100 strncpy(buf
, fms
->name
, MAX_FMPRESET_LEN
);
1102 if (!kbd_input(buf
, MAX_FMPRESET_LEN
))
1104 buf
[MAX_FMPRESET_LEN
] = '\0';
1105 strcpy(fms
->name
, buf
);
1106 presets_changed
= true;
1113 static int radio_delete_preset(void)
1115 if (num_presets
> 0)
1117 struct fmstation
* const fms
= &presets
[selected_preset
];
1119 if (selected_preset
>= --num_presets
)
1120 selected_preset
= num_presets
- 1;
1122 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
1127 /* Don't ask to save when all presets are deleted. */
1128 presets_changed
= num_presets
> 0;
1130 if (!presets_changed
)
1132 /* The preset list will be cleared, switch to Scan Mode. */
1133 radio_mode
= RADIO_SCAN_MODE
;
1134 presets_loaded
= false;
1140 static int load_preset_list(void)
1142 return !rockbox_browse(FMPRESET_PATH
, SHOW_FMR
);
1145 static int save_preset_list(void)
1149 bool bad_file_name
= true;
1151 if(!opendir(FMPRESET_PATH
)) /* Check if there is preset folder */
1152 mkdir(FMPRESET_PATH
);
1154 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
1155 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
1157 while(bad_file_name
)
1159 if(!kbd_input(filepreset
, sizeof(filepreset
)))
1161 /* check the name: max MAX_FILENAME (20) chars */
1165 p1
= strrchr(filepreset
, '/');
1167 while((p1
) && (*p2
) && (*p2
!= '.'))
1169 len
= (int)(p2
-p1
) - 1;
1170 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
1172 /* no slash, too long or too short */
1173 gui_syncsplash(HZ
, str(LANG_INVALID_FILENAME
));
1177 /* add correct extension (easier to always write)
1178 at this point, p2 points to 0 or the extension dot */
1180 strcat(filepreset
,".fmr");
1181 bad_file_name
= false;
1182 radio_save_presets();
1193 gui_syncsplash(HZ
, str(LANG_FM_NO_PRESETS
));
1198 static int clear_preset_list(void)
1200 /* Clear all the preset entries */
1201 memset(presets
, 0, sizeof (presets
));
1204 presets_loaded
= false;
1205 /* The preset list will be cleared switch to Scan Mode. */
1206 radio_mode
= RADIO_SCAN_MODE
;
1208 presets_changed
= false; /* Don't ask to save when clearing the list. */
1213 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1214 ID2P(LANG_FM_EDIT_PRESET
),
1215 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
1216 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1217 ID2P(LANG_FM_DELETE_PRESET
),
1218 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
1219 int radio_preset_callback(int action
, const struct menu_item_ex
*this_item
)
1221 if (action
== ACTION_STD_OK
)
1222 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
1226 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_FM_BUTTONBAR_PRESETS
),
1227 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
1228 &radio_delete_preset_item
);
1229 /* present a list of preset stations */
1230 char * presets_get_name(int selected_item
, void * data
, char *buffer
)
1234 return presets
[selected_item
].name
;
1237 static int handle_radio_presets(void)
1239 struct gui_synclist lists
;
1241 int action
= ACTION_NONE
;
1242 #ifdef HAS_BUTTONBAR
1243 struct gui_buttonbar buttonbar
;
1246 if(presets_loaded
== false)
1249 #ifdef HAS_BUTTONBAR
1250 gui_buttonbar_init(&buttonbar
);
1251 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
1252 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
1253 str(LANG_FM_BUTTONBAR_EXIT
),
1254 str(LANG_FM_BUTTONBAR_ACTION
));
1255 gui_buttonbar_draw(&buttonbar
);
1257 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1);
1258 gui_synclist_set_title(&lists
, str(LANG_FM_BUTTONBAR_PRESETS
), NOICON
);
1259 gui_synclist_set_icon_callback(&lists
, NULL
);
1260 gui_synclist_set_nb_items(&lists
, num_presets
);
1261 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
1265 gui_synclist_draw(&lists
);
1266 gui_syncstatusbar_draw(&statusbars
, true);
1267 action
= get_action(CONTEXT_STD
, HZ
);
1269 gui_synclist_do_button(&lists
, action
, LIST_WRAP_UNLESS_HELD
);
1272 case ACTION_STD_MENU
:
1275 case ACTION_STD_CANCEL
:
1279 curr_preset
= gui_synclist_get_sel_pos(&lists
);
1280 curr_freq
= presets
[curr_preset
].frequency
;
1282 remember_frequency();
1286 case ACTION_STD_CONTEXT
:
1287 selected_preset
= gui_synclist_get_sel_pos(&lists
);
1288 do_menu(&handle_radio_preset_menu
, NULL
);
1291 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
1298 void toggle_mono_mode(bool mono
)
1300 tuner_set(RADIO_FORCE_MONO
, mono
);
1303 void set_radio_region(int region
)
1305 #ifdef HAVE_RADIO_REGION
1306 tuner_set(RADIO_REGION
, region
);
1309 remember_frequency();
1313 MENUITEM_SETTING(set_region
, &global_settings
.fm_region
, NULL
);
1314 MENUITEM_SETTING(force_mono
, &global_settings
.fm_force_mono
, NULL
);
1317 char* get_mode_text(int selected_item
, void * data
, char *buffer
)
1319 (void)selected_item
;
1321 snprintf(buffer
, MAX_PATH
, "%s %s", str(LANG_FM_TUNE_MODE
),
1322 radio_mode
? str(LANG_RADIO_PRESET_MODE
) :
1323 str(LANG_RADIO_SCAN_MODE
));
1326 static int toggle_radio_mode(void)
1328 radio_mode
= (radio_mode
== RADIO_SCAN_MODE
) ?
1329 RADIO_PRESET_MODE
: RADIO_SCAN_MODE
;
1332 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item
, 0,
1333 toggle_radio_mode
, NULL
,
1334 get_mode_text
, NULL
, NULL
, Icon_NOICON
);
1337 static int scan_presets(void)
1339 bool do_scan
= true;
1341 if(num_presets
> 0) /* Do that to avoid 2 questions. */
1342 do_scan
= yesno_pop(str(LANG_FM_CLEAR_PRESETS
));
1346 const struct fm_region_data
* const fmr
=
1347 &fm_region_data
[global_settings
.fm_region
];
1349 char buf
[MAX_FMPRESET_LEN
+ 1];
1352 curr_freq
= fmr
->freq_min
;
1354 memset(presets
, 0, sizeof(presets
));
1355 tuner_set(RADIO_MUTE
, 1);
1357 while(curr_freq
<= fmr
->freq_max
)
1360 if (num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
1363 freq
= curr_freq
/ 10000;
1367 snprintf(buf
, MAX_FMPRESET_LEN
, str(LANG_FM_SCANNING
), freq
, frac
);
1368 gui_syncsplash(0, buf
);
1370 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
1373 snprintf(buf
, MAX_FMPRESET_LEN
,
1374 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
1375 strcpy(presets
[num_presets
].name
,buf
);
1376 presets
[num_presets
].frequency
= curr_freq
;
1380 curr_freq
+= fmr
->freq_step
;
1383 if (radio_status
== FMRADIO_PLAYING
)
1384 tuner_set(RADIO_MUTE
, 0);
1386 presets_changed
= true;
1390 gui_textarea_clear(&screens
[i
]);
1391 screen_set_xmargin(&screens
[i
],0);
1392 gui_textarea_update(&screens
[i
]);
1397 curr_freq
= presets
[0].frequency
;
1398 radio_mode
= RADIO_PRESET_MODE
;
1399 presets_loaded
= true;
1404 /* Wrap it to beginning or we'll be past end of band */
1405 presets_loaded
= false;
1413 #ifdef HAVE_RECORDING
1415 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1416 #define FM_RECORDING_SCREEN
1417 static int fm_recording_screen(void)
1421 /* switch recording source to FMRADIO for the duration */
1422 int rec_source
= global_settings
.rec_source
;
1423 global_settings
.rec_source
= AUDIO_SRC_FMRADIO
;
1425 ret
= recording_screen(true);
1427 /* safe to reset as changing sources is prohibited here */
1428 global_settings
.rec_source
= rec_source
;
1433 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1435 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1436 #define FM_RECORDING_SETTINGS
1437 static int fm_recording_settings(void)
1439 bool ret
= recording_menu(true);
1441 #if CONFIG_CODEC != SWCODEC
1444 struct audio_recording_options rec_options
;
1445 rec_init_recording_options(&rec_options
);
1446 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
1447 rec_set_recording_options(&rec_options
);
1454 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1455 #endif /* HAVE_RECORDING */
1457 #ifdef FM_RECORDING_SCREEN
1458 MENUITEM_FUNCTION(recscreen_item
, 0, ID2P(LANG_RECORDING_MENU
),
1459 fm_recording_screen
, NULL
, NULL
, Icon_Recording
);
1461 #ifdef FM_RECORDING_SETTINGS
1462 MENUITEM_FUNCTION(recsettings_item
, 0, ID2P(LANG_RECORDING_SETTINGS
),
1463 fm_recording_settings
, NULL
, NULL
, Icon_Recording
);
1466 MENUITEM_FUNCTION(radio_presets_item
, 0, ID2P(LANG_FM_BUTTONBAR_PRESETS
),
1467 handle_radio_presets
, NULL
, NULL
, Icon_NOICON
);
1469 #ifndef FM_PRESET_ADD
1470 MENUITEM_FUNCTION(radio_addpreset_item
, 0, ID2P(LANG_FM_ADD_PRESET
),
1471 radio_add_preset
, NULL
, NULL
, Icon_NOICON
);
1475 MENUITEM_FUNCTION(presetload_item
, 0, ID2P(LANG_FM_PRESET_LOAD
),
1476 load_preset_list
, NULL
, NULL
, Icon_NOICON
);
1477 MENUITEM_FUNCTION(presetsave_item
, 0, ID2P(LANG_FM_PRESET_SAVE
),
1478 save_preset_list
, NULL
, NULL
, Icon_NOICON
);
1479 MENUITEM_FUNCTION(presetclear_item
, 0, ID2P(LANG_FM_PRESET_CLEAR
),
1480 clear_preset_list
, NULL
, NULL
, Icon_NOICON
);
1481 MENUITEM_FUNCTION(scan_presets_item
, 0, ID2P(LANG_FM_SCAN_PRESETS
),
1482 scan_presets
, NULL
, NULL
, Icon_NOICON
);
1484 MAKE_MENU(radio_settings_menu
, ID2P(LANG_FM_MENU
), NULL
,
1487 &radio_presets_item
,
1489 #ifndef FM_PRESET_ADD
1490 &radio_addpreset_item
,
1492 &presetload_item
, &presetsave_item
, &presetclear_item
,
1497 &set_region
, &sound_settings
,
1498 #ifdef FM_RECORDING_SCREEN
1501 #ifdef FM_RECORDING_SETTINGS
1504 &scan_presets_item
);
1505 /* main menu of the radio screen */
1506 static bool radio_menu(void)
1508 return do_menu(&radio_settings_menu
, NULL
) == MENU_ATTACHED_USB
;