Update sound engine with some sound fixes

* Refactor client module
master
Eduardo Bart 11 years ago
parent 52ede065fc
commit 62cd3d04e1

@ -1,30 +1,33 @@
Client = {}
local musicFilename = "startup"
local musicChannel = g_sounds.getChannel(1)
local musicFilename = "startup.ogg"
function Client.setMusic(filename)
function setMusic(filename)
musicFilename = filename
g_sounds.stopMusic(0)
if not g_game.isOnline() then
g_sounds.playMusic(musicFilename, 3)
musicChannel:stop()
musicChannel:enqueue(musicFilename, 3)
end
end
function Client.reloadScripts()
function reloadScripts()
g_textures.clearTexturesCache()
g_modules.reloadModules()
dofile '/otclientrc'
dofile('/' .. g_app.getCompactName() .. 'rc')
local message = tr('All modules and scripts were reloaded.')
modules.game_textmessage.displayGameMessage(message)
print(message)
end
function Client.startup()
function startup()
-- Play startup music (The Silver Tree, by Mattias Westlund)
g_sounds.playMusic(musicFilename, 3)
connect(g_game, { onGameStart = function() g_sounds.stopMusic(3) end })
connect(g_game, { onGameEnd = function() g_sounds.playMusic(musicFilename, 3) end })
musicChannel:enqueue(musicFilename, 3)
connect(g_game, { onGameStart = function() musicChannel:stop(3) end })
connect(g_game, { onGameEnd = function()
g_sounds.stopAll()
musicChannel:enqueue(musicFilename, 3)
end })
-- Check for startup errors
local errtitle = nil
@ -44,7 +47,7 @@ function Client.startup()
end
end
function Client.init()
function init()
g_window.setMinimumSize({ width = 600, height = 480 })
g_sounds.preload(musicFilename)
@ -62,6 +65,8 @@ function Client.init()
local defaultPos = { x = (displaySize.width - size.width)/2,
y = (displaySize.height - size.height)/2 }
local pos = g_settings.getPoint('window-pos', defaultPos)
pos.x = math.max(pos.x, 0)
pos.y = math.max(pos.y, 0)
g_window.move(pos)
-- window maximized?
@ -69,23 +74,25 @@ function Client.init()
if maximized then g_window.maximize() end
end
g_window.setTitle('OTClient')
g_window.setIcon(resolvepath('clienticon.png'))
g_keyboard.bindKeyDown('Ctrl+Shift+R', Client.reloadScripts)
g_window.setTitle(g_app.getName())
g_window.setIcon(resolvepath('clienticon'))
-- poll resize events
g_window.poll()
connect(g_app, { onRun = Client.startup })
g_keyboard.bindKeyDown('Ctrl+Shift+R', reloadScripts)
connect(g_app, { onRun = startup })
end
function Client.terminate()
function terminate()
-- save window configs
g_settings.set('window-size', g_window.getUnmaximizedSize())
g_settings.set('window-pos', g_window.getUnmaximizedPos())
g_settings.set('window-maximized', g_window.isMaximized())
local protocolVersion = g_game.getProtocolVersion()
if protocolVersion ~= 0 then
g_settings.set('protocol-version', protocolVersion)
local clientVersion = g_game.getProtocolVersion()
if clientVersion ~= 0 then
g_settings.set('client-version', clientVersion)
end
Client = nil
end

@ -4,6 +4,10 @@ Module
author: edubart
website: www.otclient.info
reloadable: false
sandboxed: true
scripts: [ client ]
@onLoad: init()
@onUnload: terminate()
load-later:
- client_skins
@ -18,9 +22,3 @@ Module
- client_exit
//- client_stats
@onLoad: |
dofile 'client'
Client.init()
@onUnload: |
Client.terminate()

@ -184,7 +184,7 @@ function Options.setOption(key, value)
modules.game_interface.updateStretchShrink()
end)
elseif key == 'enableMusic' then
g_sounds.enableMusic(value)
g_sounds.enableAudio(value)
elseif key == 'showLeftPanel' then
addEvent(function()
modules.game_interface.getLeftPanel():setOn(value)

@ -426,6 +426,8 @@ if(FRAMEWORK_SOUND)
${CMAKE_CURRENT_LIST_DIR}/sound/oggsoundfile.h
${CMAKE_CURRENT_LIST_DIR}/sound/soundbuffer.cpp
${CMAKE_CURRENT_LIST_DIR}/sound/soundbuffer.h
${CMAKE_CURRENT_LIST_DIR}/sound/soundchannel.cpp
${CMAKE_CURRENT_LIST_DIR}/sound/soundchannel.h
${CMAKE_CURRENT_LIST_DIR}/sound/soundfile.cpp
${CMAKE_CURRENT_LIST_DIR}/sound/soundfile.h
${CMAKE_CURRENT_LIST_DIR}/sound/soundmanager.cpp

@ -34,6 +34,14 @@
#include <framework/stdext/net.h>
#include <framework/platform/platform.h>
#ifdef FW_SOUND
#include <framework/sound/soundmanager.h>
#include <framework/sound/soundsource.h>
#include <framework/sound/soundchannel.h>
#include <framework/sound/combinedsoundsource.h>
#include <framework/sound/streamsoundsource.h>
#endif
#ifdef FW_GRAPHICS
#include <framework/graphics/graphics.h>
#include <framework/platform/platformwindow.h>
@ -759,15 +767,29 @@ void Application::registerLuaFunctions()
// SoundManager
g_lua.registerSingletonClass("g_sounds");
g_lua.bindSingletonFunction("g_sounds", "preload", &SoundManager::preload, &g_sounds);
g_lua.bindSingletonFunction("g_sounds", "enableSound", &SoundManager::enableSound, &g_sounds);
g_lua.bindSingletonFunction("g_sounds", "play", &SoundManager::play, &g_sounds);
g_lua.bindSingletonFunction("g_sounds", "enableMusic", &SoundManager::enableMusic, &g_sounds);
g_lua.bindSingletonFunction("g_sounds", "playMusic", &SoundManager::playMusic, &g_sounds);
g_lua.bindSingletonFunction("g_sounds", "stopMusic", &SoundManager::stopMusic, &g_sounds);
g_lua.bindSingletonFunction("g_sounds", "isMusicEnabled", &SoundManager::isMusicEnabled, &g_sounds);
g_lua.bindSingletonFunction("g_sounds", "isSoundEnabled", &SoundManager::isSoundEnabled, &g_sounds);
g_lua.bindSingletonFunction("g_sounds", "getChannel", &SoundManager::getChannel, &g_sounds);
g_lua.bindSingletonFunction("g_sounds", "stopAll", &SoundManager::stopAll, &g_sounds);
g_lua.bindSingletonFunction("g_sounds", "enableAudio", &SoundManager::enableAudio, &g_sounds);
g_lua.bindSingletonFunction("g_sounds", "disableAudio", &SoundManager::disableAudio, &g_sounds);
g_lua.bindSingletonFunction("g_sounds", "setAudioEnabled", &SoundManager::setAudioEnabled, &g_sounds);
g_lua.bindSingletonFunction("g_sounds", "isAudioEnabled", &SoundManager::isAudioEnabled, &g_sounds);
g_lua.bindSingletonFunction("g_sounds", "getCurrentMusic", &SoundManager::getCurrentMusic, &g_sounds);
g_lua.registerClass<SoundSource>();
g_lua.registerClass<CombinedSoundSource, SoundSource>();
g_lua.registerClass<StreamSoundSource, SoundSource>();
g_lua.registerClass<SoundChannel>();
g_lua.bindClassMemberFunction<SoundChannel>("play", &SoundChannel::play);
g_lua.bindClassMemberFunction<SoundChannel>("stop", &SoundChannel::stop);
g_lua.bindClassMemberFunction<SoundChannel>("enqueue", &SoundChannel::enqueue);
g_lua.bindClassMemberFunction<SoundChannel>("enable", &SoundChannel::enable);
g_lua.bindClassMemberFunction<SoundChannel>("disable", &SoundChannel::disable);
g_lua.bindClassMemberFunction<SoundChannel>("setGain", &SoundChannel::setGain);
g_lua.bindClassMemberFunction<SoundChannel>("getGain", &SoundChannel::getGain);
g_lua.bindClassMemberFunction<SoundChannel>("setEnabled", &SoundChannel::setEnabled);
g_lua.bindClassMemberFunction<SoundChannel>("isEnabled", &SoundChannel::isEnabled);
g_lua.bindClassMemberFunction<SoundChannel>("getId", &SoundChannel::getId);
#endif
#ifdef FW_SQL

@ -34,6 +34,7 @@ class SoundManager;
class SoundSource;
class SoundBuffer;
class SoundFile;
class SoundChannel;
class StreamSoundSource;
class CombinedSoundSource;
class OggSoundFile;
@ -41,6 +42,7 @@ class OggSoundFile;
typedef stdext::shared_object_ptr<SoundSource> SoundSourcePtr;
typedef stdext::shared_object_ptr<SoundFile> SoundFilePtr;
typedef stdext::shared_object_ptr<SoundBuffer> SoundBufferPtr;
typedef stdext::shared_object_ptr<SoundChannel> SoundChannelPtr;
typedef stdext::shared_object_ptr<StreamSoundSource> StreamSoundSourcePtr;
typedef stdext::shared_object_ptr<CombinedSoundSource> CombinedSoundSourcePtr;
typedef stdext::shared_object_ptr<OggSoundFile> OggSoundFilePtr;

@ -46,21 +46,21 @@ void SoundManager::init()
g_logger.error(stdext::format("unable to create audio context: %s", alcGetString(m_device, alcGetError(m_device))));
return;
}
alcMakeContextCurrent(m_context);
m_musicEnabled = true;
m_soundEnabled = true;
if(alcMakeContextCurrent(m_context) != ALC_TRUE) {
g_logger.error(stdext::format("unable to make context current: %s", alcGetString(m_device, alcGetError(m_device))));
return;
}
}
void SoundManager::terminate()
{
ensureContext();
m_sources.clear();
m_buffers.clear();
m_musicSource = nullptr;
m_currentMusic = "";
m_musicEnabled = false;
m_soundEnabled = false;
m_channels.clear();
m_audioEnabled = false;
alcMakeContextCurrent(nullptr);
@ -85,6 +85,7 @@ void SoundManager::poll()
lastUpdate = now;
ensureContext();
for(auto it = m_sources.begin(); it != m_sources.end();) {
SoundSourcePtr source = *it;
@ -96,10 +97,8 @@ void SoundManager::poll()
++it;
}
if(m_musicSource) {
m_musicSource->update();
if(!m_musicSource->isPlaying())
m_musicSource = nullptr;
for(auto it : m_channels) {
it.second->update();
}
if(m_context) {
@ -107,18 +106,33 @@ void SoundManager::poll()
}
}
void SoundManager::setAudioEnabled(bool enable)
{
if(m_audioEnabled == enable)
return;
m_audioEnabled = enable;
if(!enable) {
ensureContext();
for(const SoundSourcePtr& source : m_sources) {
source->stop();
}
}
}
void SoundManager::preload(std::string filename)
{
filename = g_resources.resolvePath(filename);
filename = resolveSoundFile(filename);
auto it = m_buffers.find(filename);
if(it != m_buffers.end())
return;
ensureContext();
SoundFilePtr soundFile = SoundFile::loadSoundFile(filename);
// only keep small files
if(soundFile->getSize() > MAX_CACHE_SIZE)
if(!soundFile || soundFile->getSize() > MAX_CACHE_SIZE)
return;
SoundBufferPtr buffer = SoundBufferPtr(new SoundBuffer);
@ -126,85 +140,55 @@ void SoundManager::preload(std::string filename)
m_buffers[filename] = buffer;
}
void SoundManager::enableSound(bool enable)
SoundSourcePtr SoundManager::play(std::string filename, float fadetime, float gain)
{
if(!isAudioEnabled())
return;
}
if(!m_audioEnabled)
return nullptr;
void SoundManager::play(std::string filename)
{
if(!m_soundEnabled || filename.empty())
return;
ensureContext();
filename = g_resources.resolvePath(filename);
if(gain == 0)
gain = 1.0f;
filename = resolveSoundFile(filename);
SoundSourcePtr soundSource = createSoundSource(filename);
if(!soundSource) {
g_logger.error(stdext::format("unable to play '%s'", filename));
return;
return nullptr;
}
soundSource->setName(filename);
soundSource->setRelative(true);
soundSource->setGain(gain);
if(fadetime > 0) {
soundSource->setFading(StreamSoundSource::FadingOn, fadetime);
}
soundSource->play();
m_sources.push_back(soundSource);
return soundSource;
}
void SoundManager::enableMusic(bool enable)
SoundChannelPtr SoundManager::getChannel(int channel)
{
if(!isAudioEnabled())
return;
m_musicEnabled = enable;
if(enable && !m_currentMusic.empty())
playMusic(m_currentMusic, 3.0f);
else
m_musicSource = nullptr;
ensureContext();
if(!m_channels[channel])
m_channels[channel] = SoundChannelPtr(new SoundChannel(channel));
return m_channels[channel];
}
void SoundManager::playMusic(std::string filename, float fadetime)
void SoundManager::stopAll()
{
if(filename.empty())
return;
filename = g_resources.resolvePath(filename);
if(m_currentMusic == filename && m_musicSource)
return;
if(!m_musicEnabled)
return;
if(filename.empty()) {
m_musicSource = nullptr;
return;
ensureContext();
for(const SoundSourcePtr& source : m_sources) {
source->stop();
}
m_musicSource = createSoundSource(filename);
if(!m_musicSource) {
g_logger.error(stdext::format("unable to play '%s'", filename));
return;
}
m_musicSource->setRelative(true);
if(fadetime > 0) {
m_musicSource->setGain(0);
m_musicSource->setFading(StreamSoundSource::FadingOn, fadetime);
}
m_musicSource->play();
}
void SoundManager::stopMusic(float fadetime)
{
if(m_musicSource) {
if(fadetime > 0)
m_musicSource->setFading(StreamSoundSource::FadingOff, 3.0f);
else
m_musicSource->stop();
for(auto it : m_channels) {
it.second->stop();
}
}
@ -212,51 +196,69 @@ SoundSourcePtr SoundManager::createSoundSource(const std::string& filename)
{
SoundSourcePtr source;
auto it = m_buffers.find(filename);
if(it != m_buffers.end()) {
source = SoundSourcePtr(new SoundSource);
source->setBuffer(it->second);
} else {
SoundFilePtr soundFile = SoundFile::loadSoundFile(filename);
if(!soundFile)
return nullptr;
if(soundFile->getSize() <= MAX_CACHE_SIZE) {
try {
auto it = m_buffers.find(filename);
if(it != m_buffers.end()) {
source = SoundSourcePtr(new SoundSource);
SoundBufferPtr buffer = SoundBufferPtr(new SoundBuffer);
buffer->fillBuffer(soundFile);
source->setBuffer(buffer);
m_buffers[filename] = buffer;
g_logger.warning(stdext::format("uncached sound '%s' requested to be played", filename));
source->setBuffer(it->second);
} else {
StreamSoundSourcePtr streamSource(new StreamSoundSource);
streamSource->setSoundFile(soundFile);
source = streamSource;
#if defined __linux && !defined OPENGL_ES
// due to OpenAL implementation bug, stereo buffers are always downmixed to mono on linux systems
// this is hack to work around the issue
// solution taken from http://opensource.creative.com/pipermail/openal/2007-April/010355.html
if(soundFile->getSampleFormat() == AL_FORMAT_STEREO16) {
CombinedSoundSourcePtr combinedSource(new CombinedSoundSource);
streamSource->downMix(StreamSoundSource::DownMixLeft);
streamSource->setRelative(true);
streamSource->setPosition(Point(-128, 0));
combinedSource->addSource(streamSource);
streamSource = StreamSoundSourcePtr(new StreamSoundSource);
streamSource->setSoundFile(SoundFile::loadSoundFile(filename));
streamSource->downMix(StreamSoundSource::DownMixRight);
streamSource->setRelative(true);
streamSource->setPosition(Point(128,0));
combinedSource->addSource(streamSource);
source = combinedSource;
SoundFilePtr soundFile = SoundFile::loadSoundFile(filename);
if(!soundFile)
return nullptr;
if(soundFile->getSize() <= MAX_CACHE_SIZE) {
source = SoundSourcePtr(new SoundSource);
SoundBufferPtr buffer = SoundBufferPtr(new SoundBuffer);
buffer->fillBuffer(soundFile);
source->setBuffer(buffer);
m_buffers[filename] = buffer;
g_logger.warning(stdext::format("uncached sound '%s' requested to be played", filename));
} else {
StreamSoundSourcePtr streamSource(new StreamSoundSource);
streamSource->setSoundFile(soundFile);
source = streamSource;
#if defined __linux && !defined OPENGL_ES
// due to OpenAL implementation bug, stereo buffers are always downmixed to mono on linux systems
// this is hack to work around the issue
// solution taken from http://opensource.creative.com/pipermail/openal/2007-April/010355.html
if(soundFile->getSampleFormat() == AL_FORMAT_STEREO16) {
CombinedSoundSourcePtr combinedSource(new CombinedSoundSource);
streamSource->downMix(StreamSoundSource::DownMixLeft);
streamSource->setRelative(true);
streamSource->setPosition(Point(-128, 0));
combinedSource->addSource(streamSource);
streamSource = StreamSoundSourcePtr(new StreamSoundSource);
streamSource->setSoundFile(SoundFile::loadSoundFile(filename));
streamSource->downMix(StreamSoundSource::DownMixRight);
streamSource->setRelative(true);
streamSource->setPosition(Point(128,0));
combinedSource->addSource(streamSource);
source = combinedSource;
}
#endif
}
#endif
}
} catch(std::exception& e) {
g_logger.error(stdext::format("failed to load sound source: '%s'", e.what()));
return nullptr;
}
return source;
}
std::string SoundManager::resolveSoundFile(std::string file)
{
file = g_resources.guessFileType(file, "ogg");
file = g_resources.resolvePath(file);
return file;
}
void SoundManager::ensureContext()
{
if(m_context)
alcMakeContextCurrent(m_context);
}

@ -24,6 +24,7 @@
#define SOUNDMANAGER_H
#include "declarations.h"
#include "soundchannel.h"
//@bindsingleton g_sounds
class SoundManager
@ -32,38 +33,34 @@ class SoundManager
MAX_CACHE_SIZE = 100000,
POLL_DELAY = 100
};
public:
void init();
void terminate();
void poll();
void preload(std::string filename);
void enableSound(bool enable);
void play(std::string filename);
void setAudioEnabled(bool enable);
bool isAudioEnabled() { return m_device && m_context && m_audioEnabled ; }
void enableAudio() { setAudioEnabled(true); }
void disableAudio() { setAudioEnabled(true); }
void stopAll();
void enableMusic(bool enable);
void playMusic(std::string filename, float fadetime);
void stopMusic(float fadetime = 0);
void preload(std::string filename);
SoundSourcePtr play(std::string filename, float fadetime = 0, float gain = 0);
SoundChannelPtr getChannel(int channel);
bool isMusicEnabled() { return m_musicEnabled; }
bool isSoundEnabled() { return m_soundEnabled; }
bool isAudioEnabled() { return m_device && m_context; }
std::string getCurrentMusic() { return m_currentMusic; }
std::string resolveSoundFile(std::string file);
void ensureContext();
private:
StreamSoundSourcePtr createStreamSoundSource(const std::string& filename);
SoundSourcePtr createSoundSource(const std::string& filename);
uint loadFileIntoBuffer(const SoundFilePtr& soundFile);
std::unordered_map<std::string, SoundBufferPtr> m_buffers;
std::vector<SoundSourcePtr> m_sources;
SoundSourcePtr m_musicSource;
ALCdevice *m_device;
ALCcontext *m_context;
stdext::boolean<false> m_musicEnabled;
stdext::boolean<false> m_soundEnabled;
std::string m_currentMusic;
std::unordered_map<std::string, SoundBufferPtr> m_buffers;
std::vector<SoundSourcePtr> m_sources;
stdext::boolean<true> m_audioEnabled;
std::unordered_map<int, SoundChannelPtr> m_channels;
};
extern SoundManager g_sounds;

@ -28,9 +28,12 @@
SoundSource::SoundSource()
{
m_sourceId = 0;
m_channel = 0;
m_fadeState = NoFading;
m_fadeTime = 0;
m_fadeStartTime = 0;
m_fadeGain = 0;
m_gain = 1.0f;
alGenSources(1, &m_sourceId);
assert(alGetError() == AL_NO_ERROR);
@ -95,6 +98,7 @@ void SoundSource::setReferenceDistance(float distance)
void SoundSource::setGain(float gain)
{
alSourcef(m_sourceId, AL_GAIN, gain);
m_gain = gain;
}
void SoundSource::setPitch(float pitch)
@ -114,7 +118,7 @@ void SoundSource::setVelocity(const Point& velocity)
void SoundSource::setFading(FadeState state, float fadeTime)
{
float now = g_clock.seconds();
float now = stdext::millis() / 1000.0f;
if(m_fadeState != NoFading) {
float elapsed = now - m_fadeStartTime;
float add;
@ -128,26 +132,30 @@ void SoundSource::setFading(FadeState state, float fadeTime)
m_fadeState = state;
m_fadeTime = fadeTime;
m_fadeGain = m_gain;
if(m_fadeState == FadingOn)
setGain(0.0);
}
void SoundSource::update()
{
float now = g_clock.seconds();
float now = stdext::millis() / 1000.0f;
if(m_fadeState == FadingOn) {
float elapsed = now - m_fadeStartTime;
if(elapsed >= m_fadeTime) {
setGain(1.0);
m_fadeState = NoFading;
} else {
setGain(elapsed / m_fadeTime);
setGain((elapsed / m_fadeTime) * m_fadeGain);
}
} else if(m_fadeState == FadingOff) {
float time = now - m_fadeStartTime;
if(time >= m_fadeTime) {
float elapsed = now - m_fadeStartTime;
if(elapsed >= m_fadeTime) {
setGain(m_fadeGain);
stop();
m_fadeState = NoFading;
} else {
setGain((m_fadeTime - time) / m_fadeTime);
setGain(((m_fadeTime - elapsed) / m_fadeTime) * m_fadeGain);
}
}
}

@ -25,8 +25,9 @@
#include "declarations.h"
#include "soundbuffer.h"
#include <framework/luaengine/luaobject.h>
class SoundSource : public stdext::shared_object
class SoundSource : public LuaObject
{
protected:
SoundSource(uint sourceId) : m_sourceId(sourceId) { }
@ -43,6 +44,7 @@ public:
virtual bool isBuffering();
virtual bool isPlaying() { return isBuffering(); }
void setName(const std::string& name) { m_name == name; }
virtual void setLooping(bool looping);
virtual void setRelative(bool relative);
virtual void setReferenceDistance(float distance);
@ -52,18 +54,27 @@ public:
virtual void setVelocity(const Point& velocity);
virtual void setFading(FadeState state, float fadetime);
std::string getName() { return m_name; }
uchar getChannel() { return m_channel; }
float getGain() { return m_gain; }
protected:
void setBuffer(const SoundBufferPtr& buffer);
void setChannel(uchar channel) { m_channel = channel; }
virtual void update();
friend class SoundManager;
friend class CombinedSoundSource;
uint m_sourceId;
uchar m_channel;
std::string m_name;
SoundBufferPtr m_buffer;
FadeState m_fadeState;
float m_fadeStartTime;
float m_fadeTime;
float m_fadeGain;
float m_gain;
};
#endif

@ -28,8 +28,8 @@
class StreamSoundSource : public SoundSource
{
enum {
STREAM_BUFFER_SIZE = 1024 * 200,
STREAM_FRAGMENTS = 5,
STREAM_BUFFER_SIZE = 1024 * 400,
STREAM_FRAGMENTS = 4,
STREAM_FRAGMENT_SIZE = STREAM_BUFFER_SIZE / STREAM_FRAGMENTS
};

Loading…
Cancel
Save