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