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 /* The iPods/X5/M5 use a single button for the A-B mode markers,
242 defined as ACTION_WPSAB_SINGLE in their config files. */
243 #ifdef ACTION_WPSAB_SINGLE
244 if (!global_settings
.party_mode
&& ab_repeat_mode_enabled())
246 static int wps_ab_state
= 0;
247 if (button
== ACTION_WPSAB_SINGLE
)
249 switch (wps_ab_state
)
251 case 0: /* set the A spot */
252 button
= ACTION_WPS_ABSETA_PREVDIR
;
254 case 1: /* set the B spot */
255 button
= ACTION_WPS_ABSETB_NEXTDIR
;
258 button
= ACTION_WPS_ABRESET
;
261 wps_ab_state
= (wps_ab_state
+1) % 3;
267 case ACTION_WPS_CONTEXT
:
269 show_main_backdrop();
271 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
272 show_remote_main_backdrop();
274 /* if music is stopped in the context menu we want to exit the wps */
275 if (onplay(wps_state
.id3
->path
,
276 FILE_ATTR_AUDIO
, CONTEXT_WPS
) == ONPLAY_MAINMENU
280 /* track might have changed */
286 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
287 show_remote_wps_backdrop();
292 case ACTION_WPS_BROWSE
:
293 #ifdef HAVE_LCD_CHARCELLS
294 status_set_record(false);
295 status_set_audio(false);
298 gui_wps
[i
].display
->stop_scroll();
299 return GO_TO_PREVIOUS_BROWSER
;
303 case ACTION_WPS_PLAY
:
304 if (global_settings
.party_mode
)
306 if ( wps_state
.paused
)
308 wps_state
.paused
= false;
309 if ( global_settings
.fade_on_stop
)
316 wps_state
.paused
= true;
317 if ( global_settings
.fade_on_stop
)
322 #if !defined(HAVE_RTC_RAM) && !defined(HAVE_SW_POWEROFF)
323 call_ata_idle_notifys(true); /* make sure resume info is saved */
329 case ACTION_WPS_VOLUP
:
331 global_settings
.volume
++;
336 if(update_onvol_change(&gui_wps
[i
]))
341 restoretimer
= current_tick
+ HZ
;
347 case ACTION_WPS_VOLDOWN
:
349 global_settings
.volume
--;
354 if(update_onvol_change(&gui_wps
[i
]))
359 restoretimer
= current_tick
+ HZ
;
364 OR next dir if this is straight after ACTION_WPS_SKIPNEXT
365 OR if skip length set, next track if straight after SKIPPREV. */
366 case ACTION_WPS_SEEKFWD
:
367 if (global_settings
.party_mode
)
369 if (global_settings
.skip_length
== 0
370 && current_tick
-last_right
< HZ
)
372 if (cuesheet_is_enabled() && wps_state
.id3
->cuesheet_type
)
381 else if (global_settings
.skip_length
> 0
382 && current_tick
-last_left
< HZ
) {
386 else ffwd_rew(ACTION_WPS_SEEKFWD
);
387 last_right
= last_left
= 0;
390 OR prev dir if this is straight after ACTION_WPS_SKIPPREV,
391 OR if skip length set, beg of track or prev track if this is
392 straight after SKIPPREV */
393 case ACTION_WPS_SEEKBACK
:
394 if (global_settings
.party_mode
)
396 if (global_settings
.skip_length
== 0
397 && current_tick
-last_left
< HZ
)
399 if (cuesheet_is_enabled() && wps_state
.id3
->cuesheet_type
)
401 if (!wps_state
.paused
)
402 #if (CONFIG_CODEC == SWCODEC)
403 audio_pre_ff_rewind();
414 else if (global_settings
.skip_length
> 0
415 && current_tick
-last_right
< HZ
)
417 prev_track(3+global_settings
.skip_length
*60);
420 else ffwd_rew(ACTION_WPS_SEEKBACK
);
421 last_left
= last_right
= 0;
425 case ACTION_WPS_SKIPPREV
:
426 if (global_settings
.party_mode
)
428 last_left
= current_tick
;
431 #ifdef AB_REPEAT_ENABLE
432 /* if we're in A/B repeat mode and the current position
433 is past the A marker, jump back to the A marker... */
434 if ( ab_repeat_mode_enabled() )
436 if ( ab_after_A_marker(wps_state
.id3
->elapsed
) )
438 ab_jump_to_A_marker();
440 #if (AB_REPEAT_ENABLE == 2)
446 /* ...otherwise, do it normally */
449 if (global_settings
.skip_length
> 0)
455 OR if skip length set, hop by predetermined amount. */
456 case ACTION_WPS_SKIPNEXT
:
457 if (global_settings
.party_mode
)
459 last_right
= current_tick
;
462 #ifdef AB_REPEAT_ENABLE
463 /* if we're in A/B repeat mode and the current position is
464 before the A marker, jump to the A marker... */
465 if ( ab_repeat_mode_enabled() )
467 if ( ab_before_A_marker(wps_state
.id3
->elapsed
) )
469 ab_jump_to_A_marker();
471 #if (AB_REPEAT_ENABLE == 2)
477 /* ...otherwise, do it normally */
480 if (global_settings
.skip_length
> 0)
484 /* next / prev directories */
485 /* and set A-B markers if in a-b mode */
486 case ACTION_WPS_ABSETB_NEXTDIR
:
487 if (global_settings
.party_mode
)
489 #if defined(AB_REPEAT_ENABLE)
490 if (ab_repeat_mode_enabled())
492 ab_set_B_marker(wps_state
.id3
->elapsed
);
493 ab_jump_to_A_marker();
499 if (global_settings
.skip_length
> 0)
501 else audio_next_dir();
504 case ACTION_WPS_ABSETA_PREVDIR
:
505 if (global_settings
.party_mode
)
507 #if defined(AB_REPEAT_ENABLE)
508 if (ab_repeat_mode_enabled())
509 ab_set_A_marker(wps_state
.id3
->elapsed
);
513 if (global_settings
.skip_length
> 0)
515 else audio_prev_dir();
518 /* menu key functions */
519 case ACTION_WPS_MENU
:
521 gui_wps
[i
].display
->stop_scroll();
526 #ifdef HAVE_QUICKSCREEN
527 case ACTION_WPS_QUICKSCREEN
:
529 show_main_backdrop();
531 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
532 show_remote_main_backdrop();
534 if (quick_screen_quick(button
))
535 return SYS_USB_CONNECTED
;
539 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
540 show_remote_wps_backdrop();
544 #endif /* HAVE_QUICKSCREEN */
546 /* screen settings */
550 show_main_backdrop();
552 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
553 show_remote_main_backdrop();
555 if (quick_screen_f3(BUTTON_F3
))
556 return SYS_USB_CONNECTED
;
559 #endif /* BUTTON_F3 */
562 #ifdef HAVE_PITCHSCREEN
563 case ACTION_WPS_PITCHSCREEN
:
565 show_main_backdrop();
567 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
568 show_remote_main_backdrop();
570 if (1 == pitch_screen())
571 return SYS_USB_CONNECTED
;
575 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
576 show_remote_wps_backdrop();
580 #endif /* HAVE_PITCHSCREEN */
582 #ifdef AB_REPEAT_ENABLE
583 /* reset A&B markers */
584 case ACTION_WPS_ABRESET
:
585 if (ab_repeat_mode_enabled())
591 #endif /* AB_REPEAT_ENABLE */
593 /* stop and exit wps */
594 case ACTION_WPS_STOP
:
595 if (global_settings
.party_mode
)
601 case ACTION_WPS_ID3SCREEN
:
603 show_main_backdrop();
605 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
606 show_remote_main_backdrop();
612 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
613 show_remote_wps_backdrop();
618 case ACTION_REDRAW
: /* yes are locked, just redraw */
621 case ACTION_NONE
: /* Timeout */
623 ffwd_rew(button
); /* hopefully fix the ffw/rwd bug */
625 #ifdef HAVE_RECORDING
632 show_main_backdrop();
634 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
635 show_remote_main_backdrop();
637 default_event_handler(SYS_POWEROFF
);
641 if(default_event_handler(button
) == SYS_USB_CONNECTED
)
651 if(update(&gui_wps
[i
]))
654 update_track
= false;
658 ((restoretimer
== 0) ||
659 (restoretimer
< current_tick
)))
663 if (gui_wps_display()) {
666 else if (wps_state
.id3
){
668 gui_wps_refresh(&gui_wps
[i
], 0, WPS_REFRESH_NON_STATIC
);
673 #ifdef HAVE_LCD_CHARCELLS
674 status_set_record(false);
675 status_set_audio(false);
677 if (global_settings
.fade_on_stop
)
681 gui_wps
[i
].display
->stop_scroll();
683 bookmark_autobookmark();
685 #ifdef AB_REPEAT_ENABLE
688 #ifdef HAVE_RECORDING
689 if (button
== ACTION_WPS_REC
)
690 return GO_TO_RECSCREEN
;
692 if (global_settings
.browse_current
)
693 return GO_TO_PREVIOUS_BROWSER
;
694 return GO_TO_PREVIOUS
;
700 return GO_TO_ROOT
; /* unreachable - just to reduce compiler warnings */
703 /* needs checking if needed end*/
707 static void wps_state_init(void)
709 wps_state
.ff_rewind
= false;
710 wps_state
.paused
= false;
711 wps_state
.id3
= NULL
;
712 wps_state
.nid3
= NULL
;
713 wps_state
.current_track_path
[0] = '\0';
717 /* these are obviously not used? */
719 void wps_state_update_ff_rew(bool ff_rew
)
721 wps_state
.ff_rewind
= ff_rew
;
724 void wps_state_update_paused(bool paused
)
726 wps_state
.paused
= paused
;
728 void wps_state_update_id3_nid3(struct mp3entry
*id3
, struct mp3entry
*nid3
)
731 wps_state
.nid3
= nid3
;
735 static void wps_state_update_ctp(const char *path
)
737 strncpy(wps_state
.current_track_path
, path
,
738 sizeof(wps_state
.current_track_path
));
739 wps_state
.current_track_path
[sizeof(wps_state
.current_track_path
)-1] = '\0';
743 /* initial setup of a wps */
744 static void gui_wps_init(struct gui_wps
*gui_wps
)
746 gui_wps
->data
= NULL
;
747 gui_wps
->display
= NULL
;
748 gui_wps
->statusbar
= NULL
;
749 /* Currently no seperate wps_state needed/possible
750 so use the only aviable ( "global" ) one */
751 gui_wps
->state
= &wps_state
;
754 /* connects a wps with a format-description of the displayed content */
755 static void gui_wps_set_data(struct gui_wps
*gui_wps
, struct wps_data
*data
)
757 gui_wps
->data
= data
;
760 /* connects a wps with a screen */
761 static void gui_wps_set_disp(struct gui_wps
*gui_wps
, struct screen
*display
)
763 gui_wps
->display
= display
;
766 static void gui_wps_set_statusbar(struct gui_wps
*gui_wps
, struct gui_statusbar
*statusbar
)
768 gui_wps
->statusbar
= statusbar
;
772 void gui_sync_wps_screen_init(void)
776 gui_wps_set_disp(&gui_wps
[i
], &screens
[i
]);
778 #ifdef HAVE_LCD_BITMAP
779 static void statusbar_toggle_handler(void *data
)
783 bool draw
= global_settings
.statusbar
;
787 struct wps_viewport
*vp
= &gui_wps
[i
].data
->viewports
[0];
788 if (gui_wps
[i
].data
->wps_sb_tag
)
789 draw
= gui_wps
[i
].data
->show_sb_on_wps
;
793 vp
->vp
.height
= screens
[i
].lcdheight
;
797 vp
->vp
.y
= STATUSBAR_HEIGHT
;
798 vp
->vp
.height
= screens
[i
].lcdheight
- STATUSBAR_HEIGHT
;
804 void gui_sync_wps_init(void)
809 wps_data_init(&wps_datas
[i
]);
810 #ifdef HAVE_REMOTE_LCD
811 wps_datas
[i
].remote_wps
= (i
!= 0);
813 gui_wps_init(&gui_wps
[i
]);
814 gui_wps_set_data(&gui_wps
[i
], &wps_datas
[i
]);
815 gui_wps_set_statusbar(&gui_wps
[i
], &statusbars
.statusbars
[i
]);
817 #ifdef HAVE_LCD_BITMAP
818 add_event(STATUSBAR_TOGGLE_EVENT
, false, statusbar_toggle_handler
);
821 unload_wps_backdrop();
823 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
824 unload_remote_wps_backdrop();
829 /* Returns true if at least one of the gui_wps screens has an album art
830 tag in its wps structure */
831 bool gui_sync_wps_uses_albumart(void)
835 struct gui_wps
*gwps
= &gui_wps
[i
];
836 if (gwps
->data
&& (gwps
->data
->wps_uses_albumart
!= WPS_ALBUMART_NONE
))