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