Add audio device selection. Fixes #3553.
This commit is contained in:
1
AUTHORS
1
AUTHORS
@@ -31,6 +31,7 @@ Also thanks to:
|
||||
* Daniel Derejvanik (Harisson)
|
||||
* Danny Keary (Dan9550)
|
||||
* Erasmus Schroder (rasco)
|
||||
* Fahrradkette
|
||||
* Frank Razenberg (zzattack)
|
||||
* Igor Popov (ihptru)
|
||||
* Iran
|
||||
|
||||
@@ -104,7 +104,8 @@ namespace OpenRA.GameRules
|
||||
public bool Repeat = false;
|
||||
public bool MapMusic = true;
|
||||
public string Engine = "AL";
|
||||
|
||||
public string Device = null;
|
||||
|
||||
public SoundCashTicks SoundCashTickType = SoundCashTicks.Extreme;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,20 @@ namespace OpenRA
|
||||
video = null;
|
||||
}
|
||||
|
||||
public static SoundDevice[] AvailableDevices()
|
||||
{
|
||||
var defaultDevices = new []
|
||||
{
|
||||
new SoundDevice("AL", null, "Default Output"),
|
||||
new SoundDevice("Null", null, "Output Disabled")
|
||||
};
|
||||
|
||||
var alDevices = OpenAlSoundEngine.AvailableDevices()
|
||||
.Select(d => new SoundDevice("AL", d, d));
|
||||
|
||||
return defaultDevices.Concat(alDevices).ToArray();
|
||||
}
|
||||
|
||||
public static void SetListenerPosition(float2 position) { soundEngine.SetListenerPosition(position); }
|
||||
|
||||
static ISound Play(Player player, string name, bool headRelative, WPos pos, float volumeModifier)
|
||||
@@ -348,6 +362,24 @@ namespace OpenRA
|
||||
void SetSoundVolume(float volume, ISound music, ISound video);
|
||||
}
|
||||
|
||||
public class SoundDevice
|
||||
{
|
||||
public readonly string Engine;
|
||||
public readonly string Device;
|
||||
public readonly string Label;
|
||||
|
||||
public SoundDevice(string engine, string device, string label)
|
||||
{
|
||||
Engine = engine;
|
||||
Device = device;
|
||||
Label = label;
|
||||
|
||||
// Limit label to 32 characters
|
||||
if (Label.Length > 32)
|
||||
Label = "..." + Label.Substring(Label.Length - 32);
|
||||
}
|
||||
}
|
||||
|
||||
interface ISoundSource { }
|
||||
|
||||
public interface ISound
|
||||
@@ -372,13 +404,51 @@ namespace OpenRA
|
||||
Dictionary<int, PoolSlot> sourcePool = new Dictionary<int, PoolSlot>();
|
||||
const int POOL_SIZE = 32;
|
||||
|
||||
static string[] QueryDevices(string label, int type)
|
||||
{
|
||||
// Clear error bit
|
||||
Al.alGetError();
|
||||
|
||||
var devices = Alc.alcGetStringv(IntPtr.Zero, type);
|
||||
if (Al.alGetError() != Al.AL_NO_ERROR)
|
||||
{
|
||||
Log.Write("sound", "Failed to query OpenAL device list using {0}", label);
|
||||
return new string[] {};
|
||||
}
|
||||
|
||||
return devices;
|
||||
}
|
||||
|
||||
public static string[] AvailableDevices()
|
||||
{
|
||||
// Returns all devices under windows vista and newer
|
||||
if (Alc.alcIsExtensionPresent(IntPtr.Zero, "ALC_ENUMERATE_ALL_EXT") == Alc.ALC_TRUE)
|
||||
return QueryDevices("ALC_ENUMERATE_ALL_EXT", Alc.ALC_ALL_DEVICES_SPECIFIER);
|
||||
|
||||
if (Alc.alcIsExtensionPresent(IntPtr.Zero, "ALC_ENUMERATION_EXT") == Alc.ALC_TRUE)
|
||||
return QueryDevices("ALC_ENUMERATION_EXT", Alc.ALC_DEVICE_SPECIFIER);
|
||||
|
||||
return new string[] {};
|
||||
}
|
||||
|
||||
public OpenAlSoundEngine()
|
||||
{
|
||||
Console.WriteLine("Using OpenAL sound engine");
|
||||
//var str = Alc.alcGetString(IntPtr.Zero, Alc.ALC_DEFAULT_DEVICE_SPECIFIER);
|
||||
var dev = Alc.alcOpenDevice(null);
|
||||
|
||||
if (Game.Settings.Sound.Device != null)
|
||||
Console.WriteLine("Using device `{0}`", Game.Settings.Sound.Device);
|
||||
else
|
||||
Console.WriteLine("Using default device");
|
||||
|
||||
var dev = Alc.alcOpenDevice(Game.Settings.Sound.Device);
|
||||
if (dev == IntPtr.Zero)
|
||||
throw new InvalidOperationException("Can't create OpenAL device");
|
||||
{
|
||||
Console.WriteLine("Failed to open device. Falling back to default");
|
||||
dev = Alc.alcOpenDevice(null);
|
||||
if (dev == IntPtr.Zero)
|
||||
throw new InvalidOperationException("Can't create OpenAL device");
|
||||
}
|
||||
|
||||
var ctx = Alc.alcCreateContext(dev, IntPtr.Zero);
|
||||
if (ctx == IntPtr.Zero)
|
||||
throw new InvalidOperationException("Can't create OpenAL context");
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
|
||||
{
|
||||
enum PanelType { General, Input }
|
||||
|
||||
SoundDevice soundDevice;
|
||||
PanelType Settings = PanelType.General;
|
||||
ColorPreviewManagerWidget colorPreview;
|
||||
World world;
|
||||
@@ -112,6 +113,13 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
|
||||
shellmapMusicCheckbox.IsChecked = () => soundSettings.MapMusic;
|
||||
shellmapMusicCheckbox.OnClick = () => soundSettings.MapMusic ^= true;
|
||||
|
||||
var devices = Sound.AvailableDevices();
|
||||
soundDevice = devices.FirstOrDefault(d => d.Engine == soundSettings.Engine && d.Device == soundSettings.Device) ?? devices.First();
|
||||
|
||||
var audioDeviceDropdown = generalPane.Get<DropDownButtonWidget>("AUDIO_DEVICE");
|
||||
audioDeviceDropdown.OnMouseDown = _ => ShowAudioDeviceDropdown(audioDeviceDropdown, soundSettings, devices);
|
||||
audioDeviceDropdown.GetText = () => soundDevice.Label;
|
||||
|
||||
// Input pane
|
||||
var inputPane = panel.Get("INPUT_CONTROLS");
|
||||
inputPane.IsVisible = () => Settings == PanelType.Input;
|
||||
@@ -147,6 +155,8 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
|
||||
int.TryParse(windowWidth.Text, out x);
|
||||
int.TryParse(windowHeight.Text, out y);
|
||||
graphicsSettings.WindowedSize = new int2(x,y);
|
||||
soundSettings.Device = soundDevice.Device;
|
||||
soundSettings.Engine = soundDevice.Engine;
|
||||
Game.Settings.Save();
|
||||
Ui.CloseWindow();
|
||||
onExit();
|
||||
@@ -194,5 +204,24 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, options.Keys, setupItem);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShowAudioDeviceDropdown(DropDownButtonWidget dropdown, SoundSettings s, SoundDevice[] devices)
|
||||
{
|
||||
var i = 0;
|
||||
var options = devices.ToDictionary(d => (i++).ToString(), d => d);
|
||||
|
||||
Func<string, ScrollItemWidget, ScrollItemWidget> setupItem = (o, itemTemplate) =>
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => soundDevice == options[o],
|
||||
() => soundDevice = options[o]);
|
||||
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => options[o].Label;
|
||||
return item;
|
||||
};
|
||||
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, options.Keys, setupItem);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
public class SettingsMenuLogic
|
||||
{
|
||||
Widget bg;
|
||||
SoundDevice soundDevice;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public SettingsMenuLogic(Action onExit)
|
||||
@@ -103,12 +104,13 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
mapMusicCheckbox.IsChecked = () => Game.Settings.Sound.MapMusic;
|
||||
mapMusicCheckbox.OnClick = () => Game.Settings.Sound.MapMusic ^= true;
|
||||
|
||||
var soundEngineDropdown = audio.Get<DropDownButtonWidget>("SOUND_ENGINE");
|
||||
soundEngineDropdown.OnMouseDown = _ => ShowSoundEngineDropdown(soundEngineDropdown, soundSettings);
|
||||
soundEngineDropdown.GetText = () => soundSettings.Engine == "AL" ?
|
||||
"OpenAL" : soundSettings.Engine == "Null" ? "None" : "OpenAL";
|
||||
var devices = Sound.AvailableDevices();
|
||||
soundDevice = devices.FirstOrDefault(d => d.Engine == soundSettings.Engine && d.Device == soundSettings.Device) ?? devices.First();
|
||||
|
||||
var audioDeviceDropdown = audio.Get<DropDownButtonWidget>("AUDIO_DEVICE");
|
||||
audioDeviceDropdown.OnMouseDown = _ => ShowAudioDeviceDropdown(audioDeviceDropdown, soundSettings, devices);
|
||||
audioDeviceDropdown.GetText = () => soundDevice.Label;
|
||||
|
||||
|
||||
// Display
|
||||
var display = bg.Get("DISPLAY_PANE");
|
||||
var gs = Game.Settings.Graphics;
|
||||
@@ -244,6 +246,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
int.TryParse(windowHeight.Text, out y);
|
||||
gs.WindowedSize = new int2(x,y);
|
||||
int.TryParse(maxFrameRate.Text, out gs.MaxFramerate);
|
||||
soundSettings.Device = soundDevice.Device;
|
||||
soundSettings.Engine = soundDevice.Engine;
|
||||
Game.Settings.Save();
|
||||
Ui.CloseWindow();
|
||||
onExit();
|
||||
@@ -325,7 +329,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
textBox.OnEnterKey = () => { textBox.YieldKeyboardFocus(); return true; };
|
||||
}
|
||||
|
||||
public static bool ShowRendererDropdown(DropDownButtonWidget dropdown, GraphicSettings s)
|
||||
static bool ShowRendererDropdown(DropDownButtonWidget dropdown, GraphicSettings s)
|
||||
{
|
||||
var options = new Dictionary<string, string>()
|
||||
{
|
||||
@@ -346,20 +350,18 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ShowSoundEngineDropdown(DropDownButtonWidget dropdown, SoundSettings s)
|
||||
bool ShowAudioDeviceDropdown(DropDownButtonWidget dropdown, SoundSettings s, SoundDevice[] devices)
|
||||
{
|
||||
var options = new Dictionary<string, string>()
|
||||
{
|
||||
{ "OpenAL", "AL" },
|
||||
{ "None", "Null" },
|
||||
};
|
||||
var i = 0;
|
||||
var options = devices.ToDictionary(d => (i++).ToString(), d => d);
|
||||
|
||||
Func<string, ScrollItemWidget, ScrollItemWidget> setupItem = (o, itemTemplate) =>
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => s.Engine == options[o],
|
||||
() => s.Engine = options[o]);
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => o;
|
||||
() => soundDevice == options[o],
|
||||
() => soundDevice = options[o]);
|
||||
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => options[o].Label;
|
||||
return item;
|
||||
};
|
||||
|
||||
|
||||
@@ -50,30 +50,44 @@ Container@SETTINGS_PANEL:
|
||||
Y:6
|
||||
Width:PARENT_RIGHT-35
|
||||
Height:PARENT_BOTTOM-12
|
||||
Checkbox@SHOW_SHELLMAP:
|
||||
X:15
|
||||
Y:80
|
||||
Width:200
|
||||
Height:20
|
||||
Font:Regular
|
||||
Text:Show Shellmap
|
||||
Checkbox@SHELLMAP_MUSIC:
|
||||
X:15
|
||||
Y:110
|
||||
Width:200
|
||||
Height:20
|
||||
Font:Regular
|
||||
Text:Shellmap Music
|
||||
Label@DEBUG_TITLE:
|
||||
X:15
|
||||
Y:100
|
||||
Y:150
|
||||
Width:340
|
||||
Font:Bold
|
||||
Text:Debug
|
||||
Align:Center
|
||||
Checkbox@PERFTEXT_CHECKBOX:
|
||||
X:15
|
||||
Y:120
|
||||
Y:170
|
||||
Width:300
|
||||
Height:20
|
||||
Font:Regular
|
||||
Text:Show Performance Text
|
||||
Checkbox@PERFGRAPH_CHECKBOX:
|
||||
X:15
|
||||
Y:150
|
||||
Y:200
|
||||
Width:300
|
||||
Height:20
|
||||
Font:Regular
|
||||
Text:Show Performance Graph
|
||||
Checkbox@CHECKUNSYNCED_CHECKBOX:
|
||||
X:15
|
||||
Y:180
|
||||
Y:230
|
||||
Width:300
|
||||
Height:20
|
||||
Font:Regular
|
||||
@@ -130,7 +144,7 @@ Container@SETTINGS_PANEL:
|
||||
MaxLength:5
|
||||
Label@VIDEO_DESC:
|
||||
X:375
|
||||
Y:65
|
||||
Y:68
|
||||
Width:340
|
||||
Height:25
|
||||
Font:Tiny
|
||||
@@ -138,58 +152,65 @@ Container@SETTINGS_PANEL:
|
||||
Text:Mode/Resolution changes will be applied after the game is restarted
|
||||
Checkbox@PIXELDOUBLE_CHECKBOX:
|
||||
X:375
|
||||
Y:90
|
||||
Y:110
|
||||
Width:200
|
||||
Height:20
|
||||
Font:Regular
|
||||
Text:Enable Pixel Doubling
|
||||
Checkbox@SHOW_SHELLMAP:
|
||||
X:375
|
||||
Y:120
|
||||
Width:200
|
||||
Height:20
|
||||
Font:Regular
|
||||
Text:Show Shellmap
|
||||
Label@AUDIO_TITLE:
|
||||
X:375
|
||||
Y:160
|
||||
Y:150
|
||||
Width:340
|
||||
Font:Bold
|
||||
Text:Sound
|
||||
Align:Center
|
||||
Label@SOUND_LABEL:
|
||||
X:375
|
||||
Y:175
|
||||
Y:164
|
||||
Width:95
|
||||
Height:25
|
||||
Align:Right
|
||||
Text:Sound Volume:
|
||||
Slider@SOUND_SLIDER:
|
||||
X:475
|
||||
Y:180
|
||||
Y:170
|
||||
Width:240
|
||||
Height:20
|
||||
Ticks:5
|
||||
Label@MUSIC_LABEL:
|
||||
X:375
|
||||
Y:205
|
||||
Y:194
|
||||
Width:95
|
||||
Height:25
|
||||
Align:Right
|
||||
Text:Music Volume:
|
||||
Slider@MUSIC_SLIDER:
|
||||
X:475
|
||||
Y:210
|
||||
Y:200
|
||||
Width:240
|
||||
Height:20
|
||||
Ticks:5
|
||||
Checkbox@SHELLMAP_MUSIC:
|
||||
Label@AUDIO_DEVICE_LABEL:
|
||||
X:375
|
||||
Y:240
|
||||
Width:200
|
||||
Y:229
|
||||
Width:75
|
||||
Height:20
|
||||
Text:Audio Device:
|
||||
DropDownButton@AUDIO_DEVICE:
|
||||
X:475
|
||||
Y:230
|
||||
Width:240
|
||||
Height:25
|
||||
Font:Regular
|
||||
Text:Shellmap Music
|
||||
Text:Default Device
|
||||
Label@AUDIO_DESC:
|
||||
X:375
|
||||
Y:258
|
||||
Width:340
|
||||
Height:25
|
||||
Font:Tiny
|
||||
Align:Center
|
||||
Text:Device changes will be applied after the game is restarted
|
||||
Background@INPUT_CONTROLS:
|
||||
Width:740
|
||||
Height:290
|
||||
|
||||
@@ -182,19 +182,24 @@ Background@SETTINGS_MENU:
|
||||
Width:200
|
||||
Height:20
|
||||
Text: Autoplay Music After Map Load
|
||||
Label@SOUND_ENGINE_LABEL:
|
||||
Label@AUDIO_DEVICE_LABEL:
|
||||
X:0
|
||||
Y:150
|
||||
Width:75
|
||||
Height:25
|
||||
Text:Sound Engine:
|
||||
DropDownButton@SOUND_ENGINE:
|
||||
Text:Audio Device:
|
||||
DropDownButton@AUDIO_DEVICE:
|
||||
X:100
|
||||
Y:150
|
||||
Width:120
|
||||
Width:250
|
||||
Height:25
|
||||
Font:Regular
|
||||
Text:OpenAL
|
||||
Label@AUDIO_DESC:
|
||||
Y:175
|
||||
Width:200
|
||||
Height:25
|
||||
Font:Tiny
|
||||
Text:Device changes will be applied after the game is restarted.
|
||||
Container@DISPLAY_PANE:
|
||||
X:37
|
||||
Y:100
|
||||
|
||||
Reference in New Issue
Block a user