[EDIT] tl;dr its just a bug in my code. Casting floats to ints
truncates.
Mārtiņš hit pretty close to the issue in
this post when describing a specific intrinsic float to int cast that rounds to the nearest integer, rather than truncate. However, whilst using ordinary casting in GCC, I duplicated Casey's timing check:
| 1006 DWORD SleepMS = (DWORD)(1000.0f * (TargetSecondsPerFrame -
1007 SecondsElapsedForFrame));
|
which eventually, quickly, and inevitably triggered the Assert (duped from HMH line 1016). It might run any number of passes through the game loop, but always managed to crash within the first three wraps of the audio ring buffer. After one of the crashes, I fetched the values of the elapsed seconds, the target seconds, then did the math by hand to find 200.56 became 201ms for the time to sleep. That was just enough to push it ever so slightly over my target seconds.
As it turns out, every other major compiler apart from Microsoft's does use the round to nearest intrinsic for their casts from float. Microsoft knows this and there is an
open bug for it on their website.
̶F̶Y̶I̶,̶ ̶i̶f̶ ̶t̶h̶i̶s̶ ̶b̶u̶g̶ ̶w̶a̶s̶ ̶t̶o̶ ̶b̶e̶ ̶f̶i̶x̶e̶d̶,̶ ̶a̶n̶d̶ ̶y̶o̶u̶r̶ ̶c̶o̶d̶e̶ ̶d̶e̶p̶e̶n̶d̶s̶ ̶o̶n̶ ̶t̶r̶u̶n̶c̶a̶t̶i̶n̶g̶ ̶c̶a̶s̶t̶s̶ ̶f̶r̶o̶m̶ ̶f̶l̶o̶a̶t̶,̶ ̶y̶o̶u̶ ̶c̶o̶u̶l̶d̶ ̶h̶a̶v̶e̶ ̶s̶t̶r̶a̶n̶g̶e̶ ̶b̶u̶g̶s̶ ̶a̶p̶p̶e̶a̶r̶i̶n̶g̶ ̶i̶n̶ ̶y̶o̶u̶r̶ ̶p̶r̶o̶g̶r̶a̶m̶ ̶i̶f̶ ̶y̶o̶u̶ ̶u̶p̶d̶a̶t̶e̶d̶ ̶o̶r̶ ̶i̶n̶s̶t̶a̶l̶l̶e̶d̶ ̶a̶ ̶n̶e̶w̶ ̶v̶e̶r̶s̶i̶o̶n̶ ̶o̶f̶ ̶V̶i̶s̶u̶a̶l̶ ̶S̶t̶u̶d̶i̶o̶.̶
Though probably not a very good solution, subtracting 1ms from every calculation of time to sleep stopped the bug and allowed my Pure C version of this timing test to run. I use a gaming laptop with decent audio hardware, so I don't think I even *needed* to code Casey's logic around this and go directly to day 20's much more robust audio timing code, but in the pursuit I discovered some very useful diagnostics around compiler behavior, for which I am looking :)