1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-09 12:22:34 +01:00

Merge pull request #111 from tsjost/fix/audio

Replace SFML Audio with libsndfile + OpenAL
This commit is contained in:
Daniel Evans 2016-05-30 22:53:51 +01:00
commit 42c847cfab
15 changed files with 545 additions and 241 deletions

View File

@ -65,10 +65,12 @@ IF(APPLE)
ENDIF()
find_package(OpenGL REQUIRED)
find_package(OpenAL REQUIRED)
find_package(Bullet REQUIRED)
find_package(SFML 2 COMPONENTS system window audio graphics network REQUIRED)
find_package(SFML 2 COMPONENTS system window graphics network REQUIRED)
find_package(MAD REQUIRED)
find_package(GLM REQUIRED)
find_package(LibSndFile REQUIRED)
include_directories("${GLM_INCLUDE_DIRS}")

View File

@ -0,0 +1,34 @@
# - Try to find libsndfile
# Once done, this will define
#
# LIBSNDFILE_FOUND - system has libsndfile
# LIBSNDFILE_INCLUDE_DIRS - the libsndfile include directories
# LIBSNDFILE_LIBRARIES - link these to use libsndfile
# Use pkg-config to get hints about paths
find_package(PkgConfig QUIET)
if(PKG_CONFIG_FOUND)
pkg_check_modules(LIBSNDFILE_PKGCONF sndfile)
endif(PKG_CONFIG_FOUND)
# Include dir
find_path(LIBSNDFILE_INCLUDE_DIR
NAMES sndfile.h
PATHS ${LIBSNDFILE_PKGCONF_INCLUDE_DIRS}
)
# Library
find_library(LIBSNDFILE_LIBRARY
NAMES sndfile libsndfile-1
PATHS ${LIBSNDFILE_PKGCONF_LIBRARY_DIRS}
)
find_package(PackageHandleStandardArgs)
find_package_handle_standard_args(LibSndFile DEFAULT_MSG LIBSNDFILE_LIBRARY LIBSNDFILE_INCLUDE_DIR)
if(LIBSNDFILE_FOUND)
set(LIBSNDFILE_LIBRARIES ${LIBSNDFILE_LIBRARY})
set(LIBSNDFILE_INCLUDE_DIRS ${LIBSNDFILE_INCLUDE_DIR})
endif(LIBSNDFILE_FOUND)
mark_as_advanced(LIBSNDFILE_LIBRARY LIBSNDFILE_LIBRARIES LIBSNDFILE_INCLUDE_DIR LIBSNDFILE_INCLUDE_DIRS)

View File

@ -13,12 +13,16 @@ target_link_libraries(rwengine
rwlib
${MAD_LIBRARY}
${SFML_LIBRARIES}
${LIBSNDFILE_LIBRARY}
${OPENAL_LIBRARY}
${OPENRW_PLATFORM_LIBS})
include_directories(SYSTEM
${BULLET_INCLUDE_DIR}
${MAD_INCLUDE_DIR}
${SFML_INCLUDE_DIR}
${LIBSNDFILE_INCLUDE_DIR}
${OPENAL_INCLUDE_DIR}
)
include_directories(

View File

@ -7,30 +7,17 @@
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <SFML/Audio.hpp>
#include <stdint.h>
#include <iostream>
#include <rw/defines.hpp>
#include <AL/al.h>
#include <AL/alc.h>
#include "audio/alCheck.hpp"
static inline
signed int scale(mad_fixed_t sample)
{
/* round */
sample += (1L << (MAD_F_FRACBITS - 16));
/* clip */
if (sample >= MAD_F_ONE)
sample = MAD_F_ONE - 1;
else if (sample < -MAD_F_ONE)
sample = -MAD_F_ONE;
/* quantize */
return sample >> (MAD_F_FRACBITS + 1 - 16);
}
#include <vector>
class MADStream : public sf::SoundStream
class MADStream
{
mad_decoder mDecoder;
unsigned int mMadSampleRate;
@ -40,131 +27,34 @@ class MADStream : public sf::SoundStream
unsigned int mReadProgress;
std::vector<int16_t> mCurrentSamples;
static mad_flow ms_header(void* user, mad_header const* header)
{
MADStream* stream = static_cast<MADStream*>(user);
/**
* The number of OpenAL buffers is arbitrary, but due to the kind of small
* buffer/audio sample size, we need a bunch of them so the computer can
* keep up with filling them.
*/
constexpr static size_t numALbuffers = 8;
ALuint buffers[numALbuffers];
ALuint unqueuedBuffers[numALbuffers];
size_t numFreeBuffers = numALbuffers;
size_t currentBuffer = 0;
ALuint alSource;
stream->mMadSampleRate = header->samplerate;
// see enum mad_mode
stream->mMadChannels = header->mode + 1;
bool stopped = false;
return MAD_FLOW_CONTINUE;
}
static mad_flow ms_input(void* user, mad_stream* stream)
{
MADStream* self = static_cast<MADStream*>(user);
if(! self->mReadProgress ) {
return MAD_FLOW_STOP;
}
auto rd = self->mReadProgress;
self->mReadProgress = 0;
mad_stream_buffer(stream, self->mFdm, rd);
return MAD_FLOW_CONTINUE;
}
static mad_flow ms_output(void* user, mad_header const* header,
mad_pcm* pcm)
{
RW_UNUSED(header);
MADStream* self = static_cast<MADStream*>(user);
int nsamples = pcm->length;
mad_fixed_t const *left, *right;
left = pcm->samples[0];
right = pcm->samples[1];
int s = 0;
while( (nsamples) -- ) {
signed int sample = *left++;
self->mCurrentSamples.push_back(scale(sample));
sample = *right++;
self->mCurrentSamples.push_back(scale(sample));
s++;
}
return MAD_FLOW_CONTINUE;
}
static mad_flow ms_error(void* user, mad_stream* stream, mad_frame* frame)
{
RW_UNUSED(user);
RW_UNUSED(frame);
sf::err() << "libmad error: " << mad_stream_errorstr(stream);
return MAD_FLOW_BREAK;
}
virtual bool onGetData(sf::SoundStream::Chunk& data)
{
data.samples = mCurrentSamples.data();
data.sampleCount = mCurrentSamples.size();
return false;
}
virtual void onSeek(sf::Time timeOffset)
{
RW_UNUSED(timeOffset);
/// @todo support seeking.
}
static inline signed int scale(mad_fixed_t sample);
static mad_flow ms_header(void* user, mad_header const* header);
static mad_flow ms_input(void* user, mad_stream* stream);
static mad_flow ms_output(void* user, mad_header const* header, mad_pcm* pcm);
static mad_flow ms_error(void* user, mad_stream* stream, mad_frame* frame);
public:
MADStream()
: mFdm(nullptr)
{
MADStream();
~MADStream();
}
~MADStream()
{
if( mFdm )
{
munmap( mFdm, mStat.st_size );
mad_decoder_finish(&mDecoder);
}
}
bool openFromFile(const std::string& loc)
{
if( mFdm ) {
munmap( mFdm, mStat.st_size );
mCurrentSamples.clear();
mad_decoder_finish(&mDecoder);
}
int fd = ::open(loc.c_str(), O_RDONLY);
if( fstat(fd, &mStat) == -1 || mStat.st_size == 0) {
std::cerr << "Fstat failed (" << loc << ")" << std::endl;
return false;
}
void* m = mmap(0, mStat.st_size, PROT_READ, MAP_SHARED, fd, 0);
if( m == MAP_FAILED ) {
std::cerr << "mmap failed (" << loc << ")" << std::endl;
return false;
}
mFdm = (unsigned char*)m;
mReadProgress = mStat.st_size;
mad_decoder_init(&mDecoder, this,
ms_input, ms_header, 0, ms_output, ms_error, 0);
mad_decoder_run(&mDecoder, MAD_DECODER_MODE_SYNC);
this->initialize(2, mMadSampleRate);
return true;
}
bool openFromFile(const std::string& loc);
void play();
void stop();
};
#endif

View File

@ -1,28 +1,72 @@
#pragma once
#include <sndfile.h>
#include <AL/al.h>
#include <AL/alc.h>
#include <map>
#include <string>
#include <vector>
#include <SFML/Audio.hpp>
class MADStream;
class SoundManager
{
public:
SoundManager();
void playSound(const std::string& fileName);
bool loadSound(const std::string& name, const std::string& fileName);
bool isLoaded(const std::string& name);
void playSound(const std::string& name);
void pauseSound(const std::string& name);
bool isPlaying(const std::string& name);
bool playBackground(const std::string& fileName);
bool loadMusic(const std::string& name, const std::string& fileName);
void playMusic(const std::string& name);
void stopMusic(const std::string& name);
void pause(bool p);
private:
struct PlayingSound
class SoundSource
{
sf::Sound sound;
sf::SoundBuffer buffer;
friend class SoundManager;
friend class SoundBuffer;
public:
void loadFromFile(const std::string& filename);
private:
SF_INFO fileInfo;
SNDFILE* file;
std::vector<uint16_t> data;
};
std::vector<PlayingSound> sounds;
sf::SoundStream* backgroundNoise;
class SoundBuffer
{
friend class SoundManager;
public:
SoundBuffer();
bool bufferData(SoundSource& soundSource);
private:
ALuint source;
ALuint buffer;
};
};
struct Sound
{
SoundSource source;
SoundBuffer buffer;
bool isLoaded = false;
};
bool initializeOpenAL();
ALCcontext* alContext;
ALCdevice* alDevice;
std::map<std::string, Sound> sounds;
std::map<std::string, MADStream> musics;
std::string backgroundNoise;
};

View File

@ -0,0 +1,11 @@
#pragma once
#include <string>
void checkALerror(const std::string& file, unsigned int line);
#if RW_DEBUG
#define alCheck(stmt) do { stmt; checkALerror(__FILE__, __LINE__); } while(0)
#else
#define alCheck(stmt) stmt
#endif

View File

@ -148,7 +148,7 @@ public:
void loadWeaponDAT(const std::string& name);
bool loadAudioStream(const std::string& name);
bool loadAudioClip(const std::string& name);
bool loadAudioClip(const std::string& name, const std::string& fileName);
void loadSplash(const std::string& name);

View File

@ -306,10 +306,9 @@ public:
void clearCutscene();
bool isCutsceneDone();
sf::SoundStream* cutsceneAudio;
std::string cutsceneAudio;
bool cutsceneAudioLoaded;
sf::SoundBuffer* missionAudio;
sf::Sound missionSound;
std::string missionAudio;
/**
* @brief loads a model into a special character slot.

View File

@ -0,0 +1,174 @@
#include "audio/MADStream.hpp"
#include <thread>
inline signed int MADStream::scale(mad_fixed_t sample)
{
/* round */
sample += (1L << (MAD_F_FRACBITS - 16));
/* clip */
if (sample >= MAD_F_ONE) {
sample = MAD_F_ONE - 1;
} else if (sample < -MAD_F_ONE) {
sample = -MAD_F_ONE;
}
/* quantize */
return sample >> (MAD_F_FRACBITS + 1 - 16);
}
mad_flow MADStream::ms_header(void* user, mad_header const* header)
{
MADStream* stream = static_cast<MADStream*>(user);
stream->mMadSampleRate = header->samplerate;
// see enum mad_mode
stream->mMadChannels = header->mode + 1;
return MAD_FLOW_CONTINUE;
}
mad_flow MADStream::ms_input(void* user, mad_stream* stream)
{
MADStream* self = static_cast<MADStream*>(user);
if ( ! self->mReadProgress ) {
return MAD_FLOW_STOP;
}
auto rd = self->mReadProgress;
self->mReadProgress = 0;
mad_stream_buffer(stream, self->mFdm, rd);
return MAD_FLOW_CONTINUE;
}
mad_flow MADStream::ms_output(void* user, mad_header const* header, mad_pcm* pcm)
{
RW_UNUSED(header);
MADStream* self = static_cast<MADStream*>(user);
if (self->stopped) {
return MAD_FLOW_STOP;
}
if ( ! self->numFreeBuffers) {
ALint buffersProcessed;
do {
/**
* Sleep a bit while waiting for OpenAL buffers to become available.
* The number is arbitrary and depends on the size of the buffer/audio samples,
* as well as how quickly the computer can feed more buffers into OpenAL.
*/
std::this_thread::sleep_for(std::chrono::milliseconds(20));
alGetSourcei(self->alSource, AL_BUFFERS_PROCESSED, &buffersProcessed);
} while (buffersProcessed <= 0);
alCheck(alSourceUnqueueBuffers(self->alSource, buffersProcessed, self->unqueuedBuffers));
self->numFreeBuffers += buffersProcessed;
}
int nsamples = pcm->length;
mad_fixed_t const *left, *right;
left = pcm->samples[0];
right = pcm->samples[1];
int s = 0;
while (nsamples--) {
signed int sample = *left++;
self->mCurrentSamples.push_back(scale(sample));
sample = *right++;
self->mCurrentSamples.push_back(scale(sample));
s++;
}
alCheck(alBufferData(self->buffers[self->currentBuffer], AL_FORMAT_STEREO16, self->mCurrentSamples.data(), self->mCurrentSamples.size() * sizeof(uint16_t), pcm->samplerate));
alCheck(alSourceQueueBuffers(self->alSource, 1, self->buffers + self->currentBuffer));
self->mCurrentSamples.clear();
self->currentBuffer++;
self->currentBuffer %= numALbuffers;
self->numFreeBuffers--;
return MAD_FLOW_CONTINUE;
}
mad_flow MADStream::ms_error(void* user, mad_stream* stream, mad_frame* frame)
{
RW_UNUSED(user);
RW_UNUSED(frame);
std::cerr << "libmad error: " << mad_stream_errorstr(stream) << std::endl;
return MAD_FLOW_BREAK;
}
MADStream::MADStream()
: mFdm(nullptr)
{
alCheck(alGenBuffers(numALbuffers, buffers));
alCheck(alGenSources(1, &alSource));
}
MADStream::~MADStream()
{
if (mFdm) {
munmap(mFdm, mStat.st_size);
mad_decoder_finish(&mDecoder);
}
}
bool MADStream::openFromFile(const std::string& loc)
{
if (mFdm) {
munmap(mFdm, mStat.st_size);
mCurrentSamples.clear();
mad_decoder_finish(&mDecoder);
}
int fd = ::open(loc.c_str(), O_RDONLY);
if (fstat(fd, &mStat) == -1 || mStat.st_size == 0) {
std::cerr << "Fstat failed (" << loc << ")" << std::endl;
return false;
}
void* m = mmap(0, mStat.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (m == MAP_FAILED) {
std::cerr << "mmap failed (" << loc << ")" << std::endl;
return false;
}
mFdm = (unsigned char*) m;
mReadProgress = mStat.st_size;
mad_decoder_init(&mDecoder, this,
ms_input, ms_header, 0, ms_output, ms_error, 0);
new std::thread([&] () {
mad_decoder_run(&mDecoder, MAD_DECODER_MODE_SYNC);
});
alCheck(alSourcef(alSource, AL_PITCH, 1));
alCheck(alSourcef(alSource, AL_GAIN, 1));
alCheck(alSource3f(alSource, AL_POSITION, 0, 0, 0));
alCheck(alSource3f(alSource, AL_VELOCITY, 0, 0, 0));
alCheck(alSourcei(alSource, AL_LOOPING, AL_FALSE));
return true;
}
void MADStream::play()
{
alCheck(alSourcePlay(alSource));
}
void MADStream::stop()
{
stopped = true;
alCheck(alSourcePlay(alSource));
}

View File

@ -1,44 +1,177 @@
#include <audio/SoundManager.hpp>
#include <audio/MADStream.hpp>
SoundManager::SoundManager()
: backgroundNoise(nullptr)
{
#include "audio/alCheck.hpp"
#include "audio/MADStream.hpp"
#include <array>
#include <iostream>
void SoundManager::SoundSource::loadFromFile(const std::string& filename)
{
fileInfo.format = 0;
file = sf_open(filename.c_str(), SFM_READ, &fileInfo);
if (file) {
size_t numRead = 0;
std::array<int16_t, 4096> readBuffer;
while ((numRead = sf_read_short(file, readBuffer.data(), readBuffer.size())) != 0) {
data.insert(data.end(), readBuffer.begin(), readBuffer.begin() + numRead);
}
} else {
std::cerr << "Error opening sound file \"" << filename << "\": " << sf_strerror(file) << std::endl;
}
}
SoundManager::SoundBuffer::SoundBuffer()
{
alCheck(alGenSources(1, &source));
alCheck(alGenBuffers(1, &buffer));
alCheck(alSourcef(source, AL_PITCH, 1));
alCheck(alSourcef(source, AL_GAIN, 1));
alCheck(alSource3f(source, AL_POSITION, 0, 0, 0));
alCheck(alSource3f(source, AL_VELOCITY, 0, 0, 0));
alCheck(alSourcei(source, AL_LOOPING, AL_FALSE));
}
bool SoundManager::SoundBuffer::bufferData(SoundSource& soundSource)
{
alCheck(alBufferData(
buffer,
soundSource.fileInfo.channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16,
&soundSource.data.front(),
soundSource.data.size() * sizeof(uint16_t),
soundSource.fileInfo.samplerate
));
alCheck(alSourcei(source, AL_BUFFER, buffer));
return true;
}
SoundManager::SoundManager()
{
initializeOpenAL();
}
bool SoundManager::initializeOpenAL()
{
alDevice = alcOpenDevice(NULL);
if ( ! alDevice) {
std::cerr << "Could not find OpenAL device!" << std::endl;
return false;
}
alContext = alcCreateContext(alDevice, NULL);
if ( ! alContext) {
std::cerr << "Could not create OpenAL context!" << std::endl;
return false;
}
if ( ! alcMakeContextCurrent(alContext)) {
std::cerr << "Unable to make OpenAL context current!" << std::endl;
return false;
}
return true;
}
bool SoundManager::loadSound(const std::string& name, const std::string& fileName)
{
Sound* sound = nullptr;
auto sound_iter = sounds.find(name);
if (sound_iter != sounds.end()) {
sound = &sound_iter->second;
} else {
auto emplaced = sounds.emplace(std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple());
sound = &emplaced.first->second;
sound->source.loadFromFile(fileName);
sound->isLoaded = sound->buffer.bufferData(sound->source);
}
return sound->isLoaded;
}
bool SoundManager::isLoaded(const std::string& name)
{
if (sounds.find(name) != sounds.end()) {
return sounds[name].isLoaded;
}
return false;
}
void SoundManager::playSound(const std::string& name)
{
if (sounds.find(name) != sounds.end()) {
alCheck(alSourcePlay(sounds[name].buffer.source));
}
}
void SoundManager::pauseSound(const std::string& name)
{
if (sounds.find(name) != sounds.end()) {
alCheck(alSourcePause(sounds[name].buffer.source));
}
}
bool SoundManager::isPlaying(const std::string& name)
{
if (sounds.find(name) != sounds.end()) {
ALint sourceState;
alCheck(alGetSourcei(sounds[name].buffer.source, AL_SOURCE_STATE, &sourceState));
return AL_PLAYING == sourceState;
}
return false;
}
bool SoundManager::playBackground(const std::string& fileName)
{
if( backgroundNoise )
{
delete backgroundNoise;
}
sf::Music* bg = new sf::Music;
if( bg->openFromFile( fileName ) )
{
backgroundNoise = bg;
backgroundNoise->setLoop(true);
bg->play();
if (this->loadSound(fileName, fileName)) {
backgroundNoise = fileName;
this->playSound(fileName);
return true;
}
delete bg;
return false;
}
bool SoundManager::loadMusic(const std::string& name, const std::string& fileName)
{
MADStream* music = nullptr;
auto music_iter = musics.find(name);
if (music_iter != musics.end()) {
music = &music_iter->second;
} else {
auto emplaced = musics.emplace(std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple());
music = &emplaced.first->second;
}
return music->openFromFile(fileName);
}
void SoundManager::playMusic(const std::string& name)
{
auto music = musics.find(name);
if (music != musics.end()) {
music->second.play();
}
}
void SoundManager::stopMusic(const std::string& name)
{
auto music = musics.find(name);
if (music != musics.end()) {
music->second.stop();
}
}
void SoundManager::pause(bool p)
{
if( backgroundNoise )
{
if( p )
{
backgroundNoise->pause();
}
else
{
backgroundNoise->play();
if (backgroundNoise.length() > 0) {
if (p) {
pauseSound(backgroundNoise);
} else {
playSound(backgroundNoise);
}
}
}

View File

@ -0,0 +1,30 @@
#include "audio/alCheck.hpp"
#include <AL/al.h>
#include <AL/alc.h>
#include <iostream>
void checkALerror(const std::string& file, unsigned int line)
{
ALenum err = alGetError();
if (err != AL_NO_ERROR) {
std::cerr << "OpenAL error at " << file << ":" << line << ": ";
switch (err) {
case AL_INVALID_NAME:
std::cerr << "Invalid name!";
break;
case AL_INVALID_VALUE:
std::cerr << "Invalid value!";
break;
case AL_INVALID_OPERATION:
std::cerr << "Invalid operation!";
break;
default:
std::cerr << err;
}
std::cerr << std::endl;
}
}

View File

@ -492,59 +492,40 @@ void GameData::loadWeaponDAT(const std::string &name)
bool GameData::loadAudioStream(const std::string &name)
{
auto fname = findPathRealCase(datpath + "/audio/", name);
auto filePath = findPathRealCase(datpath + "/audio/", name);
if ( engine->cutsceneAudio )
{
delete engine->cutsceneAudio;
engine->cutsceneAudio = nullptr;
if (engine->cutsceneAudio.length() > 0) {
engine->sound.stopMusic(engine->cutsceneAudio);
}
bool result = false;
if ( name.find(".mp3") != name.npos )
{
auto stream = new MADStream;
engine->cutsceneAudio = stream;
result = stream->openFromFile(fname);
if (engine->sound.loadMusic(name, filePath)) {
engine->cutsceneAudio = name;
return true;
}
else
{
auto stream = new sf::Music;
engine->cutsceneAudio = stream;
result = stream->openFromFile(fname);
}
return result;
return false;
}
bool GameData::loadAudioClip(const std::string& name)
bool GameData::loadAudioClip(const std::string& name, const std::string& fileName)
{
auto fname = findPathRealCase(datpath + "/audio/", name);
auto filePath = findPathRealCase(datpath + "/audio/", fileName);
if ( engine->missionAudio )
{
delete engine->missionAudio;
engine->missionAudio = nullptr;
}
if ( name.find(".mp3") != name.npos )
if (fileName.find(".mp3") != fileName.npos)
{
logger->error("Data", "MP3 Audio unsupported outside cutscenes");
return false;
}
engine->missionAudio = new sf::SoundBuffer;
bool r = engine->missionAudio->loadFromFile(fname);
if (! r )
{
logger->error("Data", "Error loading audio clip " + fname);
delete engine->missionAudio;
engine->missionAudio = nullptr;
bool loaded = engine->sound.loadSound(name, filePath);
if ( ! loaded) {
logger->error("Data", "Error loading audio clip "+ filePath);
return false;
}
return r;
engine->missionAudio = name;
return true;
}
void GameData::loadSplash(const std::string &name)

View File

@ -78,7 +78,7 @@ public:
GameWorld::GameWorld(Logger* log, WorkContext* work, GameData* dat)
: logger(log), data(dat), randomEngine(rand()),
_work( work ), cutsceneAudio(nullptr), missionAudio(nullptr),
_work( work ),
paused(false)
{
data->engine = this;
@ -833,8 +833,9 @@ void GameWorld::startCutscene()
{
state->cutsceneStartTime = getGameTime();
state->skipCutscene = false;
if( cutsceneAudio ) {
cutsceneAudio->play();
if (cutsceneAudio.length() > 0) {
sound.playMusic(cutsceneAudio);
}
}
@ -844,11 +845,9 @@ void GameWorld::clearCutscene()
destroyObjectQueued(p.second);
}
if( cutsceneAudio )
{
cutsceneAudio->stop();
delete cutsceneAudio;
cutsceneAudio = nullptr;
if (cutsceneAudio.length() > 0) {
sound.stopMusic(cutsceneAudio);
cutsceneAudio = "";
}
delete state->currentCutscene;

View File

@ -2,6 +2,8 @@
#include <render/GameRenderer.hpp>
#include <engine/GameWorld.hpp>
#include <algorithm>
/// @todo This is very rough
int charToIndex(char g)
{

View File

@ -789,10 +789,9 @@ void game_load_audio(const ScriptArguments& args)
{
std::string name = args[0].string;
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
if(! args.getWorld()->data->loadAudioClip(name + ".wav") )
{
if(! args.getWorld()->data->loadAudioClip(name + ".mp3") )
{
if ( ! args.getWorld()->data->loadAudioClip(name, name + ".wav")) {
if ( ! args.getWorld()->data->loadAudioClip(name, name + ".mp3")) {
args.getWorld()->logger->error("SCM", "Failed to load audio: " + name);
}
}
@ -801,22 +800,26 @@ void game_load_audio(const ScriptArguments& args)
bool game_is_audio_loaded(const ScriptArguments& args)
{
auto world = args.getWorld();
return world->missionAudio != nullptr;
return world->sound.isLoaded(world->missionAudio);
}
void game_play_mission_audio(const ScriptArguments& args)
{
auto world = args.getWorld();
if ( world->missionAudio )
{
world->missionSound.setBuffer(*args.getWorld()->missionAudio);
world->missionSound.play();
world->missionSound.setLoop(false);
if (world->missionAudio.length() > 0) {
world->sound.playSound(world->missionAudio);
}
}
bool game_is_audio_finished(const ScriptArguments& args)
{
return args.getWorld()->missionSound.getStatus() == sf::SoundSource::Stopped;
auto world = args.getWorld();
bool isFinished = ! world->sound.isPlaying(world->missionAudio);
if (isFinished) {
world->missionAudio = "";
}
return isFinished;
}
void game_play_music_id(const ScriptArguments& args)
@ -828,16 +831,14 @@ void game_play_music_id(const ScriptArguments& args)
std::string name = "Miscom";
// TODO play anything other than Miscom.wav
if(! gw->data->loadAudioClip( name + ".wav" ) )
if(! gw->data->loadAudioClip( name, name + ".wav" ) )
{
args.getWorld()->logger->error("SCM", "Error loading audio " + name);
return;
}
else if ( args.getWorld()->missionAudio )
else if (args.getWorld()->missionAudio.length() > 0)
{
gw->missionSound.setBuffer(* args.getWorld()->missionAudio);
gw->missionSound.play();
gw->missionSound.setLoop(false);
args.getWorld()->sound.playSound(args.getWorld()->missionAudio);
}
}