Subversion Repositories Games.Chess Giants

Rev

Rev 18 | Rev 130 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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