1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 Jerome Kuptz
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 ****************************************************************************/
30 #include "backlight.h"
33 #include "filetypes.h"
38 #include "gwps-common.h"
45 #ifdef HAVE_LCD_BITMAP
47 #include "peakmeter.h"
59 #include "ata_idle_notify.h"
60 #include "root_menu.h"
62 #include "quickscreen.h"
64 /* currently only on wps_state is needed */
65 struct wps_state wps_state
;
66 struct gui_wps gui_wps
[NB_SCREENS
];
67 static struct wps_data wps_datas
[NB_SCREENS
];
69 /* change the path to the current played track */
70 static void wps_state_update_ctp(const char *path
);
71 /* initial setup of wps_data */
72 static void wps_state_init(void);
73 /* initial setup of a wps */
74 static void gui_wps_init(struct gui_wps
*gui_wps
);
75 /* connects a wps with a format-description of the displayed content */
76 static void gui_wps_set_data(struct gui_wps
*gui_wps
, struct wps_data
*data
);
77 /* connects a wps with a screen */
78 static void gui_wps_set_disp(struct gui_wps
*gui_wps
, struct screen
*display
);
79 /* connects a wps with a statusbar*/
80 static void gui_wps_set_statusbar(struct gui_wps
*gui_wps
, struct gui_statusbar
*statusbar
);
82 static void prev_track(unsigned skip_thresh
)
84 if (!wps_state
.id3
|| (wps_state
.id3
->elapsed
< skip_thresh
*1000)) {
88 if (cuesheet_is_enabled() && wps_state
.id3
->cuesheet_type
)
90 curr_cuesheet_skip(-1, wps_state
.id3
->elapsed
);
94 if (!wps_state
.paused
)
95 #if (CONFIG_CODEC == SWCODEC)
96 audio_pre_ff_rewind();
103 #if (CONFIG_CODEC != SWCODEC)
104 if (!wps_state
.paused
)
110 static void next_track(void)
112 /* take care of if we're playing a cuesheet */
113 if (cuesheet_is_enabled() && wps_state
.id3
->cuesheet_type
)
115 if (curr_cuesheet_skip(1, wps_state
.id3
->elapsed
))
117 /* if the result was false, then we really want
118 to skip to the next track */
127 long gui_wps_show(void)
130 bool restore
= false;
131 long restoretimer
= 0; /* timer to delay screen redraw temporarily */
133 bool bookmark
= false;
134 bool update_track
= false;
136 long last_left
= 0, last_right
= 0;
140 #ifdef HAVE_LCD_CHARCELLS
141 status_set_audio(true);
142 status_set_param(false);
146 #endif /* LCD_DEPTH > 1 */
149 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
150 show_remote_wps_backdrop();
153 #ifdef AB_REPEAT_ENABLE
158 if(audio_status() & AUDIO_STATUS_PLAY
)
160 wps_state
.id3
= audio_current_track();
161 wps_state
.nid3
= audio_next_track();
163 if (gui_wps_display())
166 gui_wps_refresh(&gui_wps
[i
], 0, WPS_REFRESH_ALL
);
167 wps_state_update_ctp(wps_state
.id3
->path
);
174 bool audio_paused
= (audio_status() & AUDIO_STATUS_PAUSE
)?true:false;
176 /* did someone else (i.e power thread) change audio pause mode? */
177 if (wps_state
.paused
!= audio_paused
) {
178 wps_state
.paused
= audio_paused
;
180 /* if another thread paused audio, we are probably in car mode,
181 about to shut down. lets save the settings. */
182 if (wps_state
.paused
) {
184 #if !defined(HAVE_RTC_RAM) && !defined(HAVE_SW_POWEROFF)
185 call_ata_idle_notifys(true);
190 #ifdef HAVE_LCD_BITMAP
191 /* when the peak meter is enabled we want to have a
192 few extra updates to make it look smooth. On the
193 other hand we don't want to waste energy if it
198 if(gui_wps
[i
].data
->peak_meter_enabled
)
203 long next_refresh
= current_tick
;
204 long next_big_refresh
= current_tick
+ HZ
/ 5;
205 button
= BUTTON_NONE
;
206 while (TIME_BEFORE(current_tick
, next_big_refresh
)) {
207 button
= get_action(CONTEXT_WPS
|ALLOW_SOFTLOCK
,TIMEOUT_NOBLOCK
);
208 if (button
!= ACTION_NONE
) {
212 sleep(0); /* Sleep until end of current tick. */
214 if (TIME_AFTER(current_tick
, next_refresh
)) {
217 if(gui_wps
[i
].data
->peak_meter_enabled
)
218 gui_wps_refresh(&gui_wps
[i
], 0,
219 WPS_REFRESH_PEAK_METER
);
220 next_refresh
+= HZ
/ PEAK_METER_FPS
;
227 /* The peak meter is disabled
228 -> no additional screen updates needed */
230 button
= get_action(CONTEXT_WPS
|ALLOW_SOFTLOCK
,HZ
/5);
233 button
= get_action(CONTEXT_WPS
|ALLOW_SOFTLOCK
,HZ
/5);
236 /* Exit if audio has stopped playing. This can happen if using the
237 sleep timer with the charger plugged or if starting a recording
241 #ifdef ACTION_WPSAB_SINGLE
242 if (!global_settings
.party_mode
&& ab_repeat_mode_enabled())
244 static int wps_ab_state
= 0;
245 if (button
== ACTION_WPSAB_SINGLE
)
247 switch (wps_ab_state
)
249 case 0: /* set the A spot */
250 button
= ACTION_WPS_ABSETA_PREVDIR
;
252 case 1: /* set the B spot */
253 button
= ACTION_WPS_ABSETB_NEXTDIR
;
256 button
= ACTION_WPS_ABRESET
;
259 wps_ab_state
= (wps_ab_state
+1) % 3;
265 case ACTION_WPS_CONTEXT
:
267 show_main_backdrop();
269 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
270 show_remote_main_backdrop();
272 /* if music is stopped in the context menu we want to exit the wps */
273 if (onplay(wps_state
.id3
->path
,
274 FILE_ATTR_AUDIO
, CONTEXT_WPS
) == ONPLAY_MAINMENU
278 /* track might have changed */
284 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
285 show_remote_wps_backdrop();
290 case ACTION_WPS_BROWSE
:
291 #ifdef HAVE_LCD_CHARCELLS
292 status_set_record(false);
293 status_set_audio(false);
296 gui_wps
[i
].display
->stop_scroll();
297 return GO_TO_PREVIOUS_BROWSER
;
301 case ACTION_WPS_PLAY
:
302 if (global_settings
.party_mode
)
304 if ( wps_state
.paused
)
306 wps_state
.paused
= false;
307 if ( global_settings
.fade_on_stop
)
314 wps_state
.paused
= true;
315 if ( global_settings
.fade_on_stop
)
320 #if !defined(HAVE_RTC_RAM) && !defined(HAVE_SW_POWEROFF)
321 call_ata_idle_notifys(true); /* make sure resume info is saved */
327 case ACTION_WPS_VOLUP
:
329 global_settings
.volume
++;
334 if(update_onvol_change(&gui_wps
[i
]))
339 restoretimer
= current_tick
+ HZ
;
345 case ACTION_WPS_VOLDOWN
:
347 global_settings
.volume
--;
352 if(update_onvol_change(&gui_wps
[i
]))
357 restoretimer
= current_tick
+ HZ
;
362 OR next dir if this is straight after ACTION_WPS_SKIPNEXT
363 OR in study mode, next track if straight after SKIPPREV. */
364 case ACTION_WPS_SEEKFWD
:
365 if (global_settings
.party_mode
)
367 if (!global_settings
.study_mode
368 && current_tick
-last_right
< HZ
)
370 if (cuesheet_is_enabled() && wps_state
.id3
->cuesheet_type
)
379 else if(global_settings
.study_mode
380 && current_tick
-last_left
< HZ
) {
384 else ffwd_rew(ACTION_WPS_SEEKFWD
);
385 last_right
= last_left
= 0;
388 OR prev dir if this is straight after ACTION_WPS_SKIPPREV,
389 OR in study mode, beg of track or prev track if this is
390 straight after SKIPPREV */
391 case ACTION_WPS_SEEKBACK
:
392 if (global_settings
.party_mode
)
394 if (!global_settings
.study_mode
395 && current_tick
-last_left
< HZ
)
397 if (cuesheet_is_enabled() && wps_state
.id3
->cuesheet_type
)
399 if (!wps_state
.paused
)
400 #if (CONFIG_CODEC == SWCODEC)
401 audio_pre_ff_rewind();
412 else if(global_settings
.study_mode
413 && current_tick
-last_right
< HZ
)
415 prev_track(3+global_settings
.study_hop_step
);
418 else ffwd_rew(ACTION_WPS_SEEKBACK
);
419 last_left
= last_right
= 0;
423 case ACTION_WPS_SKIPPREV
:
424 if (global_settings
.party_mode
)
426 last_left
= current_tick
;
429 #ifdef AB_REPEAT_ENABLE
430 /* if we're in A/B repeat mode and the current position
431 is past the A marker, jump back to the A marker... */
432 if ( ab_repeat_mode_enabled() )
434 if ( ab_after_A_marker(wps_state
.id3
->elapsed
) )
436 ab_jump_to_A_marker();
438 #if (AB_REPEAT_ENABLE == 2)
444 /* ...otherwise, do it normally */
447 if(global_settings
.study_mode
)
453 OR in study mode, hop by predetermined amount. */
454 case ACTION_WPS_SKIPNEXT
:
455 if (global_settings
.party_mode
)
457 last_right
= current_tick
;
460 #ifdef AB_REPEAT_ENABLE
461 /* if we're in A/B repeat mode and the current position is
462 before the A marker, jump to the A marker... */
463 if ( ab_repeat_mode_enabled() )
465 if ( ab_before_A_marker(wps_state
.id3
->elapsed
) )
467 ab_jump_to_A_marker();
469 #if (AB_REPEAT_ENABLE == 2)
475 /* ...otherwise, do it normally */
478 if(global_settings
.study_mode
)
482 /* next / prev directories */
483 /* and set A-B markers if in a-b mode */
484 case ACTION_WPS_ABSETB_NEXTDIR
:
485 if (global_settings
.party_mode
)
487 #if defined(AB_REPEAT_ENABLE)
488 if (ab_repeat_mode_enabled())
490 ab_set_B_marker(wps_state
.id3
->elapsed
);
491 ab_jump_to_A_marker();
497 if(global_settings
.study_mode
)
499 else audio_next_dir();
502 case ACTION_WPS_ABSETA_PREVDIR
:
503 if (global_settings
.party_mode
)
505 #if defined(AB_REPEAT_ENABLE)
506 if (ab_repeat_mode_enabled())
507 ab_set_A_marker(wps_state
.id3
->elapsed
);
511 if(global_settings
.study_mode
)
513 else audio_prev_dir();
516 /* menu key functions */
517 case ACTION_WPS_MENU
:
519 gui_wps
[i
].display
->stop_scroll();
524 #ifdef HAVE_QUICKSCREEN
525 case ACTION_WPS_QUICKSCREEN
:
527 show_main_backdrop();
529 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
530 show_remote_main_backdrop();
532 if (quick_screen_quick(button
))
533 return SYS_USB_CONNECTED
;
537 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
538 show_remote_wps_backdrop();
542 #endif /* HAVE_QUICKSCREEN */
544 /* screen settings */
548 show_main_backdrop();
550 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
551 show_remote_main_backdrop();
553 if (quick_screen_f3(BUTTON_F3
))
554 return SYS_USB_CONNECTED
;
557 #endif /* BUTTON_F3 */
560 #ifdef HAVE_PITCHSCREEN
561 case ACTION_WPS_PITCHSCREEN
:
563 show_main_backdrop();
565 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
566 show_remote_main_backdrop();
568 if (1 == pitch_screen())
569 return SYS_USB_CONNECTED
;
573 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
574 show_remote_wps_backdrop();
578 #endif /* HAVE_PITCHSCREEN */
580 #ifdef AB_REPEAT_ENABLE
581 /* reset A&B markers */
582 case ACTION_WPS_ABRESET
:
583 if (ab_repeat_mode_enabled())
589 #endif /* AB_REPEAT_ENABLE */
591 /* stop and exit wps */
592 case ACTION_WPS_STOP
:
593 if (global_settings
.party_mode
)
599 case ACTION_WPS_ID3SCREEN
:
601 show_main_backdrop();
603 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
604 show_remote_main_backdrop();
610 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
611 show_remote_wps_backdrop();
616 case ACTION_REDRAW
: /* yes are locked, just redraw */
619 case ACTION_NONE
: /* Timeout */
621 ffwd_rew(button
); /* hopefully fix the ffw/rwd bug */
623 #ifdef HAVE_RECORDING
630 show_main_backdrop();
632 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
633 show_remote_main_backdrop();
635 default_event_handler(SYS_POWEROFF
);
639 if(default_event_handler(button
) == SYS_USB_CONNECTED
)
649 if(update(&gui_wps
[i
]))
652 update_track
= false;
656 ((restoretimer
== 0) ||
657 (restoretimer
< current_tick
)))
661 if (gui_wps_display()) {
664 else if (wps_state
.id3
){
666 gui_wps_refresh(&gui_wps
[i
], 0, WPS_REFRESH_NON_STATIC
);
671 #ifdef HAVE_LCD_CHARCELLS
672 status_set_record(false);
673 status_set_audio(false);
675 if (global_settings
.fade_on_stop
)
679 gui_wps
[i
].display
->stop_scroll();
681 bookmark_autobookmark();
683 #ifdef AB_REPEAT_ENABLE
686 #ifdef HAVE_RECORDING
687 if (button
== ACTION_WPS_REC
)
688 return GO_TO_RECSCREEN
;
690 if (global_settings
.browse_current
)
691 return GO_TO_PREVIOUS_BROWSER
;
692 return GO_TO_PREVIOUS
;
698 return GO_TO_ROOT
; /* unreachable - just to reduce compiler warnings */
701 /* needs checking if needed end*/
705 static void wps_state_init(void)
707 wps_state
.ff_rewind
= false;
708 wps_state
.paused
= false;
709 wps_state
.id3
= NULL
;
710 wps_state
.nid3
= NULL
;
711 wps_state
.current_track_path
[0] = '\0';
715 /* these are obviously not used? */
717 void wps_state_update_ff_rew(bool ff_rew
)
719 wps_state
.ff_rewind
= ff_rew
;
722 void wps_state_update_paused(bool paused
)
724 wps_state
.paused
= paused
;
726 void wps_state_update_id3_nid3(struct mp3entry
*id3
, struct mp3entry
*nid3
)
729 wps_state
.nid3
= nid3
;
733 static void wps_state_update_ctp(const char *path
)
735 strncpy(wps_state
.current_track_path
, path
,
736 sizeof(wps_state
.current_track_path
));
737 wps_state
.current_track_path
[sizeof(wps_state
.current_track_path
)-1] = '\0';
741 /* initial setup of a wps */
742 static void gui_wps_init(struct gui_wps
*gui_wps
)
744 gui_wps
->data
= NULL
;
745 gui_wps
->display
= NULL
;
746 gui_wps
->statusbar
= NULL
;
747 /* Currently no seperate wps_state needed/possible
748 so use the only aviable ( "global" ) one */
749 gui_wps
->state
= &wps_state
;
752 /* connects a wps with a format-description of the displayed content */
753 static void gui_wps_set_data(struct gui_wps
*gui_wps
, struct wps_data
*data
)
755 gui_wps
->data
= data
;
758 /* connects a wps with a screen */
759 static void gui_wps_set_disp(struct gui_wps
*gui_wps
, struct screen
*display
)
761 gui_wps
->display
= display
;
764 static void gui_wps_set_statusbar(struct gui_wps
*gui_wps
, struct gui_statusbar
*statusbar
)
766 gui_wps
->statusbar
= statusbar
;
770 void gui_sync_wps_screen_init(void)
774 gui_wps_set_disp(&gui_wps
[i
], &screens
[i
]);
776 #ifdef HAVE_LCD_BITMAP
777 static void statusbar_toggle_handler(void *data
)
781 bool draw
= global_settings
.statusbar
;
785 struct wps_viewport
*vp
= &gui_wps
[i
].data
->viewports
[0];
786 if (gui_wps
[i
].data
->wps_sb_tag
)
787 draw
= gui_wps
[i
].data
->show_sb_on_wps
;
788 if (!global_settings
.statusbar
&& !draw
)
791 vp
->vp
.height
= screens
[i
].height
;
795 vp
->vp
.y
= STATUSBAR_HEIGHT
;
796 vp
->vp
.height
= screens
[i
].height
- STATUSBAR_HEIGHT
;
802 void gui_sync_wps_init(void)
807 wps_data_init(&wps_datas
[i
]);
808 #ifdef HAVE_REMOTE_LCD
809 wps_datas
[i
].remote_wps
= (i
!= 0);
811 gui_wps_init(&gui_wps
[i
]);
812 gui_wps_set_data(&gui_wps
[i
], &wps_datas
[i
]);
813 gui_wps_set_statusbar(&gui_wps
[i
], &statusbars
.statusbars
[i
]);
815 #ifdef HAVE_LCD_BITMAP
816 add_event(STATUSBAR_TOGGLE_EVENT
, false, statusbar_toggle_handler
);
819 unload_wps_backdrop();
821 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
822 unload_remote_wps_backdrop();
827 /* Returns true if at least one of the gui_wps screens has an album art
828 tag in its wps structure */
829 bool gui_sync_wps_uses_albumart(void)
833 struct gui_wps
*gwps
= &gui_wps
[i
];
834 if (gwps
->data
&& (gwps
->data
->wps_uses_albumart
!= WPS_ALBUMART_NONE
))