1 /*
2 * Copyright (C) 2002 Terence M. Welsh
3 * Ported to Linux by Tugrul Galatali <tugrul@galatali.com>
4 *
5 * Skyrocket is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Skyrocket is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 #include "skyrocket_sound.h"
20
21 #ifdef HAVE_OPENAL
22
23 #include <math.h>
24 #include <stdlib.h>
25 #include <AL/al.h>
26 #include <AL/alut.h>
27
28 #include <cstdlib>
29 #include <list>
30
31 #include "loadTexture.h"
32
33 // reference distance, max distance
34 // reference distance = sound is partly attenuated
35 // maximum distance = sound is completely attenuated
36 float sound_distances[NUM_BUFFERS][2] = {
37 { 300.0f, 600.0f }, // launch sounds
38 { 300.0f, 600.0f },
39 { 4000.0f, 8000.0f }, // booms
40 { 4000.0f, 8000.0f },
41 { 4000.0f, 8000.0f },
42 { 6000.0f, 12000.0f },
43 { 2500.0f, 5000.0f }, // poppers
44 { 10000.0f, 20000.0f }, // suck
45 { 20000.0f, 40000.0f }, // nuke
46 { 2500.0f, 5000.0f } // whistle
47 };
48
49 class soundnode;
50
51 ALuint g_Buffers[NUM_BUFFERS];
52 ALuint g_Sources[NUM_SOURCES];
53 extern float elapsedTime;
54 extern int dSound;
55 extern int kSlowMotion;
56
swap_bytes(unsigned char * data,int bytes)57 void swap_bytes (unsigned char *data, int bytes)
58 {
59 int i = 0;
60
61 for (i = 0; i < bytes - 1; i += 2) {
62 int temp = data[i];
63
64 data[i] = data[i + 1];
65 data[i + 1] = temp;
66 }
67 }
68
initSound()69 void initSound ()
70 {
71 int i = 1;
72 unsigned char *j;
73 unsigned char *l_snd;
74
75 j = (unsigned char *)&i;
76
77 alutInit (NULL, 0);
78
79 alDistanceModel (AL_INVERSE_DISTANCE);
80 // As of October, 2001, AL_ROLLOFF_FACTOR isn't implemented in the Windows
81 // version of OpenAL, so the distance attenuation models won't work. You
82 // have to set the gains yourself.
83
84 //alDistanceModel(AL_NONE);
85
86 alDopplerVelocity (1130.0f); // Sound travels at 1130 feet/sec
87 alListenerf (AL_GAIN, float (dSound) * 0.01f); // Volume
88
89 // Initialize sound data
90 alGenBuffers (NUM_BUFFERS, g_Buffers);
91 alGenSources (NUM_SOURCES, g_Sources);
92
93 #define BUFFER_SOUND(index, data, compressedsize, size) \
94 LOAD_TEXTURE(l_snd, data, compressedsize, size) \
95 if (!*j) swap_bytes(l_snd, size); \
96 alBufferData(g_Buffers[index], AL_FORMAT_MONO16, l_snd, size, 44100); \
97 FREE_TEXTURE(l_snd)
98
99 BUFFER_SOUND (BOOM1SOUND, launch1SoundData, launch1SoundData_compressedsize, launch1SoundData_size)
100 BUFFER_SOUND (BOOM2SOUND, launch2SoundData, launch2SoundData_compressedsize, launch2SoundData_size)
101 BUFFER_SOUND (BOOM1SOUND, boom1SoundData, boom1SoundData_compressedsize, boom1SoundData_size)
102 BUFFER_SOUND (BOOM2SOUND, boom2SoundData, boom2SoundData_compressedsize, boom2SoundData_size)
103 BUFFER_SOUND (BOOM3SOUND, boom3SoundData, boom3SoundData_compressedsize, boom3SoundData_size)
104 BUFFER_SOUND (BOOM4SOUND, boom4SoundData, boom4SoundData_compressedsize, boom4SoundData_size)
105 BUFFER_SOUND (POPPERSOUND, popperSoundData, popperSoundData_compressedsize, popperSoundData_size)
106 BUFFER_SOUND (POPPERSOUND, suckSoundData, suckSoundData_compressedsize, suckSoundData_size)
107 BUFFER_SOUND (POPPERSOUND, nukeSoundData, nukeSoundData_compressedsize, nukeSoundData_size)
108 BUFFER_SOUND (POPPERSOUND, whistleSoundData, whistleSoundData_compressedsize, whistleSoundData_size)
109 }
110
111 class soundnode {
112 public:
113 int sound;
114 float pos[3];
115 float dist;
116 float time; // time until sound plays
117
soundnode()118 soundnode () {
119 };
120
~soundnode()121 ~soundnode () {
122 };
123 };
124
125 std::list < soundnode > soundlist;
126
insertSoundNode(int sound,rsVec source,rsVec observer)127 void insertSoundNode (int sound, rsVec source, rsVec observer)
128 {
129 soundnode *node;
130 rsVec dir = observer - source;
131
132 soundlist.push_back (soundnode ());
133 node = &soundlist.back ();
134 node->sound = sound;
135 node->pos[0] = source[0];
136 node->pos[1] = source[1];
137 node->pos[2] = source[2];
138 // distance to sound
139 node->dist = sqrt (dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2]);
140 // Sound travels at 1130 feet/sec
141 node->time = node->dist * 0.000885f;
142 if (node->sound == POPPERSOUND) // poppers have a little delay
143 node->time += 2.5f;
144 }
145
updateSound(float * listenerPos,float * listenerVel,float * listenerOri)146 void updateSound (float *listenerPos, float *listenerVel, float *listenerOri)
147 {
148 static int source = 0;
149
150 // Set current listener attributes
151 alListenerfv (AL_POSITION, listenerPos);
152 alListenerfv (AL_VELOCITY, listenerVel);
153 alListenerfv (AL_ORIENTATION, listenerOri);
154
155 std::list < soundnode >::iterator cursound = soundlist.begin ();
156 while (cursound != soundlist.end ()) {
157 cursound->time -= elapsedTime;
158 if (cursound->time <= 0.0f) {
159 if (cursound->dist < sound_distances[cursound->sound][1]) {
160 alSourceStop (g_Sources[source]);
161 alSourcei (g_Sources[source], AL_BUFFER, g_Buffers[cursound->sound]);
162 //alSourcef(g_Sources[source], AL_REFERENCE_DISTANCE, sound_distances[cursound->sound][0]);
163 //alSourcef(g_Sources[source], AL_ROLLOFF_FACTOR, 0.013557606f);
164 // HACK: AL_REFERENCE_DISTANCE must be set or OpenAL won't make any sound at all.
165 // I assume this will be fixed in future implementations of OpenAL.
166 alSourcef (g_Sources[source], AL_REFERENCE_DISTANCE, 1000000.0f);
167 // As of October, 2001, AL_ROLLOFF_FACTOR isn't implemented in the Windows
168 // version of OpenAL, so the distance attenuation models won't work. You
169 // have to set the gains yourself.
170 // Here I implement the AL_INVERSE_DISTANCE model formula from the OpenAL spec.
171 //float gain = 1.0f - 20.0f * log10(1.0f + 0.013557606f
172 // * (cursound->dist - sound_distances[cursound->sound][0])
173 // / sound_distances[cursound->sound][0]);
174 // But I don't like the way it sounds, so I'll just fudge everything
175 float gain = 1.0f - (cursound->dist / sound_distances[cursound->sound][1]);
176
177 if (gain > 1.0f)
178 gain = 1.0f;
179 if (gain < 0.0f)
180 gain = 0.0f;
181 alSourcef (g_Sources[source], AL_GAIN, gain);
182 alSourcefv (g_Sources[source], AL_POSITION, cursound->pos);
183 alSourcei (g_Sources[source], AL_LOOPING, AL_FALSE);
184 if (kSlowMotion) // Slow down the sound
185 alSourcef (g_Sources[source], AL_PITCH, 0.5f);
186 else // Sound at regular speed
187 alSourcef (g_Sources[source], AL_PITCH, 1.0f);
188 alSourcePlay (g_Sources[source]);
189 source++;
190 if (source >= NUM_SOURCES)
191 source = 0;
192 }
193 cursound = soundlist.erase (cursound);
194 } else
195 cursound++;
196 }
197 }
198
cleanupSound()199 void cleanupSound ()
200 {
201 alDeleteSources (NUM_SOURCES, g_Sources);
202 alDeleteBuffers (NUM_BUFFERS, g_Buffers);
203
204 ALCcontext * const context = alcGetCurrentContext ();
205 ALCdevice * const device = alcGetContextsDevice (context);
206
207 alcMakeContextCurrent (NULL);
208 alcDestroyContext (context);
209 alcCloseDevice (device);
210
211 alutExit ();
212 }
213
214 #endif
215