4 #include "SoundBank.hpp"
6 #include "../app/Assets.hpp"
7 #include "../shared/ResourceIndex.hpp"
12 #include <glm/gtc/type_ptr.hpp>
13 #include <glm/gtx/io.hpp>
18 const char *al_error_string(ALenum num) {
23 return "invalid name";
25 return "invalid enum";
26 case AL_INVALID_VALUE:
27 return "invalid value";
28 case AL_INVALID_OPERATION:
29 return "invalid operation";
30 case AL_OUT_OF_MEMORY:
31 return "out of memory";
33 return "unknown AL error";
36 std::string al_error_append(ALenum num, std::string msg) {
37 return msg + ": " + al_error_string(num);
44 ALError::ALError(ALenum num)
45 : std::runtime_error(al_error_string(num)) {
49 ALError::ALError(ALenum num, const std::string &msg)
50 : std::runtime_error(al_error_append(num, msg)) {
57 alGenSources(NUM_SRC, source);
58 ALenum err = alGetError();
59 if (err != AL_NO_ERROR) {
60 throw ALError(err, "alGenSources");
62 for (std::size_t i = 0; i < NUM_SRC; ++i) {
63 alSourcef(source[i], AL_REFERENCE_DISTANCE, 2.0f);
64 alSourcef(source[i], AL_ROLLOFF_FACTOR, 1.0f);
69 alDeleteSources(NUM_SRC, source);
70 ALenum err = alGetError();
71 if (err != AL_NO_ERROR) {
72 std::cerr << "warning: alDeleteSources failed with " << al_error_string(err) << std::endl;
73 //throw ALError(err, "alDeleteSources");
77 void Audio::Position(const glm::vec3 &pos) noexcept {
78 alListenerfv(AL_POSITION, glm::value_ptr(pos));
79 //std::cout << "listener at " << pos << std::endl;
82 void Audio::Velocity(const glm::vec3 &vel) noexcept {
83 alListenerfv(AL_VELOCITY, glm::value_ptr(vel));
86 void Audio::Orientation(const glm::vec3 &dir, const glm::vec3 &up) noexcept {
91 alListenerfv(AL_ORIENTATION, orient);
102 std::cerr << "unable to find free audio source" << std::endl;
106 ALuint src = source[i];
107 CoarseTimer &t = timer[i];
110 alSourcefv(src, AL_POSITION, glm::value_ptr(pos));
111 alSourcefv(src, AL_VELOCITY, glm::value_ptr(vel));
112 alSourcefv(src, AL_DIRECTION, glm::value_ptr(dir));
115 t = CoarseTimer(sound.Duration());
119 void Audio::StopAll() noexcept {
120 alSourceStopv(NUM_SRC, source);
121 for (std::size_t i = 0; i < NUM_SRC; ++i) {
122 alSourcei(source[i], AL_BUFFER, AL_NONE);
126 void Audio::Update(int dt) noexcept {
127 for (std::size_t i = 0; i < NUM_SRC; ++i) {
129 if (timer[i].HitOnce()) {
131 alSourceStop(source[i]);
132 alSourcei(source[i], AL_BUFFER, AL_NONE);
138 int Audio::NextFree() noexcept {
139 if (!timer[last_free].Running()) {
142 for (int i = (last_free + 1) % NUM_SRC; i != last_free; i = (i + 1) % NUM_SRC) {
143 if (!timer[i].Running()) {
158 Sound::Sound(const char *file)
159 : handle(alutCreateBufferFromFile(file)) {
160 if (handle == AL_NONE) {
161 throw ALError(alGetError(), "alutCreateBufferFromFile");
164 ALint size, channels, bits, freq;
165 alGetBufferi(handle, AL_SIZE, &size);
166 alGetBufferi(handle, AL_CHANNELS, &channels);
167 alGetBufferi(handle, AL_BITS, &bits);
168 alGetBufferi(handle, AL_FREQUENCY, &freq);
170 duration = size * 8 * 1000 / (channels * bits * freq);
174 if (handle != AL_NONE) {
175 alDeleteBuffers(1, &handle);
176 ALenum err = alGetError();
177 if (err != AL_NO_ERROR) {
178 std::cerr << "warning: alDeleteBuffers failed with " << al_error_string(err) << std::endl;
183 Sound::Sound(Sound &&other)
184 : handle(other.handle)
185 , duration(other.duration) {
186 other.handle = AL_NONE;
189 Sound &Sound::operator =(Sound &&other) {
190 std::swap(handle, other.handle);
191 std::swap(duration, other.duration);
195 void Sound::Bind(ALuint src) const {
196 alSourcei(src, AL_BUFFER, handle);
200 SoundBank::SoundBank()
205 void SoundBank::Load(const AssetLoader &loader, const ResourceIndex &index) {
207 sounds.resize(index.Size());
208 for (const auto &entry : index.Entries()) {
209 sounds[entry.second] = loader.LoadSound(entry.first);