• Create Account

## SDL audio callback buffer size

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

6 replies to this topic

### #1ultramailman  Prime Members

Posted 28 April 2014 - 12:23 AM

Hello all.

This is my first time going into the sound module of SDL, and I was able to get it to play a sound whenever the spaceship shoots a laser, or whenever it gets hit. However, the sound comes out too slow and isn't in sync with the rapid firing laser.

The problem is the audio callback function is called only around once every second, while the space ship can shoot 10 lasers per second. So I added some print statements to show what the buffer size is, and found out that the buffer size is 22056 (close to half of the frequency, 44100). So I tried changing the buffer size through SDL_AudioSpec.samples, but it is still 22056. Then I tried changing SDL_AudioSpec.freq to something lower, and that was able to change the buffer size.

So now I can change the buffer size, but only if also change the frequency. But that makes the sounds sound slow-motion.

Is there a way to customize the buffer size without changing the frequency? Or can it be a hardware limitation?

Here's code showing what I mean

void SoundSystem::init()
{
SDL_AudioSpec want;
Sound::getSpec("sound/checkspec.wav", &want); // use a dummy file to get the spec, this dummy file has same format as other sound files
want.userdata = this;
want.callback = SoundSystem::callback;
//want.freq = 1024; // this changes buffer size to 1024, but makes sounds sound very slow and deep
//want.samples = 512; // this is what I should use to change buffer size to 512, but it doesn't do anything
good = (0 == SDL_OpenAudio(&want, &spec));
if(good)
SDL_PauseAudio(0);
}

void SoundSystem::callback(void *userdata, Uint8 *stream, int len)
{
auto sys = (SoundSystem *) userdata;
SDL_memset(stream, 0, len);
std::cout << len << '\n';    //printing this shows the buffer size
sys->lock(); // sdl spinlock
for(Playback & p : sys->playbacks) // mix all sounds in a list
{
if(p.buf == nullptr)
continue;
unsigned left = p.pos + len > p.len ?  p.len - p.pos : len;
SDL_MixAudioFormat(stream, p.buf + p.pos, sys->spec.format, left, SDL_MIX_MAXVOLUME);

p.pos += left;
if(p.pos == p.len)
p = Playback{nullptr, 0, 0};
}
sys->unlock();
}
bool Sound::getSpec(std::string path, SDL_AudioSpec * spec)
{
unsigned len;
Uint8 * buf;
bool good = SDL_LoadWAV(path.c_str(), spec, &buf, &len);
if(good)
SDL_FreeWAV(buf);
return good;
}


Edited by ultramailman, 28 April 2014 - 10:42 AM.

### #2LongPointer  Members

Posted 28 April 2014 - 06:18 AM

SDL_AudioSpec appears to have 2 buffer sizes, size (in bytes) and samples. Does Sound::getSpec fill in the size in bytes too? http://wiki.libsdl.org/SDL_AudioSpec

Perhaps it would be best to ensure the buffer size in bytes is zero?

Also, what spec is returned when calling SDL_OpenAudio? Does it have a buffer size you'd expect?

Edited by LongPointer, 28 April 2014 - 09:38 AM.

### #3ultramailman  Prime Members

Posted 28 April 2014 - 10:52 AM

Oh, I've never tried filling in the spec for getSpec (edidited first post, getSpec is now included). I've always thought loadwav is the one that is responsible for filling it.

It's still worth a try though, so I did:

bool Sound::getSpec(std::string path, SDL_AudioSpec * spec)
{
unsigned len;
Uint8 * buf;
// spec->samples = 512; // this doesn't seem to do anything
//spec->size = 1024; // doesn't do anything, gets zeroed out by SDL_LoadWAV's call to SDL_memset(spec, 0, sizeof *spec)
bool good = SDL_LoadWAV(path.c_str(), spec, &buf, &len);
if(good)
SDL_FreeWAV(buf);
return good;
}


Also, what spec is returned when calling SDL_OpenAudio? Does it have a buffer size you'd expect?

And the obtained spec is indeed different from the wanted spec, printing shows 11028 samples and 22056 buffer size, as expected. Besides, spec.size is calculated, so either I fill it in before it is calculated and it doesn't do anything, or I fill it in after it is already filled in by SDL and don't know what I might have messed up.

Edited by ultramailman, 28 April 2014 - 10:59 AM.

### #4rip-off  Moderators

Posted 28 April 2014 - 02:49 PM

The SDL audio system is very low level. Is there a reason you're not using something like SDL_Mixer?

### #5ultramailman  Prime Members

Posted 28 April 2014 - 04:36 PM

Oh, no reason at all. It's there, and I've decided to use it, that's all. SDL audio is not very straightforward, but I think I've got it working pretty much the way I've wanted, except this problem with the low rate of callback. I hope to be able to fix it, or at least find out why I can't do it.

### #6LongPointer  Members

Posted 29 April 2014 - 02:03 AM

Oh, I've never tried filling in the spec for getSpec (edidited first post, getSpec is now included). I've always thought loadwav is the one that is responsible for filling it.

It's still worth a try though, so I did:

bool Sound::getSpec(std::string path, SDL_AudioSpec * spec)
{
unsigned len;
Uint8 * buf;
// spec->samples = 512; // this doesn't seem to do anything
//spec->size = 1024; // doesn't do anything, gets zeroed out by SDL_LoadWAV's call to SDL_memset(spec, 0, sizeof *spec)
bool good = SDL_LoadWAV(path.c_str(), spec, &buf, &len);
if(good)
SDL_FreeWAV(buf);
return good;
}


Also, what spec is returned when calling SDL_OpenAudio? Does it have a buffer size you'd expect?

And the obtained spec is indeed different from the wanted spec, printing shows 11028 samples and 22056 buffer size, as expected. Besides, spec.size is calculated, so either I fill it in before it is calculated and it doesn't do anything, or I fill it in after it is already filled in by SDL and don't know what I might have messed up.

When I said fill it in yourself, I meant after SDL has filled it in. Get the format from your wav, but then overwrite all 3 parameters related to buffer sizes (sample rate, size in samples and size in bytes). In your initial post you were only overwriting 2 of them. Alternatively, you could try reducing the size of your wav to 1024 samples (or whatever you want your buffer size to be).

However, I'd advise not using a wav file to dictate your sound engine mix format. SDL_AudioSpec isn't that complicated, so it should be no problem to fill it out manually from hard coded values or a config file. That way you can be 100% confident what your format is.

### #7ultramailman  Prime Members

Posted 01 May 2014 - 01:56 AM

@ LongPointer, you are right, using checkspec.wav is kind of silly. I don't use it anymore. As for filling the numbers in after OpenAudio, it doesn't work, because I already got the audio device.

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.