Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Frequent audio popping and clicking sounds in most games. #12705

Open
orbea opened this issue Mar 12, 2020 · 49 comments · Fixed by #12916
Open

Frequent audio popping and clicking sounds in most games. #12705

orbea opened this issue Mar 12, 2020 · 49 comments · Fixed by #12916
Labels
Platform-specific (Linux/POSIX) Platform-specific (Mac OS X) Qt Issue on Qt but not all ports. SDL2 Issue on SDL (or Qt in SDL code) but not all ports.
Milestone

Comments

@orbea
Copy link
Contributor

orbea commented Mar 12, 2020

What happens?

In many (Most?) games I experience often frequent minor audio popping and clicking sounds. This is highly distracting and makes it harder to enjoy games.

I have tried most settings and the only one that seems to make any clear impact is disabling Audio sync (resampling) which only helps a little. Both OpenGL and Vulkan are affected as well as both the SDL and Qt frontends. I also tried PR #12602 which did not help.

I tried going back to v1.0 without finding a good commit.

I can always reproduce it on the title screen for Lunar Silver Star Harmony where the FPS and speed counter is a solid 60 and 100% respectively.

Other games I have experienced in are:

  • Growlanser: Wayfarer of Time
  • Legend of Heroes Ao no Kiseki
  • Nayuta: Endless Trails
  • Riviera The Promised Land
  • Tales of Eternia (Rare)
  • Tales of Rebirth
  • Tekken 6 (Rare)
  • Valkyrie Profile

One game I have not noticed it in is Guilty Gear XX Accent Core Plus.

What should happen?

Audio should be smooth and not suffer from popping or clicking sounds.

What hardware, operating system, and PPSSPP version? On desktop, GPU matters for graphical issues.

OS: Slackware64-current
GPU: RX Vega 56
CPU: AMD FX-6350
compiler: clang-10.0.0, gcc-9.2.0
mesa: https://github.com/mesa3d/mesa/commit/461ee852486da724c79c5145fa2e50bdfa54aa55
llvm: 10.0.0
alsa-lib: 1.2.1.2
Qt: 5.14.1
SDL: 2.0.10
ppsspp: d0e2aa3

@orbea
Copy link
Contributor Author

orbea commented Mar 12, 2020

Issues #9736 and #10865 seem familiar, but maybe are different.

@ghost
Copy link

ghost commented Mar 12, 2020

Can this PR #8717 helps this issue?
sorry for asking 😅

@orbea
Copy link
Contributor Author

orbea commented Mar 12, 2020

That PR has a lot of conflicts making it harder to test, but thanks for pointing it out!

@quicksilver7837
Copy link

I get the same behavior running ppsspp on my raspberry pi 4. Certain games even when running fullspeed, the audio will make popping noises. The audio pops even when the sample audio plays for certain games while navigating the game selection menu.

@unknownbrackets
Copy link
Collaborator

Well, even if you see 60/60 or 100%, that's an average. If you drop a single frame, you'll probably hear a pop even if you don't see it visually and even if it isn't enough to change the average.

If you enable the devmenu button in developer settings, you can turn on a "frame times" graph. Do the pops correspond with that graph in any way?

-[Unknown]

@quicksilver7837
Copy link

quicksilver7837 commented Mar 15, 2020

It's hard to tell, though that does make sense. However, why would the sound be popping when it plays the preview audio on some titles in the game select area of the ppsspp menu? It's only playing audio and nothing is happening on the screen so I can't imagine it's that taxing, though I am not an expert on the matter.

@orbea
Copy link
Contributor Author

orbea commented Mar 15, 2020

Well, even if you see 60/60 or 100%, that's an average. If you drop a single frame, you'll probably hear a pop even if you don't see it visually and even if it isn't enough to change the average.

Sometimes it shows 99.9% or 100.1%, but this not seem to directly correspond to the pops.

If you enable the devmenu button in developer settings, you can turn on a "frame times" graph. Do the pops correspond with that graph in any way?

No, it does not seem to correspond to the graph in any way.

@orbea
Copy link
Contributor Author

orbea commented Mar 15, 2020

@unknownbrackets Actually with the audio debug from the dev menu, the number of overruns will increase by one with every pop.

1

@unknownbrackets
Copy link
Collaborator

Is the sample rate constant at 44100 or does it fluctuate slightly within +/- 10? Are you often seeing audio buffer above 2000 or is it usually below 2000 and sometimes jumping above 2000?

An overrun would mean audio buffer went up to 8192/8192. That basically shouldn't happen.

Architecturally, it works like this:

  • The PSP game produces audio data in small bursts, and sends this to PPSSPP's audio system.
  • PPSSPP resamples this (if necessary) to keep it smooth, and keeps it in a buffer - that's the 8192 number.
  • The platform glue (this part differs on SDL, Qt, retroarch, Windows, Android, iOS, etc.) pulls this data off the buffer whenever it is ready to play more audio, and sends it to the OS.

Often a larger buffer is needed to bluetooth or wireless audio, because it can't stream audio quite as immediately. This is why it's 8192 - it should not normally use that much buffer unless you have audio latency somewhere in your setup.

An overrun means that the buffer was full. So it means that the platform glue or OS was not taking enough data fast enough. An underrun would mean the opposite - that the emulation wasn't keeping up, and couldn't produce enough audio to keep the buffer moving.

It's possible this is an issue only with SDL and Qt.

To confirm this, it might be worth trying PPSSPP in WINE. If that works well, it really points to a problem in how data is being sent through on SDL and Qt.

-[Unknown]

@unknownbrackets unknownbrackets added the SDL2 Issue on SDL (or Qt in SDL code) but not all ports. label Mar 15, 2020
@orbea
Copy link
Contributor Author

orbea commented Mar 15, 2020

Is the sample rate constant at 44100 or does it fluctuate slightly within +/- 10?

It never changes.

Are you often seeing audio buffer above 2000 or is it usually below 2000 and sometimes jumping above 2000?

It fluctuates with such speed I can't clearly read it, but from my screenshots it seems most are between 1000 and 3000, one was nearly 4000. I do not notice it reaching 8192 at all.

To confirm this, it might be worth trying PPSSPP in WINE. If that works well, it really points to a problem in how data is being sent through on SDL and Qt.

Trying 1.9.3 in wine-staging-5.0 and I am not experiencing any clicks or pops in the Lunar title screen. The sample rate fluctuates +/-10 around 44100 and the audio buffer is equally unreadable. It is not also not constantly registering overruns.

@unknownbrackets
Copy link
Collaborator

unknownbrackets commented Mar 15, 2020

Do you have the audio resampler setting enabled (it should be on by default)? That's what would make the sample rate fluctuate, as it tries to match actual speed.

-[Unknown]

@orbea
Copy link
Contributor Author

orbea commented Mar 15, 2020

With wine it was the default so it was enabled, with SDL I had it off because it makes this problem worse. When enabled in SDL it reports the sample rate as fluctuating between about 44280 and 44300 and the problem is clearly worse.

@unknownbrackets
Copy link
Collaborator

#10865 also describes the sample rate going over 44200 and a similar issue on Android.

The resampler increases the rate if there's more data in the buffer, meaning that it's reading PSP audio data faster to drain the buffer (keep it from overrun.) In theory this means your device is playing at below 44.1kHz.

That it happens more frequently when the resampler is enabled is interesting, though. Does the audio buffer look to stay below 3000 when it's enabled? Do overruns still correlate with the pops?

-[Unknown]

@orbea
Copy link
Contributor Author

orbea commented Mar 15, 2020

Does the audio buffer look to stay below 3000 when it's enabled?

Yes, none of my screenshots showed that it even reached 3000 and many were below 1000 which I did not see with the resampler disabled.

Do overruns still correlate with the pops?

Yes, at a much increased rate. Roughly 1 per second.

@orbea
Copy link
Contributor Author

orbea commented Mar 15, 2020

Is it possible to get ppsspp to use a 48000 sample rate instead? Maybe it would work better for my device?

$ cat /proc/asound/card0/pcm0p/sub0/hw_params 
access: MMAP_INTERLEAVED
format: S32_LE
subformat: STD
channels: 2
rate: 48000 (48000/1)
period_size: 1024
buffer_size: 16384

@unknownbrackets
Copy link
Collaborator

Yes, change these two numbers:

fmt.freq = 44100;

return 44100;

This will force the resampler on, I should note. PSP games always generate 44.1kHz audio, so we must resample to another hz.

-[Unknown]

@orbea
Copy link
Contributor Author

orbea commented Mar 15, 2020

That change makes the frequency of overruns and audio pops even faster, several per second followed by short moments where the pops stop.

The Audio buffer doesn't even exceed 2000 now and one was as low as 2.

@orbea
Copy link
Contributor Author

orbea commented Mar 15, 2020

Could increasing the max buffer size of 8192 possibly help?

@orbea
Copy link
Contributor Author

orbea commented Mar 15, 2020

I tried upgrading to SDL-2.0.12 and then downgrading to 2.0.6 where neither helped. Older SDL2 releases have a build failure I did not spend much time on.

@orbea
Copy link
Contributor Author

orbea commented Mar 16, 2020

@unknownbrackets

I doubled this number to 16384.

#define MAX_SAMPLES_EXTRA (8192)

With the resampler disabled the problem seems to be fixed at first, but after a minute or two the audio buffer grows from around 2000 to over 10000 and the problem begins again. With the resampler enabled the buffer is being constantly depleted and I get frequent popping sounds, but associated with underruns instead of overruns.

@unknownbrackets
Copy link
Collaborator

I'm not sure, but does increasing or decreasing CONTROL_FACTOR help with the resampler at all?

#define CONTROL_FACTOR 0.2f // in freq_shift per fifo size offset

Maybe try 0.1f or 0.3f?

Goal should be to keep the buffer "healthy". If it goes down to 2, that's like a narrow miss - it almost went below 0. Not healthy.

I think it's overcompensating somehow.

-[Unknown]

@orbea
Copy link
Contributor Author

orbea commented Mar 17, 2020

Increasing it to 0.3f caused the sample rate to report a solid 44300 even when the resampler is enabled. Otherwise it seems roughly the same behavior.

Also now I notice that with the resampler enabled it always registered underruns, the overruns are only when its disabled.

@orbea
Copy link
Contributor Author

orbea commented Mar 17, 2020

@unknownbrackets Now that I can use libretro again I can again confirm that this is only with SDL/Qt.

With #if 0 I can confirm that this code path results in underruns.

// Drift prevention mechanism

While this results in overruns.

for (; currentSample < numSamples * 2 && ((indexW - indexR) & INDEX_MASK) > 2; currentSample += 2) {

Both have similar popping/clicking sounds. I think at least libretro is also using this code, so why is windows and libretro unaffected by this issue? I'm struggling to find what they are doing differently.

@quicksilver7837
Copy link

I can confirm. I just tested libretro ppsspp on my rpi 4 and while performance is terrible compared to standalone ppsspp there is no popping/clicking sounds.

@unknownbrackets
Copy link
Collaborator

Windows typically uses WASAPI. How it works is:

  • Platform glue has dedicated thread that waits for a few milliseconds, and sends new data to WASAPI periodically.
  • WASAPI tells us how much data it still has, we just grab enough to refill its buffer.
  • If we got less frames than WASAPI wanted, we fill the rest with padding.
  • Ultimately, NativeMix() is called with dynamic sizes at a rate within PPSSPP code's control.
  • Uses stereo resampler.

libretro is a bit simpler but similar, and more like DirectSound on Windows:

  • Platform glue periodically pauses emulation to send a small batch of audio data (512 * 2 samples) to libretro.
  • Pause is very short, but not threaded.
  • Always tries for 512 stereo samples, but if less are available we only send as many as we could to libretro. No padding.
  • Ultimately, an equivalent to NativeMix() is called with a variable size at a rate within PPSSPP code's control.
  • Uses stereo resampler.

SDL works differently, though:

  • Platform glue gives SDL the callback directly, and SDL asks for whatever data it wants when it wants it. We request a buffer of 2048 samples.
  • SDL says this will "usually" run on a dedicated thread.
  • SDL determines how many samples to request. If we get less samples than SDL wanted, we fill with padding.
  • Ultimately, NativeMix() is called by SDL at a rate and with sizes PPSSPP doesn't control.
  • Uses stereo resampler.

Maybe it would help to increase or decrease the SDL buffer size which is here:

fmt.samples = 2048;

It looks like we could use SDL_QueueAudio() in SDL 2.0.4+, which would give us more control and allow us to operate like libretro or Windows.

-[Unknown]

@orbea
Copy link
Contributor Author

orbea commented Mar 18, 2020

Thanks for the detailed explanation!

Maybe it would help to increase or decrease the SDL buffer size

I tried 4096 and 8192 which is clearly worse, the sound is broken and there are constant overrunrs and underruns. With lower values the problem seems better, with values of 512 or 256 the problem is almost if not entirely gone when the resampler is enabled. When the resampler is disabled the problem begins again after some time when the audio buffer grows in size. With a value of 1024 the problem is greatly reduced, but still occurs even with the resampler enabled. I am also seeing framerates much closer to 44100 although its still slightly too high (~44130).

Perhaps it should be changed to a lower number to help mitigate this problem regardless?

It looks like we could use SDL_QueueAudio() in SDL 2.0.4+, which would give us more control and allow us to operate like libretro or Windows.

This sounds like a potentially good idea, would you be willing to spend time making a PR to test? SDL 2.0.4 came out in January of 2016 so that is not an unreasonable version requirement and potentially the old code could be left behind a conditional for backwards compatibility?

@unknownbrackets
Copy link
Collaborator

One challenge with the queue API is fast forward: it will accept as many samples as we give it, and play them at a steady pace. So if we send too many, it may desync audio. I guess we could flush it if SDL_GetQueuedAudioSize() gets too large? We probably should do it from a thread though, given this...

-[Unknown]

@orbea
Copy link
Contributor Author

orbea commented May 17, 2020

@hrydgard Seems better on my end, thanks. The problem still seems to be present when the audio resampler is disabled, but its far less noticeable without the audio debug output.

Also there are still underruns and sometimes overruns when resuming from the ppsspp menu.

@hrydgard
Copy link
Owner

Yeah those little over and underruns with the menu are present on all platforms.

I am going to remove the ability to turn off the resampler, few platforms are so well synced that it works entirely without glitches.

@hrydgard
Copy link
Owner

@orbea Fixed a slight mistake that could cause the buffer to loop over and over if stopped, too.

@quicksilver7837
Copy link

Fixed on my end (raspberry pi 4). So much more enjoyable without the audio constantly popping. Thanks! :)

@hrydgard
Copy link
Owner

Great, thanks for testing @quicksilver7837 !

@quicksilver7837
Copy link

quicksilver7837 commented May 17, 2020

@hrydgard I may have spoken too soon. Most of the titles I tested are working great now. But just tested Castlevania Dracula X and I'm still getting popping on the game menu. 😕

Edit: turning on render duplicate frames to 60hz seems to fix it though?

@hrydgard
Copy link
Owner

Huh, that's surprising, although that option will smooth out the flow of audio packets too I guess, maybe enough to avoid it. May have to increase the margin a little further. Still seems like a good improvement overall.

@mbriar
Copy link

mbriar commented Jan 16, 2023

On linux I'm also still getting consistent underruns playing Brave Story: New Traveler, which also seems to be significantly improved by setting render duplicate frames to 60hz . It also doesn't happen at all running PPSSPP in wine.

@mbriar
Copy link

mbriar commented Jan 16, 2023

Setting

fmt.samples = 128;

in InitSDLAudioDevice() also completely fixes it for me.

@hrydgard
Copy link
Owner

Huh, the current value is 1024, very surprising that reducing it would improve things..

Might be one of those things we need to add an option for..

@mbriar
Copy link

mbriar commented Jan 16, 2023

FWIW, both the filled part of the Audio Buffer and the Effective Output sample rate in the audio debug overlay seems to be much more stable with lower fmt.samples. With the default of 1024 there is a lot of fluctuation.

@viotech3
Copy link

Can verify, only noticed it when updating to 1.14.X (4 at the moment). Star Ocean 2 has it for context.

@hrydgard hrydgard reopened this Jan 17, 2023
@hrydgard
Copy link
Owner

What bothers me about this is that 128 is a far too short buffer size to be realistic on most hardware, and it seems likely that SDL says "oh, this is too short, let's fall back to a safe value" and the result is worse audio latency. @mbriar what happens if you set it all the way down to 0?

@mbriar
Copy link

mbriar commented Jan 17, 2023

If you set it down to 0, SDL will pick a default which is around 2048 samples: https://github.com/libsdl-org/SDL/blob/SDL2/src/audio/SDL_audio.c#L1250 (and yeah, this also leads to underruns)

At least the pipewire SDL audio backend will allow samples to be as low as 32 for a frequency of 44100 (PW_MIN_SAMPLES is 32): https://github.com/libsdl-org/SDL/blob/SDL2/src/audio/pipewire/SDL_pipewire.c#L1145

With the pulseaudio backend, there appears to be no explicit clamping, but it sets PA_STREAM_ADJUST_LATENCY, the lowest I end up on the pulseaudio side using pipewire-pulse as pulseaudio server is 236 samples. However, on the SDL callback side, even ridiculously low samples are honored. If I add a printf here to print out len and set fmt.samples = 1, the callback is called with a len of 4, as expected, I guess.

FWIW, what first made me try using a lower value for samples was that I saw that the WASAPI backend updates every 5ms, and indeed ends up with 256 samples at 48000hz, or around 5ms, when run on wine (as seen in pw-top). So I guess something about the ppsspp audio backend behaves better with more frequent updates? Might be interesting to see if you can reproduce the underruns on Windows when making the WASAPI backend update less frequently.

All that said, using fmt.samples = 256 for the SDL backend also fixes the underruns for me and I suppose would be a reasonable default that brings it in line with what WASAPI defaults to. Of course making it configurable also wouldn't hurt.

Here are some comparison videos where I monitor the samples and frequency used by the pipewire audio server using pw-top next to the ppsspp audio debug overlay with different values for fmt.samples :

64 samples
ppsspp_64_samples.webm
256 samples
ppsspp_256_samples.webm
1024 samples
ppsspp_1024_samples.webm
setting 0 samples which ends up with 2048 samples
ppsspp_0_samples.webm

Notice the underruns only going up in the 1024 and 0/2048 samples case.

@hrydgard
Copy link
Owner

hrydgard commented Jan 17, 2023

Hm, interesting. Yeah I chose 1024 as what I though was some kind of safe enough default, but it seems to be worth trying 256.

I made the change.

@foundObjects
Copy link

That commit seems to have reduced random stuttering in final fantasy tactics on android quite a bit, thanks!

If you want a guaranteed repo case that'll run up thousands of underruns in short order (even after the sample change above) load up FFT to the main title menu and open the "continue" screen. Just sitting on the list of saved games screen induces underruns like crazy.

@hrydgard
Copy link
Owner

That commit should have done absolutely nothing for Android, so that's placebo :)

Thanks, good to know a good repro.

@foundObjects
Copy link

Ah, my bad. I'd turned on render duplicate frames to 60 to see if that would help with the audio issues on the load/save screen and forgot to switch it off after. That did seem to help with random audio underruns in other parts of the game.

@ghost
Copy link

ghost commented Jan 22, 2023

Might be good to move this to future-prio milestone

@hrydgard hrydgard modified the milestones: v1.10.0, Future-Prio Jan 22, 2023
@kuro0768
Copy link

Is there any updates/fixes for this yet or better ways to mitigate the effects?
Playing Growlanser 4 Wayfarer of Time and Unchained Blades using PPSSPP v1.16.6 on windows 10, the fixes I have that were recommended that I'm using are Setting the screen refresh rate to 60Hz, FPS Limit to 60FPS, and finally Render duplicate frames to 60hz on in ppsspp. I still get the popping and clicking maybe once every minute, and also an effect that I can only describe as audio "tearing", as if the audio is being slightly torn like a piece of paper.
Issues aren't super frequent, but are enough to ruin any immersion...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Platform-specific (Linux/POSIX) Platform-specific (Mac OS X) Qt Issue on Qt but not all ports. SDL2 Issue on SDL (or Qt in SDL code) but not all ports.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants