.NET MAUI で音声ファイルを再生する方法

最近趣味MAUIデビューしました！

この記事では、Plugin.Maui.Audioを使って.NET MAUIで音声ファイルを再生する使い方を、流し見でササっと概要をつかめるよう短く紹介します。

この記事を流し見したあとに、公式さんや他所さんのサンプルプログラムを真似てみると理解がスムーズになると思います。

# .NET MAUI で音声ファイルを再生する方法
**[Plugin.Maui.Audio](https://github.com/jfversluis/Plugin.Maui.Audio)** というNugetパッケージを使います。
プラットフォームの違いを気にすることなく、簡単に音声ファイルを扱うことができます。

再生可能なファイル形式は、公式に記載ありませんが、MP3とWAVは大丈夫でした！
Apple社製が手元にないためm4aの確認はできていません…。

## 準備
* Visual Studio 2022 
* .NET 7.0
* .NET MAUI プロジェクトを作成しておく。

* Nugetパッケージマネージャーから Plugin.Maui.Audio をインストールしておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2271094/96081753-9612-6401-5ba4-5a32a3f81ef6.png)


# 基本の使い方
次の3ステップで簡単再生できます♪

## STEP1 🍄 AudioManagerオブジェクトを取得

DIしない場合、Currentプロパティからオブジェクトを取得できます。

```csharp
var audioManager = AudioManager.Current;
```
Currentプロパティからは常に同一のインスタンスが返るためDIしなくても複数のクラスから同一インスタンスを使い回すことができます。

::: note
DIする場合、以下の2ステップです。（推奨らしいですが個人的にはやらなくていいと思ってます）

1. MauiProgram.csでDIコンテナに登録し、(全体像は[コチラ](https://marunaka-blog.com/c-sharp-maui-behaivor/7334/)が参考になります)
```csharp:MauiProgram.cs
builder.Services.AddSingleton(AudioManager.Current);
```

2 . ViewModelでコンストラクタインジェクションしてオブジェクトを受け取る。
```csharp:AudioSampleViewModel
void AudioSampleViewModel(IAudioManager audioManager)
{
    _AudioManager = audioManager;
}
```
:::

#### 謎のクラス設計への独白(読み飛ばし推奨)

- AudioManagerクラスは、ソースを拝見したところSingletonパターン"風"の設計となっていました。staticなCurrentプロパティが唯一のAudioManagerオブジェクトを管理している…と見せかけ、なぜかprivateコンストラクタは明記されていないので外部から直接newすることもできます…。
- さらに、公式さんではこのクラスをDIコンテナでSingletonに設定して使うことを推奨しているのですが、クラス自体がSingleton設計(のつもり)なら、DIしなくても必ずシングルトンになりますよね？ならわざわざDIを推奨する必要あるのだろうか…？
- さらにさらに、インスタンスフィールドが存在してないので、C#なんだからクラス自体をstaticにしてしまえば良いのでは…？この辺はoo遵守レベルの違いから来る流派的なコーディングなのか？と思いつつstaticプロパティを既に許してるのだからもうクラス丸ごとstaticにしちゃってCurrentプロパティは消滅させてしまっても良いのでは…？など何か私の知らない意図があるのかと気になってます。

## STEP2 🍄 AudioPlayerオブジェクトを取得
AudioManagerに再生したい音声ファイルのストリームを渡すと、そのファイル専用のAudioPlayerオブジェクトを作ってくれます。
```csharp
// Resourcesフォルダ配下などに置いている場合(通常Resources\Rawに配置)
var stream = await FileSystem.OpenAppPackageFileAsync("Sample.wav");

// Projectの外に置いている場合
// var stream = new FileStream(@"C:\xxx\Sample.wav", FileMode.Open, FileAccess.Read);

audioPlayer = audioManager.CreatePlayer(stream);

```

- **1つの音声ファイルにつき1つのAudioPlayerオブジェクトが必要** なので、複数の音声ファイルを扱いたい場合は AudioPlayerオブジェクトを複数作成する必要があります。

- なお、AudioManagerオブジェクト1つあれば 複数のAudioPlayerを作成できます。

## STEP3 🍄 再生する

🎶それでは早速ポチっとな───。

```csharp
audioPlayer.Play();
```
🎼～～～🎵🎶

めっちゃ簡単じゃないですか？
これでパソコンでもスマホでも鳴りますよー！



# その他の基本機能

### ⏸ 一時停止する

```csharp:
audioPlayer.Pause();
```
再生中に実行すると止まります。
もう一度再生すると続きから再生されます。

### ⏹️ 停止する
```csharp:
audioPlayer.Stop();
```
再生中に実行すると止まります。
もう一度再生すると最初から再生されます。

一時停止中に実行した場合も、もう一度再生すると最初から再生されます。

要するに再生開始位置がリセットされます。

### 🔊 音量調節する

```csharp:
audioPlayer.Volume++;
audioPlayer.Volume--;
```
[コチラの記事](https://marunaka-blog.com/c-sharp-maui-behaivor/7334/)のサンプルアプリでは、スライダー、"+"ボタン、"-"ボタン で簡単に調節できます。
シンプルな機能しかなくコピペで作れるのでチュートリアルとして是非やってみてください！(私の書いた記事ではありません。私もお世話になりました、ありがとうございます！)

## 筆者の好きな使い方を紹介

### 🔁 ループ再生

再生が終わる前にLoopフラグを立てておくだけ！めっちゃ簡単です。
一瞬の隙間もなく繰り返してくれるので、シームレス音源も実現しやすいです！

```csharp
audioPlayer.Play(); // 10秒間の音楽だとします
Thread.Sleep(5000); // 適当に途中まで待って
audioPlayer.Loop = true; // フラグを立てると、10秒経つとまた最初から再生されます
```


### 🐸 複数の音声ファイルを同時再生する

ピアノ系アプリを作るときに重宝します！

複数のAudioPlayerを作っておけば、それぞれを非同期に動作させることができます！

```csharp:複数の音源を同時再生する
var audioPlayer_Do = audioManager.CreatePlayer(stream_Do);
var audioPlayer_So = audioManager.CreatePlayer(stream_So);
var audioPlayer_Mi = audioManager.CreatePlayer(stream_Mi);

audioPlayer_Do.Play();
audioPlayer_So.Play();
audioPlayer_Mi.Play();

```

### まとめ

基本の使い方は
1. AudioManager取得
2. AudioPlayer生成
3. audioManager.Play();

のたった3ステップ！

Plugin.Maui.Audioの開発者の方へ
便利なライブラリを作ってくれてありがとうございます！まだ初期バージョンということで、今後のアップデートも楽しみにしています！