LumixEngine/src/audio/audio_scene.cpp

716 lines
16 KiB
C++
Raw Normal View History

2015-11-20 00:35:32 +01:00
#include "audio_scene.h"
2015-11-20 16:58:10 +01:00
#include "audio_device.h"
2015-11-21 13:04:11 +01:00
#include "audio_system.h"
2015-11-20 16:58:10 +01:00
#include "clip_manager.h"
2015-11-21 13:04:11 +01:00
#include "core/blob.h"
2015-11-20 00:35:32 +01:00
#include "core/crc32.h"
#include "core/iallocator.h"
#include "core/lua_wrapper.h"
2015-11-22 11:21:27 +01:00
#include "core/matrix.h"
2015-11-21 13:04:11 +01:00
#include "core/resource_manager.h"
#include "core/resource_manager_base.h"
2015-12-08 21:40:48 +01:00
#include "editor/world_editor.h"
#include "engine/engine.h"
#include "lua_script/lua_script_system.h"
2015-11-20 16:58:10 +01:00
#include "universe/universe.h"
2015-11-20 00:35:32 +01:00
namespace Lumix
{
2015-12-08 21:40:48 +01:00
enum class AudioSceneVersion : int
{
ECHO_ZONES,
LAST
};
2015-11-21 13:04:11 +01:00
static const uint32 LISTENER_HASH = crc32("audio_listener");
2015-11-22 17:31:19 +01:00
static const uint32 AMBIENT_SOUND_HASH = crc32("ambient_sound");
2015-12-08 17:48:11 +01:00
static const uint32 ECHO_ZONE_HASH = crc32("echo_zone");
2015-11-21 13:04:11 +01:00
static const uint32 CLIP_RESOURCE_HASH = crc32("CLIP");
2015-11-20 00:35:32 +01:00
struct Listener
{
Entity entity;
};
2015-12-08 17:48:11 +01:00
struct EchoZone
{
Entity entity;
2015-12-08 21:40:48 +01:00
float radius;
float delay;
2015-12-08 17:48:11 +01:00
ComponentIndex component;
};
2015-11-22 17:31:19 +01:00
struct AmbientSound
{
Entity entity;
ComponentIndex component;
2015-11-23 21:54:13 +01:00
AudioScene::ClipInfo* clip;
bool is_3d;
2015-11-22 17:31:19 +01:00
int playing_sound;
};
2015-11-21 13:04:11 +01:00
struct PlayingSound
{
2016-01-05 23:43:12 +01:00
AudioDevice::BufferHandle buffer_id;
2015-11-21 13:04:11 +01:00
Entity entity;
2015-11-22 11:21:27 +01:00
float time;
2015-11-23 21:54:13 +01:00
AudioScene::ClipInfo* clip;
2015-11-21 13:04:11 +01:00
};
2015-11-20 00:35:32 +01:00
struct AudioSceneImpl : public AudioScene
{
2016-01-20 22:37:00 +01:00
AudioSceneImpl(AudioSystem& system, Universe& context, IAllocator& allocator)
2015-11-20 00:35:32 +01:00
: m_allocator(allocator)
2016-01-20 22:37:00 +01:00
, m_universe(context)
2015-11-21 13:04:11 +01:00
, m_clips(allocator)
, m_system(system)
2015-11-23 21:54:13 +01:00
, m_device(system.getDevice())
2015-11-22 17:31:19 +01:00
, m_ambient_sounds(allocator)
2015-12-08 17:48:11 +01:00
, m_echo_zones(allocator)
2015-11-20 00:35:32 +01:00
{
2015-12-08 17:48:11 +01:00
m_last_echo_zone_id = 0;
2015-11-22 17:31:19 +01:00
m_last_ambient_sound_id = 0;
2015-11-21 13:04:11 +01:00
m_listener.entity = INVALID_ENTITY;
for (auto& i : m_playing_sounds)
2015-11-20 16:58:10 +01:00
{
2015-11-21 13:04:11 +01:00
i.entity = INVALID_ENTITY;
2015-11-23 21:54:13 +01:00
i.buffer_id = AudioDevice::INVALID_BUFFER_HANDLE;
2015-11-20 16:58:10 +01:00
}
}
2015-12-08 17:48:11 +01:00
~AudioSceneImpl()
2015-11-20 16:58:10 +01:00
{
2015-11-21 13:04:11 +01:00
clearClips();
2015-11-20 16:58:10 +01:00
}
2016-01-15 00:05:53 +01:00
int playSound(int entity, const char* clip_name, bool is_3d)
{
auto* clip = getClipInfo(clip_name);
if (clip) return play(entity, clip, is_3d);
return -1;
}
void sendMessage(uint32 type, void*) override
{
static const uint32 register_hash = crc32("registerLuaAPI");
if (type == register_hash)
{
registerLuaAPI();
}
}
void registerLuaAPI()
{
2016-01-20 22:37:00 +01:00
auto* scene = m_universe.getScene(crc32("lua_script"));
if (!scene) return;
auto* script_scene = static_cast<LuaScriptScene*>(scene);
lua_State* L = script_scene->getGlobalState();
2016-01-15 00:05:53 +01:00
#define REGISTER_FUNCTION(F) \
do { \
auto f = &LuaWrapper::wrapMethod<AudioSceneImpl, decltype(&AudioSceneImpl::F), &AudioSceneImpl::F>; \
if (lua_getglobal(L, "Audio") == LUA_TNIL) \
{ \
lua_pop(L, 1); \
lua_newtable(L); \
lua_setglobal(L, "Audio"); \
lua_getglobal(L, "Audio"); \
} \
lua_pushcfunction(L, f); \
lua_setfield(L, -2, #F); \
2016-01-15 00:05:53 +01:00
} while(false) \
REGISTER_FUNCTION(setEcho);
REGISTER_FUNCTION(playSound);
REGISTER_FUNCTION(setVolume);
#undef REGISTER_FUNCTION
}
void update(float time_delta, bool paused) override
2015-11-20 16:58:10 +01:00
{
2015-11-21 13:04:11 +01:00
if (m_listener.entity != INVALID_ENTITY)
{
auto pos = m_universe.getPosition(m_listener.entity);
2015-11-23 21:54:13 +01:00
m_device.setListenerPosition(pos.x, pos.y, pos.z);
2015-11-22 11:21:27 +01:00
Matrix orientation;
m_universe.getRotation(m_listener.entity).toMatrix(orientation);
auto front = orientation.getZVector();
auto up = orientation.getYVector();
2015-11-23 21:54:13 +01:00
m_device.setListenerOrientation(front.x, front.y, front.z, up.x, up.y, up.z);
2015-11-21 13:04:11 +01:00
}
2016-01-05 23:43:12 +01:00
for (int i = 0; i < lengthOf(m_playing_sounds); ++i)
2015-11-21 13:04:11 +01:00
{
2015-11-22 11:21:27 +01:00
auto& sound = m_playing_sounds[i];
2015-11-23 21:54:13 +01:00
if (sound.buffer_id == AudioDevice::INVALID_BUFFER_HANDLE) continue;
2015-11-22 11:21:27 +01:00
auto pos = m_universe.getPosition(sound.entity);
2015-11-23 21:54:13 +01:00
m_device.setSourcePosition(sound.buffer_id, pos.x, pos.y, pos.z);
2015-11-22 11:21:27 +01:00
sound.time += time_delta;
2015-11-23 21:54:13 +01:00
auto* clip_info = sound.clip;
2015-11-22 11:21:27 +01:00
if (!clip_info->looped && sound.time > clip_info->clip->getLengthSeconds())
{
2015-11-23 21:54:13 +01:00
m_device.stop(sound.buffer_id);
m_playing_sounds[i].buffer_id = AudioDevice::INVALID_BUFFER_HANDLE;
2015-11-22 11:21:27 +01:00
}
2015-11-21 13:04:11 +01:00
}
2015-11-23 21:54:13 +01:00
m_device.update(time_delta);
}
bool isAmbientSound3D(ComponentIndex cmp) override
{
return m_ambient_sounds[getAmbientSoundIdx(cmp)].is_3d;
}
void setAmbientSound3D(ComponentIndex cmp, bool is_3d) override
{
m_ambient_sounds[getAmbientSoundIdx(cmp)].is_3d = is_3d;
2015-11-20 16:58:10 +01:00
}
2015-11-22 17:31:19 +01:00
void startGame() override
{
for (auto& i : m_ambient_sounds)
{
2015-11-23 21:54:13 +01:00
if (i.clip) i.playing_sound = play(i.entity, i.clip, i.is_3d);
2015-11-22 17:31:19 +01:00
}
}
2015-11-22 11:21:27 +01:00
void stopGame() override
{
for (auto& i : m_playing_sounds)
{
2015-11-23 21:54:13 +01:00
if (i.buffer_id != AudioDevice::INVALID_BUFFER_HANDLE)
2015-11-22 11:21:27 +01:00
{
2015-11-23 21:54:13 +01:00
m_device.stop(i.buffer_id);
i.buffer_id = AudioDevice::INVALID_BUFFER_HANDLE;
2015-11-22 11:21:27 +01:00
}
}
2015-11-22 17:31:19 +01:00
for (auto& i : m_ambient_sounds)
{
i.playing_sound = -1;
}
2015-11-22 11:21:27 +01:00
}
2015-11-21 13:04:11 +01:00
ComponentIndex createListener(Entity entity)
2015-11-20 16:58:10 +01:00
{
if (m_listener.entity != INVALID_ENTITY)
{
2016-02-13 14:22:18 +01:00
g_log_warning.log("Audio") << "Listener already exists";
return INVALID_COMPONENT;
}
2015-12-08 17:48:11 +01:00
2015-11-21 13:04:11 +01:00
m_listener.entity = entity;
m_universe.addComponent(entity, LISTENER_HASH, this, 0);
return 0;
2015-11-20 00:35:32 +01:00
}
2015-11-23 21:54:13 +01:00
ClipInfo* getAmbientSoundClip(ComponentIndex cmp) override
{
return m_ambient_sounds[getAmbientSoundIdx(cmp)].clip;
}
int getClipInfoIndex(ClipInfo* info) override
2015-11-22 17:31:19 +01:00
{
2015-11-23 21:54:13 +01:00
for (int i = 0; i < m_clips.size(); ++i)
{
if (m_clips[i] == info) return i;
}
return -1;
2015-11-22 17:31:19 +01:00
}
int getAmbientSoundClipIndex(ComponentIndex cmp) override
{
return m_clips.indexOf(m_ambient_sounds[getAmbientSoundIdx(cmp)].clip);
}
void setAmbientSoundClipIndex(ComponentIndex cmp, int index) override
{
m_ambient_sounds[getAmbientSoundIdx(cmp)].clip = m_clips[index];
}
2015-11-23 21:54:13 +01:00
void setAmbientSoundClip(ComponentIndex cmp, ClipInfo* clip) override
2015-11-22 17:31:19 +01:00
{
2015-11-23 21:54:13 +01:00
m_ambient_sounds[getAmbientSoundIdx(cmp)].clip = clip;
2015-11-22 17:31:19 +01:00
}
2015-11-22 17:31:19 +01:00
2015-12-08 17:48:11 +01:00
ComponentIndex createEchoZone(Entity entity)
{
2016-01-14 16:22:25 +01:00
auto& zone = m_echo_zones.emplace();
2015-12-08 17:48:11 +01:00
zone.entity = entity;
zone.component = ++m_last_echo_zone_id;
2015-12-08 21:40:48 +01:00
zone.delay = 500.0f;
zone.radius = 10;
2015-12-08 17:48:11 +01:00
m_universe.addComponent(entity, ECHO_ZONE_HASH, this, zone.component);
return zone.component;
}
2015-12-08 21:40:48 +01:00
float getEchoZoneDelay(ComponentIndex cmp) override
{
return m_echo_zones[getEchoZoneIdx(cmp)].delay;
}
void setEchoZoneDelay(ComponentIndex cmp, float delay) override
{
m_echo_zones[getEchoZoneIdx(cmp)].delay = delay;
}
float getEchoZoneRadius(ComponentIndex cmp) override
{
return m_echo_zones[getEchoZoneIdx(cmp)].radius;
}
void setEchoZoneRadius(ComponentIndex cmp, float radius) override
{
m_echo_zones[getEchoZoneIdx(cmp)].radius = radius;
}
2015-12-08 17:48:11 +01:00
int getEchoZoneIdx(ComponentIndex component)
{
for(int i = 0, c = m_echo_zones.size(); i < c; ++i)
{
2015-12-08 21:40:48 +01:00
if (m_echo_zones[i].component == component) return i;
2015-12-08 17:48:11 +01:00
}
return -1;
}
void destroyEchoZone(ComponentIndex component)
{
int idx = getEchoZoneIdx(component);
auto entity = m_echo_zones[idx].entity;
m_echo_zones.eraseFast(idx);
m_universe.destroyComponent(entity, ECHO_ZONE_HASH, this, component);
}
2015-11-22 17:31:19 +01:00
ComponentIndex createAmbientSound(Entity entity)
{
2016-01-14 16:22:25 +01:00
auto& sound = m_ambient_sounds.emplace();
2015-11-22 17:31:19 +01:00
sound.component = ++m_last_ambient_sound_id;
sound.entity = entity;
2015-11-23 21:54:13 +01:00
sound.clip = nullptr;
2015-11-22 17:31:19 +01:00
sound.playing_sound = -1;
m_universe.addComponent(entity, AMBIENT_SOUND_HASH, this, sound.component);
return sound.component;
}
2015-12-08 17:48:11 +01:00
ComponentIndex createComponent(uint32 type, Entity entity) override;
2015-11-20 16:58:10 +01:00
2015-11-22 17:31:19 +01:00
int getAmbientSoundIdx(ComponentIndex component) const
{
for (int i = 0, c = m_ambient_sounds.size(); i < c; ++i)
{
if (m_ambient_sounds[i].component == component) return i;
}
return -1;
}
2015-12-08 17:48:11 +01:00
void destroyListener(ComponentIndex component)
2015-11-20 16:58:10 +01:00
{
2015-12-08 17:48:11 +01:00
ASSERT(component == 0);
auto entity = m_listener.entity;
m_listener.entity = INVALID_ENTITY;
m_universe.destroyComponent(entity, LISTENER_HASH, this, component);
}
void destroyAmbientSound(ComponentIndex component)
{
int idx = getAmbientSoundIdx(component);
auto entity = m_ambient_sounds[idx].entity;
m_ambient_sounds.eraseFast(idx);
m_universe.destroyComponent(entity, AMBIENT_SOUND_HASH, this, component);
2015-11-21 13:04:11 +01:00
}
2015-12-08 17:48:11 +01:00
void destroyComponent(ComponentIndex component, uint32 type) override;
2015-11-21 13:04:11 +01:00
void serialize(OutputBlob& serializer) override
{
serializer.write(m_listener.entity);
serializer.write(m_clips.size());
for (auto* clip : m_clips)
2015-11-20 16:58:10 +01:00
{
2015-11-21 13:04:11 +01:00
serializer.write(clip != nullptr);
if (!clip) continue;
2015-12-08 17:48:11 +01:00
2015-11-22 11:21:27 +01:00
serializer.write(clip->looped);
2015-11-21 13:04:11 +01:00
serializer.writeString(clip->name);
serializer.writeString(clip->clip->getPath().c_str());
2015-11-20 16:58:10 +01:00
}
2015-11-22 17:31:19 +01:00
serializer.write(m_last_ambient_sound_id);
serializer.write(m_ambient_sounds.size());
for (auto& i : m_ambient_sounds)
{
2015-11-23 21:54:13 +01:00
serializer.write(m_clips.indexOf(i.clip));
2015-11-22 17:31:19 +01:00
serializer.write(i.component);
serializer.write(i.entity);
}
2015-12-08 21:40:48 +01:00
serializer.write(m_echo_zones.size());
for (auto& i : m_echo_zones)
{
serializer.write(i);
}
2015-11-20 16:58:10 +01:00
}
2015-11-21 13:04:11 +01:00
void clearClips()
2015-11-20 00:35:32 +01:00
{
2015-11-21 13:04:11 +01:00
for (auto* clip : m_clips)
{
clip->clip->getResourceManager().get(CLIP_RESOURCE_HASH)->unload(*clip->clip);
LUMIX_DELETE(m_allocator, clip);
}
m_clips.clear();
2015-11-20 00:35:32 +01:00
}
2015-12-08 21:40:48 +01:00
void deserialize(InputBlob& serializer, int version) override
2015-11-20 00:35:32 +01:00
{
2015-11-21 13:04:11 +01:00
clearClips();
serializer.read(m_listener.entity);
if (m_listener.entity != INVALID_ENTITY)
{
m_universe.addComponent(m_listener.entity, LISTENER_HASH, this, 0);
}
int count = 0;
serializer.read(count);
m_clips.resize(count);
for (int i = 0; i < count; ++i)
{
bool is_valid;
serializer.read(is_valid);
if (!is_valid)
{
m_clips[i] = nullptr;
continue;
}
auto* clip = LUMIX_NEW(m_allocator, ClipInfo);
m_clips[i] = clip;
2015-11-22 11:21:27 +01:00
serializer.read(clip->looped);
2016-01-05 23:43:12 +01:00
serializer.readString(clip->name, lengthOf(clip->name));
2015-11-28 00:25:34 +01:00
clip->name_hash = crc32(clip->name);
2015-11-21 13:04:11 +01:00
char path[MAX_PATH_LENGTH];
2016-01-05 23:43:12 +01:00
serializer.readString(path, lengthOf(path));
2015-11-21 13:04:11 +01:00
2016-01-05 23:43:12 +01:00
clip->clip = static_cast<Clip*>(m_system.getClipManager().load(Path(path)));
2015-11-21 13:04:11 +01:00
}
2015-12-08 17:48:11 +01:00
2015-11-22 17:31:19 +01:00
serializer.read(m_last_ambient_sound_id);
serializer.read(count);
m_ambient_sounds.resize(count);
for (int i = 0; i < count; ++i)
{
auto& sound = m_ambient_sounds[i];
2015-11-23 21:54:13 +01:00
int clip_idx;
serializer.read(clip_idx);
if (clip_idx >= 0) sound.clip = m_clips[clip_idx];
2015-11-22 17:31:19 +01:00
serializer.read(sound.component);
serializer.read(sound.entity);
2015-11-23 21:54:13 +01:00
m_universe.addComponent(sound.entity, AMBIENT_SOUND_HASH, this, sound.component);
2015-11-22 17:31:19 +01:00
}
2015-12-08 21:40:48 +01:00
if (version > (int)AudioSceneVersion::ECHO_ZONES)
{
serializer.read(count);
m_echo_zones.resize(count);
for (auto& i : m_echo_zones)
{
serializer.read(i);
m_universe.addComponent(i.entity, ECHO_ZONE_HASH, this, i.component);
}
}
2015-11-21 13:04:11 +01:00
}
2015-12-08 21:40:48 +01:00
int getVersion() const override { return (int)AudioSceneVersion::LAST; }
2015-11-22 17:31:19 +01:00
bool ownComponentType(uint32 type) const override
{
return type == LISTENER_HASH || type == AMBIENT_SOUND_HASH;
}
2015-11-21 13:04:11 +01:00
ComponentIndex getComponent(Entity entity, uint32 type) override
{
if (type == LISTENER_HASH) return m_listener.entity == entity ? 0 : INVALID_COMPONENT;
for (auto& i : m_ambient_sounds)
{
if (i.entity == entity) return i.component;
}
return INVALID_COMPONENT;
}
2015-11-21 13:04:11 +01:00
int getClipCount() const override { return m_clips.size(); }
2015-12-08 17:48:11 +01:00
const char* getClipName(int index) override { return m_clips[index]->name; }
2016-01-05 23:43:12 +01:00
void addClip(const char* name, const Path& path) override
2015-11-21 13:04:11 +01:00
{
auto* clip = LUMIX_NEW(m_allocator, ClipInfo);
copyString(clip->name, name);
clip->name_hash = crc32(name);
clip->clip = static_cast<Clip*>(m_system.getClipManager().load(path));
2015-11-22 11:21:27 +01:00
clip->looped = false;
2015-11-21 13:04:11 +01:00
m_clips.push(clip);
2015-11-20 16:58:10 +01:00
}
2015-12-08 17:48:11 +01:00
2015-11-20 16:58:10 +01:00
2015-11-23 21:54:13 +01:00
void removeClip(ClipInfo* info) override
2015-11-20 00:35:32 +01:00
{
2015-11-22 11:21:27 +01:00
for (auto& i : m_playing_sounds)
{
2015-11-23 21:54:13 +01:00
if (i.clip == info && i.buffer_id != AudioDevice::INVALID_BUFFER_HANDLE)
2015-11-22 11:21:27 +01:00
{
2015-11-23 21:54:13 +01:00
m_device.stop(i.buffer_id);
i.buffer_id = AudioDevice::INVALID_BUFFER_HANDLE;
2015-11-22 11:21:27 +01:00
}
}
2015-11-22 18:37:42 +01:00
for (auto& i : m_ambient_sounds)
{
2015-11-23 21:54:13 +01:00
if (i.clip == info)
2015-11-22 18:37:42 +01:00
{
2015-11-23 21:54:13 +01:00
i.clip = nullptr;
2015-11-22 18:37:42 +01:00
i.playing_sound = -1;
}
}
2015-11-23 21:54:13 +01:00
auto* clip = info->clip;
2015-11-21 13:04:11 +01:00
if (clip)
{
clip->getResourceManager().get(CLIP_RESOURCE_HASH)->unload(*clip);
}
2015-11-23 21:54:13 +01:00
LUMIX_DELETE(m_allocator, info);
m_clips.eraseItem(info);
}
ClipInfo* getClipInfo(const char* name) override
{
auto hash = crc32(name);
for (auto* i : m_clips)
{
if (i->name_hash == hash) return i;
}
return nullptr;
}
2015-11-23 21:54:13 +01:00
ClipInfo* getClipInfo(int index) override
{
return m_clips[index];
2015-11-20 00:35:32 +01:00
}
2016-01-05 23:43:12 +01:00
void setClip(int clip_id, const Path& path) override
2015-11-20 00:35:32 +01:00
{
2015-11-21 13:04:11 +01:00
auto* clip = m_clips[clip_id]->clip;
if (clip)
{
clip->getResourceManager().get(CLIP_RESOURCE_HASH)->unload(*clip);
}
auto* new_res = m_system.getClipManager().load(path);
m_clips[clip_id]->clip = static_cast<Clip*>(new_res);
2015-11-20 00:35:32 +01:00
}
2015-11-23 21:54:13 +01:00
SoundHandle play(Entity entity, ClipInfo* clip_info, bool is_3d) override
2015-11-20 16:58:10 +01:00
{
2016-01-05 23:43:12 +01:00
for (int i = 0; i < lengthOf(m_playing_sounds); ++i)
2015-11-21 13:04:11 +01:00
{
2015-11-23 21:54:13 +01:00
if (m_playing_sounds[i].buffer_id == AudioDevice::INVALID_BUFFER_HANDLE)
2015-11-20 16:58:10 +01:00
{
2015-11-23 21:54:13 +01:00
auto* clip = clip_info->clip;
2015-11-22 11:21:27 +01:00
if (!clip->isReady()) return -1;
2015-11-23 21:54:13 +01:00
int flags = is_3d ? (int)AudioDevice::BufferFlags::IS3D : 0;
auto buffer = m_device.createBuffer(clip->getData(),
2015-11-22 11:21:27 +01:00
clip->getSize(),
clip->getChannels(),
clip->getSampleRate(),
flags);
2015-12-24 20:44:06 +01:00
if (buffer == AudioDevice::INVALID_BUFFER_HANDLE) return -1;
2015-11-23 21:54:13 +01:00
m_device.play(buffer, clip_info->looped);
2015-11-22 11:21:27 +01:00
auto pos = m_universe.getPosition(entity);
2015-11-23 21:54:13 +01:00
m_device.setSourcePosition(buffer, pos.x, pos.y, pos.z);
2015-11-22 11:21:27 +01:00
2015-11-21 13:04:11 +01:00
auto& sound = m_playing_sounds[i];
sound.buffer_id = buffer;
sound.entity = entity;
2015-11-22 11:21:27 +01:00
sound.time = 0;
2015-11-23 21:54:13 +01:00
sound.clip = clip_info;
2015-12-08 21:40:48 +01:00
for (auto& zone : m_echo_zones)
{
float dist2 = (pos - m_universe.getPosition(zone.entity)).squaredLength();
float r2 = zone.radius * zone.radius;
if (dist2 > r2) continue;
float w = dist2 / r2;
m_device.setEcho(buffer, 1, 1 - w, zone.delay, zone.delay);
break;
}
2015-11-21 13:04:11 +01:00
return i;
}
}
return INVALID_SOUND_HANDLE;
}
void stop(SoundHandle sound_id) override
{
2016-01-05 23:43:12 +01:00
ASSERT(sound_id >= 0 && sound_id < lengthOf(m_playing_sounds));
2015-11-23 21:54:13 +01:00
m_device.stop(m_playing_sounds[sound_id].buffer_id);
m_playing_sounds[sound_id].buffer_id = AudioDevice::INVALID_BUFFER_HANDLE;
2015-11-20 16:58:10 +01:00
}
2015-11-21 13:04:11 +01:00
void setVolume(SoundHandle sound_id, float volume) override
2015-11-20 16:58:10 +01:00
{
2016-01-15 00:05:53 +01:00
if (sound_id == AudioScene::INVALID_SOUND_HANDLE) return;
2016-01-05 23:43:12 +01:00
ASSERT(sound_id >= 0 && sound_id < lengthOf(m_playing_sounds));
2015-11-23 21:54:13 +01:00
m_device.setVolume(m_playing_sounds[sound_id].buffer_id, volume);
2015-11-20 00:35:32 +01:00
}
void setEcho(SoundHandle sound_id,
float wet_dry_mix,
float feedback,
float left_delay,
float right_delay)
{
2016-01-05 23:43:12 +01:00
ASSERT(sound_id >= 0 && sound_id < lengthOf(m_playing_sounds));
m_device.setEcho(m_playing_sounds[sound_id].buffer_id, wet_dry_mix, feedback, left_delay, right_delay);
}
2015-11-20 00:35:32 +01:00
Universe& getUniverse() override { return m_universe; }
IPlugin& getPlugin() const override { return m_system; }
2015-11-22 17:31:19 +01:00
int m_last_ambient_sound_id;
Array<AmbientSound> m_ambient_sounds;
2015-12-08 17:48:11 +01:00
Array<EchoZone> m_echo_zones;
int m_last_echo_zone_id;
2015-11-23 21:54:13 +01:00
AudioDevice& m_device;
2015-11-21 13:04:11 +01:00
Listener m_listener;
2015-11-20 00:35:32 +01:00
IAllocator& m_allocator;
Universe& m_universe;
2015-11-21 13:04:11 +01:00
Array<ClipInfo*> m_clips;
AudioSystem& m_system;
2015-12-02 22:27:20 +01:00
PlayingSound m_playing_sounds[AudioDevice::MAX_PLAYING_SOUNDS];
2015-11-20 00:35:32 +01:00
};
2015-12-08 17:48:11 +01:00
static struct
{
uint32 type;
ComponentIndex(AudioSceneImpl::*creator)(Entity);
void (AudioSceneImpl::*destroyer)(ComponentIndex);
} COMPONENT_INFOS[] = {
{ LISTENER_HASH, &AudioSceneImpl::createListener, &AudioSceneImpl::destroyListener },
{ AMBIENT_SOUND_HASH, &AudioSceneImpl::createAmbientSound, &AudioSceneImpl::destroyAmbientSound },
{ ECHO_ZONE_HASH, &AudioSceneImpl::createEchoZone, &AudioSceneImpl::destroyEchoZone }
};
ComponentIndex AudioSceneImpl::createComponent(uint32 type, Entity entity)
{
for(auto& i : COMPONENT_INFOS)
{
if(i.type == type)
{
return (this->*i.creator)(entity);
}
}
return INVALID_COMPONENT;
}
void AudioSceneImpl::destroyComponent(ComponentIndex component, uint32 type)
{
for(auto& i : COMPONENT_INFOS)
{
if(i.type == type)
{
(this->*i.destroyer)(component);
return;
}
}
}
2015-11-21 13:04:11 +01:00
AudioScene* AudioScene::createInstance(AudioSystem& system,
2016-01-20 22:37:00 +01:00
Universe& universe,
2015-11-21 13:04:11 +01:00
IAllocator& allocator)
2015-11-20 00:35:32 +01:00
{
2016-01-20 22:37:00 +01:00
return LUMIX_NEW(allocator, AudioSceneImpl)(system, universe, allocator);
2015-11-20 00:35:32 +01:00
}
2015-11-21 13:04:11 +01:00
void AudioScene::destroyInstance(AudioScene* scene)
2015-11-20 00:35:32 +01:00
{
LUMIX_DELETE(static_cast<AudioSceneImpl*>(scene)->m_allocator, scene);
}
} // namespace Lumix