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
54 #include "appevents.h"
59 #include "screen_access.h"
62 #include "buttonbar.h"
67 #include "menus/exported_menus.h"
68 #include "root_menu.h"
70 #include "skin_engine/skin_engine.h"
71 #include "statusbar-skinned.h"
72 #include "buffering.h"
76 #if CONFIG_KEYPAD == RECORDER_PAD
79 #define FM_PRESET_ACTION
83 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
86 #define FM_NEXT_PRESET
87 #define FM_PREV_PRESET
89 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
93 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
96 /* This should be removeable if the whole tuning thing is sorted out since
97 proper tuning quiets the screen almost entirely in that extreme measures
98 have to be taken to hear any interference. */
99 #define HAVE_NOISY_IDLE_MODE
101 #elif CONFIG_KEYPAD == ONDIO_PAD
102 #define FM_RECORD_DBLPRE
104 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD)
112 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
116 #elif (CONFIG_KEYPAD == COWON_D2_PAD)
124 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
125 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
134 #define RADIO_SCAN_MODE 0
135 #define RADIO_PRESET_MODE 1
137 static int curr_preset
= -1;
138 static int curr_freq
; /* current frequency in Hz */
139 static int radio_mode
= RADIO_SCAN_MODE
;
140 static int search_dir
= 0;
142 static int radio_status
= FMRADIO_OFF
;
143 static bool in_screen
= false;
145 #define MAX_PRESETS 64
146 static bool presets_loaded
= false, presets_changed
= false;
147 static struct fmstation presets
[MAX_PRESETS
];
149 static char filepreset
[MAX_PATH
]; /* preset filename variable */
151 static int num_presets
= 0; /* The number of presets in the preset list */
153 static void radio_save_presets(void);
154 static int handle_radio_presets(void);
155 static bool radio_menu(void);
156 static int radio_add_preset(void);
157 static int save_preset_list(void);
158 static int load_preset_list(void);
159 static int clear_preset_list(void);
161 static int scan_presets(void *viewports
);
162 static void radio_off(void);
164 bool radio_scan_mode(void)
166 return radio_mode
== RADIO_SCAN_MODE
;
169 bool radio_is_stereo(void)
171 return tuner_get(RADIO_STEREO
) && !global_settings
.fm_force_mono
;
173 int radio_current_frequency(void)
178 int radio_current_preset(void)
182 int radio_preset_count(void)
186 const struct fmstation
*radio_get_preset(int preset
)
188 return &presets
[preset
];
190 /* Function to manipulate all yesno dialogues.
191 This function needs the output text as an argument. */
192 static bool yesno_pop(const char* text
)
195 const char *lines
[]={text
};
196 const struct text_message message
={lines
, 1};
197 bool ret
= (gui_syncyesno_run(&message
,NULL
,NULL
)== YESNO_YES
);
199 screens
[i
].clear_viewport();
203 #if defined(HAVE_RECORDING) && defined(HAVE_ALBUMART)
204 static void recording_started_handler(void *data
);
205 static void recording_stopped_handler(void *data
);
207 void radio_init(void)
211 #if defined(HAVE_RECORDING) && defined(HAVE_ALBUMART)
212 add_event(RECORDING_EVENT_START
, false, recording_started_handler
);
213 add_event(RECORDING_EVENT_STOP
, false, recording_stopped_handler
);
217 int get_radio_status(void)
222 bool in_radio_screen(void)
227 /* TODO: Move some more of the control functionality to firmware
228 and clean up the mess */
230 /* secret flag for starting paused - prevents unmute */
231 #define FMRADIO_START_PAUSED 0x8000
232 void radio_start(void)
234 const struct fm_region_data
*fmr
;
237 if(radio_status
== FMRADIO_PLAYING
)
240 fmr
= &fm_region_data
[global_settings
.fm_region
];
242 start_paused
= radio_status
& FMRADIO_START_PAUSED
;
243 /* clear flag before any yielding */
244 radio_status
&= ~FMRADIO_START_PAUSED
;
246 if(radio_status
== FMRADIO_OFF
)
249 curr_freq
= global_status
.last_frequency
* fmr
->freq_step
+ fmr
->freq_min
;
251 tuner_set(RADIO_SLEEP
, 0); /* wake up the tuner */
253 if(radio_status
== FMRADIO_OFF
)
255 #ifdef HAVE_RADIO_REGION
256 tuner_set(RADIO_REGION
, global_settings
.fm_region
);
258 tuner_set(RADIO_FORCE_MONO
, global_settings
.fm_force_mono
);
261 tuner_set(RADIO_FREQUENCY
, curr_freq
);
263 #ifdef HAVE_RADIO_MUTE_TIMEOUT
265 unsigned long mute_timeout
= current_tick
+ HZ
;
266 if (radio_status
!= FMRADIO_OFF
)
272 while(!tuner_get(RADIO_STEREO
) && !tuner_get(RADIO_TUNED
))
274 if(TIME_AFTER(current_tick
, mute_timeout
))
281 /* keep radio from sounding initially */
283 tuner_set(RADIO_MUTE
, 0);
285 radio_status
= FMRADIO_PLAYING
;
288 void radio_pause(void)
290 if(radio_status
== FMRADIO_PAUSED
)
293 if(radio_status
== FMRADIO_OFF
)
295 radio_status
|= FMRADIO_START_PAUSED
;
299 tuner_set(RADIO_MUTE
, 1);
300 tuner_set(RADIO_SLEEP
, 1);
302 radio_status
= FMRADIO_PAUSED
;
305 static void radio_off(void)
307 tuner_set(RADIO_MUTE
, 1);
308 tuner_set(RADIO_SLEEP
, 1); /* low power mode, if available */
309 radio_status
= FMRADIO_OFF
;
310 tuner_power(false); /* status update, power off if avail. */
313 void radio_stop(void)
315 if(radio_status
== FMRADIO_OFF
)
321 bool radio_hardware_present(void)
323 return tuner_get(RADIO_PRESENT
);
326 /* Keep freq on the grid for the current region */
327 static int snap_freq_to_grid(int freq
)
329 const struct fm_region_data
* const fmr
=
330 &fm_region_data
[global_settings
.fm_region
];
332 /* Range clamp if out of range or just round to nearest */
333 if (freq
< fmr
->freq_min
)
334 freq
= fmr
->freq_min
;
335 else if (freq
> fmr
->freq_max
)
336 freq
= fmr
->freq_max
;
338 freq
= (freq
- fmr
->freq_min
+ fmr
->freq_step
/2) /
339 fmr
->freq_step
* fmr
->freq_step
+ fmr
->freq_min
;
344 /* Find a matching preset to freq */
345 static int find_preset(int freq
)
350 for(i
= 0;i
< MAX_PRESETS
;i
++)
352 if(freq
== presets
[i
].frequency
)
359 /* Return the closest preset encountered in the search direction with
361 static int find_closest_preset(int freq
, int direction
)
368 if (direction
== 0) /* direction == 0 isn't really used */
371 for (i
= 0; i
< num_presets
; i
++)
373 int f
= presets
[i
].frequency
;
375 return i
; /* Exact match = stop */
377 /* remember the highest and lowest presets for wraparound */
378 if (f
< presets
[lowpreset
].frequency
)
380 if (f
> presets
[highpreset
].frequency
)
383 /* find the closest preset in the given direction */
384 if (direction
> 0 && f
> freq
)
386 if (closest
< 0 || f
< presets
[closest
].frequency
)
389 else if (direction
< 0 && f
< freq
)
391 if (closest
< 0 || f
> presets
[closest
].frequency
)
398 /* no presets in the given direction */
399 /* wrap around depending on direction */
401 closest
= highpreset
;
409 static void remember_frequency(void)
411 const struct fm_region_data
* const fmr
=
412 &fm_region_data
[global_settings
.fm_region
];
413 global_status
.last_frequency
= (curr_freq
- fmr
->freq_min
)
418 static void next_preset(int direction
)
423 if (curr_preset
== -1)
424 curr_preset
= find_closest_preset(curr_freq
, direction
);
426 curr_preset
= (curr_preset
+ direction
+ num_presets
) % num_presets
;
428 /* Must stay on the current grid for the region */
429 curr_freq
= snap_freq_to_grid(presets
[curr_preset
].frequency
);
431 tuner_set(RADIO_FREQUENCY
, curr_freq
);
432 remember_frequency();
435 /* Step to the next or previous frequency */
436 static int step_freq(int freq
, int direction
)
438 const struct fm_region_data
* const fmr
=
439 &fm_region_data
[global_settings
.fm_region
];
441 freq
+= direction
*fmr
->freq_step
;
443 /* Wrap first or snapping to grid will not let us on the band extremes */
444 if (freq
> fmr
->freq_max
)
445 freq
= direction
> 0 ? fmr
->freq_min
: fmr
->freq_max
;
446 else if (freq
< fmr
->freq_min
)
447 freq
= direction
< 0 ? fmr
->freq_max
: fmr
->freq_min
;
449 freq
= snap_freq_to_grid(freq
);
454 /* Step to the next or previous station */
455 static void next_station(int direction
)
457 if (direction
!= 0 && radio_mode
!= RADIO_SCAN_MODE
)
459 next_preset(direction
);
463 curr_freq
= step_freq(curr_freq
, direction
);
465 if (radio_status
== FMRADIO_PLAYING
)
466 tuner_set(RADIO_MUTE
, 1);
468 tuner_set(RADIO_FREQUENCY
, curr_freq
);
470 if (radio_status
== FMRADIO_PLAYING
)
471 tuner_set(RADIO_MUTE
, 0);
473 curr_preset
= find_preset(curr_freq
);
474 remember_frequency();
477 /* Ends an in-progress search */
478 static void end_search(void)
480 if (search_dir
!= 0 && radio_status
== FMRADIO_PLAYING
)
481 tuner_set(RADIO_MUTE
, 0);
485 /* Speak a frequency. */
486 static void talk_freq(int freq
, bool enqueue
)
489 talk_number(freq
/ 100, enqueue
);
490 talk_id(LANG_POINT
, true);
491 talk_number(freq
% 100 / 10, true);
493 talk_number(freq
% 10, true);
496 /* Speak a preset by number or by spelling its name, depending on settings. */
497 static void talk_preset(int preset
, bool fallback
, bool enqueue
)
499 if (global_settings
.talk_file
== 1) /* number */
500 talk_number(preset
+ 1, enqueue
);
503 if(presets
[preset
].name
[0])
504 talk_spell(presets
[preset
].name
, enqueue
);
506 talk_freq(presets
[preset
].frequency
, enqueue
);
511 extern struct wps_state wps_state
; /* from wps.c */
512 static struct gui_wps fms_skin
[NB_SCREENS
] = {{ .data
= NULL
}};
513 static struct wps_data fms_skin_data
[NB_SCREENS
] = {{ .wps_loaded
= 0 }};
514 static struct wps_sync_data fms_skin_sync_data
= { .do_full_update
= false };
517 #define MAX_RADIOART_IMAGES 10
522 char name
[MAX_FMPRESET_LEN
+1];
525 static struct radioart radioart
[MAX_RADIOART_IMAGES
];
526 #ifdef HAVE_RECORDING
527 static bool allow_buffer_access
= true; /* If we are recording dont touch the buffers! */
529 static int find_oldest_image(void)
532 long oldest_tick
= radioart
[0].last_tick
;
534 for(i
=1;i
<MAX_RADIOART_IMAGES
;i
++)
536 if (radioart
[i
].last_tick
< oldest_tick
)
538 oldest_tick
= radioart
[i
].last_tick
;
544 static int load_radioart_image(struct radioart
*ra
, char* preset_name
, struct dim
*dim
)
547 #ifndef HAVE_NOISY_IDLE_MODE
548 cpu_idle_mode(false);
550 snprintf(path
, sizeof(path
), FMPRESET_PATH
"/%s.bmp",preset_name
);
551 if (!file_exists(path
))
552 snprintf(path
, sizeof(path
), FMPRESET_PATH
"/%s.jpg",preset_name
);
553 if (!file_exists(path
))
555 #ifndef HAVE_NOISY_IDLE_MODE
560 strlcpy(ra
->name
, preset_name
, MAX_FMPRESET_LEN
+1);
561 ra
->dim
.height
= dim
->height
;
562 ra
->dim
.width
= dim
->width
;
563 ra
->last_tick
= current_tick
;
564 ra
->handle
= bufopen(path
, 0, TYPE_BITMAP
, &ra
->dim
);
565 if (ra
->handle
== ERR_BUFFER_FULL
)
567 int i
= find_oldest_image();
569 ra
->handle
= bufopen(path
, 0, TYPE_BITMAP
, &ra
->dim
);
571 #ifndef HAVE_NOISY_IDLE_MODE
576 int radio_get_art_hid(struct dim
*requested_dim
)
578 int preset
= radio_current_preset();
579 int i
, free_idx
= -1;
580 if ((radio_mode
!= RADIO_PRESET_MODE
) || preset
< 0)
582 #ifdef HAVE_RECORDING
583 if (!allow_buffer_access
)
586 for(i
=0;i
<MAX_RADIOART_IMAGES
;i
++)
588 if (radioart
[i
].handle
< 0)
592 else if (!strcmp(radioart
[i
].name
, presets
[preset
].name
) &&
593 radioart
[i
].dim
.width
== requested_dim
->width
&&
594 radioart
[i
].dim
.height
== requested_dim
->height
)
596 radioart
[i
].last_tick
= current_tick
;
597 return radioart
[i
].handle
;
602 return load_radioart_image(&radioart
[free_idx
],
603 presets
[preset
].name
, requested_dim
);
607 int i
= find_oldest_image();
608 bufclose(radioart
[i
].handle
);
609 return load_radioart_image(&radioart
[i
],
610 presets
[preset
].name
, requested_dim
);
615 static void playback_restarting_handler(void *data
)
619 for(i
=0;i
<MAX_RADIOART_IMAGES
;i
++)
621 if (radioart
[i
].handle
>= 0)
622 bufclose(radioart
[i
].handle
);
623 radioart
[i
].handle
= -1;
624 radioart
[i
].name
[0] = '\0';
627 #ifdef HAVE_RECORDING
628 static void recording_started_handler(void *data
)
631 allow_buffer_access
= false;
632 playback_restarting_handler(NULL
);
634 static void recording_stopped_handler(void *data
)
637 allow_buffer_access
= true;
642 void fms_data_load(enum screen_type screen
, const char *buf
, bool isfile
)
644 struct wps_data
*data
= fms_skin
[screen
].data
;
646 success
= buf
&& skin_data_load(screen
, data
, buf
, isfile
);
648 if (!success
) /* load the default */
650 const char default_fms
[] = "%Sx|Station:| %tf\n"
651 "%?ts<%Sx|Stereo||%Sx|Mono|>\n"
652 "%?tm<%Sx|Mode:| %Sx|Scan||%Sx|Preset|: %Ti. %?Tn<%Tn|%Tf>>\n"
654 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
655 "%?Rr<%Sx|Time:| %Rh:%Rn:%Rs|"
656 "%?St|prerecording time|<%Sx|Prerecord Time| %Rs|%pm>>\n"
663 skin_data_load(screen
, data
, default_fms
, false);
670 void fms_fix_displays(enum fms_exiting toggle_state
)
675 if (toggle_state
== FMS_ENTER
)
677 viewportmanager_theme_enable(i
, skin_has_sbs(i
, fms_skin
[i
].data
), NULL
);
678 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
679 screens
[i
].backdrop_show(fms_skin
[i
].data
->backdrop
);
681 screens
[i
].clear_display();
682 /* force statusbar/skin update since we just cleared the whole screen */
683 send_event(GUI_EVENT_ACTIONUPDATE
, (void*)1);
687 screens
[i
].stop_scroll();
688 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
689 screens
[i
].backdrop_show(sb_get_backdrop(i
));
691 viewportmanager_theme_undo(i
, skin_has_sbs(i
, fms_skin
[i
].data
));
697 void fms_skin_init(void)
703 fms_skin_data
[i
].albumart
= NULL
;
704 fms_skin_data
[i
].playback_aa_slot
= -1;
706 fms_skin
[i
].data
= &fms_skin_data
[i
];
707 fms_skin
[i
].display
= &screens
[i
];
708 /* Currently no seperate wps_state needed/possible
709 so use the only available ( "global" ) one */
710 fms_skin
[i
].state
= &wps_state
;
711 fms_skin
[i
].sync_data
= &fms_skin_sync_data
;
715 int radio_screen(void)
718 int ret_val
= GO_TO_ROOT
;
721 bool stereo
= false, last_stereo
= false;
722 bool update_screen
= true, restore
= true;
723 bool screen_freeze
= false;
724 bool keep_playing
= false;
726 #ifdef FM_RECORD_DBLPRE
727 int lastbutton
= BUTTON_NONE
;
728 unsigned long rec_lastclick
= 0;
730 #if CONFIG_CODEC != SWCODEC
731 bool have_recorded
= false;
732 int timeout
= current_tick
+ HZ
/10;
733 unsigned int last_seconds
= 0;
735 unsigned int seconds
= 0;
736 struct audio_recording_options rec_options
;
738 #endif /* CONFIG_CODEC != SWCODEC */
739 #ifndef HAVE_NOISY_IDLE_MODE
740 int button_timeout
= current_tick
+ (2*HZ
);
743 /* change status to "in screen" */
748 radio_load_presets(global_settings
.fmr_file
);
751 for(i
=0;i
<MAX_RADIOART_IMAGES
;i
++)
753 radioart
[i
].handle
= -1;
754 radioart
[i
].name
[0] = '\0';
756 add_event(PLAYBACK_EVENT_START_PLAYBACK
, true, playback_restarting_handler
);
759 if(radio_status
== FMRADIO_OFF
)
764 #if CONFIG_CODEC != SWCODEC
765 if(rec_create_directory() > 0)
766 have_recorded
= true;
768 audio_init_recording(talk_get_bufsize());
770 sound_settings_apply();
771 /* Yes, we use the D/A for monitoring */
772 peak_meter_playback(true);
774 peak_meter_enable(true);
776 rec_init_recording_options(&rec_options
);
777 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
778 rec_set_recording_options(&rec_options
);
780 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
781 sound_default(SOUND_RIGHT_GAIN
), AUDIO_GAIN_LINEIN
);
783 #endif /* CONFIG_CODEC != SWCODEC */
784 #endif /* ndef SIMULATOR */
787 #if CONFIG_CODEC == SWCODEC
788 audio_set_input_source(AUDIO_SRC_FMRADIO
,
789 (radio_status
== FMRADIO_PAUSED
) ?
790 SRCF_FMRADIO_PAUSED
: SRCF_FMRADIO_PLAYING
);
792 if (radio_status
== FMRADIO_OFF
)
796 if(num_presets
< 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN
)))
799 curr_preset
= find_preset(curr_freq
);
800 if(curr_preset
!= -1)
801 radio_mode
= RADIO_PRESET_MODE
;
803 #ifndef HAVE_NOISY_IDLE_MODE
811 curr_freq
= step_freq(curr_freq
, search_dir
);
812 update_screen
= true;
814 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
816 curr_preset
= find_preset(curr_freq
);
817 remember_frequency();
829 button
= skin_wait_for_action(fms_skin
, CONTEXT_FM
,
830 update_screen
? TIMEOUT_NOBLOCK
: HZ
);
832 #ifndef HAVE_NOISY_IDLE_MODE
833 if (button
!= ACTION_NONE
)
835 cpu_idle_mode(false);
836 button_timeout
= current_tick
+ (2*HZ
);
842 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
843 if(audio_status() == AUDIO_STATUS_RECORD
)
853 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
855 if(filepreset
[0] == '\0')
858 radio_save_presets();
862 update_screen
= true;
866 case ACTION_FM_RECORD
:
867 #ifdef FM_RECORD_DBLPRE
868 if (lastbutton
!= ACTION_FM_RECORD_DBLPRE
)
873 if (current_tick
- rec_lastclick
> HZ
/2)
875 rec_lastclick
= current_tick
;
878 #endif /* FM_RECORD_DBLPRE */
880 if(audio_status() == AUDIO_STATUS_RECORD
)
882 rec_command(RECORDING_CMD_START_NEWFILE
);
883 update_screen
= true;
887 have_recorded
= true;
888 rec_command(RECORDING_CMD_START
);
889 update_screen
= true;
891 #endif /* SIMULATOR */
894 #endif /* #ifdef FM_RECORD */
897 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
898 if(audio_status() == AUDIO_STATUS_RECORD
)
903 ret_val
= GO_TO_ROOT
;
906 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
908 if(filepreset
[0] == '\0')
911 radio_save_presets();
917 case ACTION_STD_PREV
:
918 case ACTION_STD_NEXT
:
919 next_station(button
== ACTION_STD_PREV
? -1 : 1);
921 update_screen
= true;
925 case ACTION_STD_PREVREPEAT
:
926 case ACTION_STD_NEXTREPEAT
:
928 int dir
= search_dir
;
929 search_dir
= button
== ACTION_STD_PREVREPEAT
? -1 : 1;
930 if (radio_mode
!= RADIO_SCAN_MODE
)
932 next_preset(search_dir
);
934 update_screen
= true;
939 /* Starting auto scan */
940 tuner_set(RADIO_MUTE
, 1);
941 update_screen
= true;
946 case ACTION_SETTINGS_INC
:
947 case ACTION_SETTINGS_INCREPEAT
:
948 global_settings
.volume
++;
950 update_screen
= true;
953 case ACTION_SETTINGS_DEC
:
954 case ACTION_SETTINGS_DECREPEAT
:
955 global_settings
.volume
--;
957 update_screen
= true;
961 if (radio_status
== FMRADIO_PLAYING
)
966 update_screen
= true;
972 fms_fix_displays(FMS_EXIT
);
974 curr_preset
= find_preset(curr_freq
);
975 update_screen
= true;
980 case ACTION_FM_PRESET
:
983 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
984 update_screen
= true;
987 fms_fix_displays(FMS_EXIT
);
988 handle_radio_presets();
989 update_screen
= true;
992 #endif /* FM_PRESET */
995 case ACTION_FM_FREEZE
:
998 splash(HZ
, str(LANG_FM_FREEZE
));
999 screen_freeze
= true;
1003 update_screen
= true;
1004 screen_freeze
= false;
1007 #endif /* FM_FREEZE */
1009 case SYS_USB_CONNECTED
:
1010 #if CONFIG_CODEC != SWCODEC
1011 /* Only accept USB connection when not recording */
1012 if(audio_status() != AUDIO_STATUS_RECORD
)
1015 default_event_handler(SYS_USB_CONNECTED
);
1016 screen_freeze
= true; /* Cosmetic: makes sure the
1017 radio screen doesn't redraw */
1023 case ACTION_FM_MODE
:
1024 if(radio_mode
== RADIO_SCAN_MODE
)
1026 /* Force scan mode if there are no presets. */
1028 radio_mode
= RADIO_PRESET_MODE
;
1031 radio_mode
= RADIO_SCAN_MODE
;
1032 update_screen
= true;
1033 cond_talk_ids_fq(radio_mode
?
1034 LANG_PRESET
: LANG_RADIO_SCAN_MODE
);
1037 #endif /* FM_MODE */
1039 #ifdef FM_NEXT_PRESET
1040 case ACTION_FM_NEXT_PRESET
:
1043 update_screen
= true;
1048 #ifdef FM_PREV_PRESET
1049 case ACTION_FM_PREV_PRESET
:
1052 update_screen
= true;
1058 default_event_handler(button
);
1060 if (tuner_get(RADIO_EVENT
))
1061 update_screen
= true;
1063 if (!tuner_get(RADIO_PRESENT
))
1065 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
1066 if(audio_status() == AUDIO_STATUS_RECORD
)
1069 keep_playing
= false;
1071 ret_val
= GO_TO_ROOT
;
1074 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES
)))
1076 if(filepreset
[0] == '\0')
1079 radio_save_presets();
1083 /* Clear the preset list on exit. */
1084 clear_preset_list();
1087 } /*switch(button)*/
1089 #ifdef FM_RECORD_DBLPRE
1090 if (button
!= ACTION_NONE
)
1091 lastbutton
= button
;
1094 #if CONFIG_CODEC != SWCODEC
1100 /* Only display the peak meter when not recording */
1101 #if CONFIG_CODEC != SWCODEC
1102 if(TIME_AFTER(current_tick
, timeout
))
1104 timeout
= current_tick
+ HZ
;
1107 #endif /* CONFIG_CODEC == SWCODEC */
1109 /* keep "mono" from always being displayed when paused */
1110 if (radio_status
!= FMRADIO_PAUSED
)
1112 stereo
= tuner_get(RADIO_STEREO
) &&
1113 !global_settings
.fm_force_mono
;
1115 if(stereo
!= last_stereo
)
1117 update_screen
= true;
1118 last_stereo
= stereo
;
1123 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
1124 seconds
= audio_recorded_time() / HZ
;
1125 if (update_screen
|| seconds
> last_seconds
|| restore
)
1127 last_seconds
= seconds
;
1129 if (update_screen
|| restore
)
1133 fms_fix_displays(FMS_ENTER
);
1135 skin_update(&fms_skin
[i
], WPS_REFRESH_ALL
);
1139 update_screen
= false;
1141 if (global_settings
.talk_file
&& talk
1142 && radio_status
== FMRADIO_PAUSED
)
1145 bool enqueue
= false;
1146 if (radio_mode
== RADIO_SCAN_MODE
)
1148 talk_freq(curr_freq
, enqueue
);
1151 if (curr_preset
>= 0)
1152 talk_preset(curr_preset
, radio_mode
== RADIO_PRESET_MODE
,
1156 #if CONFIG_CODEC != SWCODEC
1157 if(audio_status() & AUDIO_STATUS_ERROR
)
1163 #ifndef HAVE_NOISY_IDLE_MODE
1164 if (TIME_AFTER(current_tick
, button_timeout
))
1166 cpu_idle_mode(true);
1172 #if CONFIG_CODEC != SWCODEC
1173 if(audio_status() & AUDIO_STATUS_ERROR
)
1175 splash(0, str(LANG_DISK_FULL
));
1176 audio_error_clear();
1180 button
= get_action(CONTEXT_FM
, TIMEOUT_BLOCK
);
1181 if(button
== ACTION_FM_STOP
)
1186 audio_init_playback();
1187 #endif /* CONFIG_CODEC != SWCODEC */
1189 sound_settings_apply();
1190 #endif /* SIMULATOR */
1194 /* Catch FMRADIO_PLAYING status for the sim. */
1196 #if CONFIG_CODEC != SWCODEC
1197 /* Enable the Left and right A/D Converter */
1198 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN
),
1199 sound_default(SOUND_RIGHT_GAIN
),
1201 mas_codec_writereg(6, 0x4000);
1204 #endif /* SIMULATOR */
1208 #if CONFIG_CODEC == SWCODEC
1209 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
1215 #ifndef HAVE_NOISY_IDLE_MODE
1216 cpu_idle_mode(false);
1218 fms_fix_displays(FMS_EXIT
);
1220 #if CONFIG_CODEC != SWCODEC
1221 return have_recorded
;
1225 } /* radio_screen */
1227 static void radio_save_presets(void)
1232 fd
= creat(filepreset
, 0666);
1235 for(i
= 0;i
< num_presets
;i
++)
1237 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
1241 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
1242 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
1243 presets_changed
= false;
1247 splash(HZ
, ID2P(LANG_FM_PRESET_SAVE_FAILED
));
1251 void radio_load_presets(char *filename
)
1261 memset(presets
, 0, sizeof(presets
));
1264 /* No Preset in configuration. */
1265 if(filename
[0] == '\0')
1267 filepreset
[0] = '\0';
1270 /* Temporary preset, loaded until player shuts down. */
1271 else if(filename
[0] == '/')
1272 strlcpy(filepreset
, filename
, sizeof(filepreset
));
1273 /* Preset from default directory. */
1275 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
1276 FMPRESET_PATH
, filename
);
1278 fd
= open_utf8(filepreset
, O_RDONLY
);
1281 while(!done
&& num_presets
< MAX_PRESETS
)
1283 rc
= read_line(fd
, buf
, 128);
1286 if(settings_parseline(buf
, &freq
, &name
))
1289 if(f
) /* For backwards compatibility */
1291 struct fmstation
* const fms
= &presets
[num_presets
];
1293 strlcpy(fms
->name
, name
, MAX_FMPRESET_LEN
+1);
1303 else /* invalid file name? */
1304 filepreset
[0] = '\0';
1306 presets_loaded
= num_presets
> 0;
1307 presets_changed
= false;
1311 static int radio_add_preset(void)
1313 char buf
[MAX_FMPRESET_LEN
+ 1];
1315 if(num_presets
< MAX_PRESETS
)
1319 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1321 struct fmstation
* const fms
= &presets
[num_presets
];
1322 strcpy(fms
->name
, buf
);
1323 fms
->frequency
= curr_freq
;
1325 presets_changed
= true;
1326 presets_loaded
= num_presets
> 0;
1332 splash(HZ
, ID2P(LANG_FM_NO_FREE_PRESETS
));
1337 /* needed to know which preset we are edit/delete-ing */
1338 static int selected_preset
= -1;
1339 static int radio_edit_preset(void)
1341 char buf
[MAX_FMPRESET_LEN
+ 1];
1343 if (num_presets
> 0)
1345 struct fmstation
* const fms
= &presets
[selected_preset
];
1347 strcpy(buf
, fms
->name
);
1349 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
1351 strcpy(fms
->name
, buf
);
1352 presets_changed
= true;
1359 static int radio_delete_preset(void)
1361 if (num_presets
> 0)
1363 struct fmstation
* const fms
= &presets
[selected_preset
];
1365 if (selected_preset
>= --num_presets
)
1366 selected_preset
= num_presets
- 1;
1368 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
1371 if (curr_preset
>= num_presets
)
1375 /* Don't ask to save when all presets are deleted. */
1376 presets_changed
= num_presets
> 0;
1378 if (!presets_changed
)
1380 /* The preset list will be cleared, switch to Scan Mode. */
1381 radio_mode
= RADIO_SCAN_MODE
;
1383 presets_loaded
= false;
1389 static int load_preset_list(void)
1391 return !rockbox_browse(FMPRESET_PATH
, SHOW_FMR
);
1394 static int save_preset_list(void)
1398 bool bad_file_name
= true;
1400 if(!dir_exists(FMPRESET_PATH
)) /* Check if there is preset folder */
1401 mkdir(FMPRESET_PATH
);
1403 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
1404 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
1406 while(bad_file_name
)
1408 if(!kbd_input(filepreset
, sizeof(filepreset
)))
1410 /* check the name: max MAX_FILENAME (20) chars */
1414 p1
= strrchr(filepreset
, '/');
1416 while((p1
) && (*p2
) && (*p2
!= '.'))
1418 len
= (int)(p2
-p1
) - 1;
1419 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
1421 /* no slash, too long or too short */
1422 splash(HZ
, ID2P(LANG_INVALID_FILENAME
));
1426 /* add correct extension (easier to always write)
1427 at this point, p2 points to 0 or the extension dot */
1429 strcat(filepreset
,".fmr");
1430 bad_file_name
= false;
1431 radio_save_presets();
1442 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
1447 static int clear_preset_list(void)
1449 /* Clear all the preset entries */
1450 memset(presets
, 0, sizeof (presets
));
1453 presets_loaded
= false;
1454 /* The preset list will be cleared switch to Scan Mode. */
1455 radio_mode
= RADIO_SCAN_MODE
;
1457 presets_changed
= false; /* Don't ask to save when clearing the list. */
1462 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1463 ID2P(LANG_FM_EDIT_PRESET
),
1464 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
1465 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
1466 ID2P(LANG_FM_DELETE_PRESET
),
1467 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
1468 static int radio_preset_callback(int action
,
1469 const struct menu_item_ex
*this_item
)
1471 if (action
== ACTION_STD_OK
)
1472 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
1476 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_PRESET
),
1477 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
1478 &radio_delete_preset_item
);
1479 /* present a list of preset stations */
1480 static const char* presets_get_name(int selected_item
, void *data
,
1481 char *buffer
, size_t buffer_len
)
1484 struct fmstation
*p
= &presets
[selected_item
];
1487 int freq
= p
->frequency
/ 10000;
1488 int frac
= freq
% 100;
1490 snprintf(buffer
, buffer_len
,
1491 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
1495 static int presets_speak_name(int selected_item
, void * data
)
1498 talk_preset(selected_item
, true, false);
1502 static int handle_radio_presets(void)
1504 struct gui_synclist lists
;
1506 int action
= ACTION_NONE
;
1507 #ifdef HAVE_BUTTONBAR
1508 struct gui_buttonbar buttonbar
;
1511 if(presets_loaded
== false)
1514 #ifdef HAVE_BUTTONBAR
1515 gui_buttonbar_init(&buttonbar
);
1516 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
1517 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
1518 str(LANG_FM_BUTTONBAR_EXIT
),
1519 str(LANG_FM_BUTTONBAR_ACTION
));
1520 gui_buttonbar_draw(&buttonbar
);
1522 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1, NULL
);
1523 gui_synclist_set_title(&lists
, str(LANG_PRESET
), NOICON
);
1524 gui_synclist_set_icon_callback(&lists
, NULL
);
1525 if(global_settings
.talk_file
)
1526 gui_synclist_set_voice_callback(&lists
, presets_speak_name
);
1527 gui_synclist_set_nb_items(&lists
, num_presets
);
1528 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
1529 gui_synclist_speak_item(&lists
);
1533 gui_synclist_draw(&lists
);
1534 list_do_action(CONTEXT_STD
, TIMEOUT_BLOCK
,
1535 &lists
, &action
, LIST_WRAP_UNLESS_HELD
);
1538 case ACTION_STD_MENU
:
1539 if (radio_add_preset())
1541 gui_synclist_set_nb_items(&lists
, num_presets
);
1542 gui_synclist_select_item(&lists
, num_presets
- 1);
1545 case ACTION_STD_CANCEL
:
1549 curr_preset
= gui_synclist_get_sel_pos(&lists
);
1550 curr_freq
= presets
[curr_preset
].frequency
;
1552 remember_frequency();
1556 case ACTION_STD_CONTEXT
:
1557 selected_preset
= gui_synclist_get_sel_pos(&lists
);
1558 do_menu(&handle_radio_preset_menu
, NULL
, NULL
, false);
1559 gui_synclist_set_nb_items(&lists
, num_presets
);
1560 gui_synclist_select_item(&lists
, selected_preset
);
1561 gui_synclist_speak_item(&lists
);
1564 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
1571 void toggle_mono_mode(bool mono
)
1573 tuner_set(RADIO_FORCE_MONO
, mono
);
1576 void set_radio_region(int region
)
1578 #ifdef HAVE_RADIO_REGION
1579 tuner_set(RADIO_REGION
, region
);
1582 remember_frequency();
1586 MENUITEM_SETTING(set_region
, &global_settings
.fm_region
, NULL
);
1587 MENUITEM_SETTING(force_mono
, &global_settings
.fm_force_mono
, NULL
);
1590 static char* get_mode_text(int selected_item
, void * data
, char *buffer
)
1592 (void)selected_item
;
1594 snprintf(buffer
, MAX_PATH
, "%s %s", str(LANG_MODE
),
1595 radio_mode
? str(LANG_PRESET
) :
1596 str(LANG_RADIO_SCAN_MODE
));
1599 static int toggle_radio_mode(void)
1601 radio_mode
= (radio_mode
== RADIO_SCAN_MODE
) ?
1602 RADIO_PRESET_MODE
: RADIO_SCAN_MODE
;
1605 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item
, 0,
1606 toggle_radio_mode
, NULL
,
1607 get_mode_text
, NULL
, NULL
, NULL
, Icon_NOICON
);
1610 static int scan_presets(void *viewports
)
1612 bool do_scan
= true;
1614 struct viewport
*vp
= (struct viewport
*)viewports
;
1617 screens
[i
].set_viewport(vp
?&vp
[i
]:NULL
);
1618 if(num_presets
> 0) /* Do that to avoid 2 questions. */
1619 do_scan
= yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS
));
1623 const struct fm_region_data
* const fmr
=
1624 &fm_region_data
[global_settings
.fm_region
];
1626 curr_freq
= fmr
->freq_min
;
1628 memset(presets
, 0, sizeof(presets
));
1630 tuner_set(RADIO_MUTE
, 1);
1632 while(curr_freq
<= fmr
->freq_max
)
1635 if(num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
1638 freq
= curr_freq
/ 10000;
1642 splashf(0, str(LANG_FM_SCANNING
), freq
, frac
);
1644 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
1647 presets
[num_presets
].name
[0] = '\0';
1648 presets
[num_presets
].frequency
= curr_freq
;
1652 curr_freq
+= fmr
->freq_step
;
1655 if (radio_status
== FMRADIO_PLAYING
)
1656 tuner_set(RADIO_MUTE
, 0);
1658 presets_changed
= true;
1662 screens
[i
].clear_viewport();
1663 screens
[i
].update_viewport();
1668 curr_freq
= presets
[0].frequency
;
1669 radio_mode
= RADIO_PRESET_MODE
;
1670 presets_loaded
= true;
1675 /* Wrap it to beginning or we'll be past end of band */
1676 presets_loaded
= false;
1684 #ifdef HAVE_RECORDING
1686 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1687 #define FM_RECORDING_SCREEN
1688 static int fm_recording_screen(void)
1692 /* switch recording source to FMRADIO for the duration */
1693 int rec_source
= global_settings
.rec_source
;
1694 global_settings
.rec_source
= AUDIO_SRC_FMRADIO
;
1695 ret
= recording_screen(true);
1697 /* safe to reset as changing sources is prohibited here */
1698 global_settings
.rec_source
= rec_source
;
1703 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1705 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1706 #define FM_RECORDING_SETTINGS
1707 static int fm_recording_settings(void)
1709 bool ret
= recording_menu(true);
1711 #if CONFIG_CODEC != SWCODEC
1714 struct audio_recording_options rec_options
;
1715 rec_init_recording_options(&rec_options
);
1716 rec_options
.rec_source
= AUDIO_SRC_LINEIN
;
1717 rec_set_recording_options(&rec_options
);
1724 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1725 #endif /* HAVE_RECORDING */
1727 #ifdef FM_RECORDING_SCREEN
1728 MENUITEM_FUNCTION(recscreen_item
, 0, ID2P(LANG_RECORDING
),
1729 fm_recording_screen
, NULL
, NULL
, Icon_Recording
);
1731 #ifdef FM_RECORDING_SETTINGS
1732 MENUITEM_FUNCTION(recsettings_item
, 0, ID2P(LANG_RECORDING_SETTINGS
),
1733 fm_recording_settings
, NULL
, NULL
, Icon_Recording
);
1736 MENUITEM_FUNCTION(radio_presets_item
, 0, ID2P(LANG_PRESET
),
1737 handle_radio_presets
, NULL
, NULL
, Icon_NOICON
);
1739 #ifndef FM_PRESET_ADD
1740 MENUITEM_FUNCTION(radio_addpreset_item
, 0, ID2P(LANG_FM_ADD_PRESET
),
1741 radio_add_preset
, NULL
, NULL
, Icon_NOICON
);
1745 MENUITEM_FUNCTION(presetload_item
, 0, ID2P(LANG_FM_PRESET_LOAD
),
1746 load_preset_list
, NULL
, NULL
, Icon_NOICON
);
1747 MENUITEM_FUNCTION(presetsave_item
, 0, ID2P(LANG_FM_PRESET_SAVE
),
1748 save_preset_list
, NULL
, NULL
, Icon_NOICON
);
1749 MENUITEM_FUNCTION(presetclear_item
, 0, ID2P(LANG_FM_PRESET_CLEAR
),
1750 clear_preset_list
, NULL
, NULL
, Icon_NOICON
);
1751 MENUITEM_FUNCTION(scan_presets_item
, MENU_FUNC_USEPARAM
,
1752 ID2P(LANG_FM_SCAN_PRESETS
),
1753 scan_presets
, NULL
, NULL
, Icon_NOICON
);
1755 MAKE_MENU(radio_settings_menu
, ID2P(LANG_FM_MENU
), NULL
,
1758 &radio_presets_item
,
1760 #ifndef FM_PRESET_ADD
1761 &radio_addpreset_item
,
1763 &presetload_item
, &presetsave_item
, &presetclear_item
,
1768 &set_region
, &sound_settings
,
1769 #ifdef FM_RECORDING_SCREEN
1772 #ifdef FM_RECORDING_SETTINGS
1775 &scan_presets_item
);
1776 /* main menu of the radio screen */
1777 static bool radio_menu(void)
1779 return do_menu(&radio_settings_menu
, NULL
, NULL
, false) ==