SAPI 5.4 / 11 японский TTS в Delphi GUI против консоли - PullRequest
0 голосов
/ 09 марта 2020

Попытка использовать MS Speech API v11 с японским движком (MS Haruka) в Delphi 10.3.

У меня есть пример приложения с формой и кнопкой. Обработчик щелчков выглядит так:

uses SpeechLib11_TLB; // Imported from "Microsoft Speech Object Library" v.B.0
procedure TForm1.Button1Click(Sender: TObject);
var
    v: ISpeechVoice;
begin
    v := CoSpVoice.Create();
    //5.4 only but won't hurt
    v.Voice := v.GetVoices('language=411', '').Item(0);

    v.Speak('時間', SVSFDefault);
end;

Это приводит к ошибке «Ошибка Catastrophi c» (HRESULT 0x8000FFFF, E_UNEXPECTED). Код, который я думаю, должен быть эквивалентным, работает в проекте C ++:

#include <windows.h>
#import "libid:d3c4a7f2-7d27-4332-b41f-593d71e16db1" rename_namespace("SAPI") //v11
//#import "libid:C866CA3A-32F7-11D2-9602-00C04F8EE628" rename_namespace("SAPI") //v5.4

int wmain()
{
    CoInitializeEx(0, COINIT_APARTMENTTHREADED);
    {
        SAPI::ISpeechVoicePtr v;
        v.CreateInstance(__uuidof(SAPI::SpVoice));

        //Needed for 5.4 only, but won't hurt
        SAPI::ISpeechObjectTokensPtr voices(v->GetVoices(L"language=411", L""));
        v->Voice = voices->Item(0);

        v->Speak(L"時間", SAPI::SVSFDefault);
    }
    CoUninitialize();
    return 0;
}

Это работает и говорит. Таким образом, SAPI per se не сломан на машине. Платформа Win32 в обоих проектах, а не Win64. Японский голос является голосом по умолчанию (нет необходимости устанавливать его явно).

Тот же результат с собственно SAPI 5.4 (не OneCore), хотя японский голос не является голосом по умолчанию, и мне пришлось добавить пару строк, чтобы установить его как значение по умолчанию.


Дальнейшая отладка показывает, что на стороне Delphi столько, сколько вызов метода получения свойства v.Voice сразу после первой строки вызывает ту же ошибку E_UNEXPECTED. Между тем, Voice setter работает, если вы передаете ему действительный объект голосового токена из GetVoices(). Похоже, что голосовой объект правильно инициализирует себя в C ++ по умолчанию, но каким-то образом пропускает это в проекте Delphi.

Запрос v.Voice сразу после выполнения работ, хотя в Delphi с SAPI 5.4. Вызов Speak() по-прежнему выдает E_UNEXPECTED.

В чем может быть разница в контексте выполнения процесса / потока между C ++ и Delphi? Это не локаль потока. Модель COM-потока - квартира в обоих.

Тот же самый код Delphi работает с фразой Engli sh и голосом Engli sh (MS Helen). Так что, какой бы ни был сбой инициализации, он, вероятно, указывает c на Харуку.

Время выполнения SAPI 11 доступно здесь . Данные языка для TTS здесь .


Другая точка данных. Я переписал логи SAPI c в Delphi, чтобы вместо них использовать SAPI 5.4 OneCore (а не SAPI 5.4). В отличие от 5.4 и 11, он не предоставляет интерфейс на основе IDispatch, и он несколько неуклюже, особенно в Delphi, но японский TTS работает. Вопрос в том виде, в котором он изначально поставлен , до сих пор остается без ответа, но, по крайней мере, есть обходной путь. Я напишу ответ, но я не приму его.


Однако виноваты не обычные различия, а двойные. Я изменил логи c для использования пользовательских интерфейсов вместо с SAPI 5.4 собственно (typelib определяет оба), по-прежнему получая E_UNEXPECTED из Speak(). Нет информации об ошибках.


Вот еще один прекрасный момент для данных: SAPI 5.4 TTS с API-интерфейсом, основанным на автоматизации, работает и разговаривает, как и ожидалось, в Delphi консольном приложении . Так что это даже не Delphi специфика c, это как-то спецификация VCL c. Что это с Delphi GUI? Само собой разумеется, я немедленно перепроверил фрагмент кода C ++ в приложении C ++ GUI с формой и кнопкой. С ++ говорит.

1 Ответ

1 голос
/ 10 марта 2020

Не ответ, а обходной путь.

Windows 10 поставляется с двумя разновидностями 32-битного SAPI. Есть собственно SAPI 5.4 (в system32\speech), а также SAPI 5.4 OneCore (в system32\speech_onecore). Последний, хотя и внешне одинаковый, предоставляет другую библиотеку типов - здесь нет поддержки автоматизации, все интерфейсы являются пользовательскими, а не двойными. Что еще более важно, когда вы загружаете японский голос TTS в приложении Windows 10 «Настройки», вы получаете 3 голоса в OneCore ( Sayaka, почему-то отсутствует ) и только один, Харука, под 5.4, собственно .

Delphi может использовать пользовательские интерфейсы в библиотеке типов, но методы выглядят несколько неуклюже. Кроме того, перечисление голосов в API автоматизации чище. Во всяком случае, здесь идет.

uses SpeechLib54Core_TLB; // This time it's OneCore
procedure TForm1.Button1Click(Sender: TObject);
var
    v: ISpVoice;
    cat: ISpObjectTokenCategory;
    toks: IEnumSpObjectTokens;
    tok: ISpObjectToken;
    sno: LongWord;
    hr: HResult;
    n: Cardinal;
begin
    v := CoSpVoice.Create();
    hr := v.GetVoice(tok);
    tok.GetCategory(cat);
    cat.EnumTokens('language=411', '', toks); //411 means Japanese
    toks.GetCount(n);
    if n = 0 then
        exit; // No Japanese voices installed
    toks.Item(0, tok); //Take the first one - typically Ayumi
    v.SetVoice(tok);

    v.Speak('時間', 0, sno);
end;

Обратите внимание, что передача японского строкового литерала в метод COM работает без явного приведения к широкой строке.

...