Rev 130 | Rev 171 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 130 | Rev 136 | ||
---|---|---|---|
Line 12... | Line 12... | ||
12 | 12 | ||
13 | 13 | ||
14 | // structures used in this module only |
14 | // structures used in this module only |
15 | typedef struct openal_buffer_s |
15 | typedef struct openal_buffer_s |
16 | { |
16 | { |
17 | wchar_t pathname |
17 | wchar_t *pathname; // sound pathname (mallocated, if NULL then slot is empty) |
18 | ALshort *openal_samples; // OpenAL samples (16-bit mono) |
18 | ALshort *openal_samples; // OpenAL samples (16-bit mono) |
19 | ALuint openal_buffer; // associated OpenAL buffer ID |
19 | ALuint openal_buffer; // associated OpenAL buffer ID |
- | 20 | struct openal_buffer_s *next; // pointer to the next element in list |
|
20 | } openal_buffer_t; |
21 | } openal_buffer_t; |
21 | 22 | ||
22 | 23 | ||
23 | typedef struct openal_source_s |
24 | typedef struct openal_source_s |
24 | { |
25 | { |
Line 28... | Line 29... | ||
28 | 29 | ||
29 | 30 | ||
30 | // global variables used in this module only |
31 | // global variables used in this module only |
31 | static ALCdevice *openal_device; |
32 | static ALCdevice *openal_device; |
32 | static ALCcontext *openal_context; |
33 | static ALCcontext *openal_context; |
33 | static openal_buffer_t *soundbuffers; // mallocated |
34 | static openal_buffer_t *soundbuffers; // mallocated linked list |
34 | static int soundbuffer_count; |
- | |
35 | static openal_source_t *sources; // mallocated |
35 | static openal_source_t *sources; // mallocated |
36 | static int source_count; |
36 | static int source_count; |
37 | 37 | ||
38 | bool Audio_Init (void) |
38 | bool Audio_Init (void) |
39 | { |
39 | { |
Line 49... | Line 49... | ||
49 | 49 | ||
50 | if (!alcMakeContextCurrent (openal_context)) // select this audio context |
50 | if (!alcMakeContextCurrent (openal_context)) // select this audio context |
51 | return (false); |
51 | return (false); |
52 | 52 | ||
53 | soundbuffers = NULL; // we know no soundbuffer yet |
53 | soundbuffers = NULL; // we know no soundbuffer yet |
54 | soundbuffer_count = 0; |
- | |
55 | 54 | ||
56 | sources = NULL; // we have no playing source yet |
55 | sources = NULL; // we have no playing source yet |
57 | source_count = 0; |
56 | source_count = 0; |
58 | 57 | ||
59 | return (true); // audio subsystem successfully initialized |
58 | return (true); // audio subsystem successfully initialized |
Line 62... | Line 61... | ||
62 | 61 | ||
63 | void Audio_Shutdown (void) |
62 | void Audio_Shutdown (void) |
64 | { |
63 | { |
65 | // this function shuts down the audio subsystem |
64 | // this function shuts down the audio subsystem |
66 | 65 | ||
- | 66 | openal_buffer_t *soundbuffer; |
|
- | 67 | openal_buffer_t *oldbuffer; |
|
67 | int array_index; |
68 | int array_index; |
68 | ALint status; |
69 | ALint status; |
69 | 70 | ||
70 | // cycle through all sound sources, stop them if needed and delete them |
71 | // cycle through all sound sources, stop them if needed and delete them |
71 | for (array_index = 0; array_index < source_count; array_index++) |
72 | for (array_index = 0; array_index < source_count; array_index++) |
Line 79... | Line 80... | ||
79 | alDeleteSources (1, &sources[array_index].openal_source); // and tell OpenAL to dispose of it |
80 | alDeleteSources (1, &sources[array_index].openal_source); // and tell OpenAL to dispose of it |
80 | sources[array_index].is_used = false; // mark this source as unused now |
81 | sources[array_index].is_used = false; // mark this source as unused now |
81 | } |
82 | } |
82 | 83 | ||
83 | // cycle through all known sound buffers and delete them |
84 | // cycle through all known sound buffers and delete them |
84 |
|
85 | soundbuffer = soundbuffers; |
- | 86 | while (soundbuffer != NULL) |
|
85 | { |
87 | { |
86 | alDeleteBuffers (1, & |
88 | alDeleteBuffers (1, &soundbuffer->openal_buffer); // tell OpenAL to dispose of this buffer |
87 | SAFE_free ((void **) & |
89 | SAFE_free ((void **) &soundbuffer->openal_samples); // free the buffer by our side |
88 |
|
90 | SAFE_free ((void **) &soundbuffer->pathname); // remember this buffer is now empty |
- | 91 | ||
- | 92 | oldbuffer = soundbuffer; // save a pointer to the element we just processed |
|
- | 93 | soundbuffer = soundbuffer->next; // proceed to the next element in the linked list |
|
- | 94 | SAFE_free ((void **) &oldbuffer); // and free the element we just processed |
|
89 | } |
95 | } |
- | 96 | soundbuffers = NULL; // at this point, all elements in the linked list are free |
|
90 | 97 | ||
91 | alcMakeContextCurrent (NULL); // unselect the audio context |
98 | alcMakeContextCurrent (NULL); // unselect the audio context |
92 | alcDestroyContext (openal_context); // destroy it (only after it's been unselected!) |
99 | alcDestroyContext (openal_context); // destroy it (only after it's been unselected!) |
93 | alcCloseDevice (openal_device); // and close the audio device |
100 | alcCloseDevice (openal_device); // and close the audio device |
94 | 101 | ||
Line 160... | Line 167... | ||
160 | void Audio_PlaySound (int sound_type, float pos_x, float pos_y, float pos_z) |
167 | void Audio_PlaySound (int sound_type, float pos_x, float pos_y, float pos_z) |
161 | { |
168 | { |
162 | // helper function to play a sound |
169 | // helper function to play a sound |
163 | 170 | ||
164 | static wchar_t soundfile_path[MAX_PATH]; |
171 | static wchar_t soundfile_path[MAX_PATH]; |
165 |
|
172 | openal_buffer_t *soundbuffer; |
166 | buffer_t soundfile; |
173 | buffer_t soundfile; |
167 | unsigned long current_pos; |
174 | unsigned long current_pos; |
168 | uint16_t temp16; |
175 | uint16_t temp16; |
169 | uint32_t temp32; |
176 | uint32_t temp32; |
170 | uint32_t blksiz; |
177 | uint32_t blksiz; |
Line 207... | Line 214... | ||
207 | swprintf_s(soundfile_path, WCHAR_SIZEOF(soundfile_path), L"%s/themes/%s/sounds/slide.wav", app_path, theme->name); |
214 | swprintf_s(soundfile_path, WCHAR_SIZEOF(soundfile_path), L"%s/themes/%s/sounds/slide.wav", app_path, theme->name); |
208 | pitch = 1.0f + ((((float)rand()) / RAND_MAX) - 0.5f) / 2.0f; // set a random pitch for these sounds between 0.75 and 1.25 |
215 | pitch = 1.0f + ((((float)rand()) / RAND_MAX) - 0.5f) / 2.0f; // set a random pitch for these sounds between 0.75 and 1.25 |
209 | } |
216 | } |
210 | 217 | ||
211 | // now cycle through our known OpenAL buffers and see if we already know this one |
218 | // now cycle through our known OpenAL buffers and see if we already know this one |
212 | for ( |
219 | for (soundbuffer = soundbuffers; soundbuffer != NULL; soundbuffer = soundbuffer->next) |
213 | if ( |
220 | if ((soundbuffer->pathname != NULL) && (wcscmp (soundbuffer->pathname, soundfile_path) == 0)) |
214 | break; // break as soon as we find it |
221 | break; // break as soon as we find it |
215 | 222 | ||
216 | // have we NOT found it ? if so, we must create it |
223 | // have we NOT found it ? if so, we must create it |
217 | if ( |
224 | if (soundbuffer == NULL) |
218 | { |
225 | { |
219 | // load the sound file |
226 | // load the sound file |
220 | Buffer_Initialize (&soundfile); |
227 | Buffer_Initialize (&soundfile); |
221 | if (!Buffer_ReadFromFileW (&soundfile, soundfile_path)) |
228 | if (!Buffer_ReadFromFileW (&soundfile, soundfile_path)) |
222 | return; // if unable to load this sound file, give up (FIXME: log something ?) |
229 | return; // if unable to load this sound file, give up (FIXME: log something ?) |
Line 267... | Line 274... | ||
267 | return; // FIXME: not a wav file |
274 | return; // FIXME: not a wav file |
268 | 275 | ||
269 | // compute the total number of samples (number of channels * number of frames) |
276 | // compute the total number of samples (number of channels * number of frames) |
270 | sample_count /= sample_size; |
277 | sample_count /= sample_size; |
271 | 278 | ||
272 | // |
279 | // allocate space for one more sound buffer, and tie it to the linked list |
- | 280 | if (soundbuffers == NULL) |
|
- | 281 | { |
|
273 | soundbuffers = (openal_buffer_t *) |
282 | soundbuffers = (openal_buffer_t *) SAFE_malloc (1, sizeof (openal_buffer_t), false); // allocate a new slot to initialize the linked list |
- | 283 | soundbuffer = soundbuffers; // and set the pointer to the beginning of the list |
|
- | 284 | } |
|
- | 285 | else |
|
- | 286 | { |
|
274 |
|
287 | for (soundbuffer = soundbuffers; soundbuffer->next != NULL; soundbuffer = soundbuffer->next); // locate the last slot in the linked list |
- | 288 | soundbuffer->next = (openal_buffer_t *) SAFE_malloc (1, sizeof (openal_buffer_t), false); // allocate a new slot and tie it there at the same time |
|
- | 289 | soundbuffer = soundbuffer->next; // and update the pointer to it |
|
- | 290 | } |
|
- | 291 | soundbuffer->next = NULL; // this is the last sound buffer in the linked list, do remember it. |
|
- | 292 | ||
- | 293 | temp32 = wcslen (soundfile_path) + 1; // compute pathname buffer length (including null terminator) |
|
- | 294 | soundbuffer->pathname = (wchar_t *) SAFE_malloc (temp32, sizeof (wchar_t), false); // allocate space for it |
|
- | 295 | wcscpy_s (soundbuffer->pathname, temp32, soundfile_path); // and copy this sound's pathname in the newly allocated buffer |
|
275 | 296 | ||
276 | // allocate the samples buffer and fill it, mixing all the WAV channels altogether in a 16-bit mono stream |
297 | // allocate the samples buffer and fill it, mixing all the WAV channels altogether in a 16-bit mono stream |
277 |
|
298 | soundbuffer->openal_samples = (ALshort *) SAFE_malloc (sample_count, sizeof (ALshort), false); |
278 | for (sample_index = 0; sample_index < sample_count; sample_index++) |
299 | for (sample_index = 0; sample_index < sample_count; sample_index++) |
279 | { |
300 | { |
280 | sample_value = 0; |
301 | sample_value = 0; |
281 | if (channel_size == 1) |
302 | if (channel_size == 1) |
282 | for (channel_index = 0; channel_index < channel_count; channel_index++) |
303 | for (channel_index = 0; channel_index < channel_count; channel_index++) |
283 | sample_value += *((int8_t *) soundfile.data[current_pos + sample_index * sample_size + channel_index * channel_size]); |
304 | sample_value += *((int8_t *) soundfile.data[current_pos + sample_index * sample_size + channel_index * channel_size]); |
284 | else if (channel_size == 2) |
305 | else if (channel_size == 2) |
285 | for (channel_index = 0; channel_index < channel_count; channel_index++) |
306 | for (channel_index = 0; channel_index < channel_count; channel_index++) |
286 | sample_value += *((int16_t *) &soundfile.data[current_pos + sample_index * sample_size + channel_index * channel_size]); |
307 | sample_value += *((int16_t *) &soundfile.data[current_pos + sample_index * sample_size + channel_index * channel_size]); |
287 | sample_value /= channel_count; |
308 | sample_value /= channel_count; |
288 |
|
309 | soundbuffer->openal_samples[sample_index] = (ALshort) sample_value; |
289 | } |
310 | } |
290 | 311 | ||
291 | Buffer_Forget (&soundfile); // we can now forget this sound file |
312 | Buffer_Forget (&soundfile); // we can now forget this sound file |
292 | 313 | ||
293 | alGenBuffers (1, & |
314 | alGenBuffers (1, &soundbuffer->openal_buffer); // create an OpenAL sound buffer and fill it with our samples |
294 | alBufferData ( |
315 | alBufferData (soundbuffer->openal_buffer, AL_FORMAT_MONO16, soundbuffer->openal_samples, sample_count * sizeof (ALushort), (ALsizei) sample_rate); |
295 | if (alGetError () != AL_NO_ERROR) |
316 | if (alGetError () != AL_NO_ERROR) |
296 | return; // FIXME: couldn't fill OpenAL buffer |
317 | return; // FIXME: couldn't fill OpenAL buffer |
297 | - | ||
298 | soundbuffer_count++; // one more sound buffer has been created |
- | |
299 | } |
318 | } |
300 | 319 | ||
301 | // now we have a buffer to play |
320 | // now we have a buffer to play |
302 | 321 | ||
303 | // cycle through our known OpenAL sources and find a free one |
322 | // cycle through our known OpenAL sources and find a free one |
Line 320... | Line 339... | ||
320 | alSourcef (sources[source_index].openal_source, AL_PITCH, (ALfloat) pitch); // set the source's pitch |
339 | alSourcef (sources[source_index].openal_source, AL_PITCH, (ALfloat) pitch); // set the source's pitch |
321 | alSourcef (sources[source_index].openal_source, AL_GAIN, 1.0f); // set the source's volume (full) |
340 | alSourcef (sources[source_index].openal_source, AL_GAIN, 1.0f); // set the source's volume (full) |
322 | alSource3f (sources[source_index].openal_source, AL_POSITION, (ALfloat) pos_x * ATTENUATION_FACTOR, (ALfloat) pos_y * ATTENUATION_FACTOR, (ALfloat) pos_z * ATTENUATION_FACTOR); |
341 | alSource3f (sources[source_index].openal_source, AL_POSITION, (ALfloat) pos_x * ATTENUATION_FACTOR, (ALfloat) pos_y * ATTENUATION_FACTOR, (ALfloat) pos_z * ATTENUATION_FACTOR); |
323 | alSource3f (sources[source_index].openal_source, AL_VELOCITY, 0, 0, 0); // set the source's velocity (static) |
342 | alSource3f (sources[source_index].openal_source, AL_VELOCITY, 0, 0, 0); // set the source's velocity (static) |
324 | alSourcei (sources[source_index].openal_source, AL_LOOPING, AL_FALSE); // set it as non-looping |
343 | alSourcei (sources[source_index].openal_source, AL_LOOPING, AL_FALSE); // set it as non-looping |
325 | alSourcei (sources[source_index].openal_source, AL_BUFFER, |
344 | alSourcei (sources[source_index].openal_source, AL_BUFFER, soundbuffer->openal_buffer); // attach our bufferized data to it |
326 | 345 | ||
327 | // play the source! Audio_Think() will dispose of it when it's finished |
346 | // play the source! Audio_Think() will dispose of it when it's finished |
328 | alSourcePlay (sources[source_index].openal_source); |
347 | alSourcePlay (sources[source_index].openal_source); |
329 | 348 | ||
330 | return; // finished |
349 | return; // finished |