Change cuesheet handling so the id3 info is not spoofed anymore. If something wants...
[kugel-rb.git] / apps / gui / skin_engine / skin_tokens.c
blob39bf0d497e2156121231e06f34fc0ab41bbc4d51
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-extra.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 #include "cuesheet.h"
38 #ifdef HAVE_LCD_CHARCELLS
39 #include "hwcompat.h"
40 #endif
41 #include "abrepeat.h"
42 #include "lang.h"
43 #include "misc.h"
44 #include "led.h"
45 #ifdef HAVE_LCD_BITMAP
46 /* Image stuff */
47 #include "albumart.h"
48 #endif
49 #include "dsp.h"
50 #include "playlist.h"
51 #if CONFIG_CODEC == SWCODEC
52 #include "playback.h"
53 #include "tdspeed.h"
54 #endif
55 #include "viewport.h"
57 #include "wps_internals.h"
58 #include "root_menu.h"
59 #ifdef HAVE_RECORDING
60 #include "recording.h"
61 #include "pcm_record.h"
62 #endif
63 #include "language.h"
64 #include "usb.h"
65 #if CONFIG_TUNER
66 #include "radio.h"
67 #include "tuner.h"
68 #endif
70 extern struct wps_state wps_state;
72 static const char* get_codectype(const struct mp3entry* id3)
74 if (id3 && id3->codectype < AFMT_NUM_CODECS) {
75 return audio_formats[id3->codectype].label;
76 } else {
77 return NULL;
81 /* Extract a part from a path.
83 * buf - buffer extract part to.
84 * buf_size - size of buffer.
85 * path - path to extract from.
86 * level - what to extract. 0 is file name, 1 is parent of file, 2 is
87 * parent of parent, etc.
89 * Returns buf if the desired level was found, NULL otherwise.
91 char* get_dir(char* buf, int buf_size, const char* path, int level)
93 const char* sep;
94 const char* last_sep;
95 int len;
97 sep = path + strlen(path);
98 last_sep = sep;
100 while (sep > path)
102 if ('/' == *(--sep))
104 if (!level)
105 break;
107 level--;
108 last_sep = sep - 1;
112 if (level || (last_sep <= sep))
113 return NULL;
115 len = MIN(last_sep - sep, buf_size - 1);
116 strlcpy(buf, sep + 1, len + 1);
117 return buf;
120 #if (CONFIG_CODEC != MAS3507D)
121 /* A helper to determine the enum value for pitch/speed.
123 When there are two choices (i.e. boolean), return 1 if the value is
124 different from normal value and 2 if the value is the same as the
125 normal value. E.g. "%?Sp<%Sp>" would show the pitch only when
126 playing at a modified pitch.
128 When there are more than two choices (i.e. enum), the left half of
129 the choices are to show 0..normal range, and the right half of the
130 choices are to show values over that. The last entry is used when
131 it is set to the normal setting, following the rockbox convention
132 to use the last entry for special values.
134 E.g.
136 2 items: %?Sp<0..99 or 101..infinity|100>
137 3 items: %?Sp<0..99|101..infinity|100>
138 4 items: %?Sp<0..49|50..99|101..infinity|100>
139 5 items: %?Sp<0..49|50..99|101..149|150..infinity|100>
140 6 items: %?Sp<0..33|34..66|67..99|101..133|134..infinity|100>
141 7 items: %?Sp<0..33|34..66|67..99|101..133|134..167|167..infinity|100>
143 static int pitch_speed_enum(int range, int32_t val, int32_t normval)
145 int center;
146 int n;
148 if (range < 3)
149 return (val == normval) + 1;
150 if (val == normval)
151 return range;
152 center = range / 2;
153 n = (center * val) / normval + 1;
154 return (range <= n) ? (range - 1) : n;
156 #endif
159 /* All tokens which only need the info to return a value go in here */
160 const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
161 char *buf, int buf_size, int limit, int *intval)
163 struct wps_state *state = &wps_state;
164 if (id3)
166 unsigned long length = id3->length;
167 unsigned long elapsed = id3->elapsed + state->ff_rewind_count;
168 switch (token->type)
170 case WPS_TOKEN_METADATA_ARTIST:
171 return id3->artist;
172 case WPS_TOKEN_METADATA_COMPOSER:
173 return id3->composer;
174 case WPS_TOKEN_METADATA_ALBUM:
175 return id3->album;
176 case WPS_TOKEN_METADATA_ALBUM_ARTIST:
177 return id3->albumartist;
178 case WPS_TOKEN_METADATA_GROUPING:
179 return id3->grouping;
180 case WPS_TOKEN_METADATA_GENRE:
181 return id3->genre_string;
182 case WPS_TOKEN_METADATA_DISC_NUMBER:
183 if (id3->disc_string)
184 return id3->disc_string;
185 if (id3->discnum) {
186 snprintf(buf, buf_size, "%d", id3->discnum);
187 return buf;
189 return NULL;
190 case WPS_TOKEN_METADATA_TRACK_NUMBER:
191 if (id3->track_string)
192 return id3->track_string;
193 if (id3->tracknum) {
194 snprintf(buf, buf_size, "%d", id3->tracknum);
195 return buf;
197 return NULL;
198 case WPS_TOKEN_METADATA_TRACK_TITLE:
199 return id3->title;
200 case WPS_TOKEN_METADATA_VERSION:
201 switch (id3->id3version)
203 case ID3_VER_1_0:
204 return "1";
205 case ID3_VER_1_1:
206 return "1.1";
207 case ID3_VER_2_2:
208 return "2.2";
209 case ID3_VER_2_3:
210 return "2.3";
211 case ID3_VER_2_4:
212 return "2.4";
213 default:
214 break;
216 return NULL;
217 case WPS_TOKEN_METADATA_YEAR:
218 if( id3->year_string )
219 return id3->year_string;
220 if (id3->year) {
221 snprintf(buf, buf_size, "%d", id3->year);
222 return buf;
224 return NULL;
225 case WPS_TOKEN_METADATA_COMMENT:
226 return id3->comment;
227 case WPS_TOKEN_FILE_PATH:
228 return id3->path;
229 case WPS_TOKEN_FILE_BITRATE:
230 if(id3->bitrate)
231 snprintf(buf, buf_size, "%d", id3->bitrate);
232 else
233 return "?";
234 return buf;
235 case WPS_TOKEN_TRACK_TIME_ELAPSED:
236 format_time(buf, buf_size, elapsed);
237 return buf;
239 case WPS_TOKEN_TRACK_TIME_REMAINING:
240 format_time(buf, buf_size, length - elapsed);
241 return buf;
243 case WPS_TOKEN_TRACK_LENGTH:
244 format_time(buf, buf_size, length);
245 return buf;
247 case WPS_TOKEN_TRACK_ELAPSED_PERCENT:
248 if (length <= 0)
249 return NULL;
251 if (intval)
253 *intval = limit * elapsed / length + 1;
255 snprintf(buf, buf_size, "%lu", 100 * elapsed / length);
256 return buf;
258 case WPS_TOKEN_TRACK_STARTING:
260 unsigned long time = token->value.i * 1000;
261 if (elapsed < time)
262 return "starting";
264 return NULL;
265 case WPS_TOKEN_TRACK_ENDING:
267 unsigned long time = token->value.i * 1000;
268 if (length - elapsed < time)
269 return "ending";
271 return NULL;
273 case WPS_TOKEN_FILE_CODEC:
274 if (intval)
276 if(id3->codectype == AFMT_UNKNOWN)
277 *intval = AFMT_NUM_CODECS;
278 else
279 *intval = id3->codectype;
281 return get_codectype(id3);
283 case WPS_TOKEN_FILE_FREQUENCY:
284 snprintf(buf, buf_size, "%ld", id3->frequency);
285 return buf;
286 case WPS_TOKEN_FILE_FREQUENCY_KHZ:
287 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
288 if ((id3->frequency % 1000) < 100)
289 snprintf(buf, buf_size, "%ld", id3->frequency / 1000);
290 else
291 snprintf(buf, buf_size, "%ld.%lu",
292 id3->frequency / 1000,
293 (id3->frequency % 1000) / 100);
294 return buf;
295 case WPS_TOKEN_FILE_NAME:
296 if (get_dir(buf, buf_size, id3->path, 0)) {
297 /* Remove extension */
298 char* sep = strrchr(buf, '.');
299 if (NULL != sep) {
300 *sep = 0;
302 return buf;
304 return NULL;
305 case WPS_TOKEN_FILE_NAME_WITH_EXTENSION:
306 return get_dir(buf, buf_size, id3->path, 0);
307 case WPS_TOKEN_FILE_SIZE:
308 snprintf(buf, buf_size, "%ld", id3->filesize / 1024);
309 return buf;
310 case WPS_TOKEN_FILE_VBR:
311 return (id3->vbr) ? "(avg)" : NULL;
312 case WPS_TOKEN_FILE_DIRECTORY:
313 return get_dir(buf, buf_size, id3->path, token->value.i);
315 #ifdef HAVE_TAGCACHE
316 case WPS_TOKEN_DATABASE_PLAYCOUNT:
317 if (intval)
318 *intval = id3->playcount + 1;
319 snprintf(buf, buf_size, "%ld", id3->playcount);
320 return buf;
321 case WPS_TOKEN_DATABASE_RATING:
322 if (intval)
323 *intval = id3->rating + 1;
324 snprintf(buf, buf_size, "%d", id3->rating);
325 return buf;
326 case WPS_TOKEN_DATABASE_AUTOSCORE:
327 if (intval)
328 *intval = id3->score + 1;
329 snprintf(buf, buf_size, "%d", id3->score);
330 return buf;
331 #endif
333 default:
334 return NULL;
337 else /* id3 == NULL, handle the error based on the expected return type */
339 switch (token->type)
341 /* Most tokens expect NULL on error so leave that for the default case,
342 * The ones that expect "0" need to be handled */
343 case WPS_TOKEN_FILE_FREQUENCY:
344 case WPS_TOKEN_FILE_FREQUENCY_KHZ:
345 case WPS_TOKEN_FILE_SIZE:
346 #ifdef HAVE_TAGCACHE
347 case WPS_TOKEN_DATABASE_PLAYCOUNT:
348 case WPS_TOKEN_DATABASE_RATING:
349 case WPS_TOKEN_DATABASE_AUTOSCORE:
350 #endif
351 if (intval)
352 *intval = 0;
353 return "0";
354 default:
355 return NULL;
358 return buf;
361 #if CONFIG_TUNER
363 /* Formats the frequency (specified in Hz) in MHz, */
364 /* with one or two digits after the decimal point -- */
365 /* depending on the frequency changing step. */
366 /* Returns buf */
367 static char *format_freq_MHz(int freq, int freq_step, char *buf, int buf_size)
369 int scale, div;
370 char *fmt;
371 if (freq_step < 100000)
373 /* Format with two digits after decimal point */
374 scale = 10000;
375 fmt = "%d.%02d";
377 else
379 /* Format with one digit after decimal point */
380 scale = 100000;
381 fmt = "%d.%d";
383 div = 1000000 / scale;
384 freq = freq / scale;
385 snprintf(buf, buf_size, fmt, freq/div, freq%div);
386 return buf;
390 /* Tokens which are really only used by the radio screen go in here */
391 const char *get_radio_token(struct wps_token *token, int preset_offset,
392 char *buf, int buf_size, int limit, int *intval)
394 const struct fm_region_data *region_data =
395 &(fm_region_data[global_settings.fm_region]);
396 (void)limit;
397 switch (token->type)
399 /* Radio/tuner tokens */
400 case WPS_TOKEN_TUNER_TUNED:
401 if (tuner_get(RADIO_TUNED))
402 return "t";
403 return NULL;
404 case WPS_TOKEN_TUNER_SCANMODE:
405 if (radio_scan_mode())
406 return "s";
407 return NULL;
408 case WPS_TOKEN_TUNER_STEREO:
409 if (radio_is_stereo())
410 return "s";
411 return NULL;
412 case WPS_TOKEN_TUNER_MINFREQ: /* changes based on "region" */
413 return format_freq_MHz(region_data->freq_min,
414 region_data->freq_step, buf, buf_size);
415 case WPS_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */
416 return format_freq_MHz(region_data->freq_max,
417 region_data->freq_step, buf, buf_size);
418 case WPS_TOKEN_TUNER_CURFREQ:
419 return format_freq_MHz(radio_current_frequency(),
420 region_data->freq_step, buf, buf_size);
421 case WPS_TOKEN_PRESET_NAME:
422 case WPS_TOKEN_PRESET_FREQ:
423 case WPS_TOKEN_PRESET_ID:
425 int preset_count = radio_preset_count();
426 int cur_preset = radio_current_preset();
427 if (preset_count == 0 || cur_preset < 0)
428 return NULL;
429 int preset = cur_preset + preset_offset;
430 /* make sure it's in the valid range */
431 preset %= preset_count;
432 if (preset < 0)
433 preset += preset_count;
434 if (token->type == WPS_TOKEN_PRESET_NAME)
435 snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name);
436 else if (token->type == WPS_TOKEN_PRESET_FREQ)
437 format_freq_MHz(radio_get_preset(preset)->frequency,
438 region_data->freq_step, buf, buf_size);
439 else
440 snprintf(buf, buf_size, "%d", preset + 1);
441 return buf;
443 case WPS_TOKEN_PRESET_COUNT:
444 snprintf(buf, buf_size, "%d", radio_preset_count());
445 if (intval)
446 *intval = radio_preset_count();
447 return buf;
448 case WPS_TOKEN_HAVE_RDS:
449 #ifdef HAVE_RDS_CAP
450 return "rds";
451 case WPS_TOKEN_RDS_NAME:
452 return tuner_get_rds_info(RADIO_RDS_NAME);
453 case WPS_TOKEN_RDS_TEXT:
454 return tuner_get_rds_info(RADIO_RDS_TEXT);
455 #else
456 return NULL; /* end of the WPS_TOKEN_HAVE_RDS case */
457 #endif /* HAVE_RDS_CAP */
459 return NULL;
461 #endif
463 /* Return the tags value as text. buf should be used as temp storage if needed.
465 intval is used with conditionals/enums: when this function is called,
466 intval should contain the number of options in the conditional/enum.
467 When this function returns, intval is -1 if the tag is non numeric or,
468 if the tag is numeric, *intval is the enum case we want to go to (between 1
469 and the original value of *intval, inclusive).
470 When not treating a conditional/enum, intval should be NULL.
472 const char *get_token_value(struct gui_wps *gwps,
473 struct wps_token *token,
474 char *buf, int buf_size,
475 int *intval)
477 if (!gwps)
478 return NULL;
480 struct wps_data *data = gwps->data;
481 struct wps_state *state = gwps->state;
482 struct mp3entry *id3; /* Think very carefully about using this.
483 maybe get_id3_token() is the better place? */
484 const char *out_text = NULL;
486 if (!data || !state)
487 return NULL;
490 if (token->next)
491 id3 = state->nid3;
492 else
493 id3 = state->id3;
495 #if CONFIG_RTC
496 struct tm* tm = NULL;
498 /* if the token is an RTC one, update the time
499 and do the necessary checks */
500 if (token->type >= WPS_TOKENS_RTC_BEGIN
501 && token->type <= WPS_TOKENS_RTC_END)
503 tm = get_time();
505 if (!valid_time(tm))
506 return NULL;
508 #endif
510 int limit = 1;
511 if (intval)
513 limit = *intval;
514 *intval = -1;
517 if (state->id3 && state->id3->cuesheet)
519 out_text = get_cuesheetid3_token(token, state->id3, token->next?1:0, buf, buf_size);
520 if (out_text)
521 return out_text;
523 out_text = get_id3_token(token, id3, buf, buf_size, limit, intval);
524 if (out_text)
525 return out_text;
526 #if CONFIG_TUNER
527 out_text = get_radio_token(token, 0, buf, buf_size, limit, intval);
528 if (out_text)
529 return out_text;
530 #endif
532 switch (token->type)
534 case WPS_TOKEN_CHARACTER:
535 if (token->value.c == '\n')
536 return NULL;
537 return &(token->value.c);
539 case WPS_TOKEN_STRING:
540 return (char*)token->value.data;
542 case WPS_TOKEN_TRANSLATEDSTRING:
543 return (char*)P2STR(ID2P(token->value.i));
545 case WPS_TOKEN_PLAYLIST_ENTRIES:
546 snprintf(buf, buf_size, "%d", playlist_amount());
547 return buf;
549 case WPS_TOKEN_LIST_TITLE_TEXT:
550 return (char*)token->value.data;
551 case WPS_TOKEN_LIST_TITLE_ICON:
552 if (intval)
553 *intval = token->value.i;
554 snprintf(buf, buf_size, "%d", token->value.i);
555 return buf;
557 case WPS_TOKEN_PLAYLIST_NAME:
558 return playlist_name(NULL, buf, buf_size);
560 case WPS_TOKEN_PLAYLIST_POSITION:
561 snprintf(buf, buf_size, "%d", playlist_get_display_index());
562 return buf;
564 case WPS_TOKEN_PLAYLIST_SHUFFLE:
565 if ( global_settings.playlist_shuffle )
566 return "s";
567 else
568 return NULL;
569 break;
571 case WPS_TOKEN_VOLUME:
572 snprintf(buf, buf_size, "%d", global_settings.volume);
573 if (intval)
575 int minvol = sound_min(SOUND_VOLUME);
576 if (global_settings.volume == minvol)
578 *intval = 1;
580 else if (global_settings.volume == 0)
582 *intval = limit - 1;
584 else if (global_settings.volume > 0)
586 *intval = limit;
588 else
590 *intval = (limit-3) * (global_settings.volume - minvol - 1)
591 / (-1 - minvol) + 2;
594 return buf;
595 #ifdef HAVE_ALBUMART
596 case WPS_TOKEN_ALBUMART_FOUND:
597 if (data->albumart)
599 int handle = -1;
600 handle = playback_current_aa_hid(data->playback_aa_slot);
601 #if CONFIG_TUNER
602 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
604 struct dim dim = {data->albumart->width, data->albumart->height};
605 handle = radio_get_art_hid(&dim);
607 #endif
608 if (handle >= 0)
609 return "C";
611 return NULL;
613 case WPS_TOKEN_ALBUMART_DISPLAY:
614 if (!data->albumart)
615 return NULL;
616 if (!data->albumart->draw)
617 data->albumart->draw = true;
618 return NULL;
619 #endif
621 case WPS_TOKEN_BATTERY_PERCENT:
623 int l = battery_level();
625 if (intval)
627 limit = MAX(limit, 2);
628 if (l > -1) {
629 /* First enum is used for "unknown level". */
630 *intval = (limit - 1) * l / 100 + 2;
631 } else {
632 *intval = 1;
636 if (l > -1) {
637 snprintf(buf, buf_size, "%d", l);
638 return buf;
639 } else {
640 return "?";
644 case WPS_TOKEN_BATTERY_VOLTS:
646 unsigned int v = battery_voltage();
647 snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10);
648 return buf;
651 case WPS_TOKEN_BATTERY_TIME:
653 int t = battery_time();
654 if (t >= 0)
655 snprintf(buf, buf_size, "%dh %dm", t / 60, t % 60);
656 else
657 return "?h ?m";
658 return buf;
661 #if CONFIG_CHARGING
662 case WPS_TOKEN_BATTERY_CHARGER_CONNECTED:
664 if(charger_input_state==CHARGER)
665 return "p";
666 else
667 return NULL;
669 #endif
670 #if CONFIG_CHARGING >= CHARGING_MONITOR
671 case WPS_TOKEN_BATTERY_CHARGING:
673 if (charge_state == CHARGING || charge_state == TOPOFF) {
674 return "c";
675 } else {
676 return NULL;
679 #endif
680 #ifdef HAVE_USB_POWER
681 case WPS_TOKEN_USB_POWERED:
682 if (usb_powered())
683 return "u";
684 return NULL;
685 #endif
686 case WPS_TOKEN_BATTERY_SLEEPTIME:
688 if (get_sleep_timer() == 0)
689 return NULL;
690 else
692 format_time(buf, buf_size, get_sleep_timer() * 1000);
693 return buf;
697 case WPS_TOKEN_PLAYBACK_STATUS:
699 int status = current_playmode();
700 /* music */
701 int mode = 1; /* stop */
702 if (status == STATUS_PLAY)
703 mode = 2; /* play */
704 if (state->is_fading ||
705 (status == STATUS_PAUSE && !status_get_ffmode()))
706 mode = 3; /* pause */
707 else
708 { /* ff / rwd */
709 if (status_get_ffmode() == STATUS_FASTFORWARD)
710 mode = 4;
711 if (status_get_ffmode() == STATUS_FASTBACKWARD)
712 mode = 5;
714 #ifdef HAVE_RECORDING
715 /* recording */
716 if (status == STATUS_RECORD)
717 mode = 6;
718 else if (status == STATUS_RECORD_PAUSE)
719 mode = 7;
720 #endif
721 #if CONFIG_TUNER
722 /* radio */
723 if (status == STATUS_RADIO)
724 mode = 8;
725 else if (status == STATUS_RADIO_PAUSE)
726 mode = 9;
727 #endif
729 if (intval) {
730 *intval = mode;
733 snprintf(buf, buf_size, "%d", mode-1);
734 return buf;
737 case WPS_TOKEN_REPEAT_MODE:
738 if (intval)
739 *intval = global_settings.repeat_mode + 1;
740 snprintf(buf, buf_size, "%d", global_settings.repeat_mode);
741 return buf;
743 case WPS_TOKEN_RTC_PRESENT:
744 #if CONFIG_RTC
745 return "c";
746 #else
747 return NULL;
748 #endif
750 #if CONFIG_RTC
751 case WPS_TOKEN_RTC_12HOUR_CFG:
752 if (intval)
753 *intval = global_settings.timeformat + 1;
754 snprintf(buf, buf_size, "%d", global_settings.timeformat);
755 return buf;
757 case WPS_TOKEN_RTC_DAY_OF_MONTH:
758 /* d: day of month (01..31) */
759 snprintf(buf, buf_size, "%02d", tm->tm_mday);
760 if (intval)
761 *intval = tm->tm_mday - 1;
762 return buf;
764 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
765 /* e: day of month, blank padded ( 1..31) */
766 snprintf(buf, buf_size, "%2d", tm->tm_mday);
767 if (intval)
768 *intval = tm->tm_mday - 1;
769 return buf;
771 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED:
772 /* H: hour (00..23) */
773 snprintf(buf, buf_size, "%02d", tm->tm_hour);
774 if (intval)
775 *intval = tm->tm_hour;
776 return buf;
778 case WPS_TOKEN_RTC_HOUR_24:
779 /* k: hour ( 0..23) */
780 snprintf(buf, buf_size, "%2d", tm->tm_hour);
781 if (intval)
782 *intval = tm->tm_hour;
783 return buf;
785 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED:
786 /* I: hour (01..12) */
787 snprintf(buf, buf_size, "%02d",
788 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
789 if (intval)
790 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
791 return buf;
793 case WPS_TOKEN_RTC_HOUR_12:
794 /* l: hour ( 1..12) */
795 snprintf(buf, buf_size, "%2d",
796 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
797 if (intval)
798 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
799 return buf;
801 case WPS_TOKEN_RTC_MONTH:
802 /* m: month (01..12) */
803 if (intval)
804 *intval = tm->tm_mon + 1;
805 snprintf(buf, buf_size, "%02d", tm->tm_mon + 1);
806 return buf;
808 case WPS_TOKEN_RTC_MINUTE:
809 /* M: minute (00..59) */
810 snprintf(buf, buf_size, "%02d", tm->tm_min);
811 if (intval)
812 *intval = tm->tm_min;
813 return buf;
815 case WPS_TOKEN_RTC_SECOND:
816 /* S: second (00..59) */
817 snprintf(buf, buf_size, "%02d", tm->tm_sec);
818 if (intval)
819 *intval = tm->tm_sec;
820 return buf;
822 case WPS_TOKEN_RTC_YEAR_2_DIGITS:
823 /* y: last two digits of year (00..99) */
824 snprintf(buf, buf_size, "%02d", tm->tm_year % 100);
825 if (intval)
826 *intval = tm->tm_year % 100;
827 return buf;
829 case WPS_TOKEN_RTC_YEAR_4_DIGITS:
830 /* Y: year (1970...) */
831 snprintf(buf, buf_size, "%04d", tm->tm_year + 1900);
832 if (intval)
833 *intval = tm->tm_year + 1900;
834 return buf;
836 case WPS_TOKEN_RTC_AM_PM_UPPER:
837 /* p: upper case AM or PM indicator */
838 if (intval)
839 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
840 return tm->tm_hour/12 == 0 ? "AM" : "PM";
842 case WPS_TOKEN_RTC_AM_PM_LOWER:
843 /* P: lower case am or pm indicator */
844 if (intval)
845 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
846 return tm->tm_hour/12 == 0 ? "am" : "pm";
848 case WPS_TOKEN_RTC_WEEKDAY_NAME:
849 /* a: abbreviated weekday name (Sun..Sat) */
850 return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday);
852 case WPS_TOKEN_RTC_MONTH_NAME:
853 /* b: abbreviated month name (Jan..Dec) */
854 return str(LANG_MONTH_JANUARY + tm->tm_mon);
856 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON:
857 /* u: day of week (1..7); 1 is Monday */
858 if (intval)
859 *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
860 snprintf(buf, buf_size, "%1d", tm->tm_wday + 1);
861 return buf;
863 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
864 /* w: day of week (0..6); 0 is Sunday */
865 if (intval)
866 *intval = tm->tm_wday + 1;
867 snprintf(buf, buf_size, "%1d", tm->tm_wday);
868 return buf;
869 #else
870 case WPS_TOKEN_RTC_DAY_OF_MONTH:
871 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
872 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED:
873 case WPS_TOKEN_RTC_HOUR_24:
874 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED:
875 case WPS_TOKEN_RTC_HOUR_12:
876 case WPS_TOKEN_RTC_MONTH:
877 case WPS_TOKEN_RTC_MINUTE:
878 case WPS_TOKEN_RTC_SECOND:
879 case WPS_TOKEN_RTC_AM_PM_UPPER:
880 case WPS_TOKEN_RTC_AM_PM_LOWER:
881 case WPS_TOKEN_RTC_YEAR_2_DIGITS:
882 return "--";
883 case WPS_TOKEN_RTC_YEAR_4_DIGITS:
884 return "----";
885 case WPS_TOKEN_RTC_WEEKDAY_NAME:
886 case WPS_TOKEN_RTC_MONTH_NAME:
887 return "---";
888 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON:
889 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
890 return "-";
891 #endif
893 #ifdef HAVE_LCD_CHARCELLS
894 case WPS_TOKEN_PROGRESSBAR:
896 char *end = utf8encode(data->wps_progress_pat[0], buf);
897 *end = '\0';
898 return buf;
901 case WPS_TOKEN_PLAYER_PROGRESSBAR:
902 if(is_new_player())
904 /* we need 11 characters (full line) for
905 progress-bar */
906 strlcpy(buf, " ", buf_size);
908 else
910 /* Tell the user if we have an OldPlayer */
911 strlcpy(buf, " <Old LCD> ", buf_size);
913 return buf;
914 #endif
918 #if (CONFIG_CODEC == SWCODEC)
919 case WPS_TOKEN_CROSSFADE:
920 #ifdef HAVE_CROSSFADE
921 if (intval)
922 *intval = global_settings.crossfade + 1;
923 snprintf(buf, buf_size, "%d", global_settings.crossfade);
924 #else
925 snprintf(buf, buf_size, "%d", 0);
926 #endif
927 return buf;
929 case WPS_TOKEN_REPLAYGAIN:
931 int val;
933 if (global_settings.replaygain_type == REPLAYGAIN_OFF)
934 val = 1; /* off */
935 else
937 int type;
938 if (LIKELY(id3))
939 type = get_replaygain_mode(id3->track_gain_string != NULL,
940 id3->album_gain_string != NULL);
941 else
942 type = -1;
944 if (type < 0)
945 val = 6; /* no tag */
946 else
947 val = type + 2;
949 if (global_settings.replaygain_type == REPLAYGAIN_SHUFFLE)
950 val += 2;
953 if (intval)
954 *intval = val;
956 switch (val)
958 case 1:
959 case 6:
960 return "+0.00 dB";
961 break;
962 /* due to above, coming here with !id3 shouldn't be possible */
963 case 2:
964 case 4:
965 strlcpy(buf, id3->track_gain_string, buf_size);
966 break;
967 case 3:
968 case 5:
969 strlcpy(buf, id3->album_gain_string, buf_size);
970 break;
972 return buf;
974 #endif /* (CONFIG_CODEC == SWCODEC) */
976 #if (CONFIG_CODEC != MAS3507D)
977 case WPS_TOKEN_SOUND_PITCH:
979 int32_t pitch = sound_get_pitch();
980 snprintf(buf, buf_size, "%ld.%ld",
981 pitch / PITCH_SPEED_PRECISION,
982 (pitch % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
984 if (intval)
985 *intval = pitch_speed_enum(limit, pitch,
986 PITCH_SPEED_PRECISION * 100);
987 return buf;
989 #endif
991 #if CONFIG_CODEC == SWCODEC
992 case WPS_TOKEN_SOUND_SPEED:
994 int32_t pitch = sound_get_pitch();
995 int32_t speed;
996 if (dsp_timestretch_available())
997 speed = GET_SPEED(pitch, dsp_get_timestretch());
998 else
999 speed = pitch;
1000 snprintf(buf, buf_size, "%ld.%ld",
1001 speed / PITCH_SPEED_PRECISION,
1002 (speed % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
1003 if (intval)
1004 *intval = pitch_speed_enum(limit, speed,
1005 PITCH_SPEED_PRECISION * 100);
1006 return buf;
1008 #endif
1010 case WPS_TOKEN_MAIN_HOLD:
1011 #ifdef HAS_BUTTON_HOLD
1012 if (button_hold())
1013 #else
1014 if (is_keys_locked())
1015 #endif /*hold switch or softlock*/
1016 return "h";
1017 else
1018 return NULL;
1020 #ifdef HAS_REMOTE_BUTTON_HOLD
1021 case WPS_TOKEN_REMOTE_HOLD:
1022 if (remote_button_hold())
1023 return "r";
1024 else
1025 return NULL;
1026 #endif
1028 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
1029 case WPS_TOKEN_VLED_HDD:
1030 if(led_read(HZ/2))
1031 return "h";
1032 else
1033 return NULL;
1034 #endif
1035 case WPS_TOKEN_BUTTON_VOLUME:
1036 if (global_status.last_volume_change &&
1037 TIME_BEFORE(current_tick, global_status.last_volume_change +
1038 token->value.i * TIMEOUT_UNIT))
1039 return "v";
1040 return NULL;
1042 case WPS_TOKEN_LASTTOUCH:
1043 #ifdef HAVE_TOUCHSCREEN
1044 if (TIME_BEFORE(current_tick, token->value.i * TIMEOUT_UNIT +
1045 touchscreen_last_touch()))
1046 return "t";
1047 #endif
1048 return NULL;
1050 case WPS_TOKEN_SETTING:
1052 const struct settings_list *s = settings+token->value.i;
1053 if (intval)
1055 /* Handle contionals */
1056 switch (s->flags&F_T_MASK)
1058 case F_T_INT:
1059 case F_T_UINT:
1060 if (s->flags&F_T_SOUND)
1062 /* %?St|name|<min|min+1|...|max-1|max> */
1063 int sound_setting = s->sound_setting->setting;
1064 /* settings with decimals can't be used in conditionals */
1065 if (sound_numdecimals(sound_setting) == 0)
1067 *intval = (*(int*)s->setting-sound_min(sound_setting))
1068 /sound_steps(sound_setting) + 1;
1070 else
1071 *intval = -1;
1073 else if (s->flags&F_RGB)
1074 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
1075 /* shouldn't overflow since colors are stored
1076 * on 16 bits ...
1077 * but this is pretty useless anyway */
1078 *intval = *(int*)s->setting + 1;
1079 else if (s->cfg_vals == NULL)
1080 /* %?St|name|<1st choice|2nd choice|...> */
1081 *intval = (*(int*)s->setting-s->int_setting->min)
1082 /s->int_setting->step + 1;
1083 else
1084 /* %?St|name|<1st choice|2nd choice|...> */
1085 /* Not sure about this one. cfg_name/vals are
1086 * indexed from 0 right? */
1087 *intval = *(int*)s->setting + 1;
1088 break;
1089 case F_T_BOOL:
1090 /* %?St|name|<if true|if false> */
1091 *intval = *(bool*)s->setting?1:2;
1092 break;
1093 case F_T_CHARPTR:
1094 case F_T_UCHARPTR:
1095 /* %?St|name|<if non empty string|if empty>
1096 * The string's emptyness discards the setting's
1097 * prefix and suffix */
1098 *intval = ((char*)s->setting)[0]?1:2;
1099 /* if there is a prefix we should ignore it here */
1100 if (s->filename_setting->prefix)
1101 return (char*)s->setting;
1102 break;
1103 default:
1104 /* This shouldn't happen ... but you never know */
1105 *intval = -1;
1106 break;
1109 /* Special handlng for filenames because we dont want to show the prefix */
1110 if ((s->flags&F_T_MASK) == F_T_UCHARPTR ||
1111 (s->flags&F_T_MASK) == F_T_UCHARPTR)
1113 if (s->filename_setting->prefix)
1114 return (char*)s->setting;
1116 cfg_to_string(token->value.i,buf,buf_size);
1117 return buf;
1119 case WPS_TOKEN_HAVE_TUNER:
1120 #if CONFIG_TUNER
1121 if (radio_hardware_present())
1122 return "r";
1123 #endif
1124 return NULL;
1125 /* Recording tokens */
1126 case WPS_TOKEN_HAVE_RECORDING:
1127 #ifdef HAVE_RECORDING
1128 return "r";
1129 #else
1130 return NULL;
1131 #endif
1133 #ifdef HAVE_RECORDING
1134 case WPS_TOKEN_IS_RECORDING:
1135 if (audio_status() == AUDIO_STATUS_RECORD)
1136 return "r";
1137 return NULL;
1138 case WPS_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */
1140 #if CONFIG_CODEC == SWCODEC
1141 unsigned long samprk;
1142 int rec_freq = global_settings.rec_frequency;
1144 #ifdef SIMULATOR
1145 samprk = 44100;
1146 #else
1147 #if defined(HAVE_SPDIF_REC)
1148 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1150 /* Use rate in use, not current measured rate if it changed */
1151 samprk = pcm_rec_sample_rate();
1152 rec_freq = 0;
1153 while (rec_freq < SAMPR_NUM_FREQ &&
1154 audio_master_sampr_list[rec_freq] != samprk)
1156 rec_freq++;
1159 else
1160 #endif
1161 samprk = rec_freq_sampr[rec_freq];
1162 #endif /* SIMULATOR */
1163 if (intval)
1165 switch (rec_freq)
1167 REC_HAVE_96_(case REC_FREQ_96:
1168 *intval = 1;
1169 break;)
1170 REC_HAVE_88_(case REC_FREQ_88:
1171 *intval = 2;
1172 break;)
1173 REC_HAVE_64_(case REC_FREQ_64:
1174 *intval = 3;
1175 break;)
1176 REC_HAVE_48_(case REC_FREQ_48:
1177 *intval = 4;
1178 break;)
1179 REC_HAVE_44_(case REC_FREQ_44:
1180 *intval = 5;
1181 break;)
1182 REC_HAVE_32_(case REC_FREQ_32:
1183 *intval = 6;
1184 break;)
1185 REC_HAVE_24_(case REC_FREQ_24:
1186 *intval = 7;
1187 break;)
1188 REC_HAVE_22_(case REC_FREQ_22:
1189 *intval = 8;
1190 break;)
1191 REC_HAVE_16_(case REC_FREQ_16:
1192 *intval = 9;
1193 break;)
1194 REC_HAVE_12_(case REC_FREQ_12:
1195 *intval = 10;
1196 break;)
1197 REC_HAVE_11_(case REC_FREQ_11:
1198 *intval = 11;
1199 break;)
1200 REC_HAVE_8_(case REC_FREQ_8:
1201 *intval = 12;
1202 break;)
1205 snprintf(buf, buf_size, "%lu.%1lu", samprk/1000,samprk%1000);
1206 #else /* HWCODEC */
1208 static const char * const freq_strings[] =
1209 {"--", "44", "48", "32", "22", "24", "16"};
1210 int freq = 1 + global_settings.rec_frequency;
1211 #ifdef HAVE_SPDIF_REC
1212 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1214 /* Can't measure S/PDIF sample rate on Archos/Sim yet */
1215 freq = 0;
1217 #endif /* HAVE_SPDIF_IN */
1218 if (intval)
1219 *intval = freq+1; /* so the token gets a value 1<=x<=7 */
1220 snprintf(buf, buf_size, "%s\n",
1221 freq_strings[global_settings.rec_frequency]);
1222 #endif
1223 return buf;
1225 #if CONFIG_CODEC == SWCODEC
1226 case WPS_TOKEN_REC_ENCODER:
1228 int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */
1229 if (intval)
1230 *intval = rec_format;
1231 switch (rec_format)
1233 case REC_FORMAT_PCM_WAV:
1234 return "wav";
1235 case REC_FORMAT_AIFF:
1236 return "aiff";
1237 case REC_FORMAT_WAVPACK:
1238 return "wv";
1239 case REC_FORMAT_MPA_L3:
1240 return "MP3";
1241 default:
1242 return NULL;
1244 break;
1246 #endif
1247 case WPS_TOKEN_REC_BITRATE:
1248 #if CONFIG_CODEC == SWCODEC
1249 if (global_settings.rec_format == REC_FORMAT_MPA_L3)
1251 if (intval)
1253 #if 0 /* FIXME: I dont know if this is needed? */
1254 switch (1<<global_settings.mp3_enc_config.bitrate)
1256 case MP3_BITR_CAP_8:
1257 *intval = 1;
1258 break;
1259 case MP3_BITR_CAP_16:
1260 *intval = 2;
1261 break;
1262 case MP3_BITR_CAP_24:
1263 *intval = 3;
1264 break;
1265 case MP3_BITR_CAP_32:
1266 *intval = 4;
1267 break;
1268 case MP3_BITR_CAP_40:
1269 *intval = 5;
1270 break;
1271 case MP3_BITR_CAP_48:
1272 *intval = 6;
1273 break;
1274 case MP3_BITR_CAP_56:
1275 *intval = 7;
1276 break;
1277 case MP3_BITR_CAP_64:
1278 *intval = 8;
1279 break;
1280 case MP3_BITR_CAP_80:
1281 *intval = 9;
1282 break;
1283 case MP3_BITR_CAP_96:
1284 *intval = 10;
1285 break;
1286 case MP3_BITR_CAP_112:
1287 *intval = 11;
1288 break;
1289 case MP3_BITR_CAP_128:
1290 *intval = 12;
1291 break;
1292 case MP3_BITR_CAP_144:
1293 *intval = 13;
1294 break;
1295 case MP3_BITR_CAP_160:
1296 *intval = 14;
1297 break;
1298 case MP3_BITR_CAP_192:
1299 *intval = 15;
1300 break;
1302 #endif
1303 *intval = global_settings.mp3_enc_config.bitrate+1;
1305 snprintf(buf, buf_size, "%lu", global_settings.mp3_enc_config.bitrate+1);
1306 return buf;
1308 else
1309 return NULL; /* Fixme later */
1310 #else /* CONFIG_CODEC == HWCODEC */
1311 if (intval)
1312 *intval = global_settings.rec_quality+1;
1313 snprintf(buf, buf_size, "%d", global_settings.rec_quality);
1314 return buf;
1315 #endif
1316 case WPS_TOKEN_REC_MONO:
1317 if (!global_settings.rec_channels)
1318 return "m";
1319 return NULL;
1321 case WPS_TOKEN_REC_SECONDS:
1323 int time = (audio_recorded_time() / HZ) % 60;
1324 if (intval)
1325 *intval = time;
1326 snprintf(buf, buf_size, "%02d", time);
1327 return buf;
1329 case WPS_TOKEN_REC_MINUTES:
1331 int time = (audio_recorded_time() / HZ) / 60;
1332 if (intval)
1333 *intval = time;
1334 snprintf(buf, buf_size, "%02d", time);
1335 return buf;
1337 case WPS_TOKEN_REC_HOURS:
1339 int time = (audio_recorded_time() / HZ) / 3600;
1340 if (intval)
1341 *intval = time;
1342 snprintf(buf, buf_size, "%02d", time);
1343 return buf;
1346 #endif /* HAVE_RECORDING */
1348 case WPS_TOKEN_CURRENT_SCREEN:
1350 int curr_screen = current_screen();
1352 #ifdef HAVE_RECORDING
1353 /* override current_screen() for recording screen since it may
1354 * be entered from the radio screen */
1355 if (in_recording_screen())
1356 curr_screen = GO_TO_RECSCREEN;
1357 #endif
1359 switch (curr_screen)
1361 case GO_TO_WPS:
1362 curr_screen = 2;
1363 break;
1364 #ifdef HAVE_RECORDING
1365 case GO_TO_RECSCREEN:
1366 curr_screen = 3;
1367 break;
1368 #endif
1369 #if CONFIG_TUNER
1370 case GO_TO_FM:
1371 curr_screen = 4;
1372 break;
1373 #endif
1374 case GO_TO_PLAYLIST_VIEWER:
1375 curr_screen = 5;
1376 break;
1377 default: /* lists */
1378 curr_screen = 1;
1379 break;
1381 if (intval)
1383 *intval = curr_screen;
1385 snprintf(buf, buf_size, "%d", curr_screen);
1386 return buf;
1389 case WPS_TOKEN_LANG_IS_RTL:
1390 return lang_is_rtl() ? "r" : NULL;
1392 default:
1393 return NULL;