【C#】NAudioを使って、音楽ファイルの音量変更ツール作ったよ！

## はじめに
作ろうと思ったキッカケ
・C#でツールを作成してみたかった
・ゲームに使用する音楽ファイルの音量が素材によってバラバラだったので統一したかった


## 導入
１．ソリューションのNuGetパッケージの管理を開く
![qiita4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465744/a31f8591-5986-eac0-6c89-ea8d9130ff7a.png)

２．参照タブから「NAudio」と検索
![qiita2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465744/774f9f91-42f4-9531-300b-295fa6d156f8.png)

３．インストールしたいプロジェクトにチェックをしてインストール
![qiita3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465744/3b0761b2-a9a7-697d-b38e-737021fa711c.png)
※画像のプロジェクトには既にNAudioがインストールされている


## デザイン
ツールボックスから下記のように配置しました。
![qiita1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465744/ac8182aa-8332-1d8a-0dda-7d79870234dd.png)

構成は下記の通り
Button ×2
Label ×2
TextBox ×2
TrackBar ×1

## 機能

①音楽ファイルをTextBoxへドラッグアンドドロップ
②ドロップされた音楽ファイルからパスを取得、NAudioでファイル読み込み
③Volumeを変更し、Playで確認
④最後にSaveでファイル書き出し

メンバ

```C#
        // Audioファイル種類定義.
        // TODO:ファイル出力時に使用したい.
        enum AudioType
        {
            None,
            MP3,
            WAVE,
        }

        AudioType audioType             = AudioType.None;
        string audioFilePath            = null;
        WaveOut waveOut                 = new WaveOut();
        AudioFileReader audioReader     = null;
```


___①音楽ファイルをTextBoxへドラッグアンドドロップ___
mp3、wave以外のファイルは弾く。

```C#

        /// <summary>
        /// ドラッグ時イベント.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void From1_DragEnter(object sender, DragEventArgs e)
        {
            // 複数のファイルは受け付けない.
            string[] files = (string[])e.Data.GetData(DataFormats.FileDrop, false);
            audioFilePath = files[0];

            // 指定の音楽ファイル以外は受け付けない.
            if(audioFilePath.Contains(".mp3"))
            {
                audioType = AudioType.MP3;
            }
            else if(audioFilePath.Contains(".wav"))
            {
                audioType = AudioType.WAVE;
            }
            else
            {
                audioType = AudioType.None;
                e.Effect = DragDropEffects.None;
                return;
            }

            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effect = DragDropEffects.All;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

```

___②ドロップされた音楽ファイルからパスを取得、NAudioでファイル読み込み___

```C#
        /// <summary>
        /// ドロップ時イベント.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="eventArgs"></param>
        private void Form1_DragDrop(object sender, DragEventArgs eventArgs)
        {
            // 音楽ファイル以外はDragEnterで弾かれる.
            dropBox.Text = audioFilePath;

            audioReader = new AudioFileReader(audioFilePath);
            if(null != audioReader)
            {
                waveOut.Init(audioReader);
            }
        }
```

___③Volumeを変更し、Playで確認___
TrackBar、TextどちらからでもVolumeを変更できるようにしています。

```C#
        /// <summary>
        /// trackBar移動時イベント.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            textBox1.Text = trackBar1.Value.ToString();

            // trackBarにあわせて音量変更.
            audioVolume = audioRate * trackBar1.Value;
            audioReader.Volume = audioVolume;
        }

        /// <summary>
        /// Volume入力時イベント.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            string inputText = textBox1.Text;
            int resultValue = 0;
            if(int.TryParse(inputText, out resultValue))
            {
                if( (0 < resultValue)
                &&  (resultValue <= 100))
                {
                    // 入力された数値をtrackbarへ反映.
                    textBox1.Text = resultValue.ToString();
                    trackBar1.Value = resultValue;
                }
                else
                {
                    // 数値が範囲を超えている.
                    textBox1.Text = trackBar1.Value.ToString();
                }
            }
            else
            {
                // 数値以外が入力された.
                textBox1.Text = trackBar1.Value.ToString();
            }
        }
```

再生

```C#
        /// <summary>
        /// 再生、停止ボタン.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void playButton_Click(object sender, EventArgs e)
        {
            if(null == audioReader)
            {
                // ダイアログ表示.
                MessageBox.Show("ファイルをドラッグアンドドロップしてください。\n");
                return;
            }

            if (waveOut.PlaybackState != PlaybackState.Playing)
            {
                waveOut.Play();
                this.playButton.Text = "Stop";
            }
            else
            { 
                waveOut.Stop();
                this.playButton.Text = "Play";

                // 再生位置を戻す.
                audioReader.Position = 0;
            }
        }
```


___④最後にSaveでファイル書き出し___

```C#
        /// <summary>
        /// ファイル出力イベント.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void saveButton_Click(object sender, EventArgs e)
        {
            if (null != audioReader)
            {
                int fileNamePosition = audioFilePath.LastIndexOf("\\");
                string fileName = audioFilePath.Substring(fileNamePosition + 1);
                fileName = addFileName + fileName;

                WaveFileWriter.CreateWaveFile(fileName, audioReader);

                // ダイアログ表示.
                MessageBox.Show("ファイル出力が完了しました。\n");
            }
            else
            {
                // ダイアログ表示.
                MessageBox.Show("ファイルをドラッグアンドドロップしてください。\n");
                return;
            }
        }
```

## 問題点
___・ボリュームが大きくできない___
これはWaveOut、AudioFileReaderどちらのVolumeプロパティも最大値が１であり、
デフォルトも１なのでこれ以上大きくすることが出来ません。
また、WaveOutのVolumeは１より大きい値を入れると例外が投げられます。
AudioFileReaderのVolumeは１より大きい値は入りますが、実際に聞く限り音量は変化していません。

下記のURL先で音量変更と思われるコードが公開されていますが、
bufferをどこから渡してあげるのかちょっと分かりません……。
WaveFormatあたりから引っ張ってくるのでしょうか……(´・ω・｀)
https://github.com/naudio/NAudio/blob/master/NAudio/Wave/SampleProviders/VolumeSampleProvider.cs

___・Waveファイル出力のメソッドのはずが何故かmp3ファイルも出力できる(WaveFileWriter.CreateWaveFile)___
こちらのメソッド、名前からもわかる通りWaveファイルを作成するメソッドのはずなのですが、
出力するファイル名の拡張子をmp3にしたところmp3ファイルが出力されました……。
プロパティで確認をしてもmp3ファイルとなっており、正常に再生もされます……。
よく分かりません……。

## あとがき
C#、Windows formを使ってのツール作成は思いのほか楽しかったです！
アイコンの作成等も普段行わないので、新鮮でした。
また、同じC#とはいえUnityを触るのとはまた違った感覚で勉強になりました。
今後も学習を進めていけたらと思います。
至らない点が多くあると思いますが、ご意見などありましたらお気軽に宜しくお願い致します。

## 参考
https://qiita.com/following_ng/items/28381f0416cb3e14586e
https://so-zou.jp/software/tech/programming/c-sharp/media/audio/naudio/