Где голос Sayaka в Speech API OneCore? - PullRequest
2 голосов
/ 10 марта 2020

Windows 10. Я установил японские голоса TTS в настройках. Теперь, когда я использую перечисление голоса в Speech API 5.4 OneCore (но не в версии 5.4), я получаю 6 голосов:

  • David
  • Zira
  • Ayumi
  • Харука
  • Марка
  • Ичиро

На странице настроек речи также показаны эти 6. Но в реестре явно седьмой, Саяка ( HKLM\SOFTWARE\WOW6432Node\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_jaJP_SayakaM). Его файлы присутствуют в C:\windows\Speech_OneCore\Engines\TTS\ja-JP. По сравнению с остальными, есть дополнительный файл, .heq. Почему он не перечисляет?

Код перечисления идет:

    #import "libid:E6DA930B-BBA5-44DF-AC6F-FE60C1EDDEC8" rename_namespace("SAPI") //v5.4 OneCore

    HRESULT hr;
    SAPI::ISpVoicePtr v;
    v.CreateInstance(__uuidof(SAPI::SpVoice));
    SAPI::ISpObjectTokenPtr tok;
    hr = v->GetVoice(&tok); //Retrieve the default voice
    SAPI::ISpObjectTokenCategoryPtr cat;
    hr = tok->GetCategory(&cat); //Retrieve the voices category
    SAPI::IEnumSpObjectTokensPtr toks;
    hr = cat->EnumTokens(0, 0, &toks);

    //And enumerate
    unsigned long i, n;
    hr = toks->GetCount(&n);
    LPWSTR ws;
    for (i = 0; i < n; i++)
    {
        hr = toks->Item(i, &tok);
        hr = tok->GetId(&ws);
        CoTaskMemFree(ws);
    }

Единственное упоминание о Саяке онлайн, которое я могу найти, это здесь

Edit

Перечисление с помощью Reset () / Next () дает то же самое 6. Попытка создать токен непосредственно вокруг пути реестра выдает ошибку 0x8004503a (SPERR_NOT_FOUND). Во время просмотра с помощью Process Monitor обнаруживается интересный факт: вместо Sayaka под HKLM процесс запрашивает следующий ключ :

HKCU \ Software \ Microsoft \ Speech_OneCore \ Isolated \ 7WUiMB20NMV5Y7TgZ2WJXbUw32iGZQSvSkeaf0AevtQ \ HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Speech_OneCore \ Голос \ Лексема \ MSTTS_V110_jaJP_SayakaM

там это действительно ключ, как, что в HKCU, и она не содержит копию HKLM и HKCU настройки для SAPI, и есть на самом деле нет Саяка под Голоса в этом ключе. Только шесть я упомянул.

Так что происходит какая-то изоляция с настройками SAPI в нескольких экземплярах. Под Isolated есть 7 разных подключей, а для них разные голосовые наборы. Два содержат голоса, которые не имеют ничего общего с теми, которые мы знаем, и те имеют отношение к Кортане. Трудно сказать, что такое единица изоляции - может быть, пользователь, может быть, пакет приложения (в смысле UWP).

Редактировать

Как я и подозревал, происходит изоляция на основе пакета приложения. Я создал новый проект с тем же кодом, запустил его и получил другой ключ изоляции - F2yLLxINh6S1e3y3MkJo4ilfh036RB_9pHLEVL88yL0. Похоже, что каждый раз, когда вы запускаете приложение с поддержкой SAPI, оно выводит профиль изоляции из текущего исполняемого файла. Мгновение go, этого профиля изоляции не было, теперь оно есть. Так что он был создан SAPI на лету. Я не думаю, что голоса жестко запрограммированы, поэтому он скопировал голоса из профиля изоляции откуда-то из основного списка.

Где находится главный список? Это не HKLM\...\Speech_OneCore, так как можно увидеть Саяку там. Это может быть tokens_TTS_ja-JP.xml под C:\Windows\SysWOW64\Speech_OneCore\Common\ja-JP, так как там есть Аюми / Ичиро / Харука, а Саяка - нет. Безопасность этого файла довольно сурова, но у меня проблемы с редактированием этого файла даже с правами администратора. Кроме того, это вторая жесткая ссылка на C:\Windows\WinSxS\wow64_microsoft-windows-t..peech-ja-jp-onecore_31bf3856ad364e35_10.0.18362.1_none_46741f8a666da90a.

Папка SysWOW64\Speech_OneCore позволяет писать администраторам, а SysWOW64\Speech_OneCore\Common - нет. Только TrustedInstaller может написать это.

Кстати, логика изоляции c указана c для OneCore. SetId() в SAPI 5.4 правильно просматривает ключ, соответствующий предоставленному Id.


Альтернативный подход: в документах SAPI 5.4 упоминается интерфейс ISpRegDataKey, который позволяет инициализировать токен непосредственно из HKEY , Это не в typelib.

Ответы [ 2 ]

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

Если раздел реестра изоляции не имеет Sayaka, но HKLM делает, приложение может скопировать токен Sayaka в ключ изоляции при первом запуске. Основное понимание здесь заключается в том, что ключ изоляции доступен для записи без повышения прав , а SAPI поддерживает создание и заполнение токенов. Это не зависит от специфики изоляции. Создайте токен с жестко заданным идентификатором для Sayaka и скопируйте свойства и атрибуты из HKLM. Вот так:

#import "libid:E6DA930B-BBA5-44DF-AC6F-FE60C1EDDEC8" rename_namespace("SAPI") //v5.4 OneCore

//Get the default voice to avoid hard-coding the category
SAPI::ISpVoicePtr v;
SAPI::ISpObjectTokenPtr tok;
v.CreateInstance(__uuidof(SAPI::SpVoice));
v->GetVoice(&tok);
tok->GetId(&ws);
wchar_t TokID[200];
wcscpy_s(TokID, ws);
CoTaskMemFree(ws);

//Check if Sayaka is already registered in SAPI
SAPI::ISpObjectTokenCategoryPtr cat;
tok->GetCategory(&cat); //The category of voices
SAPI::IEnumSpObjectTokensPtr toks;
cat->EnumTokens(L"name=Microsoft Sayaka", 0, &toks);
unsigned long n;
toks->GetCount(&n);

if (n == 0) //Sayaka is not registered already
{
    //Is Sayaka present under HKLM\..\Voices\Tokens?
    HKEY hkSayaka, hkAttrs;
    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Speech_OneCore\\Voices\\Tokens\\MSTTS_V110_jaJP_SayakaM", 0, KEY_READ, &hkSayaka) == ERROR_SUCCESS)
    {
        if (RegOpenKeyEx(hkSayaka, L"Attributes", 0, KEY_READ, &hkAttrs) == ERROR_SUCCESS)
        {
            //If yes, create a Sayaka token where SAPI OneCore thinks it should be!

            //Replace the final path component of the default voice's ID with Sayaka
            LPWSTR pbs = wcsrchr(TokID, L'\\');
            wcscpy_s(pbs + 1, _countof(TokID) - (pbs - TokID) - 1, L"MSTTS_V110_jaJP_SayakaM");
            tok.CreateInstance(__uuidof(SAPI::SpObjectToken));
            //Note the 1 in the third parameter - "create if needed"
            HRESULT hr = tok->SetId(0, (LPWSTR)TokID, 1);

            DWORD dwi;
            wchar_t ValName[100]; //Enough
            unsigned char ValData[1000]; //Enough
            DWORD ValNameLen, ValDataLen, Type;

            //Copy all values from the Sayaka key
            //They are all strings
            for (dwi = 0; RegEnumValue(hkSayaka, dwi, ValName, &(ValNameLen = _countof(ValName)), 0, &Type, ValData, &(ValDataLen = sizeof(ValData))) == ERROR_SUCCESS; dwi++)
                tok->SetStringValue(ValName, (LPWSTR)ValData);

            //Copy all attributes from the Sayaka\Attributes key
            //All strings too.
            SAPI::ISpDataKeyPtr attrs;
            tok->CreateKey((LPWSTR)L"Attributes", &attrs);
            for (dwi = 0; RegEnumValue(hkAttrs, dwi, ValName, &(ValNameLen = _countof(ValName)), 0, &Type, ValData, &(ValDataLen = sizeof(ValData))) == ERROR_SUCCESS; dwi++)
                attrs->SetStringValue(ValName, (LPWSTR)ValData);

            RegCloseKey(hkAttrs);
        }
        RegCloseKey(hkSayaka);
    }
}

Подобный подход к разоблачению скрытых голосов TTS описан здесь: https://www.ghacks.net/2018/08/11/unlock-all-windows-10-tts-voices-system-wide-to-get-more-of-them/


Так как моя первоначальная проблема было ограничено одним приложением с поддержкой TTS, я собираюсь принять это. Тем не менее, весь вопрос с тем, чтобы не пригласить Саяку на вечеринку, - это, вероятно, упущение Microsoft, которое они должны в конечном итоге решить. Не стесняйтесь поднять мой запрос UserVoice .

0 голосов
/ 12 марта 2020

Этот ответ о включении Sayaka для тех приложений SAPI, которые явно не выбирают.

Основной список японских голосов TTS находится под C:\Windows\System32\Speech_OneCore\Common\ja-JP. Это не просто один файл - SAPI перечисляет все XML-файлы там. Проблема в том, что для записи в эту папку вам понадобится утилита, которая позволяет запускать программы как TrustedInstaller. Те существуют; есть список здесь . Я использовал файл с именем PowerRun .

. Вам нужно создать файл с именем tokens_TTS_ja-JP_Sayaka.xml следующего содержания:

<?xml version="1.0" encoding="utf-8"?>
<Tokens>
  <Category name="Voices" categoryBase="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore">
    <Token name="MSTTS_V110_jaJP_SayakaM">
      <String name="" value="Microsoft Sayaka - Japanese (Japan)" />
      <String name="LangDataPath" value="%windir%\Speech_OneCore\Engines\TTS\ja-JP\MSTTSLocjaJP.dat" />
      <String name="VoicePath" value="%windir%\Speech_OneCore\Engines\TTS\ja-JP\M1041Sayaka" />
      <String name="411" value="Microsoft Sayaka - Japanese (Japan)" />
      <String name="CLSID" value="{179F3D56-1B0B-42B2-A962-59B7EF59FE1B}" />
      <Attribute name="Version" value="11.0" />
      <Attribute name="Language" value="411" />
      <Attribute name="Gender" value="Female" />
      <Attribute name="Age" value="Adult" />
      <Attribute name="DataVersion" value="11.0.2016.0221" />
      <Attribute name="SharedPronunciation" value="" />
      <Attribute name="Name" value="Microsoft Sayaka" />
      <Attribute name="Vendor" value="Microsoft" />
      <Attribute name="SayAsSupport" value="spell=NativeSupported; cardinal=GlobalSupported; ordinal=NativeSupported; date=GlobalSupported; time=GlobalSupported; telephone=NativeSupported; address=NativeSupported; message=NativeSupported; url=NativeSupported; currency=NativeSupported; alphanumeric=NativeSupported" />
      <Attribute name="SampleText" value="既定の音声として%1を選びました" />
    </Token>
  </Category>
</Tokens>

, а затем скопировать этот файл. от TrustedInstaller до C:\Windows\System32\Speech_OneCore\Common\ja-JP. На 64-битном Windows также поместите копию в C:\Windows\SysWOW64\Speech_OneCore\Common\ja-JP, чтобы покрыть 32-битные приложения.

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

Саяка также появится в списке голосовых сообщений в меню «Настройки / Речь» и скажет свое приветствие, если будет предложено .

...