]> git.localhorst.tv Git - gong.git/blob - src/audio/audio.cpp
code, assets, and other stuff stolen from blank
[gong.git] / src / audio / audio.cpp
1 #include "Audio.hpp"
2 #include "Sound.hpp"
3 #include "SoundBank.hpp"
4
5 #include "../app/AssetLoader.hpp"
6 #include "../app/error.hpp"
7 #include "../app/ResourceIndex.hpp"
8
9 #include <algorithm>
10 #include <alut.h>
11 #include <iostream>
12 #include <glm/gtc/type_ptr.hpp>
13 #include <glm/gtx/io.hpp>
14
15
16 namespace gong {
17 namespace audio {
18
19 Audio::Audio()
20 : last_free(0) {
21         alGenSources(NUM_SRC, source);
22         ALenum err = alGetError();
23         if (err != AL_NO_ERROR) {
24                 throw app::ALError(err, "alGenSources");
25         }
26         for (std::size_t i = 0; i < NUM_SRC; ++i) {
27                 alSourcef(source[i], AL_REFERENCE_DISTANCE, 2.0f);
28                 alSourcef(source[i], AL_ROLLOFF_FACTOR, 1.0f);
29         }
30 }
31
32 Audio::~Audio() {
33         alDeleteSources(NUM_SRC, source);
34         ALenum err = alGetError();
35         if (err != AL_NO_ERROR) {
36                 app::ALError error(err, "alDeleteSources");
37                 std::cerr << "warning: " << error.what() << std::endl;
38                 //throw error;
39         }
40 }
41
42 void Audio::Position(const glm::vec3 &pos) noexcept {
43         alListenerfv(AL_POSITION, glm::value_ptr(pos));
44         //std::cout << "listener at " << pos << std::endl;
45 }
46
47 void Audio::Velocity(const glm::vec3 &vel) noexcept {
48         alListenerfv(AL_VELOCITY, glm::value_ptr(vel));
49 }
50
51 void Audio::Orientation(const glm::vec3 &dir, const glm::vec3 &up) noexcept {
52         ALfloat orient[6] = {
53                 dir.x, dir.y, dir.z,
54                 up.x, up.y, up.z,
55         };
56         alListenerfv(AL_ORIENTATION, orient);
57 }
58
59 void Audio::Play(
60         const Sound &sound,
61         const glm::vec3 &pos,
62         const glm::vec3 &vel,
63         const glm::vec3 &dir
64 ) noexcept {
65         int i = NextFree();
66         if (i < 0) {
67                 std::cerr << "unable to find free audio source" << std::endl;
68                 return;
69         }
70
71         ALuint src = source[i];
72         app::CoarseTimer &t = timer[i];
73
74         sound.Bind(src);
75         alSourcefv(src, AL_POSITION, glm::value_ptr(pos));
76         alSourcefv(src, AL_VELOCITY, glm::value_ptr(vel));
77         alSourcefv(src, AL_DIRECTION, glm::value_ptr(dir));
78         alSourcePlay(src);
79
80         t = app::CoarseTimer(sound.Duration());
81         t.Start();
82 }
83
84 void Audio::StopAll() noexcept {
85         alSourceStopv(NUM_SRC, source);
86         for (std::size_t i = 0; i < NUM_SRC; ++i) {
87                 alSourcei(source[i], AL_BUFFER, AL_NONE);
88         }
89 }
90
91 void Audio::Update(int dt) noexcept {
92         for (std::size_t i = 0; i < NUM_SRC; ++i) {
93                 timer[i].Update(dt);
94                 if (timer[i].HitOnce()) {
95                         timer[i].Stop();
96                         alSourceStop(source[i]);
97                         alSourcei(source[i], AL_BUFFER, AL_NONE);
98                         last_free = i;
99                 }
100         }
101 }
102
103 int Audio::NextFree() noexcept {
104         if (!timer[last_free].Running()) {
105                 return last_free;
106         }
107         for (int i = (last_free + 1) % NUM_SRC; i != last_free; i = (i + 1) % NUM_SRC) {
108                 if (!timer[i].Running()) {
109                         last_free = i;
110                         return i;
111                 }
112         }
113         return -1;
114 }
115
116
117 Sound::Sound()
118 : handle(AL_NONE)
119 , duration(0) {
120
121 }
122
123 Sound::Sound(const char *file)
124 : handle(alutCreateBufferFromFile(file)) {
125         if (handle == AL_NONE) {
126                 throw app::ALError(alGetError(), "alutCreateBufferFromFile");
127         }
128
129         ALint size, channels, bits, freq;
130         alGetBufferi(handle, AL_SIZE, &size);
131         alGetBufferi(handle, AL_CHANNELS, &channels);
132         alGetBufferi(handle, AL_BITS, &bits);
133         alGetBufferi(handle, AL_FREQUENCY, &freq);
134
135         duration = size * 8 * 1000 / (channels * bits * freq);
136 }
137
138 Sound::~Sound() {
139         if (handle != AL_NONE) {
140                 alDeleteBuffers(1, &handle);
141                 ALenum err = alGetError();
142                 if (err != AL_NO_ERROR) {
143                         app::ALError error(err, "alDeleteBuffers");
144                         std::cerr << "warning: " << error.what() << std::endl;
145                         //throw error;
146                 }
147         }
148 }
149
150 Sound::Sound(Sound &&other)
151 : handle(other.handle)
152 , duration(other.duration) {
153         other.handle = AL_NONE;
154 }
155
156 Sound &Sound::operator =(Sound &&other) {
157         std::swap(handle, other.handle);
158         std::swap(duration, other.duration);
159         return *this;
160 }
161
162 void Sound::Bind(ALuint src) const {
163         alSourcei(src, AL_BUFFER, handle);
164 }
165
166
167 SoundBank::SoundBank()
168 : sounds() {
169
170 }
171
172 void SoundBank::Load(const app::AssetLoader &loader, const app::ResourceIndex &index) {
173         sounds.clear();
174         sounds.resize(index.Size());
175         for (const auto &entry : index.Entries()) {
176                 sounds[entry.second] = loader.LoadSound(entry.first);
177         }
178 }
179
180 }
181 }