Add audio device selection. Fixes #3553.

This commit is contained in:
Paul Chote
2013-08-02 19:38:49 +12:00
parent 332759a5f5
commit 4009edfa96
7 changed files with 175 additions and 46 deletions

View File

@@ -31,6 +31,7 @@ Also thanks to:
* Daniel Derejvanik (Harisson)
* Danny Keary (Dan9550)
* Erasmus Schroder (rasco)
* Fahrradkette
* Frank Razenberg (zzattack)
* Igor Popov (ihptru)
* Iran

View File

@@ -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;
}

View File

@@ -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");

View File

@@ -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;
}
}
}

View File

@@ -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;
};

View File

@@ -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

View File

@@ -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