C#（Windowsフォーム）で音量ミキサーを作ってみる。ChatGPTに書かせる。

# はじめに
音量ミキサーを作りたくなりました。こういうやつ。
![fig1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340870/644d0e7b-e196-2213-3cda-18497d6fe404.png)
できたのがこちらです。
![fig2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340870/8cce1c81-5596-0894-f011-8153eb32a6e5.png)
しかもchatGPTにほとんどを書かせたので、全然調べてもないし１時間もせずにできました。

早速中身を見ていきましょう。
環境は
Windows8.1 VisualStudio2022 .NETCore7.0 

# １．プロセスIDと音量の取得
正規のWindows音量ミキサーを見てみると、アプリケーション名と現在の音量がスライダーで出てます。
これを再現するには、アプリケーション名と、音量を取得する必要がありそうです。さらに、アプリケーションはOS内ではプロセスIDというもので管理されてそうなので、これも取得したいですね。ということでコードを考えてもらいます。

ChatGPT、「オーディオを使用するプロセスのidと名前の一覧を取得するC#プログラムを教えて」
![Videotogif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340870/fa76f377-0b81-9b9e-7c38-8f8db48addcf.gif)
初めてGPTつかったけどマジですげえな、目の前でコード生えてくるの見ると感動してしまう。

```csharp
//これ実行するとプロセスid,プロセス名,オーディオ音量をリストにして返してくれる
public List<Tuple<int, string, float>> GetAudioProcesses()
        {
            var audioProcesses = new List<Tuple<int, string, float>>();
            var enumerator = new MMDeviceEnumerator();
            var devices = enumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active);

            foreach (var device in devices)
            {
                var sessions = device.AudioSessionManager.Sessions;

                for (int i = 0; i < sessions.Count; i++)
                {
                    var session = sessions[i];
                    var processId = session.GetProcessID;

                    if (processId != null)
                    {
                        var process = GetProcessFromId((int)processId);

                        if (process != null)
                        {
                            audioProcesses.Add(new Tuple<int, string, float>((int)processId, process.ProcessName, session.SimpleAudioVolume.Volume));
                            Debug.Print(session.SimpleAudioVolume.Volume.ToString());
                        }
                    }
                }
            }

            return audioProcesses;
        }
private Process GetProcessFromId(int processId)
        {
            try
            {
                return Process.GetProcessById(processId);
            }
            catch (ArgumentException)
            {
                // プロセスが存在しない場合はnullを返す
                return null;
            }
        }
```
# 画面の実装
これで取得できたので、次に実際に画面を作ってもらいます。
![fig3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340870/1e1a196c-5826-69ea-dd0d-365a80fa9bd6.png)
```csharp
private void DisplayAudioProcesses()
        {
            // 既存のコントロールをクリアする
            flowLayoutPanel.Controls.Clear();

            audioProcesses = GetAudioProcesses();

            // リストの内容を表示する
            foreach (var audioProcess in audioProcesses)
            {
                // プロセスIDを表示するラベルを作成する
                var idLabel = new Label
                {
                    Text = $"Process ID: {audioProcess.Item1}",
                    AutoSize = true,
                    TextAlign = ContentAlignment.MiddleLeft
                };

                // プロセス名を表示するラベルを作成する
                var nameLabel = new Label
                {
                    Text = $"Process Name: {audioProcess.Item2}",
                    AutoSize = true,
                    TextAlign = ContentAlignment.MiddleLeft
                };

                // 音量を表示するラベルを作成する
                var volumeLabel = new Label
                {
                    Text = $"Volume: {(int)(audioProcess.Item3*100):F2}%",
                    AutoSize = true,
                    TextAlign = ContentAlignment.MiddleLeft
                };

                // 音量を設定するスライダーを作成する
                var volumeSlider = new TrackBar
                {
                    Minimum = 0,
                    Maximum = 100,
                    Value = (int)(audioProcess.Item3*100),
                    TickFrequency = 10,
                    Width = 150
                };
                volumeSlider.ValueChanged += VolumeSlider_ValueChanged;
                Debug.Print("abya="+audioProcess.Item2 + ":" + audioProcess.Item3);
                //volumeSlider.Value =(int)audioProcess.Item3 * 100;

                // コントロールをパネルに追加する
                var panel = new FlowLayoutPanel
                {
                    FlowDirection = FlowDirection.LeftToRight,
                    Dock = DockStyle.Top,
                    Padding = new Padding(5),
                    Margin = new Padding(5),
                    Width = flowLayoutPanel.Width - 25,
                    Height = 60
                };
                panel.Controls.Add(idLabel);
                panel.Controls.Add(nameLabel);
                panel.Controls.Add(volumeLabel);
                panel.Controls.Add(volumeSlider);
                flowLayoutPanel.Controls.Add(panel);
            }
        }

        private void VolumeSlider_ValueChanged(object sender, EventArgs e)
        {
            // スライダーの値が変更された時に、対応するプロセスの音量を変更する
            var slider = sender as TrackBar;
            var panel = slider.Parent as FlowLayoutPanel;
            if (panel == null) return;
            var volumeLabel = panel.Controls[2] as Label;

            var index = flowLayoutPanel.Controls.GetChildIndex(panel);
            audioProcesses[index] = new Tuple<int, string, float>(
                audioProcesses[index].Item1,
                audioProcesses[index].Item2,
                slider.Value
            );

            Debug.Print(slider.Value.ToString());

            SetApplicationVolume(audioProcesses[index].Item1, (float)slider.Value/100);

            volumeLabel.Text = $"Volume: {slider.Value}%";
        }
```

あとは`このプログラムを実行するためには、MainFormという名前のWindowsフォームを作成し、FlowLayoutPanelという名前のコントロールを配置しておく必要があります。また、リストの内容をaudioProcessesフィールドに設定し、MainForm_LoadメソッドでDisplayAudioProcessesメソッドを呼び出す必要があります。`の指示通り、コピペします。
もうできちゃった、すげえな。

頼んだ３行の表はできませんでしたが、まあいい感じに出来たので良しとしましょう。