mirror of https://github.com/AxioDL/amuse.git
Initial stubs and basic Engine implementation
This commit is contained in:
parent
72ee790831
commit
fa8d9038df
|
@ -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})
|
|
@ -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);
|
||||||
|
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef __AMUSE_ENVELOPE_HPP__
|
||||||
|
#define __AMUSE_ENVELOPE_HPP__
|
||||||
|
|
||||||
|
namespace amuse
|
||||||
|
{
|
||||||
|
|
||||||
|
class Envelope
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __AMUSE_ENVELOPE_HPP__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef __AMUSE_SOUNDMACROSTATE_HPP__
|
||||||
|
#define __AMUSE_SOUNDMACROSTATE_HPP__
|
||||||
|
|
||||||
|
namespace amuse
|
||||||
|
{
|
||||||
|
|
||||||
|
class SoundMacroState
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __AMUSE_SOUNDMACROSTATE_HPP__
|
|
@ -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__
|
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef __AMUSE_AMUSE_HPP__
|
||||||
|
#define __AMUSE_AMUSE_HPP__
|
||||||
|
|
||||||
|
namespace amuse
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __AMUSE_AMUSE_HPP__
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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,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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include "amuse/Emitter.hpp"
|
||||||
|
|
||||||
|
namespace amuse
|
||||||
|
{
|
||||||
|
|
||||||
|
Emitter::Emitter(Engine& engine, int groupId, Voice& vox)
|
||||||
|
: Entity(engine, groupId), m_vox(vox)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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,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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue