1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002-2007 Björn Stenberg
11 * Copyright (C) 2007-2008 Nicolas Pennequin
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
24 #include "string-extra.h"
29 #include "settings_list.h"
30 #include "rbunicode.h"
31 #include "timefuncs.h"
34 #include "powermgmt.h"
38 #ifdef HAVE_LCD_CHARCELLS
45 #ifdef HAVE_LCD_BITMAP
46 #include "peakmeter.h"
52 #if CONFIG_CODEC == SWCODEC
59 #include "wps_internals.h"
60 #include "skin_engine.h"
61 #include "statusbar-skinned.h"
62 #include "root_menu.h"
64 #include "recording.h"
65 #include "pcm_record.h"
74 #define NOINLINE __attribute__ ((noinline))
76 extern struct wps_state wps_state
;
78 static const char* get_codectype(const struct mp3entry
* id3
)
80 if (id3
&& id3
->codectype
< AFMT_NUM_CODECS
) {
81 return audio_formats
[id3
->codectype
].label
;
87 /* Extract a part from a path.
89 * buf - buffer extract part to.
90 * buf_size - size of buffer.
91 * path - path to extract from.
92 * level - what to extract. 0 is file name, 1 is parent of file, 2 is
93 * parent of parent, etc.
95 * Returns buf if the desired level was found, NULL otherwise.
97 char* get_dir(char* buf
, int buf_size
, const char* path
, int level
)
100 const char* last_sep
;
103 sep
= path
+ strlen(path
);
118 if (level
|| (last_sep
<= sep
))
121 len
= MIN(last_sep
- sep
, buf_size
- 1);
122 strlcpy(buf
, sep
+ 1, len
+ 1);
126 #if (CONFIG_CODEC != MAS3507D) && defined (HAVE_PITCHSCREEN)
127 /* A helper to determine the enum value for pitch/speed.
129 When there are two choices (i.e. boolean), return 1 if the value is
130 different from normal value and 2 if the value is the same as the
131 normal value. E.g. "%?Sp<%Sp>" would show the pitch only when
132 playing at a modified pitch.
134 When there are more than two choices (i.e. enum), the left half of
135 the choices are to show 0..normal range, and the right half of the
136 choices are to show values over that. The last entry is used when
137 it is set to the normal setting, following the rockbox convention
138 to use the last entry for special values.
142 2 items: %?Sp<0..99 or 101..infinity|100>
143 3 items: %?Sp<0..99|101..infinity|100>
144 4 items: %?Sp<0..49|50..99|101..infinity|100>
145 5 items: %?Sp<0..49|50..99|101..149|150..infinity|100>
146 6 items: %?Sp<0..33|34..66|67..99|101..133|134..infinity|100>
147 7 items: %?Sp<0..33|34..66|67..99|101..133|134..167|167..infinity|100>
149 static int pitch_speed_enum(int range
, int32_t val
, int32_t normval
)
155 return (val
== normval
) + 1;
159 n
= (center
* val
) / normval
+ 1;
160 return (range
<= n
) ? (range
- 1) : n
;
164 const char *get_cuesheetid3_token(struct wps_token
*token
, struct mp3entry
*id3
,
165 int offset_tracks
, char *buf
, int buf_size
)
167 struct cuesheet
*cue
= id3
?id3
->cuesheet
:NULL
;
168 if (!cue
|| !cue
->curr_track
)
171 struct cue_track_info
*track
= cue
->curr_track
;
174 if (cue
->curr_track_idx
+offset_tracks
< cue
->track_count
)
175 track
+=offset_tracks
;
181 case SKIN_TOKEN_METADATA_ARTIST
:
182 return *track
->performer
? track
->performer
: NULL
;
183 case SKIN_TOKEN_METADATA_COMPOSER
:
184 return *track
->songwriter
? track
->songwriter
: NULL
;
185 case SKIN_TOKEN_METADATA_ALBUM
:
186 return *cue
->title
? cue
->title
: NULL
;
187 case SKIN_TOKEN_METADATA_ALBUM_ARTIST
:
188 return *cue
->performer
? cue
->performer
: NULL
;
189 case SKIN_TOKEN_METADATA_TRACK_TITLE
:
190 return *track
->title
? track
->title
: NULL
;
191 case SKIN_TOKEN_METADATA_TRACK_NUMBER
:
192 snprintf(buf
, buf_size
, "%d/%d",
193 cue
->curr_track_idx
+offset_tracks
+1, cue
->track_count
);
201 static const char* get_filename_token(struct wps_token
*token
, char* filename
,
202 char *buf
, int buf_size
)
208 case SKIN_TOKEN_FILE_PATH
:
210 case SKIN_TOKEN_FILE_NAME
:
211 if (get_dir(buf
, buf_size
, filename
, 0)) {
212 /* Remove extension */
213 char* sep
= strrchr(buf
, '.');
220 case SKIN_TOKEN_FILE_NAME_WITH_EXTENSION
:
221 return get_dir(buf
, buf_size
, filename
, 0);
222 case SKIN_TOKEN_FILE_DIRECTORY
:
223 return get_dir(buf
, buf_size
, filename
, token
->value
.i
);
231 /* All tokens which only need the info to return a value go in here */
232 const char *get_id3_token(struct wps_token
*token
, struct mp3entry
*id3
,
233 char *filename
, char *buf
, int buf_size
, int limit
, int *intval
)
235 struct wps_state
*state
= &wps_state
;
238 unsigned long length
= id3
->length
;
239 unsigned long elapsed
= id3
->elapsed
+ state
->ff_rewind_count
;
242 case SKIN_TOKEN_METADATA_ARTIST
:
244 case SKIN_TOKEN_METADATA_COMPOSER
:
245 return id3
->composer
;
246 case SKIN_TOKEN_METADATA_ALBUM
:
248 case SKIN_TOKEN_METADATA_ALBUM_ARTIST
:
249 return id3
->albumartist
;
250 case SKIN_TOKEN_METADATA_GROUPING
:
251 return id3
->grouping
;
252 case SKIN_TOKEN_METADATA_GENRE
:
253 return id3
->genre_string
;
254 case SKIN_TOKEN_METADATA_DISC_NUMBER
:
255 if (id3
->disc_string
)
256 return id3
->disc_string
;
258 snprintf(buf
, buf_size
, "%d", id3
->discnum
);
262 case SKIN_TOKEN_METADATA_TRACK_NUMBER
:
263 if (id3
->track_string
)
264 return id3
->track_string
;
266 snprintf(buf
, buf_size
, "%d", id3
->tracknum
);
270 case SKIN_TOKEN_METADATA_TRACK_TITLE
:
272 case SKIN_TOKEN_METADATA_VERSION
:
273 switch (id3
->id3version
)
289 case SKIN_TOKEN_METADATA_YEAR
:
290 if( id3
->year_string
)
291 return id3
->year_string
;
293 snprintf(buf
, buf_size
, "%d", id3
->year
);
297 case SKIN_TOKEN_METADATA_COMMENT
:
299 case SKIN_TOKEN_FILE_BITRATE
:
301 snprintf(buf
, buf_size
, "%d", id3
->bitrate
);
305 case SKIN_TOKEN_TRACK_TIME_ELAPSED
:
306 format_time(buf
, buf_size
, elapsed
);
309 case SKIN_TOKEN_TRACK_TIME_REMAINING
:
310 format_time(buf
, buf_size
, length
- elapsed
);
313 case SKIN_TOKEN_TRACK_LENGTH
:
314 format_time(buf
, buf_size
, length
);
317 case SKIN_TOKEN_TRACK_ELAPSED_PERCENT
:
323 if (limit
== TOKEN_VALUE_ONLY
)
324 limit
= 100; /* make it a percentage */
325 *intval
= limit
* elapsed
/ length
+ 1;
327 snprintf(buf
, buf_size
, "%lu", 100 * elapsed
/ length
);
330 case SKIN_TOKEN_TRACK_STARTING
:
332 unsigned long time
= token
->value
.i
* (HZ
/TIMEOUT_UNIT
);
337 case SKIN_TOKEN_TRACK_ENDING
:
339 unsigned long time
= token
->value
.i
* (HZ
/TIMEOUT_UNIT
);
340 if (length
- elapsed
< time
)
345 case SKIN_TOKEN_FILE_CODEC
:
348 if(id3
->codectype
== AFMT_UNKNOWN
)
349 *intval
= AFMT_NUM_CODECS
;
351 *intval
= id3
->codectype
;
353 return get_codectype(id3
);
355 case SKIN_TOKEN_FILE_FREQUENCY
:
356 snprintf(buf
, buf_size
, "%ld", id3
->frequency
);
358 case SKIN_TOKEN_FILE_FREQUENCY_KHZ
:
359 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
360 if ((id3
->frequency
% 1000) < 100)
361 snprintf(buf
, buf_size
, "%ld", id3
->frequency
/ 1000);
363 snprintf(buf
, buf_size
, "%ld.%lu",
364 id3
->frequency
/ 1000,
365 (id3
->frequency
% 1000) / 100);
367 case SKIN_TOKEN_FILE_VBR
:
368 return (id3
->vbr
) ? "(avg)" : NULL
;
369 case SKIN_TOKEN_FILE_SIZE
:
370 snprintf(buf
, buf_size
, "%ld", id3
->filesize
/ 1024);
374 case SKIN_TOKEN_DATABASE_PLAYCOUNT
:
376 *intval
= id3
->playcount
+ 1;
377 snprintf(buf
, buf_size
, "%ld", id3
->playcount
);
379 case SKIN_TOKEN_DATABASE_RATING
:
381 *intval
= id3
->rating
+ 1;
382 snprintf(buf
, buf_size
, "%d", id3
->rating
);
384 case SKIN_TOKEN_DATABASE_AUTOSCORE
:
386 *intval
= id3
->score
+ 1;
387 snprintf(buf
, buf_size
, "%d", id3
->score
);
392 return get_filename_token(token
, id3
->path
, buf
, buf_size
);
395 else /* id3 == NULL, handle the error based on the expected return type */
399 /* Most tokens expect NULL on error so leave that for the default case,
400 * The ones that expect "0" need to be handled */
401 case SKIN_TOKEN_FILE_FREQUENCY
:
402 case SKIN_TOKEN_FILE_FREQUENCY_KHZ
:
403 case SKIN_TOKEN_FILE_SIZE
:
405 case SKIN_TOKEN_DATABASE_PLAYCOUNT
:
406 case SKIN_TOKEN_DATABASE_RATING
:
407 case SKIN_TOKEN_DATABASE_AUTOSCORE
:
413 return get_filename_token(token
, filename
, buf
, buf_size
);
421 /* Formats the frequency (specified in Hz) in MHz, */
422 /* with one or two digits after the decimal point -- */
423 /* depending on the frequency changing step. */
425 static char *format_freq_MHz(int freq
, int freq_step
, char *buf
, int buf_size
)
429 if (freq_step
< 100000)
431 /* Format with two digits after decimal point */
437 /* Format with one digit after decimal point */
441 div
= 1000000 / scale
;
443 snprintf(buf
, buf_size
, fmt
, freq
/div
, freq
%div
);
448 /* Tokens which are really only used by the radio screen go in here */
449 const char *get_radio_token(struct wps_token
*token
, int preset_offset
,
450 char *buf
, int buf_size
, int limit
, int *intval
)
452 const struct fm_region_data
*region_data
=
453 &(fm_region_data
[global_settings
.fm_region
]);
457 /* Radio/tuner tokens */
458 case SKIN_TOKEN_TUNER_TUNED
:
459 if (tuner_get(RADIO_TUNED
))
462 case SKIN_TOKEN_TUNER_SCANMODE
:
463 if (radio_scan_mode())
466 case SKIN_TOKEN_TUNER_STEREO
:
467 if (radio_is_stereo())
470 case SKIN_TOKEN_TUNER_MINFREQ
: /* changes based on "region" */
471 return format_freq_MHz(region_data
->freq_min
,
472 region_data
->freq_step
, buf
, buf_size
);
473 case SKIN_TOKEN_TUNER_MAXFREQ
: /* changes based on "region" */
474 return format_freq_MHz(region_data
->freq_max
,
475 region_data
->freq_step
, buf
, buf_size
);
476 case SKIN_TOKEN_TUNER_CURFREQ
:
477 return format_freq_MHz(radio_current_frequency(),
478 region_data
->freq_step
, buf
, buf_size
);
479 #ifdef HAVE_RADIO_RSSI
480 case SKIN_TOKEN_TUNER_RSSI
:
481 snprintf(buf
, buf_size
, "%d",tuner_get(RADIO_RSSI
));
484 int val
= tuner_get(RADIO_RSSI
);
485 int min
= tuner_get(RADIO_RSSI_MIN
);
486 int max
= tuner_get(RADIO_RSSI_MAX
);
487 if (limit
== TOKEN_VALUE_ONLY
)
493 *intval
= 1+(limit
-1)*(val
-min
)/(max
-1-min
);
497 case SKIN_TOKEN_TUNER_RSSI_MIN
:
498 snprintf(buf
, buf_size
, "%d",tuner_get(RADIO_RSSI_MIN
));
500 case SKIN_TOKEN_TUNER_RSSI_MAX
:
501 snprintf(buf
, buf_size
, "%d",tuner_get(RADIO_RSSI_MAX
));
504 case SKIN_TOKEN_PRESET_NAME
:
505 case SKIN_TOKEN_PRESET_FREQ
:
506 case SKIN_TOKEN_PRESET_ID
:
508 int preset_count
= radio_preset_count();
509 int cur_preset
= radio_current_preset();
510 if (preset_count
== 0 || cur_preset
< 0)
512 int preset
= cur_preset
+ preset_offset
;
513 /* make sure it's in the valid range */
514 preset
%= preset_count
;
516 preset
+= preset_count
;
517 if (token
->type
== SKIN_TOKEN_PRESET_NAME
)
518 snprintf(buf
, buf_size
, "%s", radio_get_preset(preset
)->name
);
519 else if (token
->type
== SKIN_TOKEN_PRESET_FREQ
)
520 format_freq_MHz(radio_get_preset(preset
)->frequency
,
521 region_data
->freq_step
, buf
, buf_size
);
523 snprintf(buf
, buf_size
, "%d", preset
+ 1);
526 case SKIN_TOKEN_PRESET_COUNT
:
527 snprintf(buf
, buf_size
, "%d", radio_preset_count());
529 *intval
= radio_preset_count();
531 case SKIN_TOKEN_HAVE_RDS
:
534 case SKIN_TOKEN_RDS_NAME
:
535 return tuner_get_rds_info(RADIO_RDS_NAME
);
536 case SKIN_TOKEN_RDS_TEXT
:
537 return tuner_get_rds_info(RADIO_RDS_TEXT
);
539 return NULL
; /* end of the SKIN_TOKEN_HAVE_RDS case */
540 #endif /* HAVE_RDS_CAP */
548 static struct mp3entry
* get_mp3entry_from_offset(int offset
, char **filename
)
550 struct mp3entry
* pid3
= NULL
;
551 struct wps_state
*state
= skin_get_global_state();
552 struct cuesheet
*cue
= state
->id3
? state
->id3
->cuesheet
: NULL
;
553 const char *fname
= NULL
;
554 if (cue
&& cue
->curr_track_idx
+ offset
< cue
->track_count
)
556 else if (offset
== 0)
558 else if (offset
== 1)
562 static char filename_buf
[MAX_PATH
+ 1];
563 fname
= playlist_peek(offset
, filename_buf
, sizeof(filename_buf
));
564 *filename
= (char*)fname
;
565 #if CONFIG_CODEC == SWCODEC
566 static struct mp3entry tempid3
;
568 #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
569 tagcache_fill_tags(&tempid3
, fname
) ||
571 audio_peek_track(&tempid3
, offset
)
581 #ifdef HAVE_LCD_CHARCELLS
582 static void format_player_progress(struct gui_wps
*gwps
)
584 struct wps_state
*state
= skin_get_global_state();
585 struct screen
*display
= gwps
->display
;
586 unsigned char progress_pattern
[7];
591 if (LIKELY(state
->id3
))
593 elapsed
= state
->id3
->elapsed
;
594 length
= state
->id3
->length
;
603 pos
= 36 * (elapsed
+ state
->ff_rewind_count
) / length
;
605 for (i
= 0; i
< 7; i
++, pos
-= 5)
608 progress_pattern
[i
] = 0x1fu
;
610 progress_pattern
[i
] = 0x00u
;
612 progress_pattern
[i
] = 0x1fu
>> pos
;
615 display
->define_pattern(gwps
->data
->wps_progress_pat
[0], progress_pattern
);
618 static void format_player_fullbar(struct gui_wps
*gwps
, char* buf
, int buf_size
)
620 static const unsigned char numbers
[10][4] = {
621 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */
622 {0x04, 0x0c, 0x04, 0x04}, /* 1 */
623 {0x0e, 0x02, 0x04, 0x0e}, /* 2 */
624 {0x0e, 0x02, 0x06, 0x0e}, /* 3 */
625 {0x08, 0x0c, 0x0e, 0x04}, /* 4 */
626 {0x0e, 0x0c, 0x02, 0x0c}, /* 5 */
627 {0x0e, 0x08, 0x0e, 0x0e}, /* 6 */
628 {0x0e, 0x02, 0x04, 0x08}, /* 7 */
629 {0x0e, 0x0e, 0x0a, 0x0e}, /* 8 */
630 {0x0e, 0x0e, 0x02, 0x0e} /* 9 */
633 struct wps_state
*state
= skin_get_global_state();
634 struct screen
*display
= gwps
->display
;
635 struct wps_data
*data
= gwps
->data
;
636 unsigned char progress_pattern
[7];
646 if (LIKELY(state
->id3
))
648 elapsed
= state
->id3
->elapsed
;
649 length
= state
->id3
->length
;
657 if (buf_size
< 34) /* worst case: 11x UTF-8 char + \0 */
660 time
= elapsed
+ state
->ff_rewind_count
;
662 pos
= 55 * time
/ length
;
664 memset(timestr
, 0, sizeof(timestr
));
665 format_time(timestr
, sizeof(timestr
)-2, time
);
666 timestr
[strlen(timestr
)] = ':'; /* always safe */
668 for (i
= 0; i
< 11; i
++, pos
-= 5)
671 memset(progress_pattern
, 0, sizeof(progress_pattern
));
673 if ((digit
= timestr
[time_idx
]))
678 if (timestr
[time_idx
+ 1] == ':') /* ones, left aligned */
680 memcpy(progress_pattern
, numbers
[digit
], 4);
683 else /* tens, shifted right */
685 for (j
= 0; j
< 4; j
++)
686 progress_pattern
[j
] = numbers
[digit
][j
] >> 1;
688 if (time_idx
> 0) /* not the first group, add colon in front */
690 progress_pattern
[1] |= 0x10u
;
691 progress_pattern
[3] |= 0x10u
;
697 progress_pattern
[5] = progress_pattern
[6] = 0x1fu
;
700 if (pos
> 0 && pos
< 5)
703 progress_pattern
[5] = progress_pattern
[6] = (~0x1fu
>> pos
) & 0x1fu
;
706 if (softchar
&& pat_idx
< 8)
708 display
->define_pattern(data
->wps_progress_pat
[pat_idx
],
710 buf
= utf8encode(data
->wps_progress_pat
[pat_idx
], buf
);
714 buf
= utf8encode(' ', buf
);
716 buf
= utf8encode(0xe115, buf
); /* 2/7 _ */
721 #endif /* HAVE_LCD_CHARCELLS */
723 /* Don't inline this; it was broken out of get_token_value to reduce stack
726 static const char* NOINLINE
get_lif_token_value(struct gui_wps
*gwps
,
727 struct logical_if
*lif
,
728 int offset
, char *buf
,
731 int a
= lif
->num_options
;
733 const char* out_text
= get_token_value(gwps
, lif
->token
, offset
,
735 if (a
== -1 && lif
->token
->type
!= SKIN_TOKEN_VOLUME
)
736 a
= (out_text
&& *out_text
) ? 1 : 0;
737 switch (lif
->operand
.type
)
740 if (lif
->op
== IF_EQUALS
)
741 return (out_text
&& strcmp(out_text
, lif
->operand
.data
.text
) == 0)
748 b
= lif
->operand
.data
.number
;
752 char temp_buf
[MAX_PATH
];
754 struct wps_token
*token
= lif
->operand
.data
.code
->data
;
755 b
= lif
->num_options
;
756 outb
= get_token_value(gwps
, token
, offset
, temp_buf
,
757 sizeof(temp_buf
), &b
);
758 if (b
== -1 && lif
->token
->type
!= SKIN_TOKEN_VOLUME
)
760 if (!out_text
|| !outb
)
761 return (lif
->op
== IF_EQUALS
) ? NULL
: "neq";
762 bool equal
= strcmp(out_text
, outb
) == 0;
763 if (lif
->op
== IF_EQUALS
)
764 return equal
? "eq" : NULL
;
765 else if (lif
->op
== IF_NOTEQUALS
)
766 return !equal
? "neq" : NULL
;
768 b
= (outb
&& *outb
) ? 1 : 0;
779 return a
== b
? "eq" : NULL
;
781 return a
!= b
? "neq" : NULL
;
783 return a
< b
? "lt" : NULL
;
785 return a
<= b
? "lte" : NULL
;
787 return a
> b
? "gt" : NULL
;
788 case IF_GREATERTHAN_EQ
:
789 return a
>= b
? "gte" : NULL
;
794 /* Return the tags value as text. buf should be used as temp storage if needed.
796 intval is used with conditionals/enums: when this function is called,
797 intval should contain the number of options in the conditional/enum.
798 When this function returns, intval is -1 if the tag is non numeric or,
799 if the tag is numeric, *intval is the enum case we want to go to (between 1
800 and the original value of *intval, inclusive).
801 When not treating a conditional/enum, intval should be NULL.
803 const char *get_token_value(struct gui_wps
*gwps
,
804 struct wps_token
*token
, int offset
,
805 char *buf
, int buf_size
,
811 struct wps_data
*data
= gwps
->data
;
812 struct wps_state
*state
= skin_get_global_state();
813 struct mp3entry
*id3
; /* Think very carefully about using this.
814 maybe get_id3_token() is the better place? */
815 const char *out_text
= NULL
;
816 char *filename
= NULL
;
821 id3
= get_mp3entry_from_offset(token
->next
? 1: offset
, &filename
);
823 filename
= id3
->path
;
826 struct tm
* tm
= NULL
;
828 /* if the token is an RTC one, update the time
829 and do the necessary checks */
830 if (token
->type
>= SKIN_TOKENS_RTC_BEGIN
831 && token
->type
<= SKIN_TOKENS_RTC_END
)
847 if (id3
&& id3
== state
->id3
&& id3
->cuesheet
)
849 out_text
= get_cuesheetid3_token(token
, id3
,
850 token
->next
?1:offset
, buf
, buf_size
);
854 out_text
= get_id3_token(token
, id3
, filename
, buf
, buf_size
, limit
, intval
);
858 out_text
= get_radio_token(token
, offset
, buf
, buf_size
, limit
, intval
);
865 case SKIN_TOKEN_LOGICAL_IF
:
867 struct logical_if
*lif
= token
->value
.data
;
868 return get_lif_token_value(gwps
, lif
, offset
, buf
, buf_size
);
872 case SKIN_TOKEN_CHARACTER
:
873 if (token
->value
.c
== '\n')
875 return &(token
->value
.c
);
877 case SKIN_TOKEN_STRING
:
878 return (char*)token
->value
.data
;
880 case SKIN_TOKEN_TRANSLATEDSTRING
:
881 return (char*)P2STR(ID2P(token
->value
.i
));
883 case SKIN_TOKEN_PLAYLIST_ENTRIES
:
884 snprintf(buf
, buf_size
, "%d", playlist_amount());
886 *intval
= playlist_amount();
888 #ifdef HAVE_LCD_BITMAP
889 case SKIN_TOKEN_LIST_TITLE_TEXT
:
890 return sb_get_title(gwps
->display
->screen_type
);
891 case SKIN_TOKEN_LIST_TITLE_ICON
:
893 *intval
= sb_get_icon(gwps
->display
->screen_type
);
894 snprintf(buf
, buf_size
, "%d",sb_get_icon(gwps
->display
->screen_type
));
897 case SKIN_TOKEN_PLAYLIST_NAME
:
898 return playlist_name(NULL
, buf
, buf_size
);
900 case SKIN_TOKEN_PLAYLIST_POSITION
:
901 snprintf(buf
, buf_size
, "%d", playlist_get_display_index()+offset
);
903 *intval
= playlist_get_display_index()+offset
;
906 case SKIN_TOKEN_PLAYLIST_SHUFFLE
:
907 if ( global_settings
.playlist_shuffle
)
913 case SKIN_TOKEN_VOLUME
:
914 snprintf(buf
, buf_size
, "%d", global_settings
.volume
);
917 int minvol
= sound_min(SOUND_VOLUME
);
918 if (limit
== TOKEN_VALUE_ONLY
)
920 *intval
= global_settings
.volume
;
922 else if (global_settings
.volume
== minvol
)
926 else if (global_settings
.volume
== 0)
930 else if (global_settings
.volume
> 0)
936 *intval
= (limit
-3) * (global_settings
.volume
- minvol
- 1)
942 case SKIN_TOKEN_ALBUMART_FOUND
:
946 handle
= playback_current_aa_hid(data
->playback_aa_slot
);
948 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF
))
950 struct dim dim
= {data
->albumart
->width
, data
->albumart
->height
};
951 handle
= radio_get_art_hid(&dim
);
960 case SKIN_TOKEN_BATTERY_PERCENT
:
962 int l
= battery_level();
966 if (limit
== TOKEN_VALUE_ONLY
)
972 limit
= MAX(limit
, 3);
974 /* First enum is used for "unknown level",
975 * last enum is used for 100%.
977 *intval
= (limit
- 2) * l
/ 100 + 2;
985 snprintf(buf
, buf_size
, "%d", l
);
992 case SKIN_TOKEN_BATTERY_VOLTS
:
994 unsigned int v
= battery_voltage();
995 snprintf(buf
, buf_size
, "%d.%02d", v
/ 1000, (v
% 1000) / 10);
999 case SKIN_TOKEN_BATTERY_TIME
:
1001 int t
= battery_time();
1003 snprintf(buf
, buf_size
, "%dh %dm", t
/ 60, t
% 60);
1010 case SKIN_TOKEN_BATTERY_CHARGER_CONNECTED
:
1012 if(charger_input_state
==CHARGER
)
1018 #if CONFIG_CHARGING >= CHARGING_MONITOR
1019 case SKIN_TOKEN_BATTERY_CHARGING
:
1021 if (charge_state
== CHARGING
|| charge_state
== TOPOFF
) {
1028 #ifdef HAVE_USB_POWER
1029 case SKIN_TOKEN_USB_POWERED
:
1034 case SKIN_TOKEN_BATTERY_SLEEPTIME
:
1036 if (get_sleep_timer() == 0)
1040 format_time(buf
, buf_size
, get_sleep_timer() * 1000);
1045 case SKIN_TOKEN_PLAYBACK_STATUS
:
1047 int status
= current_playmode();
1049 int mode
= 1; /* stop */
1050 if (status
== STATUS_PLAY
)
1051 mode
= 2; /* play */
1052 if (state
->is_fading
||
1053 (status
== STATUS_PAUSE
&& !status_get_ffmode()))
1054 mode
= 3; /* pause */
1057 if (status_get_ffmode() == STATUS_FASTFORWARD
)
1059 if (status_get_ffmode() == STATUS_FASTBACKWARD
)
1062 #ifdef HAVE_RECORDING
1064 if (status
== STATUS_RECORD
)
1066 else if (status
== STATUS_RECORD_PAUSE
)
1071 if (status
== STATUS_RADIO
)
1073 else if (status
== STATUS_RADIO_PAUSE
)
1081 snprintf(buf
, buf_size
, "%d", mode
-1);
1085 case SKIN_TOKEN_REPEAT_MODE
:
1087 *intval
= global_settings
.repeat_mode
+ 1;
1088 snprintf(buf
, buf_size
, "%d", global_settings
.repeat_mode
);
1091 case SKIN_TOKEN_RTC_PRESENT
:
1099 case SKIN_TOKEN_RTC_12HOUR_CFG
:
1101 *intval
= global_settings
.timeformat
+ 1;
1102 snprintf(buf
, buf_size
, "%d", global_settings
.timeformat
);
1105 case SKIN_TOKEN_RTC_DAY_OF_MONTH
:
1106 /* d: day of month (01..31) */
1107 snprintf(buf
, buf_size
, "%02d", tm
->tm_mday
);
1109 *intval
= tm
->tm_mday
- 1;
1112 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
:
1113 /* e: day of month, blank padded ( 1..31) */
1114 snprintf(buf
, buf_size
, "%2d", tm
->tm_mday
);
1116 *intval
= tm
->tm_mday
- 1;
1119 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED
:
1120 /* H: hour (00..23) */
1121 snprintf(buf
, buf_size
, "%02d", tm
->tm_hour
);
1123 *intval
= tm
->tm_hour
;
1126 case SKIN_TOKEN_RTC_HOUR_24
:
1127 /* k: hour ( 0..23) */
1128 snprintf(buf
, buf_size
, "%2d", tm
->tm_hour
);
1130 *intval
= tm
->tm_hour
;
1133 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED
:
1134 /* I: hour (01..12) */
1135 snprintf(buf
, buf_size
, "%02d",
1136 (tm
->tm_hour
% 12 == 0) ? 12 : tm
->tm_hour
% 12);
1138 *intval
= (tm
->tm_hour
% 12 == 0) ? 12 : tm
->tm_hour
% 12;
1141 case SKIN_TOKEN_RTC_HOUR_12
:
1142 /* l: hour ( 1..12) */
1143 snprintf(buf
, buf_size
, "%2d",
1144 (tm
->tm_hour
% 12 == 0) ? 12 : tm
->tm_hour
% 12);
1146 *intval
= (tm
->tm_hour
% 12 == 0) ? 12 : tm
->tm_hour
% 12;
1149 case SKIN_TOKEN_RTC_MONTH
:
1150 /* m: month (01..12) */
1152 *intval
= tm
->tm_mon
+ 1;
1153 snprintf(buf
, buf_size
, "%02d", tm
->tm_mon
+ 1);
1156 case SKIN_TOKEN_RTC_MINUTE
:
1157 /* M: minute (00..59) */
1158 snprintf(buf
, buf_size
, "%02d", tm
->tm_min
);
1160 *intval
= tm
->tm_min
;
1163 case SKIN_TOKEN_RTC_SECOND
:
1164 /* S: second (00..59) */
1165 snprintf(buf
, buf_size
, "%02d", tm
->tm_sec
);
1167 *intval
= tm
->tm_sec
;
1170 case SKIN_TOKEN_RTC_YEAR_2_DIGITS
:
1171 /* y: last two digits of year (00..99) */
1172 snprintf(buf
, buf_size
, "%02d", tm
->tm_year
% 100);
1174 *intval
= tm
->tm_year
% 100;
1177 case SKIN_TOKEN_RTC_YEAR_4_DIGITS
:
1178 /* Y: year (1970...) */
1179 snprintf(buf
, buf_size
, "%04d", tm
->tm_year
+ 1900);
1181 *intval
= tm
->tm_year
+ 1900;
1184 case SKIN_TOKEN_RTC_AM_PM_UPPER
:
1185 /* p: upper case AM or PM indicator */
1187 *intval
= tm
->tm_hour
/12 == 0 ? 0 : 1;
1188 return tm
->tm_hour
/12 == 0 ? "AM" : "PM";
1190 case SKIN_TOKEN_RTC_AM_PM_LOWER
:
1191 /* P: lower case am or pm indicator */
1193 *intval
= tm
->tm_hour
/12 == 0 ? 0 : 1;
1194 return tm
->tm_hour
/12 == 0 ? "am" : "pm";
1196 case SKIN_TOKEN_RTC_WEEKDAY_NAME
:
1197 /* a: abbreviated weekday name (Sun..Sat) */
1198 return str(LANG_WEEKDAY_SUNDAY
+ tm
->tm_wday
);
1200 case SKIN_TOKEN_RTC_MONTH_NAME
:
1201 /* b: abbreviated month name (Jan..Dec) */
1202 return str(LANG_MONTH_JANUARY
+ tm
->tm_mon
);
1204 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON
:
1205 /* u: day of week (1..7); 1 is Monday */
1207 *intval
= (tm
->tm_wday
== 0) ? 7 : tm
->tm_wday
;
1208 snprintf(buf
, buf_size
, "%1d", tm
->tm_wday
+ 1);
1211 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN
:
1212 /* w: day of week (0..6); 0 is Sunday */
1214 *intval
= tm
->tm_wday
+ 1;
1215 snprintf(buf
, buf_size
, "%1d", tm
->tm_wday
);
1218 case SKIN_TOKEN_RTC_DAY_OF_MONTH
:
1219 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
:
1220 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED
:
1221 case SKIN_TOKEN_RTC_HOUR_24
:
1222 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED
:
1223 case SKIN_TOKEN_RTC_HOUR_12
:
1224 case SKIN_TOKEN_RTC_MONTH
:
1225 case SKIN_TOKEN_RTC_MINUTE
:
1226 case SKIN_TOKEN_RTC_SECOND
:
1227 case SKIN_TOKEN_RTC_AM_PM_UPPER
:
1228 case SKIN_TOKEN_RTC_AM_PM_LOWER
:
1229 case SKIN_TOKEN_RTC_YEAR_2_DIGITS
:
1231 case SKIN_TOKEN_RTC_YEAR_4_DIGITS
:
1233 case SKIN_TOKEN_RTC_WEEKDAY_NAME
:
1234 case SKIN_TOKEN_RTC_MONTH_NAME
:
1236 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON
:
1237 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN
:
1241 #ifdef HAVE_LCD_CHARCELLS
1242 case SKIN_TOKEN_PROGRESSBAR
:
1245 format_player_progress(gwps
);
1246 end
= utf8encode(data
->wps_progress_pat
[0], buf
);
1251 case SKIN_TOKEN_PLAYER_PROGRESSBAR
:
1254 /* we need 11 characters (full line) for
1256 strlcpy(buf
, " ", buf_size
);
1257 format_player_fullbar(gwps
,buf
,buf_size
);
1258 DEBUGF("bar='%s'\n",buf
);
1262 /* Tell the user if we have an OldPlayer */
1263 strlcpy(buf
, " <Old LCD> ", buf_size
);
1269 #ifdef HAVE_LCD_BITMAP
1271 case SKIN_TOKEN_PEAKMETER_LEFT
:
1272 case SKIN_TOKEN_PEAKMETER_RIGHT
:
1274 int left
, right
, val
;
1275 peak_meter_current_vals(&left
, &right
);
1276 val
= token
->type
== SKIN_TOKEN_PEAKMETER_LEFT
?
1278 val
= peak_meter_scale_value(val
, limit
==1 ? MAX_PEAK
: limit
);
1281 snprintf(buf
, buf_size
, "%d", val
);
1282 data
->peak_meter_enabled
= true;
1287 #if (CONFIG_CODEC == SWCODEC)
1288 case SKIN_TOKEN_CROSSFADE
:
1289 #ifdef HAVE_CROSSFADE
1291 *intval
= global_settings
.crossfade
+ 1;
1292 snprintf(buf
, buf_size
, "%d", global_settings
.crossfade
);
1294 snprintf(buf
, buf_size
, "%d", 0);
1298 case SKIN_TOKEN_REPLAYGAIN
:
1302 if (global_settings
.replaygain_type
== REPLAYGAIN_OFF
)
1308 type
= get_replaygain_mode(id3
->track_gain_string
!= NULL
,
1309 id3
->album_gain_string
!= NULL
);
1314 val
= 6; /* no tag */
1318 if (global_settings
.replaygain_type
== REPLAYGAIN_SHUFFLE
)
1331 /* due to above, coming here with !id3 shouldn't be possible */
1334 strlcpy(buf
, id3
->track_gain_string
, buf_size
);
1338 strlcpy(buf
, id3
->album_gain_string
, buf_size
);
1343 #endif /* (CONFIG_CODEC == SWCODEC) */
1345 #if (CONFIG_CODEC != MAS3507D) && defined (HAVE_PITCHSCREEN)
1346 case SKIN_TOKEN_SOUND_PITCH
:
1348 int32_t pitch
= sound_get_pitch();
1349 snprintf(buf
, buf_size
, "%ld.%ld",
1350 pitch
/ PITCH_SPEED_PRECISION
,
1351 (pitch
% PITCH_SPEED_PRECISION
) / (PITCH_SPEED_PRECISION
/ 10));
1354 *intval
= pitch_speed_enum(limit
, pitch
,
1355 PITCH_SPEED_PRECISION
* 100);
1360 #if (CONFIG_CODEC == SWCODEC) && defined (HAVE_PITCHSCREEN)
1361 case SKIN_TOKEN_SOUND_SPEED
:
1363 int32_t pitch
= sound_get_pitch();
1365 if (dsp_timestretch_available())
1366 speed
= GET_SPEED(pitch
, dsp_get_timestretch());
1369 snprintf(buf
, buf_size
, "%ld.%ld",
1370 speed
/ PITCH_SPEED_PRECISION
,
1371 (speed
% PITCH_SPEED_PRECISION
) / (PITCH_SPEED_PRECISION
/ 10));
1373 *intval
= pitch_speed_enum(limit
, speed
,
1374 PITCH_SPEED_PRECISION
* 100);
1379 case SKIN_TOKEN_MAIN_HOLD
:
1380 #ifdef HAS_BUTTON_HOLD
1383 if (is_keys_locked())
1384 #endif /*hold switch or softlock*/
1389 #ifdef HAS_REMOTE_BUTTON_HOLD
1390 case SKIN_TOKEN_REMOTE_HOLD
:
1391 if (remote_button_hold())
1397 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
1398 case SKIN_TOKEN_VLED_HDD
:
1404 case SKIN_TOKEN_BUTTON_VOLUME
:
1405 if (global_status
.last_volume_change
&&
1406 TIME_BEFORE(current_tick
, global_status
.last_volume_change
+
1411 case SKIN_TOKEN_LASTTOUCH
:
1413 #ifdef HAVE_TOUCHSCREEN
1414 unsigned int last_touch
= touchscreen_last_touch();
1415 if (last_touch
!= 0xffff &&
1416 TIME_BEFORE(current_tick
, token
->value
.i
+ last_touch
))
1421 case SKIN_TOKEN_HAVE_TOUCH
:
1422 #ifdef HAVE_TOUCHSCREEN
1428 case SKIN_TOKEN_SETTING
:
1430 const struct settings_list
*s
= settings
+token
->value
.i
;
1433 /* Handle contionals */
1434 switch (s
->flags
&F_T_MASK
)
1438 if (s
->flags
&F_T_SOUND
)
1440 /* %?St|name|<min|min+1|...|max-1|max> */
1441 int sound_setting
= s
->sound_setting
->setting
;
1442 /* settings with decimals can't be used in conditionals */
1443 if (sound_numdecimals(sound_setting
) == 0)
1445 *intval
= (*(int*)s
->setting
-sound_min(sound_setting
))
1446 /sound_steps(sound_setting
) + 1;
1451 else if (s
->flags
&F_RGB
)
1452 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
1453 /* shouldn't overflow since colors are stored
1455 * but this is pretty useless anyway */
1456 *intval
= *(int*)s
->setting
+ 1;
1457 else if (s
->cfg_vals
== NULL
)
1458 /* %?St|name|<1st choice|2nd choice|...> */
1459 *intval
= (*(int*)s
->setting
-s
->int_setting
->min
)
1460 /s
->int_setting
->step
+ 1;
1462 /* %?St|name|<1st choice|2nd choice|...> */
1463 /* Not sure about this one. cfg_name/vals are
1464 * indexed from 0 right? */
1465 *intval
= *(int*)s
->setting
+ 1;
1468 /* %?St|name|<if true|if false> */
1469 *intval
= *(bool*)s
->setting
?1:2;
1473 /* %?St|name|<if non empty string|if empty>
1474 * The string's emptyness discards the setting's
1475 * prefix and suffix */
1476 *intval
= ((char*)s
->setting
)[0]?1:2;
1477 /* if there is a prefix we should ignore it here */
1478 if (s
->filename_setting
->prefix
)
1479 return (char*)s
->setting
;
1482 /* This shouldn't happen ... but you never know */
1487 /* Special handlng for filenames because we dont want to show the prefix */
1488 if ((s
->flags
&F_T_MASK
) == F_T_UCHARPTR
||
1489 (s
->flags
&F_T_MASK
) == F_T_UCHARPTR
)
1491 if (s
->filename_setting
->prefix
)
1492 return (char*)s
->setting
;
1494 cfg_to_string(token
->value
.i
,buf
,buf_size
);
1497 case SKIN_TOKEN_HAVE_TUNER
:
1499 if (radio_hardware_present())
1503 /* Recording tokens */
1504 case SKIN_TOKEN_HAVE_RECORDING
:
1505 #ifdef HAVE_RECORDING
1511 #ifdef HAVE_RECORDING
1512 case SKIN_TOKEN_IS_RECORDING
:
1513 if (audio_status() == AUDIO_STATUS_RECORD
)
1516 case SKIN_TOKEN_REC_FREQ
: /* order from REC_FREQ_CFG_VAL_LIST */
1518 #if CONFIG_CODEC == SWCODEC
1519 unsigned long samprk
;
1520 int rec_freq
= global_settings
.rec_frequency
;
1525 #if defined(HAVE_SPDIF_REC)
1526 if (global_settings
.rec_source
== AUDIO_SRC_SPDIF
)
1528 /* Use rate in use, not current measured rate if it changed */
1529 samprk
= pcm_rec_sample_rate();
1531 while (rec_freq
< SAMPR_NUM_FREQ
&&
1532 audio_master_sampr_list
[rec_freq
] != samprk
)
1539 samprk
= rec_freq_sampr
[rec_freq
];
1540 #endif /* SIMULATOR */
1545 REC_HAVE_96_(case REC_FREQ_96
:
1548 REC_HAVE_88_(case REC_FREQ_88
:
1551 REC_HAVE_64_(case REC_FREQ_64
:
1554 REC_HAVE_48_(case REC_FREQ_48
:
1557 REC_HAVE_44_(case REC_FREQ_44
:
1560 REC_HAVE_32_(case REC_FREQ_32
:
1563 REC_HAVE_24_(case REC_FREQ_24
:
1566 REC_HAVE_22_(case REC_FREQ_22
:
1569 REC_HAVE_16_(case REC_FREQ_16
:
1572 REC_HAVE_12_(case REC_FREQ_12
:
1575 REC_HAVE_11_(case REC_FREQ_11
:
1578 REC_HAVE_8_(case REC_FREQ_8
:
1583 snprintf(buf
, buf_size
, "%lu.%1lu", samprk
/1000,samprk
%1000);
1586 static const char * const freq_strings
[] =
1587 {"--", "44", "48", "32", "22", "24", "16"};
1588 int freq
= 1 + global_settings
.rec_frequency
;
1589 #ifdef HAVE_SPDIF_REC
1590 if (global_settings
.rec_source
== AUDIO_SRC_SPDIF
)
1592 /* Can't measure S/PDIF sample rate on Archos/Sim yet */
1595 #endif /* HAVE_SPDIF_IN */
1597 *intval
= freq
+1; /* so the token gets a value 1<=x<=7 */
1598 snprintf(buf
, buf_size
, "%s\n",
1599 freq_strings
[global_settings
.rec_frequency
]);
1603 #if CONFIG_CODEC == SWCODEC
1604 case SKIN_TOKEN_REC_ENCODER
:
1606 int rec_format
= global_settings
.rec_format
+1; /* WAV, AIFF, WV, MPEG */
1608 *intval
= rec_format
;
1611 case REC_FORMAT_PCM_WAV
:
1613 case REC_FORMAT_AIFF
:
1615 case REC_FORMAT_WAVPACK
:
1617 case REC_FORMAT_MPA_L3
:
1625 case SKIN_TOKEN_REC_BITRATE
:
1626 #if CONFIG_CODEC == SWCODEC
1627 if (global_settings
.rec_format
== REC_FORMAT_MPA_L3
)
1631 #if 0 /* FIXME: I dont know if this is needed? */
1632 switch (1<<global_settings
.mp3_enc_config
.bitrate
)
1634 case MP3_BITR_CAP_8
:
1637 case MP3_BITR_CAP_16
:
1640 case MP3_BITR_CAP_24
:
1643 case MP3_BITR_CAP_32
:
1646 case MP3_BITR_CAP_40
:
1649 case MP3_BITR_CAP_48
:
1652 case MP3_BITR_CAP_56
:
1655 case MP3_BITR_CAP_64
:
1658 case MP3_BITR_CAP_80
:
1661 case MP3_BITR_CAP_96
:
1664 case MP3_BITR_CAP_112
:
1667 case MP3_BITR_CAP_128
:
1670 case MP3_BITR_CAP_144
:
1673 case MP3_BITR_CAP_160
:
1676 case MP3_BITR_CAP_192
:
1681 *intval
= global_settings
.mp3_enc_config
.bitrate
+1;
1683 snprintf(buf
, buf_size
, "%lu", global_settings
.mp3_enc_config
.bitrate
+1);
1687 return NULL
; /* Fixme later */
1688 #else /* CONFIG_CODEC == HWCODEC */
1690 *intval
= global_settings
.rec_quality
+1;
1691 snprintf(buf
, buf_size
, "%d", global_settings
.rec_quality
);
1694 case SKIN_TOKEN_REC_MONO
:
1695 if (!global_settings
.rec_channels
)
1699 case SKIN_TOKEN_REC_SECONDS
:
1701 int time
= (audio_recorded_time() / HZ
) % 60;
1704 snprintf(buf
, buf_size
, "%02d", time
);
1707 case SKIN_TOKEN_REC_MINUTES
:
1709 int time
= (audio_recorded_time() / HZ
) / 60;
1712 snprintf(buf
, buf_size
, "%02d", time
);
1715 case SKIN_TOKEN_REC_HOURS
:
1717 int time
= (audio_recorded_time() / HZ
) / 3600;
1720 snprintf(buf
, buf_size
, "%02d", time
);
1724 #endif /* HAVE_RECORDING */
1726 case SKIN_TOKEN_CURRENT_SCREEN
:
1728 int curr_screen
= current_screen();
1730 #ifdef HAVE_RECORDING
1731 /* override current_screen() for recording screen since it may
1732 * be entered from the radio screen */
1733 if (in_recording_screen())
1734 curr_screen
= GO_TO_RECSCREEN
;
1737 switch (curr_screen
)
1742 #ifdef HAVE_RECORDING
1743 case GO_TO_RECSCREEN
:
1752 case GO_TO_PLAYLIST_VIEWER
:
1755 default: /* lists */
1761 *intval
= curr_screen
;
1763 snprintf(buf
, buf_size
, "%d", curr_screen
);
1767 case SKIN_TOKEN_LANG_IS_RTL
:
1768 return lang_is_rtl() ? "r" : NULL
;