1

I'm using espeak-ng to turn German-language traffic messages into speech. See this example text:

B6 Weserstraße B71 Seeborg vorübergehende Begrenzung der Breite. B213 Wildeshauser Landstraße Delmenhorst-Deichhorst wegen Baustelle gesperrt.

The espeak method call looks like this:

unsigned int spoken_message_uuid = 0;

espeak_ERROR Speak (wstring text)
{
  espeak_ERROR   error = EE_OK;
  unsigned int  *uuid  = &spoken_message_uuid;
  const wchar_t *input = text.c_str ();

  wcout << L"Speaking text:" << endl << input << endl;

  error = espeak_Synth (input, text.length (), 0, POS_CHARACTER, 0, espeakCHARS_WCHAR | espeakENDPAUSE | espeakSSML, uuid, NULL);

return error;
}

My issue is now the following: All the German special characters (ä, ö, ü, ß) are not being spoken correctly! Instead, something like A Tilde ein Viertel appears in the spoken text, as if UTF-8 text had been treated erroneously as ASCII.

Here are the respective versions of espeak-ng and g++:

pi@autoradio:/import/valen/autoradio $ espeak-ng --version
eSpeak NG text-to-speech: 1.50  Data at: /usr/lib/arm-linux-gnueabihf/espeak-ng-data
pi@autoradio:/import/valen/autoradio $ g++ --version
g++ (Raspbian 6.5.0-1+rpi1+b1) 6.5.0 20181026
pi@autoradio:/import/valen/autoradio $ apt-cache policy espeak-ng
espeak-ng:
  Installiert:           1.50+dfsg-7~bpo10+1
  Installationskandidat: 1.50+dfsg-7~bpo10+1
  Versionstabelle:
 *** 1.50+dfsg-7~bpo10+1 100
        100 http://deb.debian.org/debian buster-backports/main armhf Packages
        100 /var/lib/dpkg/status
     1.49.2+dfsg-8 500
        500 http://raspbian.raspberrypi.org/raspbian buster/main armhf Packages

espeak has been installed from Debian's buster-backports repo to replace version 1.49, which didn't work either. The voice I'm using is mb-de5.

Neppomuk
  • 1,102
  • 1
  • 11
  • 24
  • 1
    Does it support `wchar`? – tadman Nov 20 '20 at 22:59
  • As I'm using the `espeakCHARS_WCHAR` flag, espeak must support wide char arrays. – Neppomuk Nov 20 '20 at 23:18
  • 1
    What encoding does espeak expect and what encoding is the source data in? `as if UTF-8 text had been treated` If the input is in `wchar_t` then why do you assume it to be UTF-8? That would be quite strange. – eerorika Nov 20 '20 at 23:19
  • @eerorika: The espeak doc doesn't state, which encoding the wide char array must be written in, unfortunately. – Neppomuk Nov 20 '20 at 23:20
  • @Neppomuk It helped if you could verify what the individual `wchar_t` values are in `input` one by one. – dxiv Nov 21 '20 at 00:14
  • 1
    @eerorika Neppomuk is describing the effect, which looks like the text has been turned into mojibake somewhere in the library. (E.g. perhaps it was internally converted to UTF-8, then interpreted as an 8-bit character set) – user253751 Nov 21 '20 at 00:22
  • 1
    @eerorika "ein Viertel" = "one quarter". The letter (perhaps ß) is being pronounced as ü – user253751 Nov 21 '20 at 00:23
  • 1
    @user253751 ß = U+00DF, encoded in UTF-8 as 0xC3 0x9F. And in ISO-8859-1 0xC3=Ã (a tilde). No idea why 0x9F became ¼, or may be it's ["u umlaut" or "ypsilon"](https://en.wikipedia.org/wiki/Western_Latin_character_sets_(computing)) – phuclv Nov 21 '20 at 05:35
  • @phuclv Maybe it's in fact the 'ü' character, which becomes ü in spoken text. – Neppomuk Nov 21 '20 at 21:58
  • 1
    @Neppomuk `ü` is `0xC3 0xBC` in UTF-8, which does indeed "translate" to `ü` if (mis)interpreted as 8-bit text in the [ISO/IEC 8859-1](https://en.wikipedia.org/wiki/ISO/IEC_8859-1) or [Windows-1252](https://en.wikipedia.org/wiki/Windows-1252) codepage. The actual solution depends on the source of your string and the compiler/environment you use, see for example my answer [here](https://stackoverflow.com/a/65094724/5538420) about a similar problem in Visual C++. – dxiv Dec 01 '20 at 17:36

1 Answers1

0

OK, this is not exactly a solution, yet a mere workaround, but at least it works: I hand over a string instead of a wstring. The original string turned out to be UTF-8-encoded, so that all the special characters fit into a string resp. char* variable. Here is the adapted code:

unsigned int spoken_message_uuid = 0;

espeak_ERROR Speak (string text)
{
  espeak_ERROR  error = EE_OK;
  unsigned int *uuid  = &spoken_message_uuid;
  const char   *input = text.c_str ();

  cout << "Speaking text:" << endl << input << endl;

  error = espeak_Synth (input, text.length (), 0, POS_CHARACTER, 0, espeakCHARS_UTF8 | espeakENDPAUSE | espeakSSML, uuid, NULL);

return error;
}
Neppomuk
  • 1,102
  • 1
  • 11
  • 24