Signal strength meter for FM radio - FS#8151 by Przemysław Hołubowski
[maemo-rb.git] / apps / gui / skin_engine / skin_tokens.c
blobefe67a186ed6cce37902ca7ef0475ae46f8ee917
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"
56 #include "tagcache.h"
58 #include "wps_internals.h"
59 #include "skin_engine.h"
60 #include "statusbar-skinned.h"
61 #include "root_menu.h"
62 #ifdef HAVE_RECORDING
63 #include "recording.h"
64 #include "pcm_record.h"
65 #endif
66 #include "language.h"
67 #include "usb.h"
68 #if CONFIG_TUNER
69 #include "radio.h"
70 #include "tuner.h"
71 #endif
73 #define NOINLINE __attribute__ ((noinline))
75 extern struct wps_state wps_state;
77 static const char* get_codectype(const struct mp3entry* id3)
79 if (id3 && id3->codectype < AFMT_NUM_CODECS) {
80 return audio_formats[id3->codectype].label;
81 } else {
82 return NULL;
86 /* Extract a part from a path.
88 * buf - buffer extract part to.
89 * buf_size - size of buffer.
90 * path - path to extract from.
91 * level - what to extract. 0 is file name, 1 is parent of file, 2 is
92 * parent of parent, etc.
94 * Returns buf if the desired level was found, NULL otherwise.
96 char* get_dir(char* buf, int buf_size, const char* path, int level)
98 const char* sep;
99 const char* last_sep;
100 int len;
102 sep = path + strlen(path);
103 last_sep = sep;
105 while (sep > path)
107 if ('/' == *(--sep))
109 if (!level)
110 break;
112 level--;
113 last_sep = sep - 1;
117 if (level || (last_sep <= sep))
118 return NULL;
120 len = MIN(last_sep - sep, buf_size - 1);
121 strlcpy(buf, sep + 1, len + 1);
122 return buf;
125 #if (CONFIG_CODEC != MAS3507D) && defined (HAVE_PITCHSCREEN)
126 /* A helper to determine the enum value for pitch/speed.
128 When there are two choices (i.e. boolean), return 1 if the value is
129 different from normal value and 2 if the value is the same as the
130 normal value. E.g. "%?Sp<%Sp>" would show the pitch only when
131 playing at a modified pitch.
133 When there are more than two choices (i.e. enum), the left half of
134 the choices are to show 0..normal range, and the right half of the
135 choices are to show values over that. The last entry is used when
136 it is set to the normal setting, following the rockbox convention
137 to use the last entry for special values.
139 E.g.
141 2 items: %?Sp<0..99 or 101..infinity|100>
142 3 items: %?Sp<0..99|101..infinity|100>
143 4 items: %?Sp<0..49|50..99|101..infinity|100>
144 5 items: %?Sp<0..49|50..99|101..149|150..infinity|100>
145 6 items: %?Sp<0..33|34..66|67..99|101..133|134..infinity|100>
146 7 items: %?Sp<0..33|34..66|67..99|101..133|134..167|167..infinity|100>
148 static int pitch_speed_enum(int range, int32_t val, int32_t normval)
150 int center;
151 int n;
153 if (range < 3)
154 return (val == normval) + 1;
155 if (val == normval)
156 return range;
157 center = range / 2;
158 n = (center * val) / normval + 1;
159 return (range <= n) ? (range - 1) : n;
161 #endif
163 const char *get_cuesheetid3_token(struct wps_token *token, struct mp3entry *id3,
164 int offset_tracks, char *buf, int buf_size)
166 struct cuesheet *cue = id3?id3->cuesheet:NULL;
167 if (!cue || !cue->curr_track)
168 return NULL;
170 struct cue_track_info *track = cue->curr_track;
171 if (offset_tracks)
173 if (cue->curr_track_idx+offset_tracks < cue->track_count)
174 track+=offset_tracks;
175 else
176 return NULL;
178 switch (token->type)
180 case SKIN_TOKEN_METADATA_ARTIST:
181 return *track->performer ? track->performer : NULL;
182 case SKIN_TOKEN_METADATA_COMPOSER:
183 return *track->songwriter ? track->songwriter : NULL;
184 case SKIN_TOKEN_METADATA_ALBUM:
185 return *cue->title ? cue->title : NULL;
186 case SKIN_TOKEN_METADATA_ALBUM_ARTIST:
187 return *cue->performer ? cue->performer : NULL;
188 case SKIN_TOKEN_METADATA_TRACK_TITLE:
189 return *track->title ? track->title : NULL;
190 case SKIN_TOKEN_METADATA_TRACK_NUMBER:
191 snprintf(buf, buf_size, "%d/%d",
192 cue->curr_track_idx+offset_tracks+1, cue->track_count);
193 return buf;
194 default:
195 return NULL;
197 return NULL;
200 static const char* get_filename_token(struct wps_token *token, char* filename,
201 char *buf, int buf_size)
203 if (filename)
205 switch (token->type)
207 case SKIN_TOKEN_FILE_PATH:
208 return filename;
209 case SKIN_TOKEN_FILE_NAME:
210 if (get_dir(buf, buf_size, filename, 0)) {
211 /* Remove extension */
212 char* sep = strrchr(buf, '.');
213 if (NULL != sep) {
214 *sep = 0;
216 return buf;
218 return NULL;
219 case SKIN_TOKEN_FILE_NAME_WITH_EXTENSION:
220 return get_dir(buf, buf_size, filename, 0);
221 case SKIN_TOKEN_FILE_DIRECTORY:
222 return get_dir(buf, buf_size, filename, token->value.i);
223 default:
224 return NULL;
227 return NULL;
230 /* All tokens which only need the info to return a value go in here */
231 const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
232 char *filename, char *buf, int buf_size, int limit, int *intval)
234 struct wps_state *state = &wps_state;
235 if (id3)
237 unsigned long length = id3->length;
238 unsigned long elapsed = id3->elapsed + state->ff_rewind_count;
239 switch (token->type)
241 case SKIN_TOKEN_METADATA_ARTIST:
242 return id3->artist;
243 case SKIN_TOKEN_METADATA_COMPOSER:
244 return id3->composer;
245 case SKIN_TOKEN_METADATA_ALBUM:
246 return id3->album;
247 case SKIN_TOKEN_METADATA_ALBUM_ARTIST:
248 return id3->albumartist;
249 case SKIN_TOKEN_METADATA_GROUPING:
250 return id3->grouping;
251 case SKIN_TOKEN_METADATA_GENRE:
252 return id3->genre_string;
253 case SKIN_TOKEN_METADATA_DISC_NUMBER:
254 if (id3->disc_string)
255 return id3->disc_string;
256 if (id3->discnum) {
257 snprintf(buf, buf_size, "%d", id3->discnum);
258 return buf;
260 return NULL;
261 case SKIN_TOKEN_METADATA_TRACK_NUMBER:
262 if (id3->track_string)
263 return id3->track_string;
264 if (id3->tracknum) {
265 snprintf(buf, buf_size, "%d", id3->tracknum);
266 return buf;
268 return NULL;
269 case SKIN_TOKEN_METADATA_TRACK_TITLE:
270 return id3->title;
271 case SKIN_TOKEN_METADATA_VERSION:
272 switch (id3->id3version)
274 case ID3_VER_1_0:
275 return "1";
276 case ID3_VER_1_1:
277 return "1.1";
278 case ID3_VER_2_2:
279 return "2.2";
280 case ID3_VER_2_3:
281 return "2.3";
282 case ID3_VER_2_4:
283 return "2.4";
284 default:
285 break;
287 return NULL;
288 case SKIN_TOKEN_METADATA_YEAR:
289 if( id3->year_string )
290 return id3->year_string;
291 if (id3->year) {
292 snprintf(buf, buf_size, "%d", id3->year);
293 return buf;
295 return NULL;
296 case SKIN_TOKEN_METADATA_COMMENT:
297 return id3->comment;
298 case SKIN_TOKEN_FILE_BITRATE:
299 if(id3->bitrate)
300 snprintf(buf, buf_size, "%d", id3->bitrate);
301 else
302 return "?";
303 return buf;
304 case SKIN_TOKEN_TRACK_TIME_ELAPSED:
305 format_time(buf, buf_size, elapsed);
306 return buf;
308 case SKIN_TOKEN_TRACK_TIME_REMAINING:
309 format_time(buf, buf_size, length - elapsed);
310 return buf;
312 case SKIN_TOKEN_TRACK_LENGTH:
313 format_time(buf, buf_size, length);
314 return buf;
316 case SKIN_TOKEN_TRACK_ELAPSED_PERCENT:
317 if (length <= 0)
318 return NULL;
320 if (intval)
322 if (limit == TOKEN_VALUE_ONLY)
323 limit = 100; /* make it a percentage */
324 *intval = limit * elapsed / length + 1;
326 snprintf(buf, buf_size, "%lu", 100 * elapsed / length);
327 return buf;
329 case SKIN_TOKEN_TRACK_STARTING:
331 unsigned long time = token->value.i * (HZ/TIMEOUT_UNIT);
332 if (elapsed < time)
333 return "starting";
335 return NULL;
336 case SKIN_TOKEN_TRACK_ENDING:
338 unsigned long time = token->value.i * (HZ/TIMEOUT_UNIT);
339 if (length - elapsed < time)
340 return "ending";
342 return NULL;
344 case SKIN_TOKEN_FILE_CODEC:
345 if (intval)
347 if(id3->codectype == AFMT_UNKNOWN)
348 *intval = AFMT_NUM_CODECS;
349 else
350 *intval = id3->codectype;
352 return get_codectype(id3);
354 case SKIN_TOKEN_FILE_FREQUENCY:
355 snprintf(buf, buf_size, "%ld", id3->frequency);
356 return buf;
357 case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
358 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
359 if ((id3->frequency % 1000) < 100)
360 snprintf(buf, buf_size, "%ld", id3->frequency / 1000);
361 else
362 snprintf(buf, buf_size, "%ld.%lu",
363 id3->frequency / 1000,
364 (id3->frequency % 1000) / 100);
365 return buf;
366 case SKIN_TOKEN_FILE_VBR:
367 return (id3->vbr) ? "(avg)" : NULL;
368 case SKIN_TOKEN_FILE_SIZE:
369 snprintf(buf, buf_size, "%ld", id3->filesize / 1024);
370 return buf;
372 #ifdef HAVE_TAGCACHE
373 case SKIN_TOKEN_DATABASE_PLAYCOUNT:
374 if (intval)
375 *intval = id3->playcount + 1;
376 snprintf(buf, buf_size, "%ld", id3->playcount);
377 return buf;
378 case SKIN_TOKEN_DATABASE_RATING:
379 if (intval)
380 *intval = id3->rating + 1;
381 snprintf(buf, buf_size, "%d", id3->rating);
382 return buf;
383 case SKIN_TOKEN_DATABASE_AUTOSCORE:
384 if (intval)
385 *intval = id3->score + 1;
386 snprintf(buf, buf_size, "%d", id3->score);
387 return buf;
388 #endif
390 default:
391 return get_filename_token(token, id3->path, buf, buf_size);
394 else /* id3 == NULL, handle the error based on the expected return type */
396 switch (token->type)
398 /* Most tokens expect NULL on error so leave that for the default case,
399 * The ones that expect "0" need to be handled */
400 case SKIN_TOKEN_FILE_FREQUENCY:
401 case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
402 case SKIN_TOKEN_FILE_SIZE:
403 #ifdef HAVE_TAGCACHE
404 case SKIN_TOKEN_DATABASE_PLAYCOUNT:
405 case SKIN_TOKEN_DATABASE_RATING:
406 case SKIN_TOKEN_DATABASE_AUTOSCORE:
407 #endif
408 if (intval)
409 *intval = 0;
410 return "0";
411 default:
412 return get_filename_token(token, filename, buf, buf_size);
415 return buf;
418 #if CONFIG_TUNER
420 /* Formats the frequency (specified in Hz) in MHz, */
421 /* with one or two digits after the decimal point -- */
422 /* depending on the frequency changing step. */
423 /* Returns buf */
424 static char *format_freq_MHz(int freq, int freq_step, char *buf, int buf_size)
426 int scale, div;
427 char *fmt;
428 if (freq_step < 100000)
430 /* Format with two digits after decimal point */
431 scale = 10000;
432 fmt = "%d.%02d";
434 else
436 /* Format with one digit after decimal point */
437 scale = 100000;
438 fmt = "%d.%d";
440 div = 1000000 / scale;
441 freq = freq / scale;
442 snprintf(buf, buf_size, fmt, freq/div, freq%div);
443 return buf;
447 /* Tokens which are really only used by the radio screen go in here */
448 const char *get_radio_token(struct wps_token *token, int preset_offset,
449 char *buf, int buf_size, int limit, int *intval)
451 const struct fm_region_data *region_data =
452 &(fm_region_data[global_settings.fm_region]);
453 (void)limit;
454 switch (token->type)
456 /* Radio/tuner tokens */
457 case SKIN_TOKEN_TUNER_TUNED:
458 if (tuner_get(RADIO_TUNED))
459 return "t";
460 return NULL;
461 case SKIN_TOKEN_TUNER_SCANMODE:
462 if (radio_scan_mode())
463 return "s";
464 return NULL;
465 case SKIN_TOKEN_TUNER_STEREO:
466 if (radio_is_stereo())
467 return "s";
468 return NULL;
469 case SKIN_TOKEN_TUNER_MINFREQ: /* changes based on "region" */
470 return format_freq_MHz(region_data->freq_min,
471 region_data->freq_step, buf, buf_size);
472 case SKIN_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */
473 return format_freq_MHz(region_data->freq_max,
474 region_data->freq_step, buf, buf_size);
475 case SKIN_TOKEN_TUNER_CURFREQ:
476 return format_freq_MHz(radio_current_frequency(),
477 region_data->freq_step, buf, buf_size);
478 #ifdef HAVE_RADIO_RSSI
479 case SKIN_TOKEN_TUNER_RSSI:
480 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI));
481 return buf;
482 case SKIN_TOKEN_TUNER_RSSI_MIN:
483 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI_MIN));
484 return buf;
485 case SKIN_TOKEN_TUNER_RSSI_MAX:
486 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI_MAX));
487 return buf;
488 #endif
489 case SKIN_TOKEN_PRESET_NAME:
490 case SKIN_TOKEN_PRESET_FREQ:
491 case SKIN_TOKEN_PRESET_ID:
493 int preset_count = radio_preset_count();
494 int cur_preset = radio_current_preset();
495 if (preset_count == 0 || cur_preset < 0)
496 return NULL;
497 int preset = cur_preset + preset_offset;
498 /* make sure it's in the valid range */
499 preset %= preset_count;
500 if (preset < 0)
501 preset += preset_count;
502 if (token->type == SKIN_TOKEN_PRESET_NAME)
503 snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name);
504 else if (token->type == SKIN_TOKEN_PRESET_FREQ)
505 format_freq_MHz(radio_get_preset(preset)->frequency,
506 region_data->freq_step, buf, buf_size);
507 else
508 snprintf(buf, buf_size, "%d", preset + 1);
509 return buf;
511 case SKIN_TOKEN_PRESET_COUNT:
512 snprintf(buf, buf_size, "%d", radio_preset_count());
513 if (intval)
514 *intval = radio_preset_count();
515 return buf;
516 case SKIN_TOKEN_HAVE_RDS:
517 #ifdef HAVE_RDS_CAP
518 return "rds";
519 case SKIN_TOKEN_RDS_NAME:
520 return tuner_get_rds_info(RADIO_RDS_NAME);
521 case SKIN_TOKEN_RDS_TEXT:
522 return tuner_get_rds_info(RADIO_RDS_TEXT);
523 #else
524 return NULL; /* end of the SKIN_TOKEN_HAVE_RDS case */
525 #endif /* HAVE_RDS_CAP */
526 default:
527 return NULL;
529 return NULL;
531 #endif
533 static struct mp3entry* get_mp3entry_from_offset(int offset, char **filename)
535 struct mp3entry* pid3 = NULL;
536 struct wps_state *state = skin_get_global_state();
537 struct cuesheet *cue = state->id3 ? state->id3->cuesheet : NULL;
538 const char *fname = NULL;
539 if (cue && cue->curr_track_idx + offset < cue->track_count)
540 pid3 = state->id3;
541 else if (offset == 0)
542 pid3 = state->id3;
543 else if (offset == 1)
544 pid3 = state->nid3;
545 else
547 static char filename_buf[MAX_PATH + 1];
548 fname = playlist_peek(offset, filename_buf, sizeof(filename_buf));
549 *filename = (char*)fname;
550 #if CONFIG_CODEC == SWCODEC
551 #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
552 static struct mp3entry tempid3;
553 if (tagcache_fill_tags(&tempid3, fname))
555 pid3 = &tempid3;
557 else
558 #endif
560 if (!audio_peek_track(&pid3, offset))
561 pid3 = NULL;
563 #endif
565 return pid3;
568 #ifdef HAVE_LCD_CHARCELLS
569 static void format_player_progress(struct gui_wps *gwps)
571 struct wps_state *state = skin_get_global_state();
572 struct screen *display = gwps->display;
573 unsigned char progress_pattern[7];
574 int pos = 0;
575 int i;
577 int elapsed, length;
578 if (LIKELY(state->id3))
580 elapsed = state->id3->elapsed;
581 length = state->id3->length;
583 else
585 elapsed = 0;
586 length = 0;
589 if (length)
590 pos = 36 * (elapsed + state->ff_rewind_count) / length;
592 for (i = 0; i < 7; i++, pos -= 5)
594 if (pos <= 0)
595 progress_pattern[i] = 0x1fu;
596 else if (pos >= 5)
597 progress_pattern[i] = 0x00u;
598 else
599 progress_pattern[i] = 0x1fu >> pos;
602 display->define_pattern(gwps->data->wps_progress_pat[0], progress_pattern);
605 static void format_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size)
607 static const unsigned char numbers[10][4] = {
608 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */
609 {0x04, 0x0c, 0x04, 0x04}, /* 1 */
610 {0x0e, 0x02, 0x04, 0x0e}, /* 2 */
611 {0x0e, 0x02, 0x06, 0x0e}, /* 3 */
612 {0x08, 0x0c, 0x0e, 0x04}, /* 4 */
613 {0x0e, 0x0c, 0x02, 0x0c}, /* 5 */
614 {0x0e, 0x08, 0x0e, 0x0e}, /* 6 */
615 {0x0e, 0x02, 0x04, 0x08}, /* 7 */
616 {0x0e, 0x0e, 0x0a, 0x0e}, /* 8 */
617 {0x0e, 0x0e, 0x02, 0x0e} /* 9 */
620 struct wps_state *state = skin_get_global_state();
621 struct screen *display = gwps->display;
622 struct wps_data *data = gwps->data;
623 unsigned char progress_pattern[7];
624 char timestr[10];
625 int time;
626 int time_idx = 0;
627 int pos = 0;
628 int pat_idx = 1;
629 int digit, i, j;
630 bool softchar;
632 int elapsed, length;
633 if (LIKELY(state->id3))
635 elapsed = state->id3->elapsed;
636 length = state->id3->length;
638 else
640 elapsed = 0;
641 length = 0;
644 if (buf_size < 34) /* worst case: 11x UTF-8 char + \0 */
645 return;
647 time = elapsed + state->ff_rewind_count;
648 if (length)
649 pos = 55 * time / length;
651 memset(timestr, 0, sizeof(timestr));
652 format_time(timestr, sizeof(timestr)-2, time);
653 timestr[strlen(timestr)] = ':'; /* always safe */
655 for (i = 0; i < 11; i++, pos -= 5)
657 softchar = false;
658 memset(progress_pattern, 0, sizeof(progress_pattern));
660 if ((digit = timestr[time_idx]))
662 softchar = true;
663 digit -= '0';
665 if (timestr[time_idx + 1] == ':') /* ones, left aligned */
667 memcpy(progress_pattern, numbers[digit], 4);
668 time_idx += 2;
670 else /* tens, shifted right */
672 for (j = 0; j < 4; j++)
673 progress_pattern[j] = numbers[digit][j] >> 1;
675 if (time_idx > 0) /* not the first group, add colon in front */
677 progress_pattern[1] |= 0x10u;
678 progress_pattern[3] |= 0x10u;
680 time_idx++;
683 if (pos >= 5)
684 progress_pattern[5] = progress_pattern[6] = 0x1fu;
687 if (pos > 0 && pos < 5)
689 softchar = true;
690 progress_pattern[5] = progress_pattern[6] = (~0x1fu >> pos) & 0x1fu;
693 if (softchar && pat_idx < 8)
695 display->define_pattern(data->wps_progress_pat[pat_idx],
696 progress_pattern);
697 buf = utf8encode(data->wps_progress_pat[pat_idx], buf);
698 pat_idx++;
700 else if (pos <= 0)
701 buf = utf8encode(' ', buf);
702 else
703 buf = utf8encode(0xe115, buf); /* 2/7 _ */
705 *buf = '\0';
708 #endif /* HAVE_LCD_CHARCELLS */
710 /* Don't inline this; it was broken out of get_token_value to reduce stack
711 * usage.
713 static const char* NOINLINE get_lif_token_value(struct gui_wps *gwps,
714 struct logical_if *lif,
715 int offset, char *buf,
716 int buf_size)
718 int a = lif->num_options;
719 int b;
720 const char* out_text = get_token_value(gwps, lif->token, offset,
721 buf, buf_size, &a);
722 if (a == -1 && lif->token->type != SKIN_TOKEN_VOLUME)
723 a = (out_text && *out_text) ? 1 : 0;
724 switch (lif->operand.type)
726 case STRING:
727 if (lif->op == IF_EQUALS)
728 return strcmp(out_text, lif->operand.data.text) == 0 ?
729 "eq" : NULL;
730 else
731 return NULL;
732 break;
733 case INTEGER:
734 case DECIMAL:
735 b = lif->operand.data.number;
736 break;
737 case CODE:
739 char temp_buf[MAX_PATH];
740 const char *outb;
741 struct wps_token *token = lif->operand.data.code->data;
742 b = lif->num_options;
743 outb = get_token_value(gwps, token, offset, temp_buf,
744 sizeof(temp_buf), &b);
745 if (b == -1 && lif->token->type != SKIN_TOKEN_VOLUME)
747 if (!out_text || !outb)
748 return (lif->op == IF_EQUALS) ? NULL : "neq";
749 bool equal = strcmp(out_text, outb) == 0;
750 if (lif->op == IF_EQUALS)
751 return equal ? "eq" : NULL;
752 else if (lif->op == IF_NOTEQUALS)
753 return !equal ? "neq" : NULL;
754 else
755 b = (outb && *outb) ? 1 : 0;
758 break;
759 case DEFAULT:
760 break;
763 switch (lif->op)
765 case IF_EQUALS:
766 return a == b ? "eq" : NULL;
767 case IF_NOTEQUALS:
768 return a != b ? "neq" : NULL;
769 case IF_LESSTHAN:
770 return a < b ? "lt" : NULL;
771 case IF_LESSTHAN_EQ:
772 return a <= b ? "lte" : NULL;
773 case IF_GREATERTHAN:
774 return a > b ? "gt" : NULL;
775 case IF_GREATERTHAN_EQ:
776 return a >= b ? "gte" : NULL;
778 return NULL;
781 /* Return the tags value as text. buf should be used as temp storage if needed.
783 intval is used with conditionals/enums: when this function is called,
784 intval should contain the number of options in the conditional/enum.
785 When this function returns, intval is -1 if the tag is non numeric or,
786 if the tag is numeric, *intval is the enum case we want to go to (between 1
787 and the original value of *intval, inclusive).
788 When not treating a conditional/enum, intval should be NULL.
790 const char *get_token_value(struct gui_wps *gwps,
791 struct wps_token *token, int offset,
792 char *buf, int buf_size,
793 int *intval)
795 if (!gwps)
796 return NULL;
798 struct wps_data *data = gwps->data;
799 struct wps_state *state = skin_get_global_state();
800 struct mp3entry *id3; /* Think very carefully about using this.
801 maybe get_id3_token() is the better place? */
802 const char *out_text = NULL;
803 char *filename = NULL;
805 if (!data || !state)
806 return NULL;
808 id3 = get_mp3entry_from_offset(token->next? 1: offset, &filename);
809 if (id3)
810 filename = id3->path;
812 #if CONFIG_RTC
813 struct tm* tm = NULL;
815 /* if the token is an RTC one, update the time
816 and do the necessary checks */
817 if (token->type >= SKIN_TOKENS_RTC_BEGIN
818 && token->type <= SKIN_TOKENS_RTC_END)
820 tm = get_time();
822 if (!valid_time(tm))
823 return NULL;
825 #endif
827 int limit = 1;
828 if (intval)
830 limit = *intval;
831 *intval = -1;
834 if (id3 && id3 == state->id3 && id3->cuesheet )
836 out_text = get_cuesheetid3_token(token, id3,
837 token->next?1:offset, buf, buf_size);
838 if (out_text)
839 return out_text;
841 out_text = get_id3_token(token, id3, filename, buf, buf_size, limit, intval);
842 if (out_text)
843 return out_text;
844 #if CONFIG_TUNER
845 out_text = get_radio_token(token, offset, buf, buf_size, limit, intval);
846 if (out_text)
847 return out_text;
848 #endif
850 switch (token->type)
852 case SKIN_TOKEN_LOGICAL_IF:
854 struct logical_if *lif = token->value.data;
855 return get_lif_token_value(gwps, lif, offset, buf, buf_size);
857 break;
859 case SKIN_TOKEN_CHARACTER:
860 if (token->value.c == '\n')
861 return NULL;
862 return &(token->value.c);
864 case SKIN_TOKEN_STRING:
865 return (char*)token->value.data;
867 case SKIN_TOKEN_TRANSLATEDSTRING:
868 return (char*)P2STR(ID2P(token->value.i));
870 case SKIN_TOKEN_PLAYLIST_ENTRIES:
871 snprintf(buf, buf_size, "%d", playlist_amount());
872 if (intval)
873 *intval = playlist_amount();
874 return buf;
875 #ifdef HAVE_LCD_BITMAP
876 case SKIN_TOKEN_LIST_TITLE_TEXT:
877 return sb_get_title(gwps->display->screen_type);
878 case SKIN_TOKEN_LIST_TITLE_ICON:
879 if (intval)
880 *intval = sb_get_icon(gwps->display->screen_type);
881 snprintf(buf, buf_size, "%d",sb_get_icon(gwps->display->screen_type));
882 return buf;
883 #endif
884 case SKIN_TOKEN_PLAYLIST_NAME:
885 return playlist_name(NULL, buf, buf_size);
887 case SKIN_TOKEN_PLAYLIST_POSITION:
888 snprintf(buf, buf_size, "%d", playlist_get_display_index()+offset);
889 if (intval)
890 *intval = playlist_get_display_index()+offset;
891 return buf;
893 case SKIN_TOKEN_PLAYLIST_SHUFFLE:
894 if ( global_settings.playlist_shuffle )
895 return "s";
896 else
897 return NULL;
898 break;
900 case SKIN_TOKEN_VOLUME:
901 snprintf(buf, buf_size, "%d", global_settings.volume);
902 if (intval)
904 int minvol = sound_min(SOUND_VOLUME);
905 if (limit == TOKEN_VALUE_ONLY)
907 *intval = global_settings.volume;
909 else if (global_settings.volume == minvol)
911 *intval = 1;
913 else if (global_settings.volume == 0)
915 *intval = limit - 1;
917 else if (global_settings.volume > 0)
919 *intval = limit;
921 else
923 *intval = (limit-3) * (global_settings.volume - minvol - 1)
924 / (-1 - minvol) + 2;
927 return buf;
928 #ifdef HAVE_ALBUMART
929 case SKIN_TOKEN_ALBUMART_FOUND:
930 if (data->albumart)
932 int handle = -1;
933 handle = playback_current_aa_hid(data->playback_aa_slot);
934 #if CONFIG_TUNER
935 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
937 struct dim dim = {data->albumart->width, data->albumart->height};
938 handle = radio_get_art_hid(&dim);
940 #endif
941 if (handle >= 0)
942 return "C";
944 return NULL;
945 #endif
947 case SKIN_TOKEN_BATTERY_PERCENT:
949 int l = battery_level();
951 if (intval)
953 if (limit == TOKEN_VALUE_ONLY)
955 *intval = l;
957 else
959 limit = MAX(limit, 3);
960 if (l > -1) {
961 /* First enum is used for "unknown level",
962 * last enum is used for 100%.
964 *intval = (limit - 2) * l / 100 + 2;
965 } else {
966 *intval = 1;
971 if (l > -1) {
972 snprintf(buf, buf_size, "%d", l);
973 return buf;
974 } else {
975 return "?";
979 case SKIN_TOKEN_BATTERY_VOLTS:
981 unsigned int v = battery_voltage();
982 snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10);
983 return buf;
986 case SKIN_TOKEN_BATTERY_TIME:
988 int t = battery_time();
989 if (t >= 0)
990 snprintf(buf, buf_size, "%dh %dm", t / 60, t % 60);
991 else
992 return "?h ?m";
993 return buf;
996 #if CONFIG_CHARGING
997 case SKIN_TOKEN_BATTERY_CHARGER_CONNECTED:
999 if(charger_input_state==CHARGER)
1000 return "p";
1001 else
1002 return NULL;
1004 #endif
1005 #if CONFIG_CHARGING >= CHARGING_MONITOR
1006 case SKIN_TOKEN_BATTERY_CHARGING:
1008 if (charge_state == CHARGING || charge_state == TOPOFF) {
1009 return "c";
1010 } else {
1011 return NULL;
1014 #endif
1015 #ifdef HAVE_USB_POWER
1016 case SKIN_TOKEN_USB_POWERED:
1017 if (usb_powered())
1018 return "u";
1019 return NULL;
1020 #endif
1021 case SKIN_TOKEN_BATTERY_SLEEPTIME:
1023 if (get_sleep_timer() == 0)
1024 return NULL;
1025 else
1027 format_time(buf, buf_size, get_sleep_timer() * 1000);
1028 return buf;
1032 case SKIN_TOKEN_PLAYBACK_STATUS:
1034 int status = current_playmode();
1035 /* music */
1036 int mode = 1; /* stop */
1037 if (status == STATUS_PLAY)
1038 mode = 2; /* play */
1039 if (state->is_fading ||
1040 (status == STATUS_PAUSE && !status_get_ffmode()))
1041 mode = 3; /* pause */
1042 else
1043 { /* ff / rwd */
1044 if (status_get_ffmode() == STATUS_FASTFORWARD)
1045 mode = 4;
1046 if (status_get_ffmode() == STATUS_FASTBACKWARD)
1047 mode = 5;
1049 #ifdef HAVE_RECORDING
1050 /* recording */
1051 if (status == STATUS_RECORD)
1052 mode = 6;
1053 else if (status == STATUS_RECORD_PAUSE)
1054 mode = 7;
1055 #endif
1056 #if CONFIG_TUNER
1057 /* radio */
1058 if (status == STATUS_RADIO)
1059 mode = 8;
1060 else if (status == STATUS_RADIO_PAUSE)
1061 mode = 9;
1062 #endif
1064 if (intval) {
1065 *intval = mode;
1068 snprintf(buf, buf_size, "%d", mode-1);
1069 return buf;
1072 case SKIN_TOKEN_REPEAT_MODE:
1073 if (intval)
1074 *intval = global_settings.repeat_mode + 1;
1075 snprintf(buf, buf_size, "%d", global_settings.repeat_mode);
1076 return buf;
1078 case SKIN_TOKEN_RTC_PRESENT:
1079 #if CONFIG_RTC
1080 return "c";
1081 #else
1082 return NULL;
1083 #endif
1085 #if CONFIG_RTC
1086 case SKIN_TOKEN_RTC_12HOUR_CFG:
1087 if (intval)
1088 *intval = global_settings.timeformat + 1;
1089 snprintf(buf, buf_size, "%d", global_settings.timeformat);
1090 return buf;
1092 case SKIN_TOKEN_RTC_DAY_OF_MONTH:
1093 /* d: day of month (01..31) */
1094 snprintf(buf, buf_size, "%02d", tm->tm_mday);
1095 if (intval)
1096 *intval = tm->tm_mday - 1;
1097 return buf;
1099 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
1100 /* e: day of month, blank padded ( 1..31) */
1101 snprintf(buf, buf_size, "%2d", tm->tm_mday);
1102 if (intval)
1103 *intval = tm->tm_mday - 1;
1104 return buf;
1106 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
1107 /* H: hour (00..23) */
1108 snprintf(buf, buf_size, "%02d", tm->tm_hour);
1109 if (intval)
1110 *intval = tm->tm_hour;
1111 return buf;
1113 case SKIN_TOKEN_RTC_HOUR_24:
1114 /* k: hour ( 0..23) */
1115 snprintf(buf, buf_size, "%2d", tm->tm_hour);
1116 if (intval)
1117 *intval = tm->tm_hour;
1118 return buf;
1120 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
1121 /* I: hour (01..12) */
1122 snprintf(buf, buf_size, "%02d",
1123 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
1124 if (intval)
1125 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
1126 return buf;
1128 case SKIN_TOKEN_RTC_HOUR_12:
1129 /* l: hour ( 1..12) */
1130 snprintf(buf, buf_size, "%2d",
1131 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
1132 if (intval)
1133 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
1134 return buf;
1136 case SKIN_TOKEN_RTC_MONTH:
1137 /* m: month (01..12) */
1138 if (intval)
1139 *intval = tm->tm_mon + 1;
1140 snprintf(buf, buf_size, "%02d", tm->tm_mon + 1);
1141 return buf;
1143 case SKIN_TOKEN_RTC_MINUTE:
1144 /* M: minute (00..59) */
1145 snprintf(buf, buf_size, "%02d", tm->tm_min);
1146 if (intval)
1147 *intval = tm->tm_min;
1148 return buf;
1150 case SKIN_TOKEN_RTC_SECOND:
1151 /* S: second (00..59) */
1152 snprintf(buf, buf_size, "%02d", tm->tm_sec);
1153 if (intval)
1154 *intval = tm->tm_sec;
1155 return buf;
1157 case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
1158 /* y: last two digits of year (00..99) */
1159 snprintf(buf, buf_size, "%02d", tm->tm_year % 100);
1160 if (intval)
1161 *intval = tm->tm_year % 100;
1162 return buf;
1164 case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
1165 /* Y: year (1970...) */
1166 snprintf(buf, buf_size, "%04d", tm->tm_year + 1900);
1167 if (intval)
1168 *intval = tm->tm_year + 1900;
1169 return buf;
1171 case SKIN_TOKEN_RTC_AM_PM_UPPER:
1172 /* p: upper case AM or PM indicator */
1173 if (intval)
1174 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
1175 return tm->tm_hour/12 == 0 ? "AM" : "PM";
1177 case SKIN_TOKEN_RTC_AM_PM_LOWER:
1178 /* P: lower case am or pm indicator */
1179 if (intval)
1180 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
1181 return tm->tm_hour/12 == 0 ? "am" : "pm";
1183 case SKIN_TOKEN_RTC_WEEKDAY_NAME:
1184 /* a: abbreviated weekday name (Sun..Sat) */
1185 return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday);
1187 case SKIN_TOKEN_RTC_MONTH_NAME:
1188 /* b: abbreviated month name (Jan..Dec) */
1189 return str(LANG_MONTH_JANUARY + tm->tm_mon);
1191 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
1192 /* u: day of week (1..7); 1 is Monday */
1193 if (intval)
1194 *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
1195 snprintf(buf, buf_size, "%1d", tm->tm_wday + 1);
1196 return buf;
1198 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
1199 /* w: day of week (0..6); 0 is Sunday */
1200 if (intval)
1201 *intval = tm->tm_wday + 1;
1202 snprintf(buf, buf_size, "%1d", tm->tm_wday);
1203 return buf;
1204 #else
1205 case SKIN_TOKEN_RTC_DAY_OF_MONTH:
1206 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
1207 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
1208 case SKIN_TOKEN_RTC_HOUR_24:
1209 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
1210 case SKIN_TOKEN_RTC_HOUR_12:
1211 case SKIN_TOKEN_RTC_MONTH:
1212 case SKIN_TOKEN_RTC_MINUTE:
1213 case SKIN_TOKEN_RTC_SECOND:
1214 case SKIN_TOKEN_RTC_AM_PM_UPPER:
1215 case SKIN_TOKEN_RTC_AM_PM_LOWER:
1216 case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
1217 return "--";
1218 case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
1219 return "----";
1220 case SKIN_TOKEN_RTC_WEEKDAY_NAME:
1221 case SKIN_TOKEN_RTC_MONTH_NAME:
1222 return "---";
1223 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
1224 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
1225 return "-";
1226 #endif
1228 #ifdef HAVE_LCD_CHARCELLS
1229 case SKIN_TOKEN_PROGRESSBAR:
1231 char *end;
1232 format_player_progress(gwps);
1233 end = utf8encode(data->wps_progress_pat[0], buf);
1234 *end = '\0';
1235 return buf;
1238 case SKIN_TOKEN_PLAYER_PROGRESSBAR:
1239 if(is_new_player())
1241 /* we need 11 characters (full line) for
1242 progress-bar */
1243 strlcpy(buf, " ", buf_size);
1244 format_player_fullbar(gwps,buf,buf_size);
1245 DEBUGF("bar='%s'\n",buf);
1247 else
1249 /* Tell the user if we have an OldPlayer */
1250 strlcpy(buf, " <Old LCD> ", buf_size);
1252 return buf;
1253 #endif
1257 #if (CONFIG_CODEC == SWCODEC)
1258 case SKIN_TOKEN_CROSSFADE:
1259 #ifdef HAVE_CROSSFADE
1260 if (intval)
1261 *intval = global_settings.crossfade + 1;
1262 snprintf(buf, buf_size, "%d", global_settings.crossfade);
1263 #else
1264 snprintf(buf, buf_size, "%d", 0);
1265 #endif
1266 return buf;
1268 case SKIN_TOKEN_REPLAYGAIN:
1270 int val;
1272 if (global_settings.replaygain_type == REPLAYGAIN_OFF)
1273 val = 1; /* off */
1274 else
1276 int type;
1277 if (LIKELY(id3))
1278 type = get_replaygain_mode(id3->track_gain_string != NULL,
1279 id3->album_gain_string != NULL);
1280 else
1281 type = -1;
1283 if (type < 0)
1284 val = 6; /* no tag */
1285 else
1286 val = type + 2;
1288 if (global_settings.replaygain_type == REPLAYGAIN_SHUFFLE)
1289 val += 2;
1292 if (intval)
1293 *intval = val;
1295 switch (val)
1297 case 1:
1298 case 6:
1299 return "+0.00 dB";
1300 break;
1301 /* due to above, coming here with !id3 shouldn't be possible */
1302 case 2:
1303 case 4:
1304 strlcpy(buf, id3->track_gain_string, buf_size);
1305 break;
1306 case 3:
1307 case 5:
1308 strlcpy(buf, id3->album_gain_string, buf_size);
1309 break;
1311 return buf;
1313 #endif /* (CONFIG_CODEC == SWCODEC) */
1315 #if (CONFIG_CODEC != MAS3507D) && defined (HAVE_PITCHSCREEN)
1316 case SKIN_TOKEN_SOUND_PITCH:
1318 int32_t pitch = sound_get_pitch();
1319 snprintf(buf, buf_size, "%ld.%ld",
1320 pitch / PITCH_SPEED_PRECISION,
1321 (pitch % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
1323 if (intval)
1324 *intval = pitch_speed_enum(limit, pitch,
1325 PITCH_SPEED_PRECISION * 100);
1326 return buf;
1328 #endif
1330 #if (CONFIG_CODEC == SWCODEC) && defined (HAVE_PITCHSCREEN)
1331 case SKIN_TOKEN_SOUND_SPEED:
1333 int32_t pitch = sound_get_pitch();
1334 int32_t speed;
1335 if (dsp_timestretch_available())
1336 speed = GET_SPEED(pitch, dsp_get_timestretch());
1337 else
1338 speed = pitch;
1339 snprintf(buf, buf_size, "%ld.%ld",
1340 speed / PITCH_SPEED_PRECISION,
1341 (speed % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
1342 if (intval)
1343 *intval = pitch_speed_enum(limit, speed,
1344 PITCH_SPEED_PRECISION * 100);
1345 return buf;
1347 #endif
1349 case SKIN_TOKEN_MAIN_HOLD:
1350 #ifdef HAS_BUTTON_HOLD
1351 if (button_hold())
1352 #else
1353 if (is_keys_locked())
1354 #endif /*hold switch or softlock*/
1355 return "h";
1356 else
1357 return NULL;
1359 #ifdef HAS_REMOTE_BUTTON_HOLD
1360 case SKIN_TOKEN_REMOTE_HOLD:
1361 if (remote_button_hold())
1362 return "r";
1363 else
1364 return NULL;
1365 #endif
1367 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
1368 case SKIN_TOKEN_VLED_HDD:
1369 if(led_read(HZ/2))
1370 return "h";
1371 else
1372 return NULL;
1373 #endif
1374 case SKIN_TOKEN_BUTTON_VOLUME:
1375 if (global_status.last_volume_change &&
1376 TIME_BEFORE(current_tick, global_status.last_volume_change +
1377 token->value.i))
1378 return "v";
1379 return NULL;
1381 case SKIN_TOKEN_LASTTOUCH:
1383 #ifdef HAVE_TOUCHSCREEN
1384 unsigned int last_touch = touchscreen_last_touch();
1385 if (last_touch != 0xffff &&
1386 TIME_BEFORE(current_tick, token->value.i + last_touch))
1387 return "t";
1388 #endif
1390 return NULL;
1391 case SKIN_TOKEN_HAVE_TOUCH:
1392 #ifdef HAVE_TOUCHSCREEN
1393 return "t";
1394 #else
1395 return NULL;
1396 #endif
1398 case SKIN_TOKEN_SETTING:
1400 const struct settings_list *s = settings+token->value.i;
1401 if (intval)
1403 /* Handle contionals */
1404 switch (s->flags&F_T_MASK)
1406 case F_T_INT:
1407 case F_T_UINT:
1408 if (s->flags&F_T_SOUND)
1410 /* %?St|name|<min|min+1|...|max-1|max> */
1411 int sound_setting = s->sound_setting->setting;
1412 /* settings with decimals can't be used in conditionals */
1413 if (sound_numdecimals(sound_setting) == 0)
1415 *intval = (*(int*)s->setting-sound_min(sound_setting))
1416 /sound_steps(sound_setting) + 1;
1418 else
1419 *intval = -1;
1421 else if (s->flags&F_RGB)
1422 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
1423 /* shouldn't overflow since colors are stored
1424 * on 16 bits ...
1425 * but this is pretty useless anyway */
1426 *intval = *(int*)s->setting + 1;
1427 else if (s->cfg_vals == NULL)
1428 /* %?St|name|<1st choice|2nd choice|...> */
1429 *intval = (*(int*)s->setting-s->int_setting->min)
1430 /s->int_setting->step + 1;
1431 else
1432 /* %?St|name|<1st choice|2nd choice|...> */
1433 /* Not sure about this one. cfg_name/vals are
1434 * indexed from 0 right? */
1435 *intval = *(int*)s->setting + 1;
1436 break;
1437 case F_T_BOOL:
1438 /* %?St|name|<if true|if false> */
1439 *intval = *(bool*)s->setting?1:2;
1440 break;
1441 case F_T_CHARPTR:
1442 case F_T_UCHARPTR:
1443 /* %?St|name|<if non empty string|if empty>
1444 * The string's emptyness discards the setting's
1445 * prefix and suffix */
1446 *intval = ((char*)s->setting)[0]?1:2;
1447 /* if there is a prefix we should ignore it here */
1448 if (s->filename_setting->prefix)
1449 return (char*)s->setting;
1450 break;
1451 default:
1452 /* This shouldn't happen ... but you never know */
1453 *intval = -1;
1454 break;
1457 /* Special handlng for filenames because we dont want to show the prefix */
1458 if ((s->flags&F_T_MASK) == F_T_UCHARPTR ||
1459 (s->flags&F_T_MASK) == F_T_UCHARPTR)
1461 if (s->filename_setting->prefix)
1462 return (char*)s->setting;
1464 cfg_to_string(token->value.i,buf,buf_size);
1465 return buf;
1467 case SKIN_TOKEN_HAVE_TUNER:
1468 #if CONFIG_TUNER
1469 if (radio_hardware_present())
1470 return "r";
1471 #endif
1472 return NULL;
1473 /* Recording tokens */
1474 case SKIN_TOKEN_HAVE_RECORDING:
1475 #ifdef HAVE_RECORDING
1476 return "r";
1477 #else
1478 return NULL;
1479 #endif
1481 #ifdef HAVE_RECORDING
1482 case SKIN_TOKEN_IS_RECORDING:
1483 if (audio_status() == AUDIO_STATUS_RECORD)
1484 return "r";
1485 return NULL;
1486 case SKIN_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */
1488 #if CONFIG_CODEC == SWCODEC
1489 unsigned long samprk;
1490 int rec_freq = global_settings.rec_frequency;
1492 #ifdef SIMULATOR
1493 samprk = 44100;
1494 #else
1495 #if defined(HAVE_SPDIF_REC)
1496 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1498 /* Use rate in use, not current measured rate if it changed */
1499 samprk = pcm_rec_sample_rate();
1500 rec_freq = 0;
1501 while (rec_freq < SAMPR_NUM_FREQ &&
1502 audio_master_sampr_list[rec_freq] != samprk)
1504 rec_freq++;
1507 else
1508 #endif
1509 samprk = rec_freq_sampr[rec_freq];
1510 #endif /* SIMULATOR */
1511 if (intval)
1513 switch (rec_freq)
1515 REC_HAVE_96_(case REC_FREQ_96:
1516 *intval = 1;
1517 break;)
1518 REC_HAVE_88_(case REC_FREQ_88:
1519 *intval = 2;
1520 break;)
1521 REC_HAVE_64_(case REC_FREQ_64:
1522 *intval = 3;
1523 break;)
1524 REC_HAVE_48_(case REC_FREQ_48:
1525 *intval = 4;
1526 break;)
1527 REC_HAVE_44_(case REC_FREQ_44:
1528 *intval = 5;
1529 break;)
1530 REC_HAVE_32_(case REC_FREQ_32:
1531 *intval = 6;
1532 break;)
1533 REC_HAVE_24_(case REC_FREQ_24:
1534 *intval = 7;
1535 break;)
1536 REC_HAVE_22_(case REC_FREQ_22:
1537 *intval = 8;
1538 break;)
1539 REC_HAVE_16_(case REC_FREQ_16:
1540 *intval = 9;
1541 break;)
1542 REC_HAVE_12_(case REC_FREQ_12:
1543 *intval = 10;
1544 break;)
1545 REC_HAVE_11_(case REC_FREQ_11:
1546 *intval = 11;
1547 break;)
1548 REC_HAVE_8_(case REC_FREQ_8:
1549 *intval = 12;
1550 break;)
1553 snprintf(buf, buf_size, "%lu.%1lu", samprk/1000,samprk%1000);
1554 #else /* HWCODEC */
1556 static const char * const freq_strings[] =
1557 {"--", "44", "48", "32", "22", "24", "16"};
1558 int freq = 1 + global_settings.rec_frequency;
1559 #ifdef HAVE_SPDIF_REC
1560 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1562 /* Can't measure S/PDIF sample rate on Archos/Sim yet */
1563 freq = 0;
1565 #endif /* HAVE_SPDIF_IN */
1566 if (intval)
1567 *intval = freq+1; /* so the token gets a value 1<=x<=7 */
1568 snprintf(buf, buf_size, "%s\n",
1569 freq_strings[global_settings.rec_frequency]);
1570 #endif
1571 return buf;
1573 #if CONFIG_CODEC == SWCODEC
1574 case SKIN_TOKEN_REC_ENCODER:
1576 int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */
1577 if (intval)
1578 *intval = rec_format;
1579 switch (rec_format)
1581 case REC_FORMAT_PCM_WAV:
1582 return "wav";
1583 case REC_FORMAT_AIFF:
1584 return "aiff";
1585 case REC_FORMAT_WAVPACK:
1586 return "wv";
1587 case REC_FORMAT_MPA_L3:
1588 return "MP3";
1589 default:
1590 return NULL;
1592 break;
1594 #endif
1595 case SKIN_TOKEN_REC_BITRATE:
1596 #if CONFIG_CODEC == SWCODEC
1597 if (global_settings.rec_format == REC_FORMAT_MPA_L3)
1599 if (intval)
1601 #if 0 /* FIXME: I dont know if this is needed? */
1602 switch (1<<global_settings.mp3_enc_config.bitrate)
1604 case MP3_BITR_CAP_8:
1605 *intval = 1;
1606 break;
1607 case MP3_BITR_CAP_16:
1608 *intval = 2;
1609 break;
1610 case MP3_BITR_CAP_24:
1611 *intval = 3;
1612 break;
1613 case MP3_BITR_CAP_32:
1614 *intval = 4;
1615 break;
1616 case MP3_BITR_CAP_40:
1617 *intval = 5;
1618 break;
1619 case MP3_BITR_CAP_48:
1620 *intval = 6;
1621 break;
1622 case MP3_BITR_CAP_56:
1623 *intval = 7;
1624 break;
1625 case MP3_BITR_CAP_64:
1626 *intval = 8;
1627 break;
1628 case MP3_BITR_CAP_80:
1629 *intval = 9;
1630 break;
1631 case MP3_BITR_CAP_96:
1632 *intval = 10;
1633 break;
1634 case MP3_BITR_CAP_112:
1635 *intval = 11;
1636 break;
1637 case MP3_BITR_CAP_128:
1638 *intval = 12;
1639 break;
1640 case MP3_BITR_CAP_144:
1641 *intval = 13;
1642 break;
1643 case MP3_BITR_CAP_160:
1644 *intval = 14;
1645 break;
1646 case MP3_BITR_CAP_192:
1647 *intval = 15;
1648 break;
1650 #endif
1651 *intval = global_settings.mp3_enc_config.bitrate+1;
1653 snprintf(buf, buf_size, "%lu", global_settings.mp3_enc_config.bitrate+1);
1654 return buf;
1656 else
1657 return NULL; /* Fixme later */
1658 #else /* CONFIG_CODEC == HWCODEC */
1659 if (intval)
1660 *intval = global_settings.rec_quality+1;
1661 snprintf(buf, buf_size, "%d", global_settings.rec_quality);
1662 return buf;
1663 #endif
1664 case SKIN_TOKEN_REC_MONO:
1665 if (!global_settings.rec_channels)
1666 return "m";
1667 return NULL;
1669 case SKIN_TOKEN_REC_SECONDS:
1671 int time = (audio_recorded_time() / HZ) % 60;
1672 if (intval)
1673 *intval = time;
1674 snprintf(buf, buf_size, "%02d", time);
1675 return buf;
1677 case SKIN_TOKEN_REC_MINUTES:
1679 int time = (audio_recorded_time() / HZ) / 60;
1680 if (intval)
1681 *intval = time;
1682 snprintf(buf, buf_size, "%02d", time);
1683 return buf;
1685 case SKIN_TOKEN_REC_HOURS:
1687 int time = (audio_recorded_time() / HZ) / 3600;
1688 if (intval)
1689 *intval = time;
1690 snprintf(buf, buf_size, "%02d", time);
1691 return buf;
1694 #endif /* HAVE_RECORDING */
1696 case SKIN_TOKEN_CURRENT_SCREEN:
1698 int curr_screen = current_screen();
1700 #ifdef HAVE_RECORDING
1701 /* override current_screen() for recording screen since it may
1702 * be entered from the radio screen */
1703 if (in_recording_screen())
1704 curr_screen = GO_TO_RECSCREEN;
1705 #endif
1707 switch (curr_screen)
1709 case GO_TO_WPS:
1710 curr_screen = 2;
1711 break;
1712 #ifdef HAVE_RECORDING
1713 case GO_TO_RECSCREEN:
1714 curr_screen = 3;
1715 break;
1716 #endif
1717 #if CONFIG_TUNER
1718 case GO_TO_FM:
1719 curr_screen = 4;
1720 break;
1721 #endif
1722 case GO_TO_PLAYLIST_VIEWER:
1723 curr_screen = 5;
1724 break;
1725 default: /* lists */
1726 curr_screen = 1;
1727 break;
1729 if (intval)
1731 *intval = curr_screen;
1733 snprintf(buf, buf_size, "%d", curr_screen);
1734 return buf;
1737 case SKIN_TOKEN_LANG_IS_RTL:
1738 return lang_is_rtl() ? "r" : NULL;
1740 default:
1741 return NULL;