Sleep problem causing Audio pops

I'm a bit behind so I just finished the audio marathon lecture and, although my sound system timings appear to be the same as Casey's, I'm getting audio crackles and pops.

The main difference I see in the numbers is that my frame times are more erratic than Casey's (his seem to be dead on). If I just busy wait, the sound is fine and the frame times are steady. The odd thing is, if I busy wait with a positive, negative or random delta on the frame time, as long as the delta is not too big (but still much bigger than the deltas I see from the Sleep code) the sound remains fine.

Here is a comparison of the output from a clean busy wait (tries to hit frame time exactly):

BTL:7680 TC:16360 BTW:8680 - PC:1920 WC:7680 DELTA:5760 (0.030000s)
BTL:16360 TC:18280 BTW:1920 - PC:3840 WC:9600 DELTA:5760 (0.030000s)
BTL:18280 TC:25960 BTW:7680 - PC:11520 WC:17280 DELTA:5760 (0.030000s)
BTL:25960 TC:31720 BTW:5760 - PC:17280 WC:23040 DELTA:5760 (0.030000s)
BTL:31720 TC:37480 BTW:5760 - PC:23040 WC:28800 DELTA:5760 (0.030000s)
BTL:37480 TC:45160 BTW:7680 - PC:30720 WC:36480 DELTA:5760 (0.030000s)
BTL:45160 TC:50920 BTW:5760 - PC:36480 WC:42240 DELTA:5760 (0.030000s)
BTL:50920 TC:58600 BTW:7680 - PC:44160 WC:49920 DELTA:5760 (0.030000s)
BTL:58600 TC:64360 BTW:5760 - PC:49920 WC:55680 DELTA:5760 (0.030000s)
BTL:64360 TC:70120 BTW:5760 - PC:55680 WC:61440 DELTA:5760 (0.030000s)
BTL:70120 TC:77800 BTW:7680 - PC:63360 WC:69120 DELTA:5760 (0.030000s)
BTL:77800 TC:83560 BTW:5760 - PC:69120 WC:74880 DELTA:5760 (0.030000s)
BTL:83560 TC:91240 BTW:7680 - PC:76800 WC:82560 DELTA:5760 (0.030000s)
BTL:91240 TC:97000 BTW:5760 - PC:82560 WC:88320 DELTA:5760 (0.030000s)
BTL:97000 TC:102760 BTW:5760 - PC:88320 WC:94080 DELTA:5760 (0.030000s)
BTL:102760 TC:110440 BTW:7680 - PC:96000 WC:101760 DELTA:5760 (0.030000s)
BTL:110440 TC:116200 BTW:5760 - PC:101760 WC:107520 DELTA:5760 (0.030000s)
BTL:116200 TC:121960 BTW:5760 - PC:107520 WC:113280 DELTA:5760 (0.030000s)
BTL:121960 TC:129640 BTW:7680 - PC:115200 WC:120960 DELTA:5760 (0.030000s)
BTL:129640 TC:135400 BTW:5760 - PC:120960 WC:126720 DELTA:5760 (0.030000s)
BTL:135400 TC:143080 BTW:7680 - PC:128640 WC:134400 DELTA:5760 (0.030000s)
BTL:143080 TC:148840 BTW:5760 - PC:134400 WC:140160 DELTA:5760 (0.030000s)
BTL:148840 TC:156520 BTW:7680 - PC:142080 WC:147840 DELTA:5760 (0.030000s)
BTL:156520 TC:162280 BTW:5760 - PC:147840 WC:153600 DELTA:5760 (0.030000s)
BTL:162280 TC:168040 BTW:5760 - PC:153600 WC:159360 DELTA:5760 (0.030000s)
BTL:168040 TC:175720 BTW:7680 - PC:161280 WC:167040 DELTA:5760 (0.030000s)
BTL:175720 TC:181480 BTW:5760 - PC:167040 WC:172800 DELTA:5760 (0.030000s)
BTL:181480 TC:187240 BTW:5760 - PC:172800 WC:178560 DELTA:5760 (0.030000s)
BTL:187240 TC:2920 BTW:7680 - PC:180480 WC:186240 DELTA:5760 (0.030000s)
BTL:2920 TC:8680 BTW:5760 - PC:186240 WC:0 DELTA:5760 (0.030000s)


And the output from the Sleep code that tries to hit the frame time (and has lots of audio cracks and pops):

BTL:5760 TC:14440 BTW:8680 - PC:0 WC:5760 DELTA:5760 (0.030000s)
BTL:14440 TC:18280 BTW:3840 - PC:3840 WC:9600 DELTA:5760 (0.030000s)
BTL:18280 TC:24040 BTW:5760 - PC:9600 WC:15360 DELTA:5760 (0.030000s)
BTL:24040 TC:31720 BTW:7680 - PC:17280 WC:23040 DELTA:5760 (0.030000s)
BTL:31720 TC:37480 BTW:5760 - PC:23040 WC:28800 DELTA:5760 (0.030000s)
BTL:37480 TC:47080 BTW:9600 - PC:32640 WC:38400 DELTA:5760 (0.030000s)
BTL:47080 TC:50920 BTW:3840 - PC:36480 WC:42240 DELTA:5760 (0.030000s)
BTL:50920 TC:58600 BTW:7680 - PC:44160 WC:49920 DELTA:5760 (0.030000s)
BTL:58600 TC:66280 BTW:7680 - PC:51840 WC:57600 DELTA:5760 (0.030000s)
BTL:66280 TC:70120 BTW:3840 - PC:55680 WC:61440 DELTA:5760 (0.030000s)
BTL:70120 TC:75880 BTW:5760 - PC:61440 WC:67200 DELTA:5760 (0.030000s)
BTL:75880 TC:83560 BTW:7680 - PC:69120 WC:74880 DELTA:5760 (0.030000s)
BTL:83560 TC:91240 BTW:7680 - PC:76800 WC:82560 DELTA:5760 (0.030000s)
BTL:91240 TC:97000 BTW:5760 - PC:82560 WC:88320 DELTA:5760 (0.030000s)
BTL:97000 TC:102760 BTW:5760 - PC:88320 WC:94080 DELTA:5760 (0.030000s)
BTL:102760 TC:110440 BTW:7680 - PC:96000 WC:101760 DELTA:5760 (0.030000s)
BTL:110440 TC:116200 BTW:5760 - PC:101760 WC:107520 DELTA:5760 (0.030000s)
BTL:116200 TC:121960 BTW:5760 - PC:107520 WC:113280 DELTA:5760 (0.030000s)
BTL:121960 TC:129640 BTW:7680 - PC:115200 WC:120960 DELTA:5760 (0.030000s)
BTL:129640 TC:135400 BTW:5760 - PC:120960 WC:126720 DELTA:5760 (0.030000s)
BTL:135400 TC:143080 BTW:7680 - PC:128640 WC:134400 DELTA:5760 (0.030000s)
BTL:143080 TC:148840 BTW:5760 - PC:134400 WC:140160 DELTA:5760 (0.030000s)
BTL:148840 TC:158440 BTW:9600 - PC:144000 WC:149760 DELTA:5760 (0.030000s)
BTL:158440 TC:162280 BTW:3840 - PC:147840 WC:153600 DELTA:5760 (0.030000s)
BTL:162280 TC:171880 BTW:9600 - PC:157440 WC:163200 DELTA:5760 (0.030000s)
BTL:171880 TC:175720 BTW:3840 - PC:161280 WC:167040 DELTA:5760 (0.030000s)
BTL:175720 TC:181480 BTW:5760 - PC:167040 WC:172800 DELTA:5760 (0.030000s)
BTL:181480 TC:189160 BTW:7680 - PC:174720 WC:180480 DELTA:5760 (0.030000s)
BTL:189160 TC:2920 BTW:5760 - PC:180480 WC:186240 DELTA:5760 (0.030000s)
BTL:2920 TC:10600 BTW:7680 - PC:188160 WC:1920 DELTA:5760 (0.030000s)
BTL:10600 TC:16360 BTW:5760 - PC:1920 WC:7680 DELTA:5760 (0.030000s)
BTL:16360 TC:24040 BTW:7680 - PC:9600 WC:15360 DELTA:5760 (0.030000s)
BTL:24040 TC:31720 BTW:7680 - PC:17280 WC:23040 DELTA:5760 (0.030000s)
BTL:31720 TC:37480 BTW:5760 - PC:23040 WC:28800 DELTA:5760 (0.030000s)
BTL:37480 TC:43240 BTW:5760 - PC:28800 WC:34560 DELTA:5760 (0.030000s)
BTL:43240 TC:49000 BTW:5760 - PC:34560 WC:40320 DELTA:5760 (0.030000s)
BTL:49000 TC:56680 BTW:7680 - PC:42240 WC:48000 DELTA:5760 (0.030000s)
BTL:56680 TC:62440 BTW:5760 - PC:48000 WC:53760 DELTA:5760 (0.030000s)
BTL:62440 TC:70120 BTW:7680 - PC:55680 WC:61440 DELTA:5760 (0.030000s)
BTL:70120 TC:75880 BTW:5760 - PC:61440 WC:67200 DELTA:5760 (0.030000s)
BTL:75880 TC:81640 BTW:5760 - PC:67200 WC:72960 DELTA:5760 (0.030000s)
BTL:81640 TC:87400 BTW:5760 - PC:72960 WC:78720 DELTA:5760 (0.030000s)
BTL:87400 TC:98920 BTW:11520 - PC:84480 WC:90240 DELTA:5760 (0.030000s)
BTL:98920 TC:100840 BTW:1920 - PC:86400 WC:92160 DELTA:5760 (0.030000s)
BTL:100840 TC:108520 BTW:7680 - PC:94080 WC:99840 DELTA:5760 (0.030000s)
BTL:108520 TC:116200 BTW:7680 - PC:101760 WC:107520 DELTA:5760 (0.030000s)

I can patch things right now by jacking up the SafetyBytes to a whole frame. Maybe we can do that for now in the "trunk" so that people like me don't need to do this every drop?
Hmm... this is interesting. Can you check to see if the sleep() is also causing you to miss your frame rate? What does the frame rate print out say?

- Casey
I've had a similar problem. I'm on windows 8 if that helps narrow it down? I found that just reducing the time to sleep for by 1ms fixed my issues, as the sleep function seemed to be sleeping for longer than I'd asked for pretty consistently. There's probably a better way however.
montysan
I've had a similar problem. I'm on windows 8 if that helps narrow it down? I found that just reducing the time to sleep for by 1ms fixed my issues, as the sleep function seemed to be sleeping for longer than I'd asked for pretty consistently. There's probably a better way however.


I can confirm that Sleep is sleeping very slightly longer than requested. My FPS was regularly dipping from 60 to ~58 even with plenty of time left in the frame.

After shaving a 1ms off of the sleep arg, the fps now reports a solid 60fps with infrequent dips to 59.99.

That's on Window 7 home prem. btw.

Edited by Chris on
This is very interesting and good to know. We should probably put some kind of rate control into the sleep part of things to look for this and fix it... I will make a note.

- Casey
I also have this problem, but subtracting from the sleep is not enough on my system. I actually have to make the sound output work in twice the actual frametime to not have popping sounds (e.g. by dividing TargetSecondsPerFrame by 2 just before the sleep stuff) or, as suggested by OP, have an entire frame's worth of safety bytes. This is the same on both my version of HH and the official one.

I have made some debug screenshots from the official HH version, but I'm too confused to read anything into it, though both look like a glitch to me (the second one certainly does, but not sure if it's actually related to the popping).

Edit: My frame timing seems stable at 33.333542ms (occasional spikes up to 33.353420ms) or 16.666771ms (up to 16.680023ms) at 30Hz and 60Hz respectively.

Edited by Dghelneshi on
Here is an interesting article: http://www.codeproject.com/Articl...Quantifying-The-Accuracy-Of-Sleep, which shows that for intervals less than 10ms, sleep can be pretty inaccurate. It's from 2003, so it might be worthwhile to re-run the tests on modern hardware.

Matra
Something very weird is going on. I recorded all of the samples that we place into the sound buffer for the case with pops. There are no gaps and no problem with what we put in there. I even hacked the code from day 9 to play back the recorded buffer that I saved to a file. The sound is clean when I play it back that way, even when I throw a Sleep(10) in the main loop.
This may be going down the wrong path, and I apologize if so, but are you setting TSine = 0 in Handmade.cpp on each frame or only on the first frame?

As for the timing issue, I had the exact same problem, the only thing I could do was purposely undercut the sleep time and spinlock the cpu for the remainder of the frame, that gets me a pretty consistent value. I'm hoping that later down the road I can insert some fine-grained monotonous drudgery code in place of the spin-locking code so as not to waste all of those cycles. Maybe do extra AI stuff in there or something, I don't know.
Here is frame rate data for a case with popping. It from the day 25 code. My previous output had corrected the off by error in the BytesToWrite.

BTL:7680 TC:16213 BTW:8533 - PC:1920 WC:7680 DELTA:5760 (0.030000s)
34.04ms/f, 0.00f/s, 77.55mc/f
BTL:16212 TC:20053 BTW:3841 - PC:5760 WC:11520 DELTA:5760 (0.030000s)
34.03ms/f, 0.00f/s, 119.16mc/f
BTL:20052 TC:25813 BTW:5761 - PC:11520 WC:17280 DELTA:5760 (0.030000s)
33.33ms/f, 0.00f/s, 116.65mc/f
BTL:25812 TC:31573 BTW:5761 - PC:17280 WC:23040 DELTA:5760 (0.030000s)
33.33ms/f, 0.00f/s, 116.74mc/f
BTL:31572 TC:39253 BTW:7681 - PC:24960 WC:30720 DELTA:5760 (0.030000s)
33.44ms/f, 0.00f/s, 119.18mc/f
BTL:39252 TC:46933 BTW:7681 - PC:32640 WC:38400 DELTA:5760 (0.030000s)
34.03ms/f, 0.00f/s, 119.05mc/f
BTL:46932 TC:54613 BTW:7681 - PC:40320 WC:46080 DELTA:5760 (0.030000s)
33.33ms/f, 0.00f/s, 116.67mc/f
BTL:54612 TC:60373 BTW:5761 - PC:46080 WC:51840 DELTA:5760 (0.030000s)
33.33ms/f, 0.00f/s, 116.70mc/f
BTL:60372 TC:66133 BTW:5761 - PC:51840 WC:57600 DELTA:5760 (0.030000s)
33.43ms/f, 0.00f/s, 115.55mc/f
BTL:66132 TC:71893 BTW:5761 - PC:57600 WC:63360 DELTA:5760 (0.030000s)
33.33ms/f, 0.00f/s, 116.65mc/f
BTL:71892 TC:77653 BTW:5761 - PC:63360 WC:69120 DELTA:5760 (0.030000s)
33.33ms/f, 0.00f/s, 119.99mc/f
BTL:77652 TC:87253 BTW:9601 - PC:72960 WC:78720 DELTA:5760 (0.030000s)
33.43ms/f, 0.00f/s, 115.93mc/f
BTL:87252 TC:91093 BTW:3841 - PC:76800 WC:82560 DELTA:5760 (0.030000s)
33.33ms/f, 0.00f/s, 114.96mc/f
BTL:91092 TC:96853 BTW:5761 - PC:82560 WC:88320 DELTA:5760 (0.030000s)
33.33ms/f, 0.00f/s, 117.05mc/f
BTL:96852 TC:104533 BTW:7681 - PC:90240 WC:96000 DELTA:5760 (0.030000s)
33.42ms/f, 0.00f/s, 115.63mc/f
BTL:104532 TC:110293 BTW:5761 - PC:96000 WC:101760 DELTA:5760 (0.030000s)
34.03ms/f, 0.00f/s, 118.79mc/f
BTL:110292 TC:116053 BTW:5761 - PC:101760 WC:107520 DELTA:5760 (0.030000s)
34.04ms/f, 0.00f/s, 119.22mc/f
BTL:116052 TC:121813 BTW:5761 - PC:107520 WC:113280 DELTA:5760 (0.030000s)
34.03ms/f, 0.00f/s, 119.80mc/f
BTL:121812 TC:129493 BTW:7681 - PC:115200 WC:120960 DELTA:5760 (0.030000s)
33.33ms/f, 0.00f/s, 116.67mc/f
BTL:129492 TC:135253 BTW:5761 - PC:120960 WC:126720 DELTA:5760 (0.030000s)
33.33ms/f, 0.00f/s, 116.67mc/f
BTL:135252 TC:142933 BTW:7681 - PC:128640 WC:134400 DELTA:5760 (0.030000s)
33.43ms/f, 0.00f/s, 117.00mc/f
BTL:142932 TC:148693 BTW:5761 - PC:134400 WC:140160 DELTA:5760 (0.030000s)
33.33ms/f, 0.00f/s, 118.89mc/f
BTL:148692 TC:156373 BTW:7681 - PC:142080 WC:147840 DELTA:5760 (0.030000s)
33.74ms/f, 0.00f/s, 116.75mc/f
BTL:156372 TC:162133 BTW:5761 - PC:147840 WC:153600 DELTA:5760 (0.030000s)
33.33ms/f, 0.00f/s, 116.67mc/f
BTL:162132 TC:169813 BTW:7681 - PC:155520 WC:161280 DELTA:5760 (0.030000s)
33.33ms/f, 0.00f/s, 116.71mc/f
BTL:169812 TC:175573 BTW:5761 - PC:161280 WC:167040 DELTA:5760 (0.030000s)
33.42ms/f, 0.00f/s, 118.24mc/f
BTL:175572 TC:183253 BTW:7681 - PC:168960 WC:174720 DELTA:5760 (0.030000s)
33.33ms/f, 0.00f/s, 116.67mc/f
BTL:183252 TC:189013 BTW:5761 - PC:174720 WC:180480 DELTA:5760 (0.030000s)
33.74ms/f, 0.00f/s, 118.70mc/f
BTL:189012 TC:4693 BTW:7681 - PC:182400 WC:188160 DELTA:5760 (0.030000s)
34.03ms/f, 0.00f/s, 119.14mc/f
BTL:4692 TC:8533 BTW:3841 - PC:186240 WC:0 DELTA:5760 (0.030000s)
33.33ms/f, 0.00f/s, 114.37mc/f
BTL:8532 TC:16213 BTW:7681 - PC:1920 WC:7680 DELTA:5760 (0.030000s)
33.72ms/f, 0.00f/s, 116.79mc/f
BTL:16212 TC:20053 BTW:3841 - PC:5760 WC:11520 DELTA:5760 (0.030000s)
34.03ms/f, 0.00f/s, 119.06mc/f
BTL:20052 TC:27733 BTW:7681 - PC:13440 WC:19200 DELTA:5760 (0.030000s)
34.03ms/f, 0.00f/s, 119.10mc/f
That is always going to be true, though, since we always write from the last place we stopped writing. The reason for the gaps/pops is just when the PlayCursor overtakes the location where we are writing, so that we try to write into the region where DirectSound is trying to play. That will happen whenever the Sleep() sleeps too long, because we are trying to time the audio exactly.

We'll definitely be hitting this stuff much harder when we try to do the shipping Win32 layer.

- Casey
cmuratori
That is always going to be true, though, since we always write from the last place we stopped writing. The reason for the gaps/pops is just when the PlayCursor overtakes the location where we are writing, so that we try to write into the region where DirectSound is trying to play. That will happen whenever the Sleep() sleeps too long, because we are trying to time the audio exactly.

We'll definitely be hitting this stuff much harder when we try to do the shipping Win32 layer.

- Casey


How can we prevent this other than going out and buying a $200 motherboard with low enough DPC/ISR latency?

Edited by John Meyer on
So I'm watching the YouTube archive to catch up, just got past Ep18 and have come across the same Sleep problem (running on Windows 8.1). The Assert kept failing because Sleep was taking too long. Taking into consideration what matra774 pointed out concerning the inaccuracy of Sleep under the 10ms mark, I modified the code to look like this:
------------------------------------------------------
if(SleepIsSet)
{
DWORD RemainingMS = (DWORD)((TargetSecondsPerFrame - FrameSecondsElapsed) *
1000.0f);

if(RemainingMS > 10)
{
Sleep(RemainingMS - 10);
}
}
real32 SecondsSoFar = Win32GetSecondsElapsed(LastCounter, Win32GetWallClock());
Assert(SecondsSoFar < TargetSecondsPerFrame);
------------------------------------------------------
It seems to catch the margin of error thoroughly, and seems pretty much logical. I'm not 100% sure on the implications of this change though. Anyone see anything funny about this?

Edited by Nate Ungrodt on Reason: more thoroughly explain problem
I actually think that audio hardware doesn't play any role on this latency issue (on Windows OS). At least I have understood that latency is highly (if not totally) dependent on api you are using. At least with any api we will be using for games. Maybe with ASIO thing might be different. I think that ASIO is only api that allows direct control of audio hardware (at least after WinXP).

I had also sound popping problems with directsound but I solved those with just enough buffering and writing constant amounts of data. I am not as experienced as Casey, but I felt that he made somekind of thinking error with all those write and play cursor calculations.

Audio just keeps reading that buffer at constant rate (ie 48kHz). If our goal is 60fps then we need to feed audio with 800 samples per frame (at 48kHz). There is also latency at how our audio buffer is read (difference between play cursros and write cursor). I have feeling that this difference is not dependent on audio hardware but is some constant rate at witch our api processess data. At least it looks like that everyone has that same delta. That delta of 5760bytes means 1440 samples (16 bit, 2ch ) of lag, that is 1.8 frames. So you need to buffer 1.8 frames worth of audio ahead of time to keep things go glitch free.

I used buckets for this. Instead of running sample idx I have running bucket idx. Size of bucket is one AUDIO frames worth of samples (audio frame rate could be same as graphics 60Hz (->800 samples) or some multiple (30H->1600samples). Size of secondary buffer is some multiple of size of bucket. Main point is that I buffer those buckets and I always write buckets worth of data to buffer and then increase write bucket idx (or wrap). I dont write some variable amount that is based on play cursor or write cursor. You can also easily decide how much latency you want. For example you if you expect 2 frame latency you can start audio so that read start at bucket idx 0 and write starts at bucket idx 2. This method is, at least for me, easier to grasp and it solved those audio problems.

Maybe I change my method later if Casey shows me the light and directs me to right the path.
One thing I'd like to point out about all these calculations..

You're assuming audio plays at exactly 48khz. You're assuming frame rate is exactly 60hz. You're also probably assuming the computer clock keeps exact time.

Now, things may have advanced since I last struggled with these issues, but those assumptions quite likely do not hold true (and the differences aren't constant from one PC to the next either). At one point we found that playing 5 minutes of audio on one sound card was actually 3 seconds faster than playing the same audio on another sound card.. which is a massive difference.