comparison OpenALSoundProvider.h @ 2324:b2e3ac05f2b3

Merge
author Grumpy7
date Thu, 27 Mar 2014 23:30:02 +0100
parents 9987f93d7e1f
children a2d95b16e28b
comparison
equal deleted inserted replaced
2323:983b8c995127 2324:b2e3ac05f2b3
1 #pragma once
2 #include "lib/OpenAL/al.h"
3 #include "lib/OpenAL/alc.h"
4 #pragma comment(lib, "OpenAL32.lib")
5
6 #include "stuff.h"
7
8 class OpenALSoundProvider
9 {
10 public:
11 struct TrackBuffer
12 {
13 unsigned int source_id;
14 unsigned int buffer_id;
15 };
16
17 struct StreamingTrackBuffer
18 {
19 unsigned int source_id;
20 ALenum sample_format;
21 int sample_rate;
22 };
23
24 inline OpenALSoundProvider()
25 {
26 this->device = nullptr;
27 this->context = nullptr;
28 }
29
30 inline bool Initialize()
31 {
32 auto device_names = alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
33 if (!device_names)
34 device_names = alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
35 if (device_names)
36 {
37 for (auto device_name = device_names; device_name[0]; device_name += strlen(device_name))
38 {
39 continue;
40 }
41 }
42
43 device = alcOpenDevice(nullptr);
44 if (!device || CheckError())
45 return false;
46
47 context = alcCreateContext(device, nullptr);
48 if (!context || CheckError())
49 return Release(), false;
50
51 alcMakeContextCurrent(context);
52
53 bool eax2 = alIsExtensionPresent("EAX2.0");
54 bool eax3 = alIsExtensionPresent("EAX3.0");
55 bool eax4 = alIsExtensionPresent("EAX4.0");
56 bool eax5 = alIsExtensionPresent("EAX5.0");
57
58 auto vendor = alGetString(AL_VENDOR);
59 auto version = alGetString(AL_VERSION);
60 auto extensions = alcGetString(device, ALC_EXTENSIONS);
61
62 return true;
63 }
64
65 void Release()
66 {
67 alcMakeContextCurrent(nullptr);
68 if (context)
69 {
70 alcDestroyContext(context);
71 context = nullptr;
72 }
73 if (device)
74 {
75 alcCloseDevice(device);
76 device = nullptr;
77 }
78 }
79
80
81 void DeleteBuffer16(TrackBuffer **buffer)
82 {
83 alDeleteBuffers(1, &(*buffer)->buffer_id);
84 CheckError();
85
86 delete *buffer;
87 *buffer = nullptr;
88 }
89
90 float alBufferLength(unsigned int buffer)
91 {
92 int size, bits, channels, freq;
93
94 alGetBufferi(buffer, AL_SIZE, &size);
95 alGetBufferi(buffer, AL_BITS, &bits);
96 alGetBufferi(buffer, AL_CHANNELS, &channels);
97 alGetBufferi(buffer, AL_FREQUENCY, &freq);
98 if (CheckError())
99 return 0.0f;
100
101 return (ALfloat)((ALuint)size / channels / (bits / 8)) / (ALfloat)freq;
102 }
103
104 StreamingTrackBuffer *CreateStreamingTrack16(int num_channels, int sample_rate, int bytes_per_sample)
105 {
106 Assert(bytes_per_sample == 2, "OpenALSoundProvider: unsupported sample size: %u", bytes_per_sample);
107
108 ALenum sound_format;
109 switch (num_channels)
110 {
111 case 1: sound_format = AL_FORMAT_MONO16; break;
112 case 2: sound_format = AL_FORMAT_STEREO16; break;
113 default:
114 if (bool multichannel = alIsExtensionPresent("AL_EXT_MCFORMATS"))
115 {
116 switch (num_channels)
117 {
118 case 4: sound_format = alGetEnumValue("AL_FORMAT_QUAD16"); break;
119 case 6: sound_format = alGetEnumValue("AL_FORMAT_51CHN16"); break;
120 case 7: sound_format = alGetEnumValue("AL_FORMAT_61CHN16"); break;
121 case 8: sound_format = alGetEnumValue("AL_FORMAT_71CHN16"); break;
122 }
123 }
124 Error("Unsupported number of audio channels: %u", num_channels);
125 }
126
127 unsigned int al_source = -1;
128 alGenSources(1, &al_source);
129 if (CheckError())
130 return nullptr;
131
132 float sound_pos[] = {0.0f, 0.0f, 0.0f},
133 sound_vel[] = {0.0f, 0.0f, 0.0f};
134
135 alSourcei(al_source, AL_LOOPING, AL_FALSE);
136 alSourcef(al_source, AL_PITCH, 1.0f);
137 alSourcef(al_source, AL_GAIN, 1.0f);
138 alSourcefv(al_source, AL_POSITION, sound_pos);
139 alSourcefv(al_source, AL_VELOCITY, sound_vel);
140
141 auto ret = new StreamingTrackBuffer;
142 ret->source_id = al_source;
143 ret->sample_format = sound_format;
144 ret->sample_rate = sample_rate;
145 return ret;
146 }
147
148 void Stream16(StreamingTrackBuffer *buffer, int num_samples, const void *samples, bool wait = false)
149 {
150 int bytes_per_sample = 2;
151
152 unsigned int al_buffer;
153 alGenBuffers(1, &al_buffer);
154 alBufferData(al_buffer, buffer->sample_format, samples, num_samples * bytes_per_sample, buffer->sample_rate);
155 if (CheckError())
156 {
157 alDeleteBuffers(1, &al_buffer);
158 return;
159 }
160
161 int num_processed_buffers = 0;
162 alGetSourcei(buffer->source_id, AL_BUFFERS_PROCESSED, &num_processed_buffers);
163 for (int i = 0; i < num_processed_buffers; ++i)
164 {
165 unsigned int processed_buffer_id;
166 alSourceUnqueueBuffers(buffer->source_id, 1, &processed_buffer_id);
167 if (!CheckError())
168 alDeleteBuffers(1, &processed_buffer_id);
169 }
170
171 alSourceQueueBuffers(buffer->source_id, 1, &al_buffer);
172 if (CheckError())
173 {
174 alDeleteBuffers(1, &al_buffer);
175 return;
176 }
177
178 volatile int status;
179 alGetSourcei(buffer->source_id, AL_SOURCE_STATE, (int *)&status);
180 if (status != AL_PLAYING)
181 {
182 float listener_pos[] = {0.0f, 0.0f, 0.0f};
183 float listener_vel[] = {0.0f, 0.0f, 0.0f};
184 float listener_orientation[] = {0.0f, 0.0f, -1.0f, // direction
185 0.0f, 1.0f, 0.0f}; // up vector
186 alListenerfv(AL_POSITION, listener_pos);
187 alListenerfv(AL_VELOCITY, listener_vel);
188 alListenerfv(AL_ORIENTATION, listener_orientation);
189
190 alSourcePlay(buffer->source_id);
191 if (CheckError())
192 __debugbreak();
193
194 if (wait)
195 {
196 do
197 {
198 alGetSourcei(buffer->source_id, AL_SOURCE_STATE, (int *)&status);
199 }
200 while (status == AL_PLAYING);
201 }
202 }
203 }
204
205
206
207
208 TrackBuffer *CreateTrack16(int num_channels, int sample_rate, int bytes_per_sample, int num_samples, const void *samples)
209 {
210 Assert(bytes_per_sample == 2, "OpenALSoundProvider: unsupported sample size: %u", bytes_per_sample);
211
212 ALenum sound_format;
213 switch (num_channels)
214 {
215 case 1: sound_format = AL_FORMAT_MONO16; break;
216 case 2: sound_format = AL_FORMAT_STEREO16; break;
217 default:
218 if (bool multichannel = alIsExtensionPresent("AL_EXT_MCFORMATS"))
219 {
220 switch (num_channels)
221 {
222 case 4: sound_format = alGetEnumValue("AL_FORMAT_QUAD16"); break;
223 case 6: sound_format = alGetEnumValue("AL_FORMAT_51CHN16"); break;
224 case 7: sound_format = alGetEnumValue("AL_FORMAT_61CHN16"); break;
225 case 8: sound_format = alGetEnumValue("AL_FORMAT_71CHN16"); break;
226 }
227 }
228 Error("Unsupported number of audio channels: %u", num_channels);
229 }
230
231 unsigned int al_source = -1;
232 alGenSources(1, &al_source);
233 if (CheckError())
234 return nullptr;
235
236 float sound_pos[] = {0.0f, 0.0f, 0.0f},
237 sound_vel[] = {0.0f, 0.0f, 0.0f};
238
239 alSourcei(al_source, AL_LOOPING, AL_FALSE);
240 alSourcef(al_source, AL_PITCH, 1.0f);
241 alSourcef(al_source, AL_GAIN, 1.0f);
242 alSourcefv(al_source, AL_POSITION, sound_pos);
243 alSourcefv(al_source, AL_VELOCITY, sound_vel);
244
245 unsigned int al_buffer = -1;
246 alGenBuffers(1, &al_buffer);
247 if (CheckError())
248 {
249 alDeleteSources(1, &al_source);
250 return nullptr;
251 }
252
253 alBufferData(al_buffer, sound_format, samples, num_samples * bytes_per_sample, sample_rate);
254 if (CheckError())
255 {
256 alDeleteSources(1, &al_source);
257 alDeleteBuffers(1, &al_buffer);
258 return nullptr;
259 }
260
261 alSourcei(al_source, AL_BUFFER, al_buffer);
262 if (CheckError())
263 {
264 alDeleteSources(1, &al_source);
265 alDeleteBuffers(1, &al_buffer);
266 return nullptr;
267 }
268
269 auto ret = new TrackBuffer;
270 ret->source_id = al_source;
271 ret->buffer_id = al_buffer;
272 return ret;
273 }
274
275
276 void PlayTrack16(TrackBuffer *buffer, bool loop = false, bool wait = false)
277 {
278 volatile int status;
279 alGetSourcei(buffer->source_id, AL_SOURCE_STATE, (int *)&status);
280 if (status == AL_PLAYING)
281 Error("Already playing");
282 else
283 {
284 float listener_pos[] = {0.0f, 0.0f, 0.0f};
285 float listener_vel[] = {0.0f, 0.0f, 0.0f};
286 float listener_orientation[] = {0.0f, 0.0f, -1.0f, // direction
287 0.0f, 1.0f, 0.0f}; // up vector
288 alListenerfv(AL_POSITION, listener_pos);
289 alListenerfv(AL_VELOCITY, listener_vel);
290 alListenerfv(AL_ORIENTATION, listener_orientation);
291
292 alSourcei(buffer->source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
293 alSourcePlay(buffer->source_id);
294 if (CheckError())
295 __debugbreak();
296
297 if (wait && !loop)
298 {
299 float track_length = alBufferLength(buffer->buffer_id);
300 do
301 {
302 float track_offset = 0;
303 alGetSourcef(buffer->source_id, AL_SEC_OFFSET, &track_offset);
304 log("playing: %.4f/%.4f\n", track_offset, track_length);
305
306 alGetSourcei(buffer->source_id, AL_SOURCE_STATE, (int *)&status);
307 }
308 while (status == AL_PLAYING);
309 }
310 }
311 }
312
313
314
315 protected:
316 ALCdevice *device;
317 ALCcontext *context;
318
319
320 bool CheckError()
321 {
322 ALenum code1 = alGetError();
323 if (code1 != AL_NO_ERROR)
324 {
325 DWORD w;
326 const char *message = alGetString(code1);
327 WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), message, lstrlenA(message), &w, nullptr);
328 WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), "\n", 1, &w, nullptr);
329 return true;
330 }
331
332 ALenum code2 = alcGetError(device);
333 if (code2 != ALC_NO_ERROR)
334 {
335 DWORD w;
336 const char *message = alcGetString(device, code2);
337 WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), message, lstrlenA(message), &w, nullptr);
338 WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), "\n", 1, &w, nullptr);
339 return true;
340 }
341 return false;
342 }
343 };