Poor audio quality when playing sounds via XAudio2?

Started by
8 comments, last by Aressera 5 years, 4 months ago

I'm making a game (shameless plug) that uses a custom game engine whose audio subsystem is built on top of XAudio2. For this game, I made a new explosion sound effect .wav file in Adobe Audition (a simple 44100 hz 32-bit float uncompressed wav), which I have attached to this post. I noticed that when playing the .wav file via my game, the sound effect is much lower quality than when playing it in Audition, lacking much of its original detail. So I did some more testing, trying it in a handful other programs. When that exact same .wav file is played in Unity3D or Google Chrome, it sounds great! (Though, interestingly, when played in Windows Media Player or VLC, it lacks detail much as it does when played via my game.) I have reproduced this on two different computers that have totally different sound hardware.

My first assumption was, of course, that I had screwed up something in my XAudio2 code. First, I double-checked to make sure that the sample rate of the .wav file matched that of my mastering voice, which it does (they're both 44100 hz), and then I played around with a variety of higher and lower sample rates, both for the .wav file and for the mastering voice. Unable to find any obvious issues in my own code but still figuring I screwed up somewhere, I then decided to sanity-check using Microsoft's XAudio2 sample code (specifically the "XAudio2BasicSound" example which does little more than load and play a few different sound effects) with my .wav file and, much to my surprise, the audio quality was just as poor as in my own game.

So now I'm wondering, is XAudio2 just bad, or is there anything I can do to improve its audio quality? (If someone knows how to improve the audio quality of Microsoft's sample code, then I can almost certainly make that same improvement in my own engine.) Or would I be better off using a different API?

Thanks for your help & advice!

explosion.wav

Advertisement
3 hours ago, Holy Fuzz said:

I'm making a game (shameless plug) that uses a custom game engine whose audio subsystem is built on top of XAudio2. For this game, I made a new explosion sound effect .wav file in Adobe Audition (a simple 44100 hz 32-bit float uncompressed wav), which I have attached to this post. I noticed that when playing the .wav file via my game, the sound effect is much lower quality than when playing it in Audition, lacking much of its original detail. So I did some more testing, trying it in a handful other programs. When that exact same .wav file is played in Unity3D or Google Chrome, it sounds great! (Though, interestingly, when played in Windows Media Player or VLC, it lacks detail much as it does when played via my game.) I have reproduced this on two different computers that have totally different sound hardware.

My first assumption was, of course, that I had screwed up something in my XAudio2 code. First, I double-checked to make sure that the sample rate of the .wav file matched that of my mastering voice, which it does (they're both 44100 hz), and then I played around with a variety of higher and lower sample rates, both for the .wav file and for the mastering voice. Unable to find any obvious issues in my own code but still figuring I screwed up somewhere, I then decided to sanity-check using Microsoft's XAudio2 sample code (specifically the "XAudio2BasicSound" example which does little more than load and play a few different sound effects) with my .wav file and, much to my surprise, the audio quality was just as poor as in my own game.

So now I'm wondering, is XAudio2 just bad, or is there anything I can do to improve its audio quality? (If someone knows how to improve the audio quality of Microsoft's sample code, then I can almost certainly make that same improvement in my own engine.) Or would I be better off using a different API?

Thanks for your help & advice!

explosion.wav

Maybe it uses the wrong or different audio device? Or some wrong format conversions ? Default settings are not always the best!

Does the wave file play properly with mini_al.h ? (Mini-al supports WASAPI, which XAudio is based on).

6 hours ago, Finalspace said:

Maybe it uses the wrong or different audio device? Or some wrong format conversions ? Default settings are not always the best!

I tried creating a mastering voice for every audio device listed for both my computers at various sample rates (44100, 48000, 96000) and channels (1 and 2), everything I've tried exhibits the same low quality. Not sure what other settings I can try?

6 hours ago, Finalspace said:

Does the wave file play properly with mini_al.h ? (Mini-al supports WASAPI, which XAudio is based on).

Nope, mini_al.h has the same low quality using their "Simple Playback Example".

43 minutes ago, Holy Fuzz said:

I tried creating a mastering voice for every audio device listed for both my computers at various sample rates (44100, 48000, 96000) and channels (1 and 2), everything I've tried exhibits the same low quality. Not sure what other settings I can try?

Nope, mini_al.h has the same low quality using their "Simple Playback Example".

I tested your sound file and i had the issue when playing it with the BASS audio library, which i have no idea what backend they are using. Maybe they use XAudio as well and for some reason, that wave file of yours will break XAudio?

 

But everything else had no issues whatsoever. I also tested several configurations, including my platform abstraction library (FPL), which just uses pure directsound and there was no issue at: https://github.com/f1nalspace/final_game_tech/tree/develop/demos/FPL_Audio

(If you want to try that demo out, just pass the full path to the wave file as argument to the executable - after you have compiled it) -> I recommend cloning the repo, so you have all the header files you need.

 

I tested it with a sample rate of 44100 Hz, the formats (S16, S32, F32) and one or two channels. All backends, WASAPI, DirectSound, even WinMM had no sound issue with that configuration at all - and i tested it with a really crap bluetooth audio headset with integrated audio output device O_o

 

Can you please verify that:

https://github.com/f1nalspace/final_game_tech/tree/develop/demos/FPL_Audio

and

https://github.com/f1nalspace/final_game_tech/tree/develop/demos/FPL_MiniAL

 

works or not? I changed the mini_al sample to use DirectSound first and WASAPI second.

 

If nothing of that works, i would recommend creating a very small C/C++ project which just loads your wave file, parses it and plays it back using XAudio - including source, so we may can help you better?

23 minutes ago, Finalspace said:

But everything else had no issues whatsoever. I also tested several configurations, including my platform abstraction library (FPL), which just uses pure directsound and there was no issue at: https://github.com/f1nalspace/final_game_tech/tree/develop/demos/FPL_Audio

(If you want to try that demo out, just pass the full path to the wave file as argument to the executable - after you have compiled it) -> I recommend cloning the repo, so you have all the header files you need.

Not working for me, it sounds the same as XAudio2.

To be clear, it's not obviously incorrect if you don't know how it's *supposed* to sound -- it's not distorted or anything, still sounds like an explosion, just lacking its original crunchy detail. But at least on my computers, there's a clear difference between playing it in XAudio2, FPL_Audio, or mini_al and playing it in Audition, Unity3D, or Chrome.

32 minutes ago, Finalspace said:

https://github.com/f1nalspace/final_game_tech/tree/develop/demos/FPL_MiniAL

 

works or not? I changed the mini_al sample to use DirectSound first and WASAPI second.

Doesn't work either. :(

Thanks for your help trying to figure this out, it's pretty puzzling.

Okay, so I have a hypothesis! This particular sound file uses clipping to give an intentional "crunchy" texture to the sound:

image.thumb.png.59e1f34ffe7bc58c357a6688484af500.png

My hypothesis is that different APIs/libraries have different ways of handling clipping in sounds when the waveform goes out of range, and that XAudio2/FPL_Audio/mini_al (or their underlying technologies) handle clipping differently than Audition/Unity3D/Chrome. (Or perhaps it's a difference with how the wave file is loaded? Maybe some wav loaders handle clipping differently.) If I reduce the volume of the sound such that it no longer clips, then it sounds pretty much the same regardless of where I play it.

As an experiment, I tried saving as 16-bit int instead of 32-bit float, and now it sounds great regardless of where I play it! So at least I have a solution that works for me! :) (Though I still wish I understood the underlying problem, why and what the difference is.)

Just a guess but a float may be storing what you think is a 'clipped' value outside the e.g. -1 to 1 range, and what the audio does with the value outside this range may be ill defined. It might be if you play a noise that goes to 2 in the float data, at half volume, it is no longer clipped. Or the audio system might be applying a soft knee or compression.

In short, one of the things that float audio is particularly good at, is not clipping. So if you want it clipped, you probably have to ask it to be clipped somewhere in your audio creation.

Nigel Tufnel explains it much better than me:

 

10 minutes ago, lawnjelly said:

Just a guess but a float may be storing what you think is a 'clipped' value outside the e.g. -1 to 1 range, and what the audio does with the value outside this range may be ill defined. It might be if you play a noise that goes to 2 in the float data, at half volume, it is no longer clipped.

Oh I'm pretty confident this is exactly what's happening, which is why converting to int fixes it. What I now wish I understood better is how exactly different audio technologies interpret/define these out-of-range values.

What is going on is that XAudio (and WASAPI shared mode) has built-in dynamic range limiting. It is applying a dynamic range limiter/compressor to your audio to avoid the distortion that comes with clipping float data to [-1,1], by reducing the gain of the signal in a level-dependent way. When the signal level approaches -1 or 1, the limiter must reduce the signal gain in anticipation of clipping (this is the compression knee) to produce a smoother gain reduction. This causes loud transients such as your explosion sound to be softened or to lose impact/attack.

This topic is closed to new replies.

Advertisement