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