1 /* |
|
2 * OpenAL Bridge - a simple portable library for OpenAL interface |
|
3 * Copyright (c) 2009 Vittorio Giovara <vittorio.giovara@gmail.com> |
|
4 * |
|
5 * This program is free software; you can redistribute it and/or modify |
|
6 * it under the terms of the GNU Lesser General Public License as published by |
|
7 * the Free Software Foundation; version 2 of the License |
|
8 * |
|
9 * This program is distributed in the hope that it will be useful, |
|
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 * GNU Lesser General Public License for more details. |
|
13 * |
|
14 * You should have received a copy of the GNU Lesser General Public License |
|
15 * along with this program; if not, write to the Free Software |
|
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
|
17 */ |
|
18 |
|
19 #include "openalbridge.h" |
|
20 #include "globals.h" |
|
21 #include "al.h" |
|
22 #include "alc.h" |
|
23 #include "wrappers.h" |
|
24 #include "loaders.h" |
|
25 |
|
26 |
|
27 /*Sources are points emitting sound*/ |
|
28 ALuint *Sources; |
|
29 /*Buffers hold sound data*/ |
|
30 ALuint *Buffers; |
|
31 /*index for Sources and Buffers*/ |
|
32 ALuint globalindex, globalsize, increment; |
|
33 |
|
34 ALboolean isBridgeReady = AL_FALSE; |
|
35 ALfloat old_gain; |
|
36 |
|
37 int openal_init (int memorysize) { |
|
38 /*Initialize an OpenAL contex and allocate memory space for data and buffers*/ |
|
39 ALCcontext *context; |
|
40 ALCdevice *device; |
|
41 |
|
42 // set the memory dimentsion and the increment width when reallocating |
|
43 if (memorysize <= 0) |
|
44 globalsize = 50; |
|
45 else |
|
46 globalsize = memorysize; |
|
47 increment = globalsize; |
|
48 |
|
49 // reuse old context but keep the new value for increment |
|
50 if (isBridgeReady == AL_TRUE) { |
|
51 fprintf(stderr,"(Bridge Warning) - already initialized"); |
|
52 return 0; |
|
53 } |
|
54 |
|
55 // open hardware device if present |
|
56 device = alcOpenDevice(NULL); |
|
57 |
|
58 if (device == NULL) { |
|
59 fprintf(stderr,"(Bridge Warning) - failed to open sound device, using software renderer"); |
|
60 device = alcOpenDevice("Generic Software"); |
|
61 if (device == NULL) { |
|
62 fprintf(stderr,"(Bridge Error) - failed to open sound software device, sound will be disabled"); |
|
63 return -1; |
|
64 } |
|
65 } |
|
66 |
|
67 fprintf(stderr,"(Bridge Info) - Output device: %s", alcGetString(device, ALC_DEVICE_SPECIFIER)); |
|
68 |
|
69 context = alcCreateContext(device, NULL); |
|
70 alcMakeContextCurrent(context); |
|
71 alcProcessContext(context); |
|
72 |
|
73 if (AL_NO_ERROR != alGetError()) { |
|
74 fprintf(stderr,"(Bridge Error) - Failed to create a new contex"); |
|
75 alcMakeContextCurrent(NULL); |
|
76 alcDestroyContext(context); |
|
77 alcCloseDevice(device); |
|
78 return -2; |
|
79 } |
|
80 |
|
81 // allocate memory space for buffers and sources |
|
82 Buffers = (ALuint*) Malloc(sizeof(ALuint)*globalsize); |
|
83 Sources = (ALuint*) Malloc(sizeof(ALuint)*globalsize); |
|
84 |
|
85 // set the listener gain, position (on xyz axes), velocity (one value for each axe) and orientation |
|
86 // Position, Velocity and Orientation of the listener |
|
87 ALfloat ListenerPos[] = {0.0, 0.0, 0.0}; |
|
88 ALfloat ListenerVel[] = {0.0, 0.0, 0.0}; |
|
89 ALfloat ListenerOri[] = {0.0, 0.0, -1.0, 0.0, 1.0, 0.0}; |
|
90 |
|
91 alListenerf (AL_GAIN, 1.0f ); |
|
92 alListenerfv(AL_POSITION, ListenerPos); |
|
93 alListenerfv(AL_VELOCITY, ListenerVel); |
|
94 alListenerfv(AL_ORIENTATION, ListenerOri); |
|
95 |
|
96 if (AL_NO_ERROR != alGetError()) { |
|
97 fprintf(stderr,"(Bridge Error) - Failed to set Listener properties"); |
|
98 return -3; |
|
99 } |
|
100 isBridgeReady = AL_TRUE; |
|
101 |
|
102 alGetError(); // clear any AL errors beforehand |
|
103 return AL_TRUE; |
|
104 } |
|
105 |
|
106 void openal_close (void) { |
|
107 /*Stop all sounds, deallocate all memory and close OpenAL */ |
|
108 ALCcontext *context; |
|
109 ALCdevice *device; |
|
110 |
|
111 if (isBridgeReady == AL_FALSE) { |
|
112 fprintf(stderr,"(Bridge Warning) - OpenAL not initialized"); |
|
113 return; |
|
114 } |
|
115 |
|
116 alSourceStopv (globalsize, Sources); |
|
117 alDeleteSources (globalsize, Sources); |
|
118 alDeleteBuffers (globalsize, Buffers); |
|
119 |
|
120 free(Sources); |
|
121 free(Buffers); |
|
122 |
|
123 context = alcGetCurrentContext(); |
|
124 device = alcGetContextsDevice(context); |
|
125 |
|
126 alcMakeContextCurrent(NULL); |
|
127 alcDestroyContext(context); |
|
128 alcCloseDevice(device); |
|
129 |
|
130 isBridgeReady = AL_FALSE; |
|
131 |
|
132 fprintf(stderr,"(Bridge Info) - closed"); |
|
133 |
|
134 return; |
|
135 } |
|
136 |
|
137 ALboolean openal_ready (void) { |
|
138 return isBridgeReady; |
|
139 } |
|
140 |
|
141 |
|
142 void helper_realloc (void) { |
|
143 /*expands allocated memory when loading more sound files than expected*/ |
|
144 int oldsize = globalsize; |
|
145 globalsize += increment; |
|
146 |
|
147 fprintf(stderr,"(Bridge Info) - Realloc in process from %d to %d\n", oldsize, globalsize); |
|
148 |
|
149 Buffers = (ALuint*) Realloc(Buffers, sizeof(ALuint)*globalsize); |
|
150 Sources = (ALuint*) Realloc(Sources, sizeof(ALuint)*globalsize); |
|
151 |
|
152 return; |
|
153 } |
|
154 |
|
155 |
|
156 int openal_loadfile (const char *filename){ |
|
157 /*Open a file, load into memory and allocate the Source buffer for playing*/ |
|
158 ALfloat SourcePos[] = { 0.0, 0.0, 0.0 }; /*Position of the source sound*/ |
|
159 ALfloat SourceVel[] = { 0.0, 0.0, 0.0 }; /*Velocity of the source sound*/ |
|
160 ALenum format; |
|
161 ALsizei bitsize, freq; |
|
162 char *data; |
|
163 uint32_t fileformat; |
|
164 ALenum error; |
|
165 FILE *fp; |
|
166 |
|
167 if (isBridgeReady == AL_FALSE) { |
|
168 fprintf(stderr,"(Bridge Warning) - not initialized"); |
|
169 return -1; |
|
170 } |
|
171 |
|
172 /*when the buffers are all used, we can expand memory to accept new files*/ |
|
173 if (globalindex == globalsize) |
|
174 helper_realloc(); |
|
175 |
|
176 /*detect the file format, as written in the first 4 bytes of the header*/ |
|
177 fp = Fopen (filename, "rb"); |
|
178 |
|
179 if (fp == NULL) |
|
180 return -2; |
|
181 |
|
182 error = fread (&fileformat, sizeof(uint32_t), 1, fp); |
|
183 fclose (fp); |
|
184 |
|
185 if (error < 0) { |
|
186 fprintf(stderr,"(Bridge Error) - File %s is too short", filename); |
|
187 return -3; |
|
188 } |
|
189 |
|
190 /*prepare the buffer to receive data*/ |
|
191 alGenBuffers(1, &Buffers[globalindex]); |
|
192 |
|
193 if (AL_NO_ERROR != alGetError()) { |
|
194 fprintf(stderr,"(Bridge Error) - Failed to allocate memory for buffers"); |
|
195 return -4; |
|
196 } |
|
197 |
|
198 /*prepare the source to emit sound*/ |
|
199 alGenSources(1, &Sources[globalindex]); |
|
200 |
|
201 if (AL_NO_ERROR != alGetError()) { |
|
202 fprintf(stderr,"(Bridge Error) - Failed to allocate memory for sources"); |
|
203 return -5; |
|
204 } |
|
205 |
|
206 switch (ENDIAN_BIG_32(fileformat)) { |
|
207 case OGG_FILE_FORMAT: |
|
208 error = load_oggvorbis (filename, &format, &data, &bitsize, &freq); |
|
209 break; |
|
210 case WAV_FILE_FORMAT: |
|
211 error = load_wavpcm (filename, &format, &data, &bitsize, &freq); |
|
212 break; |
|
213 default: |
|
214 fprintf(stderr,"(Bridge Error) - File format (%08X) not supported", ENDIAN_BIG_32(fileformat)); |
|
215 return -6; |
|
216 break; |
|
217 } |
|
218 |
|
219 if (error != 0) { |
|
220 fprintf(stderr,"(Bridge Error) - error loading file %s", filename); |
|
221 free(data); |
|
222 return -7; |
|
223 } |
|
224 |
|
225 //copy pcm data in one buffer and free it |
|
226 alBufferData(Buffers[globalindex], format, data, bitsize, freq); |
|
227 free(data); |
|
228 |
|
229 if (AL_NO_ERROR != alGetError()) { |
|
230 fprintf(stderr,"(Bridge Error) - Failed to write data to buffers"); |
|
231 return -8; |
|
232 } |
|
233 |
|
234 /*set source properties that it will use when it's in playback*/ |
|
235 alSourcei (Sources[globalindex], AL_BUFFER, Buffers[globalindex] ); |
|
236 alSourcef (Sources[globalindex], AL_PITCH, 1.0f ); |
|
237 alSourcef (Sources[globalindex], AL_GAIN, 1.0f ); |
|
238 alSourcefv(Sources[globalindex], AL_POSITION, SourcePos ); |
|
239 alSourcefv(Sources[globalindex], AL_VELOCITY, SourceVel ); |
|
240 alSourcei (Sources[globalindex], AL_LOOPING, 0 ); |
|
241 |
|
242 if (AL_NO_ERROR != alGetError()) { |
|
243 fprintf(stderr,"(Bridge Error) - Failed to set Source properties"); |
|
244 return -9; |
|
245 } |
|
246 |
|
247 alGetError(); /* clear any AL errors beforehand */ |
|
248 |
|
249 /*returns the index of the source you just loaded, increments it and exits*/ |
|
250 return globalindex++; |
|
251 } |
|
252 |
|
253 |
|
254 void openal_playsound (uint32_t index) { |
|
255 openal_playsound_loop (index, 0); |
|
256 } |
|
257 |
|
258 |
|
259 void openal_pausesound (uint32_t index) { |
|
260 if (isBridgeReady == AL_TRUE && index < globalsize) |
|
261 alSourcePause(Sources[index]); |
|
262 } |
|
263 |
|
264 |
|
265 void openal_stopsound (uint32_t index) { |
|
266 openal_stopsound_free(index, 0); |
|
267 } |
|
268 |
|
269 |
|
270 void openal_freesound (uint32_t index){ |
|
271 if (isBridgeReady == AL_TRUE && index < globalsize) |
|
272 alSourceStop(Sources[index]); |
|
273 // STUB |
|
274 } |
|
275 |
|
276 |
|
277 void openal_playsound_loop (unsigned int index, char loops) { |
|
278 if (isBridgeReady == AL_TRUE && index < globalsize) { |
|
279 alSourcePlay(Sources[index]); |
|
280 if (loops != 0) |
|
281 openal_toggleloop(index); |
|
282 } |
|
283 } |
|
284 |
|
285 void openal_stopsound_free (unsigned int index, char freesource) { |
|
286 if (isBridgeReady == AL_TRUE && index < globalsize) { |
|
287 alSourceStop(Sources[index]); |
|
288 if (freesource != 0) |
|
289 openal_freesound(index); |
|
290 } |
|
291 } |
|
292 |
|
293 void openal_toggleloop (uint32_t index) { |
|
294 ALint loop; |
|
295 |
|
296 if (isBridgeReady == AL_TRUE && index < globalsize) { |
|
297 alGetSourcei (Sources[index], AL_LOOPING, &loop); |
|
298 alSourcei (Sources[index], AL_LOOPING, !((uint8_t) loop) & 0x00000001); |
|
299 } |
|
300 |
|
301 } |
|
302 |
|
303 |
|
304 void openal_setvolume (uint32_t index, float gain) { |
|
305 if (isBridgeReady == AL_TRUE && index < globalsize) |
|
306 alSourcef (Sources[index], AL_GAIN, gain); |
|
307 } |
|
308 |
|
309 |
|
310 void openal_setglobalvolume (float gain) { |
|
311 if (isBridgeReady == AL_TRUE) |
|
312 alListenerf (AL_GAIN, gain); |
|
313 } |
|
314 |
|
315 void openal_togglemute () { |
|
316 ALfloat gain; |
|
317 |
|
318 if (isBridgeReady == AL_TRUE) { |
|
319 alGetListenerf (AL_GAIN, &gain); |
|
320 if (gain > 0) { |
|
321 old_gain = gain; |
|
322 gain = 0; |
|
323 } else |
|
324 gain = old_gain; |
|
325 |
|
326 alListenerf (AL_GAIN, gain); |
|
327 } |
|
328 } |
|
329 |
|
330 // Fade in or out by calling a helper thread |
|
331 void openal_fade (uint32_t index, uint16_t quantity, al_fade_t direction) { |
|
332 #ifndef _WIN32 |
|
333 pthread_t thread; |
|
334 #else |
|
335 HANDLE Thread; |
|
336 #endif |
|
337 fade_t *fade; |
|
338 |
|
339 if (isBridgeReady == AL_TRUE && index < globalsize) { |
|
340 fade = (fade_t*) Malloc(sizeof(fade_t)); |
|
341 fade->index = index; |
|
342 fade->quantity = quantity; |
|
343 fade->type = direction; |
|
344 |
|
345 #ifndef _WIN32 |
|
346 pthread_create(&thread, NULL, (void *)helper_fade, (void *)fade); |
|
347 pthread_detach(thread); |
|
348 #else |
|
349 Thread = (HANDLE) _beginthread((void *)helper_fade, 0, (void *)fade); |
|
350 #endif |
|
351 } |
|
352 } |
|
353 |
|
354 void openal_fadein (uint32_t index, uint16_t quantity) { |
|
355 openal_fade(index, quantity, AL_FADE_IN); |
|
356 } |
|
357 |
|
358 void openal_fadeout (uint32_t index, uint16_t quantity) { |
|
359 openal_fade(index, quantity, AL_FADE_OUT); |
|
360 } |
|
361 |
|
362 |
|
363 void openal_setposition (uint32_t index, float x, float y, float z) { |
|
364 if (isBridgeReady == AL_TRUE && index < globalsize) |
|
365 alSource3f(Sources[index], AL_POSITION, x, y, z);; |
|
366 } |
|