]> git.localhorst.tv Git - blank.git/blobdiff - src/audio/audio.cpp
some experiments with sound
[blank.git] / src / audio / audio.cpp
diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp
new file mode 100644 (file)
index 0000000..eed5dac
--- /dev/null
@@ -0,0 +1,154 @@
+#include "ALError.hpp"
+#include "Audio.hpp"
+#include "Sound.hpp"
+
+#include <algorithm>
+#include <alut.h>
+#include <iostream>
+#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtx/io.hpp>
+
+
+namespace {
+
+const char *al_error_string(ALenum num) {
+       switch (num) {
+               case AL_NO_ERROR:
+                       return "no error";
+               case AL_INVALID_NAME:
+                       return "invalid name";
+               case AL_INVALID_ENUM:
+                       return "invalid enum";
+               case AL_INVALID_VALUE:
+                       return "invalid value";
+               case AL_INVALID_OPERATION:
+                       return "invalid operation";
+               case AL_OUT_OF_MEMORY:
+                       return "out of memory";
+       }
+       return "unknown AL error";
+}
+
+std::string al_error_append(ALenum num, std::string msg) {
+       return msg + ": " + al_error_string(num);
+}
+
+}
+
+namespace blank {
+
+ALError::ALError(ALenum num)
+: std::runtime_error(al_error_string(num)) {
+
+}
+
+ALError::ALError(ALenum num, const std::string &msg)
+: std::runtime_error(al_error_append(num, msg)) {
+
+}
+
+
+Audio::Audio() {
+       alGenSources(NUM_SRC, source);
+       ALenum err = alGetError();
+       if (err != AL_NO_ERROR) {
+               throw ALError(err, "alGenSources");
+       }
+       for (std::size_t i = 0; i < NUM_SRC; ++i) {
+               alSourcef(source[i], AL_REFERENCE_DISTANCE, 2.0f);
+               alSourcef(source[i], AL_ROLLOFF_FACTOR, 1.0f);
+       }
+}
+
+Audio::~Audio() {
+       alDeleteSources(NUM_SRC, source);
+       ALenum err = alGetError();
+       if (err != AL_NO_ERROR) {
+               std::cerr << "warning: alDeleteSources failed with " << al_error_string(err) << std::endl;
+               //throw ALError(err, "alDeleteSources");
+       }
+}
+
+void Audio::Position(const glm::vec3 &pos) noexcept {
+       alListenerfv(AL_POSITION, glm::value_ptr(pos));
+       //std::cout << "listener at " << pos << std::endl;
+}
+
+void Audio::Velocity(const glm::vec3 &vel) noexcept {
+       alListenerfv(AL_VELOCITY, glm::value_ptr(vel));
+}
+
+void Audio::Orientation(const glm::vec3 &dir, const glm::vec3 &up) noexcept {
+       ALfloat orient[6] = {
+               dir.x, dir.y, dir.z,
+               up.x, up.y, up.z,
+       };
+       alListenerfv(AL_ORIENTATION, orient);
+}
+
+void Audio::Play(
+       const Sound &sound,
+       const glm::vec3 &pos,
+       const glm::vec3 &vel,
+       const glm::vec3 &dir
+) noexcept {
+       // TODO: find next free source
+       ALuint src = source[0];
+
+       sound.Bind(src);
+       alSourcefv(src, AL_POSITION, glm::value_ptr(pos));
+       alSourcefv(src, AL_VELOCITY, glm::value_ptr(vel));
+       alSourcefv(src, AL_DIRECTION, glm::value_ptr(dir));
+       alSourcePlay(src);
+}
+
+void Audio::StopAll() noexcept {
+       alSourceStopv(NUM_SRC, source);
+       for (std::size_t i = 0; i < NUM_SRC; ++i) {
+               alSourcei(source[i], AL_BUFFER, AL_NONE);
+       }
+}
+
+
+Sound::Sound()
+: handle(AL_NONE) {
+       alGenBuffers(1, &handle);
+       ALenum err = alGetError();
+       if (err != AL_NO_ERROR) {
+               throw ALError(err, "alGenBuffers");
+       }
+}
+
+Sound::Sound(const char *file)
+: handle(alutCreateBufferFromFile(file)) {
+       if (handle == AL_NONE) {
+               throw ALError(alGetError(), "alutCreateBufferFromFile");
+       }
+}
+
+Sound::~Sound() {
+       if (handle != AL_NONE) {
+               alDeleteBuffers(1, &handle);
+               ALenum err = alGetError();
+               if (err != AL_NO_ERROR) {
+                       std::cerr << "warning: alDeleteBuffers failed with " << al_error_string(err) << std::endl;
+                       //throw ALError(err, "alDeleteBuffers");
+               }
+       }
+}
+
+Sound::Sound(Sound &&other)
+: handle(other.handle) {
+       other.handle = AL_NONE;
+}
+
+Sound &Sound::operator =(Sound &&other) {
+       std::swap(handle, other.handle);
+       return *this;
+}
+
+void Sound::Bind(ALuint src) const {
+       alSourcei(src, AL_BUFFER, handle);
+}
+
+}