I am using SDL 2.0.20 on Pop!_OS 22.04 (I really need to migrate to SDL3 when I get a chance)
I am trying to output a constant square wave to the audio device via SDL_QueueAudio, but I run into a very strange issue where instead of a constant stream, I get a series of short “blips” about a second apart.
#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h>
int32 main() {
/* Initialization for window and input management */
if (SDL_InitSubSystem(SDL_INIT_AUDIO | SDL_INIT_VIDEO) < 0) {
std::cerr << "failed to initialize SDL audio, video, or events: " << SDL_GetError() << "\n";
return -1;
}
/* SDL window creation */
// Audio?
int32 devNum = SDL_GetNumAudioDevices(0) - 1;
const char* devName = SDL_GetAudioDeviceName(devNum, 0);
SDL_AudioSpec specTarget;
specTarget.format = AUDIO_S32MSB; // signed, 32-bit, big-endian (?), integer format
specTarget.freq = 48000; // samples in Hz
specTarget.channels = 2;
This is where I think the issue is originating from (described further below). I set the buffer size to 2 seconds, which to my understanding is a very large buffer. I have noticed that if I make this buffer smaller, the delay between the disconnected audio blips seems to also get smaller.
specTarget.samples = 48000; // buffer size in sample frames, 2 seconds?
specTarget.callback = 0; // will not be using a callback function
specTarget.userdata = 0; // ignored because no callback function
SDL_AudioSpec spec;
SDL_AudioDeviceID devID = SDL_OpenAudioDevice(devName, 0, &specTarget, &spec, 0);
SDL_PauseAudioDevice(devID, 0);
uint32 wavePhase = 0;
uint32 waveFreqHz = 260;
while (loopCont == true) {
/* Input management and exit condition */
/* Graphics output */
My approach to ensure that the audio is continuous was to check if there is any audio currently queued. If there is none, queue more square wave (arbitrarily set to queue 1/60th of a second’s worth of audio) then wait for it to drain again. However, when I run the program it seems that the queued audio isn’t actually draining to the device. SDL_GetQueuedAudioSize repeatedly reports 6400 bytes queued until about every second or so, where it suddenly reports 0 and then states that it is queueing audio. This happens at the same frequency of the audio blips, but not in sync with them.
uint32 audioQueuedBytes = SDL_GetQueuedAudioSize(devID);
std::cout << audioQueuedBytes << " bytes queued."; // DEBUG
if (audioQueuedBytes == 0) {
uint32 lenSamples = spec.freq * spec.channels / 60; // queue 1/60th seconds of audio?
uint32 lenBytes = lenSamples * SDL_AUDIO_BITSIZE(spec.format) / 8;
int32 audioData[lenSamples];
for (uint32 i = 0; i < lenSamples; i++) {
++wavePhase;
if (wavePhase > waveFreqHz) wavePhase = 0;
if (wavePhase <= waveFreqHz / 2) audioData[i] = 6000;
if (wavePhase > waveFreqHz / 2) audioData[i] = -6000;
}
std::cout << "Queueing audio!"; // DEBUG
SDL_QueueAudio(devID, &audioData, lenBytes);
}
std::cout << "\n"; // DEBUG
}
/* Window destruction */
}
As mentioned above, when I reduce the buffer size, it also causes the audio blips to come more frequently, which I think means I have a fundamental misunderstanding of what the buffer means. I thought that the buffer is simply the block of memory where you can store audio while it is continuously drained to the device at a constant rate regardless of the buffer size. But it seems like the size of the buffer is actually delaying the output of audio, as if SDL is waiting for the duration of the buffer to pass so it can output the audio I queued.
I also checked the SDL3 SDL_AudioSpec wiki page and noticed that it doesn’t have a buffer member at all! I’m not sure what that implies about the significance of the buffer in SDL2.