Jump to content
  • Advertisement
Sign in to follow this  
Henri Korpela

OpenAL + stb_vorbis - playing .ogg files?

This topic is 2266 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello, game developers!

I have been wandering around the Internet & managed to find a nifty little .c source file called stb_vorbis. I ended up using it due to it's easy integration to my game engine & because libvorbis' libraries didn't link themselves properly using MinGW.

After I had set up the stb_vorbis by turning it into a header file & fixing some warnings in that file the compiler helpfully informed me about, I started to look for tutorials. Well, eventually, I found some, sort of:

http://code.google.com/p/irrlamb/source/browse/trunk/source/engine/audio.cpp?r=726
https://gist.github.com/965399

Especially the last link turned out to be great, because it offered me a way to stream an .ogg file. I wanted to have an object-oriented approach to handle .ogg files, both by buffers and streams, but couldn't get it to work. Now, I still have the same problem.

By browsing the forums, I concluded that stb_vorbis is a good solution. However, there are no actual tutorials to help you to set it up. That's sad.

So, the question is, has anybody ever managed to get stb_vorbis to load and play .ogg files via OpenAL? It'd be very good thing to have a good solution for all other people to solve this similiar problem.

Here's my buffer class:

audio_buffer.hpp
/// -----------
/// @author God
/// -----------
#ifndef __TIM_AUDIO_BUFFER_HPP__
#define __TIM_AUDIO_BUFFER_HPP__
namespace Tim{
namespace Audio{
/// -------------------------------------------------------------------------
/// @class Buffer
/// @brief Represents an audio buffer, where audio files can be loaded into.
/// -------------------------------------------------------------------------
class Buffer{
/// Friends:
friend class Source;
public:
/// Enumerations:
enum Formats{FORMAT_AUTODETECT, FORMAT_MP3, FORMAT_OGG, FORMAT_VOC, FORMAT_WAV};
/// Constructors & destructors:
explicit Buffer(char const* file, Audio::Buffer::Formats const file_format = Audio::Buffer::FORMAT_AUTODETECT);
~Buffer(void);
private:
/// Static member functions:
static void _check_file(Audio::Buffer& buffer);
static void _load_ogg(Audio::Buffer& buffer);
static void _load_wav(Audio::Buffer& buffer);
/// Member data:
Audio::Buffer::Formats const _m_iFormat;
char const* _m_cpFile;
int mutable _m_iChannels;
unsigned int _m_uiBuffer;
};
}
}
#endif // __TIM_AUDIO_BUFFER_HPP__


audio_buffer.cpp
#include <cstdio>
#include <cstring>
#include <vector>
#include <tim/al/al.h>
#include <tim/al/alc.h>
#include <tim/stb_vorbis/stb_vorbis.h>
#include <tim/audio_buffer.hpp>
using namespace Tim;

/// -------------------------------------------------------------------------
/// @class Buffer
/// @brief Represents an audio buffer, where audio files can be loaded into.
/// -------------------------------------------------------------------------
/// Constructors & destructors:
Audio::Buffer::Buffer(char const* file, Audio::Buffer::Formats const file_format) : _m_iFormat(file_format), _m_cpFile(file){
::alGenBuffers(1, &_m_uiBuffer);
_check_file(*this);
}
Audio::Buffer::~Buffer(void){
::alDeleteBuffers(1, &_m_uiBuffer);
}
/// Static member functions:
void Audio::Buffer::_check_file(Audio::Buffer& buffer){
switch(buffer._m_iFormat){
case FORMAT_MP3:
break;
case FORMAT_OGG:
_load_ogg(buffer);
break;
case FORMAT_VOC:
break;
case FORMAT_WAV:
_load_wav(buffer);
break;
default:
switch(buffer._m_cpFile[::strlen(buffer._m_cpFile) - 3]){
case 79: // case 'O':
case 111: // case 'o':
_load_ogg(buffer);
break;
case 87: // case 'W':
case 119: // case 'w':
_load_wav(buffer);
break;
}
break;
}
}
void Audio::Buffer::_load_ogg(Audio::Buffer& buffer){
::stb_vorbis* __file = ::stb_vorbis_open_filename(const_cast<char*>(buffer._m_cpFile), NULL, NULL);
::stb_vorbis_info __info = ::stb_vorbis_get_info(__file);

int const __length_samples = (::stb_vorbis_stream_length_in_samples(__file) * __info.channels);
::ALshort* __buffer = new ::ALshort[__length_samples];

::alGenBuffers(1, &buffer._m_uiBuffer);
::stb_vorbis_get_samples_short_interleaved(__file, __info.channels, __buffer, __length_samples);
::alBufferData(buffer._m_uiBuffer, ((__info.channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16), __buffer, (__length_samples * sizeof(::ALshort)), __info.sample_rate);

delete[] __buffer;
::stb_vorbis_close(__file);
}
void Audio::Buffer::_load_wav(Audio::Buffer& buffer){
::FILE* __file = ::fopen(buffer._m_cpFile, "rb");
short __bits_psample, __bytes_psample, __channels, __type_format;
long __bytes_psec_avg, __rate_sample, __size, __size_chunk, __size_data;

for(__size_data = 0; __size_data < 4; ++__size_data) // __size_data-variable represents a temporary iterator.
::getc(__file);
::fread(&__size, sizeof(long), 1, __file);
for(__size_data = 0; __size_data < 8; ++__size_data) // __size_data-variable represents a temporary iterator.
::getc(__file);

::fread(&__size_chunk, sizeof(long), 1, __file);
::fread(&__type_format, sizeof(short), 1, __file);
::fread(&__channels, sizeof(short), 1, __file);
::fread(&__rate_sample, sizeof(long), 1, __file);
::fread(&__bytes_psec_avg, sizeof(long), 1, __file);
::fread(&__bytes_psample, sizeof(short), 1, __file);
::fread(&__bits_psample, sizeof(short), 1, __file);

for(__size_data = 0; __size_data < 4; ++__size_data) // __size_data-variable represents a temporary iterator.
::getc(__file);
::fread(&__size_data, sizeof(long), 1, __file);

unsigned char* __buffer = new unsigned char[__size_data];
::fread(__buffer, sizeof(unsigned char), __size_data, __file);
::fclose(__file); // Opened file no longer needed, so it will be closed.

::alGenBuffers(1, &buffer._m_uiBuffer);
::alBufferData(buffer._m_uiBuffer, (__bits_psample == 8) ? ((__channels == 1) ? AL_FORMAT_MONO8 : AL_FORMAT_STEREO8) : ((__channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16), __buffer, __size_data, __rate_sample);

delete[] __buffer; // A TEMPORARY BUFFER MUST DIE!
}

#undef __TIM_TEMPORARY_SIZE_BUFFER

Share this post


Link to post
Share on other sites
Advertisement
Not exactly what you asked for, but I am using libvorbis in the MinGW environment. Simply install the sources with:

  1. ./configure --prefix=/usr
  2. make
  3. make install

Share this post


Link to post
Share on other sites
The single .c file is public domain and can be downloaded here. There's although a simple example here (ok, not that easy to read).

I have managed to get it running in xaudio2 using the push api, it works, thought I needed some time to find all bugs.

I looked at your _load_ogg method and it seems ok.


I'm just wondering why my static member function _load_ogg does not work correctly... Could somebody explain me why?

What does not work ? Does it crash ? Sound not playing at all ? Do you hear light/heavy artifacts ? Have you tried to save the unpacked version as simple .wav file and listened to it with an external tool to check if something is wrong with your OpenAL implementation ?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!