アプリケーション単位で音量調整したい!
ゲームのマッチング待機中に、ウィンドウを切り替えて動画や音楽を聴きたいけど、ゲーム側のサウンドが邪魔する場合があります。
Windowsで音量調整する場合、Windowsキー+Ctrlキー+Vキーで音量ミキサーを開き、マウスで調整する必要があります。
そこでC#のNAudioというライブラリを利用して特定アプリケーションのみをミュートできるプログラムを作成しました。
NAudioとは
下記Wikiの引用になりますが、OSのオーディオをコントロールできるオーディオライブラリになります。音声の録音や再生、エンコード、デコードなどサウンド関係がめちゃ強ライブラリです。
NAudio(エヌオーディオ)とは.NET Framework上で動作するオーディオライブラリである。GitHub上でオープンソースで開発されている。以前はMicrosoft Public Licenseであったが、2021年2月7日リリースのv2.0.0からMIT licenseとなった
https://ja.wikipedia.org/wiki/NAudio
入手方法
名称 | 内容 |
---|---|
入手場所 | Nuget or GitHub |
ライセンス | MIT license |
環境
SDKのインストールが面倒だったため、.Net Framework v4.7.2を利用しようとしましたが
ライブラリの依存関係に引っ掛かりうまくいきませんでした。
Visual Stadioで作成すれば余裕で動くと思いますが、PCがもっさりするのが嫌なのでVisual Stadioはインストールせず、おとなしく.Net 6.0をインストールしました。
.Net Coreも対応していますので、開発環境に合わせてコンパイルしてください。
名称 | バージョン |
---|---|
フレームワーク | WPF |
.Net | v6.0 |
NAudio | v2.2.1 |
実装例
一からコードを書くのは面倒なのでDemoを利用します。
DemoはGitHubにアップロードされているため、Zipファイルでダウンロードします。
実装コード
DemoはGUIで実装していますが、コンソールアプリで十分なので起動時にVolumePanelインスタンスを作成します。
NAudioDemo\Program.cs
using System;
namespace NAudioDemo
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
//Application.EnableVisualStyles();
//Application.SetCompatibleTextRenderingDefault(false);
//var mainForm = new MainForm();
//Application.Run(mainForm);
var vmd = new NAudioDemo.VolumeMixerDemo.VolumePanel();
}
}
音量ミキサーのコントロールは VolumePanel.cs で行っているため、ファイルを使い回します。
コンストラクタ内でアプリケーションのプロセス名を検索し、該当アプリケーションをミュートに設定します。
NAudioDemo\VolumeMixerDemo\VolumePanel.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using NAudio.CoreAudioApi;
using System.Diagnostics;
using NAudio.CoreAudioApi.Interfaces;
using System.Media;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace NAudioDemo.VolumeMixerDemo
{
public partial class VolumePanel : UserControl, IAudioSessionEventsHandler
{
private readonly bool devicePanel;
private MMDevice device;
private readonly AudioSessionControl session;
public MMDevice Device
{
get
{
return device;
}
}
public event EventHandler DeviceChanged;
public event EventHandler<MuteEventArgs> MuteChanged;
public event EventHandler<VolumeEventArgs> VolumeChanged;
/// <summary>
/// Constructor for device panel creation.
/// </summary>
public VolumePanel()
{
string appName = readSettings(); //XMLからプロセス名を読み込み
this.devicePanel = true;
var deviceEnumerator = new MMDeviceEnumerator();
device = deviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
var sessions = device.AudioSessionManager.Sessions;
for (int i = 0; i < sessions.Count; i++)
{
Process process = Process.GetProcessById((int)sessions[i].GetProcessID);
Console.WriteLine(process.ProcessName.ToString());
if (process.ProcessName == appName)
{
//sessions[i].SimpleAudioVolume.Volume = 0.2f //音量変更する場合
sessions[i].SimpleAudioVolume.Mute = !sessions[i].SimpleAudioVolume.Mute;
}
}
//マスターボリューム(すべての音量)をゼロにする場合
//device.AudioEndpointVolume.MasterVolumeLevelScalar = ((float)0 / 100.0f);
//InitializeComponent();
}
~~~~~~ 以下省略 ~~~~~~
プロセス名はsettings.xmlのnameタグで管理するため、VolumePanelクラス内でXMLを読み込むメソッドを定義します。
(面倒なのでVolumePanel内に記載していますが、本番運用する場合は別ライブラリで作成してください)
NAudioDemo\VolumeMixerDemo\VolumePanel.cs
public class VolumePanel
{
public static string settings_file = "settings.xml";
public static string readSettings ()
{
try
{
//構成ファイルが無ければ作成する。
if (!File.Exists(Directory.GetCurrentDirectory() + "\\" + settings_file))
{
writeSettings();
}
XmlSerializer serializer = new XmlSerializer(typeof(AppSettings));
// XMLをAppSettingsオブジェクトに読み込む
AppSettings settings = new AppSettings();
using(FileStream fs = new FileStream(Directory.GetCurrentDirectory() + "\\" + settings_file, FileMode.Open))
{
// XMLファイルを読み込み、逆シリアル化(復元)する
settings = (AppSettings)serializer.Deserialize(fs);
}
return settings.name;
}
catch
{
MessageBox.Show("XMLの読み込みに失敗しました");
return null;
}
}
public static void writeSettings ()
{
try
{
AppSettings settings = new AppSettings();
settings.name = "please write Appname";
// XmlSerializerを使ってファイルに保存(TwitSettingオブジェクトの内容を書き込む)
XmlSerializer serializer = new XmlSerializer(typeof(AppSettings));
// カレントディレクトリに"settings.xml"というファイルで書き出す
using(FileStream fs = new FileStream(Directory.GetCurrentDirectory() + "\\" + settings_file, FileMode.Create))
{
// オブジェクトをシリアル化してXMLファイルに書き込む
serializer.Serialize(fs, settings);
}
}
catch
{
MessageBox.Show("XMLの書き込みに失敗しました");
}
}
}
public class AppSettings
{
#region メンバ変数
private string _name;
#endregion
#region プロパティ
public string name
{
get { return _name; }
set { _name = value; }
}
#endregion
}
settings.xmlにプロセス名を記載します。
初回アプリケーション起動時はnameタグに”please write Appname”と設定されるようにしています。
nameタグにchromeを指定するとGoogle Chromeをミュートすることができます。
settings.xml
<?xml version="1.0" encoding="utf-8"?>
<AppSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<name>chrome</name>
</AppSettings>
最後に
GitHubにアップロードされているDemoプロジェクトが機能てんこ盛りのため、一度Demoプロジェクトをコンパイルすることをお勧めします。
ショートカットキーの登録は次の記事で記載しています。