Initial stubs and basic Engine implementation

This commit is contained in:
Jack Andersen 2016-05-02 15:16:26 -10:00
parent 72ee790831
commit fa8d9038df
33 changed files with 947 additions and 1 deletions

46
CMakeLists.txt Normal file
View File

@ -0,0 +1,46 @@
set(SOURCES
lib/AudioGroup.cpp
lib/AudioGroupData.cpp
lib/AudioGroupPool.cpp
lib/AudioGroupProject.cpp
lib/AudioGroupSampleDirectory.cpp
lib/Emitter.cpp
lib/Engine.cpp
lib/Envelope.cpp
lib/Listener.cpp
lib/Sequencer.cpp
lib/SoundMacroState.cpp
lib/Voice.cpp)
set(HEADERS
include/amuse/AudioGroup.hpp
include/amuse/AudioGroupData.hpp
include/amuse/AudioGroupPool.hpp
include/amuse/AudioGroupProject.hpp
include/amuse/AudioGroupSampleDirectory.hpp
include/amuse/Emitter.hpp
include/amuse/Engine.hpp
include/amuse/Entity.hpp
include/amuse/Envelope.hpp
include/amuse/Listener.hpp
include/amuse/Sequencer.hpp
include/amuse/SoundMacroState.hpp
include/amuse/Voice.hpp
include/amuse/IBackendVoice.hpp
include/amuse/IBackendVoiceAllocator.hpp
include/amuse/Common.hpp
include/amuse/amuse.hpp)
unset(EXTRAS)
if(TARGET boo)
include_directories(${BOO_INCLUDE_DIR})
list(APPEND EXTRAS lib/BooBackend.cpp include/amuse/BooBackend.hpp)
endif()
include_directories(include)
set(AMUSE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE PATH "amuse include path" FORCE)
add_library(amuse
${SOURCES}
${HEADERS}
${EXTRAS})

View File

@ -30,7 +30,7 @@ Here's an example usage:
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
/* Up to the client to implement voice allocation and mixing */ /* Up to the client to implement voice allocation and mixing */
std::unique_ptr<amuse::IVoiceAllocator> voxAlloc = MakeMyVoiceAllocator(); std::unique_ptr<amuse::IBackendVoiceAllocator> voxAlloc = MakeMyVoiceAllocator();
/* Application just needs one per audio output (not per channel) */ /* Application just needs one per audio output (not per channel) */
amuse::Engine snd(*voxAlloc); amuse::Engine snd(*voxAlloc);

View File

@ -0,0 +1,33 @@
#ifndef __AMUSE_AUDIOGROUP_HPP__
#define __AMUSE_AUDIOGROUP_HPP__
#include "AudioGroupPool.hpp"
#include "AudioGroupProject.hpp"
#include "AudioGroupSampleDirectory.hpp"
namespace amuse
{
class AudioGroupData;
class AudioGroup
{
int m_groupId;
AudioGroupPool m_pool;
AudioGroupProject m_proj;
AudioGroupSampleDirectory m_sdir;
const unsigned char* m_samp;
bool m_valid;
public:
operator bool() const {return m_valid;}
AudioGroup(int groupId, const AudioGroupData& data);
int groupId() const {return m_groupId;}
bool sfxInGroup(int sfxId) const;
bool songInGroup(int songId) const;
const AudioGroupSampleDirectory::Entry* getSfxEntry(int sfxId) const;
};
}
#endif // __AMUSE_AUDIOGROUP_HPP__

View File

@ -0,0 +1,40 @@
#ifndef __AMUSE_AUDIOGROUPDATA_HPP__
#define __AMUSE_AUDIOGROUPDATA_HPP__
namespace amuse
{
/**
* @brief Simple pointer-container of the four Audio Group chunks
*/
class AudioGroupData
{
protected:
unsigned char* m_pool;
unsigned char* m_proj;
unsigned char* m_sdir;
unsigned char* m_samp;
public:
AudioGroupData(unsigned char* pool, unsigned char* proj,
unsigned char* sdir, unsigned char* samp)
: m_pool(pool), m_proj(proj), m_sdir(sdir), m_samp(samp) {}
const unsigned char* getPool() const {return m_pool;}
const unsigned char* getProj() const {return m_proj;}
const unsigned char* getSdir() const {return m_sdir;}
const unsigned char* getSamp() const {return m_samp;}
};
/**
* @brief A buffer-owning version of AudioGroupData
*/
class IntrusiveAudioGroupData : public AudioGroupData
{
public:
using AudioGroupData::AudioGroupData;
~IntrusiveAudioGroupData();
};
}
#endif // __AMUSE_AUDIOGROUPDATA_HPP__

View File

@ -0,0 +1,15 @@
#ifndef __AMUSE_AUDIOGROUPPOOL_HPP__
#define __AMUSE_AUDIOGROUPPOOL_HPP__
namespace amuse
{
class AudioGroupPool
{
public:
AudioGroupPool(const unsigned char* data);
};
}
#endif // __AMUSE_AUDIOGROUPPOOL_HPP__

View File

@ -0,0 +1,15 @@
#ifndef __AMUSE_AUDIOGROUPPROJECT_HPP__
#define __AMUSE_AUDIOGROUPPROJECT_HPP__
namespace amuse
{
class AudioGroupProject
{
public:
AudioGroupProject(const unsigned char* data);
};
}
#endif // __AMUSE_AUDIOGROUPPROJECT_HPP__

View File

@ -0,0 +1,45 @@
#ifndef __AMUSE_AUDIOGROUPSAMPLEDIR_HPP__
#define __AMUSE_AUDIOGROUPSAMPLEDIR_HPP__
#include <vector>
#include <stdint.h>
namespace amuse
{
class AudioGroupSampleDirectory
{
friend class AudioGroup;
public:
struct Entry
{
uint16_t m_sfxId;
uint32_t m_sampleOff;
uint32_t m_unk;
uint8_t m_pitch;
uint16_t m_sampleRate;
uint32_t m_numSamples;
uint32_t m_loopStartSample;
uint32_t m_loopLengthSamples;
uint32_t m_adpcmParmOffset;
void swapBig();
};
struct ADPCMParms
{
uint16_t m_bytesPerFrame;
uint8_t m_ps;
uint8_t m_lps;
int16_t m_hist1;
int16_t m_hist2;
int16_t m_coefs[16];
void swapBig();
};
private:
std::vector<Entry> m_entries;
public:
AudioGroupSampleDirectory(const unsigned char* data);
};
}
#endif // __AMUSE_AUDIOGROUPSAMPLEDIR_HPP__

View File

@ -0,0 +1,43 @@
#ifndef __AMUSE_BOO_BACKEND_HPP__
#define __AMUSE_BOO_BACKEND_HPP__
#include <boo/audiodev/IAudioVoiceEngine.hpp>
#include "IBackendVoice.hpp"
#include "IBackendVoiceAllocator.hpp"
namespace amuse
{
/** Backend voice implementation for boo mixer */
class BooBackendVoice : public IBackendVoice
{
friend class BooBackendVoiceAllocator;
Voice& m_clientVox;
struct VoiceCallback : boo::IAudioVoiceCallback
{
BooBackendVoice& m_parent;
size_t supplyAudio(boo::IAudioVoice& voice, size_t frames, int16_t* data);
VoiceCallback(BooBackendVoice& parent) : m_parent(parent) {}
} m_cb;
std::unique_ptr<boo::IAudioVoice> m_booVoice;
public:
BooBackendVoice(boo::IAudioVoiceEngine& engine, Voice& clientVox,
double sampleRate, bool dynamicPitch);
void setMatrixCoefficients(const float coefs[8]);
void setPitchRatio(double ratio);
void start();
void stop();
};
/** Backend voice allocator implementation for boo mixer */
class BooBackendVoiceAllocator : public IBackendVoiceAllocator
{
boo::IAudioVoiceEngine& m_booEngine;
public:
BooBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine);
std::unique_ptr<IBackendVoice> allocateVoice(Voice& clientVox, double sampleRate, bool dynamicPitch);
};
}
#endif // __AMUSE_BOO_BACKEND_HPP__

127
include/amuse/Common.hpp Normal file
View File

@ -0,0 +1,127 @@
#ifndef __AMUSE_COMMON_HPP__
#define __AMUSE_COMMON_HPP__
namespace amuse
{
#undef bswap16
#undef bswap32
#undef bswap64
/* Type-sensitive byte swappers */
template <typename T>
static inline T bswap16(T val)
{
#if __GNUC__
return __builtin_bswap16(val);
#elif _WIN32
return _byteswap_ushort(val);
#else
return (val = (val << 8) | ((val >> 8) & 0xFF));
#endif
}
template <typename T>
static inline T bswap32(T val)
{
#if __GNUC__
return __builtin_bswap32(val);
#elif _WIN32
return _byteswap_ulong(val);
#else
val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8;
return val;
#endif
}
template <typename T>
static inline T bswap64(T val)
{
#if __GNUC__
return __builtin_bswap64(val);
#elif _WIN32
return _byteswap_uint64(val);
#else
return ((val & 0xFF00000000000000ULL) >> 56) |
((val & 0x00FF000000000000ULL) >> 40) |
((val & 0x0000FF0000000000ULL) >> 24) |
((val & 0x000000FF00000000ULL) >> 8) |
((val & 0x00000000FF000000ULL) << 8) |
((val & 0x0000000000FF0000ULL) << 24) |
((val & 0x000000000000FF00ULL) << 40) |
((val & 0x00000000000000FFULL) << 56);
#endif
}
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
static inline int16_t SBig(int16_t val) {return bswap16(val);}
static inline uint16_t SBig(uint16_t val) {return bswap16(val);}
static inline int32_t SBig(int32_t val) {return bswap32(val);}
static inline uint32_t SBig(uint32_t val) {return bswap32(val);}
static inline int64_t SBig(int64_t val) {return bswap64(val);}
static inline uint64_t SBig(uint64_t val) {return bswap64(val);}
static inline float SBig(float val)
{
int32_t ival = bswap32(*((int32_t*)(&val)));
return *((float*)(&ival));
}
static inline double SBig(double val)
{
int64_t ival = bswap64(*((int64_t*)(&val)));
return *((double*)(&ival));
}
#ifndef SBIG
#define SBIG(q) ( ( (q) & 0x000000FF ) << 24 | ( (q) & 0x0000FF00 ) << 8 \
| ( (q) & 0x00FF0000 ) >> 8 | ( (q) & 0xFF000000 ) >> 24 )
#endif
static inline int16_t SLittle(int16_t val) {return val;}
static inline uint16_t SLittle(uint16_t val) {return val;}
static inline int32_t SLittle(int32_t val) {return val;}
static inline uint32_t SLittle(uint32_t val) {return val;}
static inline int64_t SLittle(int64_t val) {return val;}
static inline uint64_t SLittle(uint64_t val) {return val;}
static inline float SLittle(float val) {return val;}
static inline double SLittle(double val) {return val;}
#ifndef SLITTLE
#define SLITTLE(q) (q)
#endif
#else
static inline int16_t SLittle(int16_t val) {return bswap16(val);}
static inline uint16_t SLittle(uint16_t val) {return bswap16(val);}
static inline int32_t SLittle(int32_t val) {return bswap32(val);}
static inline uint32_t SLittle(uint32_t val) {return bswap32(val);}
static inline int64_t SLittle(int64_t val) {return bswap64(val);}
static inline uint64_t SLittle(uint64_t val) {return bswap64(val);}
static inline float SLittle(float val)
{
int32_t ival = bswap32(*((int32_t*)(&val)));
return *((float*)(&ival));
}
static inline double SLittle(double val)
{
int64_t ival = bswap64(*((int64_t*)(&val)));
return *((double*)(&ival));
}
#ifndef SLITTLE
#define SLITTLE(q) ( ( (q) & 0x000000FF ) << 24 | ( (q) & 0x0000FF00 ) << 8 \
| ( (q) & 0x00FF0000 ) >> 8 | ( (q) & 0xFF000000 ) >> 24 )
#endif
static inline int16_t SBig(int16_t val) {return val;}
static inline uint16_t SBig(uint16_t val) {return val;}
static inline int32_t SBig(int32_t val) {return val;}
static inline uint32_t SBig(uint32_t val) {return val;}
static inline int64_t SBig(int64_t val) {return val;}
static inline uint64_t SBig(uint64_t val) {return val;}
static inline float SBig(float val) {return val;}
static inline double SBig(double val) {return val;}
#ifndef SBIG
#define SBIG(q) (q)
#endif
#endif
}
#endif // __AMUSE_COMMON_HPP__

28
include/amuse/Emitter.hpp Normal file
View File

@ -0,0 +1,28 @@
#ifndef __AMUSE_EMITTER_HPP__
#define __AMUSE_EMITTER_HPP__
#include "Entity.hpp"
namespace amuse
{
class Voice;
using Vector3f = float[3];
class Emitter : public Entity
{
Voice& m_vox;
public:
Emitter(Engine& engine, int groupId, Voice& vox);
void setPos(const Vector3f& pos);
void setDir(const Vector3f& dir);
void setMaxDist(float maxDist);
void setMaxVol(float maxVol);
void setMinVol(float minVol);
void setFalloff(float falloff);
};
}
#endif // __AMUSE_EMITTER_HPP__

55
include/amuse/Engine.hpp Normal file
View File

@ -0,0 +1,55 @@
#ifndef __AMUSE_ENGINE_HPP__
#define __AMUSE_ENGINE_HPP__
#include <memory>
#include <list>
#include <unordered_map>
#include "Emitter.hpp"
#include "AudioGroupSampleDirectory.hpp"
namespace amuse
{
class IBackendVoiceAllocator;
class Voice;
class Emitter;
class Sequencer;
class AudioGroup;
class AudioGroupData;
/** Main audio playback system for a single audio output */
class Engine
{
IBackendVoiceAllocator& m_backend;
std::unordered_map<int, std::unique_ptr<AudioGroup>> m_audioGroups;
std::list<std::unique_ptr<Voice>> m_activeVoices;
std::list<std::unique_ptr<Emitter>> m_activeEmitters;
std::list<std::unique_ptr<Sequencer>> m_activeSequencers;
Voice* _allocateVoice(int groupId, double sampleRate, bool dynamicPitch);
AudioGroup* _findGroupFromSfxId(int sfxId, const AudioGroupSampleDirectory::Entry*& entOut) const;
AudioGroup* _findGroupFromSongId(int songId) const;
public:
Engine(IBackendVoiceAllocator& backend);
/** Update all active audio entities and fill OS audio buffers as needed */
void pumpEngine();
/** Add audio group data pointers to engine; must remain resident! */
bool addAudioGroup(int groupId, const AudioGroupData& data);
/** Remove audio group from engine */
void removeAudioGroup(int groupId);
/** Start soundFX playing from loaded audio groups */
Voice* fxStart(int sfxId, float vol, float pan);
/** Start soundFX playing from loaded audio groups, attach to positional emitter */
Emitter* addEmitter(const Vector3f& pos, const Vector3f& dir, float maxDist,
float falloff, int sfxId, float minVol, float maxVol);
/** Start song playing from loaded audio groups */
Sequencer* seqPlay(int songId, const unsigned char* arrData);
};
}
#endif // __AMUSE_ENGINE_HPP__

24
include/amuse/Entity.hpp Normal file
View File

@ -0,0 +1,24 @@
#ifndef __AMUSE_ENTITY_HPP__
#define __AMUSE_ENTITY_HPP__
namespace amuse
{
class Engine;
/** Common 'engine child' class */
class Entity
{
protected:
Engine& m_engine;
int m_groupId;
public:
Entity(Engine& engine, int groupId)
: m_engine(engine), m_groupId(groupId) {}
Engine& getEngine() {return m_engine;}
int getGroupId() {return m_groupId;}
};
}
#endif // __AMUSE_ENTITY_HPP__

View File

@ -0,0 +1,13 @@
#ifndef __AMUSE_ENVELOPE_HPP__
#define __AMUSE_ENVELOPE_HPP__
namespace amuse
{
class Envelope
{
};
}
#endif // __AMUSE_ENVELOPE_HPP__

View File

@ -0,0 +1,44 @@
#ifndef __AMUSE_IBACKENDVOICE_HPP__
#define __AMUSE_IBACKENDVOICE_HPP__
namespace amuse
{
/** Same channel enums from boo, used for matrix coefficient table index */
enum class AudioChannel
{
FrontLeft,
FrontRight,
RearLeft,
RearRight,
FrontCenter,
LFE,
SideLeft,
SideRight,
Unknown = 0xff
};
/**
* @brief Client-implemented voice instance
*/
class IBackendVoice
{
public:
virtual ~IBackendVoice() = default;
/** Set channel-gains for audio source (AudioChannel enum for array index) */
virtual void setMatrixCoefficients(const float coefs[8])=0;
/** Called by client to dynamically adjust the pitch of voices with dynamic pitch enabled */
virtual void setPitchRatio(double ratio)=0;
/** Instructs platform to begin consuming sample data; invoking callback as needed */
virtual void start()=0;
/** Instructs platform to stop consuming sample data */
virtual void stop()=0;
};
}
#endif // __AMUSE_IBACKENDVOICE_HPP__

View File

@ -0,0 +1,25 @@
#ifndef __AMUSE_IBACKENDVOICEALLOCATOR_HPP__
#define __AMUSE_IBACKENDVOICEALLOCATOR_HPP__
#include <memory>
namespace amuse
{
class IBackendVoice;
class Voice;
/**
* @brief Client-implemented voice allocator
*/
class IBackendVoiceAllocator
{
public:
virtual ~IBackendVoiceAllocator() = default;
/** Amuse obtains a new voice from the platform this way */
virtual std::unique_ptr<IBackendVoice> allocateVoice(Voice& clientVox, double sampleRate, bool dynamicPitch)=0;
};
}
#endif // __AMUSE_IBACKENDVOICEALLOCATOR_HPP__

View File

@ -0,0 +1,15 @@
#ifndef __AMUSE_LISTENER_HPP__
#define __AMUSE_LISTENER_HPP__
#include "Entity.hpp"
namespace amuse
{
class Listener : public Entity
{
};
}
#endif // __AMUSE_LISTENER_HPP__

View File

@ -0,0 +1,15 @@
#ifndef __AMUSE_SEQUENCER_HPP__
#define __AMUSE_SEQUENCER_HPP__
#include "Entity.hpp"
namespace amuse
{
class Sequencer : public Entity
{
};
}
#endif // __AMUSE_SEQUENCER_HPP__

View File

@ -0,0 +1,13 @@
#ifndef __AMUSE_SOUNDMACROSTATE_HPP__
#define __AMUSE_SOUNDMACROSTATE_HPP__
namespace amuse
{
class SoundMacroState
{
};
}
#endif // __AMUSE_SOUNDMACROSTATE_HPP__

54
include/amuse/Voice.hpp Normal file
View File

@ -0,0 +1,54 @@
#ifndef __AMUSE_VOICE_HPP__
#define __AMUSE_VOICE_HPP__
#include <stdint.h>
#include <stdlib.h>
#include <memory>
#include "SoundMacroState.hpp"
#include "Entity.hpp"
namespace amuse
{
class IBackendVoice;
/** State of voice over lifetime */
enum class VoiceState
{
Playing,
KeyOff,
Finished
};
/** Individual source of audio */
class Voice : public Entity
{
friend class Engine;
std::unique_ptr<IBackendVoice> m_backendVoice;
SoundMacroState m_state;
public:
Voice(Engine& engine, int groupId);
/** Request specified count of audio frames (samples) from voice,
* internally advancing the voice stream */
size_t supplyAudio(size_t frames, int16_t* data);
/** Get current state of voice */
VoiceState state() const;
/** Signals voice to begin fade-out, eventually reaching silence */
void keyOff();
void setVolume(float vol);
void setPanning(float pan);
void setSurroundPanning(float span);
void setPitchBend(float pitch);
void setModulation(float mod);
void setPedal(bool pedal);
void setDoppler(float doppler);
void setReverbVol(float rvol);
};
}
#endif // __AMUSE_VOICE_HPP__

10
include/amuse/amuse.hpp Normal file
View File

@ -0,0 +1,10 @@
#ifndef __AMUSE_AMUSE_HPP__
#define __AMUSE_AMUSE_HPP__
namespace amuse
{
}
#endif // __AMUSE_AMUSE_HPP__

31
lib/AudioGroup.cpp Normal file
View File

@ -0,0 +1,31 @@
#include "amuse/AudioGroup.hpp"
#include "amuse/AudioGroupData.hpp"
namespace amuse
{
AudioGroup::AudioGroup(int groupId, const AudioGroupData& data)
: m_groupId(groupId),
m_pool(data.getPool()),
m_proj(data.getProj()),
m_sdir(data.getSdir()),
m_samp(data.getSamp())
{}
bool AudioGroup::sfxInGroup(int sfxId) const
{
}
bool AudioGroup::songInGroup(int songId) const
{
}
const AudioGroupSampleDirectory::Entry* AudioGroup::getSfxEntry(int sfxId) const
{
for (const AudioGroupSampleDirectory::Entry& ent : m_sdir.m_entries)
if (ent.m_sfxId == sfxId)
return &ent;
return nullptr;
}
}

14
lib/AudioGroupData.cpp Normal file
View File

@ -0,0 +1,14 @@
#include "amuse/AudioGroupData.hpp"
namespace amuse
{
IntrusiveAudioGroupData::~IntrusiveAudioGroupData()
{
delete m_pool;
delete m_proj;
delete m_sdir;
delete m_samp;
}
}

0
lib/AudioGroupPool.cpp Normal file
View File

View File

View File

@ -0,0 +1,28 @@
#include "amuse/AudioGroupSampleDirectory.hpp"
#include "amuse/Common.hpp"
namespace amuse
{
void AudioGroupSampleDirectory::Entry::swapBig()
{
m_sfxId = SBig(m_sfxId);
m_sampleOff = SBig(m_sampleOff);
m_unk = SBig(m_unk);
m_sampleRate = SBig(m_sampleRate);
m_numSamples = SBig(m_numSamples);
m_loopStartSample = SBig(m_loopStartSample);
m_loopLengthSamples = SBig(m_loopLengthSamples);
m_adpcmParmOffset = SBig(m_adpcmParmOffset);
}
void AudioGroupSampleDirectory::ADPCMParms::swapBig()
{
m_bytesPerFrame = SBig(m_bytesPerFrame);
m_hist1 = SBig(m_hist1);
m_hist2 = SBig(m_hist2);
for (int i=0 ; i<16 ; ++i)
m_coefs[i] = SBig(m_coefs[i]);
}
}

49
lib/BooBackend.cpp Normal file
View File

@ -0,0 +1,49 @@
#include "amuse/BooBackend.hpp"
#include "amuse/Voice.hpp"
namespace amuse
{
size_t BooBackendVoice::VoiceCallback::supplyAudio(boo::IAudioVoice&,
size_t frames, int16_t* data)
{
return m_parent.m_clientVox.supplyAudio(frames, data);
}
BooBackendVoice::BooBackendVoice(boo::IAudioVoiceEngine& engine, Voice& clientVox,
double sampleRate, bool dynamicPitch)
: m_clientVox(clientVox), m_cb(*this),
m_booVoice(engine.allocateNewMonoVoice(sampleRate, &m_cb, dynamicPitch))
{}
void BooBackendVoice::setMatrixCoefficients(const float coefs[8])
{
m_booVoice->setMonoMatrixCoefficients(coefs);
}
void BooBackendVoice::setPitchRatio(double ratio)
{
m_booVoice->setPitchRatio(ratio);
}
void BooBackendVoice::start()
{
m_booVoice->start();
}
void BooBackendVoice::stop()
{
m_booVoice->stop();
}
BooBackendVoiceAllocator::BooBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine)
: m_booEngine(booEngine)
{}
std::unique_ptr<IBackendVoice>
BooBackendVoiceAllocator::allocateVoice(Voice& clientVox, double sampleRate, bool dynamicPitch)
{
return std::make_unique<BooBackendVoice>(m_booEngine, clientVox, sampleRate, dynamicPitch);
}
}

11
lib/Emitter.cpp Normal file
View File

@ -0,0 +1,11 @@
#include "amuse/Emitter.hpp"
namespace amuse
{
Emitter::Emitter(Engine& engine, int groupId, Voice& vox)
: Entity(engine, groupId), m_vox(vox)
{
}
}

137
lib/Engine.cpp Normal file
View File

@ -0,0 +1,137 @@
#include "amuse/Engine.hpp"
#include "amuse/Voice.hpp"
#include "amuse/Sequencer.hpp"
#include "amuse/IBackendVoice.hpp"
#include "amuse/IBackendVoiceAllocator.hpp"
#include "amuse/AudioGroupData.hpp"
#include "amuse/AudioGroup.hpp"
namespace amuse
{
Engine::Engine(IBackendVoiceAllocator& backend)
: m_backend(backend)
{}
Voice* Engine::_allocateVoice(int groupId, double sampleRate, bool dynamicPitch)
{
std::unique_ptr<Voice> vox = std::make_unique<Voice>(*this, groupId);
vox->m_backendVoice = m_backend.allocateVoice(*vox, sampleRate, dynamicPitch);
Voice* ret = vox.get();
m_activeVoices.push_back(std::move(vox));
return ret;
}
AudioGroup* Engine::_findGroupFromSfxId(int sfxId, const AudioGroupSampleDirectory::Entry*& entOut) const
{
for (const auto& grp : m_audioGroups)
{
entOut = grp.second->getSfxEntry(sfxId);
if (entOut)
return grp.second.get();
}
return nullptr;
}
AudioGroup* Engine::_findGroupFromSongId(int songId) const
{
for (const auto& grp : m_audioGroups)
if (grp.second->songInGroup(songId))
return grp.second.get();
return nullptr;
}
/** Update all active audio entities and fill OS audio buffers as needed */
void Engine::pumpEngine()
{
}
/** Add audio group data pointers to engine; must remain resident! */
bool Engine::addAudioGroup(int groupId, const AudioGroupData& data)
{
std::unique_ptr<AudioGroup> grp = std::make_unique<AudioGroup>(groupId, data);
if (!grp)
return false;
m_audioGroups.emplace(std::make_pair(groupId, std::move(grp)));
return true;
}
/** Remove audio group from engine */
void Engine::removeAudioGroup(int groupId)
{
for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;)
{
if ((*it)->getGroupId() == groupId)
{
it = m_activeVoices.erase(it);
continue;
}
++it;
}
for (auto it = m_activeEmitters.begin() ; it != m_activeEmitters.end() ;)
{
if ((*it)->getGroupId() == groupId)
{
it = m_activeEmitters.erase(it);
continue;
}
++it;
}
for (auto it = m_activeSequencers.begin() ; it != m_activeSequencers.end() ;)
{
if ((*it)->getGroupId() == groupId)
{
it = m_activeSequencers.erase(it);
continue;
}
++it;
}
m_audioGroups.erase(groupId);
}
/** Start soundFX playing from loaded audio groups */
Voice* Engine::fxStart(int sfxId, float vol, float pan)
{
const AudioGroupSampleDirectory::Entry* entry;
AudioGroup* grp = _findGroupFromSfxId(sfxId, entry);
if (!grp)
return nullptr;
Voice* ret = _allocateVoice(grp->groupId(), entry->m_sampleRate, true);
ret->setVolume(vol);
ret->setPanning(pan);
return ret;
}
/** Start soundFX playing from loaded audio groups, attach to positional emitter */
Emitter* Engine::addEmitter(const Vector3f& pos, const Vector3f& dir, float maxDist,
float falloff, int sfxId, float minVol, float maxVol)
{
const AudioGroupSampleDirectory::Entry* entry;
AudioGroup* grp = _findGroupFromSfxId(sfxId, entry);
if (!grp)
return nullptr;
Voice* vox = _allocateVoice(grp->groupId(), entry->m_sampleRate, true);
std::unique_ptr<Emitter> emtr = std::make_unique<Emitter>(*this, grp->groupId(), *vox);
Emitter* ret = emtr.get();
ret->setPos(pos);
ret->setDir(dir);
ret->setMaxDist(maxDist);
ret->setFalloff(falloff);
ret->setMinVol(minVol);
ret->setMaxVol(maxVol);
m_activeEmitters.push_back(std::move(emtr));
return ret;
}
/** Start song playing from loaded audio groups */
Sequencer* Engine::seqPlay(int songId, const unsigned char* arrData)
{
}
}

0
lib/Envelope.cpp Normal file
View File

0
lib/Listener.cpp Normal file
View File

0
lib/Sequencer.cpp Normal file
View File

0
lib/SoundMacroState.cpp Normal file
View File

16
lib/Voice.cpp Normal file
View File

@ -0,0 +1,16 @@
#include "amuse/Voice.hpp"
#include "amuse/IBackendVoice.hpp"
namespace amuse
{
Voice::Voice(Engine& engine, int groupId)
: Entity(engine, groupId)
{
}
size_t Voice::supplyAudio(size_t frames, int16_t* data)
{
}
}