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"
63 #include "pitchscreen.h"
64 #include "appevents.h"
68 /* currently only one wps_state is needed */
69 struct wps_state wps_state
;
70 struct gui_wps gui_wps
[NB_SCREENS
];
71 static struct wps_data wps_datas
[NB_SCREENS
];
73 /* initial setup of wps_data */
74 static void wps_state_init(void);
76 static void prev_track(unsigned skip_thresh
)
78 if (!wps_state
.id3
|| (wps_state
.id3
->elapsed
< skip_thresh
*1000)) {
82 if (cuesheet_is_enabled() && wps_state
.id3
->cuesheet_type
)
84 curr_cuesheet_skip(-1, wps_state
.id3
->elapsed
);
88 if (!wps_state
.paused
)
89 #if (CONFIG_CODEC == SWCODEC)
90 audio_pre_ff_rewind();
97 #if (CONFIG_CODEC != SWCODEC)
98 if (!wps_state
.paused
)
104 static void next_track(void)
106 /* take care of if we're playing a cuesheet */
107 if (cuesheet_is_enabled() && wps_state
.id3
->cuesheet_type
)
109 if (curr_cuesheet_skip(1, wps_state
.id3
->elapsed
))
111 /* if the result was false, then we really want
112 to skip to the next track */
120 static void play_hop(int direction
)
122 unsigned step
= ((unsigned)global_settings
.skip_length
*1000);
123 unsigned long *elapsed
= &(wps_state
.id3
->elapsed
);
125 if (direction
== 1 && wps_state
.id3
->length
- *elapsed
< step
+1000) {
126 #if CONFIG_CODEC == SWCODEC
127 if(global_settings
.beep
)
128 pcmbuf_beep(1000, 150, 1500*global_settings
.beep
);
131 } else if ((direction
== -1 && *elapsed
< step
)) {
134 *elapsed
+= step
* direction
;
136 if((audio_status() & AUDIO_STATUS_PLAY
) && !wps_state
.paused
) {
137 #if (CONFIG_CODEC == SWCODEC)
138 audio_pre_ff_rewind();
143 audio_ff_rewind(*elapsed
);
144 #if (CONFIG_CODEC != SWCODEC)
145 if (!wps_state
.paused
)
150 static int fix_wps_bars(void)
152 #ifdef HAVE_LCD_BITMAP
154 int wpsbars
= VP_SB_HIDE_ALL
;
157 bool draw
= global_settings
.statusbar
;
158 if (gui_wps
[i
].data
->wps_sb_tag
)
159 draw
= gui_wps
[i
].data
->show_sb_on_wps
;
161 wpsbars
|= (VP_SB_ONSCREEN(i
) | VP_SB_IGNORE_SETTING(i
));
165 return VP_SB_ALLSCREENS
;
169 long gui_wps_show(void)
172 bool restore
= false;
173 long restoretimer
= 0; /* timer to delay screen redraw temporarily */
175 bool bookmark
= false;
176 bool update_track
= false;
178 long last_left
= 0, last_right
= 0;
179 int wpsbars
, oldbars
;
183 #ifdef HAVE_LCD_CHARCELLS
184 status_set_audio(true);
185 status_set_param(false);
189 #endif /* LCD_DEPTH > 1 */
192 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
193 show_remote_wps_backdrop();
196 #ifdef AB_REPEAT_ENABLE
201 oldbars
= viewportmanager_set_statusbar(VP_SB_HIDE_ALL
);
202 if(audio_status() & AUDIO_STATUS_PLAY
)
204 wps_state
.id3
= audio_current_track();
205 wps_state
.nid3
= audio_next_track();
207 if (gui_wps_display())
213 wpsbars
= fix_wps_bars();
214 viewportmanager_set_statusbar(wpsbars
);
218 bool audio_paused
= (audio_status() & AUDIO_STATUS_PAUSE
)?true:false;
220 /* did someone else (i.e power thread) change audio pause mode? */
221 if (wps_state
.paused
!= audio_paused
) {
222 wps_state
.paused
= audio_paused
;
224 /* if another thread paused audio, we are probably in car mode,
225 about to shut down. lets save the settings. */
226 if (wps_state
.paused
) {
228 #if !defined(HAVE_RTC_RAM) && !defined(HAVE_SW_POWEROFF)
229 call_storage_idle_notifys(true);
234 #ifdef HAVE_LCD_BITMAP
235 /* when the peak meter is enabled we want to have a
236 few extra updates to make it look smooth. On the
237 other hand we don't want to waste energy if it
242 if(gui_wps
[i
].data
->peak_meter_enabled
)
247 long next_refresh
= current_tick
;
248 long next_big_refresh
= current_tick
+ HZ
/ 5;
249 button
= BUTTON_NONE
;
250 while (TIME_BEFORE(current_tick
, next_big_refresh
)) {
251 button
= get_action(CONTEXT_WPS
|ALLOW_SOFTLOCK
,TIMEOUT_NOBLOCK
);
252 if (button
!= ACTION_NONE
) {
256 sleep(0); /* Sleep until end of current tick. */
258 if (TIME_AFTER(current_tick
, next_refresh
)) {
261 if(gui_wps
[i
].data
->peak_meter_enabled
)
262 gui_wps_refresh(&gui_wps
[i
], 0,
263 WPS_REFRESH_PEAK_METER
);
264 next_refresh
+= HZ
/ PEAK_METER_FPS
;
271 /* The peak meter is disabled
272 -> no additional screen updates needed */
274 button
= get_action(CONTEXT_WPS
|ALLOW_SOFTLOCK
,HZ
/5);
277 button
= get_action(CONTEXT_WPS
|ALLOW_SOFTLOCK
,HZ
/5);
280 /* Exit if audio has stopped playing. This can happen if using the
281 sleep timer with the charger plugged or if starting a recording
285 /* The iPods/X5/M5 use a single button for the A-B mode markers,
286 defined as ACTION_WPSAB_SINGLE in their config files. */
287 #ifdef ACTION_WPSAB_SINGLE
288 if (!global_settings
.party_mode
&& ab_repeat_mode_enabled())
290 static int wps_ab_state
= 0;
291 if (button
== ACTION_WPSAB_SINGLE
)
293 switch (wps_ab_state
)
295 case 0: /* set the A spot */
296 button
= ACTION_WPS_ABSETA_PREVDIR
;
298 case 1: /* set the B spot */
299 button
= ACTION_WPS_ABSETB_NEXTDIR
;
302 button
= ACTION_WPS_ABRESET
;
305 wps_ab_state
= (wps_ab_state
+1) % 3;
311 case ACTION_WPS_CONTEXT
:
314 show_main_backdrop();
316 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
317 show_remote_main_backdrop();
319 viewportmanager_set_statusbar(oldbars
);
320 /* if music is stopped in the context menu we want to exit the wps */
321 if (onplay(wps_state
.id3
->path
,
322 FILE_ATTR_AUDIO
, CONTEXT_WPS
) == ONPLAY_MAINMENU
325 viewportmanager_set_statusbar(wpsbars
);
326 /* track might have changed */
332 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
333 show_remote_wps_backdrop();
339 case ACTION_WPS_BROWSE
:
340 #ifdef HAVE_LCD_CHARCELLS
341 status_set_record(false);
342 status_set_audio(false);
345 gui_wps
[i
].display
->stop_scroll();
346 return GO_TO_PREVIOUS_BROWSER
;
350 case ACTION_WPS_PLAY
:
351 if (global_settings
.party_mode
)
353 if ( wps_state
.paused
)
355 wps_state
.paused
= false;
356 if ( global_settings
.fade_on_stop
)
363 wps_state
.paused
= true;
364 if ( global_settings
.fade_on_stop
)
369 #if !defined(HAVE_RTC_RAM) && !defined(HAVE_SW_POWEROFF)
370 call_storage_idle_notifys(true); /* make sure resume info is saved */
376 case ACTION_WPS_VOLUP
:
379 gui_wps
[i
].data
->button_time_volume
= current_tick
;
380 global_settings
.volume
++;
385 if(update_onvol_change(&gui_wps
[i
]))
390 restoretimer
= current_tick
+ HZ
;
396 case ACTION_WPS_VOLDOWN
:
399 gui_wps
[i
].data
->button_time_volume
= current_tick
;
400 global_settings
.volume
--;
405 if(update_onvol_change(&gui_wps
[i
]))
410 restoretimer
= current_tick
+ HZ
;
415 OR next dir if this is straight after ACTION_WPS_SKIPNEXT
416 OR if skip length set, next track if straight after SKIPPREV. */
417 case ACTION_WPS_SEEKFWD
:
418 if (global_settings
.party_mode
)
420 if (global_settings
.skip_length
== 0
421 && current_tick
-last_right
< HZ
)
423 if (cuesheet_is_enabled() && wps_state
.id3
->cuesheet_type
)
432 else if (global_settings
.skip_length
> 0
433 && current_tick
-last_left
< HZ
) {
437 else ffwd_rew(ACTION_WPS_SEEKFWD
);
438 last_right
= last_left
= 0;
441 OR prev dir if this is straight after ACTION_WPS_SKIPPREV,
442 OR if skip length set, beg of track or prev track if this is
443 straight after SKIPPREV */
444 case ACTION_WPS_SEEKBACK
:
445 if (global_settings
.party_mode
)
447 if (global_settings
.skip_length
== 0
448 && current_tick
-last_left
< HZ
)
450 if (cuesheet_is_enabled() && wps_state
.id3
->cuesheet_type
)
452 if (!wps_state
.paused
)
453 #if (CONFIG_CODEC == SWCODEC)
454 audio_pre_ff_rewind();
465 else if (global_settings
.skip_length
> 0
466 && current_tick
-last_right
< HZ
)
468 prev_track(3+global_settings
.skip_length
);
471 else ffwd_rew(ACTION_WPS_SEEKBACK
);
472 last_left
= last_right
= 0;
476 case ACTION_WPS_SKIPPREV
:
477 if (global_settings
.party_mode
)
479 last_left
= current_tick
;
482 #ifdef AB_REPEAT_ENABLE
483 /* if we're in A/B repeat mode and the current position
484 is past the A marker, jump back to the A marker... */
485 if ( ab_repeat_mode_enabled() )
487 if ( ab_after_A_marker(wps_state
.id3
->elapsed
) )
489 ab_jump_to_A_marker();
491 #if (AB_REPEAT_ENABLE == 2)
497 /* ...otherwise, do it normally */
500 if (global_settings
.skip_length
> 0)
506 OR if skip length set, hop by predetermined amount. */
507 case ACTION_WPS_SKIPNEXT
:
508 if (global_settings
.party_mode
)
510 last_right
= current_tick
;
513 #ifdef AB_REPEAT_ENABLE
514 /* if we're in A/B repeat mode and the current position is
515 before the A marker, jump to the A marker... */
516 if ( ab_repeat_mode_enabled() )
518 if ( ab_before_A_marker(wps_state
.id3
->elapsed
) )
520 ab_jump_to_A_marker();
522 #if (AB_REPEAT_ENABLE == 2)
528 /* ...otherwise, do it normally */
531 if (global_settings
.skip_length
> 0)
535 /* next / prev directories */
536 /* and set A-B markers if in a-b mode */
537 case ACTION_WPS_ABSETB_NEXTDIR
:
538 if (global_settings
.party_mode
)
540 #if defined(AB_REPEAT_ENABLE)
541 if (ab_repeat_mode_enabled())
543 ab_set_B_marker(wps_state
.id3
->elapsed
);
544 ab_jump_to_A_marker();
550 if (global_settings
.skip_length
> 0)
552 else audio_next_dir();
555 case ACTION_WPS_ABSETA_PREVDIR
:
556 if (global_settings
.party_mode
)
558 #if defined(AB_REPEAT_ENABLE)
559 if (ab_repeat_mode_enabled())
560 ab_set_A_marker(wps_state
.id3
->elapsed
);
564 if (global_settings
.skip_length
> 0)
566 else audio_prev_dir();
569 /* menu key functions */
570 case ACTION_WPS_MENU
:
572 gui_wps
[i
].display
->stop_scroll();
577 #ifdef HAVE_QUICKSCREEN
578 case ACTION_WPS_QUICKSCREEN
:
580 viewportmanager_set_statusbar(oldbars
);
582 show_main_backdrop();
584 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
585 show_remote_main_backdrop();
587 if (quick_screen_quick(button
))
588 return SYS_USB_CONNECTED
;
589 wpsbars
= fix_wps_bars();
590 viewportmanager_set_statusbar(wpsbars
);
594 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
595 show_remote_wps_backdrop();
600 #endif /* HAVE_QUICKSCREEN */
602 /* screen settings */
606 viewportmanager_set_statusbar(oldbars
);
608 show_main_backdrop();
610 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
611 show_remote_main_backdrop();
613 if (quick_screen_f3(BUTTON_F3
))
614 return SYS_USB_CONNECTED
;
616 wpsbars
= fix_wps_bars();
617 viewportmanager_set_statusbar(wpsbars
);
620 #endif /* BUTTON_F3 */
623 #ifdef HAVE_PITCHSCREEN
624 case ACTION_WPS_PITCHSCREEN
:
626 viewportmanager_set_statusbar(oldbars
);
628 show_main_backdrop();
630 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
631 show_remote_main_backdrop();
633 if (1 == gui_syncpitchscreen_run())
634 return SYS_USB_CONNECTED
;
638 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
639 show_remote_wps_backdrop();
642 viewportmanager_set_statusbar(wpsbars
);
645 #endif /* HAVE_PITCHSCREEN */
647 #ifdef AB_REPEAT_ENABLE
648 /* reset A&B markers */
649 case ACTION_WPS_ABRESET
:
650 if (ab_repeat_mode_enabled())
656 #endif /* AB_REPEAT_ENABLE */
658 /* stop and exit wps */
659 case ACTION_WPS_STOP
:
660 if (global_settings
.party_mode
)
666 case ACTION_WPS_ID3SCREEN
:
668 viewportmanager_set_statusbar(oldbars
);
670 show_main_backdrop();
672 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
673 show_remote_main_backdrop();
679 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
680 show_remote_wps_backdrop();
683 viewportmanager_set_statusbar(wpsbars
);
687 case ACTION_REDRAW
: /* yes are locked, just redraw */
690 case ACTION_NONE
: /* Timeout */
692 ffwd_rew(button
); /* hopefully fix the ffw/rwd bug */
694 #ifdef HAVE_RECORDING
700 viewportmanager_set_statusbar(oldbars
);
702 show_main_backdrop();
704 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
705 show_remote_main_backdrop();
707 default_event_handler(SYS_POWEROFF
);
711 if(default_event_handler(button
) == SYS_USB_CONNECTED
)
721 if(update(&gui_wps
[i
]))
724 update_track
= false;
728 ((restoretimer
== 0) ||
729 (restoretimer
< current_tick
)))
733 if (gui_wps_display()) {
739 viewportmanager_set_statusbar(oldbars
);
740 #ifdef HAVE_LCD_CHARCELLS
741 status_set_record(false);
742 status_set_audio(false);
744 if (global_settings
.fade_on_stop
)
748 gui_wps
[i
].display
->stop_scroll();
750 bookmark_autobookmark();
752 #ifdef AB_REPEAT_ENABLE
755 #ifdef HAVE_RECORDING
756 if (button
== ACTION_WPS_REC
)
757 return GO_TO_RECSCREEN
;
759 if (global_settings
.browse_current
)
760 return GO_TO_PREVIOUS_BROWSER
;
761 return GO_TO_PREVIOUS
;
764 if (button
&& !IS_SYSEVENT(button
) )
767 return GO_TO_ROOT
; /* unreachable - just to reduce compiler warnings */
770 /* needs checking if needed end*/
774 static void wps_state_init(void)
776 wps_state
.ff_rewind
= false;
777 wps_state
.paused
= false;
778 wps_state
.id3
= NULL
;
779 wps_state
.nid3
= NULL
;
784 #ifdef HAVE_LCD_BITMAP
785 static void statusbar_toggle_handler(void *data
)
789 bool draw
= global_settings
.statusbar
;
793 struct wps_viewport
*vp
= &gui_wps
[i
].data
->viewports
[0];
794 if (gui_wps
[i
].data
->wps_sb_tag
)
795 draw
= gui_wps
[i
].data
->show_sb_on_wps
;
799 vp
->vp
.height
= screens
[i
].lcdheight
;
803 vp
->vp
.y
= STATUSBAR_HEIGHT
;
804 vp
->vp
.height
= screens
[i
].lcdheight
- STATUSBAR_HEIGHT
;
810 void gui_sync_wps_init(void)
815 wps_data_init(&wps_datas
[i
]);
817 wps_datas
[i
].wps_uses_albumart
= 0;
819 #ifdef HAVE_REMOTE_LCD
820 wps_datas
[i
].remote_wps
= (i
!= 0);
822 gui_wps
[i
].data
= &wps_datas
[i
];
823 gui_wps
[i
].display
= &screens
[i
];
824 /* Currently no seperate wps_state needed/possible
825 so use the only aviable ( "global" ) one */
826 gui_wps
[i
].state
= &wps_state
;
828 #ifdef HAVE_LCD_BITMAP
829 add_event(GUI_EVENT_STATUSBAR_TOGGLE
, false, statusbar_toggle_handler
);
832 unload_wps_backdrop();
834 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
835 unload_remote_wps_backdrop();
840 /* Returns true if at least one of the gui_wps screens has an album art
841 tag in its wps structure */
842 bool gui_sync_wps_uses_albumart(void)
846 struct gui_wps
*gwps
= &gui_wps
[i
];
847 if (gwps
->data
&& (gwps
->data
->wps_uses_albumart
!= WPS_ALBUMART_NONE
))