11

SpeechSynthesizerクラスを使用する C# によるテキスト読み上げアプリケーションでは、SpeakProgress発話される単語ごとに発生するという名前のイベントがあります。ただし、一部のボイスでは、パラメーターe.AudioPositionが出力オーディオ ストリームと同期されず、出力 Wave ファイルがこの位置よりも速く再生されます (この関連する質問を参照してください)。

とにかく、ビットレートに関する正確な情報や、選択した音声に関連するその他の情報を見つけようとしています。私が経験したように、この情報で wave ファイルを初期化できれば、同期の問題は解決されます。ただし、そのような情報が で見つからない場合は、SupportedAudioFormat他に見つける方法がありません。たとえば、「Microsoft David Desktop」の音声は でサポートされている形式を提供していませんVoiceInfoが、PCM 16000 hz、16 ビット形式をサポートしているようです。

SpeechSynthesizer の選択された音声のオーディオ形式を見つけるにはどうすればよいですか

 var formats = CurVoice.VoiceInfo.SupportedAudioFormats;

 if (formats.Count > 0)
 {
     var format = formats[0];
     reader.SetOutputToWaveFile(CurAudioFile, format);
 }
 else
 {
        var format = // How can I find it, if the audio hasn't provided it?           
        reader.SetOutputToWaveFile(CurAudioFile, format );
}
4

2 に答える 2

3

更新:この回答は、調査後に編集されました。当初、SupportedAudioFormats は (おそらく誤って構成された) レジストリ データからのものである可能性が高いことを記憶から示唆していました。調査によると、私にとって、Windows 7 ではこれは間違いなく当てはまり、Windows 8 では偶然にもバックアップされています。

サポートされているオーディオ形式に関する問題

System.Speech由緒ある COM 音声 API (SAPI) をラップし、一部の音声は 32 ビット対 64 ビットであるか、誤って構成されている可能性があります (64 ビット マシンのレジストリでは、HKLM/Software/Microsoft/Speech/VoicesHKLM/Software/Wow6432Node/Microsoft/Speech/Voices.

私は ILSpySystem.SpeechとそのVoiceInfoクラスを指摘しましたが、SupportedAudioFormats はレジストリ データのみに由来するものであると確信しているためSupportedAudioFormats、TTS エンジンがアプリケーションのプラットフォーム ターゲットに適切に登録されていない場合、列挙時にゼロの結果が返される可能性があります ( x86、Any、または 64 ビット)、または単にベンダーがレジストリでこの情報を提供しない場合。

音声は、レジストリ (データ) ではなく、音声エンジン (コード) 次第であるため、異なる形式、追加の形式、または少ない形式をサポートする可能性があります。そのため、暗闇でのショットになる可能性があります。この点に関して、標準の Windows の音声は、多くの場合、サード パーティの音声よりも一貫性がありますが、必ずしも有用な機能を提供するとは限りませんSupportedAudioFormats

この情報を見つけるのは難しい方法です

現在の音声の現在の形式を取得することはまだ可能であることがわかりましたが、これはリフレクションに依存して System.Speech SAPI ラッパーの内部にアクセスします。

したがって、これは非常に脆弱なコードです。また、本番環境での使用はお勧めしません。

: 以下のコードでは、セットアップのために Speak() を 1 回呼び出す必要があります。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
于 2015-12-17T01:31:45.040 に答える