Remove ALUT usage from SimGear .
Adapt the freealut code into a WAV-file reader. As a side-effect, it would now be possible to deploy WAV files compressed with gzip, since we use ZLib's gzread functions to read from disk.
This commit is contained in:
@@ -111,7 +111,6 @@ if (MSVC AND MSVC_3RDPARTY_ROOT)
|
||||
set (BOOST_ROOT ${MSVC_3RDPARTY_ROOT}/boost_1_44_0)
|
||||
message(STATUS "BOOST_ROOT is ${BOOST_ROOT}")
|
||||
set (OPENAL_INCLUDE_DIR ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/include)
|
||||
set (ALUT_INCLUDE_DIR ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/include)
|
||||
set (OPENAL_LIBRARY_DIR ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/lib)
|
||||
endif (MSVC AND MSVC_3RDPARTY_ROOT)
|
||||
|
||||
@@ -124,7 +123,6 @@ else()
|
||||
message(STATUS "SimGear mode: NORMAL")
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(OpenAL REQUIRED)
|
||||
find_package(ALUT REQUIRED)
|
||||
find_package(OpenSceneGraph 3.0.0 REQUIRED osgText osgSim osgDB osgParticle osgGA osgUtil)
|
||||
endif(SIMGEAR_HEADLESS)
|
||||
|
||||
@@ -257,7 +255,7 @@ include_directories(${PROJECT_BINARY_DIR}/simgear/xml)
|
||||
|
||||
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
|
||||
${Boost_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIR}
|
||||
${ALUT_INCLUDE_DIR} ${OPENAL_INCLUDE_DIR} )
|
||||
${OPENAL_INCLUDE_DIR} )
|
||||
|
||||
add_definitions(-DHAVE_CONFIG_H)
|
||||
add_definitions(-DHAVE_EXPAT_CONFIG_H)
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
# Locate ALUT
|
||||
# This module defines
|
||||
# ALUT_LIBRARY
|
||||
# ALUT_FOUND, if false, do not try to link to ALUT
|
||||
# ALUT_INCLUDE_DIR, where to find the headers
|
||||
#
|
||||
# $ALUTDIR is an environment variable that would
|
||||
# correspond to the ./configure --prefix=$ALUTDIR
|
||||
# used in building ALUT.
|
||||
#
|
||||
# Created by James Turner. This was influenced by the FindOpenAL.cmake module.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2005-2009 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distributed this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
# Per my request, CMake should search for frameworks first in
|
||||
# the following order:
|
||||
# ~/Library/Frameworks/OpenAL.framework/Headers
|
||||
# /Library/Frameworks/OpenAL.framework/Headers
|
||||
# /System/Library/Frameworks/OpenAL.framework/Headers
|
||||
#
|
||||
# On OS X, this will prefer the Framework version (if found) over others.
|
||||
# People will have to manually change the cache values of
|
||||
# OPENAL_LIBRARY to override this selection or set the CMake environment
|
||||
# CMAKE_INCLUDE_PATH to modify the search paths.
|
||||
|
||||
FIND_LIBRARY(ALUT_LIBRARY
|
||||
NAMES ALUT alut
|
||||
HINTS
|
||||
$ENV{ALUTDIR}
|
||||
PATH_SUFFIXES lib64 lib libs64 libs libs/Win32 libs/Win64
|
||||
PATHS
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/usr/local
|
||||
/usr
|
||||
/opt
|
||||
)
|
||||
|
||||
FIND_PATH(ALUT_INCLUDE_DIR
|
||||
NAMES ALUT/alut.h alut.h
|
||||
HINTS
|
||||
$ENV{ALUTDIR}
|
||||
PATH_SUFFIXES include/AL include
|
||||
PATHS
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/usr/local
|
||||
/usr
|
||||
/opt
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(ALUT DEFAULT_MSG ALUT_LIBRARY ALUT_INCLUDE_DIR)
|
||||
|
||||
MARK_AS_ADVANCED(ALUT_LIBRARY ALUT_INCLUDE_DIR)
|
||||
|
||||
@@ -75,7 +75,7 @@ if(SIMGEAR_SHARED)
|
||||
SimGearCore
|
||||
${ZLIB_LIBRARY}
|
||||
${OPENSCENEGRAPH_LIBRARIES}
|
||||
${OPENAL_LIBRARY} ${ALUT_LIBRARY}
|
||||
${OPENAL_LIBRARY}
|
||||
${OPENGL_LIBRARY}
|
||||
${JPEG_LIBRARY})
|
||||
|
||||
|
||||
@@ -63,6 +63,8 @@
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/threads/SGThread.hxx>
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace {
|
||||
|
||||
class Resolver : public SGThread
|
||||
|
||||
@@ -84,6 +84,9 @@ inline bool sgIsBigEndian() {
|
||||
return (*((char *) &sgEndianTest ) == 0);
|
||||
}
|
||||
|
||||
inline void sgEndianSwap(int32_t *x) { *x = (int32_t) sg_bswap_32((int32_t) *x); }
|
||||
inline void sgEndianSwap(float *x) { *x = (float) sg_bswap_32((float) *x); }
|
||||
|
||||
inline void sgEndianSwap(uint16_t *x) { *x = sg_bswap_16(*x); }
|
||||
inline void sgEndianSwap(uint32_t *x) { *x = sg_bswap_32(*x); }
|
||||
inline void sgEndianSwap(uint64_t *x) { *x = sg_bswap_64(*x); }
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "EffectBuilder.hxx"
|
||||
#include "Effect.hxx"
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ EffectPropertyMap<T>::EffectPropertyMap(const EffectNameValue<T> (&attrs)[N])
|
||||
template<typename T>
|
||||
struct SimplePropertyMap
|
||||
{
|
||||
typedef std::map<string, T> map_type;
|
||||
typedef std::map<std::string, T> map_type;
|
||||
map_type _map;
|
||||
template<int N>
|
||||
SimplePropertyMap(const EffectNameValue<T> (&attrs)[N])
|
||||
@@ -197,8 +197,8 @@ void findAttr(const effect::EffectPropertyMap<T>& pMap,
|
||||
typename EffectPropertyMap<T>::BMap::iterator itr
|
||||
= pMap._map.template get<from>().find(name);
|
||||
if (itr == pMap._map.end()) {
|
||||
throw effect::BuilderException(string("findAttr: could not find attribute ")
|
||||
+ string(name));
|
||||
throw effect::BuilderException(std::string("findAttr: could not find attribute ")
|
||||
+ std::string(name));
|
||||
} else {
|
||||
result = itr->second;
|
||||
}
|
||||
@@ -373,7 +373,7 @@ public:
|
||||
template<typename T>
|
||||
struct InstallAttributeBuilder
|
||||
{
|
||||
InstallAttributeBuilder(const string& name)
|
||||
InstallAttributeBuilder(const std::string& name)
|
||||
{
|
||||
PassAttributeBuilder::PassAttrMapSingleton::instance()
|
||||
->passAttrMap.insert(make_pair(name, new T));
|
||||
|
||||
@@ -6,6 +6,7 @@ set(HEADERS
|
||||
sample_queue.hxx
|
||||
soundmgr_openal.hxx
|
||||
xmlsound.hxx
|
||||
readwav.hxx
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
@@ -14,6 +15,7 @@ set(SOURCES
|
||||
sample_queue.cxx
|
||||
soundmgr_openal.cxx
|
||||
xmlsound.cxx
|
||||
readwav.cxx
|
||||
)
|
||||
|
||||
simgear_scene_component(sound sound "${SOURCES}" "${HEADERS}")
|
||||
@@ -27,7 +29,7 @@ else()
|
||||
sgsound sgio sgmath sgstructure sgthreads sgtiming sgmisc sgdebug
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${RT_LIBRARY}
|
||||
${ALUT_LIBRARY} ${OPENAL_LIBRARY})
|
||||
${OPENAL_LIBRARY})
|
||||
endif()
|
||||
|
||||
function(create_test TEST_NAME)
|
||||
|
||||
@@ -12,20 +12,19 @@
|
||||
# define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION
|
||||
# include <OpenAL/al.h>
|
||||
# include <OpenAL/alc.h>
|
||||
# include <ALUT/alut.h>
|
||||
#elif defined(OPENALSDK)
|
||||
# include <al.h>
|
||||
# include <alc.h>
|
||||
# include <AL/alut.h>
|
||||
#else
|
||||
# include <AL/al.h>
|
||||
# include <AL/alc.h>
|
||||
# include <AL/alut.h>
|
||||
#endif
|
||||
|
||||
#define AUDIOFILE SRC_DIR"/jet.wav"
|
||||
|
||||
#include <simgear/sound/readwav.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
static void print_openal_error( ALuint error ) {
|
||||
if ( error == AL_INVALID_NAME ) {
|
||||
@@ -44,22 +43,24 @@ static void print_openal_error( ALuint error ) {
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char *argv[] ) {
|
||||
// initialize OpenAL
|
||||
ALCdevice *dev;
|
||||
ALCcontext *context;
|
||||
|
||||
alutInit(&argc, argv);
|
||||
int main( int argc, char *argv[] )
|
||||
{
|
||||
sglog().setLogLevels( SG_ALL, SG_ALERT );
|
||||
|
||||
|
||||
// initialize OpenAL
|
||||
if ( (dev = alcOpenDevice( NULL )) != NULL
|
||||
&& ( context = alcCreateContext( dev, NULL )) != NULL ) {
|
||||
alcMakeContextCurrent( context );
|
||||
} else {
|
||||
context = 0;
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" );
|
||||
ALCdevice *dev = alcOpenDevice(NULL);
|
||||
if (!dev) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Audio device initialization failed!" );
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ALCcontext *context = alcCreateContext(dev, NULL);
|
||||
if (!context) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Audio context initialization failed!" );
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
alcMakeContextCurrent( context );
|
||||
|
||||
// Position of the listener.
|
||||
ALfloat listener_pos[3];
|
||||
@@ -108,50 +109,15 @@ int main( int argc, char *argv[] ) {
|
||||
source_pos[0] = 0.0; source_pos[1] = 0.0; source_pos[2] = 0.0;
|
||||
source_vel[0] = 0.0; source_vel[1] = 0.0; source_vel[2] = 0.0;
|
||||
|
||||
// create an OpenAL buffer handle
|
||||
alGenBuffers(1, &buffer);
|
||||
ALuint error = alGetError();
|
||||
if ( error != AL_NO_ERROR ) {
|
||||
print_openal_error( error );
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Failed to gen OpenAL buffer." );
|
||||
} else {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Buffer created ok!" );
|
||||
}
|
||||
|
||||
// Load the sample file
|
||||
#if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
|
||||
|
||||
buffer = alutCreateBufferFromFile(AUDIOFILE);
|
||||
if (buffer == AL_NONE) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Failed to buffer data.");
|
||||
}
|
||||
|
||||
#else
|
||||
ALenum format;
|
||||
ALsizei size;
|
||||
ALvoid* data;
|
||||
ALsizei freq;
|
||||
|
||||
# if defined (__APPLE__)
|
||||
alutLoadWAVFile( (ALbyte *)AUDIOFILE, &format, &data, &size, &freq );
|
||||
# else
|
||||
alutLoadWAVFile( (ALbyte *)AUDIOFILE, &format, &data, &size, &freq, &loop );
|
||||
# endif
|
||||
if (alGetError() != AL_NO_ERROR) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Failed to load wav file.");
|
||||
}
|
||||
|
||||
// Copy data to the internal OpenAL buffer
|
||||
alBufferData( buffer, format, data, size, freq );
|
||||
if (alGetError() != AL_NO_ERROR) {
|
||||
buffer = simgear::createBufferFromFile(SGPath(AUDIOFILE));
|
||||
if (buffer == AL_NONE) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Failed to buffer data.");
|
||||
}
|
||||
|
||||
alutUnloadWAV( format, data, size, freq );
|
||||
#endif
|
||||
}
|
||||
|
||||
alGenSources(1, &source);
|
||||
if (alGetError() != AL_NO_ERROR) {
|
||||
ALuint error = alGetError();
|
||||
print_openal_error( error );
|
||||
}
|
||||
|
||||
@@ -165,7 +131,10 @@ int main( int argc, char *argv[] ) {
|
||||
alSourcePlay( source );
|
||||
|
||||
sleep(10);
|
||||
alutExit();
|
||||
|
||||
|
||||
alcMakeContextCurrent(NULL);
|
||||
alcDestroyContext(context);
|
||||
alcCloseDevice(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
310
simgear/sound/readwav.cxx
Normal file
310
simgear/sound/readwav.cxx
Normal file
@@ -0,0 +1,310 @@
|
||||
// Copyright (C) 2012 James Turner - zakalawe@mac.com
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
// adapted from the freealut sources, especially alutBufferData.c, alutLoader.c
|
||||
// and alutCodec.c (freealut is also LGPL licensed)
|
||||
|
||||
#include "readwav.hxx"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <zlib.h> // for gzXXX functions
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/stdint.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
|
||||
namespace
|
||||
{
|
||||
class Buffer {
|
||||
public:
|
||||
ALvoid* data;
|
||||
ALenum format;
|
||||
ALsizei length;
|
||||
ALfloat frequency;
|
||||
SGPath path;
|
||||
|
||||
Buffer() : data(NULL), format(AL_NONE), length(0), frequency(0.0f) {}
|
||||
|
||||
~Buffer()
|
||||
{
|
||||
if (data) {
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ALenum formatConstruct(ALint numChannels, ALint bitsPerSample)
|
||||
{
|
||||
switch (numChannels)
|
||||
{
|
||||
case 1:
|
||||
switch (bitsPerSample) {
|
||||
case 8: return AL_FORMAT_MONO8;
|
||||
case 16: return AL_FORMAT_MONO16;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (bitsPerSample) {
|
||||
case 8: return AL_FORMAT_STEREO8;
|
||||
case 16: return AL_FORMAT_STEREO16;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return AL_NONE;
|
||||
}
|
||||
|
||||
// function prototype for decoding audio data
|
||||
typedef void Codec(Buffer* buf);
|
||||
|
||||
void codecLinear(Buffer* /*buf*/)
|
||||
{
|
||||
}
|
||||
|
||||
void codecPCM16 (Buffer* buf)
|
||||
{
|
||||
// always byte-swaps here; is this a good idea?
|
||||
uint16_t *d = (uint16_t *) buf->data;
|
||||
size_t i, l = buf->length / 2;
|
||||
for (i = 0; i < l; i++) {
|
||||
*d = sg_bswap_16(*d);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* From: http://www.multimedia.cx/simpleaudio.html#tth_sEc6.1
|
||||
*/
|
||||
int16_t mulaw2linear (uint8_t mulawbyte)
|
||||
{
|
||||
static const int16_t exp_lut[8] = {
|
||||
0, 132, 396, 924, 1980, 4092, 8316, 16764
|
||||
};
|
||||
int16_t sign, exponent, mantissa, sample;
|
||||
mulawbyte = ~mulawbyte;
|
||||
sign = (mulawbyte & 0x80);
|
||||
exponent = (mulawbyte >> 4) & 0x07;
|
||||
mantissa = mulawbyte & 0x0F;
|
||||
sample = exp_lut[exponent] + (mantissa << (exponent + 3));
|
||||
return sign ? -sample : sample;
|
||||
}
|
||||
|
||||
void codecULaw (Buffer* b)
|
||||
{
|
||||
uint8_t *d = (uint8_t *) b->data;
|
||||
size_t newLength = b->length * 2;
|
||||
int16_t *buf = (int16_t *) malloc(newLength);
|
||||
size_t i;
|
||||
if (buf == NULL)
|
||||
throw sg_exception("malloc failed decoing ULaw WAV file");
|
||||
|
||||
for (i = 0; i < b->length; i++) {
|
||||
buf[i] = mulaw2linear(d[i]);
|
||||
}
|
||||
|
||||
free(b->data);
|
||||
b->data = buf;
|
||||
b->length = newLength;
|
||||
}
|
||||
|
||||
bool gzSkip(gzFile fd, int skipCount)
|
||||
{
|
||||
int r = gzseek(fd, skipCount, SEEK_CUR);
|
||||
return (r >= 0);
|
||||
}
|
||||
|
||||
const int32_t WAV_RIFF_4CC = 0x52494646; // 'RIFF'
|
||||
const int32_t WAV_WAVE_4CC = 0x57415645; // 'WAVE'
|
||||
const int32_t WAV_DATA_4CC = 0x64617461; // 'data'
|
||||
const int32_t WAV_FORMAT_4CC = 0x666d7420; // 'fmt '
|
||||
|
||||
template<class T>
|
||||
bool wavReadBE(gzFile fd, T& value)
|
||||
{
|
||||
if (gzread(fd, &value, sizeof(T)) != sizeof(T))
|
||||
return false;
|
||||
|
||||
if (sgIsLittleEndian())
|
||||
sgEndianSwap(&value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool wavReadLE(gzFile fd, T& value)
|
||||
{
|
||||
if (gzread(fd, &value, sizeof(T)) != sizeof(T))
|
||||
return false;
|
||||
|
||||
if (sgIsBigEndian())
|
||||
sgEndianSwap(&value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void loadWavFile(gzFile fd, Buffer* b)
|
||||
{
|
||||
assert(b->data == NULL);
|
||||
|
||||
bool found_header = false;
|
||||
uint32_t chunkLength;
|
||||
int32_t magic;
|
||||
uint16_t audioFormat;
|
||||
uint16_t numChannels;
|
||||
uint32_t samplesPerSecond;
|
||||
uint32_t byteRate;
|
||||
uint16_t blockAlign;
|
||||
uint16_t bitsPerSample;
|
||||
Codec *codec = codecLinear;
|
||||
|
||||
if (!wavReadBE(fd, magic))
|
||||
throw sg_io_exception("corrupt or truncated WAV data", b->path);
|
||||
|
||||
if (magic != WAV_RIFF_4CC) {
|
||||
throw sg_io_exception("not a .wav file", b->path);
|
||||
}
|
||||
|
||||
if (!wavReadLE(fd, chunkLength) || !wavReadBE(fd, magic))
|
||||
throw sg_io_exception("corrupt or truncated WAV data", b->path);
|
||||
|
||||
if (magic != WAV_WAVE_4CC) /* "WAVE" */
|
||||
{
|
||||
throw sg_io_exception("unrecognized WAV magic", b->path);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (!wavReadBE(fd, magic) || !wavReadLE(fd, chunkLength))
|
||||
throw sg_io_exception("corrupt or truncated WAV data", b->path);
|
||||
|
||||
if (magic == WAV_FORMAT_4CC) /* "fmt " */
|
||||
{
|
||||
found_header = true;
|
||||
if (chunkLength < 16) {
|
||||
throw sg_io_exception("corrupt or truncated WAV data", b->path);
|
||||
}
|
||||
|
||||
if (!wavReadLE (fd, audioFormat) ||
|
||||
!wavReadLE (fd, numChannels) ||
|
||||
!wavReadLE (fd, samplesPerSecond) ||
|
||||
!wavReadLE (fd, byteRate) ||
|
||||
!wavReadLE (fd, blockAlign) ||
|
||||
!wavReadLE (fd, bitsPerSample))
|
||||
{
|
||||
throw sg_io_exception("corrupt or truncated WAV data", b->path);
|
||||
}
|
||||
|
||||
if (!gzSkip(fd, chunkLength - 16))
|
||||
throw sg_io_exception("corrupt or truncated WAV data", b->path);
|
||||
|
||||
switch (audioFormat)
|
||||
{
|
||||
case 1: /* PCM */
|
||||
codec = (bitsPerSample == 8 || sgIsLittleEndian()) ? codecLinear : codecPCM16;
|
||||
break;
|
||||
case 7: /* uLaw */
|
||||
bitsPerSample *= 2; /* ToDo: ??? */
|
||||
codec = codecULaw;
|
||||
break;
|
||||
default:
|
||||
throw sg_io_exception("unsupported WAV encoding", b->path);
|
||||
}
|
||||
|
||||
b->frequency = samplesPerSecond;
|
||||
b->format = formatConstruct(numChannels, bitsPerSample);
|
||||
} else if (magic == WAV_DATA_4CC) {
|
||||
if (!found_header) {
|
||||
/* ToDo: A bit wrong to check here, fmt chunk could come later... */
|
||||
throw sg_io_exception("corrupt or truncated WAV data", b->path);
|
||||
}
|
||||
|
||||
b->data = malloc(chunkLength);
|
||||
b->length = chunkLength;
|
||||
size_t read = gzread(fd, b->data, chunkLength);
|
||||
if (read != chunkLength) {
|
||||
throw sg_io_exception("insufficent data reading WAV file", b->path);
|
||||
}
|
||||
|
||||
break;
|
||||
} else {
|
||||
if (!gzSkip(fd, chunkLength))
|
||||
throw sg_io_exception("corrupt or truncated WAV data", b->path);
|
||||
}
|
||||
|
||||
if ((chunkLength & 1) && !gzeof(fd) && !gzSkip(fd, 1))
|
||||
throw sg_io_exception("corrupt or truncated WAV data", b->path);
|
||||
} // of file chunk parser loop
|
||||
|
||||
codec(b); // might throw if something really bad occurs
|
||||
} // of loadWav function
|
||||
|
||||
} // of anonymous namespace
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
ALvoid* loadWAVFromFile(const SGPath& path, ALenum& format, ALsizei& size, ALfloat& freqf)
|
||||
{
|
||||
if (!path.exists()) {
|
||||
throw sg_io_exception("loadWAVFromFile: file not found", path);
|
||||
}
|
||||
|
||||
Buffer b;
|
||||
b.path = path;
|
||||
|
||||
gzFile fd;
|
||||
fd = gzopen(path.c_str(), "rb");
|
||||
if (!fd) {
|
||||
throw sg_io_exception("loadWAVFromFile: unable to open file", path);
|
||||
}
|
||||
|
||||
loadWavFile(fd, &b);
|
||||
ALvoid* data = b.data;
|
||||
b.data = NULL; // don't free when Buffer does out of scope
|
||||
format = b.format;
|
||||
size = b.length;
|
||||
freqf = b.frequency;
|
||||
|
||||
gzclose(fd);
|
||||
return data;
|
||||
}
|
||||
|
||||
ALuint createBufferFromFile(const SGPath& path)
|
||||
{
|
||||
ALenum format;
|
||||
ALsizei size;
|
||||
ALfloat sampleFrequency;
|
||||
ALvoid* data = loadWAVFromFile(path, format, size, sampleFrequency);
|
||||
assert(data);
|
||||
|
||||
ALuint buffer;
|
||||
alGenBuffers(1, &buffer);
|
||||
if (alGetError() != AL_NO_ERROR) {
|
||||
free(data);
|
||||
throw sg_io_exception("OpenAL buffer allocation failed", sg_location(path.str()));
|
||||
}
|
||||
|
||||
alBufferData (buffer, format, data, size, (ALsizei) sampleFrequency);
|
||||
if (alGetError() != AL_NO_ERROR) {
|
||||
alDeleteBuffers(1, &buffer);
|
||||
free(data);
|
||||
throw sg_io_exception("OpenAL setting buffer data failed", sg_location(path.str()));
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
} // of namespace simgear
|
||||
24
simgear/sound/readwav.hxx
Normal file
24
simgear/sound/readwav.hxx
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
|
||||
#ifndef SG_SOUND_READWAV_HXX
|
||||
#define SG_SOUND_READWAV_HXX
|
||||
|
||||
#if defined( __APPLE__ )
|
||||
# include <OpenAL/al.h>
|
||||
#elif defined(OPENALSDK)
|
||||
# include <al.h>
|
||||
#else
|
||||
# include <AL/al.h>
|
||||
#endif
|
||||
|
||||
// forward decls
|
||||
class SGPath;
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
ALvoid* loadWAVFromFile(const SGPath& path, ALenum& format, ALsizei& size, ALfloat& freqf);
|
||||
|
||||
ALuint createBufferFromFile(const SGPath& path);
|
||||
}
|
||||
|
||||
#endif // of SG_SOUND_READWAV_HXX
|
||||
@@ -513,7 +513,7 @@ private:
|
||||
bool _out_of_range;
|
||||
bool _is_file;
|
||||
|
||||
string random_string();
|
||||
std::string random_string();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ private:
|
||||
bool _playing;
|
||||
bool _changed;
|
||||
|
||||
string random_string();
|
||||
std::string random_string();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -29,17 +29,12 @@
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#if defined( __APPLE__ )
|
||||
# include <ALUT/alut.h>
|
||||
#else
|
||||
# include <AL/alut.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#include "soundmgr_openal.hxx"
|
||||
#include "readwav.hxx"
|
||||
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
@@ -61,8 +56,6 @@ extern bool isNaN(float *v);
|
||||
// Sound Manager
|
||||
//
|
||||
|
||||
int SGSoundMgr::_alut_init = 0;
|
||||
|
||||
// constructor
|
||||
SGSoundMgr::SGSoundMgr() :
|
||||
_working(false),
|
||||
@@ -81,17 +74,6 @@ SGSoundMgr::SGSoundMgr() :
|
||||
_renderer("unknown"),
|
||||
_vendor("unknown")
|
||||
{
|
||||
#if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
|
||||
if (_alut_init == 0) {
|
||||
if ( !alutInitWithoutContext(NULL, NULL) ) {
|
||||
testForALUTError("alut initialization");
|
||||
return;
|
||||
}
|
||||
}
|
||||
_alut_init++;
|
||||
#else
|
||||
//#error ALUT 1.1 required, ALUT 1.0 is no longer supported, please upgrade
|
||||
#endif
|
||||
}
|
||||
|
||||
// destructor
|
||||
@@ -99,12 +81,6 @@ SGSoundMgr::SGSoundMgr() :
|
||||
SGSoundMgr::~SGSoundMgr() {
|
||||
|
||||
stop();
|
||||
#if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
|
||||
_alut_init--;
|
||||
if (_alut_init == 0) {
|
||||
alutExit ();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// initialize the sound manager
|
||||
@@ -564,7 +540,7 @@ void SGSoundMgr::update_pos_and_orientation() {
|
||||
_absolute_pos = _base_pos;
|
||||
}
|
||||
|
||||
bool SGSoundMgr::load(string &samplepath, void **dbuf, int *fmt,
|
||||
bool SGSoundMgr::load(const string &samplepath, void **dbuf, int *fmt,
|
||||
size_t *sz, int *frq )
|
||||
{
|
||||
if ( !_working ) return false;
|
||||
@@ -574,49 +550,16 @@ bool SGSoundMgr::load(string &samplepath, void **dbuf, int *fmt,
|
||||
ALsizei freq;
|
||||
ALvoid *data;
|
||||
|
||||
#if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
|
||||
ALfloat freqf;
|
||||
// ignore previous errors to prevent the system from halting on silly errors
|
||||
alGetError();
|
||||
alcGetError(_device);
|
||||
data = alutLoadMemoryFromFile(samplepath.c_str(), &format, &size, &freqf );
|
||||
data = simgear::loadWAVFromFile(samplepath, format, size, freqf );
|
||||
freq = (ALsizei)freqf;
|
||||
int error = alutGetError();
|
||||
if (data == NULL || error != ALUT_ERROR_NO_ERROR) {
|
||||
string msg = "Failed to load wav file: ";
|
||||
msg.append(alutGetErrorString(error));
|
||||
throw sg_io_exception(msg.c_str(), sg_location(samplepath));
|
||||
return false;
|
||||
if (data == NULL) {
|
||||
throw sg_io_exception("Failed to load wav file", sg_location(samplepath));
|
||||
}
|
||||
|
||||
#else
|
||||
ALbyte *fname = (ALbyte *)samplepath.c_str();
|
||||
# if defined (__APPLE__)
|
||||
alutLoadWAVFile( fname, &format, &data, &size, &freq );
|
||||
# else
|
||||
ALboolean loop;
|
||||
alutLoadWAVFile( fname, &format, &data, &size, &freq, &loop );
|
||||
# endif
|
||||
ALenum error = alGetError();
|
||||
if ( error != AL_NO_ERROR ) {
|
||||
string msg = "Failed to load wav file: ";
|
||||
const ALchar *errorString = alGetString(error);
|
||||
if (errorString) {
|
||||
msg.append(errorString);
|
||||
} else {
|
||||
// alGetString returns NULL when an unexpected or OS specific error
|
||||
// occurs: e.g. -43 on Mac when file is not found.
|
||||
// In this case, alGetString() sets 'Invalid Enum' error, so
|
||||
// showing with the original error number is helpful.
|
||||
std::stringstream ss;
|
||||
ss << alGetString(alGetError()) << "(" << error << ")";
|
||||
msg.append(ss.str());
|
||||
}
|
||||
throw sg_io_exception(msg.c_str(), sg_location(samplepath));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (format == AL_FORMAT_STEREO8 || format == AL_FORMAT_STEREO16) {
|
||||
free(data);
|
||||
throw sg_io_exception("Warning: STEREO files are not supported for 3D audio effects: " + samplepath);
|
||||
@@ -690,18 +633,3 @@ bool SGSoundMgr::testForALCError(string s)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SGSoundMgr::testForALUTError(string s)
|
||||
{
|
||||
#if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
|
||||
ALenum error;
|
||||
error = alutGetError ();
|
||||
if (error != ALUT_ERROR_NO_ERROR) {
|
||||
SG_LOG( SG_SOUND, SG_ALERT, "ALUT Error (sound manager): "
|
||||
<< alutGetErrorString(error) << " at "
|
||||
<< s);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ public:
|
||||
* @param freq Pointer to a vairable that gets the sample frequency in Herz
|
||||
* @return true if succesful, false on error
|
||||
*/
|
||||
bool load(string &samplepath, void **data, int *format,
|
||||
bool load(const string &samplepath, void **data, int *format,
|
||||
size_t *size, int *freq );
|
||||
|
||||
/**
|
||||
@@ -281,7 +281,6 @@ public:
|
||||
const std::string& get_renderer() { return _renderer; }
|
||||
|
||||
private:
|
||||
static int _alut_init;
|
||||
|
||||
bool _working;
|
||||
bool _active;
|
||||
@@ -317,7 +316,6 @@ private:
|
||||
|
||||
bool testForALError(std::string s);
|
||||
bool testForALCError(std::string s);
|
||||
bool testForALUTError(std::string s);
|
||||
bool testForError(void *p, std::string s);
|
||||
|
||||
void update_pos_and_orientation();
|
||||
|
||||
@@ -6,10 +6,13 @@
|
||||
|
||||
|
||||
#include "exception.hxx"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
using std::string;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -24,7 +27,7 @@ sg_location::sg_location ()
|
||||
_path[0] = '\0';
|
||||
}
|
||||
|
||||
sg_location::sg_location (const string& path, int line, int column)
|
||||
sg_location::sg_location (const std::string& path, int line, int column)
|
||||
: _line(line),
|
||||
_column(column),
|
||||
_byte(-1)
|
||||
@@ -97,7 +100,7 @@ sg_location::setByte (int byte)
|
||||
_byte = byte;
|
||||
}
|
||||
|
||||
string
|
||||
std::string
|
||||
sg_location::asString () const
|
||||
{
|
||||
std::ostringstream out;
|
||||
@@ -268,6 +271,12 @@ sg_io_exception::sg_io_exception (const string& message,
|
||||
{
|
||||
}
|
||||
|
||||
sg_io_exception::sg_io_exception (const string &message, const SGPath& origin)
|
||||
: sg_exception(message, origin.str())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
sg_io_exception::~sg_io_exception () throw ()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <simgear/compiler.h>
|
||||
#include <string>
|
||||
|
||||
using std::string;
|
||||
class SGPath;
|
||||
|
||||
/**
|
||||
* Information encapsulating a single location in an external resource
|
||||
@@ -135,7 +135,8 @@ public:
|
||||
sg_io_exception (const std::string &message, const std::string &origin = "");
|
||||
sg_io_exception (const std::string &message, const sg_location &location,
|
||||
const std::string &origin = "");
|
||||
|
||||
sg_io_exception (const std::string &message, const SGPath& origin);
|
||||
|
||||
virtual ~sg_io_exception () throw ();
|
||||
virtual const std::string getFormattedMessage () const;
|
||||
virtual const sg_location &getLocation () const;
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
const int SG_MAX_SUBSYSTEM_EXCEPTIONS = 4;
|
||||
|
||||
using std::string;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of SGSubsystem
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -136,7 +136,7 @@ SGTimeZoneContainer::SGTimeZoneContainer(const char *filename)
|
||||
char buffer[256];
|
||||
FILE* infile = fopen(filename, "rb");
|
||||
if (!(infile)) {
|
||||
string e = "Unable to open time zone file '";
|
||||
std::string e = "Unable to open time zone file '";
|
||||
throw sg_exception(e + filename + '\'');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user