Windowsで音声出力

# 環境
Windows 11 Pro (64bit)
Visual Studio Community 2022

# COM
## JScript

```sp_com.js
// cscript sp_com.js
var sapi = WScript.CreateObject("SAPI.SpVoice");
sapi.Speak("hello, world");
```

```enum.js
var v = WScript.CreateObject("SAPI.SpVoice");
for (var e = new Enumerator(v.GetVoices()); ! e.atEnd(); e.moveNext()) {
	var t = e.item();
	WScript.Echo(t.GetDescription());
}
```

## VC++

```sp_com.cpp
// cl /MD sp_com.cpp
#pragma comment(lib, "ole32")

#include <sapi.h>

int main(void)
{
	if (FAILED(CoInitialize(NULL))) return 1;

	ISpVoice *pVoice = NULL;
	HRESULT hr = CoCreateInstance(CLSID_SpVoice,
		NULL, CLSCTX_ALL, IID_PPV_ARGS(&pVoice));
	if (SUCCEEDED(hr)) {
		hr = pVoice->Speak(L"hello, world", 0, NULL);
		pVoice->Release();
		pVoice = NULL;
	}

	CoUninitialize();
}
```

https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ms720163(v=vs.85)

# .NET
## C#

```dev.bat
@echo off
path %path%;C:\Windows\Microsoft.NET\Framework64\v4.0.30319
prompt $e[33m$p$g$e[m
cmd
```

```sp_net.cs
/*
csc /r:"C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Speech\v4.0_4.0.0.0__31bf3856ad364e35\System.Speech.dll" sp_net.cs
*/
using System.Speech.Synthesis;

class Program {
	static void Main() {
		using (var synth = new SpeechSynthesizer()) {
			synth.SetOutputToDefaultAudioDevice();
			synth.Speak("hello, world");
		}
	}
}
```

## PowerShell

```sp_net.ps1
# powershell -ExecutionPolicy RemoteSigned ./sp_net.ps1

Add-Type -AssemblyName System.Speech

$synth = New-Object System.Speech.Synthesis.SpeechSynthesizer
$synth.SetOutputToDefaultAudioDevice()
$synth.Speak("hello, world")
```

PowerShellで追加したアセンブリのpathを確認できる。
cscではGACアセンブリ名での参照追加はできない模様。

```
Add-Type -AssemblyName System.Speech
([AppDomain]::CurrentDomain).GetAssemblies()

C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Speech\v4.0_4.0.0.0__31bf3856ad364e35\System...
```

# WinRT
## C#
適当なディレクトリを用意する。
例：`C:\Projects\.NET\SpWinRT`

```
dotnet new console
```

というコマンドで`SpWinRT.csproj`と`Program.cs`が作られる。

```SpWinRT.csproj
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>
```

TargetFrameworkを`net8.0-windows10.0.22000.0`とする。

https://learn.microsoft.com/ja-jp/windows/apps/desktop/modernize/desktop-to-uwp-enhance

```Program.cs
using Windows.Media.Core;
using Windows.Media.Playback;
using Windows.Media.SpeechSynthesis;

var text = "hello, world";
using var synth = new SpeechSynthesizer();
using var stream = await synth.SynthesizeTextToStreamAsync(text);

using var player = new MediaPlayer();
player.Source = MediaSource.CreateFromStream(
	stream, stream.ContentType);
player.Play();
System.Console.ReadLine();
```

ビルドと実行

```
dotnet build
bin\Debug\net8.0-windows10.0.22000.0\SpWinRT.exe
```

### SoundPlayer

```
dotnet add package System.Windows.Extensions
```

を実行するとobjディレクトリにnuget関連ファイルが作られる。

```Program.cs
using System.Media;
using Windows.Media.SpeechSynthesis;

var text = "hello, world";
using var synth = new SpeechSynthesizer();
using var synthStream = await synth.SynthesizeTextToStreamAsync(text);

using var player = new SoundPlayer();
player.Stream = synthStream.AsStreamForRead();
player.PlaySync();
```