forked from Mirrors/openclonk
Add OpenAL implementation of C4SoundSystem
With an Ogg Vorbis loader using libvorbis and a .wav loader using a macosx API. Günther: Add autotools supportfloating-point
parent
f327022edd
commit
243e20bdf6
|
@ -428,6 +428,8 @@ set(OC_CLONK_SOURCES
|
|||
src/platform/C4MusicSystem.h
|
||||
src/platform/C4SoundSystem.cpp
|
||||
src/platform/C4SoundSystem.h
|
||||
src/platform/C4SoundLoaders.h
|
||||
src/platform/C4SoundLoaders.cpp
|
||||
src/platform/C4Video.cpp
|
||||
src/platform/C4Video.h
|
||||
src/platform/C4VideoPlayback.cpp
|
||||
|
|
|
@ -59,7 +59,7 @@ AM_CPPFLAGS = \
|
|||
-I$(srcdir)/src/game/object \
|
||||
-I$(srcdir)/src/lib/texture \
|
||||
-I$(srcdir)/src/script \
|
||||
$(GLEW_CFLAGS) $(GTK_CFLAGS) $(FREETYPE_CFLAGS) $(SDL_CFLAGS) $(BOOST_CPPFLAGS)
|
||||
$(GLEW_CFLAGS) $(GTK_CFLAGS) $(OPENAL_CFLAGS) $(FREETYPE_CFLAGS) $(SDL_CFLAGS) $(BOOST_CPPFLAGS)
|
||||
|
||||
##BUILT_SOURCES = hgrevision.h
|
||||
##hgrevision.h: $(srcdir)/.hg/dirstate
|
||||
|
@ -428,6 +428,8 @@ src/platform/C4MusicSystem.cpp \
|
|||
src/platform/C4MusicSystem.h \
|
||||
src/platform/C4SoundSystem.cpp \
|
||||
src/platform/C4SoundSystem.h \
|
||||
src/platform/C4SoundLoaders.h \
|
||||
src/platform/C4SoundLoaders.cpp \
|
||||
src/platform/C4Video.cpp \
|
||||
src/platform/C4Video.h \
|
||||
src/platform/C4VideoPlayback.cpp \
|
||||
|
@ -547,6 +549,7 @@ clonk_LDADD = \
|
|||
lib.a \
|
||||
$(LIBICONV) \
|
||||
$(GTK_LIBS) \
|
||||
$(OPENAL_LIBS) \
|
||||
$(FREETYPE_LIBS) \
|
||||
$(SDL_LIBS) \
|
||||
$(PTHREAD_LIBS) \
|
||||
|
|
|
@ -172,6 +172,9 @@
|
|||
/* MP3 music */
|
||||
#undef USE_MP3
|
||||
|
||||
/* OpenAL sound */
|
||||
#undef USE_OPEN_AL
|
||||
|
||||
/* Define to 1 if SDL is used for the main loop */
|
||||
#undef USE_SDL_MAINLOOP
|
||||
|
||||
|
|
32
configure.ac
32
configure.ac
|
@ -15,7 +15,7 @@ dnl Process this file with autoconf to produce a configure script.
|
|||
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT(clonk, m4_format([[[%s.%s.%s.%s]]], m4_include(version)))
|
||||
AC_COPYRIGHT([©2005-2009 Günther Brammer])
|
||||
AC_COPYRIGHT([©2005-2010 Günther Brammer])
|
||||
AC_CONFIG_SRCDIR([/src/C4Game.cpp])
|
||||
AC_CONFIG_AUX_DIR([autotools])
|
||||
AC_CONFIG_HEADER([config.h])
|
||||
|
@ -115,6 +115,21 @@ AS_IF([test $with_gtk = yes],[
|
|||
])
|
||||
AM_CONDITIONAL(DEVELOPER_MODE, [test $with_gtk = yes])
|
||||
|
||||
|
||||
# OpenAL
|
||||
AC_ARG_WITH([openal],
|
||||
[AC_HELP_STRING([--with-openal],[compile with openal support [default=no]])],
|
||||
, [with_openal=no])
|
||||
if test $with_openal = yes; then
|
||||
PKG_CHECK_MODULES(OPENAL, [vorbis vorbisfile openal])
|
||||
AC_DEFINE([USE_OPEN_AL], 1, [OpenAL sound])
|
||||
if test $enable_sound = no; then
|
||||
AC_MSG_ERROR([--with-openal cannot be used with --disable-sound.])
|
||||
fi
|
||||
fi
|
||||
|
||||
# SDL
|
||||
with_sdl_mixer=no
|
||||
AC_ARG_WITH([sdl],
|
||||
AS_HELP_STRING([--with-sdl], [Use SDL @<:@default=yes (no for win32)@:>@]),
|
||||
, [if test $win32 = true; then with_sdl=no; else if test $enable_console = yes; then with_sdl=no; else with_sdl=yes; fi fi])
|
||||
|
@ -126,11 +141,12 @@ if test $with_sdl = yes; then
|
|||
[AC_MSG_ERROR([libSDL not found.])])
|
||||
AC_SUBST(SDL_CFLAGS)
|
||||
AC_SUBST(SDL_LIBS)
|
||||
if test $enable_sound = yes; then
|
||||
if test $enable_sound = yes && test $with_openal = no; then
|
||||
# Check for SDL_mixer library
|
||||
AC_CHECK_LIB(SDL_mixer, Mix_OpenAudio,
|
||||
[AC_DEFINE(HAVE_LIBSDL_MIXER,1,[Define to 1 if you have SDL_mixer.])
|
||||
SDL_LIBS="-lSDL_mixer $SDL_LIBS"],
|
||||
SDL_LIBS="-lSDL_mixer $SDL_LIBS"
|
||||
with_sdl_mixer=yes],
|
||||
[AC_MSG_ERROR([SDL_mixer not found.])],
|
||||
[$SDL_LIBS])
|
||||
fi
|
||||
|
@ -172,6 +188,10 @@ AX_BOOST_BASE([1.40.0], [], [
|
|||
AC_MSG_ERROR([Boost not found.])
|
||||
])
|
||||
|
||||
# OpenSSL
|
||||
AC_CHECK_LIB(crypto, BIO_new, [OPENSSL_LIBS="-lcrypto"],
|
||||
[AC_MSG_ERROR([libcrypto (OpenSSL) not found.])])
|
||||
|
||||
# Check for libjpeg
|
||||
AC_CHECK_LIB(jpeg, jpeg_read_header, [
|
||||
CLONK_LIBS="-ljpeg $CLONK_LIBS"
|
||||
|
@ -262,10 +282,6 @@ if test "$with_directx" = yes; then
|
|||
AC_DEFINE([USE_DIRECTX], 1, [DirectX graphics])
|
||||
fi
|
||||
|
||||
# OpenSSL
|
||||
AC_CHECK_LIB(crypto, BIO_new, [OPENSSL_LIBS="-lcrypto"],
|
||||
[AC_MSG_ERROR([libcrypto (OpenSSL) not found.])])
|
||||
|
||||
if test $win32 = false; then
|
||||
# pthread
|
||||
AX_PTHREAD( , [AC_MSG_ERROR([No pthread support.])])
|
||||
|
@ -323,6 +339,8 @@ echo "Configuration:
|
|||
DirectX: $with_directx
|
||||
OpenGL: $with_gl
|
||||
Sound: $enable_sound
|
||||
SDL_Mixer: $with_sdl_mixer
|
||||
OpenAL: $with_openal
|
||||
GTK+: $with_gtk
|
||||
X11: $have_x"
|
||||
|
||||
|
|
|
@ -54,6 +54,9 @@ C4MusicSystem::C4MusicSystem():
|
|||
SongCount(0),
|
||||
PlayMusicFile(NULL),
|
||||
Volume(100)
|
||||
#ifdef USE_OPEN_AL
|
||||
, alcDevice(NULL), alcContext(NULL)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -62,6 +65,13 @@ C4MusicSystem::~C4MusicSystem()
|
|||
Clear();
|
||||
}
|
||||
|
||||
#ifdef USE_OPEN_AL
|
||||
void C4MusicSystem::SelectContext()
|
||||
{
|
||||
alcMakeContextCurrent(alcContext);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool C4MusicSystem::InitializeMOD()
|
||||
{
|
||||
#if defined HAVE_FMOD
|
||||
|
@ -117,6 +127,14 @@ bool C4MusicSystem::InitializeMOD()
|
|||
}
|
||||
MODInitialized = true;
|
||||
return true;
|
||||
#elif defined(USE_OPEN_AL)
|
||||
alcDevice = alcOpenDevice(NULL);
|
||||
if (!alcDevice)
|
||||
return false;
|
||||
alcContext = alcCreateContext(alcDevice, NULL);
|
||||
if (!alcContext)
|
||||
return false;
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
@ -132,6 +150,11 @@ void C4MusicSystem::DeinitializeMOD()
|
|||
#elif defined HAVE_LIBSDL_MIXER
|
||||
Mix_CloseAudio();
|
||||
SDL_Quit();
|
||||
#elif defined(USE_OPEN_AL)
|
||||
alcDestroyContext(alcContext);
|
||||
alcCloseDevice(alcDevice);
|
||||
alcContext = NULL;
|
||||
alcDevice = NULL;
|
||||
#endif
|
||||
MODInitialized = false;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,16 @@
|
|||
|
||||
#include <C4Group.h>
|
||||
|
||||
#if defined(USE_OPEN_AL)
|
||||
#ifdef __APPLE__
|
||||
#import <OpenAL/al.h>
|
||||
#import <OpenAL/alc.h>
|
||||
#else
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class C4MusicFileInfoNode;
|
||||
class C4MusicFile;
|
||||
|
||||
|
@ -68,10 +78,19 @@ protected:
|
|||
|
||||
bool GrpContainsMusic(C4Group &rGrp); // return whether this group contains music files
|
||||
|
||||
// FMod / SDL_mixer
|
||||
// FMod / SDL_mixer / OpenAL
|
||||
bool MODInitialized;
|
||||
bool InitializeMOD();
|
||||
void DeinitializeMOD();
|
||||
#ifdef USE_OPEN_AL
|
||||
private:
|
||||
ALCdevice* alcDevice;
|
||||
ALCcontext* alcContext;
|
||||
public:
|
||||
void SelectContext();
|
||||
#endif
|
||||
public:
|
||||
inline bool IsMODInitialized() {return MODInitialized;}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* OpenClonk, http://www.openclonk.org
|
||||
*
|
||||
* Copyright (c) 2010 Mortimer
|
||||
* Copyright (c) 2003-2004 Peter Wortmann
|
||||
* Copyright (c) 2005-2006, 2008 Sven Eberhardt
|
||||
* Copyright (c) 2005-2006 Günther Brammer
|
||||
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
||||
*
|
||||
* Portions might be copyrighted by other authors who have contributed
|
||||
* to OpenClonk.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
* See isc_license.txt for full license and disclaimer.
|
||||
*
|
||||
* "Clonk" is a registered trademark of Matthes Bender.
|
||||
* See clonk_trademark_license.txt for full license.
|
||||
*/
|
||||
|
||||
#include <C4Include.h>
|
||||
#include "C4SoundLoaders.h"
|
||||
|
||||
#if defined(USE_OPEN_AL) && defined(__APPLE__)
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_OPEN_AL
|
||||
extern "C"
|
||||
{
|
||||
#include <vorbis/codec.h>
|
||||
#include <vorbis/vorbisfile.h>
|
||||
}
|
||||
#endif
|
||||
|
||||
using namespace C4SoundLoaders;
|
||||
|
||||
SoundLoader* SoundLoader::first_loader(NULL);
|
||||
|
||||
#if defined(USE_OPEN_AL) && defined(__APPLE__)
|
||||
namespace
|
||||
{
|
||||
static OSStatus AudioToolBoxReadCallback(void* context, SInt64 inPosition, UInt32 requestCount, void* buffer, UInt32* actualCount)
|
||||
{
|
||||
CFDataRef audio = (CFDataRef)context;
|
||||
CFIndex audio_length = CFDataGetLength(audio);
|
||||
int requestOffset = inPosition + requestCount;
|
||||
int availableBytes = audio_length - inPosition;
|
||||
if (requestOffset > audio_length) {
|
||||
*actualCount = availableBytes;
|
||||
} else {
|
||||
*actualCount = requestCount;
|
||||
}
|
||||
CFRange range;
|
||||
range.location = inPosition;
|
||||
range.length = *actualCount;
|
||||
CFDataGetBytes(audio, range, (UInt8*)buffer);
|
||||
return noErr;
|
||||
}
|
||||
static SInt64 AudioToolBoxGetSizeProc(void* context)
|
||||
{
|
||||
return CFDataGetLength((CFDataRef)context);
|
||||
}
|
||||
}
|
||||
|
||||
bool AppleSoundLoader::ReadInfo(SoundInfo& info, BYTE* data, size_t data_length, uint32_t)
|
||||
{
|
||||
CFDataRef data_container = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, data, data_length, kCFAllocatorNull);
|
||||
AudioFileID sound_file;
|
||||
OSStatus err = AudioFileOpenWithCallbacks((void*)data_container,
|
||||
AudioToolBoxReadCallback,
|
||||
NULL,
|
||||
AudioToolBoxGetSizeProc,
|
||||
NULL,
|
||||
0,
|
||||
&sound_file
|
||||
);
|
||||
if (err == noErr)
|
||||
{
|
||||
UInt32 property_size;
|
||||
|
||||
info.sound_data_size = 0;
|
||||
property_size = sizeof(info.sound_data_size);
|
||||
AudioFileGetProperty(sound_file, kAudioFilePropertyAudioDataByteCount, &property_size, &info.sound_data_size);
|
||||
|
||||
info.sample_length = -1;
|
||||
property_size = sizeof(info.sample_length);
|
||||
AudioFileGetProperty(sound_file, kAudioFilePropertyEstimatedDuration, &property_size, &info.sample_length);
|
||||
|
||||
UInt32 sound_data_size_32 = info.sound_data_size;
|
||||
info.sound_data = malloc(info.sound_data_size);
|
||||
AudioFileReadBytes(sound_file, false, 0, &sound_data_size_32, info.sound_data);
|
||||
|
||||
AudioStreamBasicDescription desc;
|
||||
property_size = sizeof(desc);
|
||||
AudioFileGetProperty(sound_file, kAudioFilePropertyDataFormat, &property_size, &desc);
|
||||
info.sample_rate = desc.mSampleRate;
|
||||
|
||||
switch (desc.mChannelsPerFrame)
|
||||
{
|
||||
case 1:
|
||||
info.format = desc.mBitsPerChannel == 16 ? AL_FORMAT_MONO16 : AL_FORMAT_MONO8;
|
||||
break;
|
||||
case 2:
|
||||
info.format = desc.mBitsPerChannel == 16 ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO8;
|
||||
break;
|
||||
default:
|
||||
info.format = 0;
|
||||
}
|
||||
}
|
||||
CFRelease(data_container);
|
||||
return err == noErr;
|
||||
}
|
||||
|
||||
AppleSoundLoader AppleSoundLoader::singleton;
|
||||
#endif
|
||||
|
||||
#ifdef USE_OPEN_AL
|
||||
|
||||
size_t VorbisLoader::read_func(void* ptr, size_t byte_size, size_t size_to_read, void* datasource)
|
||||
{
|
||||
size_t spaceToEOF;
|
||||
size_t actualSizeToRead;
|
||||
VorbisLoader* loader = (VorbisLoader*)datasource;
|
||||
|
||||
spaceToEOF = loader->data_length - loader->data_pos;
|
||||
if (size_to_read*byte_size < spaceToEOF)
|
||||
actualSizeToRead = size_to_read*byte_size;
|
||||
else
|
||||
actualSizeToRead = spaceToEOF;
|
||||
|
||||
if (actualSizeToRead)
|
||||
{
|
||||
memcpy(ptr, (char*)loader->data + loader->data_pos, actualSizeToRead);
|
||||
loader->data_pos += actualSizeToRead;
|
||||
}
|
||||
|
||||
return actualSizeToRead;
|
||||
}
|
||||
|
||||
int VorbisLoader::seek_func(void* datasource, ogg_int64_t offset, int whence)
|
||||
{
|
||||
size_t spaceToEOF;
|
||||
ogg_int64_t actualOffset; // How much we can actually offset it by
|
||||
VorbisLoader* loader = (VorbisLoader*)datasource;
|
||||
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
loader->data_pos = offset < loader->data_length ? offset : loader->data_length;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
loader->data_pos += offset < loader->data_length - loader->data_pos ? offset : loader->data_length - loader->data_pos;
|
||||
break;
|
||||
case SEEK_END:
|
||||
loader->data_pos = loader->data_length+1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int VorbisLoader::close_func(void* datasource)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
long VorbisLoader::tell_func(void* datasource)
|
||||
{
|
||||
return ((VorbisLoader*)datasource)->data_pos;
|
||||
}
|
||||
|
||||
bool VorbisLoader::ReadInfo(SoundInfo& result, BYTE* data, size_t data_length, uint32_t)
|
||||
{
|
||||
this->data = data;
|
||||
this->data_length = data_length;
|
||||
this->data_pos = 0;
|
||||
|
||||
int endian = 0;
|
||||
int bitStream;
|
||||
long bytes;
|
||||
char array[32768];
|
||||
|
||||
vorbis_info* info;
|
||||
OggVorbis_File ogg_file;
|
||||
memset(&ogg_file, 0, sizeof(ogg_file));
|
||||
ov_callbacks callbacks;
|
||||
callbacks.read_func = &read_func;
|
||||
callbacks.seek_func = &seek_func;
|
||||
callbacks.close_func = &close_func;
|
||||
callbacks.tell_func = &tell_func;
|
||||
|
||||
// open using callbacks
|
||||
if (ov_open_callbacks(this, &ogg_file, NULL, 0, callbacks) != 0)
|
||||
{
|
||||
ov_clear(&ogg_file);
|
||||
return false;
|
||||
}
|
||||
|
||||
info = ov_info(&ogg_file, -1);
|
||||
if (info->channels == 1)
|
||||
result.format = AL_FORMAT_MONO16;
|
||||
else
|
||||
result.format = AL_FORMAT_STEREO16;
|
||||
result.sample_rate = info->rate;
|
||||
|
||||
std::vector<BYTE> buffer;
|
||||
do {
|
||||
bytes = ov_read(&ogg_file, array, sizeof(array)/sizeof(array[0]), endian, 2, 1, &bitStream);
|
||||
for (int i = 0; i < bytes; i++)
|
||||
buffer.push_back(array[i]);
|
||||
} while (bytes > 0);
|
||||
|
||||
result.sound_data = malloc(buffer.size());
|
||||
result.sound_data_size = buffer.size();
|
||||
for (int i = 0; i < buffer.size(); i++)
|
||||
((BYTE*)result.sound_data)[i] = buffer[i];
|
||||
result.sample_length = 5;
|
||||
|
||||
ov_clear(&ogg_file);
|
||||
return true;
|
||||
}
|
||||
|
||||
VorbisLoader VorbisLoader::singleton;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBSDL_MIXER
|
||||
bool SDLMixerSoundLoader::ReadInfo(SoundInfo& result, BYTE* data, size_t data_length, uint32_t)
|
||||
{
|
||||
// Be paranoid about SDL_Mixer initialisation
|
||||
if (!Application.MusicSystem.IsMODInitialized())
|
||||
{ return false; }
|
||||
if (!(result.final_handle = Mix_LoadWAV_RW(SDL_RWFromConstMem(data, data_length), 1)))
|
||||
{ return false; }
|
||||
//FIXME: Is this actually correct?
|
||||
result.sample_length = result.final_handle->alen / (44100 * 2);
|
||||
result.sample_rate = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
SDLMixerSoundLoader SDLMixerSoundLoader::singleton;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FMOD
|
||||
bool FMODSoundLoader::ReadInfo(SoundInfo& result, BYTE* data, size_t data_length, uint32_t options)
|
||||
{
|
||||
int32_t iOptions = FSOUND_NORMAL | FSOUND_2D | FSOUND_LOADMEMORY;
|
||||
if (options & OPTION_Raw)
|
||||
iOptions |= FSOUND_LOADRAW;
|
||||
SoundHandle pSample;
|
||||
if (!(pSample = FSOUND_Sample_Load(FSOUND_UNMANAGED, (const char *)data, iOptions, 0, data_length)))
|
||||
{ Clear(); return false; }
|
||||
// get length
|
||||
int32_t iSamples = FSOUND_Sample_GetLength(pSample);
|
||||
int iSampleRate = SampleRate;
|
||||
if (!iSamples || !FSOUND_Sample_GetDefaults(pSample, &iSampleRate, 0, 0, 0))
|
||||
return false;
|
||||
result.sample_rate = iSampleRate;
|
||||
result.sample_length = iSamples / iSampleRate;
|
||||
result.final_handle = pSample;
|
||||
return true;
|
||||
}
|
||||
|
||||
FMODSoundLoader FMODSoundLoader::singleton;
|
||||
#endif
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* OpenClonk, http://www.openclonk.org
|
||||
*
|
||||
* Copyright (c) 2010 Mortimer
|
||||
*
|
||||
* Portions might be copyrighted by other authors who have contributed
|
||||
* to OpenClonk.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
* See isc_license.txt for full license and disclaimer.
|
||||
*
|
||||
* "Clonk" is a registered trademark of Matthes Bender.
|
||||
* See clonk_trademark_license.txt for full license.
|
||||
*/
|
||||
|
||||
#ifdef USE_OPEN_AL
|
||||
extern "C"
|
||||
{
|
||||
#include <vorbis/codec.h>
|
||||
#include <vorbis/vorbisfile.h>
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace C4SoundLoaders
|
||||
{
|
||||
struct SoundInfo
|
||||
{
|
||||
public:
|
||||
double sample_length;
|
||||
uint32_t sample_rate;
|
||||
void* sound_data;
|
||||
uint64_t sound_data_size;
|
||||
#ifdef USE_OPEN_AL
|
||||
ALenum format;
|
||||
#endif
|
||||
C4SoundHandle final_handle;
|
||||
|
||||
SoundInfo(): sound_data(NULL), final_handle(NULL) {}
|
||||
~SoundInfo()
|
||||
{
|
||||
if (sound_data)
|
||||
free(sound_data);
|
||||
}
|
||||
};
|
||||
|
||||
class SoundLoader
|
||||
{
|
||||
public:
|
||||
static const int OPTION_Raw = 1;
|
||||
public:
|
||||
static SoundLoader* first_loader;
|
||||
SoundLoader* next;
|
||||
SoundLoader()
|
||||
{
|
||||
next = first_loader;
|
||||
first_loader = this;
|
||||
}
|
||||
virtual bool ReadInfo(SoundInfo& info, BYTE* data, size_t data_length, uint32_t options = 0) = 0;
|
||||
};
|
||||
|
||||
#if defined(USE_OPEN_AL) && defined(__APPLE__)
|
||||
class AppleSoundLoader: public SoundLoader
|
||||
{
|
||||
public:
|
||||
AppleSoundLoader(): SoundLoader() {}
|
||||
virtual bool ReadInfo(SoundInfo& info, BYTE* data, size_t data_length, uint32_t);
|
||||
protected:
|
||||
static AppleSoundLoader singleton;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef USE_OPEN_AL
|
||||
class VorbisLoader: public SoundLoader
|
||||
{
|
||||
private:
|
||||
BYTE* data;
|
||||
size_t data_length;
|
||||
size_t data_pos;
|
||||
static size_t read_func(void* ptr, size_t byte_size, size_t size_to_read, void* datasource);
|
||||
static int seek_func(void* datasource, ogg_int64_t offset, int whence);
|
||||
static int close_func(void* datasource);
|
||||
static long tell_func(void* datasource);
|
||||
public:
|
||||
virtual bool ReadInfo(SoundInfo& result, BYTE* data, size_t data_length, uint32_t);
|
||||
protected:
|
||||
static VorbisLoader singleton;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBSDL_MIXER
|
||||
class SDLMixerSoundLoader: public SoundLoader
|
||||
{
|
||||
public:
|
||||
static SDLMixerSoundLoader singleton;
|
||||
virtual bool ReadInfo(SoundInfo& result, BYTE* data, size_t data_length, uint32_t);
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FMOD
|
||||
class FMODSoundLoader: public SoundLoader
|
||||
{
|
||||
public:
|
||||
static FMODSoundLoader singleton;
|
||||
virtual bool ReadInfo(SoundInfo& result, BYTE* data, size_t data_length, uint32_t options);
|
||||
};
|
||||
#endif
|
||||
}
|
|
@ -30,14 +30,15 @@
|
|||
#include <C4Config.h>
|
||||
#include <C4Application.h>
|
||||
#include <C4GraphicsSystem.h>
|
||||
#include <C4SoundLoaders.h>
|
||||
|
||||
using namespace C4SoundLoaders;
|
||||
|
||||
C4SoundEffect::C4SoundEffect():
|
||||
UsageTime (0),
|
||||
Instances (0),
|
||||
Static (false),
|
||||
#if defined HAVE_FMOD || defined HAVE_LIBSDL_MIXER
|
||||
pSample (NULL),
|
||||
#endif
|
||||
FirstInst (NULL),
|
||||
Next (NULL)
|
||||
{
|
||||
|
@ -58,9 +59,10 @@ void C4SoundEffect::Clear()
|
|||
#ifdef HAVE_LIBSDL_MIXER
|
||||
if (pSample) Mix_FreeChunk(pSample);
|
||||
#endif
|
||||
#if defined HAVE_FMOD || defined HAVE_LIBSDL_MIXER
|
||||
pSample = NULL;
|
||||
#ifdef USE_OPEN_AL
|
||||
if (pSample) alDeleteBuffers(1, &pSample);
|
||||
#endif
|
||||
pSample = NULL;
|
||||
}
|
||||
|
||||
bool C4SoundEffect::Load(const char *szFileName, C4Group &hGroup, bool fStatic)
|
||||
|
@ -81,36 +83,40 @@ bool C4SoundEffect::Load(BYTE *pData, size_t iDataLen, bool fStatic, bool fRaw)
|
|||
{
|
||||
// Sound check
|
||||
if (!Config.Sound.RXSound) return false;
|
||||
// load directly from memory
|
||||
#ifdef HAVE_FMOD
|
||||
int32_t iOptions = FSOUND_NORMAL | FSOUND_2D | FSOUND_LOADMEMORY;
|
||||
if (fRaw) iOptions |= FSOUND_LOADRAW;
|
||||
if (!(pSample = FSOUND_Sample_Load(FSOUND_UNMANAGED, (const char *)pData,
|
||||
iOptions, 0, iDataLen)))
|
||||
{ Clear(); return false; }
|
||||
// get length
|
||||
int32_t iSamples = FSOUND_Sample_GetLength(pSample);
|
||||
int iSampleRate = SampleRate;
|
||||
if (!iSamples || !FSOUND_Sample_GetDefaults(pSample, &iSampleRate, 0, 0, 0))
|
||||
return false;
|
||||
SampleRate = iSampleRate;
|
||||
Length = iSamples * 10 / (SampleRate / 100);
|
||||
#endif
|
||||
#ifdef HAVE_LIBSDL_MIXER
|
||||
// Be paranoid about SDL_Mixer initialisation
|
||||
if (!Application.MusicSystem.MODInitialized)
|
||||
{ Clear(); return false; }
|
||||
if (!(pSample = Mix_LoadWAV_RW(SDL_RWFromConstMem(pData, iDataLen), 1)))
|
||||
{ Clear(); return false; }
|
||||
//FIXME: Is this actually correct?
|
||||
Length = 1000 * pSample->alen / (44100 * 2);
|
||||
SampleRate = 0;
|
||||
|
||||
SoundInfo info;
|
||||
int32_t options = 0;
|
||||
if (fRaw)
|
||||
options |= SoundLoader::OPTION_Raw;
|
||||
for (SoundLoader* loader = SoundLoader::first_loader; loader; loader = loader->next)
|
||||
{
|
||||
if (loader->ReadInfo(info, pData, iDataLen))
|
||||
{
|
||||
if (info.final_handle)
|
||||
{
|
||||
// loader supplied the handle specific to the sound system used; just assign to pSample
|
||||
pSample = info.final_handle;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef USE_OPEN_AL
|
||||
Application.MusicSystem.SelectContext();
|
||||
alGenBuffers(1, &pSample);
|
||||
alBufferData(pSample, info.format, info.sound_data, info.sound_data_size, info.sample_rate);
|
||||
#else
|
||||
Log("SoundLoader does not provide a ready-made handle");
|
||||
#endif
|
||||
}
|
||||
SampleRate = info.sample_rate;
|
||||
Length = info.sample_length*1000;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*Name = '\0';
|
||||
// Set usage time
|
||||
UsageTime=Game.Time;
|
||||
Static=fStatic;
|
||||
return true;
|
||||
return pSample;
|
||||
}
|
||||
|
||||
void C4SoundEffect::Execute()
|
||||
|
@ -270,6 +276,11 @@ bool C4SoundInstance::Start()
|
|||
if (!Application.MusicSystem.MODInitialized) return false;
|
||||
if ((iChannel = Mix_PlayChannel(-1, pEffect->pSample, fLooping? -1 : 0)) == -1)
|
||||
return false;
|
||||
#elif defined(USE_OPEN_AL)
|
||||
Application.MusicSystem.SelectContext();
|
||||
alGenSources(1, (ALuint*)&iChannel);
|
||||
alSourcei(iChannel, AL_BUFFER, pEffect->pSample);
|
||||
alSourcePlay(iChannel);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
@ -291,6 +302,10 @@ bool C4SoundInstance::Stop()
|
|||
// iChannel == -1 will halt all channels. Is that right?
|
||||
if (Playing())
|
||||
Mix_HaltChannel(iChannel);
|
||||
#endif
|
||||
#ifdef USE_OPEN_AL
|
||||
if (Playing())
|
||||
alSourceStop(iChannel);
|
||||
#endif
|
||||
iChannel = -1;
|
||||
iStarted = 0;
|
||||
|
@ -308,6 +323,16 @@ bool C4SoundInstance::Playing()
|
|||
#endif
|
||||
#ifdef HAVE_LIBSDL_MIXER
|
||||
return Application.MusicSystem.MODInitialized && (iChannel != -1) && Mix_Playing(iChannel);
|
||||
#endif
|
||||
#ifdef USE_OPEN_AL
|
||||
if (iChannel == -1)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
ALint state;
|
||||
alGetSourcei(iChannel, AL_SOURCE_STATE, &state);
|
||||
return state == AL_PLAYING;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
@ -341,6 +366,9 @@ void C4SoundInstance::Execute()
|
|||
#endif
|
||||
#ifdef HAVE_LIBSDL_MIXER
|
||||
Mix_HaltChannel(iChannel);
|
||||
#endif
|
||||
#ifdef USE_OPEN_AL
|
||||
alDeleteSources(1, (ALuint*)&iChannel);
|
||||
#endif
|
||||
iChannel = -1;
|
||||
}
|
||||
|
@ -360,6 +388,10 @@ void C4SoundInstance::Execute()
|
|||
Mix_Volume(iChannel, (iVol * MIX_MAX_VOLUME) / (100 * 256));
|
||||
//Mix_SetPanning(iChannel, ((100 + iPan) * 256) / 200, ((100 - iPan) * 256) / 200);
|
||||
Mix_SetPanning(iChannel, BoundBy((100 - iPan) * 256 / 100, 0, 255), BoundBy((100 + iPan) * 256 / 100, 0, 255));
|
||||
#endif
|
||||
#ifdef USE_OPEN_AL
|
||||
alSource3f(iChannel, AL_POSITION, 0, 0, 0); // FIXME
|
||||
alSourcef(iChannel, AL_GAIN, iVol / 100);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -439,6 +471,9 @@ void C4SoundSystem::ClearEffects()
|
|||
|
||||
void C4SoundSystem::Execute()
|
||||
{
|
||||
#ifdef USE_OPEN_AL
|
||||
Application.MusicSystem.SelectContext();
|
||||
#endif
|
||||
// Sound effect statistics & unload check
|
||||
C4SoundEffect *csfx,*next=NULL,*prev=NULL;
|
||||
for (csfx=FirstSound; csfx; csfx=next)
|
||||
|
|
|
@ -26,23 +26,33 @@
|
|||
|
||||
#include <C4Group.h>
|
||||
|
||||
#ifdef HAVE_FMOD
|
||||
#include <fmod.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIBSDL_MIXER
|
||||
#define USE_RWOPS
|
||||
#include <SDL_mixer.h>
|
||||
#undef USE_RWOPS
|
||||
#endif
|
||||
|
||||
const int32_t C4MaxSoundName=100,
|
||||
C4MaxSoundInstances=20,
|
||||
C4NearSoundRadius=50,
|
||||
C4AudibilityRadius=700;
|
||||
const int32_t
|
||||
C4MaxSoundName=100,
|
||||
C4MaxSoundInstances=20,
|
||||
C4NearSoundRadius=50,
|
||||
C4AudibilityRadius=700;
|
||||
|
||||
class C4Object;
|
||||
class C4SoundInstance;
|
||||
|
||||
#if defined(HAVE_FMOD)
|
||||
#include <fmod.h>
|
||||
typedef FSOUND_SAMPLE* C4SoundHandle;
|
||||
#elif defined(HAVE_LIBSDL_MIXER)
|
||||
#define USE_RWOPS
|
||||
#include <SDL_mixer.h>
|
||||
typedef Mix_Chunk* C4SoundHandle;
|
||||
#elif defined(USE_OPEN_AL)
|
||||
#ifdef __APPLE__
|
||||
#import <OpenAL/al.h>
|
||||
#else
|
||||
#include <AL/al.h>
|
||||
#endif
|
||||
typedef ALuint C4SoundHandle;
|
||||
#else
|
||||
typedef void* C4SoundHandle;
|
||||
#endif
|
||||
|
||||
class C4SoundEffect
|
||||
{
|
||||
friend class C4SoundInstance;
|
||||
|
@ -54,12 +64,7 @@ public:
|
|||
int32_t UsageTime, Instances;
|
||||
int32_t SampleRate, Length;
|
||||
bool Static;
|
||||
#ifdef HAVE_FMOD
|
||||
FSOUND_SAMPLE *pSample;
|
||||
#endif
|
||||
#ifdef HAVE_LIBSDL_MIXER
|
||||
Mix_Chunk * pSample;
|
||||
#endif
|
||||
C4SoundHandle pSample;
|
||||
C4SoundInstance *FirstInst;
|
||||
C4SoundEffect *Next;
|
||||
public:
|
||||
|
|
Loading…
Reference in New Issue