[SDL] Glenn, I did read your responses RE: Audio consumed.
Glenn Maynard
g_sdl at zewt.org
Tue Dec 10 20:50:01 PST 2002
On Tue, Dec 10, 2002 at 08:56:51PM -0600, Bob Pendleton wrote:
> I seem to have missed the problem statement. What is it you are trying
> to sync to what? I spent part of a weekend last spring fiddling with the
StepMania, a DDR-ish game. Arrows scroll timed with music; the
scrolling is entirely controlled by the current music position
(the background music becomes the game's time base), so we need
to be able to query the current sound position accurately or we
get jerky scrolling and poor game timing (for scoring).
> low level SDL sound code and found it was easy to get much less that
> 10th of a second start and stop times, millisecond start and stop
> latency is closer to what I saw. Just a matter of setting the buffer
> size so that it holds roughly 1 millisecond of samples. The hardware HAS
> to be fed on a regular basis so after start up the sound stream call
The buffer size must be at least 1024 samples at 44khz (23ms) on my system
or I get choppy sound. I've heard that OS/X can handle much smaller buffers
(which would be possible with more finely-grained scheduling), but Windows
generally can't. 1ms is certainly completely impossible in Windows, since
the sound thread won't get CPU cycles every millisecond.
> backs happen very regularly. Plus, you need to keep the stream running
They happen regularly, but not precisely. (see below)
> even when you aren't playing anything. Starting the sound pipeline has
> some built in overhead. But, it is pretty easy to send 0s, or white/pink
> noise when there are no sound samples pending.
I keep the sound playing at all times, and just feed in data when sounds
start. (Actually, with my DSound implementation that uses hardware
mixing, I do start streams right when a sample starts; this allows
sounds to have nearly zero startup latency. But that's a different
topic.)
> The only thing I can think of is that SDL is filling the whole buffer on
> the card so you might be seeing a delay based on the sound card buffer
> size rather than on your buffer size.
With the DSound implementation, the buffer on the card is equal to 2 *
the buffer size you specify. (Simple double buffering.)
The problem is that we can't assume that sound will be played at a
constant time (the buffer size) after the callback is called. For
example, take a look at the DirectSound implementation:
while ( cursor == playing ) {
/* FIXME: find out how much time is left and sleep that long */
SDL_Delay(10);
This means the callback might be called up to 10ms late (meaning the
delay until the sound is played is 10ms less), plus any other delays.
(Even without this, using the blocking method of the notify code,
scheduling latencies introduce unpredictable delays--fixing this FIXME
won't fix the problem).
That is, it's reasonable to say that, with a 23 ms buffer, that "the
sound you return from your sound callback will be heard approximately 23
ms later", but it's wrong to say "... exactly 23 ms later"; it might be
heard as little as 13ms later (or less, depending on the mood of the
system scheduler and other factors).
(It's probably correct to say "at most 23 ms later", at least with the
DSound implementation, but that doesn't help.)
My code looked something like this. This is conceptual, of course, and
looks little like the actual code:
void callback(...)
{
current_play_sample = next_fed_sample - samples_of_buffer_latency;
current_play_time = GetTime();
}
int get_current_time()
{
float time_since_callback = GetTime() - current_play_time;
int samples_since_callback = time_since_callback * seconds_per_sample;
return current_play_sample + samples_since_callback;
}
It returned time that was reasonable; it didn't drift at all, even
through buffer underruns, but the times were wrong because the callback
wasn't called at the exact time that "samples_of_buffer_latency" would
have been correct (due to, for example, that SDL_Delay call).
(And we can't time based on the time since we started playing, since
buffer underruns throw that off, and it's liable to drift since it has
nothing to tie it to the actual output.)
--
Glenn Maynard
More information about the SDL
mailing list