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 ****************************************************************************/
32 #include "mp3_playback.h"
37 #include "string-extra.h"
44 #include "peakmeter.h"
47 #include "sound_menu.h"
49 #include "recording.h"
51 #ifdef IPOD_ACCESSORY_PROTOCOL
58 #include "screen_access.h"
61 #include "buttonbar.h"
66 #include "menus/exported_menus.h"
67 #include "root_menu.h"
69 #ifdef HAVE_QUICKSCREEN
70 #include "quickscreen.h"
75 #if CONFIG_KEYPAD == RECORDER_PAD
78 #define FM_PRESET_ACTION
82 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
85 #define FM_NEXT_PRESET
86 #define FM_PREV_PRESET
88 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
92 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
95 /* This should be removeable if the whole tuning thing is sorted out since
96 proper tuning quiets the screen almost entirely in that extreme measures
97 have to be taken to hear any interference. */
98 #define HAVE_NOISY_IDLE_MODE
100 #elif CONFIG_KEYPAD == ONDIO_PAD
101 #define FM_RECORD_DBLPRE
103 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD) \
104 || (CONFIG_KEYPAD == SANSA_FUZE_PAD)
108 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
112 #elif (CONFIG_KEYPAD == COWON_D2_PAD)
115 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
116 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
121 #define RADIO_SCAN_MODE 0
122 #define RADIO_PRESET_MODE 1
124 static int curr_preset
= -1;
125 static int curr_freq
; /* current frequency in Hz */
126 static int radio_mode
= RADIO_SCAN_MODE
;
127 static int search_dir
= 0;
129 static int radio_status
= FMRADIO_OFF
;
130 static bool in_screen
= false;
132 #define MAX_PRESETS 64
133 static bool presets_loaded
= false, presets_changed
= false;
134 static struct fmstation presets
[MAX_PRESETS
];
136 static char filepreset
[MAX_PATH
]; /* preset filename variable */
138 static int num_presets
= 0; /* The number of presets in the preset list */
140 static void radio_save_presets(void);
141 static int handle_radio_presets(void);
142 static bool radio_menu(void);
143 static int radio_add_preset(void);
144 static int save_preset_list(void);
145 static int load_preset_list(void);
146 static int clear_preset_list(void);
148 static int scan_presets(void *viewports
);
149 static void radio_off(void);
151 /* Function to manipulate all yesno dialogues.
152 This function needs the output text as an argument. */
153 static bool yesno_pop(const char* text
)
156 const char *lines
[]={text
};
157 const struct text_message message
={lines
, 1};
158 bool ret
= (gui_syncyesno_run(&message
,NULL
,NULL
)== YESNO_YES
);
160 screens
[i
].clear_viewport();
164 void radio_init(void)
170 int get_radio_status(void)
175 bool in_radio_screen(void)
180 /* TODO: Move some more of the control functionality to firmware
181 and clean up the mess */
183 /* secret flag for starting paused - prevents unmute */
184 #define FMRADIO_START_PAUSED 0x8000
185 void radio_start(void)
187 const struct fm_region_data
*fmr
;
190 if(radio_status
== FMRADIO_PLAYING
)
193 fmr
= &fm_region_data
[global_settings
.fm_region
];
195 start_paused
= radio_status
& FMRADIO_START_PAUSED
;
196 /* clear flag before any yielding */
197 radio_status
&= ~FMRADIO_START_PAUSED
;
199 if(radio_status
== FMRADIO_OFF
)
202 curr_freq
= global_status
.last_frequency
* fmr
->freq_step
+ fmr
->freq_min
;
204 tuner_set(RADIO_SLEEP
, 0); /* wake up the tuner */
206 if(radio_status
== FMRADIO_OFF
)
208 #ifdef HAVE_RADIO_REGION
209 tuner_set(RADIO_REGION
, global_settings
.fm_region
);
211 tuner_set(RADIO_FORCE_MONO
, global_settings
.fm_force_mono
);
214 tuner_set(RADIO_FREQUENCY
, curr_freq
);
216 #ifdef HAVE_RADIO_MUTE_TIMEOUT
218 unsigned long mute_timeout
= current_tick
+ HZ
;
219 if (radio_status
!= FMRADIO_OFF
)
225 while(!tuner_get(RADIO_STEREO
) && !tuner_get(RADIO_TUNED
))
227 if(TIME_AFTER(current_tick
, mute_timeout
))
234 /* keep radio from sounding initially */
236 tuner_set(RADIO_MUTE
, 0);
238 radio_status
= FMRADIO_PLAYING
;
241 void radio_pause(void)
243 if(radio_status
== FMRADIO_PAUSED
)
246 if(radio_status
== FMRADIO_OFF
)
248 radio_status
|= FMRADIO_START_PAUSED
;
252 tuner_set(RADIO_MUTE
, 1);
253 tuner_set(RADIO_SLEEP
, 1);
255 radio_status
= FMRADIO_PAUSED
;
258 static void radio_off(void)
260 tuner_set(RADIO_MUTE
, 1);
261 tuner_set(RADIO_SLEEP
, 1); /* low power mode, if available */
262 radio_status
= FMRADIO_OFF
;
263 tuner_power(false); /* status update, power off if avail. */
266 void radio_stop(void)
268 if(radio_status
== FMRADIO_OFF
)
274 bool radio_hardware_present(void)
276 return tuner_get(RADIO_PRESENT
);
279 /* Keep freq on the grid for the current region */
280 static int snap_freq_to_grid(int freq
)
282 const struct fm_region_data
* const fmr
=
283 &fm_region_data
[global_settings
.fm_region
];
285 /* Range clamp if out of range or just round to nearest */
286 if (freq
< fmr
->freq_min
)
287 freq
= fmr
->freq_min
;
288 else if (freq
> fmr
->freq_max
)
289 freq
= fmr
->freq_max
;
291 freq
= (freq
- fmr
->freq_min
+ fmr
->freq_step
/2) /
292 fmr
->freq_step
* fmr
->freq_step
+ fmr
->freq_min
;
297 /* Find a matching preset to freq */
298 static int find_preset(int freq
)
303 for(i
= 0;i
< MAX_PRESETS
;i
++)
305 if(freq
== presets
[i
].frequency
)
312 /* Return the closest preset encountered in the search direction with
314 static int find_closest_preset(int freq
, int direction
)
321 if (direction
== 0) /* direction == 0 isn't really used */
324 for (i
= 0; i
< num_presets
; i
++)
326 int f
= presets
[i
].frequency
;
328 return i
; /* Exact match = stop */
330 /* remember the highest and lowest presets for wraparound */
331 if (f
< presets
[lowpreset
].frequency
)
333 if (f
> presets
[highpreset
].frequency
)
336 /* find the closest preset in the given direction */
337 if (direction
> 0 && f
> freq
)
339 if (closest
< 0 || f
< presets
[closest
].frequency
)
342 else if (direction
< 0 && f
< freq
)
344 if (closest
< 0 || f
> presets
[closest
].frequency
)
351 /* no presets in the given direction */
352 /* wrap around depending on direction */
354 closest
= highpreset
;
362 static void remember_frequency(void)
364 const struct fm_region_data
* const fmr
=
365 &fm_region_data
[global_settings
.fm_region
];
366 global_status
.last_frequency
= (curr_freq
- fmr
->freq_min
)
371 static void next_preset(int direction
)
376 if (curr_preset
== -1)
377 curr_preset
= find_closest_preset(curr_freq
, direction
);
379 curr_preset
= (curr_preset
+ direction
+ num_presets
) % num_presets
;
381 /* Must stay on the current grid for the region */
382 curr_freq
= snap_freq_to_grid(presets
[curr_preset
].frequency
);
384 tuner_set(RADIO_FREQUENCY
, curr_freq
);
385 remember_frequency();
388 /* Step to the next or previous frequency */
389 static int step_freq(int freq
, int direction
)
391 const struct fm_region_data
* const fmr
=
392 &fm_region_data
[global_settings
.fm_region
];
394 freq
+= direction
*fmr
->freq_step
;
396 /* Wrap first or snapping to grid will not let us on the band extremes */
397 if (freq
> fmr
->freq_max
)
398 freq
= direction
> 0 ? fmr
->freq_min
: fmr
->freq_max
;
399 else if (freq
< fmr
->freq_min
)
400 freq
= direction
< 0 ? fmr
->freq_max
: fmr
->freq_min
;
402 freq
= snap_freq_to_grid(freq
);
407 /* Step to the next or previous station */
408 static void next_station(int direction
)
410 if (direction
!= 0 && radio_mode
!= RADIO_SCAN_MODE
)
412 next_preset(direction
);
416 curr_freq
= step_freq(curr_freq
, direction
);
418 if (radio_status
== FMRADIO_PLAYING
)
419 tuner_set(RADIO_MUTE
, 1);
421 tuner_set(RADIO_FREQUENCY
, curr_freq
);
423 if (radio_status
== FMRADIO_PLAYING
)
424 tuner_set(RADIO_MUTE
, 0);
426 curr_preset
= find_preset(curr_freq
);
427 remember_frequency();
430 /* Ends an in-progress search */
431 static void end_search(void)
433 if (search_dir
!= 0 && radio_status
== FMRADIO_PLAYING
)
434 tuner_set(RADIO_MUTE
, 0);
438 /* Speak a frequency. */
439 static void talk_freq(int freq
, bool enqueue
)
442 talk_number(freq
/ 100, enqueue
);
443 talk_id(LANG_POINT
, true);
444 talk_number(freq
% 100 / 10, true);
446 talk_number(freq
% 10, true);
449 /* Speak a preset by number or by spelling its name, depending on settings. */
450 static void talk_preset(int preset
, bool fallback
, bool enqueue
)
452 if (global_settings
.talk_file
== 1) /* number */
453 talk_number(preset
+ 1, enqueue
);
456 if(presets
[preset
].name
[0])
457 talk_spell(presets
[preset
].name
, enqueue
);
459 talk_freq(presets
[preset
].frequency
, enqueue
);
463 static void fms_restore(struct viewport vp
[NB_SCREENS
])
465 struct screen
*display
;
469 display
= &screens
[i
];
470 display
->set_viewport(&vp
[i
]);
471 display
->clear_viewport();
472 display
->update_viewport();
476 int radio_screen(void)
480 int ret_val
= GO_TO_ROOT
;
483 bool stereo
= false, last_stereo
= false;
485 int top_of_screen
= 0;
486 bool update_screen
= true;
487 bool screen_freeze
= false;
488 bool keep_playing
= false;
490 #ifdef FM_RECORD_DBLPRE
491 int lastbutton
= BUTTON_NONE
;
492 unsigned long rec_lastclick
= 0;
494 #if CONFIG_CODEC != SWCODEC
495 bool have_recorded
= false;
496 int timeout
= current_tick
+ HZ
/10;
497 unsigned int seconds
= 0;
498 unsigned int last_seconds
= 0;
500 struct audio_recording_options rec_options
;
501 #endif /* CONFIG_CODEC != SWCODEC */
502 #ifndef HAVE_NOISY_IDLE_MODE
503 int button_timeout
= current_tick
+ (2*HZ
);
505 struct viewport vp
[NB_SCREENS
];
506 #ifdef HAVE_BUTTONBAR
507 struct gui_buttonbar buttonbar
;
508 gui_buttonbar_init(&buttonbar
);
509 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
512 /* change status to "in screen" */
515 /* always display status bar in radio screen for now */
518 viewport_set_defaults(&vp
[i
], i
);
519 #ifdef HAVE_BUTTONBAR
520 if (global_settings
.buttonbar
)
521 vp
[i
].height
-= BUTTONBAR_HEIGHT
;
526 fh
= font_get(FONT_UI
)->height
;
528 /* Adjust for font size, trying to center the information vertically */
534 radio_load_presets(global_settings
.fmr_file
);
537 if(radio_status
== FMRADIO_OFF
)
541 #if CONFIG_CODEC != SWCODEC
542 if(rec_create_directory() > 0)
543 have_recorded
= true;
545 audio_init_recording(talk_get_bufsize());
547 sound_settings_apply();
548 /* Yes, we use the D/A for monitoring */
549 peak_meter_playback(true);
551 peak_meter_enabled
= true;
553 rec_init_recording_options(&rec_options
);
554 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
555 rec_set_recording_options(&rec_options
);
557 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
558 sound_default(SOUND_RIGHT_GAIN
), AUDIO_GAIN_LINEIN
);
560 #endif /* CONFIG_CODEC != SWCODEC */
561 #endif /* ndef SIMULATOR */
564 #if CONFIG_CODEC == SWCODEC
565 audio_set_input_source(AUDIO_SRC_FMRADIO
,
566 (radio_status
== FMRADIO_PAUSED
) ?
567 SRCF_FMRADIO_PAUSED
: SRCF_FMRADIO_PLAYING
);
569 if (radio_status
== FMRADIO_OFF
)
573 if(num_presets
< 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN
)))
576 curr_preset
= find_preset(curr_freq
);
577 if(curr_preset
!= -1)
578 radio_mode
= RADIO_PRESET_MODE
;
580 #ifdef HAVE_BUTTONBAR
581 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
582 str(LANG_PRESET
), str(LANG_FM_BUTTONBAR_RECORD
));
585 #ifndef HAVE_NOISY_IDLE_MODE
593 curr_freq
= step_freq(curr_freq
, search_dir
);
594 update_screen
= true;
596 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
598 curr_preset
= find_preset(curr_freq
);
599 remember_frequency();
611 #if CONFIG_CODEC != SWCODEC
612 /* TODO: Can we timeout at HZ when recording since peaks aren't
613 displayed? This should quiet recordings too. */
614 button
= get_action(CONTEXT_FM
,
615 update_screen
? TIMEOUT_NOBLOCK
: HZ
/ PEAK_METER_FPS
);
617 button
= get_action(CONTEXT_FM
,
618 update_screen
? TIMEOUT_NOBLOCK
: HZ
);
621 #ifndef HAVE_NOISY_IDLE_MODE
622 if (button
!= ACTION_NONE
)
624 cpu_idle_mode(false);
625 button_timeout
= current_tick
+ (2*HZ
);
631 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
632 if(audio_status() == AUDIO_STATUS_RECORD
)
642 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
644 if(filepreset
[0] == '\0')
647 radio_save_presets();
650 /* Clear the preset list on exit. */
653 update_screen
= true;
657 case ACTION_FM_RECORD
:
658 #ifdef FM_RECORD_DBLPRE
659 if (lastbutton
!= ACTION_FM_RECORD_DBLPRE
)
664 if (current_tick
- rec_lastclick
> HZ
/2)
666 rec_lastclick
= current_tick
;
669 #endif /* FM_RECORD_DBLPRE */
671 if(audio_status() == AUDIO_STATUS_RECORD
)
673 rec_command(RECORDING_CMD_START_NEWFILE
);
674 update_screen
= true;
678 have_recorded
= true;
679 rec_command(RECORDING_CMD_START
);
680 update_screen
= true;
682 #endif /* SIMULATOR */
685 #endif /* #ifdef FM_RECORD */
688 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
689 if(audio_status() == AUDIO_STATUS_RECORD
)
694 ret_val
= GO_TO_ROOT
;
697 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
699 if(filepreset
[0] == '\0')
702 radio_save_presets();
706 /* Clear the preset list on exit. */
711 case ACTION_STD_PREV
:
712 case ACTION_STD_NEXT
:
713 next_station(button
== ACTION_STD_PREV
? -1 : 1);
715 update_screen
= true;
719 case ACTION_STD_PREVREPEAT
:
720 case ACTION_STD_NEXTREPEAT
:
722 int dir
= search_dir
;
723 search_dir
= button
== ACTION_STD_PREVREPEAT
? -1 : 1;
724 if (radio_mode
!= RADIO_SCAN_MODE
)
726 next_preset(search_dir
);
728 update_screen
= true;
733 /* Starting auto scan */
734 tuner_set(RADIO_MUTE
, 1);
735 update_screen
= true;
740 case ACTION_SETTINGS_INC
:
741 case ACTION_SETTINGS_INCREPEAT
:
742 global_settings
.volume
++;
744 update_screen
= true;
747 case ACTION_SETTINGS_DEC
:
748 case ACTION_SETTINGS_DECREPEAT
:
749 global_settings
.volume
--;
751 update_screen
= true;
755 if (radio_status
== FMRADIO_PLAYING
)
760 update_screen
= true;
768 screens
[i
].scroll_stop(&vp
[i
]);
771 curr_preset
= find_preset(curr_freq
);
773 #ifdef HAVE_BUTTONBAR
774 gui_buttonbar_set(&buttonbar
, str(LANG_BUTTONBAR_MENU
),
776 str(LANG_FM_BUTTONBAR_RECORD
));
778 update_screen
= true;
782 case ACTION_FM_PRESET
:
785 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
786 update_screen
= true;
792 screens
[i
].scroll_stop(&vp
[i
]);
793 handle_radio_presets();
795 #ifdef HAVE_BUTTONBAR
796 gui_buttonbar_set(&buttonbar
,
797 str(LANG_BUTTONBAR_MENU
),
799 str(LANG_FM_BUTTONBAR_RECORD
));
801 update_screen
= true;
803 #endif /* FM_PRESET */
805 #ifdef HAVE_QUICKSCREEN
806 case ACTION_FM_QUICKSCREEN
:
808 if (quick_screen_quick(button
))
814 update_screen
= true;
819 case ACTION_FM_FREEZE
:
822 splash(HZ
, str(LANG_FM_FREEZE
));
823 screen_freeze
= true;
827 update_screen
= true;
828 screen_freeze
= false;
831 #endif /* FM_FREEZE */
833 case SYS_USB_CONNECTED
:
834 #if CONFIG_CODEC != SWCODEC
835 /* Only accept USB connection when not recording */
836 if(audio_status() != AUDIO_STATUS_RECORD
)
839 default_event_handler(SYS_USB_CONNECTED
);
840 screen_freeze
= true; /* Cosmetic: makes sure the
841 radio screen doesn't redraw */
848 if(radio_mode
== RADIO_SCAN_MODE
)
850 /* Force scan mode if there are no presets. */
852 radio_mode
= RADIO_PRESET_MODE
;
855 radio_mode
= RADIO_SCAN_MODE
;
856 update_screen
= true;
857 cond_talk_ids_fq(radio_mode
?
858 LANG_PRESET
: LANG_RADIO_SCAN_MODE
);
863 #ifdef FM_NEXT_PRESET
864 case ACTION_FM_NEXT_PRESET
:
867 update_screen
= true;
872 #ifdef FM_PREV_PRESET
873 case ACTION_FM_PREV_PRESET
:
876 update_screen
= true;
882 default_event_handler(button
);
884 if (tuner_get(RADIO_EVENT
))
885 update_screen
= true;
887 if (!tuner_get(RADIO_PRESENT
))
889 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
890 if(audio_status() == AUDIO_STATUS_RECORD
)
893 keep_playing
= false;
895 ret_val
= GO_TO_ROOT
;
898 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
900 if(filepreset
[0] == '\0')
903 radio_save_presets();
907 /* Clear the preset list on exit. */
913 #ifdef FM_RECORD_DBLPRE
914 if (button
!= ACTION_NONE
)
918 #if CONFIG_CODEC != SWCODEC
924 /* Only display the peak meter when not recording */
925 #if CONFIG_CODEC != SWCODEC
930 screens
[i
].set_viewport(&vp
[i
]);
931 peak_meter_screen(&screens
[i
],0, fh
*(top_of_screen
+ 4),fh
);
932 screens
[i
].update_rect(0, fh
*(top_of_screen
+ 4),
933 screens
[i
].getwidth(), fh
);
937 if(TIME_AFTER(current_tick
, timeout
))
939 timeout
= current_tick
+ HZ
;
942 #endif /* CONFIG_CODEC == SWCODEC */
944 /* keep "mono" from always being displayed when paused */
945 if (radio_status
!= FMRADIO_PAUSED
)
947 stereo
= tuner_get(RADIO_STEREO
) &&
948 !global_settings
.fm_force_mono
;
950 if(stereo
!= last_stereo
)
952 update_screen
= true;
953 last_stereo
= stereo
;
958 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
959 seconds
= audio_recorded_time() / HZ
;
960 if (update_screen
|| seconds
> last_seconds
)
962 last_seconds
= seconds
;
971 screens
[i
].set_viewport(&vp
[i
]);
974 snprintf(buf
, 128, curr_preset
>= 0 ? "%d. %s" : " ",
975 curr_preset
+ 1, presets
[curr_preset
].name
);
978 screens
[i
].puts_scroll(0, top_of_screen
, buf
);
980 freq
= curr_freq
/ 10000;
981 snprintf(buf
, 128, str(LANG_FM_STATION
),
982 freq
/ 100, freq
% 100);
984 screens
[i
].puts_scroll(0, top_of_screen
+ 1, buf
);
987 screens
[i
].puts_scroll(0, top_of_screen
+ 2,
988 stereo
? str(LANG_CHANNEL_STEREO
) :
989 str(LANG_CHANNEL_MONO
));
991 snprintf(buf
, 128, "%s %s", str(LANG_MODE
),
992 radio_mode
? str(LANG_PRESET
) :
993 str(LANG_RADIO_SCAN_MODE
));
995 screens
[i
].puts_scroll(0, top_of_screen
+ 3, buf
);
998 snprintf(buf
, 128, "%s",tuner_get_rds_info(RADIO_RDS_NAME
));
1000 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
1002 snprintf(buf
, 128, "%s",tuner_get_rds_info(RADIO_RDS_TEXT
));
1004 screens
[i
].puts_scroll(0, top_of_screen
+ 5, buf
);
1006 #endif /* SIMULATOR */
1008 #if CONFIG_CODEC != SWCODEC
1009 if(audio_status() == AUDIO_STATUS_RECORD
)
1011 hours
= seconds
/ 3600;
1012 minutes
= (seconds
- (hours
* 3600)) / 60;
1013 snprintf(buf
, 32, "%s %02d:%02d:%02d",
1014 str(LANG_RECORDING_TIME
),
1015 hours
, minutes
, seconds
%60);
1017 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
1021 if(rec_options
.rec_prerecord_time
)
1023 snprintf(buf
, 32, "%s %02d",
1024 str(LANG_RECORD_PRERECORD
), seconds
%60);
1026 screens
[i
].puts_scroll(0, top_of_screen
+ 4, buf
);
1029 #endif /* CONFIG_CODEC != SWCODEC */
1032 screens
[i
].update_viewport();
1033 #ifdef HAVE_BUTTONBAR
1034 gui_buttonbar_draw(&buttonbar
);
1039 update_screen
= false;
1041 if (global_settings
.talk_file
&& talk
1042 && radio_status
== FMRADIO_PAUSED
)
1045 bool enqueue
= false;
1046 if (radio_mode
== RADIO_SCAN_MODE
)
1048 talk_freq(curr_freq
, enqueue
);
1051 if (curr_preset
>= 0)
1052 talk_preset(curr_preset
, radio_mode
== RADIO_PRESET_MODE
,
1056 #if CONFIG_CODEC != SWCODEC
1057 if(audio_status() & AUDIO_STATUS_ERROR
)
1063 #ifndef HAVE_NOISY_IDLE_MODE
1064 if (TIME_AFTER(current_tick
, button_timeout
))
1066 cpu_idle_mode(true);
1072 #if CONFIG_CODEC != SWCODEC
1073 if(audio_status() & AUDIO_STATUS_ERROR
)
1075 splash(0, str(LANG_DISK_FULL
));
1077 audio_error_clear();
1081 button
= get_action(CONTEXT_FM
, TIMEOUT_BLOCK
);
1082 if(button
== ACTION_FM_STOP
)
1087 audio_init_playback();
1088 #endif /* CONFIG_CODEC != SWCODEC */
1090 sound_settings_apply();
1091 #endif /* SIMULATOR */
1095 /* Catch FMRADIO_PLAYING status for the sim. */
1097 #if CONFIG_CODEC != SWCODEC
1098 /* Enable the Left and right A/D Converter */
1099 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
1100 sound_default(SOUND_RIGHT_GAIN
),
1102 mas_codec_writereg(6, 0x4000);
1105 #endif /* SIMULATOR */
1109 #if CONFIG_CODEC == SWCODEC
1110 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
1116 #ifndef HAVE_NOISY_IDLE_MODE
1117 cpu_idle_mode(false);
1121 screens
[i
].scroll_stop(&vp
[i
]);
1122 screens
[i
].set_viewport(NULL
);
1125 #if CONFIG_CODEC != SWCODEC
1126 return have_recorded
;
1130 } /* radio_screen */
1132 static void radio_save_presets(void)
1137 fd
= creat(filepreset
, 0666);
1140 for(i
= 0;i
< num_presets
;i
++)
1142 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
1146 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
1147 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
1148 presets_changed
= false;
1152 splash(HZ
, ID2P(LANG_FM_PRESET_SAVE_FAILED
));
1156 void radio_load_presets(char *filename
)
1166 memset(presets
, 0, sizeof(presets
));
1169 /* No Preset in configuration. */
1170 if(filename
[0] == '\0')
1172 filepreset
[0] = '\0';
1175 /* Temporary preset, loaded until player shuts down. */
1176 else if(filename
[0] == '/')
1177 strlcpy(filepreset
, filename
, sizeof(filepreset
));
1178 /* Preset from default directory. */
1180 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
1181 FMPRESET_PATH
, filename
);
1183 fd
= open_utf8(filepreset
, O_RDONLY
);
1186 while(!done
&& num_presets
< MAX_PRESETS
)
1188 rc
= read_line(fd
, buf
, 128);
1191 if(settings_parseline(buf
, &freq
, &name
))
1194 if(f
) /* For backwards compatibility */
1196 struct fmstation
* const fms
= &presets
[num_presets
];
1198 strlcpy(fms
->name
, name
, MAX_FMPRESET_LEN
+1);
1208 else /* invalid file name? */
1209 filepreset
[0] = '\0';
1211 presets_loaded
= num_presets
> 0;
1212 presets_changed
= false;
1216 static int radio_add_preset(void)
1218 char buf
[MAX_FMPRESET_LEN
+ 1];
1220 if(num_presets
< MAX_PRESETS
)
1224 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1226 struct fmstation
* const fms
= &presets
[num_presets
];
1227 strcpy(fms
->name
, buf
);
1228 fms
->frequency
= curr_freq
;
1230 presets_changed
= true;
1231 presets_loaded
= num_presets
> 0;
1237 splash(HZ
, ID2P(LANG_FM_NO_FREE_PRESETS
));
1242 /* needed to know which preset we are edit/delete-ing */
1243 static int selected_preset
= -1;
1244 static int radio_edit_preset(void)
1246 char buf
[MAX_FMPRESET_LEN
+ 1];
1248 if (num_presets
> 0)
1250 struct fmstation
* const fms
= &presets
[selected_preset
];
1252 strcpy(buf
, fms
->name
);
1254 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1256 strcpy(fms
->name
, buf
);
1257 presets_changed
= true;
1264 static int radio_delete_preset(void)
1266 if (num_presets
> 0)
1268 struct fmstation
* const fms
= &presets
[selected_preset
];
1270 if (selected_preset
>= --num_presets
)
1271 selected_preset
= num_presets
- 1;
1273 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
1276 if (curr_preset
>= num_presets
)
1280 /* Don't ask to save when all presets are deleted. */
1281 presets_changed
= num_presets
> 0;
1283 if (!presets_changed
)
1285 /* The preset list will be cleared, switch to Scan Mode. */
1286 radio_mode
= RADIO_SCAN_MODE
;
1288 presets_loaded
= false;
1294 static int load_preset_list(void)
1296 return !rockbox_browse(FMPRESET_PATH
, SHOW_FMR
);
1299 static int save_preset_list(void)
1303 bool bad_file_name
= true;
1305 if(!dir_exists(FMPRESET_PATH
)) /* Check if there is preset folder */
1306 mkdir(FMPRESET_PATH
);
1308 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
1309 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
1311 while(bad_file_name
)
1313 if(!kbd_input(filepreset
, sizeof(filepreset
)))
1315 /* check the name: max MAX_FILENAME (20) chars */
1319 p1
= strrchr(filepreset
, '/');
1321 while((p1
) && (*p2
) && (*p2
!= '.'))
1323 len
= (int)(p2
-p1
) - 1;
1324 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
1326 /* no slash, too long or too short */
1327 splash(HZ
, ID2P(LANG_INVALID_FILENAME
));
1331 /* add correct extension (easier to always write)
1332 at this point, p2 points to 0 or the extension dot */
1334 strcat(filepreset
,".fmr");
1335 bad_file_name
= false;
1336 radio_save_presets();
1347 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
1352 static int clear_preset_list(void)
1354 /* Clear all the preset entries */
1355 memset(presets
, 0, sizeof (presets
));
1358 presets_loaded
= false;
1359 /* The preset list will be cleared switch to Scan Mode. */
1360 radio_mode
= RADIO_SCAN_MODE
;
1363 presets_changed
= false; /* Don't ask to save when clearing the list. */
1368 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1369 ID2P(LANG_FM_EDIT_PRESET
),
1370 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
1371 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1372 ID2P(LANG_FM_DELETE_PRESET
),
1373 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
1374 static int radio_preset_callback(int action
,
1375 const struct menu_item_ex
*this_item
)
1377 if (action
== ACTION_STD_OK
)
1378 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
1382 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_PRESET
),
1383 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
1384 &radio_delete_preset_item
);
1385 /* present a list of preset stations */
1386 static const char* presets_get_name(int selected_item
, void *data
,
1387 char *buffer
, size_t buffer_len
)
1390 struct fmstation
*p
= &presets
[selected_item
];
1393 int freq
= p
->frequency
/ 10000;
1394 int frac
= freq
% 100;
1396 snprintf(buffer
, buffer_len
,
1397 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
1401 static int presets_speak_name(int selected_item
, void * data
)
1404 talk_preset(selected_item
, true, false);
1408 static int handle_radio_presets(void)
1410 struct gui_synclist lists
;
1412 int action
= ACTION_NONE
;
1413 #ifdef HAVE_BUTTONBAR
1414 struct gui_buttonbar buttonbar
;
1417 if(presets_loaded
== false)
1420 #ifdef HAVE_BUTTONBAR
1421 gui_buttonbar_init(&buttonbar
);
1422 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
1423 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
1424 str(LANG_FM_BUTTONBAR_EXIT
),
1425 str(LANG_FM_BUTTONBAR_ACTION
));
1426 gui_buttonbar_draw(&buttonbar
);
1428 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1, NULL
);
1429 gui_synclist_set_title(&lists
, str(LANG_PRESET
), NOICON
);
1430 gui_synclist_set_icon_callback(&lists
, NULL
);
1431 if(global_settings
.talk_file
)
1432 gui_synclist_set_voice_callback(&lists
, presets_speak_name
);
1433 gui_synclist_set_nb_items(&lists
, num_presets
);
1434 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
1435 gui_synclist_speak_item(&lists
);
1439 gui_synclist_draw(&lists
);
1440 list_do_action(CONTEXT_STD
, TIMEOUT_BLOCK
,
1441 &lists
, &action
, LIST_WRAP_UNLESS_HELD
);
1444 case ACTION_STD_MENU
:
1445 if (radio_add_preset())
1447 gui_synclist_set_nb_items(&lists
, num_presets
);
1448 gui_synclist_select_item(&lists
, num_presets
- 1);
1451 case ACTION_STD_CANCEL
:
1455 curr_preset
= gui_synclist_get_sel_pos(&lists
);
1456 curr_freq
= presets
[curr_preset
].frequency
;
1458 remember_frequency();
1462 case ACTION_STD_CONTEXT
:
1463 selected_preset
= gui_synclist_get_sel_pos(&lists
);
1464 do_menu(&handle_radio_preset_menu
, NULL
, NULL
, false);
1465 gui_synclist_set_nb_items(&lists
, num_presets
);
1466 gui_synclist_select_item(&lists
, selected_preset
);
1467 gui_synclist_speak_item(&lists
);
1470 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
1474 gui_synclist_scroll_stop(&lists
);
1478 void toggle_mono_mode(bool mono
)
1480 tuner_set(RADIO_FORCE_MONO
, mono
);
1483 void set_radio_region(int region
)
1485 #ifdef HAVE_RADIO_REGION
1486 tuner_set(RADIO_REGION
, region
);
1489 remember_frequency();
1493 MENUITEM_SETTING(set_region
, &global_settings
.fm_region
, NULL
);
1494 MENUITEM_SETTING(force_mono
, &global_settings
.fm_force_mono
, NULL
);
1497 static char* get_mode_text(int selected_item
, void * data
, char *buffer
)
1499 (void)selected_item
;
1501 snprintf(buffer
, MAX_PATH
, "%s %s", str(LANG_MODE
),
1502 radio_mode
? str(LANG_PRESET
) :
1503 str(LANG_RADIO_SCAN_MODE
));
1506 static int toggle_radio_mode(void)
1508 radio_mode
= (radio_mode
== RADIO_SCAN_MODE
) ?
1509 RADIO_PRESET_MODE
: RADIO_SCAN_MODE
;
1512 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item
, 0,
1513 toggle_radio_mode
, NULL
,
1514 get_mode_text
, NULL
, NULL
, NULL
, Icon_NOICON
);
1517 static int scan_presets(void *viewports
)
1519 bool do_scan
= true;
1521 struct viewport
*vp
= (struct viewport
*)viewports
;
1524 screens
[i
].set_viewport(vp
?&vp
[i
]:NULL
);
1525 if(num_presets
> 0) /* Do that to avoid 2 questions. */
1526 do_scan
= yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS
));
1530 const struct fm_region_data
* const fmr
=
1531 &fm_region_data
[global_settings
.fm_region
];
1533 curr_freq
= fmr
->freq_min
;
1535 memset(presets
, 0, sizeof(presets
));
1537 tuner_set(RADIO_MUTE
, 1);
1539 while(curr_freq
<= fmr
->freq_max
)
1542 if(num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
1545 freq
= curr_freq
/ 10000;
1549 splashf(0, str(LANG_FM_SCANNING
), freq
, frac
);
1551 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
1554 presets
[num_presets
].name
[0] = '\0';
1555 presets
[num_presets
].frequency
= curr_freq
;
1559 curr_freq
+= fmr
->freq_step
;
1562 if (radio_status
== FMRADIO_PLAYING
)
1563 tuner_set(RADIO_MUTE
, 0);
1565 presets_changed
= true;
1569 screens
[i
].clear_viewport();
1570 screens
[i
].update_viewport();
1575 curr_freq
= presets
[0].frequency
;
1576 radio_mode
= RADIO_PRESET_MODE
;
1577 presets_loaded
= true;
1582 /* Wrap it to beginning or we'll be past end of band */
1583 presets_loaded
= false;
1591 #ifdef HAVE_RECORDING
1593 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1594 #define FM_RECORDING_SCREEN
1595 static int fm_recording_screen(void)
1599 /* switch recording source to FMRADIO for the duration */
1600 int rec_source
= global_settings
.rec_source
;
1601 global_settings
.rec_source
= AUDIO_SRC_FMRADIO
;
1602 ret
= recording_screen(true);
1604 /* safe to reset as changing sources is prohibited here */
1605 global_settings
.rec_source
= rec_source
;
1610 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1612 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1613 #define FM_RECORDING_SETTINGS
1614 static int fm_recording_settings(void)
1616 bool ret
= recording_menu(true);
1618 #if CONFIG_CODEC != SWCODEC
1621 struct audio_recording_options rec_options
;
1622 rec_init_recording_options(&rec_options
);
1623 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
1624 rec_set_recording_options(&rec_options
);
1631 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1632 #endif /* HAVE_RECORDING */
1634 #ifdef FM_RECORDING_SCREEN
1635 MENUITEM_FUNCTION(recscreen_item
, 0, ID2P(LANG_RECORDING
),
1636 fm_recording_screen
, NULL
, NULL
, Icon_Recording
);
1638 #ifdef FM_RECORDING_SETTINGS
1639 MENUITEM_FUNCTION(recsettings_item
, 0, ID2P(LANG_RECORDING_SETTINGS
),
1640 fm_recording_settings
, NULL
, NULL
, Icon_Recording
);
1643 MENUITEM_FUNCTION(radio_presets_item
, 0, ID2P(LANG_PRESET
),
1644 handle_radio_presets
, NULL
, NULL
, Icon_NOICON
);
1646 #ifndef FM_PRESET_ADD
1647 MENUITEM_FUNCTION(radio_addpreset_item
, 0, ID2P(LANG_FM_ADD_PRESET
),
1648 radio_add_preset
, NULL
, NULL
, Icon_NOICON
);
1652 MENUITEM_FUNCTION(presetload_item
, 0, ID2P(LANG_FM_PRESET_LOAD
),
1653 load_preset_list
, NULL
, NULL
, Icon_NOICON
);
1654 MENUITEM_FUNCTION(presetsave_item
, 0, ID2P(LANG_FM_PRESET_SAVE
),
1655 save_preset_list
, NULL
, NULL
, Icon_NOICON
);
1656 MENUITEM_FUNCTION(presetclear_item
, 0, ID2P(LANG_FM_PRESET_CLEAR
),
1657 clear_preset_list
, NULL
, NULL
, Icon_NOICON
);
1658 MENUITEM_FUNCTION(scan_presets_item
, MENU_FUNC_USEPARAM
,
1659 ID2P(LANG_FM_SCAN_PRESETS
),
1660 scan_presets
, NULL
, NULL
, Icon_NOICON
);
1662 MAKE_MENU(radio_settings_menu
, ID2P(LANG_FM_MENU
), NULL
,
1665 &radio_presets_item
,
1667 #ifndef FM_PRESET_ADD
1668 &radio_addpreset_item
,
1670 &presetload_item
, &presetsave_item
, &presetclear_item
,
1675 &set_region
, &sound_settings
,
1676 #ifdef FM_RECORDING_SCREEN
1679 #ifdef FM_RECORDING_SETTINGS
1682 &scan_presets_item
);
1683 /* main menu of the radio screen */
1684 static bool radio_menu(void)
1686 return do_menu(&radio_settings_menu
, NULL
, NULL
, false) ==