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"
|
2016-05-10 08:24:31 +02:00
|
|
|
#include "engine/blob.h"
|
|
|
|
#include "engine/crc32.h"
|
|
|
|
#include "engine/iallocator.h"
|
|
|
|
#include "engine/lua_wrapper.h"
|
|
|
|
#include "engine/matrix.h"
|
2016-06-22 00:46:48 +02:00
|
|
|
#include "engine/property_register.h"
|
2016-05-10 08:24:31 +02:00
|
|
|
#include "engine/resource_manager.h"
|
|
|
|
#include "engine/resource_manager_base.h"
|
2015-12-05 02:25:34 +01:00
|
|
|
#include "engine/engine.h"
|
|
|
|
#include "lua_script/lua_script_system.h"
|
2016-04-22 18:33:06 +02:00
|
|
|
#include "engine/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,
|
2016-07-08 16:27:05 +02:00
|
|
|
REFACTOR,
|
2016-10-01 10:58:17 +02:00
|
|
|
IS_3D,
|
2015-12-08 21:40:48 +01:00
|
|
|
|
|
|
|
LAST
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-06-22 00:46:48 +02:00
|
|
|
static const ComponentType LISTENER_TYPE = PropertyRegister::getComponentType("audio_listener");
|
|
|
|
static const ComponentType AMBIENT_SOUND_TYPE = PropertyRegister::getComponentType("ambient_sound");
|
|
|
|
static const ComponentType ECHO_ZONE_TYPE = PropertyRegister::getComponentType("echo_zone");
|
2016-07-24 22:21:43 +02:00
|
|
|
static const ResourceType CLIP_RESOURCE_TYPE("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
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-11-22 17:31:19 +01:00
|
|
|
struct AmbientSound
|
|
|
|
{
|
|
|
|
Entity entity;
|
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-23 21:54:13 +01:00
|
|
|
AudioScene::ClipInfo* clip;
|
2016-10-06 16:08:01 +02:00
|
|
|
bool is_3d;
|
2015-11-21 13:04:11 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-10-07 12:57:30 +02:00
|
|
|
struct AudioSceneImpl LUMIX_FINAL : public AudioScene
|
2015-11-20 00:35:32 +01:00
|
|
|
{
|
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-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
|
|
|
}
|
2016-07-21 14:23:46 +02:00
|
|
|
context.registerComponentTypeScene(LISTENER_TYPE, this);
|
|
|
|
context.registerComponentTypeScene(AMBIENT_SOUND_TYPE, this);
|
|
|
|
context.registerComponentTypeScene(ECHO_ZONE_TYPE, this);
|
2015-11-20 16:58:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-24 15:44:37 +02:00
|
|
|
void clear() override
|
2015-11-20 16:58:10 +01:00
|
|
|
{
|
2016-07-24 15:44:37 +02:00
|
|
|
for (auto* clip : m_clips)
|
|
|
|
{
|
2016-07-25 01:02:36 +02:00
|
|
|
clip->clip->getResourceManager().unload(*clip->clip);
|
2016-07-24 15:44:37 +02:00
|
|
|
LUMIX_DELETE(m_allocator, clip);
|
|
|
|
}
|
|
|
|
m_clips.clear();
|
|
|
|
m_ambient_sounds.clear();
|
|
|
|
m_echo_zones.clear();
|
2015-11-20 16:58:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 10:51:16 +02:00
|
|
|
int playSound(Entity entity, const char* clip_name, bool is_3d)
|
2016-01-15 00:05:53 +01:00
|
|
|
{
|
|
|
|
auto* clip = getClipInfo(clip_name);
|
|
|
|
if (clip) return play(entity, clip, is_3d);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-01-17 23:28:20 +01:00
|
|
|
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);
|
2016-07-01 22:19:34 +02:00
|
|
|
Matrix orientation = m_universe.getRotation(m_listener.entity).toMatrix();
|
2015-11-22 11:21:27 +01:00
|
|
|
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
|
|
|
}
|
2015-12-01 12:27:20 +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
|
|
|
|
2016-10-06 16:08:01 +02:00
|
|
|
if (sound.is_3d)
|
|
|
|
{
|
|
|
|
auto pos = m_universe.getPosition(sound.entity);
|
|
|
|
m_device.setSourcePosition(sound.buffer_id, pos.x, pos.y, pos.z);
|
|
|
|
}
|
2015-11-22 11:21:27 +01:00
|
|
|
|
2015-11-23 21:54:13 +01:00
|
|
|
auto* clip_info = sound.clip;
|
2016-10-06 16:08:01 +02:00
|
|
|
if (!clip_info->looped && m_device.isEnd(sound.buffer_id))
|
2015-11-22 11:21:27 +01:00
|
|
|
{
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
bool isAmbientSound3D(ComponentHandle cmp) override
|
2015-11-23 21:54:13 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
return m_ambient_sounds[{cmp.index}].is_3d;
|
2015-11-23 21:54:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
void setAmbientSound3D(ComponentHandle cmp, bool is_3d) override
|
2015-11-23 21:54:13 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
m_ambient_sounds[{cmp.index}].is_3d = is_3d;
|
2015-11-20 16:58:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-22 17:31:19 +01:00
|
|
|
void startGame() override
|
|
|
|
{
|
2016-07-09 00:54:39 +02:00
|
|
|
for (AmbientSound& sound : m_ambient_sounds)
|
2015-11-22 17:31:19 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
if (sound.clip) sound.playing_sound = play(sound.entity, sound.clip, sound.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
|
|
|
|
2016-07-09 00:54:39 +02:00
|
|
|
for (AmbientSound& sound : m_ambient_sounds)
|
2015-11-22 17:31:19 +01:00
|
|
|
{
|
2016-07-09 00:54:39 +02:00
|
|
|
sound.playing_sound = -1;
|
2015-11-22 17:31:19 +01:00
|
|
|
}
|
2015-11-22 11:21:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
ComponentHandle createListener(Entity entity)
|
2015-11-20 16:58:10 +01:00
|
|
|
{
|
2015-12-08 22:35:41 +01:00
|
|
|
if (m_listener.entity != INVALID_ENTITY)
|
|
|
|
{
|
2016-02-13 14:22:18 +01:00
|
|
|
g_log_warning.log("Audio") << "Listener already exists";
|
2015-12-08 22:35:41 +01:00
|
|
|
return INVALID_COMPONENT;
|
|
|
|
}
|
2015-12-08 17:48:11 +01:00
|
|
|
|
2015-11-21 13:04:11 +01:00
|
|
|
m_listener.entity = entity;
|
2016-06-22 15:05:19 +02:00
|
|
|
m_universe.addComponent(entity, LISTENER_TYPE, this, {0});
|
|
|
|
return {0};
|
2015-11-20 00:35:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
ClipInfo* getAmbientSoundClip(ComponentHandle cmp) override
|
2015-11-23 21:54:13 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
return m_ambient_sounds[{cmp.index}].clip;
|
2015-11-23 21:54:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
int getAmbientSoundClipIndex(ComponentHandle cmp) override
|
2015-12-01 12:27:20 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
return m_clips.indexOf(m_ambient_sounds[{cmp.index}].clip);
|
2015-12-01 12:27:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
void setAmbientSoundClipIndex(ComponentHandle cmp, int index) override
|
2015-12-01 12:27:20 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
m_ambient_sounds[{cmp.index}].clip = m_clips[index];
|
2015-12-01 12:27:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
void setAmbientSoundClip(ComponentHandle cmp, ClipInfo* clip) override
|
2015-11-22 17:31:19 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
m_ambient_sounds[{cmp.index}].clip = clip;
|
2015-11-22 17:31:19 +01:00
|
|
|
}
|
2015-12-01 12:27:20 +01:00
|
|
|
|
2015-11-22 17:31:19 +01:00
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
ComponentHandle createEchoZone(Entity entity)
|
2015-12-08 17:48:11 +01:00
|
|
|
{
|
2016-07-24 17:29:17 +02:00
|
|
|
EchoZone& zone = m_echo_zones.insert(entity);
|
2015-12-08 17:48:11 +01:00
|
|
|
zone.entity = entity;
|
2015-12-08 21:40:48 +01:00
|
|
|
zone.delay = 500.0f;
|
|
|
|
zone.radius = 10;
|
2016-07-08 16:27:05 +02:00
|
|
|
ComponentHandle cmp = {entity.index};
|
|
|
|
m_universe.addComponent(entity, ECHO_ZONE_TYPE, this, cmp);
|
|
|
|
return cmp;
|
2015-12-08 17:48:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
float getEchoZoneDelay(ComponentHandle cmp) override
|
2015-12-08 21:40:48 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
return m_echo_zones[{cmp.index}].delay;
|
2015-12-08 21:40:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
void setEchoZoneDelay(ComponentHandle cmp, float delay) override
|
2015-12-08 21:40:48 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
m_echo_zones[{cmp.index}].delay = delay;
|
2015-12-08 21:40:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
float getEchoZoneRadius(ComponentHandle cmp) override
|
2015-12-08 21:40:48 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
return m_echo_zones[{cmp.index}].radius;
|
2015-12-08 21:40:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
void setEchoZoneRadius(ComponentHandle cmp, float radius) override
|
2015-12-08 21:40:48 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
m_echo_zones[{cmp.index}].radius = radius;
|
2015-12-08 17:48:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
void destroyEchoZone(ComponentHandle component)
|
2015-12-08 17:48:11 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
Entity entity = {component.index};
|
|
|
|
int idx = m_echo_zones.find(entity);
|
|
|
|
m_echo_zones.eraseAt(idx);
|
2016-06-22 00:46:48 +02:00
|
|
|
m_universe.destroyComponent(entity, ECHO_ZONE_TYPE, this, component);
|
2015-12-08 17:48:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
ComponentHandle createAmbientSound(Entity entity)
|
2015-11-22 17:31:19 +01:00
|
|
|
{
|
2016-07-24 17:29:17 +02:00
|
|
|
AmbientSound& sound = m_ambient_sounds.insert(entity);
|
2015-11-22 17:31:19 +01:00
|
|
|
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;
|
2016-07-08 16:27:05 +02:00
|
|
|
ComponentHandle cmp = {entity.index};
|
|
|
|
m_universe.addComponent(entity, AMBIENT_SOUND_TYPE, this, cmp);
|
|
|
|
return cmp;
|
2015-11-22 17:31:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
ComponentHandle createComponent(ComponentType type, Entity entity) override;
|
2015-11-20 16:58:10 +01:00
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
void destroyListener(ComponentHandle component)
|
2015-11-20 16:58:10 +01:00
|
|
|
{
|
2016-06-22 15:05:19 +02:00
|
|
|
ASSERT(component.index == 0);
|
2015-12-08 17:48:11 +01:00
|
|
|
auto entity = m_listener.entity;
|
|
|
|
m_listener.entity = INVALID_ENTITY;
|
2016-06-22 00:46:48 +02:00
|
|
|
m_universe.destroyComponent(entity, LISTENER_TYPE, this, component);
|
2015-12-08 17:48:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
void destroyAmbientSound(ComponentHandle component)
|
2015-12-08 17:48:11 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
Entity entity = {component.index};
|
|
|
|
m_ambient_sounds.erase(entity);
|
2016-06-22 00:46:48 +02:00
|
|
|
m_universe.destroyComponent(entity, AMBIENT_SOUND_TYPE, this, component);
|
2015-11-21 13:04:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
void destroyComponent(ComponentHandle component, ComponentType type) override;
|
2015-12-08 17:48:11 +01:00
|
|
|
|
|
|
|
|
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_ambient_sounds.size());
|
2016-07-09 00:54:39 +02:00
|
|
|
for (const AmbientSound& sound : m_ambient_sounds)
|
2015-11-22 17:31:19 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
serializer.write(m_clips.indexOf(sound.clip));
|
|
|
|
serializer.write(sound.entity);
|
2016-10-01 10:58:17 +02:00
|
|
|
serializer.write(sound.is_3d);
|
2015-11-22 17:31:19 +01:00
|
|
|
}
|
2015-12-08 21:40:48 +01:00
|
|
|
|
|
|
|
serializer.write(m_echo_zones.size());
|
2016-07-09 00:54:39 +02:00
|
|
|
for (EchoZone& zone : m_echo_zones)
|
2015-12-08 21:40:48 +01:00
|
|
|
{
|
2016-07-09 00:54:39 +02:00
|
|
|
serializer.write(zone);
|
2015-12-08 21:40:48 +01:00
|
|
|
}
|
2015-11-20 16:58:10 +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
|
|
|
{
|
2016-07-24 15:44:37 +02:00
|
|
|
clear();
|
2015-11-21 13:04:11 +01:00
|
|
|
|
|
|
|
serializer.read(m_listener.entity);
|
|
|
|
if (m_listener.entity != INVALID_ENTITY)
|
|
|
|
{
|
2016-06-22 15:05:19 +02:00
|
|
|
m_universe.addComponent(m_listener.entity, LISTENER_TYPE, this, {0});
|
2015-11-21 13:04:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
2016-07-08 16:27:05 +02:00
|
|
|
ComponentHandle dummy_cmp;
|
|
|
|
if (version <= (int)AudioSceneVersion::REFACTOR) serializer.read(dummy_cmp);
|
2015-11-22 17:31:19 +01:00
|
|
|
serializer.read(count);
|
|
|
|
for (int i = 0; i < count; ++i)
|
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
AmbientSound sound;
|
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];
|
2016-07-08 16:27:05 +02:00
|
|
|
if (version <= (int)AudioSceneVersion::REFACTOR) serializer.read(dummy_cmp);
|
2015-11-22 17:31:19 +01:00
|
|
|
serializer.read(sound.entity);
|
2016-10-01 10:58:17 +02:00
|
|
|
if (version > (int)AudioSceneVersion::IS_3D) serializer.read(sound.is_3d);
|
2015-11-23 21:54:13 +01:00
|
|
|
|
2016-07-08 16:27:05 +02:00
|
|
|
ComponentHandle cmp = {sound.entity.index};
|
|
|
|
m_ambient_sounds.insert(sound.entity, sound);
|
|
|
|
m_universe.addComponent(sound.entity, AMBIENT_SOUND_TYPE, this, cmp);
|
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);
|
|
|
|
|
2016-07-08 16:27:05 +02:00
|
|
|
for (int i = 0; i < count; ++i)
|
2015-12-08 21:40:48 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
EchoZone zone;
|
|
|
|
serializer.read(zone);
|
|
|
|
if (version <= (int)AudioSceneVersion::REFACTOR) serializer.read(dummy_cmp);
|
|
|
|
|
|
|
|
m_echo_zones.insert(zone.entity, zone);
|
|
|
|
m_universe.addComponent(zone.entity, ECHO_ZONE_TYPE, this, {zone.entity.index});
|
2015-12-08 21:40:48 +01:00
|
|
|
}
|
|
|
|
}
|
2015-11-21 13:04:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-12-08 21:40:48 +01:00
|
|
|
int getVersion() const override { return (int)AudioSceneVersion::LAST; }
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
ComponentHandle getComponent(Entity entity, ComponentType type) override
|
2015-12-13 11:45:31 +01:00
|
|
|
{
|
2016-06-22 15:05:19 +02:00
|
|
|
if (type == LISTENER_TYPE)
|
|
|
|
{
|
|
|
|
ComponentHandle listener_cmp = { 0 };
|
|
|
|
return m_listener.entity == entity ? listener_cmp : INVALID_COMPONENT;
|
|
|
|
}
|
2015-12-13 11:45:31 +01:00
|
|
|
|
2016-06-22 00:46:48 +02:00
|
|
|
if (type == AMBIENT_SOUND_TYPE)
|
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
if (m_ambient_sounds.find(entity) < 0) return INVALID_COMPONENT;
|
|
|
|
return {entity.index};
|
2016-06-22 00:46:48 +02:00
|
|
|
}
|
|
|
|
if (type == ECHO_ZONE_TYPE)
|
2015-12-13 11:45:31 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
int idx = m_echo_zones.find(entity);
|
|
|
|
if (idx < 0) return INVALID_COMPONENT;
|
|
|
|
return {entity.index};
|
2015-12-13 11:45:31 +01:00
|
|
|
}
|
|
|
|
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; }
|
2015-12-01 12:27:20 +01:00
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-09 00:54:39 +02:00
|
|
|
for (AmbientSound& sound : m_ambient_sounds)
|
2015-11-22 18:37:42 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
if (sound.clip == info)
|
2015-11-22 18:37:42 +01:00
|
|
|
{
|
2016-07-08 16:27:05 +02:00
|
|
|
sound.clip = nullptr;
|
|
|
|
sound.playing_sound = -1;
|
2015-11-22 18:37:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-23 21:54:13 +01:00
|
|
|
auto* clip = info->clip;
|
2015-11-21 13:04:11 +01:00
|
|
|
if (clip)
|
|
|
|
{
|
2016-07-25 01:02:36 +02:00
|
|
|
clip->getResourceManager().unload(*clip);
|
2015-11-21 13:04:11 +01:00
|
|
|
}
|
2015-11-23 21:54:13 +01:00
|
|
|
LUMIX_DELETE(m_allocator, info);
|
|
|
|
m_clips.eraseItem(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-23 23:03:15 +01:00
|
|
|
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)
|
|
|
|
{
|
2016-07-25 01:02:36 +02:00
|
|
|
clip->getResourceManager().unload(*clip);
|
2015-11-21 13:04:11 +01:00
|
|
|
}
|
|
|
|
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];
|
2016-10-06 16:08:01 +02:00
|
|
|
sound.is_3d = is_3d;
|
2015-11-21 13:04:11 +01:00
|
|
|
sound.buffer_id = buffer;
|
|
|
|
sound.entity = entity;
|
2015-11-23 21:54:13 +01:00
|
|
|
sound.clip = clip_info;
|
2015-12-08 21:40:48 +01:00
|
|
|
|
2016-07-09 00:54:39 +02:00
|
|
|
for (const EchoZone& zone : m_echo_zones)
|
2015-12-08 21:40:48 +01:00
|
|
|
{
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-12-01 03:47:22 +01:00
|
|
|
void setEcho(SoundHandle sound_id,
|
|
|
|
float wet_dry_mix,
|
|
|
|
float feedback,
|
|
|
|
float left_delay,
|
2016-05-03 15:00:02 +02:00
|
|
|
float right_delay) override
|
2015-12-01 03:47:22 +01:00
|
|
|
{
|
2016-01-05 23:43:12 +01:00
|
|
|
ASSERT(sound_id >= 0 && sound_id < lengthOf(m_playing_sounds));
|
2015-12-01 03:47:22 +01:00
|
|
|
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; }
|
|
|
|
|
2016-07-08 16:27:05 +02:00
|
|
|
AssociativeArray<Entity, AmbientSound> m_ambient_sounds;
|
|
|
|
AssociativeArray<Entity, EchoZone> m_echo_zones;
|
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
|
|
|
|
{
|
2016-06-22 00:46:48 +02:00
|
|
|
ComponentType type;
|
2016-06-22 15:05:19 +02:00
|
|
|
ComponentHandle(AudioSceneImpl::*creator)(Entity);
|
|
|
|
void (AudioSceneImpl::*destroyer)(ComponentHandle);
|
2015-12-08 17:48:11 +01:00
|
|
|
} COMPONENT_INFOS[] = {
|
2016-06-22 00:46:48 +02:00
|
|
|
{ LISTENER_TYPE, &AudioSceneImpl::createListener, &AudioSceneImpl::destroyListener },
|
|
|
|
{ AMBIENT_SOUND_TYPE, &AudioSceneImpl::createAmbientSound, &AudioSceneImpl::destroyAmbientSound },
|
|
|
|
{ ECHO_ZONE_TYPE, &AudioSceneImpl::createEchoZone, &AudioSceneImpl::destroyEchoZone }
|
2015-12-08 17:48:11 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
ComponentHandle AudioSceneImpl::createComponent(ComponentType type, Entity entity)
|
2015-12-08 17:48:11 +01:00
|
|
|
{
|
|
|
|
for(auto& i : COMPONENT_INFOS)
|
|
|
|
{
|
|
|
|
if(i.type == type)
|
|
|
|
{
|
|
|
|
return (this->*i.creator)(entity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return INVALID_COMPONENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-22 15:05:19 +02:00
|
|
|
void AudioSceneImpl::destroyComponent(ComponentHandle component, ComponentType type)
|
2015-12-08 17:48:11 +01:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-02 15:35:08 +02:00
|
|
|
void AudioScene::registerLuaAPI(lua_State* L)
|
|
|
|
{
|
|
|
|
#define REGISTER_FUNCTION(F) \
|
|
|
|
do { \
|
|
|
|
auto f = &LuaWrapper::wrapMethod<AudioSceneImpl, decltype(&AudioSceneImpl::F), &AudioSceneImpl::F>; \
|
|
|
|
LuaWrapper::createSystemFunction(L, "Audio", #F, f); \
|
|
|
|
} while(false) \
|
|
|
|
|
|
|
|
REGISTER_FUNCTION(setEcho);
|
|
|
|
REGISTER_FUNCTION(playSound);
|
|
|
|
REGISTER_FUNCTION(setVolume);
|
|
|
|
|
|
|
|
#undef REGISTER_FUNCTION
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-11-20 00:35:32 +01:00
|
|
|
} // namespace Lumix
|