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 |