Sign in to follow this  
Henri Korpela

OpenAL + stb_vorbis - playing .ogg files?

Recommended Posts

Hello, [i]game developers[/i]!

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

After I had set up the[b] stb_vorbis[/b] 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 [i]stream [/i]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 [b]stb_vorbis[/b] 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 [b]stb_vorbis[/b] to load and play [i].ogg files[/i] via [b]OpenAL[/b]? 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
[CODE]/// -----------
/// @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__[/CODE]

audio_buffer.cpp
[CODE]#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[/CODE]

Share this post


Link to post
Share on other sites
Not exactly what you asked for, but I am using libvorbis in the MinGW environment. Simply install the sources with:
[list=1]
[*]./configure --prefix=/usr
[*]make
[*]make install
[/list]

Share this post


Link to post
Share on other sites
The single .c file is public domain and can be downloaded [url="http://nothings.org/stb_vorbis/"]here[/url]. There's although a simple example [url="http://nothings.org/stb_vorbis/samples/"]here [/url](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.

[quote name='Henri Korpela' timestamp='1335462158' post='4935141']
I'm just wondering why my static member function _load_ogg does not work correctly... Could somebody explain me why?
[/quote]
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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this