Implement %Ss for playback speed
[kugel-rb.git] / apps / gui / skin_engine / skin_tokens.c
blobb271bfedfc4234b5d61f39a6c8d69b2915748454
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
63 static char* get_codectype(const struct mp3entry* id3)
65 if (id3 && id3->codectype < AFMT_NUM_CODECS) {
66 return (char*)audio_formats[id3->codectype].label;
67 } else {
68 return NULL;
72 /* Extract a part from a path.
74 * buf - buffer extract part to.
75 * buf_size - size of buffer.
76 * path - path to extract from.
77 * level - what to extract. 0 is file name, 1 is parent of file, 2 is
78 * parent of parent, etc.
80 * Returns buf if the desired level was found, NULL otherwise.
82 static char* get_dir(char* buf, int buf_size, const char* path, int level)
84 const char* sep;
85 const char* last_sep;
86 int len;
88 sep = path + strlen(path);
89 last_sep = sep;
91 while (sep > path)
93 if ('/' == *(--sep))
95 if (!level)
96 break;
98 level--;
99 last_sep = sep - 1;
103 if (level || (last_sep <= sep))
104 return NULL;
106 len = MIN(last_sep - sep, buf_size - 1);
107 strlcpy(buf, sep + 1, len + 1);
108 return buf;
111 #if (CONFIG_CODEC != MAS3507D)
112 /* A helper to determine the enum value for pitch/speed.
114 When there are two choices (i.e. boolean), return 1 if the value is
115 different from normal value and 2 if the value is the same as the
116 normal value. E.g. "%?Sp<%Sp>" would show the pitch only when
117 playing at a modified pitch.
119 When there are more than two choices (i.e. enum), the left half of
120 the choices are to show 0..normal range, and the right half of the
121 choices are to show values over that. The last entry is used when
122 it is set to the normal setting, following the rockbox convention
123 to use the last entry for special values.
125 E.g.
127 2 items: %?Sp<0..99 or 101..infinity|100>
128 3 items: %?Sp<0..99|101..infinity|100>
129 4 items: %?Sp<0..49|50..99|101..infinity|100>
130 5 items: %?Sp<0..49|50..99|101..149|150..infinity|100>
131 6 items: %?Sp<0..33|34..66|67..99|101..133|134..infinity|100>
132 7 items: %?Sp<0..33|34..66|67..99|101..133|134..167|167..infinity|100>
134 static int pitch_speed_enum(int range, int32_t val, int32_t normval)
136 int center;
137 int n;
139 if (range < 3)
140 return (val == normval) + 1;
141 if (val == normval)
142 return range;
143 center = range / 2;
144 n = (center * val) / normval + 1;
145 return (range <= n) ? (range - 1) : n;
147 #endif
149 /* Return the tag found at index i and write its value in buf.
150 The return value is buf if the tag had a value, or NULL if not.
152 intval is used with conditionals/enums: when this function is called,
153 intval should contain the number of options in the conditional/enum.
154 When this function returns, intval is -1 if the tag is non numeric or,
155 if the tag is numeric, *intval is the enum case we want to go to (between 1
156 and the original value of *intval, inclusive).
157 When not treating a conditional/enum, intval should be NULL.
160 /* a few convinience macros for the id3 == NULL case
161 * depends on a few variable names in get_token_value() */
163 #define HANDLE_NULL_ID3(id3field) (LIKELY(id3) ? (id3field) : NULL)
165 #define HANDLE_NULL_ID3_NUM_ZERO { if (UNLIKELY(!id3)) return zero_str; }
167 #define HANDLE_NULL_ID3_NUM_INTVAL(id3field) \
168 do { \
169 if (intval) { \
170 *intval = (LIKELY(id3) ? (id3field) + 1 : 0); \
172 if (LIKELY(id3)) \
174 snprintf(buf, buf_size, "%ld", (id3field)); \
175 return buf; \
177 return zero_str; \
178 } while (0)
180 const char *get_token_value(struct gui_wps *gwps,
181 struct wps_token *token,
182 char *buf, int buf_size,
183 int *intval)
185 if (!gwps)
186 return NULL;
188 struct wps_data *data = gwps->data;
189 struct wps_state *state = gwps->state;
190 int elapsed, length;
191 static const char * const zero_str = "0";
193 if (!data || !state)
194 return NULL;
196 struct mp3entry *id3;
198 if (token->next)
199 id3 = state->nid3;
200 else
201 id3 = state->id3;
203 if (id3)
205 elapsed = id3->elapsed;
206 length = id3->length;
208 else
210 elapsed = 0;
211 length = 0;
214 #if CONFIG_RTC
215 struct tm* tm = NULL;
217 /* if the token is an RTC one, update the time
218 and do the necessary checks */
219 if (token->type >= WPS_TOKENS_RTC_BEGIN
220 && token->type <= WPS_TOKENS_RTC_END)
222 tm = get_time();
224 if (!valid_time(tm))
225 return NULL;
227 #endif
229 int limit = 1;
230 if (intval)
232 limit = *intval;
233 *intval = -1;
236 switch (token->type)
238 case WPS_TOKEN_CHARACTER:
239 if (token->value.c == '\n')
240 return NULL;
241 return &(token->value.c);
243 case WPS_TOKEN_STRING:
244 return (char*)token->value.data;
246 case WPS_TOKEN_TRANSLATEDSTRING:
247 return (char*)P2STR(ID2P(token->value.i));
249 case WPS_TOKEN_TRACK_TIME_ELAPSED:
250 format_time(buf, buf_size,
251 elapsed + state->ff_rewind_count);
252 return buf;
254 case WPS_TOKEN_TRACK_TIME_REMAINING:
255 format_time(buf, buf_size,
256 length - elapsed -
257 state->ff_rewind_count);
258 return buf;
260 case WPS_TOKEN_TRACK_LENGTH:
261 format_time(buf, buf_size, length);
262 return buf;
264 case WPS_TOKEN_PLAYLIST_ENTRIES:
265 snprintf(buf, buf_size, "%d", playlist_amount());
266 return buf;
268 case WPS_TOKEN_PLAYLIST_NAME:
269 return playlist_name(NULL, buf, buf_size);
271 case WPS_TOKEN_PLAYLIST_POSITION:
272 snprintf(buf, buf_size, "%d", playlist_get_display_index());
273 return buf;
275 case WPS_TOKEN_PLAYLIST_SHUFFLE:
276 if ( global_settings.playlist_shuffle )
277 return "s";
278 else
279 return NULL;
280 break;
282 case WPS_TOKEN_VOLUME:
283 snprintf(buf, buf_size, "%d", global_settings.volume);
284 if (intval)
286 if (global_settings.volume == sound_min(SOUND_VOLUME))
288 *intval = 1;
290 else if (global_settings.volume == 0)
292 *intval = limit - 1;
294 else if (global_settings.volume > 0)
296 *intval = limit;
298 else
300 *intval = (limit - 3) * (global_settings.volume
301 - sound_min(SOUND_VOLUME) - 1)
302 / (-1 - sound_min(SOUND_VOLUME)) + 2;
305 return buf;
307 case WPS_TOKEN_TRACK_ELAPSED_PERCENT:
308 if (length <= 0)
309 return NULL;
311 if (intval)
313 *intval = limit * (elapsed + state->ff_rewind_count)
314 / length + 1;
316 snprintf(buf, buf_size, "%d",
317 100*(elapsed + state->ff_rewind_count) / length);
318 return buf;
320 case WPS_TOKEN_METADATA_ARTIST:
321 return HANDLE_NULL_ID3(id3->artist);
323 case WPS_TOKEN_METADATA_COMPOSER:
324 return HANDLE_NULL_ID3(id3->composer);
326 case WPS_TOKEN_METADATA_ALBUM:
327 return HANDLE_NULL_ID3(id3->album);
329 case WPS_TOKEN_METADATA_ALBUM_ARTIST:
330 return HANDLE_NULL_ID3(id3->albumartist);
332 case WPS_TOKEN_METADATA_GROUPING:
333 return HANDLE_NULL_ID3(id3->grouping);
335 case WPS_TOKEN_METADATA_GENRE:
336 return HANDLE_NULL_ID3(id3->genre_string);
338 case WPS_TOKEN_METADATA_DISC_NUMBER:
339 if (LIKELY(id3)) {
340 if (id3->disc_string)
341 return id3->disc_string;
342 if (id3->discnum) {
343 snprintf(buf, buf_size, "%d", id3->discnum);
344 return buf;
347 return NULL;
349 case WPS_TOKEN_METADATA_TRACK_NUMBER:
350 if (LIKELY(id3)) {
351 if (id3->track_string)
352 return id3->track_string;
354 if (id3->tracknum) {
355 snprintf(buf, buf_size, "%d", id3->tracknum);
356 return buf;
359 return NULL;
361 case WPS_TOKEN_METADATA_TRACK_TITLE:
362 return HANDLE_NULL_ID3(id3->title);
364 case WPS_TOKEN_METADATA_VERSION:
365 if (LIKELY(id3))
367 switch (id3->id3version)
369 case ID3_VER_1_0:
370 return "1";
372 case ID3_VER_1_1:
373 return "1.1";
375 case ID3_VER_2_2:
376 return "2.2";
378 case ID3_VER_2_3:
379 return "2.3";
381 case ID3_VER_2_4:
382 return "2.4";
384 default:
385 break;
388 return NULL;
390 case WPS_TOKEN_METADATA_YEAR:
391 if (LIKELY(id3)) {
392 if( id3->year_string )
393 return id3->year_string;
395 if (id3->year) {
396 snprintf(buf, buf_size, "%d", id3->year);
397 return buf;
400 return NULL;
402 case WPS_TOKEN_METADATA_COMMENT:
403 return HANDLE_NULL_ID3(id3->comment);
405 #ifdef HAVE_ALBUMART
406 case WPS_TOKEN_ALBUMART_FOUND:
407 if (data->albumart) {
408 if (playback_current_aa_hid(data->playback_aa_slot) >= 0)
409 return "C";
411 return NULL;
413 case WPS_TOKEN_ALBUMART_DISPLAY:
414 if (!data->albumart)
415 return NULL;
416 if (!data->albumart->draw)
417 data->albumart->draw = true;
418 return NULL;
419 #endif
421 case WPS_TOKEN_FILE_BITRATE:
422 if(id3 && id3->bitrate)
423 snprintf(buf, buf_size, "%d", id3->bitrate);
424 else
425 return "?";
426 return buf;
428 case WPS_TOKEN_FILE_CODEC:
429 if (intval)
431 if (UNLIKELY(!id3))
432 *intval = 0;
433 else if(id3->codectype == AFMT_UNKNOWN)
434 *intval = AFMT_NUM_CODECS;
435 else
436 *intval = id3->codectype;
438 return get_codectype(id3);
440 case WPS_TOKEN_FILE_FREQUENCY:
441 HANDLE_NULL_ID3_NUM_ZERO;
442 snprintf(buf, buf_size, "%ld", id3->frequency);
443 return buf;
445 case WPS_TOKEN_FILE_FREQUENCY_KHZ:
446 HANDLE_NULL_ID3_NUM_ZERO;
447 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
448 if ((id3->frequency % 1000) < 100)
449 snprintf(buf, buf_size, "%ld", id3->frequency / 1000);
450 else
451 snprintf(buf, buf_size, "%ld.%d",
452 id3->frequency / 1000,
453 (id3->frequency % 1000) / 100);
454 return buf;
456 case WPS_TOKEN_FILE_NAME:
457 if (LIKELY(id3) && get_dir(buf, buf_size, id3->path, 0)) {
458 /* Remove extension */
459 char* sep = strrchr(buf, '.');
460 if (NULL != sep) {
461 *sep = 0;
463 return buf;
465 else {
466 return NULL;
469 case WPS_TOKEN_FILE_NAME_WITH_EXTENSION:
470 if (LIKELY(id3))
471 return get_dir(buf, buf_size, id3->path, 0);
472 return NULL;
474 case WPS_TOKEN_FILE_PATH:
475 return HANDLE_NULL_ID3(id3->path);
477 case WPS_TOKEN_FILE_SIZE:
478 HANDLE_NULL_ID3_NUM_ZERO;
479 snprintf(buf, buf_size, "%ld", id3->filesize / 1024);
480 return buf;
482 case WPS_TOKEN_FILE_VBR:
483 return (LIKELY(id3) && id3->vbr) ? "(avg)" : NULL;
485 case WPS_TOKEN_FILE_DIRECTORY:
486 if (LIKELY(id3))
487 return get_dir(buf, buf_size, id3->path, token->value.i);
488 return NULL;
490 case WPS_TOKEN_BATTERY_PERCENT:
492 int l = battery_level();
494 if (intval)
496 limit = MAX(limit, 2);
497 if (l > -1) {
498 /* First enum is used for "unknown level". */
499 *intval = (limit - 1) * l / 100 + 2;
500 } else {
501 *intval = 1;
505 if (l > -1) {
506 snprintf(buf, buf_size, "%d", l);
507 return buf;
508 } else {
509 return "?";
513 case WPS_TOKEN_BATTERY_VOLTS:
515 unsigned int v = battery_voltage();
516 snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10);
517 return buf;
520 case WPS_TOKEN_BATTERY_TIME:
522 int t = battery_time();
523 if (t >= 0)
524 snprintf(buf, buf_size, "%dh %dm", t / 60, t % 60);
525 else
526 return "?h ?m";
527 return buf;
530 #if CONFIG_CHARGING
531 case WPS_TOKEN_BATTERY_CHARGER_CONNECTED:
533 if(charger_input_state==CHARGER)
534 return "p";
535 else
536 return NULL;
538 #endif
539 #if CONFIG_CHARGING >= CHARGING_MONITOR
540 case WPS_TOKEN_BATTERY_CHARGING:
542 if (charge_state == CHARGING || charge_state == TOPOFF) {
543 return "c";
544 } else {
545 return NULL;
548 #endif
549 case WPS_TOKEN_BATTERY_SLEEPTIME:
551 if (get_sleep_timer() == 0)
552 return NULL;
553 else
555 format_time(buf, buf_size, get_sleep_timer() * 1000);
556 return buf;
560 case WPS_TOKEN_PLAYBACK_STATUS:
562 int status = current_playmode();
563 /* music */
564 int mode = 1; /* stop */
565 if (status == STATUS_PLAY)
566 mode = 2; /* play */
567 if (state->is_fading ||
568 (status == STATUS_PAUSE && !status_get_ffmode()))
569 mode = 3; /* pause */
570 else
571 { /* ff / rwd */
572 if (status_get_ffmode() == STATUS_FASTFORWARD)
573 mode = 4;
574 if (status_get_ffmode() == STATUS_FASTBACKWARD)
575 mode = 5;
577 #ifdef HAVE_RECORDING
578 /* recording */
579 if (status == STATUS_RECORD)
580 mode = 6;
581 else if (status == STATUS_RECORD_PAUSE)
582 mode = 7;
583 #endif
584 #if CONFIG_TUNER
585 /* radio */
586 if (status == STATUS_RADIO)
587 mode = 8;
588 else if (status == STATUS_RADIO_PAUSE)
589 mode = 9;
590 #endif
592 if (intval) {
593 *intval = mode;
596 snprintf(buf, buf_size, "%d", mode-1);
597 return buf;
600 case WPS_TOKEN_REPEAT_MODE:
601 if (intval)
602 *intval = global_settings.repeat_mode + 1;
603 snprintf(buf, buf_size, "%d", global_settings.repeat_mode);
604 return buf;
606 case WPS_TOKEN_RTC_PRESENT:
607 #if CONFIG_RTC
608 return "c";
609 #else
610 return NULL;
611 #endif
613 #if CONFIG_RTC
614 case WPS_TOKEN_RTC_12HOUR_CFG:
615 if (intval)
616 *intval = global_settings.timeformat + 1;
617 snprintf(buf, buf_size, "%d", global_settings.timeformat);
618 return buf;
620 case WPS_TOKEN_RTC_DAY_OF_MONTH:
621 /* d: day of month (01..31) */
622 snprintf(buf, buf_size, "%02d", tm->tm_mday);
623 return buf;
625 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
626 /* e: day of month, blank padded ( 1..31) */
627 snprintf(buf, buf_size, "%2d", tm->tm_mday);
628 return buf;
630 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED:
631 /* H: hour (00..23) */
632 snprintf(buf, buf_size, "%02d", tm->tm_hour);
633 return buf;
635 case WPS_TOKEN_RTC_HOUR_24:
636 /* k: hour ( 0..23) */
637 snprintf(buf, buf_size, "%2d", tm->tm_hour);
638 return buf;
640 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED:
641 /* I: hour (01..12) */
642 snprintf(buf, buf_size, "%02d",
643 (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 return buf;
652 case WPS_TOKEN_RTC_MONTH:
653 /* m: month (01..12) */
654 if (intval)
655 *intval = tm->tm_mon + 1;
656 snprintf(buf, buf_size, "%02d", tm->tm_mon + 1);
657 return buf;
659 case WPS_TOKEN_RTC_MINUTE:
660 /* M: minute (00..59) */
661 snprintf(buf, buf_size, "%02d", tm->tm_min);
662 return buf;
664 case WPS_TOKEN_RTC_SECOND:
665 /* S: second (00..59) */
666 snprintf(buf, buf_size, "%02d", tm->tm_sec);
667 return buf;
669 case WPS_TOKEN_RTC_YEAR_2_DIGITS:
670 /* y: last two digits of year (00..99) */
671 snprintf(buf, buf_size, "%02d", tm->tm_year % 100);
672 return buf;
674 case WPS_TOKEN_RTC_YEAR_4_DIGITS:
675 /* Y: year (1970...) */
676 snprintf(buf, buf_size, "%04d", tm->tm_year + 1900);
677 return buf;
679 case WPS_TOKEN_RTC_AM_PM_UPPER:
680 /* p: upper case AM or PM indicator */
681 return tm->tm_hour/12 == 0 ? "AM" : "PM";
683 case WPS_TOKEN_RTC_AM_PM_LOWER:
684 /* P: lower case am or pm indicator */
685 return tm->tm_hour/12 == 0 ? "am" : "pm";
687 case WPS_TOKEN_RTC_WEEKDAY_NAME:
688 /* a: abbreviated weekday name (Sun..Sat) */
689 return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday);
691 case WPS_TOKEN_RTC_MONTH_NAME:
692 /* b: abbreviated month name (Jan..Dec) */
693 return str(LANG_MONTH_JANUARY + tm->tm_mon);
695 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON:
696 /* u: day of week (1..7); 1 is Monday */
697 if (intval)
698 *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
699 snprintf(buf, buf_size, "%1d", tm->tm_wday + 1);
700 return buf;
702 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
703 /* w: day of week (0..6); 0 is Sunday */
704 if (intval)
705 *intval = tm->tm_wday + 1;
706 snprintf(buf, buf_size, "%1d", tm->tm_wday);
707 return buf;
708 #else
709 case WPS_TOKEN_RTC_DAY_OF_MONTH:
710 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
711 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED:
712 case WPS_TOKEN_RTC_HOUR_24:
713 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED:
714 case WPS_TOKEN_RTC_HOUR_12:
715 case WPS_TOKEN_RTC_MONTH:
716 case WPS_TOKEN_RTC_MINUTE:
717 case WPS_TOKEN_RTC_SECOND:
718 case WPS_TOKEN_RTC_AM_PM_UPPER:
719 case WPS_TOKEN_RTC_AM_PM_LOWER:
720 case WPS_TOKEN_RTC_YEAR_2_DIGITS:
721 return "--";
722 case WPS_TOKEN_RTC_YEAR_4_DIGITS:
723 return "----";
724 case WPS_TOKEN_RTC_WEEKDAY_NAME:
725 case WPS_TOKEN_RTC_MONTH_NAME:
726 return "---";
727 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON:
728 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
729 return "-";
730 #endif
732 #ifdef HAVE_LCD_CHARCELLS
733 case WPS_TOKEN_PROGRESSBAR:
735 char *end = utf8encode(data->wps_progress_pat[0], buf);
736 *end = '\0';
737 return buf;
740 case WPS_TOKEN_PLAYER_PROGRESSBAR:
741 if(is_new_player())
743 /* we need 11 characters (full line) for
744 progress-bar */
745 strlcpy(buf, " ", buf_size);
747 else
749 /* Tell the user if we have an OldPlayer */
750 strlcpy(buf, " <Old LCD> ", buf_size);
752 return buf;
753 #endif
756 #ifdef HAVE_TAGCACHE
757 case WPS_TOKEN_DATABASE_PLAYCOUNT:
758 HANDLE_NULL_ID3_NUM_INTVAL(id3->playcount);
760 case WPS_TOKEN_DATABASE_RATING:
761 HANDLE_NULL_ID3_NUM_INTVAL(id3->rating);
763 case WPS_TOKEN_DATABASE_AUTOSCORE:
764 HANDLE_NULL_ID3_NUM_INTVAL(id3->score);
765 #endif
767 #if (CONFIG_CODEC == SWCODEC)
768 case WPS_TOKEN_CROSSFADE:
769 if (intval)
770 *intval = global_settings.crossfade + 1;
771 snprintf(buf, buf_size, "%d", global_settings.crossfade);
772 return buf;
774 case WPS_TOKEN_REPLAYGAIN:
776 int val;
778 if (global_settings.replaygain_type == REPLAYGAIN_OFF)
779 val = 1; /* off */
780 else
782 int type;
783 if (LIKELY(id3))
784 type = get_replaygain_mode(id3->track_gain_string != NULL,
785 id3->album_gain_string != NULL);
786 else
787 type = -1;
789 if (type < 0)
790 val = 6; /* no tag */
791 else
792 val = type + 2;
794 if (global_settings.replaygain_type == REPLAYGAIN_SHUFFLE)
795 val += 2;
798 if (intval)
799 *intval = val;
801 switch (val)
803 case 1:
804 case 6:
805 return "+0.00 dB";
806 break;
807 /* due to above, coming here with !id3 shouldn't be possible */
808 case 2:
809 case 4:
810 strlcpy(buf, id3->track_gain_string, buf_size);
811 break;
812 case 3:
813 case 5:
814 strlcpy(buf, id3->album_gain_string, buf_size);
815 break;
817 return buf;
819 #endif /* (CONFIG_CODEC == SWCODEC) */
821 #if (CONFIG_CODEC != MAS3507D)
822 case WPS_TOKEN_SOUND_PITCH:
824 int32_t pitch = sound_get_pitch();
825 snprintf(buf, buf_size, "%ld.%ld",
826 pitch / PITCH_SPEED_PRECISION,
827 (pitch % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
829 if (intval)
830 *intval = pitch_speed_enum(limit, pitch,
831 PITCH_SPEED_PRECISION * 100);
832 return buf;
834 #endif
836 #if CONFIG_CODEC == SWCODEC
837 case WPS_TOKEN_SOUND_SPEED:
839 int32_t pitch = sound_get_pitch();
840 int32_t speed;
841 if (dsp_timestretch_available())
842 speed = GET_SPEED(pitch, dsp_get_timestretch());
843 else
844 speed = pitch;
845 snprintf(buf, buf_size, "%ld.%ld",
846 speed / PITCH_SPEED_PRECISION,
847 (speed % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
848 if (intval)
849 *intval = pitch_speed_enum(limit, speed,
850 PITCH_SPEED_PRECISION * 100);
851 return buf;
853 #endif
855 case WPS_TOKEN_MAIN_HOLD:
856 #ifdef HAS_BUTTON_HOLD
857 if (button_hold())
858 #else
859 if (is_keys_locked())
860 #endif /*hold switch or softlock*/
861 return "h";
862 else
863 return NULL;
865 #ifdef HAS_REMOTE_BUTTON_HOLD
866 case WPS_TOKEN_REMOTE_HOLD:
867 if (remote_button_hold())
868 return "r";
869 else
870 return NULL;
871 #endif
873 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
874 case WPS_TOKEN_VLED_HDD:
875 if(led_read(HZ/2))
876 return "h";
877 else
878 return NULL;
879 #endif
880 case WPS_TOKEN_BUTTON_VOLUME:
881 if (global_status.last_volume_change &&
882 TIME_BEFORE(current_tick, global_status.last_volume_change +
883 token->value.i * TIMEOUT_UNIT))
884 return "v";
885 return NULL;
886 case WPS_TOKEN_LASTTOUCH:
887 #ifdef HAVE_TOUCHSCREEN
888 if (TIME_BEFORE(current_tick, token->value.i * TIMEOUT_UNIT +
889 touchscreen_last_touch()))
890 return "t";
891 #endif
892 return NULL;
894 case WPS_TOKEN_SETTING:
896 if (intval)
898 /* Handle contionals */
899 const struct settings_list *s = settings+token->value.i;
900 switch (s->flags&F_T_MASK)
902 case F_T_INT:
903 case F_T_UINT:
904 if (s->flags&F_RGB)
905 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
906 /* shouldn't overflow since colors are stored
907 * on 16 bits ...
908 * but this is pretty useless anyway */
909 *intval = *(int*)s->setting + 1;
910 else if (s->cfg_vals == NULL)
911 /* %?St|name|<1st choice|2nd choice|...> */
912 *intval = (*(int*)s->setting-s->int_setting->min)
913 /s->int_setting->step + 1;
914 else
915 /* %?St|name|<1st choice|2nd choice|...> */
916 /* Not sure about this one. cfg_name/vals are
917 * indexed from 0 right? */
918 *intval = *(int*)s->setting + 1;
919 break;
920 case F_T_BOOL:
921 /* %?St|name|<if true|if false> */
922 *intval = *(bool*)s->setting?1:2;
923 break;
924 case F_T_CHARPTR:
925 /* %?St|name|<if non empty string|if empty>
926 * The string's emptyness discards the setting's
927 * prefix and suffix */
928 *intval = ((char*)s->setting)[0]?1:2;
929 break;
930 default:
931 /* This shouldn't happen ... but you never know */
932 *intval = -1;
933 break;
936 cfg_to_string(token->value.i,buf,buf_size);
937 return buf;
939 /* Recording tokens */
940 case WPS_TOKEN_HAVE_RECORDING:
941 #ifdef HAVE_RECORDING
942 return "r";
943 #else
944 return NULL;
945 #endif
947 #ifdef HAVE_RECORDING
948 case WPS_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */
950 #if CONFIG_CODEC == SWCODEC
951 unsigned long samprk;
952 int rec_freq = global_settings.rec_frequency;
954 #ifdef SIMULATOR
955 samprk = 44100;
956 #else
957 #if defined(HAVE_SPDIF_REC)
958 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
960 /* Use rate in use, not current measured rate if it changed */
961 samprk = pcm_rec_sample_rate();
962 rec_freq = 0;
963 while (rec_freq < SAMPR_NUM_FREQ &&
964 audio_master_sampr_list[rec_freq] != samprk)
966 rec_freq++;
969 else
970 #endif
971 samprk = rec_freq_sampr[rec_freq];
972 #endif /* SIMULATOR */
973 if (intval)
975 switch (rec_freq)
977 REC_HAVE_96_(case REC_FREQ_96:
978 *intval = 1;
979 break;)
980 REC_HAVE_88_(case REC_FREQ_88:
981 *intval = 2;
982 break;)
983 REC_HAVE_64_(case REC_FREQ_64:
984 *intval = 3;
985 break;)
986 REC_HAVE_48_(case REC_FREQ_48:
987 *intval = 4;
988 break;)
989 REC_HAVE_44_(case REC_FREQ_44:
990 *intval = 5;
991 break;)
992 REC_HAVE_32_(case REC_FREQ_32:
993 *intval = 6;
994 break;)
995 REC_HAVE_24_(case REC_FREQ_24:
996 *intval = 7;
997 break;)
998 REC_HAVE_22_(case REC_FREQ_22:
999 *intval = 8;
1000 break;)
1001 REC_HAVE_16_(case REC_FREQ_16:
1002 *intval = 9;
1003 break;)
1004 REC_HAVE_12_(case REC_FREQ_12:
1005 *intval = 10;
1006 break;)
1007 REC_HAVE_11_(case REC_FREQ_11:
1008 *intval = 11;
1009 break;)
1010 REC_HAVE_8_(case REC_FREQ_8:
1011 *intval = 12;
1012 break;)
1014 *intval = rec_freq+1;
1016 snprintf(buf, buf_size, "%d.%1d", samprk/1000,samprk%1000);
1017 #else /* HWCODEC */
1019 static const char * const freq_strings[] =
1020 {"--", "44", "48", "32", "22", "24", "16"};
1021 int freq = 1 + global_settings.rec_frequency;
1022 #ifdef HAVE_SPDIF_REC
1023 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1025 /* Can't measure S/PDIF sample rate on Archos/Sim yet */
1026 freq = 0;
1028 #endif /* HAVE_SPDIF_IN */
1029 if (intval)
1030 *intval = freq+1; /* so the token gets a value 1<=x<=7 */
1031 snprintf(buf, buf_size, "%d\n",
1032 freq_strings[global_settings.rec_frequency]);
1033 #endif
1034 return buf;
1036 #if CONFIG_CODEC == SWCODEC
1037 case WPS_TOKEN_REC_ENCODER:
1039 int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */
1040 if (intval)
1041 *intval = rec_format;
1042 switch (rec_format)
1044 case REC_FORMAT_PCM_WAV:
1045 return "wav";
1046 case REC_FORMAT_AIFF:
1047 return "aiff";
1048 case REC_FORMAT_WAVPACK:
1049 return "wv";
1050 case REC_FORMAT_MPA_L3:
1051 return "MP3";
1052 default:
1053 return NULL;
1055 break;
1057 #endif
1058 case WPS_TOKEN_REC_BITRATE:
1059 #if CONFIG_CODEC == SWCODEC
1060 if (global_settings.rec_format == REC_FORMAT_MPA_L3)
1062 if (intval)
1064 #if 0 /* FIXME: I dont know if this is needed? */
1065 switch (1<<global_settings.mp3_enc_config.bitrate)
1067 case MP3_BITR_CAP_8:
1068 *intval = 1;
1069 break;
1070 case MP3_BITR_CAP_16:
1071 *intval = 2;
1072 break;
1073 case MP3_BITR_CAP_24:
1074 *intval = 3;
1075 break;
1076 case MP3_BITR_CAP_32:
1077 *intval = 4;
1078 break;
1079 case MP3_BITR_CAP_40:
1080 *intval = 5;
1081 break;
1082 case MP3_BITR_CAP_48:
1083 *intval = 6;
1084 break;
1085 case MP3_BITR_CAP_56:
1086 *intval = 7;
1087 break;
1088 case MP3_BITR_CAP_64:
1089 *intval = 8;
1090 break;
1091 case MP3_BITR_CAP_80:
1092 *intval = 9;
1093 break;
1094 case MP3_BITR_CAP_96:
1095 *intval = 10;
1096 break;
1097 case MP3_BITR_CAP_112:
1098 *intval = 11;
1099 break;
1100 case MP3_BITR_CAP_128:
1101 *intval = 12;
1102 break;
1103 case MP3_BITR_CAP_144:
1104 *intval = 13;
1105 break;
1106 case MP3_BITR_CAP_160:
1107 *intval = 14;
1108 break;
1109 case MP3_BITR_CAP_192:
1110 *intval = 15;
1111 break;
1113 #endif
1115 *intval = global_settings.mp3_enc_config.bitrate+1;
1116 snprintf(buf, buf_size, "%d", global_settings.mp3_enc_config.bitrate+1);
1117 return buf;
1119 else
1120 return NULL; /* Fixme later */
1121 #else /* CONFIG_CODEC == HWCODEC */
1122 if (intval)
1123 *intval = global_settings.rec_quality+1;
1124 snprintf(buf, buf_size, "%d", global_settings.rec_quality);
1125 return buf;
1126 #endif
1127 case WPS_TOKEN_REC_MONO:
1128 if (intval)
1129 *intval = global_settings.rec_channels?2:1;
1130 snprintf(buf, buf_size, "%s", !global_settings.rec_channels?"m":'\0');
1131 return buf;
1133 #endif /* HAVE_RECORDING */
1134 case WPS_TOKEN_CURRENT_SCREEN:
1136 int curr_screen = current_screen();
1138 #ifdef HAVE_RECORDING
1139 /* override current_screen() for recording screen since it may
1140 * be entered from the radio screen */
1141 if (in_recording_screen())
1142 curr_screen = GO_TO_RECSCREEN;
1143 #endif
1145 switch (curr_screen)
1147 case GO_TO_WPS:
1148 curr_screen = 2;
1149 break;
1150 #ifdef HAVE_RECORDING
1151 case GO_TO_RECSCREEN:
1152 curr_screen = 3;
1153 break;
1154 #endif
1155 #if CONFIG_TUNER
1156 case GO_TO_FM:
1157 curr_screen = 4;
1158 break;
1159 #endif
1160 default: /* lists */
1161 curr_screen = 1;
1162 break;
1164 if (intval)
1167 *intval = curr_screen;
1169 snprintf(buf, buf_size, "%d", curr_screen);
1170 return buf;
1173 default:
1174 return NULL;