BizHawk/BizHawk.Client.EmuHawk/config/SoundConfig.cs

248 lines
9.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Client.EmuHawk.CustomControls;
using BizHawk.Common;
namespace BizHawk.Client.EmuHawk
{
public sealed class SoundConfig : Form
{
private readonly CheckBox cbEnableNormal;
private readonly TrackBar tbNormal;
private readonly CheckBox cbEnableRWFFW;
private readonly TrackBar tbRWFFW;
private readonly CheckBox cbEnableMaster;
private readonly CheckBox cbMuteFrameAdvance;
private readonly RadioButton rbOutputMethodDirectSound;
private readonly RadioButton rbOutputMethodXAudio2;
private readonly RadioButton rbOutputMethodOpenAL;
private readonly ListBox lbSoundDevices;
private readonly NumericUpDown nudBufferSize;
public SoundConfig()
{
cbEnableNormal = new CheckBox { AutoSize = true, Text = "Enable", UseVisualStyleBackColor = true };
var trackBarSize = new Size(32, 160);
tbNormal = new TrackBar { LargeChange = 10, Maximum = 100, Orientation = Orientation.Vertical, Size = trackBarSize, TickFrequency = 10 };
var nudSize = new Size(48, 19);
var nudNormal = new NumericUpDown { Size = nudSize };
nudNormal.ValueChanged += (sender, e) =>
{
var newValue = (int) ((NumericUpDown) sender).Value;
tbNormal.Value = newValue;
cbEnableNormal.Checked = newValue != 0; // mute when set to 0% volume
};
tbNormal.Scroll += (sender, e) => nudNormal.Value = ((TrackBar) sender).Value;
nudNormal.Value = Global.Config.SoundVolume;
cbEnableRWFFW = new CheckBox { AutoSize = true, Text = "Enable", UseVisualStyleBackColor = true };
tbRWFFW = new TrackBar { LargeChange = 10, Maximum = 100, Orientation = Orientation.Vertical, Size = trackBarSize, TickFrequency = 10 };
var nudRWFFW = new NumericUpDown { Size = nudSize };
nudRWFFW.ValueChanged += (sender, e) =>
{
var newValue = (int) ((NumericUpDown) sender).Value;
tbRWFFW.Value = newValue;
cbEnableRWFFW.Checked = newValue != 0; // mute when set to 0% volume
};
tbRWFFW.Scroll += (sender, e) => nudRWFFW.Value = ((TrackBar) sender).Value;
nudRWFFW.Value = Global.Config.SoundVolumeRWFF;
cbEnableRWFFW.Checked = Global.Config.SoundEnabledRWFF;
var flpRWFFW = new SingleColumnFLP
{
Controls = { new AutosizedLabel("RW/FFW"), cbEnableRWFFW, tbRWFFW, nudRWFFW },
Margin = Padding.Empty
};
cbEnableNormal.CheckedChanged += (sender, e) => flpRWFFW.Enabled = ((CheckBox) sender).Checked;
cbEnableNormal.Checked = Global.Config.SoundEnabledNormal;
var grpSoundVol = new FLPInGroupBox
{
Controls = {
new SingleColumnFLP
{
Controls = { new AutosizedLabel("Normal"), cbEnableNormal, tbNormal, nudNormal },
Margin = Padding.Empty
},
flpRWFFW
},
InnerFLP = { FlowDirection = FlowDirection.LeftToRight },
Size = new Size(124, 248),
Text = "Volume"
};
cbEnableMaster = new CheckBox { AutoSize = true, Text = "Master sound toggle", UseVisualStyleBackColor = true };
cbMuteFrameAdvance = new CheckBox
{
AutoSize = true,
Checked = Global.Config.MuteFrameAdvance,
Text = "Mute Frame Advance",
UseVisualStyleBackColor = true
};
cbEnableMaster.CheckedChanged += (sender, e) => grpSoundVol.Enabled = ((CheckBox) sender).Checked;
cbEnableMaster.Checked = Global.Config.SoundEnabled;
var onWindows = OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows;
rbOutputMethodDirectSound = new RadioButton { AutoSize = true, Enabled = onWindows, Text = "DirectSound", UseVisualStyleBackColor = true };
rbOutputMethodXAudio2 = new RadioButton { AutoSize = true, Enabled = onWindows, Text = "XAudio2", UseVisualStyleBackColor = true };
rbOutputMethodOpenAL = new RadioButton { AutoSize = true, Text = "OpenAL", UseVisualStyleBackColor = true };
lbSoundDevices = new ListBox { FormattingEnabled = true, Size = new Size(224, 96) };
void UpdateDeviceList(object sender, EventArgs e)
{
if ((sender as RadioButton)?.Checked == false) return; // only update for the radio button just clicked, or once in the constructor
IEnumerable<string> deviceNames;
if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows)
{
if (rbOutputMethodDirectSound.Checked) deviceNames = DirectSoundSoundOutput.GetDeviceNames();
else if (rbOutputMethodXAudio2.Checked) deviceNames = XAudio2SoundOutput.GetDeviceNames();
else if (rbOutputMethodOpenAL.Checked) deviceNames = OpenALSoundOutput.GetDeviceNames();
else deviceNames = Enumerable.Empty<string>(); // never hit
}
else
{
deviceNames = OpenALSoundOutput.GetDeviceNames();
}
lbSoundDevices.Items.Clear();
lbSoundDevices.Items.Add("<default>");
var i = 1;
foreach (var name in deviceNames)
{
lbSoundDevices.Items.Add(name);
if (name == Global.Config.SoundDevice) lbSoundDevices.SelectedIndex = i;
i++;
}
}
rbOutputMethodDirectSound.CheckedChanged += UpdateDeviceList;
rbOutputMethodXAudio2.CheckedChanged += UpdateDeviceList;
rbOutputMethodOpenAL.CheckedChanged += UpdateDeviceList;
var checkedRadio = Global.Config.SoundOutputMethod switch
{
Config.ESoundOutputMethod.DirectSound => rbOutputMethodDirectSound,
Config.ESoundOutputMethod.XAudio2 => rbOutputMethodXAudio2,
Config.ESoundOutputMethod.OpenAL => rbOutputMethodOpenAL,
_ => null
};
if (checkedRadio != null) checkedRadio.Checked = true;
var grpOutputMethod = new FLPInGroupBox
{
Controls = { rbOutputMethodDirectSound, rbOutputMethodXAudio2, rbOutputMethodOpenAL },
Size = new Size(88, 84),
Text = "Output Method"
};
var flpDeviceSelector = new SingleColumnFLP
{
AutoSize = false,
Controls = { new AutosizedLabel("Sound Device:"), lbSoundDevices },
Size = new Size(254, 112)
};
nudBufferSize = new NumericUpDown { Maximum = 250.0M, Minimum = 30.0M, Size = nudSize, Value = Global.Config.SoundBufferSizeMs };
var labelAlignment = new Padding(0, 5, 0, 0);
var flpRHS = new FlowLayoutPanel
{
AutoSize = true,
Controls =
{
new SingleColumnFLP
{
Controls =
{
cbEnableMaster,
new AutosizedLabel("Controls whether cores\neven generate audio.") { Margin = new Padding(24, 0, 0, 16) },
cbMuteFrameAdvance
}
},
grpOutputMethod,
flpDeviceSelector,
new SingleRowFLP
{
Controls =
{
new AutosizedLabel("Buffer Size:") { Margin = labelAlignment },
nudBufferSize,
new AutosizedLabel("milliseconds") { Margin = labelAlignment }
}
}
}
};
flpRHS.SetFlowBreak(grpOutputMethod, true);
flpRHS.SetFlowBreak(flpDeviceSelector, true);
var btnOk = new Button { Text = "&OK", UseVisualStyleBackColor = true };
btnOk.Click += (sender, e) =>
{
if (rbOutputMethodDirectSound.Checked && nudBufferSize.Value < 60.0M)
{
MessageBox.Show("Buffer size must be at least 60 milliseconds for DirectSound.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
var oldOutputMethod = Global.Config.SoundOutputMethod;
var oldDevice = Global.Config.SoundDevice;
SaveControlsTo(Global.Config);
GlobalWin.Sound.StopSound();
if (Global.Config.SoundOutputMethod != oldOutputMethod || Global.Config.SoundDevice != oldDevice)
{
GlobalWin.Sound.Dispose();
GlobalWin.Sound = new Sound(GlobalWin.MainForm.Handle);
}
GlobalWin.Sound.StartSound();
GlobalWin.OSD.AddMessage("Sound settings saved");
DialogResult = DialogResult.OK;
};
var btnCancel = new Button { Text = "&Cancel", UseVisualStyleBackColor = true };
btnCancel.Click += (sender, e) =>
{
GlobalWin.OSD.AddMessage("Sound config aborted");
Close();
};
SuspendLayout();
AcceptButton = btnOk;
AutoScaleDimensions = new SizeF(6F, 13F);
AutoScaleMode = AutoScaleMode.Font;
CancelButton = btnCancel;
ClientSize = new Size(372, 276);
Controls.AddRange(new Control[]
{
new SingleRowFLP { Controls = { btnOk, btnCancel }, Location = new Point(208, 244) },
new SingleRowFLP { Controls = { grpSoundVol, flpRHS }, Location = new Point(4, 0) }
});
FormBorderStyle = FormBorderStyle.FixedDialog;
Name = "SoundConfig";
ShowIcon = false;
StartPosition = FormStartPosition.CenterParent;
Text = "Sound Configuration";
ResumeLayout();
}
private void SaveControlsTo(Config config)
{
config.SoundEnabledNormal = cbEnableNormal.Checked;
config.SoundVolume = tbNormal.Value;
config.SoundEnabledRWFF = cbEnableRWFFW.Checked;
config.SoundVolumeRWFF = tbRWFFW.Value;
config.SoundEnabled = cbEnableMaster.Checked;
config.MuteFrameAdvance = cbMuteFrameAdvance.Checked;
if (rbOutputMethodDirectSound.Checked) config.SoundOutputMethod = Config.ESoundOutputMethod.DirectSound;
else if (rbOutputMethodXAudio2.Checked) config.SoundOutputMethod = Config.ESoundOutputMethod.XAudio2;
else if (rbOutputMethodOpenAL.Checked) config.SoundOutputMethod = Config.ESoundOutputMethod.OpenAL;
config.SoundDevice = (string) lbSoundDevices.SelectedItem ?? "<default>";
config.SoundBufferSizeMs = (int) nudBufferSize.Value;
}
}
}