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 ****************************************************************************/
26 #include "backlight.h"
34 #include "wps-display.h"
36 #include "mp3_playback.h"
39 #include "main_menu.h"
43 #ifdef HAVE_LCD_BITMAP
45 #include "peakmeter.h"
49 #define FF_REWIND_MAX_PERCENT 3 /* cap ff/rewind step size at max % of file */
50 /* 3% of 30min file == 54s step size */
52 bool keys_locked
= false;
53 static bool ff_rewind
= false;
54 static bool paused
= false;
55 static struct mp3entry
* id3
= NULL
;
56 static char current_track_path
[MAX_PATH
+1];
58 #if defined(HAVE_PLAYER_KEYPAD) || defined(HAVE_NEO_KEYPAD)
59 void player_change_volume(int button
)
69 case BUTTON_MENU
| BUTTON_RIGHT
:
70 case BUTTON_MENU
| BUTTON_RIGHT
| BUTTON_REPEAT
:
71 global_settings
.volume
++;
72 if(global_settings
.volume
> mpeg_sound_max(SOUND_VOLUME
))
73 global_settings
.volume
= mpeg_sound_max(SOUND_VOLUME
);
74 mpeg_sound_set(SOUND_VOLUME
, global_settings
.volume
);
75 wps_refresh(id3
, 0, WPS_REFRESH_NON_STATIC
);
79 case BUTTON_MENU
| BUTTON_LEFT
:
80 case BUTTON_MENU
| BUTTON_LEFT
| BUTTON_REPEAT
:
81 global_settings
.volume
--;
82 if(global_settings
.volume
< mpeg_sound_min(SOUND_VOLUME
))
83 global_settings
.volume
= mpeg_sound_min(SOUND_VOLUME
);
84 mpeg_sound_set(SOUND_VOLUME
, global_settings
.volume
);
85 wps_refresh(id3
, 0, WPS_REFRESH_NON_STATIC
);
89 case BUTTON_MENU
| BUTTON_REL
:
90 case BUTTON_MENU
| BUTTON_LEFT
| BUTTON_REL
:
91 case BUTTON_MENU
| BUTTON_RIGHT
| BUTTON_REL
:
96 snprintf(buffer
,sizeof(buffer
),"Vol: %d %% ",
97 mpeg_val2phys(SOUND_VOLUME
, global_settings
.volume
));
99 #ifdef HAVE_LCD_CHARCELLS
100 lcd_puts(0, 0, buffer
);
102 lcd_puts(2, 3, buffer
);
108 button
= button_get(true);
110 wps_refresh(id3
,0, WPS_REFRESH_ALL
);
114 void display_keylock_text(bool locked
)
118 #ifdef HAVE_LCD_CHARCELLS
120 s
= str(LANG_KEYLOCK_ON_PLAYER
);
122 s
= str(LANG_KEYLOCK_OFF_PLAYER
);
125 s
= str(LANG_KEYLOCK_ON_RECORDER
);
127 s
= str(LANG_KEYLOCK_OFF_RECORDER
);
132 void display_mute_text(bool muted
)
136 #ifdef HAVE_LCD_CHARCELLS
138 lcd_puts(0, 0, str(LANG_MUTE_ON_PLAYER
));
140 lcd_puts(0, 0, str(LANG_MUTE_OFF_PLAYER
));
143 lcd_puts(2, 3, str(LANG_MUTE_ON_RECORDER
));
145 lcd_puts(2, 3, str(LANG_MUTE_OFF_RECORDER
));
152 bool browse_id3(void)
158 char scroll_text
[MAX_PATH
];
160 if (!(mpeg_status() & MPEG_STATUS_PLAY
))
170 lcd_puts(0, 0, str(LANG_ID3_TITLE
));
171 lcd_puts_scroll(0, 1, id3
->title
? id3
->title
:
172 (char*)str(LANG_ID3_NO_TITLE
));
176 lcd_puts(0, 0, str(LANG_ID3_ARTIST
));
177 lcd_puts_scroll(0, 1,
178 id3
->artist
? id3
->artist
:
179 (char*)str(LANG_ID3_NO_ARTIST
));
183 lcd_puts(0, 0, str(LANG_ID3_ALBUM
));
184 lcd_puts_scroll(0, 1, id3
->album
? id3
->album
:
185 (char*)str(LANG_ID3_NO_ALBUM
));
189 lcd_puts(0, 0, str(LANG_ID3_TRACKNUM
));
192 snprintf(scroll_text
,sizeof(scroll_text
), "%d",
194 lcd_puts_scroll(0, 1, scroll_text
);
197 lcd_puts_scroll(0, 1, str(LANG_ID3_NO_TRACKNUM
));
201 lcd_puts(0, 0, str(LANG_ID3_GENRE
));
202 lcd_puts_scroll(0, 1,
203 wps_get_genre(id3
->genre
) ?
204 wps_get_genre(id3
->genre
) :
205 (char*)str(LANG_ID3_NO_INFO
));
209 lcd_puts(0, 0, str(LANG_ID3_YEAR
));
211 snprintf(scroll_text
,sizeof(scroll_text
), "%d",
213 lcd_puts_scroll(0, 1, scroll_text
);
216 lcd_puts_scroll(0, 1, str(LANG_ID3_NO_INFO
));
220 lcd_puts(0, 0, str(LANG_ID3_LENGHT
));
221 snprintf(scroll_text
,sizeof(scroll_text
), "%d:%02d",
223 id3
->length
% 60000 / 1000 );
224 lcd_puts(0, 1, scroll_text
);
228 lcd_puts(0, 0, str(LANG_ID3_PLAYLIST
));
229 snprintf(scroll_text
,sizeof(scroll_text
), "%d/%d",
230 playlist_get_display_index(), playlist_amount());
231 lcd_puts_scroll(0, 1, scroll_text
);
236 lcd_puts(0, 0, str(LANG_ID3_BITRATE
));
237 snprintf(scroll_text
,sizeof(scroll_text
), "%d kbps",
239 lcd_puts(0, 1, scroll_text
);
243 lcd_puts(0, 0, str(LANG_ID3_FRECUENCY
));
244 snprintf(scroll_text
,sizeof(scroll_text
), "%d Hz",
246 lcd_puts(0, 1, scroll_text
);
250 lcd_puts(0, 0, str(LANG_ID3_PATH
));
251 lcd_puts_scroll(0, 1, id3
->path
);
256 button
= button_get(true);
261 #ifdef HAVE_RECORDER_KEYPAD
271 #ifdef HAVE_RECORDER_KEYPAD
274 if (menu_pos
< menu_max
)
290 /* eat release event */
295 case SYS_USB_CONNECTED
:
296 status_set_playmode(STATUS_STOP
);
305 static bool ffwd_rew(int button
)
307 static int ff_rew_steps
[] = {
308 1000, 2000, 3000, 4000,
309 5000, 6000, 8000, 10000,
310 15000, 20000, 25000, 30000,
314 unsigned int step
= 0; /* current ff/rewind step */
315 unsigned int max_step
= 0; /* maximum ff/rewind step */
316 int ff_rewind_count
= 0; /* current ff/rewind count (in ticks) */
317 int direction
= 1; /* forward=1 or backward=-1 */
318 long accel_tick
= 0; /* next time at which to bump the step size */
324 case BUTTON_LEFT
| BUTTON_REPEAT
:
325 case BUTTON_RIGHT
| BUTTON_REPEAT
:
328 ff_rewind_count
+= step
* direction
;
330 if (global_settings
.ff_rewind_accel
!= 0 &&
331 current_tick
>= accel_tick
)
337 accel_tick
= current_tick
+
338 global_settings
.ff_rewind_accel
*HZ
;
343 if ( (mpeg_status() & MPEG_STATUS_PLAY
) &&
348 #ifdef HAVE_PLAYER_KEYPAD
351 direction
= (button
& BUTTON_RIGHT
) ? 1 : -1;
354 status_set_playmode(STATUS_FASTFORWARD
);
356 status_set_playmode(STATUS_FASTBACKWARD
);
360 step
= ff_rew_steps
[global_settings
.ff_rewind_min_step
];
362 max_step
= id3
->length
* FF_REWIND_MAX_PERCENT
/ 100;
367 ff_rewind_count
= step
* direction
;
368 accel_tick
= current_tick
+
369 global_settings
.ff_rewind_accel
*HZ
;
376 if ((id3
->elapsed
+ ff_rewind_count
) > id3
->length
)
377 ff_rewind_count
= id3
->length
- id3
->elapsed
;
380 if ((int)(id3
->elapsed
+ ff_rewind_count
) < 0)
381 ff_rewind_count
= -id3
->elapsed
;
384 if(wps_time_countup
== false)
385 wps_refresh(id3
, -ff_rewind_count
,
386 WPS_REFRESH_PLAYER_PROGRESS
|
387 WPS_REFRESH_DYNAMIC
);
389 wps_refresh(id3
, ff_rewind_count
,
390 WPS_REFRESH_PLAYER_PROGRESS
|
391 WPS_REFRESH_DYNAMIC
);
395 case BUTTON_LEFT
| BUTTON_REL
:
396 case BUTTON_RIGHT
| BUTTON_REL
:
397 mpeg_ff_rewind(id3
->elapsed
+ff_rewind_count
);
401 status_set_playmode(STATUS_PAUSE
);
404 status_set_playmode(STATUS_PLAY
);
406 #ifdef HAVE_LCD_CHARCELLS
412 case SYS_USB_CONNECTED
:
413 status_set_playmode(STATUS_STOP
);
420 button
= button_get(true);
423 /* let mpeg thread update id3->elapsed before calling wps_refresh */
425 wps_refresh(id3
, 0, WPS_REFRESH_ALL
);
429 static bool update(void)
431 bool track_changed
= mpeg_has_changed_track();
432 bool retcode
= false;
437 id3
= mpeg_current_track();
438 if (wps_display(id3
))
441 wps_refresh(id3
, 0, WPS_REFRESH_ALL
);
444 memcpy(current_track_path
, id3
->path
, sizeof(current_track_path
));
448 wps_refresh(id3
, 0, WPS_REFRESH_NON_STATIC
);
452 /* save resume data */
454 global_settings
.resume
&&
455 global_settings
.resume_offset
!= id3
->offset
) {
456 DEBUGF("R%X,%X (%X)\n", global_settings
.resume_offset
,
459 if (!playlist_get_resume_info(&global_settings
.resume_index
))
461 global_settings
.resume_offset
= id3
->offset
;
465 else if ( !id3
&& track_changed
) {
466 global_settings
.resume_index
= -1;
467 global_settings
.resume_offset
= -1;
474 static bool menu(void)
476 static bool muted
= false;
480 #ifdef HAVE_LCD_CHARCELLS
481 status_set_param(true);
486 int button
= button_get(true);
490 #ifdef HAVE_RECORDER_KEYPAD
491 case BUTTON_F1
| BUTTON_REL
:
493 case BUTTON_MENU
| BUTTON_REL
:
496 if ( !last_button
&& !keys_locked
) {
501 #ifdef HAVE_LCD_BITMAP
502 if(global_settings
.statusbar
)
503 lcd_setmargins(0, STATUSBAR_HEIGHT
);
505 lcd_setmargins(0, 0);
512 case BUTTON_MENU
| BUTTON_PLAY
:
514 case BUTTON_F1
| BUTTON_PLAY
:
517 mpeg_sound_set(SOUND_VOLUME
, global_settings
.volume
);
519 mpeg_sound_set(SOUND_VOLUME
, 0);
521 #ifdef HAVE_LCD_CHARCELLS
522 status_set_param(false);
524 display_mute_text(muted
);
528 #ifdef HAVE_RECORDER_KEYPAD
529 case BUTTON_F1
| BUTTON_DOWN
:
531 case BUTTON_MENU
| BUTTON_STOP
:
533 keys_locked
= !keys_locked
;
534 display_keylock_text(keys_locked
);
536 while (button_get(false)); /* clear button queue */
541 case BUTTON_MENU
| BUTTON_LEFT
:
542 case BUTTON_MENU
| BUTTON_LEFT
| BUTTON_REPEAT
:
543 case BUTTON_MENU
| BUTTON_RIGHT
:
544 case BUTTON_MENU
| BUTTON_RIGHT
| BUTTON_REPEAT
:
545 player_change_volume(button
);
551 case BUTTON_MENU
| BUTTON_ON
:
552 status_set_param(true);
553 status_set_audio(true);
556 case BUTTON_F1
| BUTTON_ON
:
559 lcd_puts(0, 0, str(LANG_ID3_INFO
));
560 lcd_puts(0, 1, str(LANG_ID3_SCREEN
));
566 #ifdef HAVE_PLAYER_KEYPAD
567 status_set_param(false);
568 status_set_audio(true);
573 case SYS_USB_CONNECTED
:
574 status_set_playmode(STATUS_STOP
);
578 last_button
= button
;
581 #ifdef HAVE_LCD_CHARCELLS
582 status_set_param(false);
588 static void fade(bool fade_in
)
592 int current_volume
= 20;
594 /* zero out the sound */
595 mpeg_sound_set(SOUND_VOLUME
, current_volume
);
597 sleep(HZ
/10); /* let mpeg thread run */
600 while (current_volume
< global_settings
.volume
) {
603 mpeg_sound_set(SOUND_VOLUME
, current_volume
);
605 mpeg_sound_set(SOUND_VOLUME
, global_settings
.volume
);
609 int current_volume
= global_settings
.volume
;
611 while (current_volume
> 20) {
614 mpeg_sound_set(SOUND_VOLUME
, current_volume
);
617 sleep(HZ
/5); /* let mpeg thread run */
619 /* reset volume to what it was before the fade */
620 mpeg_sound_set(SOUND_VOLUME
, global_settings
.volume
);
625 /* demonstrates showing different formats from playtune */
628 int button
= 0, lastbutton
= 0;
629 bool ignore_keyup
= true;
630 bool restore
= false;
632 bool update_track
= false;
635 current_track_path
[0] = '\0';
637 #ifdef HAVE_LCD_CHARCELLS
638 status_set_audio(true);
639 status_set_param(false);
641 if(global_settings
.statusbar
)
642 lcd_setmargins(0, STATUSBAR_HEIGHT
);
644 lcd_setmargins(0, 0);
649 if(mpeg_status() & MPEG_STATUS_PLAY
)
651 id3
= mpeg_current_track();
653 if (wps_display(id3
))
655 wps_refresh(id3
, 0, WPS_REFRESH_ALL
);
657 memcpy(current_track_path
, id3
->path
, sizeof(current_track_path
));
665 bool mpeg_paused
= (mpeg_status() & MPEG_STATUS_PAUSE
)?true:false;
667 /* did someone else (i.e power thread) change mpeg pause mode? */
668 if (paused
!= mpeg_paused
) {
669 paused
= mpeg_paused
;
670 status_set_playmode(paused
? STATUS_PAUSE
: STATUS_PLAY
);
672 /* if another thread paused mpeg, we are probably in car mode,
673 about to shut down. lets save the settings. */
674 if (paused
&& global_settings
.resume
) {
682 #ifdef HAVE_LCD_BITMAP
683 /* when the peak meter is enabled we want to have a
684 few extra updates to make it look smooth. On the
685 other hand we don't want to waste energy if it
687 if (peak_meter_enabled
) {
690 /* In high performance mode we read out the mas as
691 often as we can. There is no sleep for cpu */
692 if (global_settings
.peak_meter_performance
) {
693 long next_refresh
= current_tick
;
694 long next_big_refresh
= current_tick
+ HZ
/ 5;
695 button
= BUTTON_NONE
;
696 while (!TIME_AFTER(current_tick
, next_big_refresh
)) {
697 button
= button_get(false);
698 if (button
!= BUTTON_NONE
) {
704 if (TIME_AFTER(current_tick
, next_refresh
)) {
705 wps_refresh(id3
, 0, WPS_REFRESH_PEAK_METER
);
706 next_refresh
= current_tick
+ HZ
/ peak_meter_fps
;
711 /* In energy saver mode the cpu may sleep a
712 little bit while waiting for buttons */
714 for (i
= 0; i
< 4; i
++) {
715 button
= button_get_w_tmo(HZ
/ peak_meter_fps
);
719 wps_refresh(id3
, 0, WPS_REFRESH_PEAK_METER
);
724 /* The peak meter is disabled
725 -> no additional screen updates needed */
727 button
= button_get_w_tmo(HZ
/5);
730 button
= button_get_w_tmo(HZ
/5);
733 /* discard first event if it's a button release */
734 if (button
&& ignore_keyup
)
736 ignore_keyup
= false;
737 if (button
& BUTTON_REL
&& button
!= SYS_USB_CONNECTED
)
741 /* ignore non-remote buttons when keys are locked */
743 #ifdef HAVE_RECORDER_KEYPAD
744 ! ((button
& BUTTON_F1
) ||
746 ! ((button
& BUTTON_MENU
) ||
748 (button
== BUTTON_NONE
) ||
749 (button
== SYS_USB_CONNECTED
)
751 || (button
& BUTTON_REMOTE
)
755 while (button_get(false)); /* clear button queue */
756 display_keylock_text(true);
761 /* Exit if mpeg has stopped playing. This can happen if using the
762 sleep timer with the charger plugged or if starting a recording
771 #ifdef HAVE_RECORDER_KEYPAD
772 switch (on_screen()) {
775 return SYS_USB_CONNECTED
;
778 /* was on_screen used? */
781 /* pause may have been turned off by pitch screen */
782 if (paused
&& !(mpeg_status() & MPEG_STATUS_PAUSE
)) {
784 status_set_playmode(STATUS_PLAY
);
789 /* otherwise, exit to browser */
791 status_set_record(false);
792 status_set_audio(false);
796 /* set dir browser to current playing song */
797 if (global_settings
.browse_current
&&
798 current_track_path
[0] != '\0')
799 set_current_file(current_track_path
);
802 #ifdef HAVE_RECORDER_KEYPAD
806 #endif /* BUTTON_ON */
809 #ifdef BUTTON_RC_PLAY
815 status_set_playmode(STATUS_PLAY
);
816 if ( global_settings
.fade_on_stop
)
824 status_set_playmode(STATUS_PAUSE
);
825 if ( global_settings
.fade_on_stop
)
829 if (global_settings
.resume
) {
839 #ifdef HAVE_RECORDER_KEYPAD
841 case BUTTON_UP
| BUTTON_REPEAT
:
843 #ifdef BUTTON_RC_VOL_UP
844 case BUTTON_RC_VOL_UP
:
846 global_settings
.volume
++;
847 if(global_settings
.volume
> mpeg_sound_max(SOUND_VOLUME
))
848 global_settings
.volume
= mpeg_sound_max(SOUND_VOLUME
);
849 mpeg_sound_set(SOUND_VOLUME
, global_settings
.volume
);
855 #ifdef HAVE_RECORDER_KEYPAD
857 case BUTTON_DOWN
| BUTTON_REPEAT
:
859 #ifdef BUTTON_RC_VOL_DOWN
860 case BUTTON_RC_VOL_DOWN
:
862 global_settings
.volume
--;
863 if(global_settings
.volume
< mpeg_sound_min(SOUND_VOLUME
))
864 global_settings
.volume
= mpeg_sound_min(SOUND_VOLUME
);
865 mpeg_sound_set(SOUND_VOLUME
, global_settings
.volume
);
870 /* fast forward / rewind */
871 case BUTTON_LEFT
| BUTTON_REPEAT
:
872 case BUTTON_RIGHT
| BUTTON_REPEAT
:
877 #ifdef BUTTON_RC_LEFT
880 case BUTTON_LEFT
| BUTTON_REL
:
881 #ifdef HAVE_RECORDER_KEYPAD
882 if ((button
== (BUTTON_LEFT
| BUTTON_REL
)) &&
883 (lastbutton
!= BUTTON_LEFT
))
886 if (!id3
|| (id3
->elapsed
< 3*1000)) {
901 #ifdef BUTTON_RC_RIGHT
902 case BUTTON_RC_RIGHT
:
904 case BUTTON_RIGHT
| BUTTON_REL
:
905 #ifdef HAVE_RECORDER_KEYPAD
906 if ((button
== (BUTTON_RIGHT
| BUTTON_REL
)) &&
907 (lastbutton
!= BUTTON_RIGHT
))
913 /* menu key functions */
920 return SYS_USB_CONNECTED
;
926 #ifdef HAVE_RECORDER_KEYPAD
930 return SYS_USB_CONNECTED
;
934 /* screen settings */
937 return SYS_USB_CONNECTED
;
942 /* stop and exit wps */
943 #ifdef BUTTON_RC_STOP
947 case BUTTON_OFF
| BUTTON_REL
:
949 case BUTTON_STOP
| BUTTON_REL
:
950 if ( lastbutton
!= BUTTON_STOP
)
956 case SYS_USB_CONNECTED
:
957 status_set_playmode(STATUS_STOP
);
959 return SYS_USB_CONNECTED
;
961 case BUTTON_NONE
: /* Timeout */
970 /* set dir browser to current playing song */
971 if (global_settings
.browse_current
&&
972 current_track_path
[0] != '\0')
973 set_current_file(current_track_path
);
977 update_track
= false;
981 #ifdef HAVE_LCD_CHARCELLS
982 status_set_record(false);
983 status_set_audio(false);
985 if (global_settings
.fade_on_stop
)
989 bookmark_autobookmark();
991 status_set_playmode(STATUS_STOP
);
993 /* Keys can be locked when exiting, so either unlock here
994 or implement key locking in tree.c too */
997 /* set dir browser to current playing song */
998 if (global_settings
.browse_current
&&
999 current_track_path
[0] != '\0')
1000 set_current_file(current_track_path
);
1010 if (wps_display(id3
))
1012 /* set dir browser to current playing song */
1013 if (global_settings
.browse_current
&&
1014 current_track_path
[0] != '\0')
1015 set_current_file(current_track_path
);
1021 wps_refresh(id3
, 0, WPS_REFRESH_NON_STATIC
);
1023 if(button
!= BUTTON_NONE
)
1024 lastbutton
= button
;
1026 return 0; /* unreachable - just to reduce compiler warnings */