kcat / openal-soft

OpenAL Soft is a software implementation of the OpenAL 3D audio API.
Other
2.2k stars 530 forks source link

Arma: Cold War Assault for Linux -- audio sources looping (v1.22.2) #831

Open QmwJlHuSg9pa opened 1 year ago

QmwJlHuSg9pa commented 1 year ago

OS: Fedora Silverblue 37.

Arma: CWA for Linux (Steam) includes libopenal-soft.so.1, which appears to be v1.17.2 (i686). This seems to perform correctly.

Though, replacing this file with the latest v1.22.2 build (i686, from Fedora 37 repo) results in many audio sources looping their first several seconds of audio. This is very noticeable whenever scripted music or NPC dialogue plays.

https://store.steampowered.com/app/594550/Arma_Cold_War_Assault_MacLinux/

Edit: The issue seems to have been introduced with v1.18.0, whereas the v1.17.2 build from Fedora repo seems to work fine.

kcat commented 1 year ago

If you're able to build from source, can you test of it works with commit 1e5af1eb2f8334045e71a831f98424f1eb19854a? If it's a 32-bit game, make sure to build it as 32-bit.

QmwJlHuSg9pa commented 1 year ago

Thanks for writing back. I'm a bit of a noob at this, and so I'm stuck with the following errors:

[ 10%] Built target common
[ 10%] Built target build_version
[ 89%] Built target OpenAL
[ 90%] Linking C executable openal-info
/usr/bin/ld: libopenal.so.1.23.0: error adding symbols: file in wrong format
collect2: error: ld returned 1 exit status
gmake[2]: *** [CMakeFiles/openal-info.dir/build.make:98: openal-info] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:197: CMakeFiles/openal-info.dir/all] Error 2
gmake: *** [Makefile:136: all] Error 2

Here's the approximate process I'd followed up till this point (within a fresh Toolbox env.):


git clone https://github.com/kcat/openal-soft.git
cd openal-soft/
git reset --hard 1e5af1eb2f8334045e71a831f98424f1eb19854a

sudo dnf install gcc-c++ cmake libgcc.i686 glibc-devel.i686

export CFLAGS=-m32

cd build/
cmake ..
cmake --build .
kcat commented 1 year ago

You should set CXXFLAGS=-m32 too (and maybe LDFLAGS=-m32?). And make sure the appropriate 32-bit dev packages are installed for whatever audio system you use (PipeWire, PulseAudio, plain ALSA, etc), so that OpenAL can use it.

QmwJlHuSg9pa commented 1 year ago

I went and set both of those variables, then installed pulseaudio-libs-devel.i686 and alsa-lib-devel.i686, which were subsequently detected by cmake (though, I couldn't figure out the appropriate package for PipeWire). Still, the error messages haven't changed at all.

kcat commented 1 year ago

CMake might need a toolchain file to compile code as 32-bit from 64-bit. Clear the build directory, and put this in some file (e.g. xcompile32.txt):

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_SYSTEM_PROCESSOR "i686")

set(CMAKE_CXX_COMPILER_ARG1 "-m32")
set(CMAKE_C_COMPILER_ARG1 "-m32")

Then run cmake using the toolchain:

cmake .. -DCMAKE_TOOLCHAIN_FILE=../xcompile32.txt <extra cmake args>

You only need to pass -DCMAKE_TOOLCHAIN_FILE=../xcompile32.txt the first time configuring the project, the project's cache remembers the settings.

QmwJlHuSg9pa commented 1 year ago

My bad, I had neglected to install dbus-devel.i686.

The following was enough to create a working 32-bit library:

git clone https://github.com/kcat/openal-soft.git
cd openal-soft/
git reset --hard 1e5af1eb2f8334045e71a831f98424f1eb19854a

sudo dnf install gcc-c++ cmake dbus-devel.i686 libgcc.i686 glibc-devel.i686 pulseaudio-libs-devel.i686 alsa-lib-devel.i686

export CFLAGS=-m32
export CXXFLAGS=-m32

cd build
cmake ..
cmake --build .

Though unfortunately, the commit did not fix the "looping audio" issue.

kcat commented 1 year ago

It looks like the game uses the old AL_SOFT_buffer_sub_data extension to stream music and longer dialog clips over a looping buffer, but that isn't supported anymore since it conflicts with the AL_EXT_SOURCE_RADIUS extension.

Luckily, the alBufferSubDataSOFT function itself is still there in the library, but it tries to query the AL_BYTE_RW_OFFSETS_SOFT property, which is actually AL_SOURCE_RADIUS now so it doesn't get the expected offset values to update the buffer. I could possibly add a game_compat config option to restore AL_SOFT_buffer_sub_data and disable AL_EXT_SOURCE_RADIUS. It would just need a flag to restore the AL_BYTE_RW_OFFSETS_SOFT and AL_SAMPLE_RW_OFFSETS_SOFT queries in place of the AL_SOURCE_RADIUS query.

kcat commented 1 year ago

Commit 186a29b77d8ec01c14d13797f9d51c7c21b22b60 adds such a compat option. You can either set the __ALSOFT_ENABLE_SUB_DATA_EXT env var to 1 or true, or set

[game_compat]
enable-sub-data-ext = true

in an app-local alsoft.conf.

QmwJlHuSg9pa commented 1 year ago

Sorry, I had forgotten to follow this up till now.

The 186a29b commit, with variable set, appears to be working well! My only issue at this point is that I'm unable to enable EAX, neither ingame, nor through the enableEAX config variable -- the game keeps resetting it to 0. Assuming this option isn't outright broken in the Linux port, is it possible to get this working?

kcat commented 1 year ago

EAX is probably disabled in the Linux port. EAX properties are set through GUIDs, which is a structure defined by Windows' headers, and the official eax headers use them. A game could theoretically define GUID structures and stuff itself, but I doubt many/any bother. And there's an additional issue with 64-bit apps, as a number of EAX properties are or include long types, which is 32-bit on Windows and 64-bit on most non-Windows systems (so depending on how the app handles those properties, it may have the wrong size for the properties when built as 64-bit).

As an aside, I am wondering now if OpenAL Soft should try to detect if it's playing this game and auto-enable the compatibility setting by default. It would be the first time OpenAL Soft has a game-specific behavior change, but it would avoid having to make people set the compat option manually.

QmwJlHuSg9pa commented 3 months ago

As an aside, I am wondering now if OpenAL Soft should try to detect if it's playing this game and auto-enable the compatibility setting by default. It would be the first time OpenAL Soft has a game-specific behavior change, but it would avoid having to make people set the compat option manually.

I've been pondering this further. There seems to be numerous games that require fixes (I've noticed there's a couple with axis inversion requirements, etc.). It might not be a bad idea to try this, with options to override per-game fixes via config files (global or local) and env. vars. Windows and Wine rely upon their own "shims", as it stands, and I've seen multiple emulators employ similar strategies. It would also reduce burden on maintainers of game install scripts (e.g. Lutris, POL, ./play.it).