Fix the mechanism to fail to parse skins if images fail to load and fix having no...
[kugel-rb.git] / apps / gui / skin_engine / skin_tokens.c
blob1189925ea0dcb85f0cc5fb524c7bb5eaff3c6aa0
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
22 #include "font.h"
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include "action.h"
27 #include "system.h"
28 #include "settings.h"
29 #include "settings_list.h"
30 #include "rbunicode.h"
31 #include "timefuncs.h"
32 #include "status.h"
33 #include "power.h"
34 #include "powermgmt.h"
35 #include "sound.h"
36 #include "debug.h"
37 #ifdef HAVE_LCD_CHARCELLS
38 #include "hwcompat.h"
39 #endif
40 #include "abrepeat.h"
41 #include "lang.h"
42 #include "misc.h"
43 #include "led.h"
44 #ifdef HAVE_LCD_BITMAP
45 /* Image stuff */
46 #include "albumart.h"
47 #endif
48 #include "dsp.h"
49 #include "playlist.h"
50 #if CONFIG_CODEC == SWCODEC
51 #include "playback.h"
52 #include "tdspeed.h"
53 #endif
54 #include "viewport.h"
56 #include "wps_internals.h"
57 #include "root_menu.h"
58 #ifdef HAVE_RECORDING
59 #include "recording.h"
60 #include "pcm_record.h"
61 #endif
62 #include "language.h"
63 #include "usb.h"
65 extern struct wps_state wps_state;
67 static char* get_codectype(const struct mp3entry* id3)
69 if (id3 && id3->codectype < AFMT_NUM_CODECS) {
70 return (char*)audio_formats[id3->codectype].label;
71 } else {
72 return NULL;
76 /* Extract a part from a path.
78 * buf - buffer extract part to.
79 * buf_size - size of buffer.
80 * path - path to extract from.
81 * level - what to extract. 0 is file name, 1 is parent of file, 2 is
82 * parent of parent, etc.
84 * Returns buf if the desired level was found, NULL otherwise.
86 char* get_dir(char* buf, int buf_size, const char* path, int level)
88 const char* sep;
89 const char* last_sep;
90 int len;
92 sep = path + strlen(path);
93 last_sep = sep;
95 while (sep > path)
97 if ('/' == *(--sep))
99 if (!level)
100 break;
102 level--;
103 last_sep = sep - 1;
107 if (level || (last_sep <= sep))
108 return NULL;
110 len = MIN(last_sep - sep, buf_size - 1);
111 strlcpy(buf, sep + 1, len + 1);
112 return buf;
115 #if (CONFIG_CODEC != MAS3507D)
116 /* A helper to determine the enum value for pitch/speed.
118 When there are two choices (i.e. boolean), return 1 if the value is
119 different from normal value and 2 if the value is the same as the
120 normal value. E.g. "%?Sp<%Sp>" would show the pitch only when
121 playing at a modified pitch.
123 When there are more than two choices (i.e. enum), the left half of
124 the choices are to show 0..normal range, and the right half of the
125 choices are to show values over that. The last entry is used when
126 it is set to the normal setting, following the rockbox convention
127 to use the last entry for special values.
129 E.g.
131 2 items: %?Sp<0..99 or 101..infinity|100>
132 3 items: %?Sp<0..99|101..infinity|100>
133 4 items: %?Sp<0..49|50..99|101..infinity|100>
134 5 items: %?Sp<0..49|50..99|101..149|150..infinity|100>
135 6 items: %?Sp<0..33|34..66|67..99|101..133|134..infinity|100>
136 7 items: %?Sp<0..33|34..66|67..99|101..133|134..167|167..infinity|100>
138 static int pitch_speed_enum(int range, int32_t val, int32_t normval)
140 int center;
141 int n;
143 if (range < 3)
144 return (val == normval) + 1;
145 if (val == normval)
146 return range;
147 center = range / 2;
148 n = (center * val) / normval + 1;
149 return (range <= n) ? (range - 1) : n;
151 #endif
154 /* All tokens which only need the info to return a value go in here */
155 const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
156 char *buf, int buf_size, int limit, int *intval)
158 struct wps_state *state = &wps_state;
159 if (id3)
161 switch (token->type)
163 case WPS_TOKEN_METADATA_ARTIST:
164 return id3->artist;
165 case WPS_TOKEN_METADATA_COMPOSER:
166 return id3->composer;
167 case WPS_TOKEN_METADATA_ALBUM:
168 return id3->album;
169 case WPS_TOKEN_METADATA_ALBUM_ARTIST:
170 return id3->albumartist;
171 case WPS_TOKEN_METADATA_GROUPING:
172 return id3->grouping;
173 case WPS_TOKEN_METADATA_GENRE:
174 return id3->genre_string;
175 case WPS_TOKEN_METADATA_DISC_NUMBER:
176 if (id3->disc_string)
177 return id3->disc_string;
178 if (id3->discnum) {
179 snprintf(buf, buf_size, "%d", id3->discnum);
180 return buf;
182 return NULL;
183 case WPS_TOKEN_METADATA_TRACK_NUMBER:
184 if (id3->track_string)
185 return id3->track_string;
186 if (id3->tracknum) {
187 snprintf(buf, buf_size, "%d", id3->tracknum);
188 return buf;
190 return NULL;
191 case WPS_TOKEN_METADATA_TRACK_TITLE:
192 return id3->title;
193 case WPS_TOKEN_METADATA_VERSION:
194 switch (id3->id3version)
196 case ID3_VER_1_0:
197 return "1";
198 case ID3_VER_1_1:
199 return "1.1";
200 case ID3_VER_2_2:
201 return "2.2";
202 case ID3_VER_2_3:
203 return "2.3";
204 case ID3_VER_2_4:
205 return "2.4";
206 default:
207 break;
209 return NULL;
210 case WPS_TOKEN_METADATA_YEAR:
211 if( id3->year_string )
212 return id3->year_string;
213 if (id3->year) {
214 snprintf(buf, buf_size, "%d", id3->year);
215 return buf;
217 return NULL;
218 case WPS_TOKEN_METADATA_COMMENT:
219 return id3->comment;
220 case WPS_TOKEN_FILE_PATH:
221 return id3->path;
222 case WPS_TOKEN_FILE_BITRATE:
223 if(id3->bitrate)
224 snprintf(buf, buf_size, "%d", id3->bitrate);
225 else
226 return "?";
227 return buf;
228 case WPS_TOKEN_TRACK_TIME_ELAPSED:
229 format_time(buf, buf_size,
230 id3->elapsed + state->ff_rewind_count);
231 return buf;
233 case WPS_TOKEN_TRACK_TIME_REMAINING:
234 format_time(buf, buf_size,
235 id3->length - id3->elapsed -
236 state->ff_rewind_count);
237 return buf;
239 case WPS_TOKEN_TRACK_LENGTH:
240 format_time(buf, buf_size, id3->length);
241 return buf;
243 case WPS_TOKEN_TRACK_ELAPSED_PERCENT:
244 if (id3->length <= 0)
245 return NULL;
247 if (intval)
249 *intval = limit * (id3->elapsed + state->ff_rewind_count)
250 / id3->length + 1;
252 snprintf(buf, buf_size, "%d",
253 100*(id3->elapsed + state->ff_rewind_count) / id3->length);
254 return buf;
257 case WPS_TOKEN_FILE_CODEC:
258 if (intval)
260 if(id3->codectype == AFMT_UNKNOWN)
261 *intval = AFMT_NUM_CODECS;
262 else
263 *intval = id3->codectype;
265 return get_codectype(id3);
267 case WPS_TOKEN_FILE_FREQUENCY:
268 snprintf(buf, buf_size, "%ld", id3->frequency);
269 return buf;
270 case WPS_TOKEN_FILE_FREQUENCY_KHZ:
271 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
272 if ((id3->frequency % 1000) < 100)
273 snprintf(buf, buf_size, "%ld", id3->frequency / 1000);
274 else
275 snprintf(buf, buf_size, "%ld.%d",
276 id3->frequency / 1000,
277 (id3->frequency % 1000) / 100);
278 return buf;
279 case WPS_TOKEN_FILE_NAME:
280 if (get_dir(buf, buf_size, id3->path, 0)) {
281 /* Remove extension */
282 char* sep = strrchr(buf, '.');
283 if (NULL != sep) {
284 *sep = 0;
286 return buf;
288 return NULL;
289 case WPS_TOKEN_FILE_NAME_WITH_EXTENSION:
290 return get_dir(buf, buf_size, id3->path, 0);
291 case WPS_TOKEN_FILE_SIZE:
292 snprintf(buf, buf_size, "%ld", id3->filesize / 1024);
293 return buf;
294 case WPS_TOKEN_FILE_VBR:
295 return (id3->vbr) ? "(avg)" : NULL;
296 case WPS_TOKEN_FILE_DIRECTORY:
297 return get_dir(buf, buf_size, id3->path, token->value.i);
299 #ifdef HAVE_TAGCACHE
300 case WPS_TOKEN_DATABASE_PLAYCOUNT:
301 if (intval)
302 *intval = id3->playcount + 1;
303 snprintf(buf, buf_size, "%ld", id3->playcount);
304 return buf;
305 case WPS_TOKEN_DATABASE_RATING:
306 if (intval)
307 *intval = id3->rating + 1;
308 snprintf(buf, buf_size, "%ld", id3->rating);
309 return buf;
310 case WPS_TOKEN_DATABASE_AUTOSCORE:
311 if (intval)
312 *intval = id3->score + 1;
313 snprintf(buf, buf_size, "%ld", id3->score);
314 return buf;
315 #endif
317 default:
318 return NULL;
321 else /* id3 == NULL, handle the error based on the expected return type */
323 switch (token->type)
325 /* Most tokens expect NULL on error so leave that for the default case,
326 * The ones that expect "0" need to be handled */
327 case WPS_TOKEN_FILE_FREQUENCY:
328 case WPS_TOKEN_FILE_FREQUENCY_KHZ:
329 case WPS_TOKEN_FILE_SIZE:
330 #ifdef HAVE_TAGCACHE
331 case WPS_TOKEN_DATABASE_PLAYCOUNT:
332 case WPS_TOKEN_DATABASE_RATING:
333 case WPS_TOKEN_DATABASE_AUTOSCORE:
334 #endif
335 if (intval)
336 *intval = 0;
337 return "0";
338 default:
339 return NULL;
342 return buf;
345 /* Return the tags value as text. buf should be used as temp storage if needed.
347 intval is used with conditionals/enums: when this function is called,
348 intval should contain the number of options in the conditional/enum.
349 When this function returns, intval is -1 if the tag is non numeric or,
350 if the tag is numeric, *intval is the enum case we want to go to (between 1
351 and the original value of *intval, inclusive).
352 When not treating a conditional/enum, intval should be NULL.
354 const char *get_token_value(struct gui_wps *gwps,
355 struct wps_token *token,
356 char *buf, int buf_size,
357 int *intval)
359 if (!gwps)
360 return NULL;
362 struct wps_data *data = gwps->data;
363 struct wps_state *state = gwps->state;
364 struct mp3entry *id3; /* Think very carefully about using this.
365 maybe get_id3_token() is the better place? */
366 const char *out_text = NULL;
368 if (!data || !state)
369 return NULL;
372 if (token->next)
373 id3 = state->nid3;
374 else
375 id3 = state->id3;
377 #if CONFIG_RTC
378 struct tm* tm = NULL;
380 /* if the token is an RTC one, update the time
381 and do the necessary checks */
382 if (token->type >= WPS_TOKENS_RTC_BEGIN
383 && token->type <= WPS_TOKENS_RTC_END)
385 tm = get_time();
387 if (!valid_time(tm))
388 return NULL;
390 #endif
392 int limit = 1;
393 if (intval)
395 limit = *intval;
396 *intval = -1;
399 out_text = get_id3_token(token, id3, buf, buf_size, limit, intval);
400 if (out_text)
401 return out_text;
403 switch (token->type)
405 case WPS_TOKEN_CHARACTER:
406 if (token->value.c == '\n')
407 return NULL;
408 return &(token->value.c);
410 case WPS_TOKEN_STRING:
411 return (char*)token->value.data;
413 case WPS_TOKEN_TRANSLATEDSTRING:
414 return (char*)P2STR(ID2P(token->value.i));
416 case WPS_TOKEN_PLAYLIST_ENTRIES:
417 snprintf(buf, buf_size, "%d", playlist_amount());
418 return buf;
420 case WPS_TOKEN_PLAYLIST_NAME:
421 return playlist_name(NULL, buf, buf_size);
423 case WPS_TOKEN_PLAYLIST_POSITION:
424 snprintf(buf, buf_size, "%d", playlist_get_display_index());
425 return buf;
427 case WPS_TOKEN_PLAYLIST_SHUFFLE:
428 if ( global_settings.playlist_shuffle )
429 return "s";
430 else
431 return NULL;
432 break;
434 case WPS_TOKEN_VOLUME:
435 snprintf(buf, buf_size, "%d", global_settings.volume);
436 if (intval)
438 if (global_settings.volume == sound_min(SOUND_VOLUME))
440 *intval = 1;
442 else if (global_settings.volume == 0)
444 *intval = limit - 1;
446 else if (global_settings.volume > 0)
448 *intval = limit;
450 else
452 *intval = (limit - 3) * (global_settings.volume
453 - sound_min(SOUND_VOLUME) - 1)
454 / (-1 - sound_min(SOUND_VOLUME)) + 2;
457 return buf;
458 #ifdef HAVE_ALBUMART
459 case WPS_TOKEN_ALBUMART_FOUND:
460 if (data->albumart) {
461 if (playback_current_aa_hid(data->playback_aa_slot) >= 0)
462 return "C";
464 return NULL;
466 case WPS_TOKEN_ALBUMART_DISPLAY:
467 if (!data->albumart)
468 return NULL;
469 if (!data->albumart->draw)
470 data->albumart->draw = true;
471 return NULL;
472 #endif
474 case WPS_TOKEN_BATTERY_PERCENT:
476 int l = battery_level();
478 if (intval)
480 limit = MAX(limit, 2);
481 if (l > -1) {
482 /* First enum is used for "unknown level". */
483 *intval = (limit - 1) * l / 100 + 2;
484 } else {
485 *intval = 1;
489 if (l > -1) {
490 snprintf(buf, buf_size, "%d", l);
491 return buf;
492 } else {
493 return "?";
497 case WPS_TOKEN_BATTERY_VOLTS:
499 unsigned int v = battery_voltage();
500 snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10);
501 return buf;
504 case WPS_TOKEN_BATTERY_TIME:
506 int t = battery_time();
507 if (t >= 0)
508 snprintf(buf, buf_size, "%dh %dm", t / 60, t % 60);
509 else
510 return "?h ?m";
511 return buf;
514 #if CONFIG_CHARGING
515 case WPS_TOKEN_BATTERY_CHARGER_CONNECTED:
517 if(charger_input_state==CHARGER)
518 return "p";
519 else
520 return NULL;
522 #endif
523 #if CONFIG_CHARGING >= CHARGING_MONITOR
524 case WPS_TOKEN_BATTERY_CHARGING:
526 if (charge_state == CHARGING || charge_state == TOPOFF) {
527 return "c";
528 } else {
529 return NULL;
532 #endif
533 #ifdef HAVE_USB_POWER
534 case WPS_TOKEN_USB_POWERED:
535 if (usb_powered())
536 return "u";
537 return NULL;
538 #endif
539 case WPS_TOKEN_BATTERY_SLEEPTIME:
541 if (get_sleep_timer() == 0)
542 return NULL;
543 else
545 format_time(buf, buf_size, get_sleep_timer() * 1000);
546 return buf;
550 case WPS_TOKEN_PLAYBACK_STATUS:
552 int status = current_playmode();
553 /* music */
554 int mode = 1; /* stop */
555 if (status == STATUS_PLAY)
556 mode = 2; /* play */
557 if (state->is_fading ||
558 (status == STATUS_PAUSE && !status_get_ffmode()))
559 mode = 3; /* pause */
560 else
561 { /* ff / rwd */
562 if (status_get_ffmode() == STATUS_FASTFORWARD)
563 mode = 4;
564 if (status_get_ffmode() == STATUS_FASTBACKWARD)
565 mode = 5;
567 #ifdef HAVE_RECORDING
568 /* recording */
569 if (status == STATUS_RECORD)
570 mode = 6;
571 else if (status == STATUS_RECORD_PAUSE)
572 mode = 7;
573 #endif
574 #if CONFIG_TUNER
575 /* radio */
576 if (status == STATUS_RADIO)
577 mode = 8;
578 else if (status == STATUS_RADIO_PAUSE)
579 mode = 9;
580 #endif
582 if (intval) {
583 *intval = mode;
586 snprintf(buf, buf_size, "%d", mode-1);
587 return buf;
590 case WPS_TOKEN_REPEAT_MODE:
591 if (intval)
592 *intval = global_settings.repeat_mode + 1;
593 snprintf(buf, buf_size, "%d", global_settings.repeat_mode);
594 return buf;
596 case WPS_TOKEN_RTC_PRESENT:
597 #if CONFIG_RTC
598 return "c";
599 #else
600 return NULL;
601 #endif
603 #if CONFIG_RTC
604 case WPS_TOKEN_RTC_12HOUR_CFG:
605 if (intval)
606 *intval = global_settings.timeformat + 1;
607 snprintf(buf, buf_size, "%d", global_settings.timeformat);
608 return buf;
610 case WPS_TOKEN_RTC_DAY_OF_MONTH:
611 /* d: day of month (01..31) */
612 snprintf(buf, buf_size, "%02d", tm->tm_mday);
613 if (intval)
614 *intval = tm->tm_mday - 1;
615 return buf;
617 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
618 /* e: day of month, blank padded ( 1..31) */
619 snprintf(buf, buf_size, "%2d", tm->tm_mday);
620 if (intval)
621 *intval = tm->tm_mday - 1;
622 return buf;
624 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED:
625 /* H: hour (00..23) */
626 snprintf(buf, buf_size, "%02d", tm->tm_hour);
627 if (intval)
628 *intval = tm->tm_hour;
629 return buf;
631 case WPS_TOKEN_RTC_HOUR_24:
632 /* k: hour ( 0..23) */
633 snprintf(buf, buf_size, "%2d", tm->tm_hour);
634 if (intval)
635 *intval = tm->tm_hour;
636 return buf;
638 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED:
639 /* I: hour (01..12) */
640 snprintf(buf, buf_size, "%02d",
641 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
642 if (intval)
643 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
644 return buf;
646 case WPS_TOKEN_RTC_HOUR_12:
647 /* l: hour ( 1..12) */
648 snprintf(buf, buf_size, "%2d",
649 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
650 if (intval)
651 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
652 return buf;
654 case WPS_TOKEN_RTC_MONTH:
655 /* m: month (01..12) */
656 if (intval)
657 *intval = tm->tm_mon + 1;
658 snprintf(buf, buf_size, "%02d", tm->tm_mon + 1);
659 return buf;
661 case WPS_TOKEN_RTC_MINUTE:
662 /* M: minute (00..59) */
663 snprintf(buf, buf_size, "%02d", tm->tm_min);
664 if (intval)
665 *intval = tm->tm_min;
666 return buf;
668 case WPS_TOKEN_RTC_SECOND:
669 /* S: second (00..59) */
670 snprintf(buf, buf_size, "%02d", tm->tm_sec);
671 if (intval)
672 *intval = tm->tm_sec;
673 return buf;
675 case WPS_TOKEN_RTC_YEAR_2_DIGITS:
676 /* y: last two digits of year (00..99) */
677 snprintf(buf, buf_size, "%02d", tm->tm_year % 100);
678 if (intval)
679 *intval = tm->tm_year % 100;
680 return buf;
682 case WPS_TOKEN_RTC_YEAR_4_DIGITS:
683 /* Y: year (1970...) */
684 snprintf(buf, buf_size, "%04d", tm->tm_year + 1900);
685 if (intval)
686 *intval = tm->tm_year + 1900;
687 return buf;
689 case WPS_TOKEN_RTC_AM_PM_UPPER:
690 /* p: upper case AM or PM indicator */
691 if (intval)
692 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
693 return tm->tm_hour/12 == 0 ? "AM" : "PM";
695 case WPS_TOKEN_RTC_AM_PM_LOWER:
696 /* P: lower case am or pm indicator */
697 if (intval)
698 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
699 return tm->tm_hour/12 == 0 ? "am" : "pm";
701 case WPS_TOKEN_RTC_WEEKDAY_NAME:
702 /* a: abbreviated weekday name (Sun..Sat) */
703 return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday);
705 case WPS_TOKEN_RTC_MONTH_NAME:
706 /* b: abbreviated month name (Jan..Dec) */
707 return str(LANG_MONTH_JANUARY + tm->tm_mon);
709 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON:
710 /* u: day of week (1..7); 1 is Monday */
711 if (intval)
712 *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
713 snprintf(buf, buf_size, "%1d", tm->tm_wday + 1);
714 return buf;
716 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
717 /* w: day of week (0..6); 0 is Sunday */
718 if (intval)
719 *intval = tm->tm_wday + 1;
720 snprintf(buf, buf_size, "%1d", tm->tm_wday);
721 return buf;
722 #else
723 case WPS_TOKEN_RTC_DAY_OF_MONTH:
724 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
725 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED:
726 case WPS_TOKEN_RTC_HOUR_24:
727 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED:
728 case WPS_TOKEN_RTC_HOUR_12:
729 case WPS_TOKEN_RTC_MONTH:
730 case WPS_TOKEN_RTC_MINUTE:
731 case WPS_TOKEN_RTC_SECOND:
732 case WPS_TOKEN_RTC_AM_PM_UPPER:
733 case WPS_TOKEN_RTC_AM_PM_LOWER:
734 case WPS_TOKEN_RTC_YEAR_2_DIGITS:
735 return "--";
736 case WPS_TOKEN_RTC_YEAR_4_DIGITS:
737 return "----";
738 case WPS_TOKEN_RTC_WEEKDAY_NAME:
739 case WPS_TOKEN_RTC_MONTH_NAME:
740 return "---";
741 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON:
742 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
743 return "-";
744 #endif
746 #ifdef HAVE_LCD_CHARCELLS
747 case WPS_TOKEN_PROGRESSBAR:
749 char *end = utf8encode(data->wps_progress_pat[0], buf);
750 *end = '\0';
751 return buf;
754 case WPS_TOKEN_PLAYER_PROGRESSBAR:
755 if(is_new_player())
757 /* we need 11 characters (full line) for
758 progress-bar */
759 strlcpy(buf, " ", buf_size);
761 else
763 /* Tell the user if we have an OldPlayer */
764 strlcpy(buf, " <Old LCD> ", buf_size);
766 return buf;
767 #endif
771 #if (CONFIG_CODEC == SWCODEC)
772 case WPS_TOKEN_CROSSFADE:
773 #ifdef HAVE_CROSSFADE
774 if (intval)
775 *intval = global_settings.crossfade + 1;
776 snprintf(buf, buf_size, "%d", global_settings.crossfade);
777 #else
778 snprintf(buf, buf_size, "%d", 0);
779 #endif
780 return buf;
782 case WPS_TOKEN_REPLAYGAIN:
784 int val;
786 if (global_settings.replaygain_type == REPLAYGAIN_OFF)
787 val = 1; /* off */
788 else
790 int type;
791 if (LIKELY(id3))
792 type = get_replaygain_mode(id3->track_gain_string != NULL,
793 id3->album_gain_string != NULL);
794 else
795 type = -1;
797 if (type < 0)
798 val = 6; /* no tag */
799 else
800 val = type + 2;
802 if (global_settings.replaygain_type == REPLAYGAIN_SHUFFLE)
803 val += 2;
806 if (intval)
807 *intval = val;
809 switch (val)
811 case 1:
812 case 6:
813 return "+0.00 dB";
814 break;
815 /* due to above, coming here with !id3 shouldn't be possible */
816 case 2:
817 case 4:
818 strlcpy(buf, id3->track_gain_string, buf_size);
819 break;
820 case 3:
821 case 5:
822 strlcpy(buf, id3->album_gain_string, buf_size);
823 break;
825 return buf;
827 #endif /* (CONFIG_CODEC == SWCODEC) */
829 #if (CONFIG_CODEC != MAS3507D)
830 case WPS_TOKEN_SOUND_PITCH:
832 int32_t pitch = sound_get_pitch();
833 snprintf(buf, buf_size, "%ld.%ld",
834 pitch / PITCH_SPEED_PRECISION,
835 (pitch % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
837 if (intval)
838 *intval = pitch_speed_enum(limit, pitch,
839 PITCH_SPEED_PRECISION * 100);
840 return buf;
842 #endif
844 #if CONFIG_CODEC == SWCODEC
845 case WPS_TOKEN_SOUND_SPEED:
847 int32_t pitch = sound_get_pitch();
848 int32_t speed;
849 if (dsp_timestretch_available())
850 speed = GET_SPEED(pitch, dsp_get_timestretch());
851 else
852 speed = pitch;
853 snprintf(buf, buf_size, "%ld.%ld",
854 speed / PITCH_SPEED_PRECISION,
855 (speed % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
856 if (intval)
857 *intval = pitch_speed_enum(limit, speed,
858 PITCH_SPEED_PRECISION * 100);
859 return buf;
861 #endif
863 case WPS_TOKEN_MAIN_HOLD:
864 #ifdef HAS_BUTTON_HOLD
865 if (button_hold())
866 #else
867 if (is_keys_locked())
868 #endif /*hold switch or softlock*/
869 return "h";
870 else
871 return NULL;
873 #ifdef HAS_REMOTE_BUTTON_HOLD
874 case WPS_TOKEN_REMOTE_HOLD:
875 if (remote_button_hold())
876 return "r";
877 else
878 return NULL;
879 #endif
881 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
882 case WPS_TOKEN_VLED_HDD:
883 if(led_read(HZ/2))
884 return "h";
885 else
886 return NULL;
887 #endif
888 case WPS_TOKEN_BUTTON_VOLUME:
889 if (global_status.last_volume_change &&
890 TIME_BEFORE(current_tick, global_status.last_volume_change +
891 token->value.i * TIMEOUT_UNIT))
892 return "v";
893 return NULL;
894 case WPS_TOKEN_LASTTOUCH:
895 #ifdef HAVE_TOUCHSCREEN
896 if (TIME_BEFORE(current_tick, token->value.i * TIMEOUT_UNIT +
897 touchscreen_last_touch()))
898 return "t";
899 #endif
900 return NULL;
902 case WPS_TOKEN_SETTING:
904 const struct settings_list *s = settings+token->value.i;
905 if (intval)
907 /* Handle contionals */
908 switch (s->flags&F_T_MASK)
910 case F_T_INT:
911 case F_T_UINT:
912 if (s->flags&F_T_SOUND)
914 /* %?St|name|<min|min+1|...|max-1|max> */
915 int sound_setting = s->sound_setting->setting;
916 /* settings with decimals can't be used in conditionals */
917 if (sound_numdecimals(sound_setting) == 0)
919 *intval = (*(int*)s->setting-sound_min(sound_setting))
920 /sound_steps(sound_setting) + 1;
922 else
923 *intval = -1;
925 else if (s->flags&F_RGB)
926 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
927 /* shouldn't overflow since colors are stored
928 * on 16 bits ...
929 * but this is pretty useless anyway */
930 *intval = *(int*)s->setting + 1;
931 else if (s->cfg_vals == NULL)
932 /* %?St|name|<1st choice|2nd choice|...> */
933 *intval = (*(int*)s->setting-s->int_setting->min)
934 /s->int_setting->step + 1;
935 else
936 /* %?St|name|<1st choice|2nd choice|...> */
937 /* Not sure about this one. cfg_name/vals are
938 * indexed from 0 right? */
939 *intval = *(int*)s->setting + 1;
940 break;
941 case F_T_BOOL:
942 /* %?St|name|<if true|if false> */
943 *intval = *(bool*)s->setting?1:2;
944 break;
945 case F_T_CHARPTR:
946 case F_T_UCHARPTR:
947 /* %?St|name|<if non empty string|if empty>
948 * The string's emptyness discards the setting's
949 * prefix and suffix */
950 *intval = ((char*)s->setting)[0]?1:2;
951 break;
952 default:
953 /* This shouldn't happen ... but you never know */
954 *intval = -1;
955 break;
958 /* Special handlng for filenames because we dont want to show the prefix */
959 if ((s->flags&F_T_MASK) == F_T_UCHARPTR ||
960 (s->flags&F_T_MASK) == F_T_UCHARPTR)
962 if (s->filename_setting->prefix)
963 return (char*)s->setting;
965 cfg_to_string(token->value.i,buf,buf_size);
966 return buf;
968 /* Recording tokens */
969 case WPS_TOKEN_HAVE_RECORDING:
970 #ifdef HAVE_RECORDING
971 return "r";
972 #else
973 return NULL;
974 #endif
976 #ifdef HAVE_RECORDING
977 case WPS_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */
979 #if CONFIG_CODEC == SWCODEC
980 unsigned long samprk;
981 int rec_freq = global_settings.rec_frequency;
983 #ifdef SIMULATOR
984 samprk = 44100;
985 #else
986 #if defined(HAVE_SPDIF_REC)
987 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
989 /* Use rate in use, not current measured rate if it changed */
990 samprk = pcm_rec_sample_rate();
991 rec_freq = 0;
992 while (rec_freq < SAMPR_NUM_FREQ &&
993 audio_master_sampr_list[rec_freq] != samprk)
995 rec_freq++;
998 else
999 #endif
1000 samprk = rec_freq_sampr[rec_freq];
1001 #endif /* SIMULATOR */
1002 if (intval)
1004 switch (rec_freq)
1006 REC_HAVE_96_(case REC_FREQ_96:
1007 *intval = 1;
1008 break;)
1009 REC_HAVE_88_(case REC_FREQ_88:
1010 *intval = 2;
1011 break;)
1012 REC_HAVE_64_(case REC_FREQ_64:
1013 *intval = 3;
1014 break;)
1015 REC_HAVE_48_(case REC_FREQ_48:
1016 *intval = 4;
1017 break;)
1018 REC_HAVE_44_(case REC_FREQ_44:
1019 *intval = 5;
1020 break;)
1021 REC_HAVE_32_(case REC_FREQ_32:
1022 *intval = 6;
1023 break;)
1024 REC_HAVE_24_(case REC_FREQ_24:
1025 *intval = 7;
1026 break;)
1027 REC_HAVE_22_(case REC_FREQ_22:
1028 *intval = 8;
1029 break;)
1030 REC_HAVE_16_(case REC_FREQ_16:
1031 *intval = 9;
1032 break;)
1033 REC_HAVE_12_(case REC_FREQ_12:
1034 *intval = 10;
1035 break;)
1036 REC_HAVE_11_(case REC_FREQ_11:
1037 *intval = 11;
1038 break;)
1039 REC_HAVE_8_(case REC_FREQ_8:
1040 *intval = 12;
1041 break;)
1044 snprintf(buf, buf_size, "%d.%1d", samprk/1000,samprk%1000);
1045 #else /* HWCODEC */
1047 static const char * const freq_strings[] =
1048 {"--", "44", "48", "32", "22", "24", "16"};
1049 int freq = 1 + global_settings.rec_frequency;
1050 #ifdef HAVE_SPDIF_REC
1051 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1053 /* Can't measure S/PDIF sample rate on Archos/Sim yet */
1054 freq = 0;
1056 #endif /* HAVE_SPDIF_IN */
1057 if (intval)
1058 *intval = freq+1; /* so the token gets a value 1<=x<=7 */
1059 snprintf(buf, buf_size, "%d\n",
1060 freq_strings[global_settings.rec_frequency]);
1061 #endif
1062 return buf;
1064 #if CONFIG_CODEC == SWCODEC
1065 case WPS_TOKEN_REC_ENCODER:
1067 int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */
1068 if (intval)
1069 *intval = rec_format;
1070 switch (rec_format)
1072 case REC_FORMAT_PCM_WAV:
1073 return "wav";
1074 case REC_FORMAT_AIFF:
1075 return "aiff";
1076 case REC_FORMAT_WAVPACK:
1077 return "wv";
1078 case REC_FORMAT_MPA_L3:
1079 return "MP3";
1080 default:
1081 return NULL;
1083 break;
1085 #endif
1086 case WPS_TOKEN_REC_BITRATE:
1087 #if CONFIG_CODEC == SWCODEC
1088 if (global_settings.rec_format == REC_FORMAT_MPA_L3)
1090 if (intval)
1092 #if 0 /* FIXME: I dont know if this is needed? */
1093 switch (1<<global_settings.mp3_enc_config.bitrate)
1095 case MP3_BITR_CAP_8:
1096 *intval = 1;
1097 break;
1098 case MP3_BITR_CAP_16:
1099 *intval = 2;
1100 break;
1101 case MP3_BITR_CAP_24:
1102 *intval = 3;
1103 break;
1104 case MP3_BITR_CAP_32:
1105 *intval = 4;
1106 break;
1107 case MP3_BITR_CAP_40:
1108 *intval = 5;
1109 break;
1110 case MP3_BITR_CAP_48:
1111 *intval = 6;
1112 break;
1113 case MP3_BITR_CAP_56:
1114 *intval = 7;
1115 break;
1116 case MP3_BITR_CAP_64:
1117 *intval = 8;
1118 break;
1119 case MP3_BITR_CAP_80:
1120 *intval = 9;
1121 break;
1122 case MP3_BITR_CAP_96:
1123 *intval = 10;
1124 break;
1125 case MP3_BITR_CAP_112:
1126 *intval = 11;
1127 break;
1128 case MP3_BITR_CAP_128:
1129 *intval = 12;
1130 break;
1131 case MP3_BITR_CAP_144:
1132 *intval = 13;
1133 break;
1134 case MP3_BITR_CAP_160:
1135 *intval = 14;
1136 break;
1137 case MP3_BITR_CAP_192:
1138 *intval = 15;
1139 break;
1141 #endif
1142 *intval = global_settings.mp3_enc_config.bitrate+1;
1144 snprintf(buf, buf_size, "%d", global_settings.mp3_enc_config.bitrate+1);
1145 return buf;
1147 else
1148 return NULL; /* Fixme later */
1149 #else /* CONFIG_CODEC == HWCODEC */
1150 if (intval)
1151 *intval = global_settings.rec_quality+1;
1152 snprintf(buf, buf_size, "%d", global_settings.rec_quality);
1153 return buf;
1154 #endif
1155 case WPS_TOKEN_REC_MONO:
1156 if (!global_settings.rec_channels)
1157 return "m";
1158 return NULL;
1160 #endif /* HAVE_RECORDING */
1161 case WPS_TOKEN_CURRENT_SCREEN:
1163 int curr_screen = current_screen();
1165 #ifdef HAVE_RECORDING
1166 /* override current_screen() for recording screen since it may
1167 * be entered from the radio screen */
1168 if (in_recording_screen())
1169 curr_screen = GO_TO_RECSCREEN;
1170 #endif
1172 switch (curr_screen)
1174 case GO_TO_WPS:
1175 curr_screen = 2;
1176 break;
1177 #ifdef HAVE_RECORDING
1178 case GO_TO_RECSCREEN:
1179 curr_screen = 3;
1180 break;
1181 #endif
1182 #if CONFIG_TUNER
1183 case GO_TO_FM:
1184 curr_screen = 4;
1185 break;
1186 #endif
1187 default: /* lists */
1188 curr_screen = 1;
1189 break;
1191 if (intval)
1194 *intval = curr_screen;
1196 snprintf(buf, buf_size, "%d", curr_screen);
1197 return buf;
1200 case WPS_TOKEN_LANG_IS_RTL:
1201 return lang_is_rtl() ? "r" : NULL;
1203 default:
1204 return NULL;