]> git.localhorst.tv Git - blank.git/blob - src/audio/audio.cpp
some experiments with sound
[blank.git] / src / audio / audio.cpp
1 #include "ALError.hpp"
2 #include "Audio.hpp"
3 #include "Sound.hpp"
4
5 #include <algorithm>
6 #include <alut.h>
7 #include <iostream>
8 #include <glm/gtc/type_ptr.hpp>
9 #include <glm/gtx/io.hpp>
10
11
12 namespace {
13
14 const char *al_error_string(ALenum num) {
15         switch (num) {
16                 case AL_NO_ERROR:
17                         return "no error";
18                 case AL_INVALID_NAME:
19                         return "invalid name";
20                 case AL_INVALID_ENUM:
21                         return "invalid enum";
22                 case AL_INVALID_VALUE:
23                         return "invalid value";
24                 case AL_INVALID_OPERATION:
25                         return "invalid operation";
26                 case AL_OUT_OF_MEMORY:
27                         return "out of memory";
28         }
29         return "unknown AL error";
30 }
31
32 std::string al_error_append(ALenum num, std::string msg) {
33         return msg + ": " + al_error_string(num);
34 }
35
36 }
37
38 namespace blank {
39
40 ALError::ALError(ALenum num)
41 : std::runtime_error(al_error_string(num)) {
42
43 }
44
45 ALError::ALError(ALenum num, const std::string &msg)
46 : std::runtime_error(al_error_append(num, msg)) {
47
48 }
49
50
51 Audio::Audio() {
52         alGenSources(NUM_SRC, source);
53         ALenum err = alGetError();
54         if (err != AL_NO_ERROR) {
55                 throw ALError(err, "alGenSources");
56         }
57         for (std::size_t i = 0; i < NUM_SRC; ++i) {
58                 alSourcef(source[i], AL_REFERENCE_DISTANCE, 2.0f);
59                 alSourcef(source[i], AL_ROLLOFF_FACTOR, 1.0f);
60         }
61 }
62
63 Audio::~Audio() {
64         alDeleteSources(NUM_SRC, source);
65         ALenum err = alGetError();
66         if (err != AL_NO_ERROR) {
67                 std::cerr << "warning: alDeleteSources failed with " << al_error_string(err) << std::endl;
68                 //throw ALError(err, "alDeleteSources");
69         }
70 }
71
72 void Audio::Position(const glm::vec3 &pos) noexcept {
73         alListenerfv(AL_POSITION, glm::value_ptr(pos));
74         //std::cout << "listener at " << pos << std::endl;
75 }
76
77 void Audio::Velocity(const glm::vec3 &vel) noexcept {
78         alListenerfv(AL_VELOCITY, glm::value_ptr(vel));
79 }
80
81 void Audio::Orientation(const glm::vec3 &dir, const glm::vec3 &up) noexcept {
82         ALfloat orient[6] = {
83                 dir.x, dir.y, dir.z,
84                 up.x, up.y, up.z,
85         };
86         alListenerfv(AL_ORIENTATION, orient);
87 }
88
89 void Audio::Play(
90         const Sound &sound,
91         const glm::vec3 &pos,
92         const glm::vec3 &vel,
93         const glm::vec3 &dir
94 ) noexcept {
95         // TODO: find next free source
96         ALuint src = source[0];
97
98         sound.Bind(src);
99         alSourcefv(src, AL_POSITION, glm::value_ptr(pos));
100         alSourcefv(src, AL_VELOCITY, glm::value_ptr(vel));
101         alSourcefv(src, AL_DIRECTION, glm::value_ptr(dir));
102         alSourcePlay(src);
103 }
104
105 void Audio::StopAll() noexcept {
106         alSourceStopv(NUM_SRC, source);
107         for (std::size_t i = 0; i < NUM_SRC; ++i) {
108                 alSourcei(source[i], AL_BUFFER, AL_NONE);
109         }
110 }
111
112
113 Sound::Sound()
114 : handle(AL_NONE) {
115         alGenBuffers(1, &handle);
116         ALenum err = alGetError();
117         if (err != AL_NO_ERROR) {
118                 throw ALError(err, "alGenBuffers");
119         }
120 }
121
122 Sound::Sound(const char *file)
123 : handle(alutCreateBufferFromFile(file)) {
124         if (handle == AL_NONE) {
125                 throw ALError(alGetError(), "alutCreateBufferFromFile");
126         }
127 }
128
129 Sound::~Sound() {
130         if (handle != AL_NONE) {
131                 alDeleteBuffers(1, &handle);
132                 ALenum err = alGetError();
133                 if (err != AL_NO_ERROR) {
134                         std::cerr << "warning: alDeleteBuffers failed with " << al_error_string(err) << std::endl;
135                         //throw ALError(err, "alDeleteBuffers");
136                 }
137         }
138 }
139
140 Sound::Sound(Sound &&other)
141 : handle(other.handle) {
142         other.handle = AL_NONE;
143 }
144
145 Sound &Sound::operator =(Sound &&other) {
146         std::swap(handle, other.handle);
147         return *this;
148 }
149
150 void Sound::Bind(ALuint src) const {
151         alSourcei(src, AL_BUFFER, handle);
152 }
153
154 }