1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 Jerome Kuptz
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
28 #include "backlight.h"
31 #include "filetypes.h"
36 #include "gwps-common.h"
43 #ifdef HAVE_LCD_BITMAP
45 #include "peakmeter.h"
57 #include "ata_idle_notify.h"
58 #include "root_menu.h"
60 #include "quickscreen.h"
62 /* currently only on wps_state is needed */
63 struct wps_state wps_state
;
64 struct gui_wps gui_wps
[NB_SCREENS
];
65 static struct wps_data wps_datas
[NB_SCREENS
];
67 /* change the path to the current played track */
68 static void wps_state_update_ctp(const char *path
);
69 /* initial setup of wps_data */
70 static void wps_state_init(void);
71 /* initial setup of a wps */
72 static void gui_wps_init(struct gui_wps
*gui_wps
);
73 /* connects a wps with a format-description of the displayed content */
74 static void gui_wps_set_data(struct gui_wps
*gui_wps
, struct wps_data
*data
);
75 /* connects a wps with a screen */
76 static void gui_wps_set_disp(struct gui_wps
*gui_wps
, struct screen
*display
);
77 /* connects a wps with a statusbar*/
78 static void gui_wps_set_statusbar(struct gui_wps
*gui_wps
, struct gui_statusbar
*statusbar
);
80 #ifdef HAVE_LCD_BITMAP
81 static void gui_wps_set_margin(struct gui_wps
*gwps
)
84 struct wps_data
*data
= gwps
->data
;
85 if(data
->wps_sb_tag
&& data
->show_sb_on_wps
)
86 offset
= STATUSBAR_HEIGHT
;
87 else if ( global_settings
.statusbar
&& !data
->wps_sb_tag
)
88 offset
= STATUSBAR_HEIGHT
;
89 gwps
->display
->setmargins(0, offset
);
93 static void prev_track(unsigned skip_thresh
)
95 if (!wps_state
.id3
|| (wps_state
.id3
->elapsed
< skip_thresh
*1000)) {
99 if (cuesheet_is_enabled() && wps_state
.id3
->cuesheet_type
)
101 curr_cuesheet_skip(-1, wps_state
.id3
->elapsed
);
105 if (!wps_state
.paused
)
106 #if (CONFIG_CODEC == SWCODEC)
107 audio_pre_ff_rewind();
114 #if (CONFIG_CODEC != SWCODEC)
115 if (!wps_state
.paused
)
121 static void next_track(void)
123 /* take care of if we're playing a cuesheet */
124 if (cuesheet_is_enabled() && wps_state
.id3
->cuesheet_type
)
126 if (curr_cuesheet_skip(1, wps_state
.id3
->elapsed
))
128 /* if the result was false, then we really want
129 to skip to the next track */
138 long gui_wps_show(void)
141 bool restore
= false;
142 long restoretimer
= 0; /* timer to delay screen redraw temporarily */
144 bool bookmark
= false;
145 bool update_track
= false;
147 long last_left
= 0, last_right
= 0;
151 #ifdef HAVE_LCD_CHARCELLS
152 status_set_audio(true);
153 status_set_param(false);
157 gui_wps_set_margin(&gui_wps
[i
]);
161 #endif /* LCD_DEPTH > 1 */
164 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
165 show_remote_wps_backdrop();
168 #ifdef AB_REPEAT_ENABLE
173 if(audio_status() & AUDIO_STATUS_PLAY
)
175 wps_state
.id3
= audio_current_track();
176 wps_state
.nid3
= audio_next_track();
178 if (gui_wps_display())
181 gui_wps_refresh(&gui_wps
[i
], 0, WPS_REFRESH_ALL
);
182 wps_state_update_ctp(wps_state
.id3
->path
);
189 bool audio_paused
= (audio_status() & AUDIO_STATUS_PAUSE
)?true:false;
191 /* did someone else (i.e power thread) change audio pause mode? */
192 if (wps_state
.paused
!= audio_paused
) {
193 wps_state
.paused
= audio_paused
;
195 /* if another thread paused audio, we are probably in car mode,
196 about to shut down. lets save the settings. */
197 if (wps_state
.paused
) {
199 #if !defined(HAVE_RTC_RAM) && !defined(HAVE_SW_POWEROFF)
200 call_ata_idle_notifys(true);
205 #ifdef HAVE_LCD_BITMAP
206 /* when the peak meter is enabled we want to have a
207 few extra updates to make it look smooth. On the
208 other hand we don't want to waste energy if it
213 if(gui_wps
[i
].data
->peak_meter_enabled
)
218 long next_refresh
= current_tick
;
219 long next_big_refresh
= current_tick
+ HZ
/ 5;
220 button
= BUTTON_NONE
;
221 while (TIME_BEFORE(current_tick
, next_big_refresh
)) {
222 button
= get_action(CONTEXT_WPS
|ALLOW_SOFTLOCK
,TIMEOUT_NOBLOCK
);
223 if (button
!= ACTION_NONE
) {
227 sleep(0); /* Sleep until end of current tick. */
229 if (TIME_AFTER(current_tick
, next_refresh
)) {
232 if(gui_wps
[i
].data
->peak_meter_enabled
)
233 gui_wps_refresh(&gui_wps
[i
], 0,
234 WPS_REFRESH_PEAK_METER
);
235 next_refresh
+= HZ
/ PEAK_METER_FPS
;
242 /* The peak meter is disabled
243 -> no additional screen updates needed */
245 button
= get_action(CONTEXT_WPS
|ALLOW_SOFTLOCK
,HZ
/5);
248 button
= get_action(CONTEXT_WPS
|ALLOW_SOFTLOCK
,HZ
/5);
251 /* Exit if audio has stopped playing. This can happen if using the
252 sleep timer with the charger plugged or if starting a recording
256 #ifdef ACTION_WPSAB_SINGLE
257 if (!global_settings
.party_mode
&& ab_repeat_mode_enabled())
259 static int wps_ab_state
= 0;
260 if (button
== ACTION_WPSAB_SINGLE
)
262 switch (wps_ab_state
)
264 case 0: /* set the A spot */
265 button
= ACTION_WPS_ABSETA_PREVDIR
;
267 case 1: /* set the B spot */
268 button
= ACTION_WPS_ABSETB_NEXTDIR
;
271 button
= ACTION_WPS_ABRESET
;
274 wps_ab_state
= (wps_ab_state
+1) % 3;
280 case ACTION_WPS_CONTEXT
:
282 show_main_backdrop();
284 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
285 show_remote_main_backdrop();
287 /* if music is stopped in the context menu we want to exit the wps */
288 if (onplay(wps_state
.id3
->path
,
289 FILE_ATTR_AUDIO
, CONTEXT_WPS
) == ONPLAY_MAINMENU
293 /* track might have changed */
299 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
300 show_remote_wps_backdrop();
302 #ifdef HAVE_LCD_BITMAP
305 gui_wps_set_margin(&gui_wps
[i
]);
311 case ACTION_WPS_BROWSE
:
312 #ifdef HAVE_LCD_CHARCELLS
313 status_set_record(false);
314 status_set_audio(false);
317 gui_wps
[i
].display
->stop_scroll();
318 return GO_TO_PREVIOUS_BROWSER
;
322 case ACTION_WPS_PLAY
:
323 if (global_settings
.party_mode
)
325 if ( wps_state
.paused
)
327 wps_state
.paused
= false;
328 if ( global_settings
.fade_on_stop
)
335 wps_state
.paused
= true;
336 if ( global_settings
.fade_on_stop
)
341 #if !defined(HAVE_RTC_RAM) && !defined(HAVE_SW_POWEROFF)
342 call_ata_idle_notifys(true); /* make sure resume info is saved */
348 case ACTION_WPS_VOLUP
:
350 global_settings
.volume
++;
355 if(update_onvol_change(&gui_wps
[i
]))
360 restoretimer
= current_tick
+ HZ
;
366 case ACTION_WPS_VOLDOWN
:
368 global_settings
.volume
--;
373 if(update_onvol_change(&gui_wps
[i
]))
378 restoretimer
= current_tick
+ HZ
;
383 OR next dir if this is straight after ACTION_WPS_SKIPNEXT
384 OR in study mode, next track if straight after SKIPPREV. */
385 case ACTION_WPS_SEEKFWD
:
386 if (global_settings
.party_mode
)
388 if (!global_settings
.study_mode
389 && current_tick
-last_right
< HZ
)
391 if (cuesheet_is_enabled() && wps_state
.id3
->cuesheet_type
)
400 else if(global_settings
.study_mode
401 && current_tick
-last_left
< HZ
) {
405 else ffwd_rew(ACTION_WPS_SEEKFWD
);
406 last_right
= last_left
= 0;
409 OR prev dir if this is straight after ACTION_WPS_SKIPPREV,
410 OR in study mode, beg of track or prev track if this is
411 straight after SKIPPREV */
412 case ACTION_WPS_SEEKBACK
:
413 if (global_settings
.party_mode
)
415 if (!global_settings
.study_mode
416 && current_tick
-last_left
< HZ
)
418 if (cuesheet_is_enabled() && wps_state
.id3
->cuesheet_type
)
420 if (!wps_state
.paused
)
421 #if (CONFIG_CODEC == SWCODEC)
422 audio_pre_ff_rewind();
433 else if(global_settings
.study_mode
434 && current_tick
-last_right
< HZ
)
436 prev_track(3+global_settings
.study_hop_step
);
439 else ffwd_rew(ACTION_WPS_SEEKBACK
);
440 last_left
= last_right
= 0;
444 case ACTION_WPS_SKIPPREV
:
445 if (global_settings
.party_mode
)
447 last_left
= current_tick
;
450 #ifdef AB_REPEAT_ENABLE
451 /* if we're in A/B repeat mode and the current position
452 is past the A marker, jump back to the A marker... */
453 if ( ab_repeat_mode_enabled() )
455 if ( ab_after_A_marker(wps_state
.id3
->elapsed
) )
457 ab_jump_to_A_marker();
459 #if (AB_REPEAT_ENABLE == 2)
465 /* ...otherwise, do it normally */
468 if(global_settings
.study_mode
)
474 OR in study mode, hop by predetermined amount. */
475 case ACTION_WPS_SKIPNEXT
:
476 if (global_settings
.party_mode
)
478 last_right
= current_tick
;
481 #ifdef AB_REPEAT_ENABLE
482 /* if we're in A/B repeat mode and the current position is
483 before the A marker, jump to the A marker... */
484 if ( ab_repeat_mode_enabled() )
486 if ( ab_before_A_marker(wps_state
.id3
->elapsed
) )
488 ab_jump_to_A_marker();
490 #if (AB_REPEAT_ENABLE == 2)
496 /* ...otherwise, do it normally */
499 if(global_settings
.study_mode
)
503 /* next / prev directories */
504 /* and set A-B markers if in a-b mode */
505 case ACTION_WPS_ABSETB_NEXTDIR
:
506 if (global_settings
.party_mode
)
508 #if defined(AB_REPEAT_ENABLE)
509 if (ab_repeat_mode_enabled())
511 ab_set_B_marker(wps_state
.id3
->elapsed
);
512 ab_jump_to_A_marker();
518 if(global_settings
.study_mode
)
520 else audio_next_dir();
523 case ACTION_WPS_ABSETA_PREVDIR
:
524 if (global_settings
.party_mode
)
526 #if defined(AB_REPEAT_ENABLE)
527 if (ab_repeat_mode_enabled())
528 ab_set_A_marker(wps_state
.id3
->elapsed
);
532 if(global_settings
.study_mode
)
534 else audio_prev_dir();
537 /* menu key functions */
538 case ACTION_WPS_MENU
:
540 gui_wps
[i
].display
->stop_scroll();
545 #ifdef HAVE_QUICKSCREEN
546 case ACTION_WPS_QUICKSCREEN
:
548 show_main_backdrop();
550 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
551 show_remote_main_backdrop();
553 if (quick_screen_quick(button
))
554 return SYS_USB_CONNECTED
;
558 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
559 show_remote_wps_backdrop();
561 #ifdef HAVE_LCD_BITMAP
564 gui_wps_set_margin(&gui_wps
[i
]);
569 #endif /* HAVE_QUICKSCREEN */
571 /* screen settings */
575 show_main_backdrop();
577 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
578 show_remote_main_backdrop();
580 if (quick_screen_f3(BUTTON_F3
))
581 return SYS_USB_CONNECTED
;
582 #ifdef HAVE_LCD_BITMAP
585 gui_wps_set_margin(&gui_wps
[i
]);
590 #endif /* BUTTON_F3 */
593 #ifdef HAVE_PITCHSCREEN
594 case ACTION_WPS_PITCHSCREEN
:
596 show_main_backdrop();
598 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
599 show_remote_main_backdrop();
601 if (1 == pitch_screen())
602 return SYS_USB_CONNECTED
;
606 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
607 show_remote_wps_backdrop();
611 #endif /* HAVE_PITCHSCREEN */
613 #ifdef AB_REPEAT_ENABLE
614 /* reset A&B markers */
615 case ACTION_WPS_ABRESET
:
616 if (ab_repeat_mode_enabled())
622 #endif /* AB_REPEAT_ENABLE */
624 /* stop and exit wps */
625 case ACTION_WPS_STOP
:
626 if (global_settings
.party_mode
)
632 case ACTION_WPS_ID3SCREEN
:
634 show_main_backdrop();
636 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
637 show_remote_main_backdrop();
643 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
644 show_remote_wps_backdrop();
646 #ifdef HAVE_LCD_BITMAP
649 gui_wps_set_margin(&gui_wps
[i
]);
655 case ACTION_REDRAW
: /* yes are locked, just redraw */
658 case ACTION_NONE
: /* Timeout */
660 ffwd_rew(button
); /* hopefully fix the ffw/rwd bug */
662 #ifdef HAVE_RECORDING
669 show_main_backdrop();
671 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
672 show_remote_main_backdrop();
674 default_event_handler(SYS_POWEROFF
);
678 if(default_event_handler(button
) == SYS_USB_CONNECTED
)
688 if(update(&gui_wps
[i
]))
691 update_track
= false;
695 ((restoretimer
== 0) ||
696 (restoretimer
< current_tick
)))
700 if (gui_wps_display()) {
703 else if (wps_state
.id3
){
705 gui_wps_refresh(&gui_wps
[i
], 0, WPS_REFRESH_NON_STATIC
);
710 #ifdef HAVE_LCD_CHARCELLS
711 status_set_record(false);
712 status_set_audio(false);
714 if (global_settings
.fade_on_stop
)
718 gui_wps
[i
].display
->stop_scroll();
720 bookmark_autobookmark();
722 #ifdef AB_REPEAT_ENABLE
725 #ifdef HAVE_RECORDING
726 if (button
== ACTION_WPS_REC
)
727 return GO_TO_RECSCREEN
;
729 if (global_settings
.browse_current
)
730 return GO_TO_PREVIOUS_BROWSER
;
731 return GO_TO_PREVIOUS
;
737 return GO_TO_ROOT
; /* unreachable - just to reduce compiler warnings */
740 /* needs checking if needed end*/
744 static void wps_state_init(void)
746 wps_state
.ff_rewind
= false;
747 wps_state
.paused
= false;
748 wps_state
.id3
= NULL
;
749 wps_state
.nid3
= NULL
;
750 wps_state
.current_track_path
[0] = '\0';
754 /* these are obviously not used? */
756 void wps_state_update_ff_rew(bool ff_rew
)
758 wps_state
.ff_rewind
= ff_rew
;
761 void wps_state_update_paused(bool paused
)
763 wps_state
.paused
= paused
;
765 void wps_state_update_id3_nid3(struct mp3entry
*id3
, struct mp3entry
*nid3
)
768 wps_state
.nid3
= nid3
;
772 static void wps_state_update_ctp(const char *path
)
774 strncpy(wps_state
.current_track_path
, path
,
775 sizeof(wps_state
.current_track_path
));
776 wps_state
.current_track_path
[sizeof(wps_state
.current_track_path
)-1] = '\0';
780 /* initial setup of a wps */
781 static void gui_wps_init(struct gui_wps
*gui_wps
)
783 gui_wps
->data
= NULL
;
784 gui_wps
->display
= NULL
;
785 gui_wps
->statusbar
= NULL
;
786 /* Currently no seperate wps_state needed/possible
787 so use the only aviable ( "global" ) one */
788 gui_wps
->state
= &wps_state
;
791 /* connects a wps with a format-description of the displayed content */
792 static void gui_wps_set_data(struct gui_wps
*gui_wps
, struct wps_data
*data
)
794 gui_wps
->data
= data
;
797 /* connects a wps with a screen */
798 static void gui_wps_set_disp(struct gui_wps
*gui_wps
, struct screen
*display
)
800 gui_wps
->display
= display
;
803 static void gui_wps_set_statusbar(struct gui_wps
*gui_wps
, struct gui_statusbar
*statusbar
)
805 gui_wps
->statusbar
= statusbar
;
809 void gui_sync_wps_screen_init(void)
813 gui_wps_set_disp(&gui_wps
[i
], &screens
[i
]);
816 void gui_sync_wps_init(void)
821 wps_data_init(&wps_datas
[i
]);
822 #ifdef HAVE_REMOTE_LCD
823 wps_datas
[i
].remote_wps
= (i
!= 0);
825 gui_wps_init(&gui_wps
[i
]);
826 gui_wps_set_data(&gui_wps
[i
], &wps_datas
[i
]);
827 gui_wps_set_statusbar(&gui_wps
[i
], &statusbars
.statusbars
[i
]);
830 unload_wps_backdrop();
832 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
833 unload_remote_wps_backdrop();
838 /* Returns true if at least one of the gui_wps screens has an album art
839 tag in its wps structure */
840 bool gui_sync_wps_uses_albumart(void)
844 struct gui_wps
*gwps
= &gui_wps
[i
];
845 if (gwps
->data
&& (gwps
->data
->wps_uses_albumart
!= WPS_ALBUMART_NONE
))