stk-code_catmod/src/audio/sfx_buffer.cpp
auria 407c5319b5 More work to fix building without OpenAL for Android
git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@10267 178a84e3-b1eb-0310-8ba1-8eac791a3b58
2011-11-27 18:15:12 +00:00

191 lines
4.8 KiB
C++

// $Id$
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2010 Marianne Gagnon
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "audio/sfx_buffer.hpp"
#include "audio/sfx_manager.hpp"
#include "io/file_manager.hpp"
#include "utils/constants.hpp"
#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>
#if HAVE_OGGVORBIS
# ifdef __APPLE__
# include <OpenAL/al.h>
# include <OpenAL/alc.h>
# else
# include <AL/al.h>
# include <AL/alc.h>
# endif
#endif
//----------------------------------------------------------------------------
SFXBuffer::SFXBuffer(const std::string& file,
bool positional,
float rolloff,
float gain)
{
m_buffer = 0;
m_gain = 1.0f;
m_rolloff = 0.1f;
m_loaded = false;
m_file = file;
m_rolloff = rolloff;
m_positional = positional;
m_gain = gain;
}
//----------------------------------------------------------------------------
SFXBuffer::SFXBuffer(const std::string& file,
const XMLNode* node)
{
m_buffer = 0;
m_gain = 1.0f;
m_rolloff = 0.1f;
m_positional = false;
m_loaded = false;
m_file = file;
node->get("rolloff", &m_rolloff );
node->get("positional", &m_positional );
node->get("volume", &m_gain );
}
//----------------------------------------------------------------------------
bool SFXBuffer::load()
{
#if HAVE_OGGVORBIS
if (m_loaded) return false;
alGetError(); // clear errors from previously
alGenBuffers(1, &m_buffer);
if (!SFXManager::checkError("generating a buffer"))
{
return false;
}
assert( alIsBuffer(m_buffer) );
if (!loadVorbisBuffer(m_file, m_buffer))
{
fprintf(stderr, "Could not load sound effect %s\n", m_file.c_str());
// TODO: free al buffer here?
return false;
}
#endif
m_loaded = true;
return true;
}
//----------------------------------------------------------------------------
void SFXBuffer::unload()
{
#if HAVE_OGGVORBIS
if (m_loaded)
{
alDeleteBuffers(1, &m_buffer);
m_buffer = 0;
}
#endif
m_loaded = false;
}
//----------------------------------------------------------------------------
/** Load a vorbis file into an OpenAL buffer
* based on a routine by Peter Mulholland, used with permission (quote :
* "Feel free to use")
*/
bool SFXBuffer::loadVorbisBuffer(const std::string &name, ALuint buffer)
{
#if HAVE_OGGVORBIS
const int ogg_endianness = (IS_LITTLE_ENDIAN ? 0 : 1);
bool success = false;
FILE *file;
vorbis_info *info;
OggVorbis_File oggFile;
if (alIsBuffer(buffer) == AL_FALSE)
{
printf("Error, bad OpenAL buffer");
return false;
}
file = fopen(name.c_str(), "rb");
if(!file)
{
fprintf(stderr, "[SFXBuffer] LoadVorbisBuffer() - couldn't open file!\n");
return false;
}
if (ov_open_callbacks(file, &oggFile, NULL, 0, OV_CALLBACKS_NOCLOSE) != 0)
{
fclose(file);
fprintf(stderr, "[SFXBuffer] LoadVorbisBuffer() - ov_open_callbacks() failed, file isn't vorbis?\n");
return false;
}
info = ov_info(&oggFile, -1);
long len = (long)ov_pcm_total(&oggFile, -1) * info->channels * 2; // always 16 bit data
char *data = (char *) malloc(len);
if(!data)
{
ov_clear(&oggFile);
fprintf(stderr, "[SFXBuffer] loadVorbisBuffer() - Error : LoadVorbisBuffer() - couldn't allocate decode buffer\n");
return false;
}
int bs = -1;
long todo = len;
char *bufpt = data;
while (todo)
{
int read = ov_read(&oggFile, bufpt, todo, ogg_endianness, 2, 1, &bs);
todo -= read;
bufpt += read;
}
alBufferData(buffer, (info->channels == 1) ? AL_FORMAT_MONO16
: AL_FORMAT_STEREO16,
data, len, info->rate);
success = true;
free(data);
ov_clear(&oggFile);
fclose(file);
return success;
#else
return false;
#endif
}