Audio module, simple text rendering

This commit is contained in:
MihailRis
2022-03-20 23:48:21 +03:00
committed by GitHub
parent e96fd909ea
commit 1770acbfef
15 changed files with 702 additions and 17 deletions
+180
View File
@@ -0,0 +1,180 @@
#include "Audio.h"
#include "audioutil.h"
#include <string>
#include <iostream>
#include <AL/al.h>
#include <AL/alc.h>
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 alCheck();
}
bool ALSource::play(){
alSourcePlay(id);
return alCheck();
}
bool ALSource::setPosition(glm::vec3 position){
alSource3f(id, AL_POSITION, position.x, position.y, position.z);
return alCheck();
}
bool ALSource::setVelocity(glm::vec3 velocity){
alSource3f(id, AL_VELOCITY, velocity.x, velocity.y, velocity.z);
return alCheck();
}
bool ALSource::setLoop(bool loop){
alSourcei(id, AL_LOOPING, AL_TRUE ? loop : AL_FALSE);
return alCheck();
}
bool ALSource::setGain(float gain) {
alSourcef(id, AL_GAIN, gain);
return alCheck();
}
bool ALSource::setPitch(float pitch) {
alSourcef(id, AL_PITCH, pitch);
return alCheck();
}
bool ALBuffer::load(int format, const char* data, int size, int freq){
alBufferData(id, format, data, size, freq);
return alCheck();
}
bool Audio::initialize(){
device = alcOpenDevice(nullptr);
if (device == nullptr)
return false;
context = alcCreateContext(device, nullptr);
if (!alcMakeContextCurrent(context)){
alcCloseDevice(device);
return false;
}
if (!alCheck())
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){
alSourceStop(source->id); alCheck();
alDeleteSources(1, &source->id); alCheck();
}
for (ALBuffer* buffer : allbuffers){
alDeleteBuffers(1, &buffer->id); alCheck();
}
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 (!alCheck())
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 (!alCheck())
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 (!alCheck())
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::setOrientation(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);
alCheck();
alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z);
alCheck();
alListenerfv(AL_ORIENTATION, listenerOri);
alCheck();
}
+61
View File
@@ -0,0 +1,61 @@
#ifndef SRC_AUDIO_AUDIO_H_
#define SRC_AUDIO_AUDIO_H_
#include <vector>
#include <string>
#include <AL/al.h>
#include <AL/alc.h>
#include <glm/glm.hpp>
struct ALBuffer;
struct ALSource {
ALuint id;
ALSource(ALuint id) : id(id) {}
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 setOrientation(glm::vec3 position, glm::vec3 velocity, glm::vec3 at, glm::vec3 up);
};
#endif /* SRC_AUDIO_AUDIO_H_ */
+194
View File
@@ -0,0 +1,194 @@
#include "audioutil.h"
#include <iostream>
#include <fstream>
#include <cstring>
#include <type_traits>
#include <AL/al.h>
#include <AL/alc.h>
bool is_big_endian(void){
union {
uint32_t i;
char c[4];
} bint = {0x01020304};
return bint.c[0] == 1;
}
std::int32_t convert_to_int(char* buffer, std::size_t len){
std::int32_t a = 0;
if(!is_big_endian())
std::memcpy(&a, buffer, len);
else
for(std::size_t i = 0; i < len; ++i)
reinterpret_cast<char*>(&a)[3 - i] = buffer[i];
return a;
}
bool check_al_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;
}
bool load_wav_file_header(std::ifstream& file,
std::uint8_t& channels,
std::int32_t& sampleRate,
std::uint8_t& bitsPerSample,
ALsizei& size){
char buffer[4];
if(!file.is_open())
return false;
// the RIFF
if(!file.read(buffer, 4)){
std::cerr << "ERROR: could not read RIFF" << std::endl;
return false;
}
if(std::strncmp(buffer, "RIFF", 4) != 0){
std::cerr << "ERROR: file is not a valid WAVE file (header doesn't begin with RIFF)" << std::endl;
return false;
}
// the size of the file
if(!file.read(buffer, 4)){
std::cerr << "ERROR: could not read size of file" << std::endl;
return false;
}
// the WAVE
if(!file.read(buffer, 4)){
std::cerr << "ERROR: could not read WAVE" << std::endl;
return false;
}
if(std::strncmp(buffer, "WAVE", 4) != 0){
std::cerr << "ERROR: file is not a valid WAVE file (header doesn't contain WAVE)" << std::endl;
return false;
}
// "fmt/0"
if(!file.read(buffer, 4)){
std::cerr << "ERROR: could not read fmt/0" << std::endl;
return false;
}
// this is always 16, the size of the fmt data chunk
if(!file.read(buffer, 4)){
std::cerr << "ERROR: could not read the 16" << std::endl;
return false;
}
// PCM should be 1?
if(!file.read(buffer, 2)){
std::cerr << "ERROR: could not read PCM" << std::endl;
return false;
}
// the number of channels
if(!file.read(buffer, 2)){
std::cerr << "ERROR: could not read number of channels" << std::endl;
return false;
}
channels = convert_to_int(buffer, 2);
// sample rate
if(!file.read(buffer, 4)){
std::cerr << "ERROR: could not read sample rate" << std::endl;
return false;
}
sampleRate = convert_to_int(buffer, 4);
// (sampleRate * bitsPerSample * channels) / 8
if(!file.read(buffer, 4)){
std::cerr << "ERROR: could not read (sampleRate * bitsPerSample * channels) / 8" << std::endl;
return false;
}
// ?? dafaq
if(!file.read(buffer, 2)){
std::cerr << "ERROR: could not read dafaq" << std::endl;
return false;
}
// bitsPerSample
if(!file.read(buffer, 2)){
std::cerr << "ERROR: could not read bits per sample" << std::endl;
return false;
}
bitsPerSample = convert_to_int(buffer, 2);
// data chunk header "data"
if(!file.read(buffer, 4)){
std::cerr << "ERROR: could not read data chunk header" << std::endl;
return false;
}
if(std::strncmp(buffer, "data", 4) != 0){
std::cerr << "ERROR: file is not a valid WAVE file (doesn't have 'data' tag)" << std::endl;
return false;
}
// size of data
if(!file.read(buffer, 4)){
std::cerr << "ERROR: could not read data size" << std::endl;
return false;
}
size = convert_to_int(buffer, 4);
/* cannot be at the end of file */
if(file.eof()){
std::cerr << "ERROR: reached EOF on the file" << std::endl;
return false;
}
if(file.fail()){
std::cerr << "ERROR: fail state set on the file" << std::endl;
return false;
}
return true;
}
char* load_wav(const std::string& filename,
std::uint8_t& channels,
std::int32_t& sampleRate,
std::uint8_t& bitsPerSample,
ALsizei& size){
std::ifstream in(filename, std::ios::binary);
if(!in.is_open()){
std::cerr << "ERROR: Could not open \"" << filename << "\"" << std::endl;
return nullptr;
}
if(!load_wav_file_header(in, channels, sampleRate, bitsPerSample, size)){
std::cerr << "ERROR: Could not load wav header of \"" << filename << "\"" << std::endl;
return nullptr;
}
char* data = new char[size];
in.read(data, size);
return data;
}
+44
View File
@@ -0,0 +1,44 @@
#ifndef SRC_AUDIO_AUDIOUTIL_H_
#define SRC_AUDIO_AUDIOUTIL_H_
#include <string>
#include <type_traits>
#include <AL/al.h>
#define alCheck() 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_ */