
OpenAL Device Choices
Posted Saturday, 27 June, 2009 - 14:18 by Inertia inI've recently bought a Creative Labs Soundblaster X-Fi Platinum Fatal1ty Champion Series (TM)(C)(R) card (hope I did not forget any buzzwords) and getting the impression that it finally works as it should, but AudioContext is giving me some troubles porting the old Alut code. (I want to confirm that OpenTK's X-Ram class works as advertised by me :P)
The card did not ship with a driver CD, I've installed latest drivers and oalinst right from creative labs website.
My impression is that AudioContext uses the wrong tokens to select it's device, here's c&p from some AlcGetString queries.
Mind the "Detected by OpenTK" is simply what AudioContext.AvailableDevices returns. Also I have nothing connected to the SPDIF Out, so it's correctly recognizing Speakers to use for output.
Using Creative Labs driver (result identical for x32 and x64):
Detected by OpenTK:
Generic Software
Returned by AlcGetString.DefaultDeviceSpecifier:
Generic Software
Returned by AlcGetString.DefaultAllDevicesSpecifier:
Generic Software on Speakers (Creative SB X-Fi)
Returned by AlcGetStringList.DeviceSpecifier:
Generic Software
Returned by AlcGetStringList.AllDevicesSpecifier:
Generic Software on Speakers (Creative SB X-Fi)
Generic Software on SPDIF Out (Creative SB X-Fi)
using OpenAL Soft drivers (copied to app dir, result identical for x32 and x64)
Detected by OpenTK:
DirectSound Software
Wave File Writer
Returned by AlcGetString.DefaultDeviceSpecifier:
DirectSound Software
Returned by AlcGetString.DefaultAllDevicesSpecifier:
DirectSound Software on Speakers (Creative SB X-Fi)
Returned by AlcGetStringList.DeviceSpecifier:
DirectSound Software
Wave File Writer
Returned by AlcGetStringList.AllDevicesSpecifier:
DirectSound Software on Speakers (Creative SB X-Fi)
DirectSound Software on SPDIF Out (Creative SB X-Fi)
Wave File Writer
------------------------------------------------
However when I run the EfxEnumerateWin32.exe from the OpenAL SDK I get these device choices:
Enumerate EFX Application
Select OpenAL Device:
1. SB X-Fi Audio [E800](DEFAULT)
2. Generic Software
Running EfxEnumerateWin64.exe gives:
Enumerate EFX Application
Select OpenAL Device:
1. Generic Software(DEFAULT)
---------------------------------------------
Running openal-info.exe (with OpenAL Soft in it's dir) returns
Available playback devices:
DirectSound Software on Speakers (Creative SB X-Fi)
DirectSound Software on SPDIF Out (Creative SB X-Fi)
Wave File Writer
Available capture devices:
WaveIn on Line-In 2/Mic 2 (Creative SB X-
WaveIn on Digital-In (Creative SB X-Fi)
WaveIn on S/PDIF-In (Creative SB X-Fi)
WaveIn on Auxiliary (Creative SB X-Fi)
WaveIn on Microphone (Creative SB X-Fi)
WaveIn on Auxiliary 2 (Creative SB X-Fi)
WaveIn on Line-In (Creative SB X-Fi)
Default device: DirectSound Software
Default capture device: WaveIn on Line-In 2/Mic 2 (Creative SB X-
ALC version: 1.1
ALC extensions:
ALC_ENUMERATE_ALL_EXT, ALC_ENUMERATION_EXT, ALC_EXT_CAPTURE, ALC_EXT_EFX
OpenAL vendor string: OpenAL Community
OpenAL renderer string: OpenAL Soft
OpenAL version string: 1.1 ALSOFT 1.8.466
OpenAL extensions:
AL_EXTX_buffer_sub_data, AL_EXT_EXPONENT_DISTANCE, AL_EXT_FLOAT32,
AL_EXT_IMA4, AL_EXT_LINEAR_DISTANCE, AL_EXT_MCFORMATS, AL_EXT_OFFSET,
AL_EXTX_source_distance_model, AL_LOKI_quadriphonic
EFX version: 1.0
Max auxiliary sends: 2
Available filters:
Low-pass
Available effects:
EAX Reverb
Reverb
EchoRunning openal-info.exe without OpenAL Soft returns:
Available playback devices:
SB X-Fi Audio [E800]
Generic Software on Speakers (Creative SB X-Fi)
Generic Software on SPDIF Out (Creative SB X-Fi)
Available capture devices:
Line-In 2/Mic 2 (Creative SB X-
Digital-In (Creative SB X-Fi)
S/PDIF-In (Creative SB X-Fi)
Auxiliary (Creative SB X-Fi)
Microphone (Creative SB X-Fi)
Auxiliary 2 (Creative SB X-Fi)
Line-In (Creative SB X-Fi)
Default device: SB X-Fi Audio [E800]
Default capture device: Line-In 2/Mic 2 (Creative SB X-
ALC version: 1.1
ALC extensions:
None
OpenAL vendor string: Creative Labs Inc.
OpenAL renderer string: SB X-Fi Audio [E800]
OpenAL version string: OpenAL version 1.1
OpenAL extensions:
EAX
EAX1.0
EAX2.0
EAX3.0
EAX4.0
EAX5.0
EFX version: 1.0
Max auxiliary sends: 2
Available filters:
Low-pass
Available effects:
EAX Reverb
Reverb
Chorus
Distortion
Echo
Flanger
Frequency Shifter
Vocal Morpher
Pitch Shifter
Ring Modulator
Autowah
Compressor
Equalizeropenal-info is most likely an x86 app (came with the OpenAL Soft x86 driver), could it be that my x64 driver is simply broken?
I kinda miss the "Generic Hardware" device, which is probably the "SB X-Fi Audio [E800]". (mind the device name is identical to "OpenAL renderer string: SB X-Fi Audio [E800]" returned by openal-info)
Either way I think AudioContext should use AlcGetString.DefaultAllDevicesSpecifier to select the default device. With both drivers it selects the most appropriate device.
Edit: Could it be that the problem is related to either a) the disabled onboard sound or b) the graphic card's HDMI out? Another solution might be http://icculus.org/alextreg/wiki/ALC_ENUMERATE_ALL_EXT currently AudioContext uses ALC_ENUMERATE_EXT only.


Comments
Re: OpenAL Device Choices
Try changing
GetString.DeviceSpecifiertoGetStringList.AllDevicesSpecifierinAudioContext.LoadAvailableDevices. Does it return the correct devices after the change?Other than that, you can force a specific device using the
AudioContext(string device)constructor.Re: OpenAL Device Choices
After the change the list returned is
Generic Software on Speakers (Creative SB X-Fi)
Generic Software on SPDIF Out (Creative SB X-Fi)
but it should be this:
Available playback devices:
SB X-Fi Audio [E800]
Generic Software on Speakers (Creative SB X-Fi)
Generic Software on SPDIF Out (Creative SB X-Fi)
I have already tried creating an AudioContext with "SB X-Fi Audio [E800]" as parameter, but it would not use any other device than before according to AL.Get( ALGetString..) and the available Efx Extensions are the same as for software.
You might have missed my edit to the initial post (when I commited changes your reply was suddenly there), could that be part of the issue?
Re: OpenAL Device Choices
Yep, I missed your edit. How do you use ALC_ENUMERATE_ALL_EXT?
Re: OpenAL Device Choices
Idk, the AL Extension registry is not quite like the GL one. The only other info there is 2 tokens:
So basically the changes you suggested in your last post are using the Extension already.
I find it rather strange that explicitly requesting a device by name does not give the expected result, maybe the char* handling is not right. I'll take a look.
Re: OpenAL Device Choices
Alc.OpenDevice() is ok, it returns null for the string "SB X-Fi Audio [E800]" but a non-zero pointer for "Generic Software". Alc.GetString is ok aswell.
The different reports by EfxEnumerateWinXX.exe appear to be connected with their x86 framework. But I'm running debug x86 builds from VS2010 here - targeting .Net 2.0 - so I should get all devices the 32-Bit driver knows of?
Re: OpenAL Device Choices
Could it be that Creative really doesn't ship 64bit drivers? Compiling for x86 should give you the same results as EfxEnumerateWin86.exe - provided we are not missing something obvious.
Does openal-info do anything different than AudioContext? It's source code should be distributed with OpenAL Soft.
Another idea (to verify the differences between x86 and x64) is to compile openal-info for x64.
Re: OpenAL Device Choices
I had a quick glance at it and as far as I can see the command patterns in Alfw (OpenAL SDK), openal-info and AudioContext are close to identical. It's most likely a driver problem on my end, reinstalling oalinst did not help so far though.
here's an openal-info log from a X-Fi card (eXtremegamer edition IIRC) under windows xp x86, what is really weird is that neither of the 2 logs contains any ALC Extensions. Could it be - because the extensions were promoted to core 1.1 - that they are not in the list anymore? But why does OpenAL Soft list them?
He'll test my example app too, but needs Net Framework installed first and that's not going to happen tonight.
Available playback devices: SB X-Fi Audio [CC00] Generic Software on Lautsprecher (Creative SB X-Fi) Generic Software on SPDIF Out (Creative SB X-Fi) Available capture devices: Microphone (Creative SB X-Fi) "What U Hear" (Creative SB X-Fi Line-In (Creative SB X-Fi) Auxiliary (Creative SB X-Fi) Default device: SB X-Fi Audio [CC00] Default capture device: Microphone (Creative SB X-Fi) ALC version: 1.1 ALC extensions: None OpenAL vendor string: Creative Labs Inc. OpenAL renderer string: SB X-Fi Audio [CC00] OpenAL version string: OpenAL version 1.1 OpenAL extensions: EAX EAX1.0 EAX2.0 EAX3.0 EAX4.0 EAX5.0 EFX version: 1.0 Max auxiliary sends: 2 Available filters: Low-pass Available effects: EAX Reverb Reverb Chorus Distortion Echo Flanger Frequency Shifter Vocal Morpher Pitch Shifter Ring Modulator Autowah Compressor EqualizerRe: OpenAL Device Choices
Afaik OpenAL-Soft doesn't support hardware features of any sound card. It does everything in software - that is why it's name contains word Soft (as in Software).
And that is why it is behaves same on any hardware - it does not suffer from bad or missing drivers for soundcard.
Re: OpenAL Device Choices
That is correct and because 99.5% of those who use OpenTK.Audio use the software driver, the issues listed above did not show up yet ;)
[Extensions]
It appears the missing extension strings are a driver quirk. Tests like Alc.IsExtensionPresent() will correctly return true/false, but you cannot get a full list from Alc.GetString.
For example, this code will fork correctly to "1". However the extensions string returned by Alc.GetString is 2x null (blank).
[Device Detection]
I've ported parts of strangesoft's openal-info to OpenTK.Audio, it gives me the following result:
Available playback devices:
SB X-Fi Audio [E800]
Generic Software on Speakers (Creative SB X-Fi)
Generic Software on SPDIF Out (Creative SB X-Fi)
Available capture devices:
Line-In 2/Mic 2 (Creative SB X-
Digital-In (Creative SB X-Fi)
S/PDIF-In (Creative SB X-Fi)
Auxiliary (Creative SB X-Fi)
Microphone (Creative SB X-Fi)
Auxiliary 2 (Creative SB X-Fi)
Line-In (Creative SB X-Fi)
Default device:
SB X-Fi Audio [E800]
Default capture device:
Line-In 2/Mic 2 (Creative SB X-
ALC version: 1.1
ALC extensions: for device (96234192)
None
ALC extensions: for device (null)
I'm not quite sure yet what the difference to AudioContext is, but this is the desired - correct - result. It uses Alc to create the dummy context - not AudioContext - so the problem is very likely in AudioContext's constructor.
Re: OpenAL Device Choices
The AudioContext doesn't create a dummy context before querying available devices. Actually, I don't recall the OpenAL manual mentioning anything about dummy contexts.
Maybe that's the reason for the discrepancy.
Re: OpenAL Device Choices
Do you intend to work on this? I'm already working on it, but since you wrote it you know your way around better than me and I'll gladly hand it over ;-)
btw. X-Ram works fine, it reports 66MB total RAM although it should be 64MB (free RAM reports 64MB), but I think this has something to do with all X-Fi cards having 2MB onboard RAM, probably for streaming the mixed output or something like that. No reason for concern imho.
Re: OpenAL Device Choices
Feel free to tackle the issue. I'm studying for exams, so my OpenTK time is strictly limited.
Re: OpenAL Device Choices
Good luck with that, but I hope you will review changes because I'm getting creative here ...
Re: OpenAL Device Choices
Suggestion: commit the code to a new branch (branches/openal-next or something). Both easier to review and more fine-grained commits this way (instead of a single, large code dump in the end).
IIRC, the design-guidelines suggest to avoid 'Get' in properties, i.e. DeviceName instead of GetDeviceName (the latter is fine if it is a function, however).
Are you planning to add capture functionality? Do capture contexts share functionality with plain contexts or do they use completely different APIs? (never used OpenAL capture before. Are they even called "capture contexts"?)
Re: OpenAL Device Choices
[branch]
k, but the changes are really minor (besides the refactoring of AvailableDevices).
[get]
How would you name GetAlcError? AlcError is the name of an already used enum. It does internally call Alc.GetError, so maybe simply "Error" or "FirstError"?
[capture]
IIRC the OpenAL spec likes to call playback "render" and recording "capture".
Recording does not use a context, you can only open/close the device, start/stop recording and capture the samples. No AL commands and only few Alc commands work with the recording device, i.e. you need a playback device first to query available recording devices.
I can wrap the associated commands up, but I don't think it would be a good design to include any form of threads/mainloop into the class.
It might look like this in the end:
Re: OpenAL Device Choices
[branch]
Just makes reviewing easier (there is an rss feed of new commits you can subscribe to).
[get]
I think error checking is better served by a function: context.CheckErrors() or similar to this (but see below).
[error checking]
Which conditions generate errors? Is it possible to perform all error checking inside the AudioContext and throw exceptions instead?
[capture]
The code sample you posted looks just about perfect. No threading/whatnot, just a thin wrapper over Alc.
Neither AudioContext or RecordingDevice are strictly necessary (in the sense of GraphicsContext, which *is* necessary). You could get the same results with plain Alc, only with more code for error checking). Besides, the symmetry between graphics/audio is nice.
Edit: if you actually need a playback device to create a recording device, maybe you could pass it as a (non-optional) parameter to the RecordingDevice constructor? This would enforce correct order of construction:
Re: OpenAL Device Choices
[error checking]
The system is the same as for GL, pretty much any function can generate InvalidOperation/-Enum/OutOfMemory etc.
The "automatic GL.GetError" for debug builds could be applied to AL in the same way, assuming the functions have some internal import and a public interface where to place the geterror calls.
There are also some special cases that require handling by the application, for example the user may intentionally or accidentially unplug the microphone or put it on mute. At least I do prefer testing for this condition manually rather than creating a huge try{} to encase all code where some AudioDeviceUnpluggedException could be thrown.
[capture]
There is no need for an AudioContext instance in order to use the capture extension, but AudioContext's static constructor must be called to create the dummy device/context and query available devices from the driver. This may have not been clear in the recording-example application I posted a couple of weeks ago, since it uses an AudioContext for playback anyway. But in theory (I cannot think of any good usage example for it) you could write an application that only captures microphone input but has no AudioContext to play anything back.
Re: OpenAL Device Choices
[error checking]
Automatic AL error checking will require a great amount of work (and possibly some kind of code generator). I'd prefer to postpone that until we can find a way to implement GL/AL/CL error checking in a unified way. However, AudioContext and/or RecordingDevice should probably check for ALC errors occuring in their code.
I don't think OpenAL 1.1 supports dynamic enumeration of devices, i.e. the list of available recording or playback devices won't change once OpenAL is initialized. I really have no idea how OpenAL will react upon removal of a device. For example, Windows Vista will reroute audio to another device automatically, but I'm not sure if OpenAL can detect that.
Have you tried disconnecting the microphone while capture is running? Does it result in an error or does the application continue as if nothing happened?
[capture]
My mistake, I assumed recording devices needed a playback context. Since they don't, maybe it would make sense to enumerate recording devices inside the RecordingDevice constructor instead of the AudioContext one?
Re: OpenAL Device Choices
How about the name "AudioRecorder" instead of "RecordingDevice"? Then we'd have AudioContext for playback and AudioRecorder for recording. Maybe even refactor AudioContext to AudioPlayback?
[error checking]
How about some
bool ThrowOnError? I'd prefer that over forcing exceptions to be default behaviour.[unplugged]
IIRC Alc.CaptureStart will generate an Alc Error if no microphone is connected, but opening the device worked. Haven't tried unplug it during capturing and currently the mic is not working (did I already say that installing the card is a bitch and that I miss the the days where you had to RTFM, jumper the card's IRQ and it worked after that, instead of Plug&Pray?)
[enumeration]
From the isolation-perspective that would certainly be the best choice, but from an efficiency-perspective it is horrible: 2 dummy contexts would be created and destroyed, devices must be protected from both static constructors accessing the device at the same time and also only a fraction of OpenTK applications do use Audio, even less will use the recording capabilities.
I'd rather add a get-property to the AudioRecorder that pulls the information from AudioContext's properties. Like I said before I cannot think of any good usage example that would want to use recording capabilities but no playback.
Re: OpenAL Device Choices
[AudioRecorder vs RecordingDevice]
AudioRecorder is much better than RecordingDevice. The documentation refers to it as 'capture', so AudioCapture is another good option.
No point in renaming AudioContext, since it agrees with the documentation (alcCreateContext). It's also nicely symmetrical with GraphicsContext.
[error checking]
I can see this working for automatic AL error checking (just like you can turn off GL exceptions), but how would this work inside e.g. AudioContext? For example if alcOpenDevice fails in the AudioContext constructor, you don't have any option other than throwing an exception. If you don't throw, the AudioContext will be constructed successfully but remain invalid - which is all kinds of wrong.
[unplugged]
Isn't this a PCIe card? How can it be so difficult to install? :/
The ideal solution would be to have a DeviceUnplugged event that you can subscribe to. Unfortunately, OpenAL doesn't offer any notification mechanism, so the only way to discover an unplugged device is to try and use it - and by that time it's already too late for a notification.
[enumeration]
You are right, no point in creating two dummy contexts (I don't even want to think what this would do to buggy implementations).
Arguably, we could add a common, non-public class accessed by both AudioContext and AudioRecorder/Capture/whatever.
Re: OpenAL Device Choices
AudioCapture it is.
[enumeration]
I've created a branch like you suggested, stripped off all GL/CL/Input/Platform stuff so it builds fast ;) I forgot to add in the description that it's based on 0.9.9 though, but I believe this is not a problem since not much happend to OpenTK.Audio in previous releases.
Don't bother read it yet though, it's quite a mess. Just wanted to back it up before moving the device detection into the new class. I'll take your advice and move the static stuff into AudioDeviceEnumerator class.
[error checking]
Agreed, it is absolutely necessary to throw for errors at device initialization. But during "normal" program operation no AL or Alc Error should occur (or potential exceptions requiring try/catch), it's the programmers responsibility to query device capabilities at initialization time and chose an appropriate codepath that will execute error-free (just like for GL).
Btw. is it ok if I use AudioDeviceException for AudioCapture too? Or rather create new ones?
[DeviceUnplugged]
This would be quite interesting to have, I will take a look where exactly the alc error occurs when unplugging the mic (once it works). Since the user will regularly use the AvailableSamples property and the GetSamples method (and I think that's where Alc errors related to unplugged devices will occur) it should be doable to use an event. Detecting when a device is plugged in again will be trickier but should be doable aswell.
[hardware]
It's an PCI card, all PCIe slots are covered by the graphics card and no card would possibly fit in there without a saw, hammer and alot of brute force. The compatibility problems appear to be related to the mainboard's chipset (according to creative labs forums), but the drivers also have alot more tweaking options than the onboard sound ones, so I'm positive it will work perfectly after some patient experimentation.
Mind the card has more input/output connectors than I can count (it has a 5.25" front panel too), it may be as simple as disabling some input/output channels for everything to work as intended.
Re: OpenAL Device Choices
[error checking]
I think AudioDeviceException would work fine for 'InvalidDevice' types of errors.
[DeviceUnplugged]
My only hesitation is whether it's possible to make this 100% reliable, i.e. always trigger the event when a device is unplugged/plugged. It will be great if this is possible but if not, I think it's better to avoid this.
[hardware]
I can't say I'm surprised about motherboard incompatibilities. Apart from my old, trusty SB16, I've never seen a Creative card that hasn't had *some* kinds of incompatibilities. Fortunately, they generally work fine once you get them to work. :)
On the other hand, I never cease to wonder why 1x PCIe slots always lie at positions covered by video cards. My only free PCIe slot lies somewhere between the CPU, the motherboard and the GPU cooler (the only saving grace is the lack of cooling fans!)
Edit: you can subscribe to the commit feed at http://cia.vc/stats/project/opentk/.rss, if you wish to be notified of updates automatically.
Re: OpenAL Device Choices
What's the purpose of
bool openal_supported? Merely track whether the dll is present? or should it also include whether device detection failed/succeeded?[AudioDeviceException]
I'm only using it for errors related to OpenDevice-alike functions.
[hardware]
Only the more-recent X-Fi Titanium has PCIe, I've got the older X-Fi Platinum series. The sound quality is truely an upgrade compared to onboard sound. In Doom3, I found myself running back a couple of rooms that were already cleared, because I heard a zombie that I had overlooked in the dark. That were about 30-40m distance with walls inbetween, but I knew exactly where to find it. When realizing that I was like: O.o
Reverb and Headphones certainly make a difference.
Motherboard designs are probably like that to fit as many slots as possible on as little space as possible. I do agree that it might be the better design not to squeeze all PCIe slots next to each other since graphic card's cooling starts to get ridiculously huge. I've no idea how I'd fit some SLI/Crossfire in there.
[RSS]
I've bookmarked the url, but I rather do a few clicks to get information than getting it when I don't want&|care . The very first thing I disable after installing vista is the sidebar.
[MacOS/Linux]
I take it the only way to test whether the changes I made run on other platforms are me installing the OS? I'm afraid of Unices.
Re: OpenAL Device Choices
'Openal_supported' merely tracks the presence of the dll. There is a chance that OpenAL may be supported (or 'supported' as far as drivers go) without the enumeration extension. In that case, I think the device lists should return only a single device (named e.g. 'Default' or 'Unknown') without any enumeration taking place (always use alcOpenDevice(null)).
No reason to ban OpenAL 1.0 outright.
[MacOS/Linux]
VirtualBox 3.0 (beta) + Ubuntu 9.04 = win. You get OpenGL 2.0, audio, network and everything else you might need (plus you'll get to love the terminal :p).
Hint: install necessary applications first.
and then install the 'guest additions' of VirtualBox (for 3d and copy&paste support):
Finally fetch opentk:
(In case you wonder, I do this procedure once or twice a day. It keeps me in shape :p)
Re: OpenAL Device Choices
When using the word "afraid" I did not mean "scared". Rather "concerned" that Linux has the same effect on me like a shot of heroine for an ex-junkie who has lived happily with methadon before. ;)
Thanks for the crashcourse, I will at least confirm that the changes work as intended on Linux. But I won't buy MacOS - which I don't need - just to go through the horrors of driver installation a 3rd time.
VS 2010 is also a good way to stay in shape, since they somehow broke IntelliSense (compared to VC# 2005 EE). Often you need to type letters first before intellisense will accept confirmation of the choice by the enter key, but using the mouse you can select and confirm at all times. With VC# 2005 the only times I use the mouse is with forms or moving c&p, so VS2010 does actually slow me down :|
Re: OpenAL Device Choices
Can you please run this test application and c&p the output in here?
I have not worked any further on the AudioCapture class so far, but rather wrote this diagnostic that should help identify any OpenAL related problems much easier. It's missing capture-related tests atm, but I'll write those while working further on AudioCapture.
Idk whether it should be polished and become part of OpenTK.Audio, or simply add it to the example launcher. Either is fine with me, but we really need something like this in the distribution.
Edit: OFCOURSE I forgot to add the dll-config file. :)
Re: OpenAL Device Choices
Ok, ran this on Ubuntu 9.04 amd64 (OpenAL Soft 1.4).
Two things seem to fail:
(Use wordpad to open the file)
Re: OpenAL Device Choices
I've got the same problem with AL.DeleteSources() with the OpenAL Soft x86, it works flawless with creative lab's driver tho. Will meditate over this.
"AL lib: alsa.c:564: set access failed: Invalid argument"
I take it alsa is the linux equivalent to directsound for windows?
Do you have a microphone plugged in?
Re: OpenAL Device Choices
Yep, alsa is something like directsound and no, I forgot to plug my microphone.
Re: OpenAL Device Choices
Regarding capture, all the test does atm is open and close the device. It does not throw the exception on my PC, the mic is connected but it doesn't work in any application (and yes, it's neither muted nor at min. volume).
You didn't comment whether you'd like this to become part of the example launcher, I guess you want a cutie fluffy WinForms UI for it? Tell me, I can take it.