audio WIP

This commit is contained in:
Mikulas Florek 2015-11-21 13:04:11 +01:00
parent 629c4da6bb
commit 71ac25755c
17 changed files with 482 additions and 165 deletions

View file

@ -5,6 +5,7 @@ namespace Lumix
{
class Clip;
class Engine;
class IAllocator;
class Path;
@ -13,28 +14,28 @@ class Path;
namespace Audio
{
enum class ClipFlags
{
IS3D,
enum class BufferFlags
{
IS3D = 1
};
COUNT
};
typedef void* BufferHandle;
static const BufferHandle INVALID_BUFFER_HANDLE = nullptr;
bool init(Engine& engine, IAllocator& allocator);
void shutdown();
bool init(Engine& engine, IAllocator& allocator);
void shutdown();
typedef void* ClipHandle;
ClipHandle load(const Path& path, const void* data, int size, int channels, int sample_rate, int flags);
void unload(ClipHandle clip);
void play(ClipHandle clip);
void stop(ClipHandle clip);
void pause(ClipHandle clip);
void setVolume(ClipHandle clip, float volume);
void setFrequency(ClipHandle clip, float frequency);
void setCurrentPosition(ClipHandle clip, float time_seconds);
void setListenerPosition(int index, float x, float y, float z);
void setSourcePosition(ClipHandle clip, float x, float y, float z);
BufferHandle createBuffer(const void* data, int size_bytes, int channels, int sample_rate, int flags);
void destroyBuffer(BufferHandle buffer);
void play(BufferHandle buffer);
void stop(BufferHandle buffer);
void pause(BufferHandle buffer);
void setVolume(BufferHandle buffer, float volume);
void setFrequency(BufferHandle buffer, float frequency);
void setCurrentTime(BufferHandle buffer, float time_seconds);
void setListenerPosition(int index, float x, float y, float z);
void setSourcePosition(BufferHandle buffer, float x, float y, float z);
void update(float time_delta);
} // namespace Audio

View file

@ -1,8 +1,12 @@
#include "audio_scene.h"
#include "audio_device.h"
#include "audio_system.h"
#include "clip_manager.h"
#include "core/blob.h"
#include "core/crc32.h"
#include "core/iallocator.h"
#include "core/resource_manager.h"
#include "core/resource_manager_base.h"
#include "universe/universe.h"
@ -10,13 +14,9 @@ namespace Lumix
{
namespace Audio
{
static const uint32 SOURCE_HASH = crc32("source");
static const uint32 LISTENER_HASH = crc32("listener");
static const int MAX_LISTENERS_COUNT = 1;
static const uint32 LISTENER_HASH = crc32("audio_listener");
static const uint32 CLIP_RESOURCE_HASH = crc32("CLIP");
static const int MAX_PLAYING_SOUNDS = 256;
struct Listener
@ -32,66 +32,86 @@ struct Source
};
struct PlayingSound
{
Lumix::Audio::BufferHandle buffer_id;
Entity entity;
};
struct ClipInfo
{
Clip* clip;
char name[30];
uint32 name_hash;
int index;
};
struct AudioSceneImpl : public AudioScene
{
AudioSceneImpl(IPlugin& system, Universe& universe, IAllocator& allocator)
AudioSceneImpl(AudioSystem& system, Universe& universe, IAllocator& allocator)
: m_allocator(allocator)
, m_universe(universe)
, m_system(system)
, m_sources(allocator)
, m_clips(allocator)
, m_system(system)
{
m_last_source_id = 0;
for(auto& l : m_listeners)
m_listener.entity = INVALID_ENTITY;
for (auto& i : m_playing_sounds)
{
l.entity = INVALID_ENTITY;
i.entity = INVALID_ENTITY;
i.buffer_id = Audio::INVALID_BUFFER_HANDLE;
}
}
~AudioSceneImpl()
{
clearClips();
}
void update(float time_delta) override
{
if(m_listeners[0].entity != INVALID_ENTITY)
if (m_listener.entity != INVALID_ENTITY)
{
auto pos = m_universe.getPosition(m_listeners[0].entity);
setListenerPosition(0, pos.x, pos.y, pos.z);
auto pos = m_universe.getPosition(m_listener.entity);
Audio::setListenerPosition(0, pos.x, pos.y, pos.z);
}
for (auto& i : m_playing_sounds)
{
if (i.buffer_id == Audio::INVALID_BUFFER_HANDLE) continue;
auto pos = m_universe.getPosition(i.entity);
Audio::setSourcePosition(i.buffer_id, pos.x, pos.y, pos.z);
}
Audio::update(time_delta);
}
void createListener(Entity entity)
ComponentIndex createListener(Entity entity)
{
m_listeners[0].entity = entity;
m_listener.entity = entity;
m_universe.addComponent(entity, LISTENER_HASH, this, 0);
}
void createSource(Entity entity)
{
auto& source = m_sources.pushEmpty();
source.entity = entity;
source.component = m_last_source_id;
++m_last_source_id;
return 0;
}
ComponentIndex createComponent(uint32 type, Entity entity) override
{
if(type == LISTENER_HASH && m_listeners[0].entity == INVALID_ENTITY)
if (type == LISTENER_HASH && m_listener.entity == INVALID_ENTITY)
{
createListener(entity);
}
else if(type == SOURCE_HASH)
{
createSource(entity);
return createListener(entity);
}
return INVALID_COMPONENT;
}
int getSourceIndex(ComponentIndex component)
{
for(int i = 0, c = m_sources.size(); i < c; ++i)
for (int i = 0, c = m_sources.size(); i < c; ++i)
{
if(m_sources[i].component == component) return i;
if (m_sources[i].component == component) return i;
}
return -1;
}
@ -99,17 +119,11 @@ struct AudioSceneImpl : public AudioScene
void destroyComponent(ComponentIndex component, uint32 type) override
{
if(type == LISTENER_HASH)
if (type == LISTENER_HASH)
{
auto entity = m_listeners[component].entity;
m_listeners[component].entity = INVALID_ENTITY;
m_universe.destroyComponent(entity, type, this, component);
}
else if (type == SOURCE_HASH)
{
int index = getSourceIndex(component);
auto entity = m_sources[index].entity;
m_sources.eraseFast(index);
ASSERT(component == 0);
auto entity = m_listener.entity;
m_listener.entity = INVALID_ENTITY;
m_universe.destroyComponent(entity, type, this, component);
}
}
@ -117,72 +131,181 @@ struct AudioSceneImpl : public AudioScene
void serialize(OutputBlob& serializer) override
{
ASSERT(false);
TODO("todo");
serializer.write(m_listener.entity);
serializer.write(m_clips.size());
for (auto* clip : m_clips)
{
serializer.write(clip != nullptr);
if (!clip) continue;
serializer.write(clip->index);
serializer.writeString(clip->name);
serializer.writeString(clip->clip->getPath().c_str());
}
}
void clearClips()
{
for (auto* clip : m_clips)
{
clip->clip->getResourceManager().get(CLIP_RESOURCE_HASH)->unload(*clip->clip);
LUMIX_DELETE(m_allocator, clip);
}
m_clips.clear();
}
void deserialize(InputBlob& serializer, int version) override
{
ASSERT(false);
TODO("todo");
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;
serializer.read(clip->index);
serializer.readString(clip->name, Lumix::lengthOf(clip->name));
char path[MAX_PATH_LENGTH];
serializer.readString(path, Lumix::lengthOf(path));
clip->clip = static_cast<Clip*>(m_system.getClipManager().load(Lumix::Path(path)));
}
}
bool ownComponentType(uint32 type) const override
{
return type == SOURCE_HASH || type == LISTENER_HASH;
}
bool ownComponentType(uint32 type) const override { return type == LISTENER_HASH; }
int getClipCount() const override
{
ASSERT(false);
TODO("todo");
}
int getClipCount() const override { return m_clips.size(); }
int addClip(const char* name, const Lumix::Path& path) override
{
ASSERT(false);
TODO("todo");
return -1;
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));
m_clips.push(clip);
return m_clips.size() - 1;
}
void setClipName(int clip_id, const char* clip_name) override
{
Lumix::copyString(m_clips[clip_id]->name, clip_name);
}
const char* getClipName(int clip_id) override { return m_clips[clip_id]->name; }
void removeClip(int clip_id) override
{
ASSERT(false);
TODO("todo");
auto* clip = m_clips[clip_id]->clip;
if (clip)
{
clip->getResourceManager().get(CLIP_RESOURCE_HASH)->unload(*clip);
}
LUMIX_DELETE(m_allocator, clip);
m_clips[clip_id] = nullptr;
}
void setClip(int clip_id, const Lumix::Path& path) override
{
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);
}
bool isClipIDValid(int clip_id) override
{
return m_clips[clip_id] != nullptr;
}
Clip* getClip(int clip_id) override { return m_clips[clip_id]->clip; }
int getClipID(const char* name) override
{
ASSERT(false);
TODO("todo");
uint32 hash = crc32(name);
for (int i = 0; i < m_clips.size(); ++i)
{
if (m_clips[i] && m_clips[i]->name_hash == hash) return i;
}
return -1;
}
int play(Entity entity, int clip_id) override
SoundHandle play(Entity entity, int clip_id) override
{
ASSERT(false);
TODO("todo");
}
auto* clip = m_clips[clip_id]->clip;
if (!clip) return -1;
auto buffer = Audio::createBuffer(clip->getData(),
clip->getSize(),
clip->getChannels(),
clip->getSampleRate(),
(int)Audio::BufferFlags::IS3D);
if (!buffer) return -1;
Audio::play(buffer);
void stop(int sound_id) override
auto pos = m_universe.getPosition(entity);
Audio::setSourcePosition(buffer, pos.x, pos.y, pos.z);
for (int i = 0; i < Lumix::lengthOf(m_playing_sounds); ++i)
{
if (m_playing_sounds[i].buffer_id == Audio::INVALID_BUFFER_HANDLE)
{
ASSERT(false);
TODO("todo");
auto& sound = m_playing_sounds[i];
sound.buffer_id = buffer;
sound.entity = entity;
return i;
}
}
return INVALID_SOUND_HANDLE;
}
void setVolume(int sound_id, float volume) override
void stop(SoundHandle sound_id) override
{
ASSERT(false);
TODO("todo");
ASSERT(sound_id >= 0 && sound_id < Lumix::lengthOf(m_playing_sounds));
Audio::stop(m_playing_sounds[sound_id].buffer_id);
m_playing_sounds[sound_id].buffer_id = Audio::INVALID_BUFFER_HANDLE;
}
void setVolume(SoundHandle sound_id, float volume) override
{
ASSERT(sound_id >= 0 && sound_id < Lumix::lengthOf(m_playing_sounds));
Audio::setVolume(m_playing_sounds[sound_id].buffer_id, volume);
}
@ -190,27 +313,28 @@ struct AudioSceneImpl : public AudioScene
IPlugin& getPlugin() const override { return m_system; }
Lumix::Array<Source> m_sources;
int m_last_source_id;
Listener m_listeners[MAX_LISTENERS_COUNT];
Listener m_listener;
IAllocator& m_allocator;
Universe& m_universe;
IPlugin& m_system;
Array<ClipInfo*> m_clips;
AudioSystem& m_system;
PlayingSound m_playing_sounds[MAX_PLAYING_SOUNDS];
};
static AudioScene* createInstance(IPlugin& system, Engine& engine, Universe& universe, IAllocator& allocator)
AudioScene* AudioScene::createInstance(AudioSystem& system,
Engine& engine,
Universe& universe,
IAllocator& allocator)
{
return LUMIX_NEW(allocator, AudioSceneImpl)(system, universe, allocator);
}
static void destroyInstance(AudioScene* scene)
void AudioScene::destroyInstance(AudioScene* scene)
{
LUMIX_DELETE(static_cast<AudioSceneImpl*>(scene)->m_allocator, scene);
}
} //namespace Audio
} // namespace Lumix

View file

@ -8,6 +8,8 @@ namespace Lumix
{
class AudioSystem;
class Clip;
class Path;
@ -15,9 +17,10 @@ class AudioScene : public IScene
{
public:
typedef int SoundHandle;
static const SoundHandle INVALID_SOUND_HANDLE = -1;
public:
static AudioScene* createInstance(IPlugin& system,
static AudioScene* createInstance(AudioSystem& system,
Engine& engine,
Universe& universe,
class IAllocator& allocator);
@ -27,10 +30,15 @@ public:
virtual int addClip(const char* name, const Lumix::Path& path) = 0;
virtual void removeClip(int clip_id) = 0;
virtual int getClipID(const char* name) = 0;
virtual bool isClipIDValid(int clip_id) = 0;
virtual Clip* getClip(int clid_id) = 0;
virtual void setClip(int clip_id, const Lumix::Path& path) = 0;
virtual const char* getClipName(int clip_id) = 0;
virtual void setClipName(int clip_id, const char* clip_name) = 0;
virtual int play(Entity entity, int clip_id) = 0;
virtual void stop(int sound_id) = 0;
virtual void setVolume(int sound_id, float volume) = 0;
virtual SoundHandle play(Entity entity, int clip_id) = 0;
virtual void stop(SoundHandle sound_id) = 0;
virtual void setVolume(SoundHandle sound_id, float volume) = 0;
};

View file

@ -1,5 +1,10 @@
#include "audio_system.h"
#include "audio_device.h"
#include "audio_scene.h"
#include "clip_manager.h"
#include "core/crc32.h"
#include "core/path.h"
#include "core/resource_manager.h"
#include "engine/engine.h"
#include "engine/iplugin.h"
@ -8,31 +13,46 @@ namespace Lumix
{
struct AudioSystemImpl : public IPlugin
struct AudioSystemImpl : public AudioSystem
{
AudioSystemImpl(Engine& engine)
: m_engine(engine)
, m_manager(engine.getAllocator())
{
}
ClipManager& getClipManager() override { return m_manager; }
bool create() override
{
return Audio::init(m_engine, m_engine.getAllocator());
bool result = Audio::init(m_engine, m_engine.getAllocator());
m_manager.create(crc32("CLIP"), m_engine.getResourceManager());
return result;
}
void destroy() override
{
Audio::shutdown();
m_manager.destroy();
}
const char* getName() const override { return "audio"; }
IScene* createScene(UniverseContext&) { return nullptr; }
void destroyScene(IScene* scene) { ASSERT(false); }
IScene* createScene(UniverseContext& ctx)
{
return AudioScene::createInstance(*this, m_engine, *ctx.m_universe, m_engine.getAllocator());
}
void destroyScene(IScene* scene) { AudioScene::destroyInstance(static_cast<AudioScene*>(scene)); }
ClipManager m_manager;
Engine& m_engine;
};

18
src/audio/audio_system.h Normal file
View file

@ -0,0 +1,18 @@
#pragma once
#include "engine/iplugin.h"
namespace Lumix
{
class AudioSystem : public IPlugin
{
public:
virtual class ClipManager& getClipManager() = 0;
};
} // namespace Lumix

View file

@ -12,10 +12,6 @@ namespace Lumix
{
namespace Audio
{
void Clip::unload()
{
m_data.clear();
@ -25,7 +21,8 @@ void Clip::unload()
bool Clip::load(FS::IFile& file)
{
short* output = nullptr;
auto res = stb_vorbis_decode_memory((unsigned char*)file.getBuffer(), file.size(), &m_channels, &m_sample_rate, &output);
auto res = stb_vorbis_decode_memory(
(unsigned char*)file.getBuffer(), (int)file.size(), &m_channels, &m_sample_rate, &output);
if (res <= 0) return false;
m_data.resize(res);
@ -48,7 +45,4 @@ void ClipManager::destroyResource(Resource& resource)
}
} // namespace Audio
} // namespace Lumix

View file

@ -10,11 +10,7 @@ namespace Lumix
{
namespace Audio
{
class LUMIX_LIBRARY_EXPORT Clip : public Resource
class LUMIX_AUDIO_API Clip : public Resource
{
public:
Clip(const Path& path, ResourceManager& manager, IAllocator& allocator)
@ -26,7 +22,8 @@ public:
void unload(void) override;
bool load(FS::IFile& file) override;
int getChannels() const { return m_channels; }
int getSamplerate() const { return m_sample_rate; }
int getSampleRate() const { return m_sample_rate; }
int getSize() const { return m_data.size() * sizeof(m_data[0]); }
uint16* getData() { return &m_data[0]; }
private:
@ -36,7 +33,7 @@ private:
};
class LUMIX_LIBRARY_EXPORT ClipManager : public ResourceManagerBase
class LUMIX_AUDIO_API ClipManager : public ResourceManagerBase
{
public:
ClipManager(IAllocator& allocator)
@ -56,7 +53,4 @@ private:
};
} // namespace Audio
} // namespace Lumix

View file

@ -1,5 +1,5 @@
#include "audio_device.h"
#include "core/path.h"
#include "clip_manager.h"
#include "engine/engine.h"
#include "engine/iplugin.h"
#include <dsound.h>
@ -16,9 +16,10 @@ namespace Audio
struct
{
HMODULE library;
LPDIRECTSOUND direct_sound;
LPDIRECTSOUND8 direct_sound;
bool initialized;
LPDIRECTSOUNDBUFFER primary_buffer;
LPDIRECTSOUND3DLISTENER8 listener;
} g_audio_device;
@ -26,7 +27,8 @@ static bool initPrimaryBuffer()
{
DSBUFFERDESC primary_buffer_desc = {};
primary_buffer_desc.dwSize = sizeof(primary_buffer_desc);
primary_buffer_desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D;
primary_buffer_desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRL3D;
primary_buffer_desc.guid3DAlgorithm = DS3DALG_DEFAULT;
auto result = SUCCEEDED(g_audio_device.direct_sound->CreateSoundBuffer(
&primary_buffer_desc, &g_audio_device.primary_buffer, nullptr));
if (!result) return false;
@ -34,7 +36,7 @@ static bool initPrimaryBuffer()
WAVEFORMATEX wave_format = {};
wave_format.cbSize = 0;
wave_format.nChannels = 2;
wave_format.nSamplesPerSec = 24 * 1024;
wave_format.nSamplesPerSec = 44100;
wave_format.wBitsPerSample = 16;
wave_format.nBlockAlign = wave_format.nChannels * wave_format.wBitsPerSample / 8;
wave_format.nAvgBytesPerSec = wave_format.nSamplesPerSec * wave_format.nBlockAlign;
@ -43,6 +45,15 @@ static bool initPrimaryBuffer()
result = SUCCEEDED(g_audio_device.primary_buffer->SetFormat(&wave_format));
if (!result) return false;
result = SUCCEEDED(g_audio_device.primary_buffer->QueryInterface(
IID_IDirectSound3DListener8, (void**)&g_audio_device.listener));
if (!result) return false;
g_audio_device.listener->SetDopplerFactor(1.0, DS3D_DEFERRED);
g_audio_device.listener->SetDistanceFactor(1.0f, DS3D_DEFERRED);
g_audio_device.listener->SetRolloffFactor(1.0f, DS3D_DEFERRED);
g_audio_device.primary_buffer->Play(0, 0, DSBPLAY_LOOPING);
return true;
}
@ -51,10 +62,13 @@ bool init(Engine& engine, IAllocator& allocator)
{
ASSERT(!g_audio_device.initialized);
auto result = SUCCEEDED(CoInitialize(nullptr));
ASSERT(result);
g_audio_device.library = LoadLibrary("dsound.dll");
if (!g_audio_device.library) return false;
decltype(DirectSoundCreate)* dsoundCreate =
(decltype(DirectSoundCreate)*)GetProcAddress(g_audio_device.library, "DirectSoundCreate");
auto* dsoundCreate =
(decltype(DirectSoundCreate8)*)GetProcAddress(g_audio_device.library, "DirectSoundCreate8");
if (!dsoundCreate)
{
ASSERT(false);
@ -62,7 +76,7 @@ bool init(Engine& engine, IAllocator& allocator)
return false;
}
auto result = SUCCEEDED(dsoundCreate(0, &g_audio_device.direct_sound, nullptr));
result = SUCCEEDED(dsoundCreate(0, &g_audio_device.direct_sound, nullptr));
if (!result)
{
ASSERT(false);
@ -94,14 +108,20 @@ void shutdown()
}
ClipHandle load(const Path& path, const void* data, int size, int channels, int sample_rate, int flags)
BufferHandle createBuffer(const void* data,
int size_bytes,
int channels,
int sample_rate,
int flags)
{
DSBUFFERDESC desc = {};
LPDIRECTSOUNDBUFFER buffer;
desc.dwSize = sizeof(desc);
desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLFX | DSBCAPS_LOCSOFTWARE;
if ((flags & (int)ClipFlags::IS3D) != 0) desc.dwFlags = DSBCAPS_CTRL3D;
desc.dwBufferBytes = size;
desc.dwFlags =
DSBCAPS_CTRLVOLUME | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLFX;
bool is_3d = (flags & (int)BufferFlags::IS3D) != 0;
if (is_3d) desc.dwFlags |= DSBCAPS_CTRL3D;
desc.dwBufferBytes = size_bytes;
WAVEFORMATEX wave_format = {};
wave_format.cbSize = 0;
@ -120,7 +140,7 @@ ClipHandle load(const Path& path, const void* data, int size, int channels, int
void* p1;
void* p2;
DWORD s1, s2;
result = SUCCEEDED(buffer->Lock(0, size, &p1, &s1, &p2, &s2, 0));
result = SUCCEEDED(buffer->Lock(0, size_bytes, &p1, &s1, &p2, &s2, 0));
if (!result)
{
buffer->Release();
@ -140,46 +160,57 @@ ClipHandle load(const Path& path, const void* data, int size, int channels, int
return nullptr;
}
if (is_3d)
{
LPDIRECTSOUND3DBUFFER8 source;
if (SUCCEEDED(buffer->QueryInterface(IID_IDirectSound3DBuffer8, (void**)&source)))
{
source->SetMaxDistance(10000, DS3D_DEFERRED);
source->SetMinDistance(2, DS3D_DEFERRED);
source->SetMode(DS3DMODE_NORMAL, DS3D_DEFERRED);
}
}
return buffer;
}
void unload(ClipHandle clip)
void destroyBuffer(BufferHandle clip)
{
auto buffer = (LPDIRECTSOUNDBUFFER)clip;
buffer->Release();
}
void play(ClipHandle clip)
void play(BufferHandle clip)
{
auto buffer = (LPDIRECTSOUNDBUFFER)clip;
buffer->Play(0, 0, DSBPLAY_LOOPING);
}
void stop(ClipHandle clip)
void stop(BufferHandle clip)
{
auto buffer = (LPDIRECTSOUNDBUFFER)clip;
buffer->Stop();
}
void pause(ClipHandle clip)
void pause(BufferHandle clip)
{
auto buffer = (LPDIRECTSOUNDBUFFER)clip;
buffer->Stop();
}
void setVolume(ClipHandle clip, float volume)
void setVolume(BufferHandle clip, float volume)
{
auto buffer = (LPDIRECTSOUNDBUFFER)clip;
buffer->SetVolume(DSBVOLUME_MIN + LONG(volume * (DSBVOLUME_MAX - DSBVOLUME_MIN)));
}
void setFrequency(ClipHandle clip, float frequency)
void setFrequency(BufferHandle clip, float frequency)
{
auto buffer = (LPDIRECTSOUNDBUFFER)clip;
buffer->SetFrequency(
@ -187,7 +218,7 @@ void setFrequency(ClipHandle clip, float frequency)
}
void setCurrentPosition(ClipHandle clip, float time_seconds)
void setCurrentTime(BufferHandle clip, float time_seconds)
{
auto buffer = (LPDIRECTSOUNDBUFFER)clip;
WAVEFORMATEX format;
@ -199,11 +230,17 @@ void setCurrentPosition(ClipHandle clip, float time_seconds)
}
void setSourcePosition(ClipHandle clip, float x, float y, float z)
void update(float)
{
LPDIRECTSOUND3DBUFFER source;
g_audio_device.listener->CommitDeferredSettings();
}
void setSourcePosition(BufferHandle clip, float x, float y, float z)
{
LPDIRECTSOUND3DBUFFER8 source;
auto buffer = (LPDIRECTSOUNDBUFFER)clip;
if(SUCCEEDED(buffer->QueryInterface(IID_IDirectSound3DBuffer8, (void**)&source)))
if (SUCCEEDED(buffer->QueryInterface(IID_IDirectSound3DBuffer8, (void**)&source)))
{
source->SetPosition(x, y, z, DS3D_DEFERRED);
}
@ -212,11 +249,7 @@ void setSourcePosition(ClipHandle clip, float x, float y, float z)
void setListenerPosition(int index, float x, float y, float z)
{
LPDIRECTSOUND3DBUFFER listener;
if(SUCCEEDED(g_audio_device.primary_buffer->QueryInterface(IID_IDirectSound3DBuffer8, (void**)&listener)))
{
listener->SetPosition(x, y, z, DS3D_DEFERRED);
}
g_audio_device.listener->SetPosition(x, y, z, DS3D_DEFERRED);
}

View file

@ -59,6 +59,8 @@
#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H
#define STB_VORBIS_INCLUDE_STB_VORBIS_H
#define STB_VORBIS_NO_STDIO 1
#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)
#define STB_VORBIS_NO_STDIO 1
#endif
@ -4458,7 +4460,7 @@ int stb_vorbis_decode_frame_pushdata(
while (get8_packet(f) != EOP)
if (f->eof) break;
*samples = 0;
return f->stream - data;
return (int)(f->stream - data);
}
if (error == VORBIS_continued_packet_flag_invalid) {
if (f->previous_length == 0) {
@ -4468,7 +4470,7 @@ int stb_vorbis_decode_frame_pushdata(
while (get8_packet(f) != EOP)
if (f->eof) break;
*samples = 0;
return f->stream - data;
return (int)(f->stream - data);
}
}
// if we get an error while parsing, what to do?
@ -4488,7 +4490,7 @@ int stb_vorbis_decode_frame_pushdata(
if (channels) *channels = f->channels;
*samples = len;
*output = f->outputs;
return f->stream - data;
return (int)(f->stream - data);
}
stb_vorbis *stb_vorbis_open_pushdata(
@ -4511,7 +4513,7 @@ stb_vorbis *stb_vorbis_open_pushdata(
f = vorbis_alloc(&p);
if (f) {
*f = p;
*data_used = f->stream - data;
*data_used = (int)(f->stream - data);
*error = 0;
return f;
}
@ -4527,7 +4529,7 @@ unsigned int stb_vorbis_get_file_offset(stb_vorbis *f)
#ifndef STB_VORBIS_NO_PUSHDATA_API
if (f->push_mode) return 0;
#endif
if (USE_MEMORY(f)) return f->stream - f->stream_start;
if (USE_MEMORY(f)) return (unsigned int)(f->stream - f->stream_start);
#ifndef STB_VORBIS_NO_STDIO
return ftell(f->f) - f->f_start;
#endif

View file

@ -69,6 +69,12 @@ namespace Lumix
#define LUMIX_RESTRICT __restrict
#ifdef BUILDING_AUDIO
#define LUMIX_AUDIO_API LUMIX_LIBRARY_EXPORT
#else
#define LUMIX_AUDIO_API LUMIX_LIBRARY_IMPORT
#endif
#ifdef BUILDING_PHYSICS
#define LUMIX_PHYSICS_API LUMIX_LIBRARY_EXPORT
#else

View file

@ -0,0 +1,52 @@
#include "audio/audio_scene.h"
#include "core/crc32.h"
#include "core/lua_wrapper.h"
#include "engine.h"
#include "iplugin.h"
#include "universe/universe.h"
namespace Lumix
{
namespace LuaAPI
{
static int playSound(IScene* scene,
int entity,
int clip_id)
{
return static_cast<AudioScene*>(scene)->play(entity, clip_id);
}
static void setSoundVolume(IScene* scene, int sound_id, float volume)
{
static_cast<AudioScene*>(scene)->setVolume(sound_id, volume);
}
} // namespace LuaAPI
static void registerCFunction(lua_State* L, const char* name, lua_CFunction func)
{
lua_pushcfunction(L, func);
lua_setglobal(L, name);
}
void registerAudioLuaAPI(Engine&, Universe&, lua_State* L)
{
registerCFunction(L,
"API_playSound",
LuaWrapper::wrap<decltype(&LuaAPI::playSound), LuaAPI::playSound>);
registerCFunction(L,
"API_setSoundVolume",
LuaWrapper::wrap<decltype(&LuaAPI::setSoundVolume), LuaAPI::setSoundVolume>);
}
} // namespace Lumix

View file

@ -14,19 +14,21 @@ namespace LuaAPI
{
static void moveController(
IScene* scene, int component, float x, float y, float z, float time_delta)
static void moveController(IScene* scene,
int component,
float x,
float y,
float z,
float time_delta)
{
static_cast<PhysicsScene*>(scene)
->moveController(component, Vec3(x, y, z), time_delta);
static_cast<PhysicsScene*>(scene)->moveController(component, Vec3(x, y, z), time_delta);
}
} // namespace LuaAPI
static void
registerCFunction(lua_State* L, const char* name, lua_CFunction func)
static void registerCFunction(lua_State* L, const char* name, lua_CFunction func)
{
lua_pushcfunction(L, func);
lua_setglobal(L, name);

View file

@ -32,6 +32,8 @@ class LuaScriptSystemImpl;
void registerEngineLuaAPI(Engine&, lua_State* L);
void registerUniverse(UniverseContext*, lua_State* L);
void registerPhysicsLuaAPI(Engine&, Universe&, lua_State* L);
void registerAudioLuaAPI(Engine&, Universe&, lua_State* L);
static const uint32 LUA_SCRIPT_HASH = crc32("lua_script");
@ -117,6 +119,10 @@ public:
{
registerPhysicsLuaAPI(m_system.m_engine, *m_universe_context.m_universe, L);
}
if (m_system.m_engine.getPluginManager().getPlugin("audio"))
{
registerAudioLuaAPI(m_system.m_engine, *m_universe_context.m_universe, L);
}
}

View file

@ -30,6 +30,7 @@
static const Lumix::uint32 UNIVERSE_HASH = Lumix::crc32("universe");
static const Lumix::uint32 SOURCE_HASH = Lumix::crc32("source");
static const Lumix::uint32 CLIP_HASH = Lumix::crc32("CLIP");
static const Lumix::uint32 LUA_SCRIPT_HASH = Lumix::crc32("lua_script");
@ -38,6 +39,7 @@ static Lumix::uint32 getResourceType(const char* path)
char ext[10];
Lumix::PathUtils::getExtension(ext, sizeof(ext), path);
if (Lumix::compareString(ext, "ogg") == 0) return CLIP_HASH;
if (Lumix::compareString(ext, "mat") == 0) return Lumix::ResourceManager::MATERIAL;
if (Lumix::compareString(ext, "msh") == 0) return Lumix::ResourceManager::MODEL;
if (Lumix::compareString(ext, "dds") == 0) return Lumix::ResourceManager::TEXTURE;
@ -803,6 +805,7 @@ void AssetBrowser::addResource(const char* path, const char* filename)
int index = -1;
if (Lumix::compareString(ext, "dds") == 0 || Lumix::compareString(ext, "tga") == 0 || Lumix::compareString(ext, "raw") == 0) index = TEXTURE;
if (Lumix::compareString(ext, "ogg") == 0) index = AUDIO;
if (Lumix::compareString(ext, "msh") == 0) index = MODEL;
if (Lumix::compareString(ext, "mat") == 0) index = MATERIAL;
if (Lumix::compareString(ext, "unv") == 0) index = UNIVERSE;

View file

@ -28,6 +28,7 @@ public:
TEXTURE,
UNIVERSE,
LUA_SCRIPT,
AUDIO,
Count
};

View file

@ -1,3 +1,5 @@
#include "audio/audio_scene.h"
#include "audio/clip_manager.h"
#include "asset_browser.h"
#include "core/blob.h"
#include "core/command_line_parser.h"
@ -239,6 +241,7 @@ public:
m_log_ui->onGUI();
m_import_asset_dialog->onGUI();
m_property_grid->onGUI();
showClipManager();
showEntityList();
showEntityTemplateList();
m_sceneview.onGUI();
@ -597,6 +600,49 @@ public:
}
void showClipManager()
{
if (ImGui::Begin("Clip manager"))
{
auto* audio_scene = static_cast<Lumix::AudioScene*>(m_editor->getScene(Lumix::crc32("audio")));
int clip_count = audio_scene->getClipCount();
for (int clip_id = 0; clip_id < clip_count; ++clip_id)
{
if (!audio_scene->isClipIDValid(clip_id)) continue;
if (ImGui::TreeNode((const void*)clip_id, audio_scene->getClipName(clip_id)))
{
char buf[30];
Lumix::copyString(buf, Lumix::lengthOf(buf), audio_scene->getClipName(clip_id));
if (ImGui::InputText("Name", buf, sizeof(buf)))
{
audio_scene->setClipName(clip_id, buf);
}
auto* clip = audio_scene->getClip(clip_id);
char path[Lumix::MAX_PATH_LENGTH];
Lumix::copyString(path, clip ? clip->getPath().c_str() : "");
if (m_asset_browser->resourceInput(
"Clip", "", path, Lumix::lengthOf(path), AssetBrowser::Type::AUDIO))
{
audio_scene->setClip(clip_id, Lumix::Path(path));
}
if (ImGui::Button("Remove"))
{
audio_scene->removeClip(clip_id);
--clip_count;
}
ImGui::TreePop();
}
}
if (ImGui::Button("Add"))
{
audio_scene->addClip("test", Lumix::Path("test.ogg"));
}
}
ImGui::End();
}
void showEntityList()
{
if (!m_is_entity_list_opened) return;

View file

@ -26,6 +26,12 @@ void registerLuaScriptProperties(Lumix::IAllocator& allocator)
}
void registerAudioProperties(Lumix::IAllocator& allocator)
{
PropertyRegister::registerComponentType("audio_listener", "Audio - listener");
}
void registerPhysicsProperties(Lumix::IAllocator& allocator)
{
PropertyRegister::registerComponentType("box_rigid_actor", "Physics Box");
@ -361,4 +367,5 @@ void registerProperties(Lumix::WorldEditor& editor)
registerRendererProperties(editor.getAllocator());
registerLuaScriptProperties(editor.getAllocator());
registerPhysicsProperties(editor.getAllocator());
registerAudioProperties(editor.getAllocator());
}