minor refactor
This commit is contained in:
@@ -0,0 +1,249 @@
|
||||
#include "ALAudio.h"
|
||||
#include "alutil.h"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
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;
|
||||
}
|
||||
AL_CHECK(alSourcei(source, AL_BUFFER, buffer));
|
||||
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));
|
||||
}
|
||||
|
||||
bool ALSpeaker::isLoop() const {
|
||||
return AL::getSourcei(source, AL_LOOPING) == AL_TRUE;
|
||||
}
|
||||
|
||||
void ALSpeaker::setLoop(bool loop) {
|
||||
AL_CHECK(alSourcei(source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE));
|
||||
}
|
||||
|
||||
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)
|
||||
: device(device), context(context)
|
||||
{
|
||||
ALCint size;
|
||||
alcGetIntegerv(device, ALC_ATTRIBUTES_SIZE, 1, &size);
|
||||
std::vector<ALCint> attrs(size);
|
||||
alcGetIntegerv(device, ALC_ALL_ATTRIBUTES, size, &attrs[0]);
|
||||
for (size_t i = 0; i < attrs.size(); ++i){
|
||||
if (attrs[i] == ALC_MONO_SOURCES) {
|
||||
std::cout << "AL: max mono sources: " << attrs[i+1] << std::endl;
|
||||
maxSources = attrs[i+1];
|
||||
}
|
||||
}
|
||||
auto devices = getAvailableDevices();
|
||||
std::cout << "AL devices:" << std::endl;
|
||||
for (auto& name : devices) {
|
||||
std::cout << " " << name << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
ALAudio::~ALAudio() {
|
||||
for (uint source : allsources) {
|
||||
int state = AL::getSourcei(source, AL_SOURCE_STATE);
|
||||
if (state == AL_PLAYING || state == AL_PAUSED) {
|
||||
AL_CHECK(alSourceStop(source));
|
||||
}
|
||||
AL_CHECK(alDeleteSources(1, &source));
|
||||
}
|
||||
|
||||
for (uint buffer : allbuffers){
|
||||
AL_CHECK(alDeleteBuffers(1, &buffer));
|
||||
}
|
||||
|
||||
AL_CHECK(alcMakeContextCurrent(context));
|
||||
alcDestroyContext(context);
|
||||
if (!alcCloseDevice(device)) {
|
||||
std::cerr << "AL: device not closed!" << std::endl;
|
||||
}
|
||||
device = nullptr;
|
||||
context = nullptr;
|
||||
}
|
||||
|
||||
Sound* ALAudio::createSound(std::shared_ptr<PCM> pcm, bool keepPCM) {
|
||||
auto format = AL::to_al_format(pcm->channels, pcm->bitsPerSample);
|
||||
uint buffer = getFreeBuffer();
|
||||
AL_CHECK(alBufferData(buffer, format, pcm->data.data(), pcm->data.size(), pcm->sampleRate));
|
||||
return new ALSound(this, buffer, pcm, keepPCM);
|
||||
}
|
||||
|
||||
ALAudio* ALAudio::create() {
|
||||
ALCdevice* device = alcOpenDevice(nullptr);
|
||||
if (device == nullptr)
|
||||
return nullptr;
|
||||
ALCcontext* context = alcCreateContext(device, nullptr);
|
||||
if (!alcMakeContextCurrent(context)){
|
||||
alcCloseDevice(device);
|
||||
return nullptr;
|
||||
}
|
||||
AL_CHECK();
|
||||
std::cout << "AL: initialized" << std::endl;
|
||||
return new ALAudio(device, context);
|
||||
}
|
||||
|
||||
uint ALAudio::getFreeSource(){
|
||||
if (!freesources.empty()){
|
||||
uint source = freesources.back();
|
||||
freesources.pop_back();
|
||||
return source;
|
||||
}
|
||||
if (allsources.size() == maxSources){
|
||||
std::cerr << "attempted to create new source, but limit is " << maxSources << std::endl;
|
||||
return 0;
|
||||
}
|
||||
ALuint id;
|
||||
alGenSources(1, &id);
|
||||
if (!AL_GET_ERROR())
|
||||
return 0;
|
||||
allsources.push_back(id);
|
||||
return id;
|
||||
}
|
||||
|
||||
uint ALAudio::getFreeBuffer(){
|
||||
if (!freebuffers.empty()){
|
||||
uint buffer = freebuffers.back();
|
||||
freebuffers.pop_back();
|
||||
return buffer;
|
||||
}
|
||||
ALuint id;
|
||||
alGenBuffers(1, &id);
|
||||
if (!AL_GET_ERROR()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
allbuffers.push_back(id);
|
||||
return id;
|
||||
}
|
||||
|
||||
void ALAudio::freeSource(uint source){
|
||||
freesources.push_back(source);
|
||||
}
|
||||
|
||||
void ALAudio::freeBuffer(uint buffer){
|
||||
freebuffers.push_back(buffer);
|
||||
}
|
||||
|
||||
std::vector<std::string> ALAudio::getAvailableDevices() const {
|
||||
std::vector<std::string> devicesVec;
|
||||
|
||||
const ALCchar* devices;
|
||||
devices = alcGetString(device, ALC_DEVICE_SPECIFIER);
|
||||
if (!AL_GET_ERROR()) {
|
||||
return devicesVec;
|
||||
}
|
||||
|
||||
const char* ptr = devices;
|
||||
do {
|
||||
devicesVec.push_back(std::string(ptr));
|
||||
ptr += devicesVec.back().size() + 1;
|
||||
}
|
||||
while (ptr[0]);
|
||||
|
||||
return devicesVec;
|
||||
}
|
||||
|
||||
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 };
|
||||
|
||||
AL_CHECK(alListener3f(AL_POSITION, position.x, position.y, position.z));
|
||||
AL_CHECK(alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z));
|
||||
AL_CHECK(alListenerfv(AL_ORIENTATION, listenerOri));
|
||||
}
|
||||
|
||||
void ALAudio::update(double delta) {
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
#ifndef SRC_AUDIO_AUDIO_H_
|
||||
#define SRC_AUDIO_AUDIO_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <glm/glm.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <OpenAL/al.h>
|
||||
#include <OpenAL/alc.h>
|
||||
#else
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#endif
|
||||
|
||||
#include "../audio.h"
|
||||
#include "../../typedefs.h"
|
||||
|
||||
namespace audio {
|
||||
struct ALBuffer;
|
||||
class ALAudio;
|
||||
|
||||
class ALSound : public Sound {
|
||||
ALAudio* al;
|
||||
uint buffer;
|
||||
std::shared_ptr<PCM> pcm;
|
||||
duration_t duration;
|
||||
public:
|
||||
ALSound(ALAudio* al, uint buffer, std::shared_ptr<PCM> pcm, bool keepPCM);
|
||||
~ALSound();
|
||||
|
||||
duration_t getDuration() const override {
|
||||
return duration;
|
||||
}
|
||||
|
||||
std::shared_ptr<PCM> getPCM() const override {
|
||||
return pcm;
|
||||
}
|
||||
|
||||
Speaker* newInstance(int priority) const override;
|
||||
};
|
||||
|
||||
/// @brief AL source adapter
|
||||
class ALSpeaker : public Speaker {
|
||||
ALAudio* al;
|
||||
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;
|
||||
|
||||
bool isLoop() const override;
|
||||
void setLoop(bool loop) 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 {
|
||||
ALCdevice* device;
|
||||
ALCcontext* context;
|
||||
|
||||
std::vector<uint> allsources;
|
||||
std::vector<uint> freesources;
|
||||
|
||||
std::vector<uint> allbuffers;
|
||||
std::vector<uint> freebuffers;
|
||||
|
||||
uint maxSources;
|
||||
|
||||
ALAudio(ALCdevice* device, ALCcontext* context);
|
||||
public:
|
||||
~ALAudio();
|
||||
|
||||
uint getFreeSource();
|
||||
uint getFreeBuffer();
|
||||
void freeSource(uint source);
|
||||
void freeBuffer(uint buffer);
|
||||
|
||||
std::vector<std::string> getAvailableDevices() const;
|
||||
|
||||
Sound* createSound(std::shared_ptr<PCM> pcm, bool keepPCM) override;
|
||||
|
||||
void setListener(
|
||||
glm::vec3 position,
|
||||
glm::vec3 velocity,
|
||||
glm::vec3 lookAt,
|
||||
glm::vec3 up
|
||||
) override;
|
||||
|
||||
void update(double delta) override;
|
||||
|
||||
bool isDummy() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
static ALAudio* create();
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* SRC_AUDIO_AUDIO_H_ */
|
||||
@@ -0,0 +1,44 @@
|
||||
#include "alutil.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <OpenAL/al.h>
|
||||
#include <OpenAL/alc.h>
|
||||
#else
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#endif
|
||||
|
||||
bool AL::check_errors(const std::string& filename, const std::uint_fast32_t line){
|
||||
ALenum error = alGetError();
|
||||
if(error != AL_NO_ERROR){
|
||||
std::cerr << "OpenAL ERROR (" << filename << ": " << line << ")\n" ;
|
||||
switch(error){
|
||||
case AL_INVALID_NAME:
|
||||
std::cerr << "AL_INVALID_NAME: a bad name (ID) was passed to an OpenAL function";
|
||||
break;
|
||||
case AL_INVALID_ENUM:
|
||||
std::cerr << "AL_INVALID_ENUM: an invalid enum value was passed to an OpenAL function";
|
||||
break;
|
||||
case AL_INVALID_VALUE:
|
||||
std::cerr << "AL_INVALID_VALUE: an invalid value was passed to an OpenAL function";
|
||||
break;
|
||||
case AL_INVALID_OPERATION:
|
||||
std::cerr << "AL_INVALID_OPERATION: the requested operation is not valid";
|
||||
break;
|
||||
case AL_OUT_OF_MEMORY:
|
||||
std::cerr << "AL_OUT_OF_MEMORY: the requested operation resulted in OpenAL running out of memory";
|
||||
break;
|
||||
default:
|
||||
std::cerr << "UNKNOWN AL ERROR: " << error;
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#ifndef SRC_AUDIO_AUDIOUTIL_H_
|
||||
#define SRC_AUDIO_AUDIOUTIL_H_
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <OpenAL/al.h>
|
||||
#else
|
||||
#include <AL/al.h>
|
||||
#endif
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include "../../typedefs.h"
|
||||
|
||||
#define AL_CHECK(STATEMENT) STATEMENT; AL::check_errors(__FILE__, __LINE__)
|
||||
#define AL_GET_ERROR() AL::check_errors(__FILE__, __LINE__)
|
||||
|
||||
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 bitsPerSample){
|
||||
bool stereo = (channels > 1);
|
||||
|
||||
switch (bitsPerSample) {
|
||||
case 16:
|
||||
if (stereo)
|
||||
return AL_FORMAT_STEREO16;
|
||||
else
|
||||
return AL_FORMAT_MONO16;
|
||||
case 8:
|
||||
if (stereo)
|
||||
return AL_FORMAT_STEREO8;
|
||||
else
|
||||
return AL_FORMAT_MONO8;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SRC_AUDIO_AUDIOUTIL_H_ */
|
||||
Reference in New Issue
Block a user