【问题标题】:Microsoft Text-To-Speech doesn't speak accented charactersMicrosoft Text-To-Speech 不会说出重音字符
【发布时间】:2019-08-11 07:56:51
【问题描述】:

我正在使用 Microsoft sapi 库开发文本转语音应用程序。我实现了口语功能,发现重音字符 (à,á,â,ä,é,è,ê,í,ì,î,ó,ò,ô,ö,ù,ú,û,ü ) 不说话。 这是我的代码:

int ttsSpeak( const char* text ) //Text to Speech speaking function
{
  if( SUCCEEDED(hr) )
  {
    hr = SpEnumTokens( SPCAT_VOICES, NULL, NULL, &cpEnum );

    cpEnum->Item( saveVoice, &cpVoiceToken );
    cpVoice->SetVoice( cpVoiceToken ); //Initialization of the voice

    string str( text );
    cout << str;
    std::wstring stemp = std::wstring( str.begin(), str.end() );
    LPCWSTR sw = ( LPCWSTR )stemp.c_str(); //variable allowing to speak my entered text

    printf( "Text To Speech processing\n" );
    hr = cpVoice->Speak( sw, SPF_DEFAULT, NULL ); //speak my text

    saveText = text;

    cpEnum.Release();
    cpVoiceToken.Release();
  }
  else
  {
    printf( "Could not speak entered text\n" );
  }

  return true;
}

我调试了我的应用程序,发现变量 str 获取了重音字符。但是,我创建了一个名为stempwstring 变量,在其中转换了我的字符串,并且这里的重音字符被替换为一个空方块。然后,创建一个 LPCWSTR 变量(指向常量宽字符串的长指针)以朗读输入的文本。下面是我的变量值的图片。

也许我的代码有问题,但我能做些什么来确保重音字符被读出?

【问题讨论】:

标签: c++ text-to-speech sapi


【解决方案1】:

您不能简单地将单字节或多字节字符串(charstd::string)复制到宽字符串(wchar_tstd::wstring)。您需要在编码或字符集之间进行适当的转换。

您必须确定用于两个字符串的正确编码。在 Windows 上,std::string 数据通常采用本地编码,例如 Windows-1252,std::wstring 数据采用 UTF-16。

在 Windows 上,您可以使用 MultiByteToWideChar 进行转换。

或者,您可以使用mbstowcsstd::mbtowc 等标准函数。

【讨论】:

  • 或者,您可以简单地将ttsSpeak() 更改为以const wchar_t* 开头,并完全摆脱strstemp 局部变量,并将text 直接传递给Speak()。然后,ttsSpeak() 的调用者有责任传入一个有效的 Unicode 字符串。
  • @RemyLebeau 没错,但这更多是一种架构选择。从这个问题来看,发帖人似乎甚至不知道字符类型和编码的概念,这是首先要做对的事情。
  • @rveerd,MultiByteToWideChar 有效。但是,我找到了一种更短的方法来实现它,但我会接受你的回答
【解决方案2】:

我实现了@rveerd 建议的MultiByteToWideChar。代码如下:

int ttsSpeak( const char* text ) //Text to Speech speaking function
{
  if( SUCCEEDED(hr) )
  {
    hr = SpEnumTokens( SPCAT_VOICES, NULL, NULL, &cpEnum );

    cpEnum->Item( saveVoice, &cpVoiceToken );
    cpVoice->SetVoice( cpVoiceToken ); //Initialization of the voice

    //processing conversion
    int wchars_num = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 ); 
    wchar_t* wstr = new wchar_t[ wchars_num ];
    MultiByteToWideChar( CP_ACP, 0, text, -1, wstr, wchars_num );

    printf( "Text To Speech processing\n" );
    hr = cpVoice->Speak( wstr, SPF_DEFAULT, NULL ); //speak my text

    saveText = text;

    cpEnum.Release();
    cpVoiceToken.Release();
    delete new wchar_t[wchars_num];
  }
  else
  {
    printf( "Could not speak entered text\n" );
  }

  return true;
}

我还找到了一种更短的转换方法。只需将 MultiByteToWideChar 代码替换为以下代码:

CA2W pszWide( str.c_str(), CP_ACP);
hr = cpVoice->Speak( pszWide, SPF_DEFAULT, NULL );

编辑:我替换了 CP_UTF7,因为它很少使用。 CP_UTF8 是首选。但是,它对我不起作用,但我发现 CP_ACP 对我有用。有关更多信息,请查看link@rveerd 发布

【讨论】:

  • 您的输入是 UTF-7 的可能性非常小。 UTF-8 的普及率可能要高一百万倍,这并不夸张。
  • @MSalters 我尝试使用 UTF-8,但我遇到了与上下文中解释的相同的错误。这一次,ç 被替换为 ?黑色菱形
  • 您的输入也可能是 CP-1252 或许多其他常见编码。 UTF-7 真的很少见,即使不是完全理论上的。
  • @georges619 是的,如果数据来自 Windows 环境,通常需要使用 CP_ACP。
  • MultiByteToWideChar() 的例子中,char*string 的转换是不必要的,只需将char* 直接传递给MultiByteToWideChar()。不要忘记delete[] wchar_t* 分配给new[]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-22
  • 2021-03-08
  • 2020-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多