Rev 171 | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 1 | pmbaty | 1 | // audio.cpp | 
| 2 | |||
| 3 | #include "common.h" | ||
| 4 | |||
| 116 | pmbaty | 5 | // OpenAL includes | 
| 6 | #include "openal/al.h" | ||
| 7 | #include "openal/alc.h" | ||
| 1 | pmbaty | 8 | |
| 116 | pmbaty | 9 | |
| 10 | // attenuation factor (lower means sounds fade LESS with distance, higher means sounds fade MORE with distance) | ||
| 11 | #define ATTENUATION_FACTOR 0.02f | ||
| 12 | |||
| 13 | |||
| 14 | // structures used in this module only | ||
| 171 | pmbaty | 15 | typedef struct enqueued_sound_s | 
| 16 | { | ||
| 17 | int type; | ||
| 18 | float emitterlocation_x; | ||
| 19 | float emitterlocation_y; | ||
| 20 | float emitterlocation_z; | ||
| 21 | } enqueued_sound_t; | ||
| 22 | |||
| 23 | |||
| 116 | pmbaty | 24 | typedef struct openal_buffer_s | 
| 25 | { | ||
| 136 | pmbaty | 26 | wchar_t *pathname; // sound pathname (mallocated, if NULL then slot is empty) | 
| 116 | pmbaty | 27 | ALshort *openal_samples; // OpenAL samples (16-bit mono) | 
| 28 | ALuint openal_buffer; // associated OpenAL buffer ID | ||
| 136 | pmbaty | 29 | struct openal_buffer_s *next; // pointer to the next element in list | 
| 116 | pmbaty | 30 | } openal_buffer_t; | 
| 31 | |||
| 32 | |||
| 33 | typedef struct openal_source_s | ||
| 34 | { | ||
| 35 | bool is_used; // set to TRUE if this source is used | ||
| 36 | ALuint openal_source; // OpenAL sound source | ||
| 37 | } openal_source_t; | ||
| 38 | |||
| 39 | |||
| 1 | pmbaty | 40 | // global variables used in this module only | 
| 116 | pmbaty | 41 | static ALCdevice *openal_device; | 
| 42 | static ALCcontext *openal_context; | ||
| 136 | pmbaty | 43 | static openal_buffer_t *soundbuffers; // mallocated linked list | 
| 116 | pmbaty | 44 | static openal_source_t *sources; // mallocated | 
| 181 | pmbaty | 45 | static enqueued_sound_t enqueued_sounds[8]; | 
| 46 | static int enqueued_sound_count = 0; | ||
| 116 | pmbaty | 47 | static int source_count; | 
| 1 | pmbaty | 48 | |
| 171 | pmbaty | 49 | |
| 116 | pmbaty | 50 | bool Audio_Init (void) | 
| 51 | { | ||
| 52 |    // this function initializes the audio subsystem (OpenAL) | ||
| 1 | pmbaty | 53 | |
| 116 | pmbaty | 54 | openal_device = alcOpenDevice (NULL); // open audio device | 
| 55 | if (openal_device == NULL) | ||
| 56 | return (false); | ||
| 57 | |||
| 58 | openal_context = alcCreateContext (openal_device, NULL); // create audio context | ||
| 59 | if (openal_context == NULL) | ||
| 60 | return (false); | ||
| 61 | |||
| 62 | if (!alcMakeContextCurrent (openal_context)) // select this audio context | ||
| 63 | return (false); | ||
| 64 | |||
| 65 | soundbuffers = NULL; // we know no soundbuffer yet | ||
| 66 | |||
| 67 | sources = NULL; // we have no playing source yet | ||
| 68 | source_count = 0; | ||
| 69 | |||
| 181 | pmbaty | 70 | memset (enqueued_sounds, 0, sizeof (enqueued_sounds)); | 
| 71 | enqueued_sound_count = 0; // no sound is enqueued yet | ||
| 171 | pmbaty | 72 | |
| 116 | pmbaty | 73 | return (true); // audio subsystem successfully initialized | 
| 74 | } | ||
| 75 | |||
| 76 | |||
| 77 | void Audio_Shutdown (void) | ||
| 78 | { | ||
| 79 |    // this function shuts down the audio subsystem | ||
| 80 | |||
| 136 | pmbaty | 81 | openal_buffer_t *soundbuffer; | 
| 82 | openal_buffer_t *oldbuffer; | ||
| 116 | pmbaty | 83 | int array_index; | 
| 84 |    ALint status; | ||
| 85 | |||
| 86 |    // cycle through all sound sources, stop them if needed and delete them | ||
| 87 | for (array_index = 0; array_index < source_count; array_index++) | ||
| 88 |    { | ||
| 89 | if (!sources[array_index].is_used) | ||
| 90 | continue; // skip unused sources | ||
| 91 | alGetSourcei (sources[array_index].openal_source, AL_SOURCE_STATE, &status); // get this source's playing state | ||
| 92 | if (status == AL_PLAYING) | ||
| 93 | alSourceStop (sources[array_index].openal_source); // stop all playing sources | ||
| 94 | alSourcei (sources[array_index].openal_source, AL_BUFFER, NULL); // untie the buffer from this source | ||
| 95 | alDeleteSources (1, &sources[array_index].openal_source); // and tell OpenAL to dispose of it | ||
| 96 | sources[array_index].is_used = false; // mark this source as unused now | ||
| 97 |    } | ||
| 98 | |||
| 99 |    // cycle through all known sound buffers and delete them | ||
| 136 | pmbaty | 100 | soundbuffer = soundbuffers; | 
| 101 | while (soundbuffer != NULL) | ||
| 116 | pmbaty | 102 |    { | 
| 136 | pmbaty | 103 | alDeleteBuffers (1, &soundbuffer->openal_buffer); // tell OpenAL to dispose of this buffer | 
| 104 | SAFE_free ((void **) &soundbuffer->openal_samples); // free the buffer by our side | ||
| 105 | SAFE_free ((void **) &soundbuffer->pathname); // remember this buffer is now empty | ||
| 106 | |||
| 107 | oldbuffer = soundbuffer; // save a pointer to the element we just processed | ||
| 108 | soundbuffer = soundbuffer->next; // proceed to the next element in the linked list | ||
| 109 | SAFE_free ((void **) &oldbuffer); // and free the element we just processed | ||
| 116 | pmbaty | 110 |    } | 
| 136 | pmbaty | 111 | soundbuffers = NULL; // at this point, all elements in the linked list are free | 
| 116 | pmbaty | 112 | |
| 113 | alcMakeContextCurrent (NULL); // unselect the audio context | ||
| 114 | alcDestroyContext (openal_context); // destroy it (only after it's been unselected!) | ||
| 115 | alcCloseDevice (openal_device); // and close the audio device | ||
| 116 | |||
| 117 | return; // finished, audio subsystem has been shutdown | ||
| 118 | } | ||
| 119 | |||
| 120 | |||
| 1 | pmbaty | 121 | void Audio_Think (void) | 
| 122 | { | ||
| 171 | pmbaty | 123 |    // this function enqueues sounds, plays them and disposes of sound buffers and sources that have finished playing | 
| 1 | pmbaty | 124 | |
| 171 | pmbaty | 125 | static wchar_t soundfile_path[MAX_PATH]; | 
| 126 | |||
| 181 | pmbaty | 127 | enqueued_sound_t *processed_sound; | 
| 171 | pmbaty | 128 | openal_buffer_t *soundbuffer; | 
| 129 | ALfloat camera_position[3]; | ||
| 130 | ALfloat forward_and_up[6]; | ||
| 131 | unsigned long current_pos; | ||
| 132 |    buffer_t soundfile; | ||
| 133 | int sample_value; | ||
| 134 | int sample_count; | ||
| 135 | int sample_index; | ||
| 136 | int sample_size; | ||
| 137 | int sample_rate; | ||
| 138 | int channel_count; | ||
| 139 | int channel_index; | ||
| 140 | int channel_size; | ||
| 116 | pmbaty | 141 | int source_index; | 
| 181 | pmbaty | 142 | int sound_index; | 
| 171 | pmbaty | 143 | uint32_t chunk_id; | 
| 144 | uint32_t blksiz; | ||
| 145 | uint32_t temp32; | ||
| 146 | uint16_t temp16; | ||
| 116 | pmbaty | 147 |    ALint status; | 
| 148 | float angle; | ||
| 149 | float sin_pitch; | ||
| 150 | float sin_yaw; | ||
| 151 | float cos_pitch; | ||
| 152 | float cos_yaw; | ||
| 171 | pmbaty | 153 | float pitch; | 
| 1 | pmbaty | 154 | |
| 116 | pmbaty | 155 |    // compute the sine and cosine of the pitch component | 
| 156 | angle = current_pitch * TO_RADIANS; | ||
| 157 | sin_pitch = sinf (angle); | ||
| 158 | cos_pitch = cosf (angle); | ||
| 159 | |||
| 160 |    // compute the sine and cosine of the yaw component | ||
| 161 | angle = current_yaw * TO_RADIANS; | ||
| 162 | sin_yaw = sinf (angle); | ||
| 163 | cos_yaw = cosf (angle); | ||
| 164 | |||
| 165 |    // build the camera position | ||
| 166 | camera_position[0] = (ALfloat) -(cos_pitch * cos_yaw) * current_distance * ATTENUATION_FACTOR; | ||
| 167 | camera_position[1] = (ALfloat) -(cos_pitch * sin_yaw) * current_distance * ATTENUATION_FACTOR; | ||
| 168 | camera_position[2] = (ALfloat) sin_pitch * current_distance * ATTENUATION_FACTOR; | ||
| 169 | |||
| 170 |    // build the camera orientation | ||
| 171 | forward_and_up[0] = -camera_position[0]; // forward direction is the opposite of camera position, since the camera is looking at the center of the scene | ||
| 172 | forward_and_up[1] = -camera_position[1]; | ||
| 173 | forward_and_up[2] = -camera_position[2]; | ||
| 174 | forward_and_up[3] = 0.0f; | ||
| 175 | forward_and_up[3] = 0.0f; | ||
| 176 | forward_and_up[3] = 1.0f; // FIXME: upwards direction is not quite exact. It depends on the lookdown angle. | ||
| 177 | |||
| 178 |    // update the listener's position and orientation | ||
| 179 | alListener3f (AL_POSITION, camera_position[0], camera_position[1], camera_position[2]); | ||
| 180 | alListener3f (AL_VELOCITY, 0, 0, 0); // TODO: compute velocity dynamically with previous position | ||
| 181 | alListenerfv (AL_ORIENTATION, forward_and_up); | ||
| 182 | |||
| 181 | pmbaty | 183 |    // are there sounds enqueued for playing ? if so, process them one after the other | 
| 184 | for (sound_index = 0; sound_index < enqueued_sound_count; sound_index++) | ||
| 1 | pmbaty | 185 |    { | 
| 181 | pmbaty | 186 | processed_sound = &enqueued_sounds[sound_index]; // quick access to enqueued sound | 
| 1 | pmbaty | 187 | |
| 171 | pmbaty | 188 |       // given the type of sound we want, enqueue the right one | 
| 189 | pitch = 1.0f; // assume fixed pitch until told otherwise | ||
| 181 | pmbaty | 190 | if (processed_sound->type == SOUNDTYPE_CLICK) swprintf_s (soundfile_path, WCHAR_SIZEOF (soundfile_path), L"%s/themes/%s/sounds/click.wav", app_path, theme->name); | 
| 191 | else if (processed_sound->type == SOUNDTYPE_ILLEGALMOVE) swprintf_s (soundfile_path, WCHAR_SIZEOF (soundfile_path), L"%s/themes/%s/sounds/illegal.wav", app_path, theme->name); | ||
| 192 | else if (processed_sound->type == SOUNDTYPE_VICTORY) swprintf_s (soundfile_path, WCHAR_SIZEOF (soundfile_path), L"%s/themes/%s/sounds/win.wav", app_path, theme->name); | ||
| 193 | else if (processed_sound->type == SOUNDTYPE_DEFEAT) swprintf_s (soundfile_path, WCHAR_SIZEOF (soundfile_path), L"%s/themes/%s/sounds/lose.wav", app_path, theme->name); | ||
| 194 | else if (processed_sound->type == SOUNDTYPE_CHECK) swprintf_s (soundfile_path, WCHAR_SIZEOF (soundfile_path), L"%s/themes/%s/sounds/check.wav", app_path, theme->name); | ||
| 195 | else if (processed_sound->type == SOUNDTYPE_PIECETAKEN) swprintf_s (soundfile_path, WCHAR_SIZEOF (soundfile_path), L"%s/themes/%s/sounds/take.wav", app_path, theme->name); | ||
| 196 | else if (processed_sound->type == SOUNDTYPE_HINTWINDOW) swprintf_s (soundfile_path, WCHAR_SIZEOF (soundfile_path), L"%s/themes/%s/sounds/hintwindow.wav", app_path, theme->name); | ||
| 197 | else if (processed_sound->type == SOUNDTYPE_IMPORTANT) swprintf_s (soundfile_path, WCHAR_SIZEOF (soundfile_path), L"%s/themes/%s/sounds/important.wav", app_path, theme->name); | ||
| 198 | else if (processed_sound->type == SOUNDTYPE_MOVE) | ||
| 171 | pmbaty | 199 |       { | 
| 200 | temp32 = rand () % 6; // there are several movement sounds, pick one at random | ||
| 201 | if (temp32 == 0) swprintf_s (soundfile_path, WCHAR_SIZEOF (soundfile_path), L"%s/themes/%s/sounds/move1.wav", app_path, theme->name); | ||
| 202 | else if (temp32 == 1) swprintf_s (soundfile_path, WCHAR_SIZEOF (soundfile_path), L"%s/themes/%s/sounds/move2.wav", app_path, theme->name); | ||
| 203 | else if (temp32 == 2) swprintf_s (soundfile_path, WCHAR_SIZEOF (soundfile_path), L"%s/themes/%s/sounds/move3.wav", app_path, theme->name); | ||
| 204 | else if (temp32 == 3) swprintf_s (soundfile_path, WCHAR_SIZEOF (soundfile_path), L"%s/themes/%s/sounds/move4.wav", app_path, theme->name); | ||
| 205 | else if (temp32 == 4) swprintf_s (soundfile_path, WCHAR_SIZEOF (soundfile_path), L"%s/themes/%s/sounds/move5.wav", app_path, theme->name); | ||
| 206 | else swprintf_s (soundfile_path, WCHAR_SIZEOF (soundfile_path), L"%s/themes/%s/sounds/move6.wav", app_path, theme->name); | ||
| 207 | pitch = 1.0f + ((((float) rand ()) / RAND_MAX) - 0.5f) / 2.0f; // set a random pitch for these sounds between 0.75 and 1.25 | ||
| 208 |       } | ||
| 181 | pmbaty | 209 | else if (processed_sound->type == SOUNDTYPE_SLIDE) | 
| 171 | pmbaty | 210 |       { | 
| 211 | swprintf_s (soundfile_path, WCHAR_SIZEOF (soundfile_path), L"%s/themes/%s/sounds/slide.wav", app_path, theme->name); | ||
| 212 | pitch = 1.0f + ((((float) rand ()) / RAND_MAX) - 0.5f) / 2.0f; // set a random pitch for these sounds between 0.75 and 1.25 | ||
| 213 |       } | ||
| 116 | pmbaty | 214 | |
| 171 | pmbaty | 215 |       // now cycle through our known OpenAL buffers and see if we already know this one | 
| 216 | for (soundbuffer = soundbuffers; soundbuffer != NULL; soundbuffer = soundbuffer->next) | ||
| 217 | if ((soundbuffer->pathname != NULL) && (wcscmp (soundbuffer->pathname, soundfile_path) == 0)) | ||
| 218 | break; // break as soon as we find it | ||
| 1 | pmbaty | 219 | |
| 171 | pmbaty | 220 |       // have we NOT found it ? if so, we must create it | 
| 221 | if (soundbuffer == NULL) | ||
| 222 |       { | ||
| 223 |          // load the sound file | ||
| 224 | Buffer_Initialize (&soundfile); | ||
| 225 | if (!Buffer_ReadFromFileW (&soundfile, soundfile_path)) | ||
| 226 | return; // if unable to load this sound file, give up (FIXME: log something ?) | ||
| 1 | pmbaty | 227 | |
| 171 | pmbaty | 228 |          // parse the WAV file | 
| 229 | sample_count = channel_count = sample_size = channel_size = 0; | ||
| 230 | current_pos = 0; | ||
| 231 | for (;;) | ||
| 232 |          { | ||
| 233 | #define READ_DATA(type) *((type *) &soundfile.data[current_pos]); current_pos += sizeof (type); if (current_pos >= soundfile.size) break; | ||
| 1 | pmbaty | 234 | |
| 171 | pmbaty | 235 | chunk_id = READ_DATA (uint32_t); | 
| 236 | if (chunk_id == *((uint32_t *) "RIFF")) | ||
| 237 |             { | ||
| 238 | temp32 = READ_DATA (uint32_t); // skip the "chunk size" field | ||
| 239 | temp32 = READ_DATA (uint32_t); // skip the "riff style" field (typically "WAVE") | ||
| 240 |             } | ||
| 241 | else if (chunk_id == *((uint32_t *) "fmt ")) | ||
| 242 |             { | ||
| 243 | blksiz = READ_DATA (uint32_t); | ||
| 244 | temp16 = READ_DATA (uint16_t); if (temp16 != 1) break; // compressed WAVs are unsupported | ||
| 245 | temp32 = READ_DATA (uint16_t); channel_count = (int) temp16; | ||
| 246 | temp32 = READ_DATA (uint32_t); sample_rate = (int) temp32; | ||
| 247 | temp32 = READ_DATA (uint32_t); | ||
| 248 | temp16 = READ_DATA (uint16_t); sample_size = (int) temp16; | ||
| 249 | temp16 = READ_DATA (uint16_t); channel_size = (int) temp16 / 8; | ||
| 250 | if (blksiz > 16) | ||
| 251 | current_pos += blksiz - 16; | ||
| 252 | if (current_pos >= soundfile.size) | ||
| 253 | break; // don't go beyond the end of the file | ||
| 254 |             } | ||
| 255 | else if (chunk_id == *((uint32_t *) "data")) | ||
| 256 |             { | ||
| 257 | temp32 = READ_DATA (uint32_t); sample_count = (int) temp32; | ||
| 258 | break; // current_pos is now at the beginning of data, and data measures sample_count bytes long | ||
| 259 |             } | ||
| 260 |             else | ||
| 261 |             { | ||
| 262 | blksiz = READ_DATA (uint32_t); // skip the "chunk size" field | ||
| 263 | current_pos += blksiz; // useless chunk, skip it | ||
| 264 | if (current_pos >= soundfile.size) | ||
| 265 | break; // don't go beyond the end of the file | ||
| 266 |             } | ||
| 1 | pmbaty | 267 | |
| 171 | pmbaty | 268 | #undef READ_DATA | 
| 269 |          } | ||
| 270 | if ((sample_count == 0) || (channel_count == 0) || (sample_size == 0) || (channel_size == 0)) | ||
| 271 | return; // FIXME: not a wav file | ||
| 116 | pmbaty | 272 | |
| 171 | pmbaty | 273 |          // compute the total number of samples (number of channels * number of frames) | 
| 274 | sample_count /= sample_size; | ||
| 1 | pmbaty | 275 | |
| 171 | pmbaty | 276 |          // allocate space for one more sound buffer, and tie it to the linked list | 
| 277 | if (soundbuffers == NULL) | ||
| 116 | pmbaty | 278 |          { | 
| 171 | pmbaty | 279 | soundbuffers = (openal_buffer_t *) SAFE_malloc (1, sizeof (openal_buffer_t), false); // allocate a new slot to initialize the linked list | 
| 280 | soundbuffer = soundbuffers; // and set the pointer to the beginning of the list | ||
| 116 | pmbaty | 281 |          } | 
| 171 | pmbaty | 282 |          else | 
| 116 | pmbaty | 283 |          { | 
| 171 | pmbaty | 284 | for (soundbuffer = soundbuffers; soundbuffer->next != NULL; soundbuffer = soundbuffer->next); // locate the last slot in the linked list | 
| 285 | 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 | ||
| 286 | soundbuffer = soundbuffer->next; // and update the pointer to it | ||
| 116 | pmbaty | 287 |          } | 
| 171 | pmbaty | 288 | soundbuffer->next = NULL; // this is the last sound buffer in the linked list, do remember it. | 
| 289 | |||
| 290 | temp32 = wcslen (soundfile_path) + 1; // compute pathname buffer length (including null terminator) | ||
| 291 | soundbuffer->pathname = (wchar_t *) SAFE_malloc (temp32, sizeof (wchar_t), false); // allocate space for it | ||
| 292 | wcscpy_s (soundbuffer->pathname, temp32, soundfile_path); // and copy this sound's pathname in the newly allocated buffer | ||
| 293 | |||
| 294 |          // allocate the samples buffer and fill it, mixing all the WAV channels altogether in a 16-bit mono stream | ||
| 295 | soundbuffer->openal_samples = (ALshort *) SAFE_malloc (sample_count, sizeof (ALshort), false); | ||
| 296 | for (sample_index = 0; sample_index < sample_count; sample_index++) | ||
| 116 | pmbaty | 297 |          { | 
| 171 | pmbaty | 298 | sample_value = 0; | 
| 299 | if (channel_size == 1) | ||
| 300 | for (channel_index = 0; channel_index < channel_count; channel_index++) | ||
| 301 | sample_value += *((int8_t *) soundfile.data[current_pos + sample_index * sample_size + channel_index * channel_size]); | ||
| 302 | else if (channel_size == 2) | ||
| 303 | for (channel_index = 0; channel_index < channel_count; channel_index++) | ||
| 304 | sample_value += *((int16_t *) &soundfile.data[current_pos + sample_index * sample_size + channel_index * channel_size]); | ||
| 305 | sample_value /= channel_count; | ||
| 306 | soundbuffer->openal_samples[sample_index] = (ALshort) sample_value; | ||
| 116 | pmbaty | 307 |          } | 
| 308 | |||
| 171 | pmbaty | 309 | Buffer_Forget (&soundfile); // we can now forget this sound file | 
| 310 | |||
| 311 | alGenBuffers (1, &soundbuffer->openal_buffer); // create an OpenAL sound buffer and fill it with our samples | ||
| 312 | alBufferData (soundbuffer->openal_buffer, AL_FORMAT_MONO16, soundbuffer->openal_samples, sample_count * sizeof (ALushort), (ALsizei) sample_rate); | ||
| 313 | if (alGetError () != AL_NO_ERROR) | ||
| 314 | return; // FIXME: couldn't fill OpenAL buffer | ||
| 116 | pmbaty | 315 |       } | 
| 316 | |||
| 171 | pmbaty | 317 |       // now we have a buffer to play | 
| 116 | pmbaty | 318 | |
| 171 | pmbaty | 319 |       // cycle through our known OpenAL sources and find a free one | 
| 320 | for (source_index = 0; source_index < source_count; source_index++) | ||
| 321 | if (!sources[source_index].is_used) | ||
| 322 | break; // break as soon as we find it | ||
| 323 | |||
| 324 |       // have we NOT found any ? if so, reallocate so as to have one more | ||
| 325 | if (source_index == source_count) | ||
| 136 | pmbaty | 326 |       { | 
| 171 | pmbaty | 327 | sources = (openal_source_t *) SAFE_realloc (sources, source_count, source_count + 1, sizeof (openal_source_t), false); | 
| 328 | source_count++; // one more source has been created | ||
| 136 | pmbaty | 329 |       } | 
| 116 | pmbaty | 330 | |
| 171 | pmbaty | 331 |       // now we have a source to play our buffer | 
| 136 | pmbaty | 332 | |
| 171 | pmbaty | 333 | sources[source_index].is_used = true; // immediately mark it as used | 
| 334 | alGenSources (1, &sources[source_index].openal_source); // (re)create an OpenAL source | ||
| 116 | pmbaty | 335 | |
| 171 | pmbaty | 336 | alSourcef (sources[source_index].openal_source, AL_PITCH, (ALfloat) pitch); // set the source's pitch | 
| 337 | alSourcef (sources[source_index].openal_source, AL_GAIN, 1.0f); // set the source's volume (full) | ||
| 181 | pmbaty | 338 | alSource3f (sources[source_index].openal_source, AL_POSITION, (ALfloat) processed_sound->emitterlocation_x * ATTENUATION_FACTOR, (ALfloat) processed_sound->emitterlocation_y * ATTENUATION_FACTOR, (ALfloat) processed_sound->emitterlocation_z * ATTENUATION_FACTOR); | 
| 171 | pmbaty | 339 | alSource3f (sources[source_index].openal_source, AL_VELOCITY, 0, 0, 0); // set the source's velocity (static) | 
| 340 | alSourcei (sources[source_index].openal_source, AL_LOOPING, AL_FALSE); // set it as non-looping | ||
| 341 | alSourcei (sources[source_index].openal_source, AL_BUFFER, soundbuffer->openal_buffer); // attach our bufferized data to it | ||
| 116 | pmbaty | 342 | |
| 171 | pmbaty | 343 |       // play the source! Audio_Think() will dispose of it when it's finished | 
| 344 | alSourcePlay (sources[source_index].openal_source); | ||
| 116 | pmbaty | 345 |    } | 
| 346 | |||
| 181 | pmbaty | 347 | enqueued_sound_count = 0; // after that, remember that all enqueued sounds have been sent to OpenAL | 
| 348 | |||
| 171 | pmbaty | 349 |    // cycle through all used sources and see if one is no longer playing | 
| 116 | pmbaty | 350 | for (source_index = 0; source_index < source_count; source_index++) | 
| 171 | pmbaty | 351 |    { | 
| 116 | pmbaty | 352 | if (!sources[source_index].is_used) | 
| 171 | pmbaty | 353 | continue; // skip unused slots | 
| 116 | pmbaty | 354 | |
| 171 | pmbaty | 355 | alGetSourcei (sources[source_index].openal_source, AL_SOURCE_STATE, &status); // get this source's playing state | 
| 356 | if (status == AL_PLAYING) | ||
| 357 | continue; // skip sources that are still playing | ||
| 358 | |||
| 359 | alSourcei (sources[source_index].openal_source, AL_BUFFER, NULL); // untie the buffer from this source | ||
| 360 | alDeleteSources (1, &sources[source_index].openal_source); // and tell OpenAL to dispose of it | ||
| 361 | sources[source_index].is_used = false; // mark this source as unused now | ||
| 116 | pmbaty | 362 |    } | 
| 363 | |||
| 171 | pmbaty | 364 | return; // finished, audio has been handled | 
| 365 | } | ||
| 116 | pmbaty | 366 | |
| 367 | |||
| 171 | pmbaty | 368 | void Audio_PlaySound (int sound_type, float pos_x, float pos_y, float pos_z) | 
| 369 | { | ||
| 370 |    // helper function to play a sound (WARNING: it is NOT thread-safe!) | ||
| 116 | pmbaty | 371 | |
| 181 | pmbaty | 372 | if (!options.want_sounds || (enqueued_sound_count == sizeof (enqueued_sounds) / sizeof (enqueued_sounds[0]))) | 
| 373 | return; // if we want no sound OR if there's no space to add one, don't play anything | ||
| 116 | pmbaty | 374 | |
| 181 | pmbaty | 375 | enqueued_sounds[enqueued_sound_count].type = sound_type; // enqueue this sound for playing. Audio_Think() will take care of it. | 
| 376 | enqueued_sounds[enqueued_sound_count].emitterlocation_x = pos_x; | ||
| 377 | enqueued_sounds[enqueued_sound_count].emitterlocation_y = pos_y; | ||
| 378 | enqueued_sounds[enqueued_sound_count].emitterlocation_z = pos_z; | ||
| 379 | enqueued_sound_count++; // there's now one more sound to play | ||
| 171 | pmbaty | 380 | |
| 1 | pmbaty | 381 | return; // finished | 
| 382 | } |