Обновление: этот ответ был изменен после расследования. Первоначально я предполагал по памяти, что SupportedAudioFormats, скорее всего, просто из (возможно, неправильно настроенных) данных реестра; расследование показало, что для меня в Windows 7 это определенно так, и в Windows 8 выполняется тщательное резервное копирование.
Проблемы с поддерживаемыми аудиоформатами
System.Speech
является оболочкой почтенного COM-речевого API (SAPI), а некоторые голоса имеют 32-битный и 64-битный формат или могут быть неправильно сконфигурированы (в реестре 64-битной машины HKLM/Software/Microsoft/Speech/Voices
против HKLM/Software/Wow6432Node/Microsoft/Speech/Voices
.
Я указал ILSpy на System.Speech
и его VoiceInfo
класс, и я почти убежден, что SupportedAudioFormats исходит исключительно из данных реестра, поэтому при перечислении SupportedAudioFormats
можно получить нулевые результаты, если любой из ваших движков TTS не зарегистрирован должным образом для вашего приложения. Целевая платформа (x86, Any или 64 bit), или если поставщик просто не предоставляет эту информацию в реестре.
Голоса могут по-прежнему поддерживать другие, дополнительные или меньшее количество форматов, поскольку это зависит от механизма речи (кода), а не реестра (данных). Так что это может быть выстрел в темноте. Стандартные голоса Windows часто в этом отношении в разы более последовательны, чем голоса третьих лиц, но они все равно не обязательно обеспечивают SupportedAudioFormats
.
Трудный путь поиска этой информации
Я обнаружил, что все еще можно получить текущий формат текущего голоса, но это зависит от отражения для доступа к внутренним компонентам оболочек SAPI System.Speech.
Следовательно, это довольно хрупкий код! И я бы не рекомендовал использовать в продакшене.
Примечание. Приведенный ниже код требует, чтобы вы один раз вызывали Speak () для настройки; для принудительной установки без Speak () потребуется больше вызовов. Однако я могу позвонить Speak("")
, чтобы ничего не сказать, и это прекрасно работает.
Выполнение:
[StructLayout(LayoutKind.Sequential)]
struct WAVEFORMATEX
{
public ushort wFormatTag;
public ushort nChannels;
public uint nSamplesPerSec;
public uint nAvgBytesPerSec;
public ushort nBlockAlign;
public ushort wBitsPerSample;
public ushort cbSize;
}
WAVEFORMATEX GetCurrentWaveFormat(SpeechSynthesizer synthesizer)
{
var voiceSynthesis = synthesizer.GetType()
.GetProperty("VoiceSynthesizer", BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(synthesizer, null);
var ttsVoice = voiceSynthesis.GetType()
.GetMethod("CurrentVoice", BindingFlags.Instance | BindingFlags.NonPublic)
.Invoke(voiceSynthesis, new object[] { false });
var waveFormat = (byte[])ttsVoice.GetType()
.GetField("_waveFormat", BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(ttsVoice);
var pin = GCHandle.Alloc(waveFormat, GCHandleType.Pinned);
var format = (WAVEFORMATEX)Marshal.PtrToStructure(pin.AddrOfPinnedObject(), typeof(WAVEFORMATEX));
pin.Free();
return format;
}
Использование:
SpeechSynthesizer s = new SpeechSynthesizer();
s.Speak("Hello");
var format = GetCurrentWaveFormat(s);
Debug.WriteLine($"{s.Voice.SupportedAudioFormats.Count} formats are claimed as supported.");
Debug.WriteLine($"Actual format: {format.nChannels} channel {format.nSamplesPerSec} Hz {format.wBitsPerSample} audio");
Чтобы проверить это, я переименовал раздел реестра Microsoft Anna AudioFormats
в HKLM/Software/Wow6432Node/Microsoft/Speech/Voices/Tokens/MS-Anna-1033-20-Dsk/Attributes
, в результате чего SpeechSynthesizer.Voice.SupportedAudioFormats
не содержал никаких элементов при запросе. Ниже приведен результат в этой ситуации:
0 formats are claimed as supported.
Actual format: 1 channel 16000 Hz 16 audio
person
El Zorko
schedule
17.12.2015