Reputation: 165
No matter what what audio file I use, it always cuts off about a fourth of the way through. I have a feeling it's because I'm casting the decoded audio to a Uint8*
, but if I don't, the audio plays really fast and it still only plays about half of the file. Also, using SDL_MixAudio
instead of SDL_memcpy
causes a bunch of copies of the sound to play over each other for some reason.
Uint8* audio_pos;
Uint32 audio_len;
void audioCallback(void* userdata, Uint8* stream, int len) {
if (audio_len == 0) return;
len = (len > audio_len ? audio_len : len);
SDL_memcpy(stream, audio_pos, len);
audio_pos += len;
audio_len -= len;
}
int main(int argc, char *argv[]) {
...
short* decoded;
int channels, rate, len;
len = stb_vorbis_decode_filename(RealPath("music.ogg").c_str(), &channels, &rate, &decoded);
SDL_AudioSpec spec;
spec.freq = rate;
spec.format = AUDIO_S16;
spec.channels = channels;
spec.samples = 2048;
spec.callback = audioCallback;
spec.userdata = NULL;
audio_pos = (Uint8*)decoded;
audio_len = len;
if (SDL_OpenAudio(&spec, NULL) < 0) {
std::cout << "failed to open audio device: " << SDL_GetError() << '\n';
SDL_GL_DeleteContext(context);
SDL_Quit();
return -1;
}
SDL_PauseAudio(0);
SDL_Event windowEvt;
while (true) {
if (audio_len == 0) break;
if (SDL_PollEvent(&windowEvt)) {
if (windowEvt.type == SDL_QUIT) break;
if (windowEvt.type == SDL_KEYUP && windowEvt.key.keysym.sym == SDLK_ESCAPE) break;
}
SDL_GL_SwapWindow(window);
}
...
}
Upvotes: 0
Views: 1284
Reputation: 1
stb_vorbis_decode_filename
returns the "number of samples decoded," which is respect to an int16
, and doesn't include the channel factor.
You're looking for:
int32 length = stb_vorbis_decode_filename("thing.ogg", &channels, &rate, &decoded);
int32 audio_length = length * channels * (sizeof(int16) / sizeof(uint8));
With respect to SDL_MixAudio
vs SDL_memcpy
for sound overlap, you need to explicitly clear the stream with a silence value. For example, SDL_memset
when you enter the SDL audio callback.
void audioCallback(void* userdata, Uint8* stream, int len)
{
SDL_memset(stream, 0, len);// silence the stream
if (audio_len == 0) return;
len = (len > audio_len ? audio_len : len);
SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);// this takes a volume argument
audio_pos += len;
audio_len -= len;
}
The zero passed to SDL_memset
should be the same silence value you created in SDL_AudioSpec
, when calling SDL_OpenAudioDevice
.
Upvotes: 0