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
, long time
)
242 if ( time
< 3600000 ) {
243 snprintf(buf
, buf_size
, "%d:%02d",
244 (int) (time
% 3600000 / 60000), (int) (time
% 60000 / 1000));
246 snprintf(buf
, buf_size
, "%d:%02d:%02d",
247 (int) (time
/ 3600000), (int) (time
% 3600000 / 60000),
248 (int) (time
% 60000 / 1000));
252 /* Extract a part from a path.
254 * buf - buffer extract part to.
255 * buf_size - size of buffer.
256 * path - path to extract from.
257 * level - what to extract. 0 is file name, 1 is parent of file, 2 is
258 * parent of parent, etc.
260 * Returns buf if the desired level was found, NULL otherwise.
262 static char* get_dir(char* buf
, int buf_size
, const char* path
, int level
)
265 const char* last_sep
;
268 sep
= path
+ strlen(path
);
285 if (level
|| (last_sep
<= sep
))
290 len
= MIN(last_sep
- sep
, buf_size
- 1);
291 strncpy(buf
, sep
+ 1, len
);
296 /* Get the tag specified by the two characters at fmt.
298 * id3 - ID3 data to get tag values from.
299 * nid3 - next-song ID3 data to get tag values from.
300 * tag - string (of two characters) specifying the tag to get.
301 * buf - buffer to certain tags, such as track number, play time or
303 * buf_size - size of buffer.
304 * flags - returns the type of the line. See constants i wps-display.h
306 * Returns the tag. NULL indicates the tag wasn't available.
308 static char* get_tag(struct mp3entry
* cid3
,
309 struct mp3entry
* nid3
,
313 unsigned char* tag_len
,
314 unsigned short* subline_time_mult
,
315 unsigned char* flags
)
317 struct mp3entry
*id3
= cid3
; /* default to current song */
319 if ((0 == tag
[0]) || (0 == tag
[1]))
329 case 'I': /* ID3 Information */
330 id3
= nid3
; /* display next-song data */
331 *flags
|= WPS_REFRESH_DYNAMIC
;
333 return NULL
; /* no such info (yet) */
335 case 'i': /* ID3 Information */
336 *flags
|= WPS_REFRESH_STATIC
;
339 case 't': /* ID3 Title */
342 case 'a': /* ID3 Artist */
345 case 'n': /* ID3 Track Number */
346 if (id3
->track_string
)
347 return id3
->track_string
;
350 snprintf(buf
, buf_size
, "%d", id3
->tracknum
);
355 case 'd': /* ID3 Album/Disc */
358 case 'c': /* ID3 Composer */
359 return id3
->composer
;
362 if( id3
->year_string
)
363 return id3
->year_string
;
366 snprintf(buf
, buf_size
, "%d", id3
->year
);
371 case 'g': /* genre */
372 return id3_get_genre(id3
);
374 case 'v': /* id3 version */
375 switch (id3
->id3version
) {
397 case 'F': /* File Information */
399 *flags
|= WPS_REFRESH_DYNAMIC
;
401 return NULL
; /* no such info (yet) */
403 case 'f': /* File Information */
404 *flags
|= WPS_REFRESH_STATIC
;
407 case 'v': /* VBR file? */
408 return id3
->vbr
? "(avg)" : NULL
;
410 case 'b': /* File Bitrate */
412 snprintf(buf
, buf_size
, "%d", id3
->bitrate
);
414 snprintf(buf
, buf_size
, "?");
417 case 'f': /* File Frequency */
418 snprintf(buf
, buf_size
, "%d", id3
->frequency
);
421 case 'p': /* File Path */
424 case 'm': /* File Name - With Extension */
425 return get_dir(buf
, buf_size
, id3
->path
, 0);
427 case 'n': /* File Name */
428 if (get_dir(buf
, buf_size
, id3
->path
, 0))
430 /* Remove extension */
431 char* sep
= strrchr(buf
, '.');
445 case 's': /* File Size (in kilobytes) */
446 snprintf(buf
, buf_size
, "%d", id3
->filesize
/ 1024);
451 case 'p': /* Playlist/Song Information */
454 case 'b': /* progress bar */
455 *flags
|= WPS_REFRESH_PLAYER_PROGRESS
;
456 #ifdef HAVE_LCD_CHARCELLS
457 snprintf(buf
, buf_size
, "%c", wps_progress_pat
[0]);
458 full_line_progressbar
=0;
463 case 'f': /* full-line progress bar */
464 #ifdef HAVE_LCD_CHARCELLS
465 if(is_new_player()) {
466 *flags
|= WPS_REFRESH_PLAYER_PROGRESS
;
467 *flags
|= WPS_REFRESH_DYNAMIC
;
468 full_line_progressbar
=1;
469 /* we need 11 characters (full line) for
471 snprintf(buf
, buf_size
, " ");
475 /* Tell the user if we have an OldPlayer */
476 snprintf(buf
, buf_size
, " <Old LCD> ");
480 case 'p': /* Playlist Position */
481 *flags
|= WPS_REFRESH_STATIC
;
482 snprintf(buf
, buf_size
, "%d", playlist_get_display_index());
485 case 'n': /* Playlist Name (without path) */
486 *flags
|= WPS_REFRESH_STATIC
;
487 return playlist_name(NULL
, buf
, buf_size
);
489 case 'e': /* Playlist Total Entries */
490 *flags
|= WPS_REFRESH_STATIC
;
491 snprintf(buf
, buf_size
, "%d", playlist_amount());
494 case 'c': /* Current Time in Song */
495 *flags
|= WPS_REFRESH_DYNAMIC
;
496 format_time(buf
, buf_size
, id3
->elapsed
+ ff_rewind_count
);
499 case 'r': /* Remaining Time in Song */
500 *flags
|= WPS_REFRESH_DYNAMIC
;
501 format_time(buf
, buf_size
,
502 id3
->length
- id3
->elapsed
- ff_rewind_count
);
505 case 't': /* Total Time */
506 *flags
|= WPS_REFRESH_STATIC
;
507 format_time(buf
, buf_size
, id3
->length
);
510 #ifdef HAVE_LCD_BITMAP
511 case 'm': /* Peak Meter */
512 *flags
|= WPS_REFRESH_PEAK_METER
;
515 case 's': /* shuffle */
516 if ( global_settings
.playlist_shuffle
)
522 case 'v': /* volume */
523 *flags
|= WPS_REFRESH_DYNAMIC
;
524 snprintf(buf
, buf_size
, "%d%%", global_settings
.volume
);
530 case 'b': /* battery info */
531 *flags
|= WPS_REFRESH_DYNAMIC
;
533 case 'l': /* battery level */
535 int l
= battery_level();
537 snprintf(buf
, buf_size
, "%d%%", l
);
543 case 't': /* estimated battery time */
545 int t
= battery_time();
547 snprintf(buf
, buf_size
, "%dh %dm", t
/ 60, t
% 60);
549 strncpy(buf
, "?h ?m", buf_size
);
555 case 'D': /* Directory path information */
556 id3
= nid3
; /* next song please! */
557 *flags
|= WPS_REFRESH_DYNAMIC
;
559 return NULL
; /* no such info (yet) */
561 case 'd': /* Directory path information */
563 int level
= tag
[1] - '0';
564 *flags
|= WPS_REFRESH_STATIC
;
566 if ((0 < level
) && (9 > level
))
568 return get_dir(buf
, buf_size
, id3
->path
, level
);
573 case 't': /* set sub line time multiplier */
577 bool have_point
= false;
578 bool have_tenth
= false;
580 while (((tag
[d
] >= '0') &&
586 time_mult
= time_mult
* 10;
587 time_mult
= time_mult
+ tag
[d
] - '0';
602 if (have_tenth
== false)
605 *subline_time_mult
= time_mult
;
617 /* Skip to the end of the current %? conditional.
619 * fmt - string to skip it. Should point to somewhere after the leading
620 * "<" char (and before or at the last ">").
621 * to_else - if true, skip to the else part (after the "|", if any), else skip
622 * to the end (the ">").
624 * Returns the new position in fmt.
626 static const char* skip_conditional(const char* fmt
, bool to_else
)
638 if (to_else
&& (1 == level
))
667 while (*fmt
&& ('<' != *fmt
))
684 /* Generate the display based on id3 information and format string.
686 * buf - char buffer to write the display to.
687 * buf_size - the size of buffer.
688 * id3 - the ID3 data to format with.
689 * nid3 - the ID3 data of the next song (might by NULL)
690 * fmt - format description.
691 * flags - returns the type of the line. See constants i wps-display.h
693 static void format_display(char* buf
,
695 struct mp3entry
* id3
,
696 struct mp3entry
* nid3
, /* next song's id3 */
698 unsigned short* subline_time_mult
,
699 unsigned char* flags
)
702 char* buf_start
= buf
;
703 char* buf_end
= buf
+ buf_size
- 1; /* Leave room for end null */
706 unsigned char tag_length
;
708 *subline_time_mult
= DEFAULT_SUBLINE_TIME_MULTIPLIER
;
710 while (fmt
&& *fmt
&& buf
< buf_end
)
722 fmt
= skip_conditional(fmt
, false);
726 /* Else fall through */
740 *flags
|= WPS_REFRESH_SCROLL
;
754 value
= get_tag(id3
, nid3
, fmt
, temp_buf
, sizeof(temp_buf
),
755 &tag_length
, subline_time_mult
, flags
);
757 while (*fmt
&& ('<' != *fmt
))
763 /* No value, so skip to else part */
764 if ((!value
) || (!strlen(value
)))
765 fmt
= skip_conditional(fmt
, true);
771 value
= get_tag(id3
, nid3
, fmt
, temp_buf
, sizeof(temp_buf
),
772 &tag_length
, subline_time_mult
, flags
);
777 while (*value
&& (buf
< buf_end
))
785 /* if resulting line is an empty line, set the subline time to 0 */
787 *subline_time_mult
= 0;
789 /* If no flags have been set, the line didn't contain any format codes.
790 We still want to refresh it. */
792 *flags
= WPS_REFRESH_STATIC
;
795 bool wps_refresh(struct mp3entry
* id3
,
796 struct mp3entry
* nid3
,
798 unsigned char refresh_mode
)
804 bool only_one_subline
;
805 bool new_subline_refresh
;
808 #ifdef HAVE_LCD_BITMAP
809 int h
= font_get(FONT_UI
)->height
;
810 int offset
= global_settings
.statusbar
? STATUSBAR_HEIGHT
: 0;
811 /* to find out wether the peak meter is enabled we
812 assume it wasn't until we find a line that contains
813 the peak meter. We can't use peak_meter_enabled itself
814 because that would mean to turn off the meter thread
815 temporarily. (That shouldn't matter unless yield
816 or sleep is called but who knows...)
818 bool enable_pm
= false;
821 /* reset to first subline if refresh all flag is set */
822 if (refresh_mode
== WPS_REFRESH_ALL
)
824 for (i
=0; i
<MAX_LINES
; i
++)
826 curr_subline
[i
] = SUBLINE_RESET
;
830 #ifdef HAVE_LCD_CHARCELLS
831 for (i
=0; i
<8; i
++) {
832 if (wps_progress_pat
[i
]==0)
833 wps_progress_pat
[i
]=lcd_get_locked_pattern();
843 ff_rewind_count
= ffwd_offset
;
845 for (i
= 0; i
< MAX_LINES
; i
++)
847 new_subline_refresh
= false;
848 only_one_subline
= false;
850 /* if time to advance to next sub-line */
851 if (TIME_AFTER(current_tick
, subline_expire_time
[i
] - 1) ||
852 (curr_subline
[i
] == SUBLINE_RESET
))
854 /* search all sublines until the next subline with time > 0
855 is found or we get back to the subline we started with */
856 if (curr_subline
[i
] == SUBLINE_RESET
)
859 search_start
= curr_subline
[i
];
860 for (search
=0; search
<MAX_SUBLINES
; search
++)
864 /* wrap around if beyond last defined subline or MAX_SUBLINES */
865 if ((!format_lines
[i
][curr_subline
[i
]]) ||
866 (curr_subline
[i
] == MAX_SUBLINES
))
868 if (curr_subline
[i
] == 1)
869 only_one_subline
= true;
873 /* if back where we started after search or
874 only one subline is defined on the line */
875 if (((search
> 0) && (curr_subline
[i
] == search_start
)) ||
878 /* no other subline with a time > 0 exists */
879 subline_expire_time
[i
] = current_tick
+ 100 * HZ
;
884 /* get initial time multiplier and
885 line type flags for this subline */
886 format_display(buf
, sizeof(buf
), id3
, nid3
,
887 format_lines
[i
][curr_subline
[i
]],
888 &time_mult
[i
][curr_subline
[i
]],
889 &line_type
[i
][curr_subline
[i
]]);
891 /* only use this subline if subline time > 0 */
892 if (time_mult
[i
][curr_subline
[i
]] > 0)
894 new_subline_refresh
= true;
895 subline_expire_time
[i
] = current_tick
+
896 BASE_SUBLINE_TIME
* time_mult
[i
][curr_subline
[i
]];
906 if ( !format_lines
[i
][curr_subline
[i
]] )
909 if ((line_type
[i
][curr_subline
[i
]] & refresh_mode
) ||
910 (refresh_mode
== WPS_REFRESH_ALL
) ||
914 format_display(buf
, sizeof(buf
), id3
, nid3
,
915 format_lines
[i
][curr_subline
[i
]],
916 &time_mult
[i
][curr_subline
[i
]],
918 line_type
[i
][curr_subline
[i
]] = flags
;
920 #ifdef HAVE_LCD_BITMAP
922 if (flags
& refresh_mode
& WPS_REFRESH_PLAYER_PROGRESS
) {
923 scrollbar(0, i
*h
+ offset
+ 1, LCD_WIDTH
, 6,
924 id3
->length
?id3
->length
:1, 0,
925 id3
->length
?id3
->elapsed
+ ff_rewind_count
:0,
929 if (flags
& refresh_mode
& WPS_REFRESH_PEAK_METER
) {
934 peak_meter_y
= i
* h
+ offset
;
936 /* The user might decide to have the peak meter in the last
937 line so that it is only displayed if no status bar is
938 visible. If so we neither want do draw nor enable the
940 if (peak_meter_y
+ h
<= LCD_HEIGHT
) {
941 /* found a line with a peak meter -> remember that we must
944 peak_meter_draw(0, peak_meter_y
, LCD_WIDTH
,
945 MIN(h
, LCD_HEIGHT
- peak_meter_y
));
950 if (flags
& refresh_mode
& WPS_REFRESH_PLAYER_PROGRESS
) {
951 if (full_line_progressbar
)
952 draw_player_fullbar(buf
, sizeof(buf
),
953 id3
, ff_rewind_count
);
955 draw_player_progress(id3
, ff_rewind_count
);
959 if (flags
& WPS_REFRESH_SCROLL
) {
962 if ((refresh_mode
& WPS_REFRESH_SCROLL
) ||
963 new_subline_refresh
) {
964 lcd_puts_scroll(0, i
, buf
);
968 else if (flags
& (WPS_REFRESH_DYNAMIC
| WPS_REFRESH_STATIC
))
970 /* dynamic / static line */
971 if ((refresh_mode
& (WPS_REFRESH_DYNAMIC
|WPS_REFRESH_STATIC
)) ||
979 #ifdef HAVE_LCD_BITMAP
981 lcd_update_rect(0, i
*h
+ offset
, LCD_WIDTH
, h
);
985 #ifdef HAVE_LCD_BITMAP
986 /* Now we know wether the peak meter is used.
987 So we can enable / disable the peak meter thread */
988 peak_meter_enabled
= enable_pm
;
991 #if defined(CONFIG_BACKLIGHT) && !defined(SIMULATOR)
992 if (global_settings
.caption_backlight
&& id3
) {
993 /* turn on backlight n seconds before track ends, and turn it off n
994 seconds into the new track. n == backlight_timeout, or 5s */
996 backlight_timeout_value
[global_settings
.backlight_timeout
] * 1000;
999 n
= 5000; /* use 5s if backlight is always on or off */
1001 if ((id3
->elapsed
< 1000) ||
1002 ((id3
->length
- id3
->elapsed
) < (unsigned)n
))
1009 bool wps_display(struct mp3entry
* id3
,
1010 struct mp3entry
* nid3
)
1012 lcd_clear_display();
1014 if (!id3
&& !(audio_status() & AUDIO_STATUS_PLAY
))
1016 #ifdef HAVE_LCD_CHARCELLS
1017 lcd_puts(0, 0, str(LANG_END_PLAYLIST_PLAYER
));
1019 lcd_puts(0, 2, str(LANG_END_PLAYLIST_RECORDER
));
1022 global_settings
.resume_index
= -1;
1030 if ( !format_buffer
[0] ) {
1031 #ifdef HAVE_LCD_BITMAP
1032 wps_format("%s%?it<%?in<%in. |>%it|%fn>\n"
1033 "%s%?ia<%ia|%?d2<%d2|(root)>>\n"
1034 "%s%?id<%id|%?d1<%d1|(root)>> %?iy<(%iy)|>\n"
1036 "%pc/%pt [%pp:%pe]\n"
1037 "%fbkBit %?fv<avg|> %?iv<(id3v%iv)|(no id3)>\n"
1041 wps_format("%s%pp/%pe: %?it<%it|%fn> - %?ia<%ia|%d2> - %?id<%id|%d1>\n"
1042 "%pc%?ps<*|/>%pt\n");
1048 wps_refresh(id3
, nid3
, 0, WPS_REFRESH_ALL
);
1054 #ifdef HAVE_LCD_CHARCELLS
1055 static bool draw_player_progress(const struct mp3entry
* id3
,
1056 int ff_rewwind_count
)
1058 char player_progressbar
[7];
1066 memset(binline
, 1, sizeof binline
);
1067 memset(player_progressbar
, 1, sizeof player_progressbar
);
1069 if(id3
->elapsed
>= id3
->length
)
1073 if(wps_time_countup
== false)
1074 songpos
= ((id3
->elapsed
- ff_rewwind_count
) * 36) / id3
->length
;
1076 songpos
= ((id3
->elapsed
+ ff_rewwind_count
) * 36) / id3
->length
;
1078 for (i
=0; i
< songpos
; i
++)
1081 for (i
=0; i
<=6; i
++) {
1083 player_progressbar
[i
] <<= 1;
1084 player_progressbar
[i
] += binline
[i
*5+j
];
1087 lcd_define_pattern(wps_progress_pat
[0], player_progressbar
);
1091 static void draw_player_fullbar(char* buf
, int buf_size
,
1092 const struct mp3entry
* id3
,
1093 int ff_rewwind_count
)
1095 int i
,j
,lcd_char_pos
;
1097 char player_progressbar
[7];
1099 static const char numbers
[12][4][3]={
1100 {{1,1,1},{1,0,1},{1,0,1},{1,1,1}},/*0*/
1101 {{0,1,0},{1,1,0},{0,1,0},{0,1,0}},/*1*/
1102 {{1,1,1},{0,0,1},{0,1,0},{1,1,1}},/*2*/
1103 {{1,1,1},{0,0,1},{0,1,1},{1,1,1}},/*3*/
1104 {{1,0,0},{1,1,0},{1,1,1},{0,1,0}},/*4*/
1105 {{1,1,1},{1,1,0},{0,0,1},{1,1,0}},/*5*/
1106 {{1,1,1},{1,0,0},{1,1,1},{1,1,1}},/*6*/
1107 {{1,1,1},{0,0,1},{0,1,0},{1,0,0}},/*7*/
1108 {{1,1,1},{1,1,1},{1,0,1},{1,1,1}},/*8*/
1109 {{1,1,1},{1,1,1},{0,0,1},{1,1,1}},/*9*/
1110 {{0,0,0},{0,1,0},{0,0,0},{0,1,0}},/*:*/
1111 {{0,0,0},{0,0,0},{0,0,0},{0,0,0}} /*<blank>*/
1119 for (i
=0; i
< buf_size
; i
++)
1122 if(id3
->elapsed
>= id3
->length
)
1125 if(wps_time_countup
== false)
1126 songpos
= ((id3
->elapsed
- ff_rewwind_count
) * 55) / id3
->length
;
1128 songpos
= ((id3
->elapsed
+ ff_rewwind_count
) * 55) / id3
->length
;
1131 time
=(id3
->elapsed
+ ff_rewind_count
);
1133 memset(timestr
, 0, sizeof(timestr
));
1134 format_time(timestr
, sizeof(timestr
), time
);
1135 for(lcd_char_pos
=0; lcd_char_pos
<6; lcd_char_pos
++) {
1136 digits
[lcd_char_pos
] = map_fullbar_char(timestr
[lcd_char_pos
]);
1139 /* build the progressbar-icons */
1140 for (lcd_char_pos
=0; lcd_char_pos
<6; lcd_char_pos
++) {
1141 memset(binline
, 0, sizeof binline
);
1142 memset(player_progressbar
, 0, sizeof player_progressbar
);
1144 /* make the character (progressbar & digit)*/
1145 for (i
=0; i
<7; i
++) {
1147 /* make the progressbar */
1148 if (lcd_char_pos
==(songpos
/5)) {
1150 if ((j
<(songpos
%5))&&(i
>4))
1156 if (lcd_char_pos
<(songpos
/5)) {
1157 /* full character */
1162 /* insert the digit */
1164 if (numbers
[digits
[lcd_char_pos
]][i
][j
]==1)
1170 for (i
=0; i
<=6; i
++) {
1172 player_progressbar
[i
] <<= 1;
1173 player_progressbar
[i
] += binline
[i
*5+j
];
1177 lcd_define_pattern(wps_progress_pat
[lcd_char_pos
+1],player_progressbar
);
1178 buf
[lcd_char_pos
]=wps_progress_pat
[lcd_char_pos
+1];
1182 /* make rest of the progressbar if necessary */
1185 /* set the characters positions that use the full 5 pixel wide bar */
1186 for (lcd_char_pos
=6; lcd_char_pos
< (songpos
/5); lcd_char_pos
++)
1187 buf
[lcd_char_pos
] = 0x86; /* '_' */
1189 /* build the partial bar character for the tail character position */
1190 memset(binline
, 0, sizeof binline
);
1191 memset(player_progressbar
, 0, sizeof player_progressbar
);
1193 for (i
=5; i
<7; i
++) {
1195 if (j
<(songpos
%5)) {
1201 for (i
=0; i
<7; i
++) {
1203 player_progressbar
[i
] <<= 1;
1204 player_progressbar
[i
] += binline
[i
*5+j
];
1208 lcd_define_pattern(wps_progress_pat
[7],player_progressbar
);
1210 buf
[songpos
/5]=wps_progress_pat
[7];
1214 static char map_fullbar_char(char ascii_val
)
1216 if (ascii_val
>= '0' && ascii_val
<= '9') {
1217 return(ascii_val
- '0');
1219 else if (ascii_val
== ':') {
1223 return(11); /* anything besides a number or ':' is mapped to <blank> */
1229 /* -----------------------------------------------------------------
1230 * vim: et sw=4 ts=8 sts=4 tw=78