diff options
Diffstat (limited to 'apps/radio/radio.c')
-rw-r--r-- | apps/radio/radio.c | 1042 |
1 files changed, 1042 insertions, 0 deletions
diff --git a/apps/radio/radio.c b/apps/radio/radio.c new file mode 100644 index 0000000000..b3540610f1 --- /dev/null +++ b/apps/radio/radio.c | |||
@@ -0,0 +1,1042 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2003 Linus Nielsen Feltzing | ||
11 | * | ||
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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "config.h" | ||
23 | #include <stdio.h> | ||
24 | #include <stdbool.h> | ||
25 | #include <stdlib.h> | ||
26 | #include "mas.h" | ||
27 | #include "settings.h" | ||
28 | #include "button.h" | ||
29 | #include "status.h" | ||
30 | #include "thread.h" | ||
31 | #include "audio.h" | ||
32 | #include "mp3_playback.h" | ||
33 | #include "ctype.h" | ||
34 | #include "file.h" | ||
35 | #include "general.h" | ||
36 | #include "errno.h" | ||
37 | #include "string-extra.h" | ||
38 | #include "system.h" | ||
39 | #include "radio.h" | ||
40 | #include "menu.h" | ||
41 | #include "misc.h" | ||
42 | #include "keyboard.h" | ||
43 | #include "screens.h" | ||
44 | #include "peakmeter.h" | ||
45 | #include "lang.h" | ||
46 | #include "font.h" | ||
47 | #include "sound_menu.h" | ||
48 | #ifdef HAVE_RECORDING | ||
49 | #include "recording.h" | ||
50 | #endif | ||
51 | #ifdef IPOD_ACCESSORY_PROTOCOL | ||
52 | #include "iap.h" | ||
53 | #endif | ||
54 | #include "appevents.h" | ||
55 | #include "talk.h" | ||
56 | #include "tuner.h" | ||
57 | #include "power.h" | ||
58 | #include "sound.h" | ||
59 | #include "screen_access.h" | ||
60 | #include "splash.h" | ||
61 | #include "yesno.h" | ||
62 | #include "buttonbar.h" | ||
63 | #include "tree.h" | ||
64 | #include "dir.h" | ||
65 | #include "action.h" | ||
66 | #include "list.h" | ||
67 | #include "menus/exported_menus.h" | ||
68 | #include "root_menu.h" | ||
69 | #include "viewport.h" | ||
70 | #include "skin_engine/skin_engine.h" | ||
71 | #include "statusbar-skinned.h" | ||
72 | #include "buffering.h" | ||
73 | |||
74 | #if CONFIG_TUNER | ||
75 | |||
76 | #if CONFIG_KEYPAD == RECORDER_PAD | ||
77 | #define FM_RECORD | ||
78 | #define FM_PRESET_ADD | ||
79 | #define FM_PRESET_ACTION | ||
80 | #define FM_PRESET | ||
81 | #define FM_MODE | ||
82 | |||
83 | #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) | ||
84 | #define FM_PRESET | ||
85 | #define FM_MODE | ||
86 | #define FM_NEXT_PRESET | ||
87 | #define FM_PREV_PRESET | ||
88 | |||
89 | #elif CONFIG_KEYPAD == IRIVER_H10_PAD | ||
90 | #define FM_PRESET | ||
91 | #define FM_MODE | ||
92 | |||
93 | #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) | ||
94 | #define FM_PRESET | ||
95 | #define FM_MODE | ||
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 | ||
100 | |||
101 | #elif CONFIG_KEYPAD == ONDIO_PAD | ||
102 | #define FM_RECORD_DBLPRE | ||
103 | #define FM_RECORD | ||
104 | #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD) | ||
105 | #define FM_MENU | ||
106 | #define FM_PRESET | ||
107 | #define FM_STOP | ||
108 | #define FM_MODE | ||
109 | #define FM_EXIT | ||
110 | #define FM_PLAY | ||
111 | |||
112 | #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD) | ||
113 | #define FM_PRESET | ||
114 | #define FM_MODE | ||
115 | |||
116 | #elif (CONFIG_KEYPAD == COWON_D2_PAD) | ||
117 | #define FM_MENU | ||
118 | #define FM_PRESET | ||
119 | #define FM_STOP | ||
120 | #define FM_MODE | ||
121 | #define FM_EXIT | ||
122 | #define FM_PLAY | ||
123 | |||
124 | #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ | ||
125 | (CONFIG_KEYPAD == IPOD_1G2G_PAD) | ||
126 | #define FM_MENU | ||
127 | #define FM_STOP | ||
128 | #define FM_EXIT | ||
129 | #define FM_PLAY | ||
130 | #define FM_MODE | ||
131 | |||
132 | #endif | ||
133 | |||
134 | /* presets.c needs these so keep unstatic or redo the whole thing! */ | ||
135 | int curr_freq; /* current frequency in Hz */ | ||
136 | /* these are all in presets.c... someone PLEASE rework this ! */ | ||
137 | int handle_radio_presets(void); | ||
138 | static bool radio_menu(void); | ||
139 | int radio_add_preset(void); | ||
140 | int save_preset_list(void); | ||
141 | int load_preset_list(void); | ||
142 | int clear_preset_list(void); | ||
143 | void next_preset(int direction); | ||
144 | void set_current_preset(int preset); | ||
145 | int scan_presets(void *viewports); | ||
146 | int find_preset(int freq); | ||
147 | void radio_save_presets(void); | ||
148 | bool has_presets_changed(void); | ||
149 | void talk_preset(int preset, bool fallback, bool enqueue); | ||
150 | void presets_save(void); | ||
151 | |||
152 | |||
153 | |||
154 | int radio_mode = RADIO_SCAN_MODE; | ||
155 | static int search_dir = 0; | ||
156 | |||
157 | static int radio_status = FMRADIO_OFF; | ||
158 | static bool in_screen = false; | ||
159 | |||
160 | |||
161 | static void radio_off(void); | ||
162 | |||
163 | bool radio_scan_mode(void) | ||
164 | { | ||
165 | return radio_mode == RADIO_SCAN_MODE; | ||
166 | } | ||
167 | |||
168 | bool radio_is_stereo(void) | ||
169 | { | ||
170 | return tuner_get(RADIO_STEREO) && !global_settings.fm_force_mono; | ||
171 | } | ||
172 | int radio_current_frequency(void) | ||
173 | { | ||
174 | return curr_freq; | ||
175 | } | ||
176 | |||
177 | /* Function to manipulate all yesno dialogues. | ||
178 | This function needs the output text as an argument. */ | ||
179 | bool yesno_pop(const char* text) | ||
180 | { | ||
181 | int i; | ||
182 | const char *lines[]={text}; | ||
183 | const struct text_message message={lines, 1}; | ||
184 | bool ret = (gui_syncyesno_run(&message,NULL,NULL)== YESNO_YES); | ||
185 | FOR_NB_SCREENS(i) | ||
186 | screens[i].clear_viewport(); | ||
187 | return ret; | ||
188 | } | ||
189 | |||
190 | void radio_init(void) | ||
191 | { | ||
192 | tuner_init(); | ||
193 | radio_off(); | ||
194 | #ifdef HAVE_ALBUMART | ||
195 | radioart_init(false); | ||
196 | #endif | ||
197 | } | ||
198 | |||
199 | int get_radio_status(void) | ||
200 | { | ||
201 | return radio_status; | ||
202 | } | ||
203 | |||
204 | bool in_radio_screen(void) | ||
205 | { | ||
206 | return in_screen; | ||
207 | } | ||
208 | |||
209 | /* TODO: Move some more of the control functionality to firmware | ||
210 | and clean up the mess */ | ||
211 | |||
212 | /* secret flag for starting paused - prevents unmute */ | ||
213 | #define FMRADIO_START_PAUSED 0x8000 | ||
214 | void radio_start(void) | ||
215 | { | ||
216 | const struct fm_region_data *fmr; | ||
217 | bool start_paused; | ||
218 | |||
219 | if(radio_status == FMRADIO_PLAYING) | ||
220 | return; | ||
221 | |||
222 | fmr = &fm_region_data[global_settings.fm_region]; | ||
223 | |||
224 | start_paused = radio_status & FMRADIO_START_PAUSED; | ||
225 | /* clear flag before any yielding */ | ||
226 | radio_status &= ~FMRADIO_START_PAUSED; | ||
227 | |||
228 | if(radio_status == FMRADIO_OFF) | ||
229 | tuner_power(true); | ||
230 | |||
231 | curr_freq = global_status.last_frequency * fmr->freq_step + fmr->freq_min; | ||
232 | |||
233 | tuner_set(RADIO_SLEEP, 0); /* wake up the tuner */ | ||
234 | |||
235 | if(radio_status == FMRADIO_OFF) | ||
236 | { | ||
237 | #ifdef HAVE_RADIO_REGION | ||
238 | tuner_set(RADIO_REGION, global_settings.fm_region); | ||
239 | #endif | ||
240 | tuner_set(RADIO_FORCE_MONO, global_settings.fm_force_mono); | ||
241 | } | ||
242 | |||
243 | tuner_set(RADIO_FREQUENCY, curr_freq); | ||
244 | |||
245 | #ifdef HAVE_RADIO_MUTE_TIMEOUT | ||
246 | { | ||
247 | unsigned long mute_timeout = current_tick + HZ; | ||
248 | if (radio_status != FMRADIO_OFF) | ||
249 | { | ||
250 | /* paused */ | ||
251 | mute_timeout += HZ; | ||
252 | } | ||
253 | |||
254 | while(!tuner_get(RADIO_STEREO) && !tuner_get(RADIO_TUNED)) | ||
255 | { | ||
256 | if(TIME_AFTER(current_tick, mute_timeout)) | ||
257 | break; | ||
258 | yield(); | ||
259 | } | ||
260 | } | ||
261 | #endif | ||
262 | |||
263 | /* keep radio from sounding initially */ | ||
264 | if(!start_paused) | ||
265 | tuner_set(RADIO_MUTE, 0); | ||
266 | |||
267 | radio_status = FMRADIO_PLAYING; | ||
268 | } /* radio_start */ | ||
269 | |||
270 | void radio_pause(void) | ||
271 | { | ||
272 | if(radio_status == FMRADIO_PAUSED) | ||
273 | return; | ||
274 | |||
275 | if(radio_status == FMRADIO_OFF) | ||
276 | { | ||
277 | radio_status |= FMRADIO_START_PAUSED; | ||
278 | radio_start(); | ||
279 | } | ||
280 | |||
281 | tuner_set(RADIO_MUTE, 1); | ||
282 | tuner_set(RADIO_SLEEP, 1); | ||
283 | |||
284 | radio_status = FMRADIO_PAUSED; | ||
285 | } /* radio_pause */ | ||
286 | |||
287 | static void radio_off(void) | ||
288 | { | ||
289 | tuner_set(RADIO_MUTE, 1); | ||
290 | tuner_set(RADIO_SLEEP, 1); /* low power mode, if available */ | ||
291 | radio_status = FMRADIO_OFF; | ||
292 | tuner_power(false); /* status update, power off if avail. */ | ||
293 | } | ||
294 | |||
295 | void radio_stop(void) | ||
296 | { | ||
297 | if(radio_status == FMRADIO_OFF) | ||
298 | return; | ||
299 | |||
300 | radio_off(); | ||
301 | } /* radio_stop */ | ||
302 | |||
303 | bool radio_hardware_present(void) | ||
304 | { | ||
305 | return tuner_get(RADIO_PRESENT); | ||
306 | } | ||
307 | |||
308 | /* Keep freq on the grid for the current region */ | ||
309 | int snap_freq_to_grid(int freq) | ||
310 | { | ||
311 | const struct fm_region_data * const fmr = | ||
312 | &fm_region_data[global_settings.fm_region]; | ||
313 | |||
314 | /* Range clamp if out of range or just round to nearest */ | ||
315 | if (freq < fmr->freq_min) | ||
316 | freq = fmr->freq_min; | ||
317 | else if (freq > fmr->freq_max) | ||
318 | freq = fmr->freq_max; | ||
319 | else | ||
320 | freq = (freq - fmr->freq_min + fmr->freq_step/2) / | ||
321 | fmr->freq_step * fmr->freq_step + fmr->freq_min; | ||
322 | |||
323 | return freq; | ||
324 | } | ||
325 | |||
326 | void remember_frequency(void) | ||
327 | { | ||
328 | const struct fm_region_data * const fmr = | ||
329 | &fm_region_data[global_settings.fm_region]; | ||
330 | global_status.last_frequency = (curr_freq - fmr->freq_min) | ||
331 | / fmr->freq_step; | ||
332 | status_save(); | ||
333 | } | ||
334 | |||
335 | /* Step to the next or previous frequency */ | ||
336 | static int step_freq(int freq, int direction) | ||
337 | { | ||
338 | const struct fm_region_data * const fmr = | ||
339 | &fm_region_data[global_settings.fm_region]; | ||
340 | |||
341 | freq += direction*fmr->freq_step; | ||
342 | |||
343 | /* Wrap first or snapping to grid will not let us on the band extremes */ | ||
344 | if (freq > fmr->freq_max) | ||
345 | freq = direction > 0 ? fmr->freq_min : fmr->freq_max; | ||
346 | else if (freq < fmr->freq_min) | ||
347 | freq = direction < 0 ? fmr->freq_max : fmr->freq_min; | ||
348 | else | ||
349 | freq = snap_freq_to_grid(freq); | ||
350 | |||
351 | return freq; | ||
352 | } | ||
353 | |||
354 | /* Step to the next or previous station */ | ||
355 | void next_station(int direction) | ||
356 | { | ||
357 | if (direction != 0 && radio_mode != RADIO_SCAN_MODE) | ||
358 | { | ||
359 | next_preset(direction); | ||
360 | return; | ||
361 | } | ||
362 | |||
363 | curr_freq = step_freq(curr_freq, direction); | ||
364 | |||
365 | if (radio_status == FMRADIO_PLAYING) | ||
366 | tuner_set(RADIO_MUTE, 1); | ||
367 | |||
368 | tuner_set(RADIO_FREQUENCY, curr_freq); | ||
369 | |||
370 | if (radio_status == FMRADIO_PLAYING) | ||
371 | tuner_set(RADIO_MUTE, 0); | ||
372 | |||
373 | set_current_preset(find_preset(curr_freq)); | ||
374 | remember_frequency(); | ||
375 | } | ||
376 | |||
377 | /* Ends an in-progress search */ | ||
378 | static void end_search(void) | ||
379 | { | ||
380 | if (search_dir != 0 && radio_status == FMRADIO_PLAYING) | ||
381 | tuner_set(RADIO_MUTE, 0); | ||
382 | search_dir = 0; | ||
383 | } | ||
384 | |||
385 | /* Speak a frequency. */ | ||
386 | void talk_freq(int freq, bool enqueue) | ||
387 | { | ||
388 | freq /= 10000; | ||
389 | talk_number(freq / 100, enqueue); | ||
390 | talk_id(LANG_POINT, true); | ||
391 | talk_number(freq % 100 / 10, true); | ||
392 | if (freq % 10) | ||
393 | talk_number(freq % 10, true); | ||
394 | } | ||
395 | |||
396 | |||
397 | int radio_screen(void) | ||
398 | { | ||
399 | bool done = false; | ||
400 | int ret_val = GO_TO_ROOT; | ||
401 | int button; | ||
402 | int i; | ||
403 | bool stereo = false, last_stereo = false; | ||
404 | bool update_screen = true, restore = true; | ||
405 | bool screen_freeze = false; | ||
406 | bool keep_playing = false; | ||
407 | bool talk = false; | ||
408 | #ifdef FM_RECORD_DBLPRE | ||
409 | int lastbutton = BUTTON_NONE; | ||
410 | unsigned long rec_lastclick = 0; | ||
411 | #endif | ||
412 | #if CONFIG_CODEC != SWCODEC | ||
413 | bool have_recorded = false; | ||
414 | int timeout = current_tick + HZ/10; | ||
415 | unsigned int last_seconds = 0; | ||
416 | #ifndef SIMULATOR | ||
417 | unsigned int seconds = 0; | ||
418 | struct audio_recording_options rec_options; | ||
419 | #endif | ||
420 | #endif /* CONFIG_CODEC != SWCODEC */ | ||
421 | #ifndef HAVE_NOISY_IDLE_MODE | ||
422 | int button_timeout = current_tick + (2*HZ); | ||
423 | #endif | ||
424 | |||
425 | /* change status to "in screen" */ | ||
426 | in_screen = true; | ||
427 | |||
428 | if(radio_preset_count() <= 0) | ||
429 | { | ||
430 | radio_load_presets(global_settings.fmr_file); | ||
431 | } | ||
432 | #ifdef HAVE_ALBUMART | ||
433 | radioart_init(true); | ||
434 | #endif | ||
435 | |||
436 | if(radio_status == FMRADIO_OFF) | ||
437 | audio_stop(); | ||
438 | |||
439 | #ifndef SIMULATOR | ||
440 | |||
441 | #if CONFIG_CODEC != SWCODEC | ||
442 | if(rec_create_directory() > 0) | ||
443 | have_recorded = true; | ||
444 | |||
445 | audio_init_recording(talk_get_bufsize()); | ||
446 | |||
447 | sound_settings_apply(); | ||
448 | /* Yes, we use the D/A for monitoring */ | ||
449 | peak_meter_playback(true); | ||
450 | |||
451 | peak_meter_enable(true); | ||
452 | |||
453 | rec_init_recording_options(&rec_options); | ||
454 | rec_options.rec_source = AUDIO_SRC_LINEIN; | ||
455 | rec_set_recording_options(&rec_options); | ||
456 | |||
457 | audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN), | ||
458 | sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN); | ||
459 | |||
460 | #endif /* CONFIG_CODEC != SWCODEC */ | ||
461 | #endif /* ndef SIMULATOR */ | ||
462 | |||
463 | /* turn on radio */ | ||
464 | #if CONFIG_CODEC == SWCODEC | ||
465 | audio_set_input_source(AUDIO_SRC_FMRADIO, | ||
466 | (radio_status == FMRADIO_PAUSED) ? | ||
467 | SRCF_FMRADIO_PAUSED : SRCF_FMRADIO_PLAYING); | ||
468 | #else | ||
469 | if (radio_status == FMRADIO_OFF) | ||
470 | radio_start(); | ||
471 | #endif | ||
472 | |||
473 | if(radio_preset_count() < 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN))) | ||
474 | scan_presets(NULL); | ||
475 | |||
476 | set_current_preset(find_preset(curr_freq)); | ||
477 | if(radio_current_preset() != -1) | ||
478 | radio_mode = RADIO_PRESET_MODE; | ||
479 | |||
480 | #ifndef HAVE_NOISY_IDLE_MODE | ||
481 | cpu_idle_mode(true); | ||
482 | #endif | ||
483 | |||
484 | while(!done) | ||
485 | { | ||
486 | if(search_dir != 0) | ||
487 | { | ||
488 | curr_freq = step_freq(curr_freq, search_dir); | ||
489 | update_screen = true; | ||
490 | |||
491 | if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq)) | ||
492 | { | ||
493 | set_current_preset(find_preset(curr_freq)); | ||
494 | remember_frequency(); | ||
495 | end_search(); | ||
496 | talk = true; | ||
497 | } | ||
498 | trigger_cpu_boost(); | ||
499 | } | ||
500 | |||
501 | if (!update_screen) | ||
502 | { | ||
503 | cancel_cpu_boost(); | ||
504 | } | ||
505 | |||
506 | button = fms_do_button_loop(update_screen); | ||
507 | |||
508 | #ifndef HAVE_NOISY_IDLE_MODE | ||
509 | if (button != ACTION_NONE) | ||
510 | { | ||
511 | cpu_idle_mode(false); | ||
512 | button_timeout = current_tick + (2*HZ); | ||
513 | } | ||
514 | #endif | ||
515 | switch(button) | ||
516 | { | ||
517 | case ACTION_FM_STOP: | ||
518 | #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR) | ||
519 | if(audio_status() == AUDIO_STATUS_RECORD) | ||
520 | { | ||
521 | audio_stop(); | ||
522 | } | ||
523 | else | ||
524 | #endif | ||
525 | { | ||
526 | done = true; | ||
527 | if(has_presets_changed()) | ||
528 | { | ||
529 | if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES))) | ||
530 | { | ||
531 | presets_save(); | ||
532 | } | ||
533 | } | ||
534 | } | ||
535 | update_screen = true; | ||
536 | break; | ||
537 | |||
538 | #ifdef FM_RECORD | ||
539 | case ACTION_FM_RECORD: | ||
540 | #ifdef FM_RECORD_DBLPRE | ||
541 | if (lastbutton != ACTION_FM_RECORD_DBLPRE) | ||
542 | { | ||
543 | rec_lastclick = 0; | ||
544 | break; | ||
545 | } | ||
546 | if (current_tick - rec_lastclick > HZ/2) | ||
547 | { | ||
548 | rec_lastclick = current_tick; | ||
549 | break; | ||
550 | } | ||
551 | #endif /* FM_RECORD_DBLPRE */ | ||
552 | #ifndef SIMULATOR | ||
553 | if(audio_status() == AUDIO_STATUS_RECORD) | ||
554 | { | ||
555 | rec_command(RECORDING_CMD_START_NEWFILE); | ||
556 | update_screen = true; | ||
557 | } | ||
558 | else | ||
559 | { | ||
560 | have_recorded = true; | ||
561 | rec_command(RECORDING_CMD_START); | ||
562 | update_screen = true; | ||
563 | } | ||
564 | #endif /* SIMULATOR */ | ||
565 | last_seconds = 0; | ||
566 | break; | ||
567 | #endif /* #ifdef FM_RECORD */ | ||
568 | |||
569 | case ACTION_FM_EXIT: | ||
570 | #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR) | ||
571 | if(audio_status() == AUDIO_STATUS_RECORD) | ||
572 | audio_stop(); | ||
573 | #endif | ||
574 | keep_playing = true; | ||
575 | done = true; | ||
576 | ret_val = GO_TO_ROOT; | ||
577 | if(has_presets_changed()) | ||
578 | { | ||
579 | if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES))) | ||
580 | { | ||
581 | presets_save(); | ||
582 | } | ||
583 | } | ||
584 | |||
585 | break; | ||
586 | |||
587 | case ACTION_STD_PREV: | ||
588 | case ACTION_STD_NEXT: | ||
589 | next_station(button == ACTION_STD_PREV ? -1 : 1); | ||
590 | end_search(); | ||
591 | update_screen = true; | ||
592 | talk = true; | ||
593 | break; | ||
594 | |||
595 | case ACTION_STD_PREVREPEAT: | ||
596 | case ACTION_STD_NEXTREPEAT: | ||
597 | { | ||
598 | int dir = search_dir; | ||
599 | search_dir = button == ACTION_STD_PREVREPEAT ? -1 : 1; | ||
600 | if (radio_mode != RADIO_SCAN_MODE) | ||
601 | { | ||
602 | next_preset(search_dir); | ||
603 | end_search(); | ||
604 | update_screen = true; | ||
605 | talk = true; | ||
606 | } | ||
607 | else if (dir == 0) | ||
608 | { | ||
609 | /* Starting auto scan */ | ||
610 | tuner_set(RADIO_MUTE, 1); | ||
611 | update_screen = true; | ||
612 | } | ||
613 | break; | ||
614 | } | ||
615 | |||
616 | case ACTION_SETTINGS_INC: | ||
617 | case ACTION_SETTINGS_INCREPEAT: | ||
618 | global_settings.volume++; | ||
619 | setvol(); | ||
620 | update_screen = true; | ||
621 | break; | ||
622 | |||
623 | case ACTION_SETTINGS_DEC: | ||
624 | case ACTION_SETTINGS_DECREPEAT: | ||
625 | global_settings.volume--; | ||
626 | setvol(); | ||
627 | update_screen = true; | ||
628 | break; | ||
629 | |||
630 | case ACTION_FM_PLAY: | ||
631 | if (radio_status == FMRADIO_PLAYING) | ||
632 | radio_pause(); | ||
633 | else | ||
634 | radio_start(); | ||
635 | |||
636 | update_screen = true; | ||
637 | talk = false; | ||
638 | talk_shutup(); | ||
639 | break; | ||
640 | |||
641 | case ACTION_FM_MENU: | ||
642 | fms_fix_displays(FMS_EXIT); | ||
643 | radio_menu(); | ||
644 | set_current_preset(find_preset(curr_freq)); | ||
645 | update_screen = true; | ||
646 | restore = true; | ||
647 | break; | ||
648 | |||
649 | #ifdef FM_PRESET | ||
650 | case ACTION_FM_PRESET: | ||
651 | if(radio_preset_count() < 1) | ||
652 | { | ||
653 | splash(HZ, ID2P(LANG_FM_NO_PRESETS)); | ||
654 | update_screen = true; | ||
655 | break; | ||
656 | } | ||
657 | fms_fix_displays(FMS_EXIT); | ||
658 | handle_radio_presets(); | ||
659 | update_screen = true; | ||
660 | restore = true; | ||
661 | break; | ||
662 | #endif /* FM_PRESET */ | ||
663 | |||
664 | #ifdef FM_FREEZE | ||
665 | case ACTION_FM_FREEZE: | ||
666 | if(!screen_freeze) | ||
667 | { | ||
668 | splash(HZ, str(LANG_FM_FREEZE)); | ||
669 | screen_freeze = true; | ||
670 | } | ||
671 | else | ||
672 | { | ||
673 | update_screen = true; | ||
674 | screen_freeze = false; | ||
675 | } | ||
676 | break; | ||
677 | #endif /* FM_FREEZE */ | ||
678 | |||
679 | case SYS_USB_CONNECTED: | ||
680 | #if CONFIG_CODEC != SWCODEC | ||
681 | /* Only accept USB connection when not recording */ | ||
682 | if(audio_status() != AUDIO_STATUS_RECORD) | ||
683 | #endif | ||
684 | { | ||
685 | default_event_handler(SYS_USB_CONNECTED); | ||
686 | screen_freeze = true; /* Cosmetic: makes sure the | ||
687 | radio screen doesn't redraw */ | ||
688 | done = true; | ||
689 | } | ||
690 | break; | ||
691 | |||
692 | #ifdef FM_MODE | ||
693 | case ACTION_FM_MODE: | ||
694 | if(radio_mode == RADIO_SCAN_MODE) | ||
695 | { | ||
696 | /* Force scan mode if there are no presets. */ | ||
697 | if(radio_preset_count() > 0) | ||
698 | radio_mode = RADIO_PRESET_MODE; | ||
699 | } | ||
700 | else | ||
701 | radio_mode = RADIO_SCAN_MODE; | ||
702 | update_screen = true; | ||
703 | cond_talk_ids_fq(radio_mode ? | ||
704 | LANG_PRESET : LANG_RADIO_SCAN_MODE); | ||
705 | talk = true; | ||
706 | break; | ||
707 | #endif /* FM_MODE */ | ||
708 | |||
709 | #ifdef FM_NEXT_PRESET | ||
710 | case ACTION_FM_NEXT_PRESET: | ||
711 | next_preset(1); | ||
712 | end_search(); | ||
713 | update_screen = true; | ||
714 | talk = true; | ||
715 | break; | ||
716 | #endif | ||
717 | |||
718 | #ifdef FM_PREV_PRESET | ||
719 | case ACTION_FM_PREV_PRESET: | ||
720 | next_preset(-1); | ||
721 | end_search(); | ||
722 | update_screen = true; | ||
723 | talk = true; | ||
724 | break; | ||
725 | #endif | ||
726 | |||
727 | default: | ||
728 | default_event_handler(button); | ||
729 | #ifdef HAVE_RDS_CAP | ||
730 | if (tuner_get(RADIO_EVENT)) | ||
731 | update_screen = true; | ||
732 | #endif | ||
733 | if (!tuner_get(RADIO_PRESENT)) | ||
734 | { | ||
735 | #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR) | ||
736 | if(audio_status() == AUDIO_STATUS_RECORD) | ||
737 | audio_stop(); | ||
738 | #endif | ||
739 | keep_playing = false; | ||
740 | done = true; | ||
741 | ret_val = GO_TO_ROOT; | ||
742 | if(has_presets_changed()) | ||
743 | { | ||
744 | if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES))) | ||
745 | { | ||
746 | radio_save_presets(); | ||
747 | } | ||
748 | } | ||
749 | |||
750 | /* Clear the preset list on exit. */ | ||
751 | clear_preset_list(); | ||
752 | } | ||
753 | break; | ||
754 | } /*switch(button)*/ | ||
755 | |||
756 | #ifdef FM_RECORD_DBLPRE | ||
757 | if (button != ACTION_NONE) | ||
758 | lastbutton = button; | ||
759 | #endif | ||
760 | |||
761 | #if CONFIG_CODEC != SWCODEC | ||
762 | peak_meter_peek(); | ||
763 | #endif | ||
764 | |||
765 | if(!screen_freeze) | ||
766 | { | ||
767 | /* Only display the peak meter when not recording */ | ||
768 | #if CONFIG_CODEC != SWCODEC | ||
769 | if(TIME_AFTER(current_tick, timeout)) | ||
770 | { | ||
771 | timeout = current_tick + HZ; | ||
772 | #else /* SWCODEC */ | ||
773 | { | ||
774 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
775 | |||
776 | /* keep "mono" from always being displayed when paused */ | ||
777 | if (radio_status != FMRADIO_PAUSED) | ||
778 | { | ||
779 | stereo = tuner_get(RADIO_STEREO) && | ||
780 | !global_settings.fm_force_mono; | ||
781 | |||
782 | if(stereo != last_stereo) | ||
783 | { | ||
784 | update_screen = true; | ||
785 | last_stereo = stereo; | ||
786 | } | ||
787 | } | ||
788 | } | ||
789 | |||
790 | #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR) | ||
791 | seconds = audio_recorded_time() / HZ; | ||
792 | if (update_screen || seconds > last_seconds || restore) | ||
793 | { | ||
794 | last_seconds = seconds; | ||
795 | #else | ||
796 | if (update_screen || restore) | ||
797 | { | ||
798 | #endif | ||
799 | if (restore) | ||
800 | fms_fix_displays(FMS_ENTER); | ||
801 | FOR_NB_SCREENS(i) | ||
802 | skin_update(fms_get(i), WPS_REFRESH_ALL); | ||
803 | restore = false; | ||
804 | } | ||
805 | } | ||
806 | update_screen = false; | ||
807 | |||
808 | if (global_settings.talk_file && talk | ||
809 | && radio_status == FMRADIO_PAUSED) | ||
810 | { | ||
811 | talk = false; | ||
812 | bool enqueue = false; | ||
813 | if (radio_mode == RADIO_SCAN_MODE) | ||
814 | { | ||
815 | talk_freq(curr_freq, enqueue); | ||
816 | enqueue = true; | ||
817 | } | ||
818 | if (radio_current_preset() >= 0) | ||
819 | talk_preset(radio_current_preset(), radio_mode == RADIO_PRESET_MODE, | ||
820 | enqueue); | ||
821 | } | ||
822 | |||
823 | #if CONFIG_CODEC != SWCODEC | ||
824 | if(audio_status() & AUDIO_STATUS_ERROR) | ||
825 | { | ||
826 | done = true; | ||
827 | } | ||
828 | #endif | ||
829 | |||
830 | #ifndef HAVE_NOISY_IDLE_MODE | ||
831 | if (TIME_AFTER(current_tick, button_timeout)) | ||
832 | { | ||
833 | cpu_idle_mode(true); | ||
834 | } | ||
835 | #endif | ||
836 | } /*while(!done)*/ | ||
837 | |||
838 | #ifndef SIMULATOR | ||
839 | #if CONFIG_CODEC != SWCODEC | ||
840 | if(audio_status() & AUDIO_STATUS_ERROR) | ||
841 | { | ||
842 | splash(0, str(LANG_DISK_FULL)); | ||
843 | audio_error_clear(); | ||
844 | |||
845 | while(1) | ||
846 | { | ||
847 | button = get_action(CONTEXT_FM, TIMEOUT_BLOCK); | ||
848 | if(button == ACTION_FM_STOP) | ||
849 | break; | ||
850 | } | ||
851 | } | ||
852 | |||
853 | audio_init_playback(); | ||
854 | #endif /* CONFIG_CODEC != SWCODEC */ | ||
855 | |||
856 | sound_settings_apply(); | ||
857 | #endif /* SIMULATOR */ | ||
858 | |||
859 | if(keep_playing) | ||
860 | { | ||
861 | /* Catch FMRADIO_PLAYING status for the sim. */ | ||
862 | #ifndef SIMULATOR | ||
863 | #if CONFIG_CODEC != SWCODEC | ||
864 | /* Enable the Left and right A/D Converter */ | ||
865 | audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN), | ||
866 | sound_default(SOUND_RIGHT_GAIN), | ||
867 | AUDIO_GAIN_LINEIN); | ||
868 | mas_codec_writereg(6, 0x4000); | ||
869 | #endif | ||
870 | end_search(); | ||
871 | #endif /* SIMULATOR */ | ||
872 | } | ||
873 | else | ||
874 | { | ||
875 | #if CONFIG_CODEC == SWCODEC | ||
876 | audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); | ||
877 | #else | ||
878 | radio_stop(); | ||
879 | #endif | ||
880 | } | ||
881 | |||
882 | #ifndef HAVE_NOISY_IDLE_MODE | ||
883 | cpu_idle_mode(false); | ||
884 | #endif | ||
885 | fms_fix_displays(FMS_EXIT); | ||
886 | in_screen = false; | ||
887 | #if CONFIG_CODEC != SWCODEC | ||
888 | return have_recorded; | ||
889 | #else | ||
890 | return false; | ||
891 | #endif | ||
892 | } /* radio_screen */ | ||
893 | |||
894 | void toggle_mono_mode(bool mono) | ||
895 | { | ||
896 | tuner_set(RADIO_FORCE_MONO, mono); | ||
897 | } | ||
898 | |||
899 | void set_radio_region(int region) | ||
900 | { | ||
901 | #ifdef HAVE_RADIO_REGION | ||
902 | tuner_set(RADIO_REGION, region); | ||
903 | #endif | ||
904 | next_station(0); | ||
905 | remember_frequency(); | ||
906 | (void)region; | ||
907 | } | ||
908 | |||
909 | MENUITEM_SETTING(set_region, &global_settings.fm_region, NULL); | ||
910 | MENUITEM_SETTING(force_mono, &global_settings.fm_force_mono, NULL); | ||
911 | |||
912 | #ifndef FM_MODE | ||
913 | static char* get_mode_text(int selected_item, void * data, char *buffer) | ||
914 | { | ||
915 | (void)selected_item; | ||
916 | (void)data; | ||
917 | snprintf(buffer, MAX_PATH, "%s %s", str(LANG_MODE), | ||
918 | radio_mode ? str(LANG_PRESET) : | ||
919 | str(LANG_RADIO_SCAN_MODE)); | ||
920 | return buffer; | ||
921 | } | ||
922 | static int toggle_radio_mode(void) | ||
923 | { | ||
924 | radio_mode = (radio_mode == RADIO_SCAN_MODE) ? | ||
925 | RADIO_PRESET_MODE : RADIO_SCAN_MODE; | ||
926 | return 0; | ||
927 | } | ||
928 | MENUITEM_FUNCTION_DYNTEXT(radio_mode_item, 0, | ||
929 | toggle_radio_mode, NULL, | ||
930 | get_mode_text, NULL, NULL, NULL, Icon_NOICON); | ||
931 | #endif | ||
932 | |||
933 | |||
934 | |||
935 | #ifdef HAVE_RECORDING | ||
936 | |||
937 | #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC | ||
938 | #define FM_RECORDING_SCREEN | ||
939 | static int fm_recording_screen(void) | ||
940 | { | ||
941 | bool ret; | ||
942 | |||
943 | /* switch recording source to FMRADIO for the duration */ | ||
944 | int rec_source = global_settings.rec_source; | ||
945 | global_settings.rec_source = AUDIO_SRC_FMRADIO; | ||
946 | ret = recording_screen(true); | ||
947 | |||
948 | /* safe to reset as changing sources is prohibited here */ | ||
949 | global_settings.rec_source = rec_source; | ||
950 | |||
951 | return ret; | ||
952 | } | ||
953 | |||
954 | #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */ | ||
955 | |||
956 | #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC | ||
957 | #define FM_RECORDING_SETTINGS | ||
958 | static int fm_recording_settings(void) | ||
959 | { | ||
960 | bool ret = recording_menu(true); | ||
961 | |||
962 | #if CONFIG_CODEC != SWCODEC | ||
963 | if (!ret) | ||
964 | { | ||
965 | struct audio_recording_options rec_options; | ||
966 | rec_init_recording_options(&rec_options); | ||
967 | rec_options.rec_source = AUDIO_SRC_LINEIN; | ||
968 | rec_set_recording_options(&rec_options); | ||
969 | } | ||
970 | #endif | ||
971 | |||
972 | return ret; | ||
973 | } | ||
974 | |||
975 | #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */ | ||
976 | #endif /* HAVE_RECORDING */ | ||
977 | |||
978 | #ifdef FM_RECORDING_SCREEN | ||
979 | MENUITEM_FUNCTION(recscreen_item, 0, ID2P(LANG_RECORDING), | ||
980 | fm_recording_screen, NULL, NULL, Icon_Recording); | ||
981 | #endif | ||
982 | #ifdef FM_RECORDING_SETTINGS | ||
983 | MENUITEM_FUNCTION(recsettings_item, 0, ID2P(LANG_RECORDING_SETTINGS), | ||
984 | fm_recording_settings, NULL, NULL, Icon_Recording); | ||
985 | #endif | ||
986 | #ifndef FM_PRESET | ||
987 | int handle_radio_presets_menu(void) | ||
988 | { | ||
989 | return handle_radio_presets(); | ||
990 | } | ||
991 | MENUITEM_FUNCTION(radio_presets_item, 0, ID2P(LANG_PRESET), | ||
992 | handle_radio_presets_menu, NULL, NULL, Icon_NOICON); | ||
993 | #endif | ||
994 | #ifndef FM_PRESET_ADD | ||
995 | int handle_radio_addpreset_menu(void) | ||
996 | { | ||
997 | return radio_add_preset(); | ||
998 | } | ||
999 | MENUITEM_FUNCTION(radio_addpreset_item, 0, ID2P(LANG_FM_ADD_PRESET), | ||
1000 | radio_add_preset, NULL, NULL, Icon_NOICON); | ||
1001 | #endif | ||
1002 | |||
1003 | |||
1004 | MENUITEM_FUNCTION(presetload_item, 0, ID2P(LANG_FM_PRESET_LOAD), | ||
1005 | load_preset_list, NULL, NULL, Icon_NOICON); | ||
1006 | MENUITEM_FUNCTION(presetsave_item, 0, ID2P(LANG_FM_PRESET_SAVE), | ||
1007 | save_preset_list, NULL, NULL, Icon_NOICON); | ||
1008 | MENUITEM_FUNCTION(presetclear_item, 0, ID2P(LANG_FM_PRESET_CLEAR), | ||
1009 | clear_preset_list, NULL, NULL, Icon_NOICON); | ||
1010 | MENUITEM_FUNCTION(scan_presets_item, MENU_FUNC_USEPARAM, | ||
1011 | ID2P(LANG_FM_SCAN_PRESETS), | ||
1012 | scan_presets, NULL, NULL, Icon_NOICON); | ||
1013 | |||
1014 | MAKE_MENU(radio_settings_menu, ID2P(LANG_FM_MENU), NULL, | ||
1015 | Icon_Radio_screen, | ||
1016 | #ifndef FM_PRESET | ||
1017 | &radio_presets_item, | ||
1018 | #endif | ||
1019 | #ifndef FM_PRESET_ADD | ||
1020 | &radio_addpreset_item, | ||
1021 | #endif | ||
1022 | &presetload_item, &presetsave_item, &presetclear_item, | ||
1023 | &force_mono, | ||
1024 | #ifndef FM_MODE | ||
1025 | &radio_mode_item, | ||
1026 | #endif | ||
1027 | &set_region, &sound_settings, | ||
1028 | #ifdef FM_RECORDING_SCREEN | ||
1029 | &recscreen_item, | ||
1030 | #endif | ||
1031 | #ifdef FM_RECORDING_SETTINGS | ||
1032 | &recsettings_item, | ||
1033 | #endif | ||
1034 | &scan_presets_item); | ||
1035 | /* main menu of the radio screen */ | ||
1036 | static bool radio_menu(void) | ||
1037 | { | ||
1038 | return do_menu(&radio_settings_menu, NULL, NULL, false) == | ||
1039 | MENU_ATTACHED_USB; | ||
1040 | } | ||
1041 | |||
1042 | #endif | ||