1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 Björn Stenberg
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 ****************************************************************************/
20 /* ID3 formatting based on code from the MAD Winamp plugin (in_mad.dll),
21 * Copyright (C) 2000-2001 Robert Leslie.
22 * See http://www.mars.org/home/rob/proj/mpeg/ for more information.
39 #include "wps-display.h"
43 #include "powermgmt.h"
45 #include "backlight.h"
47 #ifdef HAVE_LCD_BITMAP
50 #include "peakmeter.h"
53 #define WPS_CONFIG ROCKBOX_DIR "/default.wps"
55 #ifdef HAVE_LCD_BITMAP
57 #define FORMAT_BUFFER_SIZE 800
60 #define FORMAT_BUFFER_SIZE 400
62 #define MAX_SUBLINES 12
63 #define DEFAULT_SUBLINE_TIME_MULTIPLIER 20 /* (10ths of sec) */
64 #define BASE_SUBLINE_TIME 10 /* base time that multiplier is applied to
65 (1/HZ sec, or 100ths of sec) */
66 #define SUBLINE_RESET -1
68 #ifdef HAVE_LCD_CHARCELLS
69 static unsigned char wps_progress_pat
[8]={0,0,0,0,0,0,0,0};
70 static bool full_line_progressbar
=0;
71 static bool draw_player_progress(const struct mp3entry
* id3
,
72 int ff_rewwind_count
);
73 static void draw_player_fullbar(char* buf
, int buf_size
,
74 const struct mp3entry
* id3
,
75 int ff_rewwind_count
);
76 static char map_fullbar_char(char ascii_val
);
79 static char format_buffer
[FORMAT_BUFFER_SIZE
];
80 static char* format_lines
[MAX_LINES
][MAX_SUBLINES
];
81 static unsigned char line_type
[MAX_LINES
][MAX_SUBLINES
];
82 static unsigned short time_mult
[MAX_LINES
][MAX_SUBLINES
];
83 static long subline_expire_time
[MAX_LINES
];
84 static int curr_subline
[MAX_LINES
];
86 static int ff_rewind_count
;
87 bool wps_time_countup
= true;
88 static bool wps_loaded
= false;
90 /* Set format string to use for WPS, splitting it into lines */
91 static void wps_format(const char* fmt
)
93 char* buf
= format_buffer
;
94 char* start_of_line
= format_buffer
;
98 strncpy(format_buffer
, fmt
, sizeof(format_buffer
));
99 format_buffer
[sizeof(format_buffer
) - 1] = 0;
101 for (line
=0; line
<MAX_LINES
; line
++)
103 for (subline
=0; subline
<MAX_SUBLINES
; subline
++)
105 format_lines
[line
][subline
] = 0;
106 time_mult
[line
][subline
] = 0;
108 subline_expire_time
[line
] = 0;
109 curr_subline
[line
] = SUBLINE_RESET
;
114 format_lines
[line
][subline
] = buf
;
116 while ((*buf
) && (line
< MAX_LINES
))
120 /* skip % sequences so "%;" doesn't start a new subline */
132 if (*start_of_line
!= '#') /* A comment? */
135 if (line
< MAX_LINES
)
137 /* the next line starts on the next byte */
139 format_lines
[line
][subline
] = buf
+1;
140 start_of_line
= format_lines
[line
][subline
];
144 case ';': /* start a new subline */
147 if (subline
< MAX_SUBLINES
)
149 format_lines
[line
][subline
] = buf
+1;
151 else /* exceeded max sublines, skip rest of line */
155 if ((*buf
== '\r') || (*buf
== '\n'))
172 memset(&format_buffer
, 0, sizeof format_buffer
);
175 bool wps_load(const char* file
, bool display
)
178 char buffer
[FORMAT_BUFFER_SIZE
];
181 fd
= open(file
, O_RDONLY
);
185 int numread
= read(fd
, buffer
, sizeof(buffer
) - 1);
196 bool any_defined_line
;
198 #ifdef HAVE_LCD_BITMAP
201 for (s
=0; s
<MAX_SUBLINES
; s
++)
203 any_defined_line
= false;
204 for (i
=0; i
<MAX_LINES
; i
++)
206 if (format_lines
[i
][s
])
208 if (*format_lines
[i
][s
] == 0)
211 lcd_puts(0,i
,format_lines
[i
][s
]);
212 any_defined_line
= true;
219 if (any_defined_line
)
234 /* Format time into buf.
236 * buf - buffer to format to.
237 * buf_size - size of buffer.
238 * time - time to format, in milliseconds.
240 static void format_time(char* buf
, int buf_size
, int time
)
242 if ( time
< 3600000 ) {
243 snprintf(buf
, buf_size
, "%d:%02d",
244 time
% 3600000 / 60000, time
% 60000 / 1000);
246 snprintf(buf
, buf_size
, "%d:%02d:%02d",
247 time
/ 3600000, time
% 3600000 / 60000, time
% 60000 / 1000);
251 /* Extract a part from a path.
253 * buf - buffer extract part to.
254 * buf_size - size of buffer.
255 * path - path to extract from.
256 * level - what to extract. 0 is file name, 1 is parent of file, 2 is
257 * parent of parent, etc.
259 * Returns buf if the desired level was found, NULL otherwise.
261 static char* get_dir(char* buf
, int buf_size
, const char* path
, int level
)
264 const char* last_sep
;
267 sep
= path
+ strlen(path
);
284 if (level
|| (last_sep
<= sep
))
289 len
= MIN(last_sep
- sep
, buf_size
- 1);
290 strncpy(buf
, sep
+ 1, len
);
295 /* Get the tag specified by the two characters at fmt.
297 * id3 - ID3 data to get tag values from.
298 * nid3 - next-song ID3 data to get tag values from.
299 * tag - string (of two characters) specifying the tag to get.
300 * buf - buffer to certain tags, such as track number, play time or
302 * buf_size - size of buffer.
303 * flags - returns the type of the line. See constants i wps-display.h
305 * Returns the tag. NULL indicates the tag wasn't available.
307 static char* get_tag(struct mp3entry
* cid3
,
308 struct mp3entry
* nid3
,
312 unsigned char* tag_len
,
313 unsigned short* subline_time_mult
,
314 unsigned char* flags
)
316 struct mp3entry
*id3
= cid3
; /* default to current song */
318 if ((0 == tag
[0]) || (0 == tag
[1]))
328 case 'I': /* ID3 Information */
329 id3
= nid3
; /* display next-song data */
330 *flags
|= WPS_REFRESH_DYNAMIC
;
332 return NULL
; /* no such info (yet) */
334 case 'i': /* ID3 Information */
335 *flags
|= WPS_REFRESH_STATIC
;
338 case 't': /* ID3 Title */
341 case 'a': /* ID3 Artist */
344 case 'n': /* ID3 Track Number */
345 if (id3
->track_string
)
346 return id3
->track_string
;
349 snprintf(buf
, buf_size
, "%d", id3
->tracknum
);
354 case 'd': /* ID3 Album/Disc */
357 case 'c': /* ID3 Composer */
358 return id3
->composer
;
361 if( id3
->year_string
)
362 return id3
->year_string
;
365 snprintf(buf
, buf_size
, "%d", id3
->year
);
370 case 'g': /* genre */
371 return id3_get_genre(id3
);
373 case 'v': /* id3 version */
374 switch (id3
->id3version
) {
396 case 'F': /* File Information */
398 *flags
|= WPS_REFRESH_DYNAMIC
;
400 return NULL
; /* no such info (yet) */
402 case 'f': /* File Information */
403 *flags
|= WPS_REFRESH_STATIC
;
406 case 'v': /* VBR file? */
407 return id3
->vbr
? "(avg)" : NULL
;
409 case 'b': /* File Bitrate */
411 snprintf(buf
, buf_size
, "%d", id3
->bitrate
);
413 snprintf(buf
, buf_size
, "?");
416 case 'f': /* File Frequency */
417 snprintf(buf
, buf_size
, "%d", id3
->frequency
);
420 case 'p': /* File Path */
423 case 'm': /* File Name - With Extension */
424 return get_dir(buf
, buf_size
, id3
->path
, 0);
426 case 'n': /* File Name */
427 if (get_dir(buf
, buf_size
, id3
->path
, 0))
429 /* Remove extension */
430 char* sep
= strrchr(buf
, '.');
444 case 's': /* File Size (in kilobytes) */
445 snprintf(buf
, buf_size
, "%d", id3
->filesize
/ 1024);
450 case 'p': /* Playlist/Song Information */
453 case 'b': /* progress bar */
454 *flags
|= WPS_REFRESH_PLAYER_PROGRESS
;
455 #ifdef HAVE_LCD_CHARCELLS
456 snprintf(buf
, buf_size
, "%c", wps_progress_pat
[0]);
457 full_line_progressbar
=0;
462 case 'f': /* full-line progress bar */
463 #ifdef HAVE_LCD_CHARCELLS
464 if(is_new_player()) {
465 *flags
|= WPS_REFRESH_PLAYER_PROGRESS
;
466 *flags
|= WPS_REFRESH_DYNAMIC
;
467 full_line_progressbar
=1;
468 /* we need 11 characters (full line) for
470 snprintf(buf
, buf_size
, " ");
474 /* Tell the user if we have an OldPlayer */
475 snprintf(buf
, buf_size
, " <Old LCD> ");
479 case 'p': /* Playlist Position */
480 *flags
|= WPS_REFRESH_STATIC
;
481 snprintf(buf
, buf_size
, "%d", playlist_get_display_index());
484 case 'n': /* Playlist Name (without path) */
485 *flags
|= WPS_REFRESH_STATIC
;
486 return playlist_name(NULL
, buf
, buf_size
);
488 case 'e': /* Playlist Total Entries */
489 *flags
|= WPS_REFRESH_STATIC
;
490 snprintf(buf
, buf_size
, "%d", playlist_amount());
493 case 'c': /* Current Time in Song */
494 *flags
|= WPS_REFRESH_DYNAMIC
;
495 format_time(buf
, buf_size
, id3
->elapsed
+ ff_rewind_count
);
498 case 'r': /* Remaining Time in Song */
499 *flags
|= WPS_REFRESH_DYNAMIC
;
500 format_time(buf
, buf_size
,
501 id3
->length
- id3
->elapsed
- ff_rewind_count
);
504 case 't': /* Total Time */
505 *flags
|= WPS_REFRESH_STATIC
;
506 format_time(buf
, buf_size
, id3
->length
);
509 #ifdef HAVE_LCD_BITMAP
510 case 'm': /* Peak Meter */
511 *flags
|= WPS_REFRESH_PEAK_METER
;
514 case 's': /* shuffle */
515 if ( global_settings
.playlist_shuffle
)
521 case 'v': /* volume */
522 *flags
|= WPS_REFRESH_DYNAMIC
;
523 snprintf(buf
, buf_size
, "%d%%", global_settings
.volume
);
529 case 'b': /* battery info */
530 *flags
|= WPS_REFRESH_DYNAMIC
;
532 case 'l': /* battery level */
534 int l
= battery_level();
536 snprintf(buf
, buf_size
, "%d%%", l
);
542 case 't': /* estimated battery time */
544 int t
= battery_time();
546 snprintf(buf
, buf_size
, "%dh %dm", t
/ 60, t
% 60);
548 strncpy(buf
, "?h ?m", buf_size
);
554 case 'D': /* Directory path information */
555 id3
= nid3
; /* next song please! */
556 *flags
|= WPS_REFRESH_DYNAMIC
;
558 return NULL
; /* no such info (yet) */
560 case 'd': /* Directory path information */
562 int level
= tag
[1] - '0';
563 *flags
|= WPS_REFRESH_STATIC
;
565 if ((0 < level
) && (9 > level
))
567 return get_dir(buf
, buf_size
, id3
->path
, level
);
572 case 't': /* set sub line time multiplier */
576 bool have_point
= false;
577 bool have_tenth
= false;
579 while (((tag
[d
] >= '0') &&
585 time_mult
= time_mult
* 10;
586 time_mult
= time_mult
+ tag
[d
] - '0';
601 if (have_tenth
== false)
604 *subline_time_mult
= time_mult
;
616 /* Skip to the end of the current %? conditional.
618 * fmt - string to skip it. Should point to somewhere after the leading
619 * "<" char (and before or at the last ">").
620 * to_else - if true, skip to the else part (after the "|", if any), else skip
621 * to the end (the ">").
623 * Returns the new position in fmt.
625 static const char* skip_conditional(const char* fmt
, bool to_else
)
637 if (to_else
&& (1 == level
))
666 while (*fmt
&& ('<' != *fmt
))
683 /* Generate the display based on id3 information and format string.
685 * buf - char buffer to write the display to.
686 * buf_size - the size of buffer.
687 * id3 - the ID3 data to format with.
688 * nid3 - the ID3 data of the next song (might by NULL)
689 * fmt - format description.
690 * flags - returns the type of the line. See constants i wps-display.h
692 static void format_display(char* buf
,
694 struct mp3entry
* id3
,
695 struct mp3entry
* nid3
, /* next song's id3 */
697 unsigned short* subline_time_mult
,
698 unsigned char* flags
)
701 char* buf_start
= buf
;
702 char* buf_end
= buf
+ buf_size
- 1; /* Leave room for end null */
705 unsigned char tag_length
;
707 *subline_time_mult
= DEFAULT_SUBLINE_TIME_MULTIPLIER
;
709 while (fmt
&& *fmt
&& buf
< buf_end
)
721 fmt
= skip_conditional(fmt
, false);
725 /* Else fall through */
739 *flags
|= WPS_REFRESH_SCROLL
;
753 value
= get_tag(id3
, nid3
, fmt
, temp_buf
, sizeof(temp_buf
),
754 &tag_length
, subline_time_mult
, flags
);
756 while (*fmt
&& ('<' != *fmt
))
762 /* No value, so skip to else part */
763 if ((!value
) || (!strlen(value
)))
764 fmt
= skip_conditional(fmt
, true);
770 value
= get_tag(id3
, nid3
, fmt
, temp_buf
, sizeof(temp_buf
),
771 &tag_length
, subline_time_mult
, flags
);
776 while (*value
&& (buf
< buf_end
))
784 /* if resulting line is an empty line, set the subline time to 0 */
786 *subline_time_mult
= 0;
788 /* If no flags have been set, the line didn't contain any format codes.
789 We still want to refresh it. */
791 *flags
= WPS_REFRESH_STATIC
;
794 bool wps_refresh(struct mp3entry
* id3
,
795 struct mp3entry
* nid3
,
797 unsigned char refresh_mode
)
803 bool only_one_subline
;
804 bool new_subline_refresh
;
807 #ifdef HAVE_LCD_BITMAP
808 int h
= font_get(FONT_UI
)->height
;
809 int offset
= global_settings
.statusbar
? STATUSBAR_HEIGHT
: 0;
810 /* to find out wether the peak meter is enabled we
811 assume it wasn't until we find a line that contains
812 the peak meter. We can't use peak_meter_enabled itself
813 because that would mean to turn off the meter thread
814 temporarily. (That shouldn't matter unless yield
815 or sleep is called but who knows...)
817 bool enable_pm
= false;
820 /* reset to first subline if refresh all flag is set */
821 if (refresh_mode
== WPS_REFRESH_ALL
)
823 for (i
=0; i
<MAX_LINES
; i
++)
825 curr_subline
[i
] = SUBLINE_RESET
;
829 #ifdef HAVE_LCD_CHARCELLS
830 for (i
=0; i
<8; i
++) {
831 if (wps_progress_pat
[i
]==0)
832 wps_progress_pat
[i
]=lcd_get_locked_pattern();
842 ff_rewind_count
= ffwd_offset
;
844 for (i
= 0; i
< MAX_LINES
; i
++)
846 new_subline_refresh
= false;
847 only_one_subline
= false;
849 /* if time to advance to next sub-line */
850 if (TIME_AFTER(current_tick
, subline_expire_time
[i
] - 1) ||
851 (curr_subline
[i
] == SUBLINE_RESET
))
853 /* search all sublines until the next subline with time > 0
854 is found or we get back to the subline we started with */
855 if (curr_subline
[i
] == SUBLINE_RESET
)
858 search_start
= curr_subline
[i
];
859 for (search
=0; search
<MAX_SUBLINES
; search
++)
863 /* wrap around if beyond last defined subline or MAX_SUBLINES */
864 if ((!format_lines
[i
][curr_subline
[i
]]) ||
865 (curr_subline
[i
] == MAX_SUBLINES
))
867 if (curr_subline
[i
] == 1)
868 only_one_subline
= true;
872 /* if back where we started after search or
873 only one subline is defined on the line */
874 if (((search
> 0) && (curr_subline
[i
] == search_start
)) ||
877 /* no other subline with a time > 0 exists */
878 subline_expire_time
[i
] = current_tick
+ 100 * HZ
;
883 /* get initial time multiplier and
884 line type flags for this subline */
885 format_display(buf
, sizeof(buf
), id3
, nid3
,
886 format_lines
[i
][curr_subline
[i
]],
887 &time_mult
[i
][curr_subline
[i
]],
888 &line_type
[i
][curr_subline
[i
]]);
890 /* only use this subline if subline time > 0 */
891 if (time_mult
[i
][curr_subline
[i
]] > 0)
893 new_subline_refresh
= true;
894 subline_expire_time
[i
] = current_tick
+
895 BASE_SUBLINE_TIME
* time_mult
[i
][curr_subline
[i
]];
905 if ( !format_lines
[i
][curr_subline
[i
]] )
908 if ((line_type
[i
][curr_subline
[i
]] & refresh_mode
) ||
909 (refresh_mode
== WPS_REFRESH_ALL
) ||
913 format_display(buf
, sizeof(buf
), id3
, nid3
,
914 format_lines
[i
][curr_subline
[i
]],
915 &time_mult
[i
][curr_subline
[i
]],
917 line_type
[i
][curr_subline
[i
]] = flags
;
919 #ifdef HAVE_LCD_BITMAP
921 if (flags
& refresh_mode
& WPS_REFRESH_PLAYER_PROGRESS
) {
922 scrollbar(0, i
*h
+ offset
+ 1, LCD_WIDTH
, 6,
923 id3
->length
?id3
->length
:1, 0,
924 id3
->length
?id3
->elapsed
+ ff_rewind_count
:0,
928 if (flags
& refresh_mode
& WPS_REFRESH_PEAK_METER
) {
933 peak_meter_y
= i
* h
+ offset
;
935 /* The user might decide to have the peak meter in the last
936 line so that it is only displayed if no status bar is
937 visible. If so we neither want do draw nor enable the
939 if (peak_meter_y
+ h
<= LCD_HEIGHT
) {
940 /* found a line with a peak meter -> remember that we must
943 peak_meter_draw(0, peak_meter_y
, LCD_WIDTH
,
944 MIN(h
, LCD_HEIGHT
- peak_meter_y
));
949 if (flags
& refresh_mode
& WPS_REFRESH_PLAYER_PROGRESS
) {
950 if (full_line_progressbar
)
951 draw_player_fullbar(buf
, sizeof(buf
),
952 id3
, ff_rewind_count
);
954 draw_player_progress(id3
, ff_rewind_count
);
958 if (flags
& WPS_REFRESH_SCROLL
) {
961 if ((refresh_mode
& WPS_REFRESH_SCROLL
) ||
962 new_subline_refresh
) {
963 lcd_puts_scroll(0, i
, buf
);
967 else if (flags
& (WPS_REFRESH_DYNAMIC
| WPS_REFRESH_STATIC
))
969 /* dynamic / static line */
970 if ((refresh_mode
& (WPS_REFRESH_DYNAMIC
|WPS_REFRESH_STATIC
)) ||
978 #ifdef HAVE_LCD_BITMAP
980 lcd_update_rect(0, i
*h
+ offset
, LCD_WIDTH
, h
);
984 #ifdef HAVE_LCD_BITMAP
985 /* Now we know wether the peak meter is used.
986 So we can enable / disable the peak meter thread */
987 peak_meter_enabled
= enable_pm
;
990 #if defined(CONFIG_BACKLIGHT) && !defined(SIMULATOR)
991 if (global_settings
.caption_backlight
&& id3
) {
992 /* turn on backlight n seconds before track ends, and turn it off n
993 seconds into the new track. n == backlight_timeout, or 5s */
995 backlight_timeout_value
[global_settings
.backlight_timeout
] * 1000;
998 n
= 5000; /* use 5s if backlight is always on or off */
1000 if ((id3
->elapsed
< 1000) ||
1001 ((id3
->length
- id3
->elapsed
) < (unsigned)n
))
1008 bool wps_display(struct mp3entry
* id3
,
1009 struct mp3entry
* nid3
)
1011 lcd_clear_display();
1013 if (!id3
&& !(mpeg_status() & MPEG_STATUS_PLAY
))
1015 #ifdef HAVE_LCD_CHARCELLS
1016 lcd_puts(0, 0, str(LANG_END_PLAYLIST_PLAYER
));
1018 lcd_puts(0, 2, str(LANG_END_PLAYLIST_RECORDER
));
1021 global_settings
.resume_index
= -1;
1029 if ( !format_buffer
[0] ) {
1030 #ifdef HAVE_LCD_BITMAP
1031 wps_format("%s%?it<%?in<%in. |>%it|%fn>\n"
1032 "%s%?ia<%ia|%?d2<%d2|(root)>>\n"
1033 "%s%?id<%id|%?d1<%d1|(root)>> %?iy<(%iy)|>\n"
1035 "%pc/%pt [%pp:%pe]\n"
1036 "%fbkBit %?fv<avg|> %?iv<(id3v%iv)|(no id3)>\n"
1040 wps_format("%s%pp/%pe: %?it<%it|%fn> - %?ia<%ia|%d2> - %?id<%id|%d1>\n"
1041 "%pc%?ps<*|/>%pt\n");
1047 wps_refresh(id3
, nid3
, 0, WPS_REFRESH_ALL
);
1053 #ifdef HAVE_LCD_CHARCELLS
1054 static bool draw_player_progress(const struct mp3entry
* id3
,
1055 int ff_rewwind_count
)
1057 char player_progressbar
[7];
1065 memset(binline
, 1, sizeof binline
);
1066 memset(player_progressbar
, 1, sizeof player_progressbar
);
1068 if(id3
->elapsed
>= id3
->length
)
1072 if(wps_time_countup
== false)
1073 songpos
= ((id3
->elapsed
- ff_rewwind_count
) * 36) / id3
->length
;
1075 songpos
= ((id3
->elapsed
+ ff_rewwind_count
) * 36) / id3
->length
;
1077 for (i
=0; i
< songpos
; i
++)
1080 for (i
=0; i
<=6; i
++) {
1082 player_progressbar
[i
] <<= 1;
1083 player_progressbar
[i
] += binline
[i
*5+j
];
1086 lcd_define_pattern(wps_progress_pat
[0], player_progressbar
);
1090 static void draw_player_fullbar(char* buf
, int buf_size
,
1091 const struct mp3entry
* id3
,
1092 int ff_rewwind_count
)
1094 int i
,j
,lcd_char_pos
;
1096 char player_progressbar
[7];
1098 static const char numbers
[12][4][3]={
1099 {{1,1,1},{1,0,1},{1,0,1},{1,1,1}},/*0*/
1100 {{0,1,0},{1,1,0},{0,1,0},{0,1,0}},/*1*/
1101 {{1,1,1},{0,0,1},{0,1,0},{1,1,1}},/*2*/
1102 {{1,1,1},{0,0,1},{0,1,1},{1,1,1}},/*3*/
1103 {{1,0,0},{1,1,0},{1,1,1},{0,1,0}},/*4*/
1104 {{1,1,1},{1,1,0},{0,0,1},{1,1,0}},/*5*/
1105 {{1,1,1},{1,0,0},{1,1,1},{1,1,1}},/*6*/
1106 {{1,1,1},{0,0,1},{0,1,0},{1,0,0}},/*7*/
1107 {{1,1,1},{1,1,1},{1,0,1},{1,1,1}},/*8*/
1108 {{1,1,1},{1,1,1},{0,0,1},{1,1,1}},/*9*/
1109 {{0,0,0},{0,1,0},{0,0,0},{0,1,0}},/*:*/
1110 {{0,0,0},{0,0,0},{0,0,0},{0,0,0}} /*<blank>*/
1118 for (i
=0; i
< buf_size
; i
++)
1121 if(id3
->elapsed
>= id3
->length
)
1124 if(wps_time_countup
== false)
1125 songpos
= ((id3
->elapsed
- ff_rewwind_count
) * 55) / id3
->length
;
1127 songpos
= ((id3
->elapsed
+ ff_rewwind_count
) * 55) / id3
->length
;
1130 time
=(id3
->elapsed
+ ff_rewind_count
);
1132 memset(timestr
, 0, sizeof(timestr
));
1133 format_time(timestr
, sizeof(timestr
), time
);
1134 for(lcd_char_pos
=0; lcd_char_pos
<6; lcd_char_pos
++) {
1135 digits
[lcd_char_pos
] = map_fullbar_char(timestr
[lcd_char_pos
]);
1138 /* build the progressbar-icons */
1139 for (lcd_char_pos
=0; lcd_char_pos
<6; lcd_char_pos
++) {
1140 memset(binline
, 0, sizeof binline
);
1141 memset(player_progressbar
, 0, sizeof player_progressbar
);
1143 /* make the character (progressbar & digit)*/
1144 for (i
=0; i
<7; i
++) {
1146 /* make the progressbar */
1147 if (lcd_char_pos
==(songpos
/5)) {
1149 if ((j
<(songpos
%5))&&(i
>4))
1155 if (lcd_char_pos
<(songpos
/5)) {
1156 /* full character */
1161 /* insert the digit */
1163 if (numbers
[digits
[lcd_char_pos
]][i
][j
]==1)
1169 for (i
=0; i
<=6; i
++) {
1171 player_progressbar
[i
] <<= 1;
1172 player_progressbar
[i
] += binline
[i
*5+j
];
1176 lcd_define_pattern(wps_progress_pat
[lcd_char_pos
+1],player_progressbar
);
1177 buf
[lcd_char_pos
]=wps_progress_pat
[lcd_char_pos
+1];
1181 /* make rest of the progressbar if necessary */
1184 /* set the characters positions that use the full 5 pixel wide bar */
1185 for (lcd_char_pos
=6; lcd_char_pos
< (songpos
/5); lcd_char_pos
++)
1186 buf
[lcd_char_pos
] = 0x86; /* '_' */
1188 /* build the partial bar character for the tail character position */
1189 memset(binline
, 0, sizeof binline
);
1190 memset(player_progressbar
, 0, sizeof player_progressbar
);
1192 for (i
=5; i
<7; i
++) {
1194 if (j
<(songpos
%5)) {
1200 for (i
=0; i
<7; i
++) {
1202 player_progressbar
[i
] <<= 1;
1203 player_progressbar
[i
] += binline
[i
*5+j
];
1207 lcd_define_pattern(wps_progress_pat
[7],player_progressbar
);
1209 buf
[songpos
/5]=wps_progress_pat
[7];
1213 static char map_fullbar_char(char ascii_val
)
1215 if (ascii_val
>= '0' && ascii_val
<= '9') {
1216 return(ascii_val
- '0');
1218 else if (ascii_val
== ':') {
1222 return(11); /* anything besides a number or ':' is mapped to <blank> */
1228 /* -----------------------------------------------------------------
1229 * vim: et sw=4 ts=8 sts=4 tw=78