Sign in to follow this  

OpenAL + stb_vorbis - playing .ogg files?

This topic is 2051 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, [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

This topic is 2051 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.

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