Mercurial > mm7
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 }; |