update
This commit is contained in:
parent
97539aa9f4
commit
58661a94a6
@ -5,6 +5,105 @@
|
|||||||
|
|
||||||
using namespace audio;
|
using namespace audio;
|
||||||
|
|
||||||
|
ALSound::ALSound(ALAudio* al, uint buffer, std::shared_ptr<PCM> pcm, bool keepPCM)
|
||||||
|
: al(al), buffer(buffer)
|
||||||
|
{
|
||||||
|
duration = pcm->getDuration();
|
||||||
|
if (keepPCM) {
|
||||||
|
this->pcm = pcm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ALSound::~ALSound() {
|
||||||
|
al->freeBuffer(buffer);
|
||||||
|
buffer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Speaker* ALSound::newInstance(int priority) const {
|
||||||
|
uint source = al->getFreeSource();
|
||||||
|
if (source == 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return new ALSpeaker(al, source, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
ALSpeaker::ALSpeaker(ALAudio* al, uint source, int priority) : al(al), source(source), priority(priority) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ALSpeaker::~ALSpeaker() {
|
||||||
|
if (source) {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
State ALSpeaker::getState() const {
|
||||||
|
int state = AL::getSourcei(source, AL_SOURCE_STATE, AL_STOPPED);
|
||||||
|
switch (state) {
|
||||||
|
case AL_PLAYING: return State::playing;
|
||||||
|
case AL_PAUSED: return State::paused;
|
||||||
|
default: return State::stopped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float ALSpeaker::getVolume() const {
|
||||||
|
return AL::getSourcef(source, AL_GAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ALSpeaker::setVolume(float volume) {
|
||||||
|
AL_CHECK(alSourcef(source, AL_GAIN, volume));
|
||||||
|
}
|
||||||
|
|
||||||
|
float ALSpeaker::getPitch() const {
|
||||||
|
return AL::getSourcef(source, AL_PITCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ALSpeaker::setPitch(float pitch) {
|
||||||
|
AL_CHECK(alSourcef(source, AL_PITCH, pitch));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ALSpeaker::play() {
|
||||||
|
AL_CHECK(alSourcePlay(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ALSpeaker::pause() {
|
||||||
|
AL_CHECK(alSourcePause(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ALSpeaker::stop() {
|
||||||
|
AL_CHECK(alSourceStop(source));
|
||||||
|
al->freeSource(source);
|
||||||
|
source = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
duration_t ALSpeaker::getTime() const {
|
||||||
|
return static_cast<duration_t>(AL::getSourcef(source, AL_SEC_OFFSET));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ALSpeaker::setTime(duration_t time) {
|
||||||
|
AL_CHECK(alSourcef(source, AL_SEC_OFFSET, static_cast<float>(time)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ALSpeaker::setPosition(glm::vec3 pos) {
|
||||||
|
AL_CHECK(alSource3f(source, AL_POSITION, pos.x, pos.y, pos.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 ALSpeaker::getPosition() const {
|
||||||
|
return AL::getSource3f(source, AL_POSITION);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ALSpeaker::setVelocity(glm::vec3 vel) {
|
||||||
|
AL_CHECK(alSource3f(source, AL_VELOCITY, vel.x, vel.y, vel.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 ALSpeaker::getVelocity() const {
|
||||||
|
return AL::getSource3f(source, AL_VELOCITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ALSpeaker::getPriority() const {
|
||||||
|
return priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ALAudio::ALAudio(ALCdevice* device, ALCcontext* context)
|
ALAudio::ALAudio(ALCdevice* device, ALCcontext* context)
|
||||||
: device(device), context(context)
|
: device(device), context(context)
|
||||||
{
|
{
|
||||||
@ -26,22 +125,20 @@ ALAudio::ALAudio(ALCdevice* device, ALCcontext* context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ALAudio::~ALAudio() {
|
ALAudio::~ALAudio() {
|
||||||
for (ALSource* source : allsources) {
|
for (uint source : allsources) {
|
||||||
if (source->isPlaying()){
|
int state = AL::getSourcei(source, AL_SOURCE_STATE);
|
||||||
alSourceStop(source->id);
|
if (state == AL_PLAYING || state == AL_PAUSED) {
|
||||||
alCheckErrorsMacro();
|
AL_CHECK(alSourceStop(source));
|
||||||
}
|
}
|
||||||
alDeleteSources(1, &source->id);
|
AL_CHECK(alDeleteSources(1, &source));
|
||||||
alCheckErrorsMacro();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ALBuffer* buffer : allbuffers){
|
for (uint buffer : allbuffers){
|
||||||
alDeleteBuffers(1, &buffer->id);
|
AL_CHECK(alDeleteBuffers(1, &buffer));
|
||||||
alCheckErrorsMacro();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
alcMakeContextCurrent(context);
|
AL_CHECK(alcMakeContextCurrent(context));
|
||||||
alcDestroyContext(context);
|
AL_CHECK(alcDestroyContext(context));
|
||||||
if (!alcCloseDevice(device)) {
|
if (!alcCloseDevice(device)) {
|
||||||
std::cerr << "AL: device not closed!" << std::endl;
|
std::cerr << "AL: device not closed!" << std::endl;
|
||||||
}
|
}
|
||||||
@ -49,53 +146,6 @@ ALAudio::~ALAudio() {
|
|||||||
context = nullptr;
|
context = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ALSource::setBuffer(ALBuffer* buffer) {
|
|
||||||
alSourcei(id, AL_BUFFER, buffer->id);
|
|
||||||
return alCheckErrorsMacro();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ALSource::play(){
|
|
||||||
alSourcePlay(id);
|
|
||||||
return alCheckErrorsMacro();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ALSource::isPlaying() {
|
|
||||||
int state;
|
|
||||||
alGetSourcei(id, AL_SOURCE_STATE, &state);
|
|
||||||
return state == AL_PLAYING;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ALSource::setPosition(glm::vec3 position) {
|
|
||||||
alSource3f(id, AL_POSITION, position.x, position.y, position.z);
|
|
||||||
return alCheckErrorsMacro();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ALSource::setVelocity(glm::vec3 velocity) {
|
|
||||||
alSource3f(id, AL_VELOCITY, velocity.x, velocity.y, velocity.z);
|
|
||||||
return alCheckErrorsMacro();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ALSource::setLoop(bool loop) {
|
|
||||||
alSourcei(id, AL_LOOPING, AL_TRUE ? loop : AL_FALSE);
|
|
||||||
return alCheckErrorsMacro();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ALSource::setGain(float gain) {
|
|
||||||
alSourcef(id, AL_GAIN, gain);
|
|
||||||
return alCheckErrorsMacro();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool ALSource::setPitch(float pitch) {
|
|
||||||
alSourcef(id, AL_PITCH, pitch);
|
|
||||||
return alCheckErrorsMacro();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ALBuffer::load(int format, const char* data, int size, int freq) {
|
|
||||||
alBufferData(id, format, data, size, freq);
|
|
||||||
return alCheckErrorsMacro();
|
|
||||||
}
|
|
||||||
|
|
||||||
Sound* ALAudio::createSound(std::shared_ptr<PCM> pcm, bool keepPCM) {
|
Sound* ALAudio::createSound(std::shared_ptr<PCM> pcm, bool keepPCM) {
|
||||||
// TODO: implement
|
// TODO: implement
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -110,59 +160,55 @@ ALAudio* ALAudio::create() {
|
|||||||
alcCloseDevice(device);
|
alcCloseDevice(device);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (!alCheckErrorsMacro()) {
|
AL_CHECK();
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
std::cout << "AL: initialized" << std::endl;
|
std::cout << "AL: initialized" << std::endl;
|
||||||
return new ALAudio(device, context);
|
return new ALAudio(device, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALSource* ALAudio::getFreeSource(){
|
uint ALAudio::getFreeSource(){
|
||||||
if (!freesources.empty()){
|
if (!freesources.empty()){
|
||||||
ALSource* source = freesources.back();
|
uint source = freesources.back();
|
||||||
freesources.pop_back();
|
freesources.pop_back();
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
if (allsources.size() == maxSources){
|
if (allsources.size() == maxSources){
|
||||||
std::cerr << "attempted to create new source, but limit is " << maxSources << std::endl;
|
std::cerr << "attempted to create new source, but limit is " << maxSources << std::endl;
|
||||||
return nullptr;
|
return 0;
|
||||||
}
|
}
|
||||||
ALuint id;
|
ALuint id;
|
||||||
alGenSources(1, &id);
|
alGenSources(1, &id);
|
||||||
if (!alCheckErrorsMacro())
|
if (!AL_GET_ERORR())
|
||||||
return nullptr;
|
return 0;
|
||||||
|
|
||||||
ALSource* source = new ALSource(id);
|
allsources.push_back(id);
|
||||||
allsources.push_back(source);
|
return id;
|
||||||
return source;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ALBuffer* ALAudio::getFreeBuffer(){
|
uint ALAudio::getFreeBuffer(){
|
||||||
if (!freebuffers.empty()){
|
if (!freebuffers.empty()){
|
||||||
ALBuffer* buffer = freebuffers.back();
|
uint buffer = freebuffers.back();
|
||||||
freebuffers.pop_back();
|
freebuffers.pop_back();
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
if (allbuffers.size() == maxBuffers){
|
if (allbuffers.size() == maxBuffers){
|
||||||
std::cerr << "attempted to create new ALbuffer, but limit is " << maxBuffers << std::endl;
|
std::cerr << "attempted to create new ALbuffer, but limit is " << maxBuffers << std::endl;
|
||||||
return nullptr;
|
return 0;
|
||||||
}
|
}
|
||||||
ALuint id;
|
ALuint id;
|
||||||
alGenBuffers(1, &id);
|
alGenBuffers(1, &id);
|
||||||
if (!alCheckErrorsMacro()) {
|
if (!AL_GET_ERORR()) {
|
||||||
return nullptr;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALBuffer* buffer = new ALBuffer(id);
|
allbuffers.push_back(id);
|
||||||
allbuffers.push_back(buffer);
|
return id;
|
||||||
return buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ALAudio::freeSource(ALSource* source){
|
void ALAudio::freeSource(uint source){
|
||||||
freesources.push_back(source);
|
freesources.push_back(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ALAudio::freeBuffer(ALBuffer* buffer){
|
void ALAudio::freeBuffer(uint buffer){
|
||||||
freebuffers.push_back(buffer);
|
freebuffers.push_back(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +217,7 @@ std::vector<std::string> ALAudio::getAvailableDevices() const {
|
|||||||
|
|
||||||
const ALCchar* devices;
|
const ALCchar* devices;
|
||||||
devices = alcGetString(device, ALC_DEVICE_SPECIFIER);
|
devices = alcGetString(device, ALC_DEVICE_SPECIFIER);
|
||||||
if (!alCheckErrorsMacro()) {
|
if (!AL_GET_ERORR()) {
|
||||||
return devicesVec;
|
return devicesVec;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,10 +234,11 @@ std::vector<std::string> ALAudio::getAvailableDevices() const {
|
|||||||
void ALAudio::setListener(glm::vec3 position, glm::vec3 velocity, glm::vec3 at, glm::vec3 up){
|
void ALAudio::setListener(glm::vec3 position, glm::vec3 velocity, glm::vec3 at, glm::vec3 up){
|
||||||
ALfloat listenerOri[] = { at.x, at.y, at.z, up.x, up.y, up.z };
|
ALfloat listenerOri[] = { at.x, at.y, at.z, up.x, up.y, up.z };
|
||||||
|
|
||||||
alListener3f(AL_POSITION, position.x, position.y, position.z);
|
AL_CHECK(alListener3f(AL_POSITION, position.x, position.y, position.z));
|
||||||
alCheckErrorsMacro();
|
AL_CHECK(alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z));
|
||||||
alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z);
|
AL_CHECK(alListenerfv(AL_ORIENTATION, listenerOri));
|
||||||
alCheckErrorsMacro();
|
}
|
||||||
alListenerfv(AL_ORIENTATION, listenerOri);
|
|
||||||
alCheckErrorsMacro();
|
void ALAudio::update(double delta) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <OpenAL/al.h>
|
#include <OpenAL/al.h>
|
||||||
@ -18,36 +19,70 @@
|
|||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
struct ALBuffer;
|
struct ALBuffer;
|
||||||
|
class ALAudio;
|
||||||
|
|
||||||
struct ALSource {
|
class ALSound : public Sound {
|
||||||
uint id;
|
ALAudio* al;
|
||||||
ALSource(uint id) : id(id) {}
|
uint buffer;
|
||||||
|
std::shared_ptr<PCM> pcm;
|
||||||
|
duration_t duration;
|
||||||
|
public:
|
||||||
|
ALSound(ALAudio* al, uint buffer, std::shared_ptr<PCM> pcm, bool keepPCM);
|
||||||
|
~ALSound();
|
||||||
|
|
||||||
bool isPlaying();
|
duration_t getDuration() const override {
|
||||||
bool setPosition(glm::vec3 position);
|
return duration;
|
||||||
bool setVelocity(glm::vec3 velocity);
|
}
|
||||||
bool setBuffer(ALBuffer* buffer);
|
|
||||||
bool setLoop(bool loop);
|
std::shared_ptr<PCM> getPCM() const override {
|
||||||
bool setGain(float gain);
|
return pcm;
|
||||||
bool setPitch(float pitch);
|
}
|
||||||
bool play();
|
|
||||||
|
Speaker* newInstance(int priority) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ALBuffer {
|
/// @brief AL source adapter
|
||||||
uint id;
|
class ALSpeaker : public Speaker {
|
||||||
ALBuffer(uint id) : id(id) {}
|
ALAudio* al;
|
||||||
bool load(int format, const char* data, int size, int freq);
|
uint source;
|
||||||
|
int priority;
|
||||||
|
public:
|
||||||
|
ALSpeaker(ALAudio* al, uint source, int priority);
|
||||||
|
~ALSpeaker();
|
||||||
|
|
||||||
|
State getState() const override;
|
||||||
|
|
||||||
|
float getVolume() const override;
|
||||||
|
void setVolume(float volume) override;
|
||||||
|
|
||||||
|
float getPitch() const override;
|
||||||
|
void setPitch(float pitch) override;
|
||||||
|
|
||||||
|
void play() override;
|
||||||
|
void pause() override;
|
||||||
|
void stop() override;
|
||||||
|
|
||||||
|
duration_t getTime() const override;
|
||||||
|
void setTime(duration_t time) override;
|
||||||
|
|
||||||
|
void setPosition(glm::vec3 pos) override;
|
||||||
|
glm::vec3 getPosition() const override;
|
||||||
|
|
||||||
|
void setVelocity(glm::vec3 vel) override;
|
||||||
|
glm::vec3 getVelocity() const override;
|
||||||
|
|
||||||
|
int getPriority() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ALAudio : public Backend {
|
class ALAudio : public Backend {
|
||||||
ALCdevice* device;
|
ALCdevice* device;
|
||||||
ALCcontext* context;
|
ALCcontext* context;
|
||||||
|
|
||||||
std::vector<ALSource*> allsources;
|
std::vector<uint> allsources;
|
||||||
std::vector<ALSource*> freesources;
|
std::vector<uint> freesources;
|
||||||
|
|
||||||
std::vector<ALBuffer*> allbuffers;
|
std::vector<uint> allbuffers;
|
||||||
std::vector<ALBuffer*> freebuffers;
|
std::vector<uint> freebuffers;
|
||||||
|
|
||||||
uint maxSources;
|
uint maxSources;
|
||||||
uint maxBuffers;
|
uint maxBuffers;
|
||||||
@ -56,10 +91,10 @@ namespace audio {
|
|||||||
public:
|
public:
|
||||||
~ALAudio();
|
~ALAudio();
|
||||||
|
|
||||||
ALSource* getFreeSource();
|
uint getFreeSource();
|
||||||
ALBuffer* getFreeBuffer();
|
uint getFreeBuffer();
|
||||||
void freeSource(ALSource* source);
|
void freeSource(uint source);
|
||||||
void freeBuffer(ALBuffer* buffer);
|
void freeBuffer(uint buffer);
|
||||||
|
|
||||||
std::vector<std::string> getAvailableDevices() const;
|
std::vector<std::string> getAvailableDevices() const;
|
||||||
|
|
||||||
@ -72,6 +107,8 @@ namespace audio {
|
|||||||
glm::vec3 up
|
glm::vec3 up
|
||||||
) override;
|
) override;
|
||||||
|
|
||||||
|
void update(double delta) override;
|
||||||
|
|
||||||
static ALAudio* create();
|
static ALAudio* create();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,8 +19,8 @@ namespace audio {
|
|||||||
return pcm;
|
return pcm;
|
||||||
}
|
}
|
||||||
|
|
||||||
speakerid_t newInstance(int priority) const override {
|
Speaker* newInstance(int priority) const override {
|
||||||
return 0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -37,6 +37,8 @@ namespace audio {
|
|||||||
glm::vec3 up
|
glm::vec3 up
|
||||||
) override {}
|
) override {}
|
||||||
|
|
||||||
|
void update(double delta) override {}
|
||||||
|
|
||||||
static NoAudio* create();
|
static NoAudio* create();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,7 +35,7 @@ std::int32_t convert_to_int(char* buffer, std::size_t len){
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_al_errors(const std::string& filename, const std::uint_fast32_t line){
|
bool AL::check_errors(const std::string& filename, const std::uint_fast32_t line){
|
||||||
ALenum error = alGetError();
|
ALenum error = alGetError();
|
||||||
if(error != AL_NO_ERROR){
|
if(error != AL_NO_ERROR){
|
||||||
std::cerr << "OpenAL ERROR (" << filename << ": " << line << ")\n" ;
|
std::cerr << "OpenAL ERROR (" << filename << ": " << line << ")\n" ;
|
||||||
|
|||||||
@ -11,9 +11,10 @@
|
|||||||
#include <AL/al.h>
|
#include <AL/al.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define alCheckErrorsMacro() check_al_errors(__FILE__, __LINE__)
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
bool check_al_errors(const std::string& filename, const std::uint_fast32_t line);
|
#define AL_CHECK(STATEMENT) STATEMENT; AL::check_errors(__FILE__, __LINE__)
|
||||||
|
#define AL_GET_ERORR() AL::check_errors(__FILE__, __LINE__)
|
||||||
|
|
||||||
bool load_wav_file_header(
|
bool load_wav_file_header(
|
||||||
std::ifstream& file,
|
std::ifstream& file,
|
||||||
@ -31,6 +32,43 @@ char* load_wav(
|
|||||||
ALsizei& size
|
ALsizei& size
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
namespace AL {
|
||||||
|
bool check_errors(const std::string& filename, const std::uint_fast32_t line);
|
||||||
|
|
||||||
|
/// @brief alGetSourcef wrapper
|
||||||
|
/// @param source target source
|
||||||
|
/// @param field enum value
|
||||||
|
/// @param def default value will be returned in case of error
|
||||||
|
/// @return field value or default
|
||||||
|
inline float getSourcef(uint source, ALenum field, float def=0.0f) {
|
||||||
|
float value = def;
|
||||||
|
AL_CHECK(alGetSourcef(source, field, &value));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief alGetSource3f wrapper
|
||||||
|
/// @param source target source
|
||||||
|
/// @param field enum value
|
||||||
|
/// @param def default value will be returned in case of error
|
||||||
|
/// @return field value or default
|
||||||
|
inline glm::vec3 getSource3f(uint source, ALenum field, glm::vec3 def={}) {
|
||||||
|
glm::vec3 value = def;
|
||||||
|
AL_CHECK(alGetSource3f(source, field, &value.x, &value.y, &value.z));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief alGetSourcei wrapper
|
||||||
|
/// @param source target source
|
||||||
|
/// @param field enum value
|
||||||
|
/// @param def default value will be returned in case of error
|
||||||
|
/// @return field value or default
|
||||||
|
inline float getSourcei(uint source, ALenum field, int def=0) {
|
||||||
|
int value = def;
|
||||||
|
AL_CHECK(alGetSourcei(source, field, &value));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
static inline ALenum to_al_format(short channels, short samples){
|
static inline ALenum to_al_format(short channels, short samples){
|
||||||
bool stereo = (channels > 1);
|
bool stereo = (channels > 1);
|
||||||
|
|
||||||
@ -49,5 +87,6 @@ static inline ALenum to_al_format(short channels, short samples){
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* SRC_AUDIO_AUDIOUTIL_H_ */
|
#endif /* SRC_AUDIO_AUDIOUTIL_H_ */
|
||||||
|
|||||||
@ -5,6 +5,10 @@
|
|||||||
#include "ALAudio.h"
|
#include "ALAudio.h"
|
||||||
#include "NoAudio.h"
|
#include "NoAudio.h"
|
||||||
|
|
||||||
|
namespace audio {
|
||||||
|
extern Backend* backend;
|
||||||
|
}
|
||||||
|
|
||||||
audio::Backend* audio::backend = nullptr;
|
audio::Backend* audio::backend = nullptr;
|
||||||
|
|
||||||
void audio::initialize(bool enabled) {
|
void audio::initialize(bool enabled) {
|
||||||
@ -26,6 +30,10 @@ void audio::setListener(
|
|||||||
audio::backend->setListener(position, velocity, lookAt, up);
|
audio::backend->setListener(position, velocity, lookAt, up);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void audio::update(double delta) {
|
||||||
|
audio::backend->update(delta);
|
||||||
|
}
|
||||||
|
|
||||||
void audio::close() {
|
void audio::close() {
|
||||||
delete audio::backend;
|
delete audio::backend;
|
||||||
audio::backend = nullptr;
|
audio::backend = nullptr;
|
||||||
|
|||||||
@ -11,6 +11,14 @@ namespace audio {
|
|||||||
/// @brief duration unit is second
|
/// @brief duration unit is second
|
||||||
using duration_t = float;
|
using duration_t = float;
|
||||||
|
|
||||||
|
class Speaker;
|
||||||
|
|
||||||
|
enum class State {
|
||||||
|
playing,
|
||||||
|
paused,
|
||||||
|
stopped
|
||||||
|
};
|
||||||
|
|
||||||
/// @brief Pulse-code modulation data
|
/// @brief Pulse-code modulation data
|
||||||
struct PCM {
|
struct PCM {
|
||||||
/// @brief May contain 8 bit and 16 bit PCM data
|
/// @brief May contain 8 bit and 16 bit PCM data
|
||||||
@ -46,20 +54,78 @@ namespace audio {
|
|||||||
/// @brief Create new sound instance
|
/// @brief Create new sound instance
|
||||||
/// @param priority instance priority. High priority instance can
|
/// @param priority instance priority. High priority instance can
|
||||||
/// take out speaker from low priority instance
|
/// take out speaker from low priority instance
|
||||||
/// @return new speaker id with sound bound or 0
|
/// @return new speaker with sound bound or nullptr
|
||||||
/// if all speakers are in use
|
/// if all speakers are in use
|
||||||
virtual speakerid_t newInstance(int priority) const = 0;
|
virtual Speaker* newInstance(int priority) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Audio source controller interface
|
||||||
|
class Speaker {
|
||||||
|
public:
|
||||||
|
virtual ~Speaker() {}
|
||||||
|
|
||||||
|
/// @brief Get current speaker state
|
||||||
|
/// @return speaker state
|
||||||
|
virtual State getState() const = 0;
|
||||||
|
|
||||||
|
/// @brief Get speaker audio gain
|
||||||
|
/// @return speaker audio gain value
|
||||||
|
virtual float getVolume() const = 0;
|
||||||
|
|
||||||
|
/// @brief Set speaker audio gain (must be positive)
|
||||||
|
/// @param volume new gain value
|
||||||
|
virtual void setVolume(float volume) = 0;
|
||||||
|
|
||||||
|
/// @brief Get speaker pitch multiplier
|
||||||
|
/// @return pitch multiplier
|
||||||
|
virtual float getPitch() const = 0;
|
||||||
|
|
||||||
|
/// @brief Set speaker pitch multiplier
|
||||||
|
/// @param pitch new pitch multiplier (must be positive)
|
||||||
|
virtual void setPitch(float pitch) = 0;
|
||||||
|
|
||||||
|
/// @brief Play, replay or resume audio
|
||||||
|
virtual void play() = 0;
|
||||||
|
|
||||||
|
/// @brief Pause playing audio and keep speaker alive
|
||||||
|
virtual void pause() = 0;
|
||||||
|
|
||||||
|
/// @brief Stop and destroy speaker
|
||||||
|
virtual void stop() = 0;
|
||||||
|
|
||||||
|
/// @brief Get current time position of playing audio
|
||||||
|
/// @return time position in seconds
|
||||||
|
virtual duration_t getTime() const = 0;
|
||||||
|
|
||||||
|
/// @brief Set playing audio time position
|
||||||
|
/// @param time time position in seconds
|
||||||
|
virtual void setTime(duration_t time) = 0;
|
||||||
|
|
||||||
|
/// @brief Set speaker 3D position in the world
|
||||||
|
/// @param pos new position
|
||||||
|
virtual void setPosition(glm::vec3 pos) = 0;
|
||||||
|
|
||||||
|
/// @brief Get speaker 3D position in the world
|
||||||
|
/// @return position
|
||||||
|
virtual glm::vec3 getPosition() const = 0;
|
||||||
|
|
||||||
|
/// @brief Set speaker movement velocity used for Doppler effect
|
||||||
|
/// @param vel velocity vector
|
||||||
|
virtual void setVelocity(glm::vec3 vel) = 0;
|
||||||
|
|
||||||
|
/// @brief Get speaker movement velocity used for Doppler effect
|
||||||
|
/// @return velocity vector
|
||||||
|
virtual glm::vec3 getVelocity() const = 0;
|
||||||
|
|
||||||
|
/// @brief Get speaker priority
|
||||||
|
/// @return speaker priority value
|
||||||
|
virtual int getPriority() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Backend {
|
class Backend {
|
||||||
public:
|
public:
|
||||||
virtual ~Backend() {};
|
virtual ~Backend() {};
|
||||||
|
|
||||||
/// @brief Create new sound from PCM data
|
|
||||||
/// @param pcm PCM data
|
|
||||||
/// @param keepPCM store PCM data in sound to make it accessible with
|
|
||||||
/// Sound::getPCM
|
|
||||||
/// @return new Sound instance
|
|
||||||
virtual Sound* createSound(std::shared_ptr<PCM> pcm, bool keepPCM) = 0;
|
virtual Sound* createSound(std::shared_ptr<PCM> pcm, bool keepPCM) = 0;
|
||||||
|
|
||||||
virtual void setListener(
|
virtual void setListener(
|
||||||
@ -68,14 +134,21 @@ namespace audio {
|
|||||||
glm::vec3 lookAt,
|
glm::vec3 lookAt,
|
||||||
glm::vec3 up
|
glm::vec3 up
|
||||||
) = 0;
|
) = 0;
|
||||||
};
|
|
||||||
|
|
||||||
extern Backend* backend;
|
virtual void update(double delta) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
/// @brief Initialize audio system or use no audio mode
|
/// @brief Initialize audio system or use no audio mode
|
||||||
/// @param enabled try to initialize actual audio
|
/// @param enabled try to initialize actual audio
|
||||||
extern void initialize(bool enabled);
|
extern void initialize(bool enabled);
|
||||||
|
|
||||||
|
/// @brief Create new sound from PCM data
|
||||||
|
/// @param pcm PCM data
|
||||||
|
/// @param keepPCM store PCM data in sound to make it accessible with
|
||||||
|
/// Sound::getPCM
|
||||||
|
/// @return new Sound instance
|
||||||
|
extern Sound* createSound(std::shared_ptr<PCM> pcm, bool keepPCM);
|
||||||
|
|
||||||
/// @brief Configure 3D listener
|
/// @brief Configure 3D listener
|
||||||
/// @param position listener position
|
/// @param position listener position
|
||||||
/// @param velocity listener velocity (used for Doppler effect)
|
/// @param velocity listener velocity (used for Doppler effect)
|
||||||
@ -87,6 +160,11 @@ namespace audio {
|
|||||||
glm::vec3 lookAt,
|
glm::vec3 lookAt,
|
||||||
glm::vec3 up
|
glm::vec3 up
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// @brief Update audio streams and sound instanced
|
||||||
|
/// @param delta time since the last update (seconds)
|
||||||
|
extern void update(double delta);
|
||||||
|
|
||||||
/// @brief Finalize audio system
|
/// @brief Finalize audio system
|
||||||
extern void close();
|
extern void close();
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user