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 #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
567 static struct mp3entry tempid3
;
568 if (tagcache_fill_tags(&tempid3
, fname
))
575 if (!audio_peek_track(&pid3
, offset
))
583 #ifdef HAVE_LCD_CHARCELLS
584 static void format_player_progress(struct gui_wps
*gwps
)
586 struct wps_state
*state
= skin_get_global_state();
587 struct screen
*display
= gwps
->display
;
588 unsigned char progress_pattern
[7];
593 if (LIKELY(state
->id3
))
595 elapsed
= state
->id3
->elapsed
;
596 length
= state
->id3
->length
;
605 pos
= 36 * (elapsed
+ state
->ff_rewind_count
) / length
;
607 for (i
= 0; i
< 7; i
++, pos
-= 5)
610 progress_pattern
[i
] = 0x1fu
;
612 progress_pattern
[i
] = 0x00u
;
614 progress_pattern
[i
] = 0x1fu
>> pos
;
617 display
->define_pattern(gwps
->data
->wps_progress_pat
[0], progress_pattern
);
620 static void format_player_fullbar(struct gui_wps
*gwps
, char* buf
, int buf_size
)
622 static const unsigned char numbers
[10][4] = {
623 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */
624 {0x04, 0x0c, 0x04, 0x04}, /* 1 */
625 {0x0e, 0x02, 0x04, 0x0e}, /* 2 */
626 {0x0e, 0x02, 0x06, 0x0e}, /* 3 */
627 {0x08, 0x0c, 0x0e, 0x04}, /* 4 */
628 {0x0e, 0x0c, 0x02, 0x0c}, /* 5 */
629 {0x0e, 0x08, 0x0e, 0x0e}, /* 6 */
630 {0x0e, 0x02, 0x04, 0x08}, /* 7 */
631 {0x0e, 0x0e, 0x0a, 0x0e}, /* 8 */
632 {0x0e, 0x0e, 0x02, 0x0e} /* 9 */
635 struct wps_state
*state
= skin_get_global_state();
636 struct screen
*display
= gwps
->display
;
637 struct wps_data
*data
= gwps
->data
;
638 unsigned char progress_pattern
[7];
648 if (LIKELY(state
->id3
))
650 elapsed
= state
->id3
->elapsed
;
651 length
= state
->id3
->length
;
659 if (buf_size
< 34) /* worst case: 11x UTF-8 char + \0 */
662 time
= elapsed
+ state
->ff_rewind_count
;
664 pos
= 55 * time
/ length
;
666 memset(timestr
, 0, sizeof(timestr
));
667 format_time(timestr
, sizeof(timestr
)-2, time
);
668 timestr
[strlen(timestr
)] = ':'; /* always safe */
670 for (i
= 0; i
< 11; i
++, pos
-= 5)
673 memset(progress_pattern
, 0, sizeof(progress_pattern
));
675 if ((digit
= timestr
[time_idx
]))
680 if (timestr
[time_idx
+ 1] == ':') /* ones, left aligned */
682 memcpy(progress_pattern
, numbers
[digit
], 4);
685 else /* tens, shifted right */
687 for (j
= 0; j
< 4; j
++)
688 progress_pattern
[j
] = numbers
[digit
][j
] >> 1;
690 if (time_idx
> 0) /* not the first group, add colon in front */
692 progress_pattern
[1] |= 0x10u
;
693 progress_pattern
[3] |= 0x10u
;
699 progress_pattern
[5] = progress_pattern
[6] = 0x1fu
;
702 if (pos
> 0 && pos
< 5)
705 progress_pattern
[5] = progress_pattern
[6] = (~0x1fu
>> pos
) & 0x1fu
;
708 if (softchar
&& pat_idx
< 8)
710 display
->define_pattern(data
->wps_progress_pat
[pat_idx
],
712 buf
= utf8encode(data
->wps_progress_pat
[pat_idx
], buf
);
716 buf
= utf8encode(' ', buf
);
718 buf
= utf8encode(0xe115, buf
); /* 2/7 _ */
723 #endif /* HAVE_LCD_CHARCELLS */
725 /* Don't inline this; it was broken out of get_token_value to reduce stack
728 static const char* NOINLINE
get_lif_token_value(struct gui_wps
*gwps
,
729 struct logical_if
*lif
,
730 int offset
, char *buf
,
733 int a
= lif
->num_options
;
735 const char* out_text
= get_token_value(gwps
, lif
->token
, offset
,
737 if (a
== -1 && lif
->token
->type
!= SKIN_TOKEN_VOLUME
)
738 a
= (out_text
&& *out_text
) ? 1 : 0;
739 switch (lif
->operand
.type
)
742 if (lif
->op
== IF_EQUALS
)
743 return (out_text
&& strcmp(out_text
, lif
->operand
.data
.text
) == 0)
750 b
= lif
->operand
.data
.number
;
754 char temp_buf
[MAX_PATH
];
756 struct wps_token
*token
= lif
->operand
.data
.code
->data
;
757 b
= lif
->num_options
;
758 outb
= get_token_value(gwps
, token
, offset
, temp_buf
,
759 sizeof(temp_buf
), &b
);
760 if (b
== -1 && lif
->token
->type
!= SKIN_TOKEN_VOLUME
)
762 if (!out_text
|| !outb
)
763 return (lif
->op
== IF_EQUALS
) ? NULL
: "neq";
764 bool equal
= strcmp(out_text
, outb
) == 0;
765 if (lif
->op
== IF_EQUALS
)
766 return equal
? "eq" : NULL
;
767 else if (lif
->op
== IF_NOTEQUALS
)
768 return !equal
? "neq" : NULL
;
770 b
= (outb
&& *outb
) ? 1 : 0;
781 return a
== b
? "eq" : NULL
;
783 return a
!= b
? "neq" : NULL
;
785 return a
< b
? "lt" : NULL
;
787 return a
<= b
? "lte" : NULL
;
789 return a
> b
? "gt" : NULL
;
790 case IF_GREATERTHAN_EQ
:
791 return a
>= b
? "gte" : NULL
;
796 /* Return the tags value as text. buf should be used as temp storage if needed.
798 intval is used with conditionals/enums: when this function is called,
799 intval should contain the number of options in the conditional/enum.
800 When this function returns, intval is -1 if the tag is non numeric or,
801 if the tag is numeric, *intval is the enum case we want to go to (between 1
802 and the original value of *intval, inclusive).
803 When not treating a conditional/enum, intval should be NULL.
805 const char *get_token_value(struct gui_wps
*gwps
,
806 struct wps_token
*token
, int offset
,
807 char *buf
, int buf_size
,
813 struct wps_data
*data
= gwps
->data
;
814 struct wps_state
*state
= skin_get_global_state();
815 struct mp3entry
*id3
; /* Think very carefully about using this.
816 maybe get_id3_token() is the better place? */
817 const char *out_text
= NULL
;
818 char *filename
= NULL
;
823 id3
= get_mp3entry_from_offset(token
->next
? 1: offset
, &filename
);
825 filename
= id3
->path
;
828 struct tm
* tm
= NULL
;
830 /* if the token is an RTC one, update the time
831 and do the necessary checks */
832 if (token
->type
>= SKIN_TOKENS_RTC_BEGIN
833 && token
->type
<= SKIN_TOKENS_RTC_END
)
849 if (id3
&& id3
== state
->id3
&& id3
->cuesheet
)
851 out_text
= get_cuesheetid3_token(token
, id3
,
852 token
->next
?1:offset
, buf
, buf_size
);
856 out_text
= get_id3_token(token
, id3
, filename
, buf
, buf_size
, limit
, intval
);
860 out_text
= get_radio_token(token
, offset
, buf
, buf_size
, limit
, intval
);
867 case SKIN_TOKEN_LOGICAL_IF
:
869 struct logical_if
*lif
= token
->value
.data
;
870 return get_lif_token_value(gwps
, lif
, offset
, buf
, buf_size
);
874 case SKIN_TOKEN_CHARACTER
:
875 if (token
->value
.c
== '\n')
877 return &(token
->value
.c
);
879 case SKIN_TOKEN_STRING
:
880 return (char*)token
->value
.data
;
882 case SKIN_TOKEN_TRANSLATEDSTRING
:
883 return (char*)P2STR(ID2P(token
->value
.i
));
885 case SKIN_TOKEN_PLAYLIST_ENTRIES
:
886 snprintf(buf
, buf_size
, "%d", playlist_amount());
888 *intval
= playlist_amount();
890 #ifdef HAVE_LCD_BITMAP
891 case SKIN_TOKEN_LIST_TITLE_TEXT
:
892 return sb_get_title(gwps
->display
->screen_type
);
893 case SKIN_TOKEN_LIST_TITLE_ICON
:
895 *intval
= sb_get_icon(gwps
->display
->screen_type
);
896 snprintf(buf
, buf_size
, "%d",sb_get_icon(gwps
->display
->screen_type
));
899 case SKIN_TOKEN_PLAYLIST_NAME
:
900 return playlist_name(NULL
, buf
, buf_size
);
902 case SKIN_TOKEN_PLAYLIST_POSITION
:
903 snprintf(buf
, buf_size
, "%d", playlist_get_display_index()+offset
);
905 *intval
= playlist_get_display_index()+offset
;
908 case SKIN_TOKEN_PLAYLIST_SHUFFLE
:
909 if ( global_settings
.playlist_shuffle
)
915 case SKIN_TOKEN_VOLUME
:
916 snprintf(buf
, buf_size
, "%d", global_settings
.volume
);
919 int minvol
= sound_min(SOUND_VOLUME
);
920 if (limit
== TOKEN_VALUE_ONLY
)
922 *intval
= global_settings
.volume
;
924 else if (global_settings
.volume
== minvol
)
928 else if (global_settings
.volume
== 0)
932 else if (global_settings
.volume
> 0)
938 *intval
= (limit
-3) * (global_settings
.volume
- minvol
- 1)
944 case SKIN_TOKEN_ALBUMART_FOUND
:
948 handle
= playback_current_aa_hid(data
->playback_aa_slot
);
950 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF
))
952 struct dim dim
= {data
->albumart
->width
, data
->albumart
->height
};
953 handle
= radio_get_art_hid(&dim
);
962 case SKIN_TOKEN_BATTERY_PERCENT
:
964 int l
= battery_level();
968 if (limit
== TOKEN_VALUE_ONLY
)
974 limit
= MAX(limit
, 3);
976 /* First enum is used for "unknown level",
977 * last enum is used for 100%.
979 *intval
= (limit
- 2) * l
/ 100 + 2;
987 snprintf(buf
, buf_size
, "%d", l
);
994 case SKIN_TOKEN_BATTERY_VOLTS
:
996 unsigned int v
= battery_voltage();
997 snprintf(buf
, buf_size
, "%d.%02d", v
/ 1000, (v
% 1000) / 10);
1001 case SKIN_TOKEN_BATTERY_TIME
:
1003 int t
= battery_time();
1005 snprintf(buf
, buf_size
, "%dh %dm", t
/ 60, t
% 60);
1012 case SKIN_TOKEN_BATTERY_CHARGER_CONNECTED
:
1014 if(charger_input_state
==CHARGER
)
1020 #if CONFIG_CHARGING >= CHARGING_MONITOR
1021 case SKIN_TOKEN_BATTERY_CHARGING
:
1023 if (charge_state
== CHARGING
|| charge_state
== TOPOFF
) {
1030 #ifdef HAVE_USB_POWER
1031 case SKIN_TOKEN_USB_POWERED
:
1036 case SKIN_TOKEN_BATTERY_SLEEPTIME
:
1038 if (get_sleep_timer() == 0)
1042 format_time(buf
, buf_size
, get_sleep_timer() * 1000);
1047 case SKIN_TOKEN_PLAYBACK_STATUS
:
1049 int status
= current_playmode();
1051 int mode
= 1; /* stop */
1052 if (status
== STATUS_PLAY
)
1053 mode
= 2; /* play */
1054 if (state
->is_fading
||
1055 (status
== STATUS_PAUSE
&& !status_get_ffmode()))
1056 mode
= 3; /* pause */
1059 if (status_get_ffmode() == STATUS_FASTFORWARD
)
1061 if (status_get_ffmode() == STATUS_FASTBACKWARD
)
1064 #ifdef HAVE_RECORDING
1066 if (status
== STATUS_RECORD
)
1068 else if (status
== STATUS_RECORD_PAUSE
)
1073 if (status
== STATUS_RADIO
)
1075 else if (status
== STATUS_RADIO_PAUSE
)
1083 snprintf(buf
, buf_size
, "%d", mode
-1);
1087 case SKIN_TOKEN_REPEAT_MODE
:
1089 *intval
= global_settings
.repeat_mode
+ 1;
1090 snprintf(buf
, buf_size
, "%d", global_settings
.repeat_mode
);
1093 case SKIN_TOKEN_RTC_PRESENT
:
1101 case SKIN_TOKEN_RTC_12HOUR_CFG
:
1103 *intval
= global_settings
.timeformat
+ 1;
1104 snprintf(buf
, buf_size
, "%d", global_settings
.timeformat
);
1107 case SKIN_TOKEN_RTC_DAY_OF_MONTH
:
1108 /* d: day of month (01..31) */
1109 snprintf(buf
, buf_size
, "%02d", tm
->tm_mday
);
1111 *intval
= tm
->tm_mday
- 1;
1114 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
:
1115 /* e: day of month, blank padded ( 1..31) */
1116 snprintf(buf
, buf_size
, "%2d", tm
->tm_mday
);
1118 *intval
= tm
->tm_mday
- 1;
1121 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED
:
1122 /* H: hour (00..23) */
1123 snprintf(buf
, buf_size
, "%02d", tm
->tm_hour
);
1125 *intval
= tm
->tm_hour
;
1128 case SKIN_TOKEN_RTC_HOUR_24
:
1129 /* k: hour ( 0..23) */
1130 snprintf(buf
, buf_size
, "%2d", tm
->tm_hour
);
1132 *intval
= tm
->tm_hour
;
1135 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED
:
1136 /* I: hour (01..12) */
1137 snprintf(buf
, buf_size
, "%02d",
1138 (tm
->tm_hour
% 12 == 0) ? 12 : tm
->tm_hour
% 12);
1140 *intval
= (tm
->tm_hour
% 12 == 0) ? 12 : tm
->tm_hour
% 12;
1143 case SKIN_TOKEN_RTC_HOUR_12
:
1144 /* l: hour ( 1..12) */
1145 snprintf(buf
, buf_size
, "%2d",
1146 (tm
->tm_hour
% 12 == 0) ? 12 : tm
->tm_hour
% 12);
1148 *intval
= (tm
->tm_hour
% 12 == 0) ? 12 : tm
->tm_hour
% 12;
1151 case SKIN_TOKEN_RTC_MONTH
:
1152 /* m: month (01..12) */
1154 *intval
= tm
->tm_mon
+ 1;
1155 snprintf(buf
, buf_size
, "%02d", tm
->tm_mon
+ 1);
1158 case SKIN_TOKEN_RTC_MINUTE
:
1159 /* M: minute (00..59) */
1160 snprintf(buf
, buf_size
, "%02d", tm
->tm_min
);
1162 *intval
= tm
->tm_min
;
1165 case SKIN_TOKEN_RTC_SECOND
:
1166 /* S: second (00..59) */
1167 snprintf(buf
, buf_size
, "%02d", tm
->tm_sec
);
1169 *intval
= tm
->tm_sec
;
1172 case SKIN_TOKEN_RTC_YEAR_2_DIGITS
:
1173 /* y: last two digits of year (00..99) */
1174 snprintf(buf
, buf_size
, "%02d", tm
->tm_year
% 100);
1176 *intval
= tm
->tm_year
% 100;
1179 case SKIN_TOKEN_RTC_YEAR_4_DIGITS
:
1180 /* Y: year (1970...) */
1181 snprintf(buf
, buf_size
, "%04d", tm
->tm_year
+ 1900);
1183 *intval
= tm
->tm_year
+ 1900;
1186 case SKIN_TOKEN_RTC_AM_PM_UPPER
:
1187 /* p: upper case AM or PM indicator */
1189 *intval
= tm
->tm_hour
/12 == 0 ? 0 : 1;
1190 return tm
->tm_hour
/12 == 0 ? "AM" : "PM";
1192 case SKIN_TOKEN_RTC_AM_PM_LOWER
:
1193 /* P: lower case am or pm indicator */
1195 *intval
= tm
->tm_hour
/12 == 0 ? 0 : 1;
1196 return tm
->tm_hour
/12 == 0 ? "am" : "pm";
1198 case SKIN_TOKEN_RTC_WEEKDAY_NAME
:
1199 /* a: abbreviated weekday name (Sun..Sat) */
1200 return str(LANG_WEEKDAY_SUNDAY
+ tm
->tm_wday
);
1202 case SKIN_TOKEN_RTC_MONTH_NAME
:
1203 /* b: abbreviated month name (Jan..Dec) */
1204 return str(LANG_MONTH_JANUARY
+ tm
->tm_mon
);
1206 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON
:
1207 /* u: day of week (1..7); 1 is Monday */
1209 *intval
= (tm
->tm_wday
== 0) ? 7 : tm
->tm_wday
;
1210 snprintf(buf
, buf_size
, "%1d", tm
->tm_wday
+ 1);
1213 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN
:
1214 /* w: day of week (0..6); 0 is Sunday */
1216 *intval
= tm
->tm_wday
+ 1;
1217 snprintf(buf
, buf_size
, "%1d", tm
->tm_wday
);
1220 case SKIN_TOKEN_RTC_DAY_OF_MONTH
:
1221 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
:
1222 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED
:
1223 case SKIN_TOKEN_RTC_HOUR_24
:
1224 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED
:
1225 case SKIN_TOKEN_RTC_HOUR_12
:
1226 case SKIN_TOKEN_RTC_MONTH
:
1227 case SKIN_TOKEN_RTC_MINUTE
:
1228 case SKIN_TOKEN_RTC_SECOND
:
1229 case SKIN_TOKEN_RTC_AM_PM_UPPER
:
1230 case SKIN_TOKEN_RTC_AM_PM_LOWER
:
1231 case SKIN_TOKEN_RTC_YEAR_2_DIGITS
:
1233 case SKIN_TOKEN_RTC_YEAR_4_DIGITS
:
1235 case SKIN_TOKEN_RTC_WEEKDAY_NAME
:
1236 case SKIN_TOKEN_RTC_MONTH_NAME
:
1238 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON
:
1239 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN
:
1243 #ifdef HAVE_LCD_CHARCELLS
1244 case SKIN_TOKEN_PROGRESSBAR
:
1247 format_player_progress(gwps
);
1248 end
= utf8encode(data
->wps_progress_pat
[0], buf
);
1253 case SKIN_TOKEN_PLAYER_PROGRESSBAR
:
1256 /* we need 11 characters (full line) for
1258 strlcpy(buf
, " ", buf_size
);
1259 format_player_fullbar(gwps
,buf
,buf_size
);
1260 DEBUGF("bar='%s'\n",buf
);
1264 /* Tell the user if we have an OldPlayer */
1265 strlcpy(buf
, " <Old LCD> ", buf_size
);
1271 #ifdef HAVE_LCD_BITMAP
1273 case SKIN_TOKEN_PEAKMETER_LEFT
:
1274 case SKIN_TOKEN_PEAKMETER_RIGHT
:
1276 int left
, right
, val
;
1277 peak_meter_current_vals(&left
, &right
);
1278 val
= token
->type
== SKIN_TOKEN_PEAKMETER_LEFT
?
1280 val
= peak_meter_scale_value(val
, limit
==1 ? MAX_PEAK
: limit
);
1283 snprintf(buf
, buf_size
, "%d", val
);
1284 data
->peak_meter_enabled
= true;
1289 #if (CONFIG_CODEC == SWCODEC)
1290 case SKIN_TOKEN_CROSSFADE
:
1291 #ifdef HAVE_CROSSFADE
1293 *intval
= global_settings
.crossfade
+ 1;
1294 snprintf(buf
, buf_size
, "%d", global_settings
.crossfade
);
1296 snprintf(buf
, buf_size
, "%d", 0);
1300 case SKIN_TOKEN_REPLAYGAIN
:
1304 if (global_settings
.replaygain_type
== REPLAYGAIN_OFF
)
1310 type
= get_replaygain_mode(id3
->track_gain_string
!= NULL
,
1311 id3
->album_gain_string
!= NULL
);
1316 val
= 6; /* no tag */
1320 if (global_settings
.replaygain_type
== REPLAYGAIN_SHUFFLE
)
1333 /* due to above, coming here with !id3 shouldn't be possible */
1336 strlcpy(buf
, id3
->track_gain_string
, buf_size
);
1340 strlcpy(buf
, id3
->album_gain_string
, buf_size
);
1345 #endif /* (CONFIG_CODEC == SWCODEC) */
1347 #if (CONFIG_CODEC != MAS3507D) && defined (HAVE_PITCHSCREEN)
1348 case SKIN_TOKEN_SOUND_PITCH
:
1350 int32_t pitch
= sound_get_pitch();
1351 snprintf(buf
, buf_size
, "%ld.%ld",
1352 pitch
/ PITCH_SPEED_PRECISION
,
1353 (pitch
% PITCH_SPEED_PRECISION
) / (PITCH_SPEED_PRECISION
/ 10));
1356 *intval
= pitch_speed_enum(limit
, pitch
,
1357 PITCH_SPEED_PRECISION
* 100);
1362 #if (CONFIG_CODEC == SWCODEC) && defined (HAVE_PITCHSCREEN)
1363 case SKIN_TOKEN_SOUND_SPEED
:
1365 int32_t pitch
= sound_get_pitch();
1367 if (dsp_timestretch_available())
1368 speed
= GET_SPEED(pitch
, dsp_get_timestretch());
1371 snprintf(buf
, buf_size
, "%ld.%ld",
1372 speed
/ PITCH_SPEED_PRECISION
,
1373 (speed
% PITCH_SPEED_PRECISION
) / (PITCH_SPEED_PRECISION
/ 10));
1375 *intval
= pitch_speed_enum(limit
, speed
,
1376 PITCH_SPEED_PRECISION
* 100);
1381 case SKIN_TOKEN_MAIN_HOLD
:
1382 #ifdef HAS_BUTTON_HOLD
1385 if (is_keys_locked())
1386 #endif /*hold switch or softlock*/
1391 #ifdef HAS_REMOTE_BUTTON_HOLD
1392 case SKIN_TOKEN_REMOTE_HOLD
:
1393 if (remote_button_hold())
1399 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
1400 case SKIN_TOKEN_VLED_HDD
:
1406 case SKIN_TOKEN_BUTTON_VOLUME
:
1407 if (global_status
.last_volume_change
&&
1408 TIME_BEFORE(current_tick
, global_status
.last_volume_change
+
1413 case SKIN_TOKEN_LASTTOUCH
:
1415 #ifdef HAVE_TOUCHSCREEN
1416 unsigned int last_touch
= touchscreen_last_touch();
1417 if (last_touch
!= 0xffff &&
1418 TIME_BEFORE(current_tick
, token
->value
.i
+ last_touch
))
1423 case SKIN_TOKEN_HAVE_TOUCH
:
1424 #ifdef HAVE_TOUCHSCREEN
1430 case SKIN_TOKEN_SETTING
:
1432 const struct settings_list
*s
= settings
+token
->value
.i
;
1435 /* Handle contionals */
1436 switch (s
->flags
&F_T_MASK
)
1440 if (s
->flags
&F_T_SOUND
)
1442 /* %?St|name|<min|min+1|...|max-1|max> */
1443 int sound_setting
= s
->sound_setting
->setting
;
1444 /* settings with decimals can't be used in conditionals */
1445 if (sound_numdecimals(sound_setting
) == 0)
1447 *intval
= (*(int*)s
->setting
-sound_min(sound_setting
))
1448 /sound_steps(sound_setting
) + 1;
1453 else if (s
->flags
&F_RGB
)
1454 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
1455 /* shouldn't overflow since colors are stored
1457 * but this is pretty useless anyway */
1458 *intval
= *(int*)s
->setting
+ 1;
1459 else if (s
->cfg_vals
== NULL
)
1460 /* %?St|name|<1st choice|2nd choice|...> */
1461 *intval
= (*(int*)s
->setting
-s
->int_setting
->min
)
1462 /s
->int_setting
->step
+ 1;
1464 /* %?St|name|<1st choice|2nd choice|...> */
1465 /* Not sure about this one. cfg_name/vals are
1466 * indexed from 0 right? */
1467 *intval
= *(int*)s
->setting
+ 1;
1470 /* %?St|name|<if true|if false> */
1471 *intval
= *(bool*)s
->setting
?1:2;
1475 /* %?St|name|<if non empty string|if empty>
1476 * The string's emptyness discards the setting's
1477 * prefix and suffix */
1478 *intval
= ((char*)s
->setting
)[0]?1:2;
1479 /* if there is a prefix we should ignore it here */
1480 if (s
->filename_setting
->prefix
)
1481 return (char*)s
->setting
;
1484 /* This shouldn't happen ... but you never know */
1489 /* Special handlng for filenames because we dont want to show the prefix */
1490 if ((s
->flags
&F_T_MASK
) == F_T_UCHARPTR
||
1491 (s
->flags
&F_T_MASK
) == F_T_UCHARPTR
)
1493 if (s
->filename_setting
->prefix
)
1494 return (char*)s
->setting
;
1496 cfg_to_string(token
->value
.i
,buf
,buf_size
);
1499 case SKIN_TOKEN_HAVE_TUNER
:
1501 if (radio_hardware_present())
1505 /* Recording tokens */
1506 case SKIN_TOKEN_HAVE_RECORDING
:
1507 #ifdef HAVE_RECORDING
1513 #ifdef HAVE_RECORDING
1514 case SKIN_TOKEN_IS_RECORDING
:
1515 if (audio_status() == AUDIO_STATUS_RECORD
)
1518 case SKIN_TOKEN_REC_FREQ
: /* order from REC_FREQ_CFG_VAL_LIST */
1520 #if CONFIG_CODEC == SWCODEC
1521 unsigned long samprk
;
1522 int rec_freq
= global_settings
.rec_frequency
;
1527 #if defined(HAVE_SPDIF_REC)
1528 if (global_settings
.rec_source
== AUDIO_SRC_SPDIF
)
1530 /* Use rate in use, not current measured rate if it changed */
1531 samprk
= pcm_rec_sample_rate();
1533 while (rec_freq
< SAMPR_NUM_FREQ
&&
1534 audio_master_sampr_list
[rec_freq
] != samprk
)
1541 samprk
= rec_freq_sampr
[rec_freq
];
1542 #endif /* SIMULATOR */
1547 REC_HAVE_96_(case REC_FREQ_96
:
1550 REC_HAVE_88_(case REC_FREQ_88
:
1553 REC_HAVE_64_(case REC_FREQ_64
:
1556 REC_HAVE_48_(case REC_FREQ_48
:
1559 REC_HAVE_44_(case REC_FREQ_44
:
1562 REC_HAVE_32_(case REC_FREQ_32
:
1565 REC_HAVE_24_(case REC_FREQ_24
:
1568 REC_HAVE_22_(case REC_FREQ_22
:
1571 REC_HAVE_16_(case REC_FREQ_16
:
1574 REC_HAVE_12_(case REC_FREQ_12
:
1577 REC_HAVE_11_(case REC_FREQ_11
:
1580 REC_HAVE_8_(case REC_FREQ_8
:
1585 snprintf(buf
, buf_size
, "%lu.%1lu", samprk
/1000,samprk
%1000);
1588 static const char * const freq_strings
[] =
1589 {"--", "44", "48", "32", "22", "24", "16"};
1590 int freq
= 1 + global_settings
.rec_frequency
;
1591 #ifdef HAVE_SPDIF_REC
1592 if (global_settings
.rec_source
== AUDIO_SRC_SPDIF
)
1594 /* Can't measure S/PDIF sample rate on Archos/Sim yet */
1597 #endif /* HAVE_SPDIF_IN */
1599 *intval
= freq
+1; /* so the token gets a value 1<=x<=7 */
1600 snprintf(buf
, buf_size
, "%s\n",
1601 freq_strings
[global_settings
.rec_frequency
]);
1605 #if CONFIG_CODEC == SWCODEC
1606 case SKIN_TOKEN_REC_ENCODER
:
1608 int rec_format
= global_settings
.rec_format
+1; /* WAV, AIFF, WV, MPEG */
1610 *intval
= rec_format
;
1613 case REC_FORMAT_PCM_WAV
:
1615 case REC_FORMAT_AIFF
:
1617 case REC_FORMAT_WAVPACK
:
1619 case REC_FORMAT_MPA_L3
:
1627 case SKIN_TOKEN_REC_BITRATE
:
1628 #if CONFIG_CODEC == SWCODEC
1629 if (global_settings
.rec_format
== REC_FORMAT_MPA_L3
)
1633 #if 0 /* FIXME: I dont know if this is needed? */
1634 switch (1<<global_settings
.mp3_enc_config
.bitrate
)
1636 case MP3_BITR_CAP_8
:
1639 case MP3_BITR_CAP_16
:
1642 case MP3_BITR_CAP_24
:
1645 case MP3_BITR_CAP_32
:
1648 case MP3_BITR_CAP_40
:
1651 case MP3_BITR_CAP_48
:
1654 case MP3_BITR_CAP_56
:
1657 case MP3_BITR_CAP_64
:
1660 case MP3_BITR_CAP_80
:
1663 case MP3_BITR_CAP_96
:
1666 case MP3_BITR_CAP_112
:
1669 case MP3_BITR_CAP_128
:
1672 case MP3_BITR_CAP_144
:
1675 case MP3_BITR_CAP_160
:
1678 case MP3_BITR_CAP_192
:
1683 *intval
= global_settings
.mp3_enc_config
.bitrate
+1;
1685 snprintf(buf
, buf_size
, "%lu", global_settings
.mp3_enc_config
.bitrate
+1);
1689 return NULL
; /* Fixme later */
1690 #else /* CONFIG_CODEC == HWCODEC */
1692 *intval
= global_settings
.rec_quality
+1;
1693 snprintf(buf
, buf_size
, "%d", global_settings
.rec_quality
);
1696 case SKIN_TOKEN_REC_MONO
:
1697 if (!global_settings
.rec_channels
)
1701 case SKIN_TOKEN_REC_SECONDS
:
1703 int time
= (audio_recorded_time() / HZ
) % 60;
1706 snprintf(buf
, buf_size
, "%02d", time
);
1709 case SKIN_TOKEN_REC_MINUTES
:
1711 int time
= (audio_recorded_time() / HZ
) / 60;
1714 snprintf(buf
, buf_size
, "%02d", time
);
1717 case SKIN_TOKEN_REC_HOURS
:
1719 int time
= (audio_recorded_time() / HZ
) / 3600;
1722 snprintf(buf
, buf_size
, "%02d", time
);
1726 #endif /* HAVE_RECORDING */
1728 case SKIN_TOKEN_CURRENT_SCREEN
:
1730 int curr_screen
= current_screen();
1732 #ifdef HAVE_RECORDING
1733 /* override current_screen() for recording screen since it may
1734 * be entered from the radio screen */
1735 if (in_recording_screen())
1736 curr_screen
= GO_TO_RECSCREEN
;
1739 switch (curr_screen
)
1744 #ifdef HAVE_RECORDING
1745 case GO_TO_RECSCREEN
:
1754 case GO_TO_PLAYLIST_VIEWER
:
1757 default: /* lists */
1763 *intval
= curr_screen
;
1765 snprintf(buf
, buf_size
, "%d", curr_screen
);
1769 case SKIN_TOKEN_LANG_IS_RTL
:
1770 return lang_is_rtl() ? "r" : NULL
;