summaryrefslogtreecommitdiff
path: root/apps/screens.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/screens.c')
-rw-r--r--apps/screens.c181
1 files changed, 177 insertions, 4 deletions
diff --git a/apps/screens.c b/apps/screens.c
index 5fa92f5fbd..d341fa8eef 100644
--- a/apps/screens.c
+++ b/apps/screens.c
@@ -22,6 +22,7 @@
22#include <stdbool.h> 22#include <stdbool.h>
23#include <string.h> 23#include <string.h>
24#include <stdio.h> 24#include <stdio.h>
25#include <stdlib.h>
25#include "backlight.h" 26#include "backlight.h"
26#include "action.h" 27#include "action.h"
27#include "lcd.h" 28#include "lcd.h"
@@ -81,6 +82,7 @@ int mmc_remove_request(void)
81 } 82 }
82} 83}
83#endif 84#endif
85#include "ctype.h"
84 86
85/* the charging screen is only used for archos targets */ 87/* the charging screen is only used for archos targets */
86#if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING) && defined(CPU_SH) 88#if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING) && defined(CPU_SH)
@@ -643,14 +645,102 @@ struct id3view_info {
643 int info_id[ARRAYLEN(id3_headers)]; 645 int info_id[ARRAYLEN(id3_headers)];
644}; 646};
645 647
646static const char* id3_get_info(int selected_item, void* data, 648/* Spell out a buffer, but when successive digits are encountered, say
647 char *buffer, size_t buffer_len) 649 the whole number. Useful for some ID3 tags that usually contain a
650 number but are in fact free-form. */
651static void say_number_and_spell(char *buf, bool year_style)
652{
653 char *ptr = buf;
654 while(*ptr) {
655 if(isdigit(*ptr)) {
656 /* parse the number */
657 int n = atoi(ptr);
658 /* skip over digits to rest of string */
659 while(isdigit(*++ptr));
660 /* say the number */
661 if(year_style)
662 talk_value(n, UNIT_DATEYEAR, true);
663 else talk_number(n, true);
664 }else{
665 /* Spell a sequence of non-digits */
666 char tmp, *start = ptr;
667 while(*++ptr && !isdigit(*ptr));
668 /* temporarily truncate the string here */
669 tmp = *ptr;
670 *ptr = '\0';
671 talk_spell(start, true);
672 *ptr = tmp; /* restore string */
673 }
674 }
675}
676
677/* Say a replaygain ID3 value from its text form */
678static void say_gain(char *buf)
679{
680 /* Expected form is "-5.74 dB". We'll try to parse out the number
681 until the dot, say it (forcing the + sign), then say dot and
682 spell the following numbers, and then say the decibel unit. */
683 char *ptr = buf;
684 if(*ptr == '-' || *ptr == '+')
685 /* skip sign */
686 ++ptr;
687 /* See if we can parse out a number. */
688 if(isdigit(*ptr)) {
689 char tmp;
690 /* skip successive digits */
691 while(isdigit(*++ptr));
692 /* temporarily truncate the string here */
693 tmp = *ptr;
694 *ptr = '\0';
695 /* parse out the number we just skipped */
696 talk_value(atoi(buf), UNIT_SIGNED, true); /* say the number with sign */
697 *ptr = tmp; /* restore the string */
698 if(*ptr == '.') {
699 /* found the dot, get fractional part */
700 buf = ptr;
701 while (isdigit(*++ptr));
702 while (*--ptr == '0');
703 if (ptr > buf) {
704 tmp = *++ptr;
705 *ptr = '\0';
706 talk_id(LANG_POINT, true);
707 while (*++buf == '0')
708 talk_id(VOICE_ZERO, true);
709 talk_number(atoi(buf), true);
710 *ptr = tmp;
711 }
712 ptr = buf;
713 while (isdigit(*++ptr));
714 }
715 buf = ptr;
716 if(strlen(buf) >2 && !strcmp(buf+strlen(buf)-2, "dB")) {
717 /* String does end with "dB" */
718 /* point to that "dB" */
719 ptr = buf+strlen(buf)-2;
720 /* backup any spaces */
721 while (ptr >buf && ptr[-1] == ' ')
722 --ptr;
723 if (ptr > buf)
724 talk_spell(buf, true);
725 else talk_id(VOICE_DB, true); /* say the dB unit */
726 }else /* doesn't end with dB, just spell everything after the
727 number of dot. */
728 talk_spell(buf, true);
729 }else /* we didn't find a number, just spell everything */
730 talk_spell(buf, true);
731}
732
733static const char * id3_get_or_speak_info(int selected_item, void* data,
734 char *buffer, size_t buffer_len,
735 bool say_it)
648{ 736{
649 struct id3view_info *info = (struct id3view_info*)data; 737 struct id3view_info *info = (struct id3view_info*)data;
650 struct mp3entry* id3 =info->id3; 738 struct mp3entry* id3 =info->id3;
651 int info_no=selected_item/2; 739 int info_no=selected_item/2;
652 if(!(selected_item%2)) 740 if(!(selected_item%2))
653 {/* header */ 741 {/* header */
742 if(say_it)
743 talk_id(id3_headers[info->info_id[info_no]], false);
654 snprintf(buffer, buffer_len, 744 snprintf(buffer, buffer_len,
655 "[%s]", str(id3_headers[info->info_id[info_no]])); 745 "[%s]", str(id3_headers[info->info_id[info_no]]));
656 return buffer; 746 return buffer;
@@ -663,35 +753,57 @@ static const char* id3_get_info(int selected_item, void* data,
663 { 753 {
664 case LANG_ID3_TITLE: 754 case LANG_ID3_TITLE:
665 val=id3->title; 755 val=id3->title;
756 if(say_it && val)
757 talk_spell(val, true);
666 break; 758 break;
667 case LANG_ID3_ARTIST: 759 case LANG_ID3_ARTIST:
668 val=id3->artist; 760 val=id3->artist;
761 if(say_it && val)
762 talk_spell(val, true);
669 break; 763 break;
670 case LANG_ID3_ALBUM: 764 case LANG_ID3_ALBUM:
671 val=id3->album; 765 val=id3->album;
766 if(say_it && val)
767 talk_spell(val, true);
672 break; 768 break;
673 case LANG_ID3_ALBUMARTIST: 769 case LANG_ID3_ALBUMARTIST:
674 val=id3->albumartist; 770 val=id3->albumartist;
771 if(say_it && val)
772 talk_spell(val, true);
675 break; 773 break;
676 case LANG_ID3_GROUPING: 774 case LANG_ID3_GROUPING:
677 val=id3->grouping; 775 val=id3->grouping;
776 if(say_it && val)
777 talk_spell(val, true);
678 break; 778 break;
679 case LANG_ID3_DISCNUM: 779 case LANG_ID3_DISCNUM:
680 if (id3->disc_string) 780 if (id3->disc_string)
781 {
681 val = id3->disc_string; 782 val = id3->disc_string;
783 if(say_it)
784 say_number_and_spell(val, true);
785 }
682 else if (id3->discnum) 786 else if (id3->discnum)
683 { 787 {
684 snprintf(buffer, buffer_len, "%d", id3->discnum); 788 snprintf(buffer, buffer_len, "%d", id3->discnum);
685 val = buffer; 789 val = buffer;
790 if(say_it)
791 talk_number(id3->discnum, true);
686 } 792 }
687 break; 793 break;
688 case LANG_ID3_TRACKNUM: 794 case LANG_ID3_TRACKNUM:
689 if (id3->track_string) 795 if (id3->track_string)
796 {
690 val = id3->track_string; 797 val = id3->track_string;
798 if(say_it)
799 say_number_and_spell(val, true);
800 }
691 else if (id3->tracknum) 801 else if (id3->tracknum)
692 { 802 {
693 snprintf(buffer, buffer_len, "%d", id3->tracknum); 803 snprintf(buffer, buffer_len, "%d", id3->tracknum);
694 val = buffer; 804 val = buffer;
805 if(say_it)
806 talk_number(id3->tracknum, true);
695 } 807 }
696 break; 808 break;
697 case LANG_ID3_COMMENT: 809 case LANG_ID3_COMMENT:
@@ -699,62 +811,119 @@ static const char* id3_get_info(int selected_item, void* data,
699 return NULL; 811 return NULL;
700 snprintf(buffer, buffer_len, "%s", id3->comment); 812 snprintf(buffer, buffer_len, "%s", id3->comment);
701 val=buffer; 813 val=buffer;
814 if(say_it && val)
815 talk_spell(val, true);
702 break; 816 break;
703 case LANG_ID3_GENRE: 817 case LANG_ID3_GENRE:
704 val = id3->genre_string; 818 val = id3->genre_string;
819 if(say_it && val)
820 talk_spell(val, true);
705 break; 821 break;
706 case LANG_ID3_YEAR: 822 case LANG_ID3_YEAR:
707 if (id3->year_string) 823 if (id3->year_string)
824 {
708 val = id3->year_string; 825 val = id3->year_string;
826 if(say_it && val)
827 say_number_and_spell(val, true);
828 }
709 else if (id3->year) 829 else if (id3->year)
710 { 830 {
711 snprintf(buffer, buffer_len, "%d", id3->year); 831 snprintf(buffer, buffer_len, "%d", id3->year);
712 val = buffer; 832 val = buffer;
833 if(say_it)
834 talk_value(id3->year, UNIT_DATEYEAR, true);
713 } 835 }
714 break; 836 break;
715 case LANG_ID3_LENGTH: 837 case LANG_ID3_LENGTH:
716 format_time(buffer, buffer_len, id3->length); 838 format_time(buffer, buffer_len, id3->length);
717 val=buffer; 839 val=buffer;
840 if(say_it)
841 talk_value(id3->length /1000, UNIT_TIME, true);
718 break; 842 break;
719 case LANG_ID3_PLAYLIST: 843 case LANG_ID3_PLAYLIST:
720 snprintf(buffer, buffer_len, "%d/%d", 844 snprintf(buffer, buffer_len, "%d/%d",
721 playlist_get_display_index(), playlist_amount()); 845 playlist_get_display_index(), playlist_amount());
722 val=buffer; 846 val=buffer;
847 if(say_it)
848 {
849 talk_number(playlist_get_display_index(), true);
850 talk_id(VOICE_OF, true);
851 talk_number(playlist_amount(), true);
852 }
723 break; 853 break;
724 case LANG_ID3_BITRATE: 854 case LANG_ID3_BITRATE:
725 snprintf(buffer, buffer_len, "%d kbps%s", id3->bitrate, 855 snprintf(buffer, buffer_len, "%d kbps%s", id3->bitrate,
726 id3->vbr ? str(LANG_ID3_VBR) : (const unsigned char*) ""); 856 id3->vbr ? str(LANG_ID3_VBR) : (const unsigned char*) "");
727 val=buffer; 857 val=buffer;
858 if(say_it)
859 {
860 talk_value(id3->bitrate, UNIT_KBIT, true);
861 if(id3->vbr)
862 talk_id(LANG_ID3_VBR, true);
863 }
728 break; 864 break;
729 case LANG_ID3_FREQUENCY: 865 case LANG_ID3_FREQUENCY:
730 snprintf(buffer, buffer_len, "%ld Hz", id3->frequency); 866 snprintf(buffer, buffer_len, "%ld Hz", id3->frequency);
731 val=buffer; 867 val=buffer;
868 if(say_it)
869 talk_value(id3->frequency, UNIT_HERTZ, true);
732 break; 870 break;
733#if CONFIG_CODEC == SWCODEC 871#if CONFIG_CODEC == SWCODEC
734 case LANG_ID3_TRACK_GAIN: 872 case LANG_ID3_TRACK_GAIN:
735 replaygain_itoa(buffer, buffer_len, id3->track_level); 873 replaygain_itoa(buffer, buffer_len, id3->track_level);
736 val=(id3->track_level) ? buffer : NULL; /* only show level!=0 */ 874 val=(id3->track_level) ? buffer : NULL; /* only show level!=0 */
875 if(say_it && val)
876 say_gain(val);
737 break; 877 break;
738 case LANG_ID3_ALBUM_GAIN: 878 case LANG_ID3_ALBUM_GAIN:
739 replaygain_itoa(buffer, buffer_len, id3->album_level); 879 replaygain_itoa(buffer, buffer_len, id3->album_level);
740 val=(id3->album_level) ? buffer : NULL; /* only show level!=0 */ 880 val=(id3->album_level) ? buffer : NULL; /* only show level!=0 */
881 if(say_it && val)
882 say_gain(val);
741 break; 883 break;
742#endif 884#endif
743 case LANG_ID3_PATH: 885 case LANG_ID3_PATH:
744 val=id3->path; 886 val=id3->path;
887 if(say_it && val)
888 talk_fullpath(val, true);
745 break; 889 break;
746 case LANG_ID3_COMPOSER: 890 case LANG_ID3_COMPOSER:
747 val=id3->composer; 891 val=id3->composer;
892 if(say_it && val)
893 talk_spell(val, true);
748 break; 894 break;
749 case LANG_FILESIZE: /* not LANG_ID3_FILESIZE because the string is shared */ 895 case LANG_FILESIZE: /* not LANG_ID3_FILESIZE because the string is shared */
750 output_dyn_value(buffer, buffer_len, id3->filesize, byte_units, 4, true); 896 output_dyn_value(buffer, buffer_len, id3->filesize, byte_units, 4, true);
751 val=buffer; 897 val=buffer;
898 if(say_it && val)
899 output_dyn_value(NULL, 0, id3->filesize, byte_units, true);
752 break; 900 break;
753 } 901 }
902 if((!val || !*val) && say_it)
903 talk_id(LANG_ID3_NO_INFO, true);
754 return val && *val ? val : NULL; 904 return val && *val ? val : NULL;
755 } 905 }
756} 906}
757 907
908/* gui_synclist callback */
909static const char* id3_get_info(int selected_item, void* data,
910 char *buffer, size_t buffer_len)
911{
912 return id3_get_or_speak_info(selected_item, data, buffer,
913 buffer_len, false);
914}
915
916static int id3_speak_item(int selected_item, void* data)
917{
918 char buffer[MAX_PATH];
919 selected_item &= ~1; /* Make sure it's even, to indicate the header */
920 /* say field name */
921 id3_get_or_speak_info(selected_item, data, buffer, MAX_PATH, true);
922 /* and field value */
923 id3_get_or_speak_info(selected_item+1, data, buffer, MAX_PATH, true);
924 return 0;
925}
926
758bool browse_id3(void) 927bool browse_id3(void)
759{ 928{
760 struct gui_synclist id3_lists; 929 struct gui_synclist id3_lists;
@@ -775,11 +944,15 @@ bool browse_id3(void)
775 } 944 }
776 945
777 gui_synclist_init(&id3_lists, &id3_get_info, &info, true, 2, NULL); 946 gui_synclist_init(&id3_lists, &id3_get_info, &info, true, 2, NULL);
947 if(global_settings.talk_menu)
948 gui_synclist_set_voice_callback(&id3_lists, id3_speak_item);
778 gui_synclist_set_nb_items(&id3_lists, info.count*2); 949 gui_synclist_set_nb_items(&id3_lists, info.count*2);
779 gui_synclist_draw(&id3_lists); 950 gui_synclist_draw(&id3_lists);
951 gui_synclist_speak_item(&id3_lists);
780 while (true) { 952 while (true) {
781 key = get_action(CONTEXT_LIST,HZ/2); 953 if(!list_do_action(CONTEXT_LIST,HZ/2,
782 if(!gui_synclist_do_button(&id3_lists, &key,LIST_WRAP_UNLESS_HELD)) 954 &id3_lists, &key,LIST_WRAP_UNLESS_HELD)
955 && key!=ACTION_NONE && key!=ACTION_UNKNOWN)
783 { 956 {
784 if (key == ACTION_STD_OK || key == ACTION_STD_CANCEL) 957 if (key == ACTION_STD_OK || key == ACTION_STD_CANCEL)
785 { 958 {