Index: rockbox-devel/apps/lang/english.lang
===================================================================
--- rockbox-devel.orig/apps/lang/english.lang
+++ rockbox-devel/apps/lang/english.lang
@@ -10546,3 +10546,689 @@
*: "Blank"
+
+ id: VOICE_CHAR_APOSTROPHE
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "apostrophe"
+
+
+
+ id: VOICE_CHAR_COMMA
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "comma"
+
+
+
+ id: VOICE_CHAR_COLON
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "colon"
+
+
+
+ id: VOICE_CHAR_SEMICOLON
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "semicolon"
+
+
+
+ id: VOICE_CHAR_LESS_THAN
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "less than"
+
+
+
+ id: VOICE_CHAR_GREATER_THAN
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "greater than"
+
+
+
+ id: VOICE_CHAR_BACK_QUOTE
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "back quote"
+
+
+
+ id: VOICE_CHAR_TILDA
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "tilda"
+
+
+
+ id: VOICE_CHAR_LEFT
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "left"
+
+
+
+ id: VOICE_CHAR_RIGHT
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "right"
+
+
+
+ id: VOICE_CHAR_BRACKET
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "bracket"
+
+
+
+ id: VOICE_CHAR_BRACE
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "brace"
+
+
+
+ id: VOICE_CHAR_EQUAL
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "equal"
+
+
+
+ id: VOICE_CHAR_UNDERLINE
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "underline"
+
+
+
+ id: VOICE_CHAR_PARENTHESIS
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "parenthesis"
+
+
+
+ id: VOICE_CHAR_ASTERISK
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "asterisk"
+
+
+
+ id: VOICE_CHAR_AND
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "and"
+
+
+
+ id: VOICE_CHAR_QUESTION_MARK
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "question mark"
+
+
+
+ id: VOICE_CHAR_PERCENT
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "percent"
+
+
+
+ id: VOICE_CHAR_DOLLAR
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "dollar"
+
+
+
+ id: VOICE_CHAR_QUOTE
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "quote"
+
+
+
+ id: VOICE_CHAR_EXCLAMATION_POINT
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "exclamation point"
+
+
+
+ id: VOICE_CHAR_BAR
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "bar"
+
+
+
+ id: VOICE_CHAR_NUMBER
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "number"
+
+
+
+ id: VOICE_CHAR_BACKSLASH
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "backslash"
+
+
+
+ id: VOICE_CHAR_PLUS_OR_MINUS
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "plus or minus"
+
+
+
+ id: VOICE_CHAR_AT_SIGN
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "att sign"
+
+
+
+ id: VOICE_CHAR_CARET
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "caret"
+
+
+
+ id: VOICE_CHAR_POUNDS
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "pounds"
+
+
+
+ id: VOICE_CHAR_CENTS
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "cents"
+
+
+
+ id: VOICE_CHAR_SUPERSCRIPT_2
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "superscript 2"
+
+
+
+ id: VOICE_CHAR_SUPERSCRIPT_3
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "superscript 3"
+
+
+
+ id: VOICE_CHAR_ONE_FOURTH
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "one fourth"
+
+
+
+ id: VOICE_CHAR_ONE_HALF
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "one half"
+
+
+
+ id: VOICE_CHAR_THREE_FOURTHS
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "three fourths"
+
+
+
+ id: VOICE_CHAR_COPYRIGHT
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "copyright"
+
+
+
+ id: VOICE_CHAR_REGISTERED
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "registered"
+
+
+
+ id: VOICE_CHAR_DEGREES
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "degrees"
+
+
+
+ id: VOICE_CHAR_DOUBLE_ANGLE_BRACKET
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "double angle bracket"
+
+
+
+ id: VOICE_CHAR_INVERTED
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "inverted"
+
+
+
+ id: VOICE_CHAR_TIMES
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "times"
+
+
+
+ id: VOICE_CHAR_DIVIDED_BY
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "divided by"
+
+
+
+ id: VOICE_CHAR_ACUTE
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "acute"
+
+
+
+ id: VOICE_CHAR_GRAVE
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "grave"
+
+
+
+ id: VOICE_CHAR_CIRCUMFLEX
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "circumflex"
+
+
+
+ id: VOICE_CHAR_UMLAUT
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "umlaut"
+
+
+
+ id: VOICE_CHAR_CEDILLA
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "cedilla"
+
+
+
+ id: VOICE_CHAR_CAP
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "cap"
+
+
+
+ id: VOICE_CHAR_UNKNOWN
+ desc: for spelling
+ user:
+
+ *: ""
+
+
+ *: ""
+
+
+ *: "unknown char"
+
+
Index: rockbox-devel/apps/talk.c
===================================================================
--- rockbox-devel.orig/apps/talk.c
+++ rockbox-devel/apps/talk.c
@@ -41,6 +41,7 @@
#include "debug.h"
#include "kernel.h"
#include "pcmbuf.h"
+#include "rbunicode.h"
/* Memory layout varies between targets because the
@@ -1022,10 +1023,116 @@ int talk_value(long n, int unit, bool en
return 0;
}
+/* Spelling table, indexed by char number, gives id to speak. Hack:
+ optinal second ID for each entry placed in higher bits, mostly used
+ for accents. Also a one bit flag indicates capital letters. */
+static unsigned long spell_table[256] = {
+#define DOUBLE_SHIFT 14
+#define DOUBLE_MASK ((1< */,
+ [63] = S(VOICE_CHAR_QUESTION_MARK) /* ? */,
+ [64] = S(VOICE_CHAR_AT_SIGN) /* @ */,
+ [91] = D(VOICE_CHAR_LEFT, VOICE_CHAR_BRACKET) /* [ */,
+ [92] = S(VOICE_CHAR_BACKSLASH) /* \ */,
+ [93] = D(VOICE_CHAR_RIGHT, VOICE_CHAR_BRACKET) /* ] */,
+ [94] = S(VOICE_CHAR_CARET) /* ^ */,
+ [95] = S(VOICE_CHAR_UNDERLINE) /* _ */,
+ [96] = S(VOICE_CHAR_BACK_QUOTE) /* ` */,
+ [123] = D(VOICE_CHAR_LEFT, VOICE_CHAR_BRACE) /* { */,
+ [124] = S(VOICE_CHAR_BAR) /* | */,
+ [125] = D(VOICE_CHAR_RIGHT, VOICE_CHAR_BRACE) /* } */,
+ [126] = S(VOICE_CHAR_TILDA) /* ~ */,
+ [162] = S(VOICE_CHAR_CENTS) /* ¢ */,
+ [163] = S(VOICE_CHAR_POUNDS) /* £ */,
+ [169] = S(VOICE_CHAR_COPYRIGHT) /* © */,
+ [171] = D(VOICE_CHAR_LEFT, VOICE_CHAR_DOUBLE_ANGLE_BRACKET) /* « */,
+ [174] = S(VOICE_CHAR_REGISTERED) /* ® */,
+ [176] = S(VOICE_CHAR_DEGREES) /* ° */,
+ [177] = S(VOICE_CHAR_PLUS_OR_MINUS) /* ± */,
+ [178] = S(VOICE_CHAR_SUPERSCRIPT_2) /* ² */,
+ [179] = S(VOICE_CHAR_SUPERSCRIPT_3) /* ³ */,
+ [180] = S(VOICE_CHAR_ACUTE) /* ´ */,
+ [184] = S(VOICE_CHAR_CEDILLA) /* ¸ */,
+ [186] = S(VOICE_CHAR_DEGREES) /* º */,
+ [187] = D(VOICE_CHAR_RIGHT, VOICE_CHAR_DOUBLE_ANGLE_BRACKET) /* » */,
+ [188] = S(VOICE_CHAR_ONE_FOURTH) /* ¼ */,
+ [189] = S(VOICE_CHAR_ONE_HALF) /* ½ */,
+ [190] = S(VOICE_CHAR_THREE_FOURTHS) /* ¾ */,
+ [191] = D(VOICE_CHAR_INVERTED, VOICE_CHAR_QUESTION_MARK) /* ¿ */,
+ [192] = CAP(D(VOICE_CHAR_A, VOICE_CHAR_GRAVE)) /* À */,
+ [194] = CAP(D(VOICE_CHAR_A, VOICE_CHAR_CIRCUMFLEX)) /* Â */,
+ [196] = CAP(D(VOICE_CHAR_A, VOICE_CHAR_UMLAUT)) /* Ä */,
+ [199] = CAP(D(VOICE_CHAR_C, VOICE_CHAR_CEDILLA)) /* Ç */,
+ [200] = CAP(D(VOICE_CHAR_E, VOICE_CHAR_GRAVE)) /* È */,
+ [201] = CAP(D(VOICE_CHAR_E, VOICE_CHAR_ACUTE)) /* É */,
+ [202] = CAP(D(VOICE_CHAR_E, VOICE_CHAR_CIRCUMFLEX)) /* Ê */,
+ [203] = CAP(D(VOICE_CHAR_E, VOICE_CHAR_UMLAUT)) /* Ë */,
+ [204] = CAP(D(VOICE_CHAR_I, VOICE_CHAR_GRAVE)) /* Ì */,
+ [205] = CAP(D(VOICE_CHAR_I, VOICE_CHAR_ACUTE)) /* Í */,
+ [206] = CAP(D(VOICE_CHAR_I, VOICE_CHAR_CIRCUMFLEX)) /* Î */,
+ [207] = CAP(D(VOICE_CHAR_I, VOICE_CHAR_UMLAUT)) /* Ï */,
+ [210] = CAP(D(VOICE_CHAR_O, VOICE_CHAR_GRAVE)) /* Ò */,
+ [211] = CAP(D(VOICE_CHAR_O, VOICE_CHAR_ACUTE)) /* Ó */,
+ [212] = CAP(D(VOICE_CHAR_O, VOICE_CHAR_CIRCUMFLEX)) /* Ô */,
+ [214] = CAP(D(VOICE_CHAR_O, VOICE_CHAR_UMLAUT)) /* Ö */,
+ [215] = S(VOICE_CHAR_TIMES) /* × */,
+ [217] = CAP(D(VOICE_CHAR_U, VOICE_CHAR_GRAVE)) /* Ù */,
+ [218] = CAP(D(VOICE_CHAR_U, VOICE_CHAR_ACUTE)) /* Ú */,
+ [219] = CAP(D(VOICE_CHAR_U, VOICE_CHAR_CIRCUMFLEX)) /* Û */,
+ [220] = CAP(D(VOICE_CHAR_U, VOICE_CHAR_UMLAUT)) /* Ü */,
+ [224] = D(VOICE_CHAR_A, VOICE_CHAR_GRAVE) /* à */,
+ [225] = D(VOICE_CHAR_A, VOICE_CHAR_ACUTE) /* á */,
+ [226] = D(VOICE_CHAR_A, VOICE_CHAR_CIRCUMFLEX) /* â */,
+ [228] = D(VOICE_CHAR_A, VOICE_CHAR_UMLAUT) /* ä */,
+ [231] = D(VOICE_CHAR_C, VOICE_CHAR_CEDILLA) /* ç */,
+ [232] = D(VOICE_CHAR_E, VOICE_CHAR_GRAVE) /* è */,
+ [233] = D(VOICE_CHAR_E, VOICE_CHAR_ACUTE) /* é */,
+ [234] = D(VOICE_CHAR_E, VOICE_CHAR_CIRCUMFLEX) /* ê */,
+ [235] = D(VOICE_CHAR_E, VOICE_CHAR_UMLAUT) /* ë */,
+ [236] = D(VOICE_CHAR_I, VOICE_CHAR_GRAVE) /* ì */,
+ [237] = D(VOICE_CHAR_I, VOICE_CHAR_ACUTE) /* í */,
+ [238] = D(VOICE_CHAR_I, VOICE_CHAR_CIRCUMFLEX) /* î */,
+ [239] = D(VOICE_CHAR_I, VOICE_CHAR_UMLAUT) /* ï */,
+ [242] = D(VOICE_CHAR_O, VOICE_CHAR_GRAVE) /* ò */,
+ [243] = D(VOICE_CHAR_O, VOICE_CHAR_ACUTE) /* ó */,
+ [244] = D(VOICE_CHAR_O, VOICE_CHAR_CIRCUMFLEX) /* ô */,
+ [246] = D(VOICE_CHAR_O, VOICE_CHAR_UMLAUT) /* ö */,
+ [247] = S(VOICE_CHAR_DIVIDED_BY) /* ÷ */,
+ [249] = D(VOICE_CHAR_U, VOICE_CHAR_GRAVE) /* ù */,
+ [250] = D(VOICE_CHAR_U, VOICE_CHAR_ACUTE) /* ú */,
+ [251] = D(VOICE_CHAR_U, VOICE_CHAR_CIRCUMFLEX) /* û */,
+ [252] = D(VOICE_CHAR_U, VOICE_CHAR_UMLAUT) /* ü */,
+};
+
/* spell a string */
int talk_spell(const char* spell, bool enqueue)
{
- char c; /* currently processed char */
+ unsigned short c; /* currently processed char */
#if CONFIG_CODEC != SWCODEC
if (audio_status()) /* busy, buffer in use */
@@ -1035,25 +1142,58 @@ int talk_spell(const char* spell, bool e
if (!enqueue)
shutup(); /* cut off all the pending stuff */
- while ((c = *spell++) != '\0')
+ while (*spell)
{
- /* if this grows into too many cases, I should use a table */
- if (c >= 'A' && c <= 'Z')
- talk_id(VOICE_CHAR_A + c - 'A', true);
- else if (c >= 'a' && c <= 'z')
- talk_id(VOICE_CHAR_A + c - 'a', true);
- else if (c >= '0' && c <= '9')
- talk_id(VOICE_ZERO + c - '0', true);
- else if (c == '-')
- talk_id(VOICE_MINUS, true);
- else if (c == '+')
- talk_id(VOICE_PLUS, true);
- else if (c == '.')
- talk_id(VOICE_DOT, true);
- else if (c == ' ')
- talk_id(VOICE_PAUSE, true);
- else if (c == '/')
- talk_id(VOICE_CHAR_SLASH, true);
+ bool cap = false;
+ long id = -1, id2 = -1;
+ spell = utf8decode(spell, &c);
+ switch(c) {
+ case 'A' ... 'Z':
+ cap = true;
+ id = VOICE_CHAR_A + c - 'A';
+ break;
+ case 'a' ... 'z':
+ id = VOICE_CHAR_A + c - 'a';
+ break;
+ case '0' ... '9':
+ id = VOICE_ZERO + c - '0';
+ break;
+ case '-':
+ id = VOICE_MINUS;
+ break;
+ case '+':
+ id = VOICE_PLUS;
+ break;
+ case '.':
+ id = VOICE_DOT;
+ break;
+ case ' ':
+ id = VOICE_PAUSE;
+ break;
+ case '/':
+ id = VOICE_CHAR_SLASH;
+ break;
+ default:
+ if(c>DOUBLE_SHIFT) &DOUBLE_MASK;
+ cap = (x & CAP_FLAG);
+ }
+ };
+ if(id == -1 && id2 == -1) {
+ /* unknown char */
+ talk_id(VOICE_CHAR_UNKNOWN, true);
+ talk_number(c, true);
+ }
+ if(cap)
+ talk_id(VOICE_CHAR_CAP, true);
+ if(id != -1)
+ talk_id(id, true);
+ if(id2 != -1)
+ talk_id(id2, true);
}
return 0;
Index: rockbox-devel/tools/genlang
===================================================================
--- rockbox-devel.orig/tools/genlang
+++ rockbox-devel/tools/genlang
@@ -178,7 +178,7 @@ if($english) {
# -u it is convenient.
my $idnum=0; # start with a true number
- my $vidnum=0x8000; # first voice id
+ my $vidnum=0x1000; # first voice id
open(ENG, "<$english") || die "can't open $english";
my @phrase;
my $id;
@@ -292,7 +292,7 @@ sub compare {
}
my $idcount; # counter for lang ID numbers
-my $voiceid=0x8000; # counter for voice-only ID numbers
+my $voiceid=0x1000; # counter for voice-only ID numbers
#
# Now start the scanning of the selected language string
@@ -498,12 +498,12 @@ MOO
print HFILE <