audio system basic interface
This commit is contained in:
@@ -0,0 +1,197 @@
|
|||||||
|
#include "ALAudio.h"
|
||||||
|
#include "alutil.h"
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace audio;
|
||||||
|
|
||||||
|
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 (ALSource* source : allsources) {
|
||||||
|
if (source->isPlaying()){
|
||||||
|
alSourceStop(source->id);
|
||||||
|
alCheckErrorsMacro();
|
||||||
|
}
|
||||||
|
alDeleteSources(1, &source->id);
|
||||||
|
alCheckErrorsMacro();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ALBuffer* buffer : allbuffers){
|
||||||
|
alDeleteBuffers(1, &buffer->id);
|
||||||
|
alCheckErrorsMacro();
|
||||||
|
}
|
||||||
|
|
||||||
|
alcMakeContextCurrent(context);
|
||||||
|
alcDestroyContext(context);
|
||||||
|
if (!alcCloseDevice(device)) {
|
||||||
|
std::cerr << "AL: device not closed!" << std::endl;
|
||||||
|
}
|
||||||
|
device = 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) {
|
||||||
|
// TODO: implement
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALAudio* ALAudio::create() {
|
||||||
|
ALCdevice* device = alcOpenDevice(nullptr);
|
||||||
|
if (device == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
ALCcontext* context = alcCreateContext(device, nullptr);
|
||||||
|
if (!alcMakeContextCurrent(context)){
|
||||||
|
alcCloseDevice(device);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (!alCheckErrorsMacro()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
std::cout << "AL: initialized" << std::endl;
|
||||||
|
return new ALAudio(device, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
ALSource* ALAudio::getFreeSource(){
|
||||||
|
if (!freesources.empty()){
|
||||||
|
ALSource* 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 nullptr;
|
||||||
|
}
|
||||||
|
ALuint id;
|
||||||
|
alGenSources(1, &id);
|
||||||
|
if (!alCheckErrorsMacro())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
ALSource* source = new ALSource(id);
|
||||||
|
allsources.push_back(source);
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALBuffer* ALAudio::getFreeBuffer(){
|
||||||
|
if (!freebuffers.empty()){
|
||||||
|
ALBuffer* buffer = freebuffers.back();
|
||||||
|
freebuffers.pop_back();
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
if (allbuffers.size() == maxBuffers){
|
||||||
|
std::cerr << "attempted to create new ALbuffer, but limit is " << maxBuffers << std::endl;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
ALuint id;
|
||||||
|
alGenBuffers(1, &id);
|
||||||
|
if (!alCheckErrorsMacro()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALBuffer* buffer = new ALBuffer(id);
|
||||||
|
allbuffers.push_back(buffer);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ALAudio::freeSource(ALSource* source){
|
||||||
|
freesources.push_back(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ALAudio::freeBuffer(ALBuffer* 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 (!alCheckErrorsMacro()) {
|
||||||
|
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 };
|
||||||
|
|
||||||
|
alListener3f(AL_POSITION, position.x, position.y, position.z);
|
||||||
|
alCheckErrorsMacro();
|
||||||
|
alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z);
|
||||||
|
alCheckErrorsMacro();
|
||||||
|
alListenerfv(AL_ORIENTATION, listenerOri);
|
||||||
|
alCheckErrorsMacro();
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
#ifndef SRC_AUDIO_AUDIO_H_
|
||||||
|
#define SRC_AUDIO_AUDIO_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
|
||||||
|
struct ALSource {
|
||||||
|
uint id;
|
||||||
|
ALSource(uint id) : id(id) {}
|
||||||
|
|
||||||
|
bool isPlaying();
|
||||||
|
bool setPosition(glm::vec3 position);
|
||||||
|
bool setVelocity(glm::vec3 velocity);
|
||||||
|
bool setBuffer(ALBuffer* buffer);
|
||||||
|
bool setLoop(bool loop);
|
||||||
|
bool setGain(float gain);
|
||||||
|
bool setPitch(float pitch);
|
||||||
|
bool play();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ALBuffer {
|
||||||
|
uint id;
|
||||||
|
ALBuffer(uint id) : id(id) {}
|
||||||
|
bool load(int format, const char* data, int size, int freq);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ALAudio : public Backend {
|
||||||
|
ALCdevice* device;
|
||||||
|
ALCcontext* context;
|
||||||
|
|
||||||
|
std::vector<ALSource*> allsources;
|
||||||
|
std::vector<ALSource*> freesources;
|
||||||
|
|
||||||
|
std::vector<ALBuffer*> allbuffers;
|
||||||
|
std::vector<ALBuffer*> freebuffers;
|
||||||
|
|
||||||
|
uint maxSources;
|
||||||
|
uint maxBuffers;
|
||||||
|
|
||||||
|
ALAudio(ALCdevice* device, ALCcontext* context);
|
||||||
|
public:
|
||||||
|
~ALAudio();
|
||||||
|
|
||||||
|
ALSource* getFreeSource();
|
||||||
|
ALBuffer* getFreeBuffer();
|
||||||
|
void freeSource(ALSource* source);
|
||||||
|
void freeBuffer(ALBuffer* 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;
|
||||||
|
|
||||||
|
static ALAudio* create();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* SRC_AUDIO_AUDIO_H_ */
|
||||||
@@ -1,193 +0,0 @@
|
|||||||
#include "Audio.h"
|
|
||||||
#include "audioutil.h"
|
|
||||||
#include <string>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <OpenAL/al.h>
|
|
||||||
#include <OpenAL/alc.h>
|
|
||||||
#else
|
|
||||||
#include <AL/al.h>
|
|
||||||
#include <AL/alc.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ALCdevice* Audio::device;
|
|
||||||
ALCcontext* Audio::context;
|
|
||||||
unsigned Audio::maxSources;
|
|
||||||
unsigned Audio::maxBuffers = 1024;
|
|
||||||
std::vector<ALSource*> Audio::allsources;
|
|
||||||
std::vector<ALSource*> Audio::freesources;
|
|
||||||
std::vector<ALBuffer*> Audio::allbuffers;
|
|
||||||
std::vector<ALBuffer*> Audio::freebuffers;
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Audio::initialize() {
|
|
||||||
device = alcOpenDevice(nullptr);
|
|
||||||
if (device == nullptr)
|
|
||||||
return false;
|
|
||||||
context = alcCreateContext(device, nullptr);
|
|
||||||
if (!alcMakeContextCurrent(context)){
|
|
||||||
alcCloseDevice(device);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!alCheckErrorsMacro())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
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 << "max mono sources: " << attrs[i+1] << std::endl;
|
|
||||||
maxSources = attrs[i+1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Audio::finalize(){
|
|
||||||
for (ALSource* source : allsources){
|
|
||||||
if (source->isPlaying()){
|
|
||||||
alSourceStop(source->id); alCheckErrorsMacro();
|
|
||||||
}
|
|
||||||
alDeleteSources(1, &source->id); alCheckErrorsMacro();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ALBuffer* buffer : allbuffers){
|
|
||||||
alDeleteBuffers(1, &buffer->id); alCheckErrorsMacro();
|
|
||||||
}
|
|
||||||
|
|
||||||
alcMakeContextCurrent(context);
|
|
||||||
alcDestroyContext(context);
|
|
||||||
if (!alcCloseDevice(device)){
|
|
||||||
std::cerr << "device not closed!" << std::endl;
|
|
||||||
}
|
|
||||||
device = nullptr;
|
|
||||||
context = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ALSource* Audio::getFreeSource(){
|
|
||||||
if (!freesources.empty()){
|
|
||||||
ALSource* 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 nullptr;
|
|
||||||
}
|
|
||||||
ALuint id;
|
|
||||||
alGenSources(1, &id);
|
|
||||||
if (!alCheckErrorsMacro())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
ALSource* source = new ALSource(id);
|
|
||||||
allsources.push_back(source);
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
ALBuffer* Audio::getFreeBuffer(){
|
|
||||||
if (!freebuffers.empty()){
|
|
||||||
ALBuffer* buffer = freebuffers.back();
|
|
||||||
freebuffers.pop_back();
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
if (allbuffers.size() == maxBuffers){
|
|
||||||
std::cerr << "attempted to create new ALbuffer, but limit is " << maxBuffers << std::endl;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
ALuint id;
|
|
||||||
alGenBuffers(1, &id);
|
|
||||||
if (!alCheckErrorsMacro())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
ALBuffer* buffer = new ALBuffer(id);
|
|
||||||
allbuffers.push_back(buffer);
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Audio::freeSource(ALSource* source){
|
|
||||||
freesources.push_back(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Audio::freeBuffer(ALBuffer* buffer){
|
|
||||||
freebuffers.push_back(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Audio::get_available_devices(std::vector<std::string>& devicesVec){
|
|
||||||
const ALCchar* devices;
|
|
||||||
devices = alcGetString(device, ALC_DEVICE_SPECIFIER);
|
|
||||||
if (!alCheckErrorsMacro())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const char* ptr = devices;
|
|
||||||
|
|
||||||
devicesVec.clear();
|
|
||||||
|
|
||||||
do {
|
|
||||||
devicesVec.push_back(std::string(ptr));
|
|
||||||
ptr += devicesVec.back().size() + 1;
|
|
||||||
}
|
|
||||||
while(*(ptr + 1) != '\0');
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Audio::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 };
|
|
||||||
|
|
||||||
alListener3f(AL_POSITION, position.x, position.y, position.z);
|
|
||||||
alCheckErrorsMacro();
|
|
||||||
alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z);
|
|
||||||
alCheckErrorsMacro();
|
|
||||||
alListenerfv(AL_ORIENTATION, listenerOri);
|
|
||||||
alCheckErrorsMacro();
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
#ifndef SRC_AUDIO_AUDIO_H_
|
|
||||||
#define SRC_AUDIO_AUDIO_H_
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <OpenAL/al.h>
|
|
||||||
#include <OpenAL/alc.h>
|
|
||||||
#else
|
|
||||||
#include <AL/al.h>
|
|
||||||
#include <AL/alc.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
struct ALBuffer;
|
|
||||||
|
|
||||||
struct ALSource {
|
|
||||||
ALuint id;
|
|
||||||
ALSource(ALuint id) : id(id) {}
|
|
||||||
|
|
||||||
bool isPlaying();
|
|
||||||
bool setPosition(glm::vec3 position);
|
|
||||||
bool setVelocity(glm::vec3 velocity);
|
|
||||||
bool setBuffer(ALBuffer* buffer);
|
|
||||||
bool setLoop(bool loop);
|
|
||||||
bool setGain(float gain);
|
|
||||||
bool setPitch(float pitch);
|
|
||||||
bool play();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ALBuffer {
|
|
||||||
ALuint id;
|
|
||||||
ALBuffer(ALuint id) : id(id) {}
|
|
||||||
bool load(int format, const char* data, int size, int freq);
|
|
||||||
};
|
|
||||||
|
|
||||||
class Audio {
|
|
||||||
static ALCdevice* device;
|
|
||||||
static ALCcontext* context;
|
|
||||||
|
|
||||||
static std::vector<ALSource*> allsources;
|
|
||||||
static std::vector<ALSource*> freesources;
|
|
||||||
|
|
||||||
static std::vector<ALBuffer*> allbuffers;
|
|
||||||
static std::vector<ALBuffer*> freebuffers;
|
|
||||||
|
|
||||||
static unsigned maxSources;
|
|
||||||
static unsigned maxBuffers;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static ALSource* getFreeSource();
|
|
||||||
static ALBuffer* getFreeBuffer();
|
|
||||||
static void freeSource(ALSource* source);
|
|
||||||
static void freeBuffer(ALBuffer* buffer);
|
|
||||||
|
|
||||||
static bool initialize();
|
|
||||||
static void finalize();
|
|
||||||
static bool get_available_devices(std::vector<std::string>& devicesVec);
|
|
||||||
|
|
||||||
static void setListener(glm::vec3 position, glm::vec3 velocity, glm::vec3 at, glm::vec3 up);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* SRC_AUDIO_AUDIO_H_ */
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#include "NoAudio.h"
|
||||||
|
|
||||||
|
using namespace audio;
|
||||||
|
|
||||||
|
NoSound::NoSound(std::shared_ptr<PCM> pcm, bool keepPCM) {
|
||||||
|
duration = pcm->getDuration();
|
||||||
|
if (keepPCM) {
|
||||||
|
this->pcm = pcm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Sound* NoAudio::createSound(std::shared_ptr<PCM> pcm, bool keepPCM) {
|
||||||
|
return new NoSound(pcm, keepPCM);
|
||||||
|
}
|
||||||
|
|
||||||
|
NoAudio* NoAudio::create() {
|
||||||
|
return new NoAudio();
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#ifndef AUDIO_NOAUDIO_H_
|
||||||
|
#define AUDIO_NOAUDIO_H_
|
||||||
|
|
||||||
|
#include "audio.h"
|
||||||
|
|
||||||
|
namespace audio {
|
||||||
|
class NoSound : public Sound {
|
||||||
|
std::shared_ptr<PCM> pcm;
|
||||||
|
duration_t duration;
|
||||||
|
public:
|
||||||
|
NoSound(std::shared_ptr<PCM> pcm, bool keepPCM);
|
||||||
|
~NoSound() {}
|
||||||
|
|
||||||
|
duration_t getDuration() const override {
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<PCM> getPCM() const override {
|
||||||
|
return pcm;
|
||||||
|
}
|
||||||
|
|
||||||
|
speakerid_t newInstance(int priority) const override {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class NoAudio : public Backend {
|
||||||
|
public:
|
||||||
|
~NoAudio() {}
|
||||||
|
|
||||||
|
Sound* createSound(std::shared_ptr<PCM> pcm, bool keepPCM) override;
|
||||||
|
|
||||||
|
void setListener(
|
||||||
|
glm::vec3 position,
|
||||||
|
glm::vec3 velocity,
|
||||||
|
glm::vec3 at,
|
||||||
|
glm::vec3 up
|
||||||
|
) override {}
|
||||||
|
|
||||||
|
static NoAudio* create();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // AUDIO_NOAUDIO_H_
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "audioutil.h"
|
#include "alutil.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -180,11 +180,13 @@ bool load_wav_file_header(std::ifstream& file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// after that user must free returned memory by himself!
|
// after that user must free returned memory by himself!
|
||||||
char* load_wav(const std::string& filename,
|
char* load_wav(
|
||||||
std::uint8_t& channels,
|
const std::string& filename,
|
||||||
std::int32_t& sampleRate,
|
std::uint8_t& channels,
|
||||||
std::uint8_t& bitsPerSample,
|
std::int32_t& sampleRate,
|
||||||
ALsizei& size){
|
std::uint8_t& bitsPerSample,
|
||||||
|
ALsizei& size
|
||||||
|
){
|
||||||
std::ifstream in(filename, std::ios::binary);
|
std::ifstream in(filename, std::ios::binary);
|
||||||
if(!in.is_open()){
|
if(!in.is_open()){
|
||||||
std::cerr << "ERROR: Could not open \"" << filename << "\"" << std::endl;
|
std::cerr << "ERROR: Could not open \"" << filename << "\"" << std::endl;
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#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
|
||||||
|
|
||||||
|
#define alCheckErrorsMacro() check_al_errors(__FILE__, __LINE__)
|
||||||
|
|
||||||
|
bool check_al_errors(const std::string& filename, const std::uint_fast32_t line);
|
||||||
|
|
||||||
|
bool load_wav_file_header(
|
||||||
|
std::ifstream& file,
|
||||||
|
std::uint8_t& channels,
|
||||||
|
std::int32_t& sampleRate,
|
||||||
|
std::uint8_t& bitsPerSample,
|
||||||
|
ALsizei& size
|
||||||
|
);
|
||||||
|
|
||||||
|
char* load_wav(
|
||||||
|
const std::string& filename,
|
||||||
|
std::uint8_t& channels,
|
||||||
|
std::int32_t& sampleRate,
|
||||||
|
std::uint8_t& bitsPerSample,
|
||||||
|
ALsizei& size
|
||||||
|
);
|
||||||
|
|
||||||
|
static inline ALenum to_al_format(short channels, short samples){
|
||||||
|
bool stereo = (channels > 1);
|
||||||
|
|
||||||
|
switch (samples) {
|
||||||
|
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_ */
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#include "audio.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "ALAudio.h"
|
||||||
|
#include "NoAudio.h"
|
||||||
|
|
||||||
|
audio::Backend* audio::backend = nullptr;
|
||||||
|
|
||||||
|
void audio::initialize(bool enabled) {
|
||||||
|
if (enabled) {
|
||||||
|
audio::backend = ALAudio::create();
|
||||||
|
}
|
||||||
|
if (audio::backend == nullptr) {
|
||||||
|
std::cerr << "could not to initialize audio" << std::endl;
|
||||||
|
audio::backend = NoAudio::create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void audio::setListener(
|
||||||
|
glm::vec3 position,
|
||||||
|
glm::vec3 velocity,
|
||||||
|
glm::vec3 lookAt,
|
||||||
|
glm::vec3 up
|
||||||
|
) {
|
||||||
|
audio::backend->setListener(position, velocity, lookAt, up);
|
||||||
|
}
|
||||||
|
|
||||||
|
void audio::close() {
|
||||||
|
delete audio::backend;
|
||||||
|
audio::backend = nullptr;
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
#ifndef AUDIO_AUDIO_H_
|
||||||
|
#define AUDIO_AUDIO_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include "../typedefs.h"
|
||||||
|
|
||||||
|
namespace audio {
|
||||||
|
using speakerid_t = int64_t;
|
||||||
|
/// @brief duration unit is second
|
||||||
|
using duration_t = float;
|
||||||
|
|
||||||
|
/// @brief Pulse-code modulation data
|
||||||
|
struct PCM {
|
||||||
|
/// @brief May contain 8 bit and 16 bit PCM data
|
||||||
|
std::vector<char> data;
|
||||||
|
uint8_t channels;
|
||||||
|
uint8_t bitsPerSample;
|
||||||
|
uint sampleRate;
|
||||||
|
|
||||||
|
constexpr inline size_t countSamples() const {
|
||||||
|
return data.size() / channels / (bitsPerSample / 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline duration_t getDuration() const {
|
||||||
|
return countSamples() / static_cast<duration_t>(sampleRate);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Sound is an audio asset that supposed to support many
|
||||||
|
/// simultaneously playing instances with different sources.
|
||||||
|
/// So it's audio data is stored in memory.
|
||||||
|
class Sound {
|
||||||
|
public:
|
||||||
|
virtual ~Sound() {}
|
||||||
|
|
||||||
|
/// @brief Get sound duration
|
||||||
|
/// @return duration in seconds (>= 0.0)
|
||||||
|
virtual duration_t getDuration() const = 0;
|
||||||
|
|
||||||
|
/// @brief Get sound PCM data
|
||||||
|
/// @return PCM data or nullptr
|
||||||
|
virtual std::shared_ptr<PCM> getPCM() const = 0;
|
||||||
|
|
||||||
|
/// @brief Create new sound instance
|
||||||
|
/// @param priority instance priority. High priority instance can
|
||||||
|
/// take out speaker from low priority instance
|
||||||
|
/// @return new speaker id with sound bound or 0
|
||||||
|
/// if all speakers are in use
|
||||||
|
virtual speakerid_t newInstance(int priority) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Backend {
|
||||||
|
public:
|
||||||
|
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 void setListener(
|
||||||
|
glm::vec3 position,
|
||||||
|
glm::vec3 velocity,
|
||||||
|
glm::vec3 lookAt,
|
||||||
|
glm::vec3 up
|
||||||
|
) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Backend* backend;
|
||||||
|
|
||||||
|
/// @brief Initialize audio system or use no audio mode
|
||||||
|
/// @param enabled try to initialize actual audio
|
||||||
|
extern void initialize(bool enabled);
|
||||||
|
|
||||||
|
/// @brief Configure 3D listener
|
||||||
|
/// @param position listener position
|
||||||
|
/// @param velocity listener velocity (used for Doppler effect)
|
||||||
|
/// @param lookAt point the listener look at
|
||||||
|
/// @param up camera up vector
|
||||||
|
extern void setListener(
|
||||||
|
glm::vec3 position,
|
||||||
|
glm::vec3 velocity,
|
||||||
|
glm::vec3 lookAt,
|
||||||
|
glm::vec3 up
|
||||||
|
);
|
||||||
|
/// @brief Finalize audio system
|
||||||
|
extern void close();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // AUDIO_AUDIO_H_
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
#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
|
|
||||||
|
|
||||||
#define alCheckErrorsMacro() check_al_errors(__FILE__, __LINE__)
|
|
||||||
|
|
||||||
bool check_al_errors(const std::string& filename, const std::uint_fast32_t line);
|
|
||||||
|
|
||||||
bool load_wav_file_header(std::ifstream& file,
|
|
||||||
std::uint8_t& channels,
|
|
||||||
std::int32_t& sampleRate,
|
|
||||||
std::uint8_t& bitsPerSample,
|
|
||||||
ALsizei& size);
|
|
||||||
|
|
||||||
char* load_wav(const std::string& filename,
|
|
||||||
std::uint8_t& channels,
|
|
||||||
std::int32_t& sampleRate,
|
|
||||||
std::uint8_t& bitsPerSample,
|
|
||||||
ALsizei& size);
|
|
||||||
|
|
||||||
static inline ALenum to_al_format(short channels, short samples){
|
|
||||||
bool stereo = (channels > 1);
|
|
||||||
|
|
||||||
switch (samples) {
|
|
||||||
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_ */
|
|
||||||
+3
-5
@@ -10,7 +10,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#define GLEW_STATIC
|
#define GLEW_STATIC
|
||||||
|
|
||||||
#include "audio/Audio.h"
|
#include "audio/audio.h"
|
||||||
#include "assets/Assets.h"
|
#include "assets/Assets.h"
|
||||||
#include "assets/AssetsLoader.h"
|
#include "assets/AssetsLoader.h"
|
||||||
#include "world/WorldGenerators.h"
|
#include "world/WorldGenerators.h"
|
||||||
@@ -56,6 +56,7 @@ Engine::Engine(EngineSettings& settings, EnginePaths* paths)
|
|||||||
if (Window::initialize(settings.display)){
|
if (Window::initialize(settings.display)){
|
||||||
throw initialize_error("could not initialize window");
|
throw initialize_error("could not initialize window");
|
||||||
}
|
}
|
||||||
|
audio::initialize(true);
|
||||||
|
|
||||||
auto resdir = paths->getResources();
|
auto resdir = paths->getResources();
|
||||||
scripting::initialize(this);
|
scripting::initialize(this);
|
||||||
@@ -66,7 +67,6 @@ Engine::Engine(EngineSettings& settings, EnginePaths* paths)
|
|||||||
resPaths = std::make_unique<ResPaths>(resdir, roots);
|
resPaths = std::make_unique<ResPaths>(resdir, roots);
|
||||||
assets = std::make_unique<Assets>();
|
assets = std::make_unique<Assets>();
|
||||||
|
|
||||||
|
|
||||||
AssetsLoader loader(assets.get(), resPaths.get());
|
AssetsLoader loader(assets.get(), resPaths.get());
|
||||||
AssetsLoader::addDefaults(loader, nullptr);
|
AssetsLoader::addDefaults(loader, nullptr);
|
||||||
|
|
||||||
@@ -79,8 +79,6 @@ Engine::Engine(EngineSettings& settings, EnginePaths* paths)
|
|||||||
throw initialize_error("could not to load assets");
|
throw initialize_error("could not to load assets");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Audio::initialize();
|
|
||||||
gui = std::make_unique<gui::GUI>();
|
gui = std::make_unique<gui::GUI>();
|
||||||
if (settings.ui.language == "auto") {
|
if (settings.ui.language == "auto") {
|
||||||
settings.ui.language = langs::locale_by_envlocale(platform::detect_locale(), paths->getResources());
|
settings.ui.language = langs::locale_by_envlocale(platform::detect_locale(), paths->getResources());
|
||||||
@@ -148,7 +146,7 @@ Engine::~Engine() {
|
|||||||
screen.reset();
|
screen.reset();
|
||||||
content.reset();
|
content.reset();
|
||||||
|
|
||||||
Audio::finalize();
|
audio::close();
|
||||||
assets.reset();
|
assets.reset();
|
||||||
scripting::close();
|
scripting::close();
|
||||||
Window::terminate();
|
Window::terminate();
|
||||||
|
|||||||
Reference in New Issue
Block a user