Skip to content

Instantly share code, notes, and snippets.

@tilkinsc
Created October 31, 2018 14:01
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tilkinsc/f91d2a74cff62cc3760a7c9291290b29 to your computer and use it in GitHub Desktop.
Save tilkinsc/f91d2a74cff62cc3760a7c9291290b29 to your computer and use it in GitHub Desktop.
OpenAL how to load an Ogg Vorbis file and play it
// Created by: http://github.com/tilkinsc
// returns ALuint* aka a single openal buffer of ready-to-play ogg vorbis sound samples
// returns 0 on error
ALuint* sound_load_ogg(const char* path) {
ALenum error = 0;
ALuint* sound = 0;
FILE* fp = 0;
OggVorbis_File vf;
vorbis_info* vi = 0;
ALenum format = 0;
short* pcmout = 0;
// open the file in read binary mode
fp = fopen(path, "rb");
if(fp == 0) {
fprintf(stderr, "Could not open file `%s`\n", path);
goto exit;
}
// make a handle
sound = malloc(1 * sizeof(ALuint));
if(sound == 0) {
fprintf(stderr, "Out of memory.");
goto exit;
}
// make a buffer
alGenBuffers(1, sound);
// check for errors
if((error = alGetError()) != AL_NO_ERROR) {
fprintf(stderr, "Failed to generate sound buffer %d\n", error);
goto exit;
}
// open the ogg vorbis file. This is a must on windows, do not use ov_open.
// set OV_CALLBACKS_NOCLOSE else it will close your fp when ov_close() is reached, which is fine.
if(ov_open_callbacks(fp, &vf, NULL, 0, OV_CALLBACKS_NOCLOSE) < 0) {
fprintf(stderr, "Stream is not a valid OggVorbis stream!\n");
goto exit;
}
// fill vi with a new ogg vorbis info struct, determine audio format
// audio format will always been a length of 16bits, vi->channels determines mono or stereo
vi = ov_info(&vf, -1);
format = vi->channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
// data_len is the amount of data to read, allocate said data space
// this is calculated by (samples * channels * 2 (aka 16bits))
size_t data_len = ov_pcm_total(&vf, -1) * vi->channels * 2;
pcmout = malloc(data_len);
if(pcmout == 0) {
fprintf(stderr, "Out of memory.\n");
goto exit;
}
// fill pcmout buffer with ov_read data samples
// you can't just slap data_len in place of 4096, it doesn't work that way
// 0 is endianess, 0 for little, 1 for big
// 2 is the data type short's size, mine is 2
// 1 is the signedness you want, I want short not unsigned short (for openal) so 1
for (size_t size = 0, offset = 0, sel = 0;
(size = ov_read(&vf, (char*) pcmout + offset, 4096, 0, 2, 1, (int*) &sel)) != 0;
offset += size) {
if(size < 0)
puts("Faulty ogg file :o"); // use https://xiph.org/vorbis/doc/vorbisfile/ov_read.html for handling enums
}
// send data to openal, vi->rate is your freq in Hz, dont assume 44100
alBufferData(*sound, format, pcmout, data_len, vi->rate);
if ((error = alGetError()) != AL_NO_ERROR) {
printf("Failed to send audio information buffer to OpenAL! 0x%06x\n", error);
goto exit;
}
// free your resources >:(
free(pcmout);
fclose(fp);
ov_clear(&vf);
return sound;
exit:
free(pcmout);
free(sound);
fclose(fp);
ov_clear(&vf);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment